buzbee | e88dfbf | 2012-03-05 11:19:57 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2012 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | #include "../../CompilerInternals.h" |
| 18 | #include "X86LIR.h" |
| 19 | #include "../Ralloc.h" |
| 20 | |
| 21 | #include <string> |
| 22 | |
| 23 | namespace art { |
| 24 | |
buzbee | f0504cd | 2012-11-13 16:31:10 -0800 | [diff] [blame] | 25 | RegLocation locCReturn() |
| 26 | { |
| 27 | RegLocation res = X86_LOC_C_RETURN; |
| 28 | return res; |
| 29 | } |
| 30 | |
| 31 | RegLocation locCReturnWide() |
| 32 | { |
| 33 | RegLocation res = X86_LOC_C_RETURN_WIDE; |
| 34 | return res; |
| 35 | } |
| 36 | |
| 37 | RegLocation locCReturnFloat() |
| 38 | { |
| 39 | RegLocation res = X86_LOC_C_RETURN_FLOAT; |
| 40 | return res; |
| 41 | } |
| 42 | |
| 43 | RegLocation locCReturnDouble() |
| 44 | { |
| 45 | RegLocation res = X86_LOC_C_RETURN_DOUBLE; |
| 46 | return res; |
| 47 | } |
| 48 | |
| 49 | // Return a target-dependent special register. |
| 50 | int targetReg(SpecialTargetRegister reg) { |
| 51 | int res = INVALID_REG; |
| 52 | switch (reg) { |
| 53 | case kSelf: res = rX86_SELF; break; |
| 54 | case kSuspend: res = rX86_SUSPEND; break; |
| 55 | case kLr: res = rX86_LR; break; |
| 56 | case kPc: res = rX86_PC; break; |
| 57 | case kSp: res = rX86_SP; break; |
| 58 | case kArg0: res = rX86_ARG0; break; |
| 59 | case kArg1: res = rX86_ARG1; break; |
| 60 | case kArg2: res = rX86_ARG2; break; |
| 61 | case kArg3: res = rX86_ARG3; break; |
| 62 | case kFArg0: res = rX86_FARG0; break; |
| 63 | case kFArg1: res = rX86_FARG1; break; |
| 64 | case kFArg2: res = rX86_FARG2; break; |
| 65 | case kFArg3: res = rX86_FARG3; break; |
| 66 | case kRet0: res = rX86_RET0; break; |
| 67 | case kRet1: res = rX86_RET1; break; |
| 68 | case kInvokeTgt: res = rX86_INVOKE_TGT; break; |
| 69 | case kCount: res = rX86_COUNT; break; |
| 70 | } |
| 71 | return res; |
| 72 | } |
| 73 | |
| 74 | // Create a double from a pair of singles. |
| 75 | int s2d(int lowReg, int highReg) |
| 76 | { |
| 77 | return X86_S2D(lowReg, highReg); |
| 78 | } |
| 79 | |
| 80 | // Is reg a single or double? |
| 81 | bool fpReg(int reg) |
| 82 | { |
| 83 | return X86_FPREG(reg); |
| 84 | } |
| 85 | |
| 86 | // Is reg a single? |
| 87 | bool singleReg(int reg) |
| 88 | { |
| 89 | return X86_SINGLEREG(reg); |
| 90 | } |
| 91 | |
| 92 | // Is reg a double? |
| 93 | bool doubleReg(int reg) |
| 94 | { |
| 95 | return X86_DOUBLEREG(reg); |
| 96 | } |
| 97 | |
| 98 | // Return mask to strip off fp reg flags and bias. |
| 99 | uint32_t fpRegMask() |
| 100 | { |
| 101 | return X86_FP_REG_MASK; |
| 102 | } |
| 103 | |
| 104 | // True if both regs single, both core or both double. |
| 105 | bool sameRegType(int reg1, int reg2) |
| 106 | { |
| 107 | return (X86_REGTYPE(reg1) == X86_REGTYPE(reg2)); |
| 108 | } |
| 109 | |
buzbee | ec13743 | 2012-11-13 12:13:16 -0800 | [diff] [blame] | 110 | /* |
| 111 | * Decode the register id. |
| 112 | */ |
| 113 | u8 getRegMaskCommon(CompilationUnit* cUnit, int reg) |
| 114 | { |
| 115 | u8 seed; |
| 116 | int shift; |
| 117 | int regId; |
| 118 | |
| 119 | regId = reg & 0xf; |
| 120 | /* Double registers in x86 are just a single FP register */ |
| 121 | seed = 1; |
| 122 | /* FP register starts at bit position 16 */ |
buzbee | f0504cd | 2012-11-13 16:31:10 -0800 | [diff] [blame] | 123 | shift = X86_FPREG(reg) ? kX86FPReg0 : 0; |
buzbee | ec13743 | 2012-11-13 12:13:16 -0800 | [diff] [blame] | 124 | /* Expand the double register id into single offset */ |
| 125 | shift += regId; |
| 126 | return (seed << shift); |
| 127 | } |
| 128 | |
| 129 | uint64_t getPCUseDefEncoding() |
| 130 | { |
| 131 | /* |
| 132 | * FIXME: might make sense to use a virtual resource encoding bit for pc. Might be |
| 133 | * able to clean up some of the x86/Arm_Mips differences |
| 134 | */ |
| 135 | LOG(FATAL) << "Unexpected call to getPCUseDefEncoding for x86"; |
| 136 | return 0ULL; |
| 137 | } |
| 138 | |
buzbee | b046e16 | 2012-10-30 15:48:42 -0700 | [diff] [blame] | 139 | void setupTargetResourceMasks(CompilationUnit* cUnit, LIR* lir) |
| 140 | { |
| 141 | DCHECK_EQ(cUnit->instructionSet, kX86); |
| 142 | |
| 143 | // X86-specific resource map setup here. |
buzbee | ec13743 | 2012-11-13 12:13:16 -0800 | [diff] [blame] | 144 | uint64_t flags = EncodingMap[lir->opcode].flags; |
| 145 | |
| 146 | if (flags & REG_USE_SP) { |
| 147 | lir->useMask |= ENCODE_X86_REG_SP; |
| 148 | } |
| 149 | |
| 150 | if (flags & REG_DEF_SP) { |
| 151 | lir->defMask |= ENCODE_X86_REG_SP; |
| 152 | } |
| 153 | |
buzbee | b046e16 | 2012-10-30 15:48:42 -0700 | [diff] [blame] | 154 | if (flags & REG_DEFA) { |
| 155 | oatSetupRegMask(cUnit, &lir->defMask, rAX); |
| 156 | } |
| 157 | |
| 158 | if (flags & REG_DEFD) { |
| 159 | oatSetupRegMask(cUnit, &lir->defMask, rDX); |
| 160 | } |
| 161 | if (flags & REG_USEA) { |
| 162 | oatSetupRegMask(cUnit, &lir->useMask, rAX); |
| 163 | } |
| 164 | |
| 165 | if (flags & REG_USEC) { |
| 166 | oatSetupRegMask(cUnit, &lir->useMask, rCX); |
| 167 | } |
| 168 | |
| 169 | if (flags & REG_USED) { |
| 170 | oatSetupRegMask(cUnit, &lir->useMask, rDX); |
| 171 | } |
| 172 | } |
| 173 | |
buzbee | e88dfbf | 2012-03-05 11:19:57 -0800 | [diff] [blame] | 174 | /* For dumping instructions */ |
Ian Rogers | b5d09b2 | 2012-03-06 22:14:17 -0800 | [diff] [blame] | 175 | static const char* x86RegName[] = { |
Bill Buzbee | a114add | 2012-05-03 15:00:40 -0700 | [diff] [blame] | 176 | "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", |
| 177 | "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" |
buzbee | e88dfbf | 2012-03-05 11:19:57 -0800 | [diff] [blame] | 178 | }; |
| 179 | |
Ian Rogers | b5d09b2 | 2012-03-06 22:14:17 -0800 | [diff] [blame] | 180 | static const char* x86CondName[] = { |
Bill Buzbee | a114add | 2012-05-03 15:00:40 -0700 | [diff] [blame] | 181 | "O", |
| 182 | "NO", |
| 183 | "B/NAE/C", |
| 184 | "NB/AE/NC", |
| 185 | "Z/EQ", |
| 186 | "NZ/NE", |
| 187 | "BE/NA", |
| 188 | "NBE/A", |
| 189 | "S", |
| 190 | "NS", |
| 191 | "P/PE", |
| 192 | "NP/PO", |
| 193 | "L/NGE", |
| 194 | "NL/GE", |
| 195 | "LE/NG", |
| 196 | "NLE/G" |
Ian Rogers | b5d09b2 | 2012-03-06 22:14:17 -0800 | [diff] [blame] | 197 | }; |
| 198 | |
buzbee | e88dfbf | 2012-03-05 11:19:57 -0800 | [diff] [blame] | 199 | /* |
| 200 | * Interpret a format string and build a string no longer than size |
Ian Rogers | 7caad77 | 2012-03-30 01:07:54 -0700 | [diff] [blame] | 201 | * See format key in Assemble.cc. |
buzbee | e88dfbf | 2012-03-05 11:19:57 -0800 | [diff] [blame] | 202 | */ |
Ian Rogers | b5d09b2 | 2012-03-06 22:14:17 -0800 | [diff] [blame] | 203 | std::string buildInsnString(const char *fmt, LIR *lir, unsigned char* baseAddr) { |
| 204 | std::string buf; |
| 205 | size_t i = 0; |
| 206 | size_t fmt_len = strlen(fmt); |
Elliott Hughes | b25c3f6 | 2012-03-26 16:35:06 -0700 | [diff] [blame] | 207 | while (i < fmt_len) { |
Ian Rogers | b5d09b2 | 2012-03-06 22:14:17 -0800 | [diff] [blame] | 208 | if (fmt[i] != '!') { |
| 209 | buf += fmt[i]; |
| 210 | i++; |
| 211 | } else { |
| 212 | i++; |
| 213 | DCHECK_LT(i, fmt_len); |
| 214 | char operand_number_ch = fmt[i]; |
| 215 | i++; |
| 216 | if (operand_number_ch == '!') { |
| 217 | buf += "!"; |
| 218 | } else { |
| 219 | int operand_number = operand_number_ch - '0'; |
| 220 | DCHECK_LT(operand_number, 6); // Expect upto 6 LIR operands. |
| 221 | DCHECK_LT(i, fmt_len); |
| 222 | int operand = lir->operands[operand_number]; |
Elliott Hughes | b25c3f6 | 2012-03-26 16:35:06 -0700 | [diff] [blame] | 223 | switch (fmt[i]) { |
Ian Rogers | b3ab25b | 2012-03-19 01:12:01 -0700 | [diff] [blame] | 224 | case 'c': |
| 225 | DCHECK_LT(static_cast<size_t>(operand), sizeof(x86CondName)); |
| 226 | buf += x86CondName[operand]; |
| 227 | break; |
Ian Rogers | b5d09b2 | 2012-03-06 22:14:17 -0800 | [diff] [blame] | 228 | case 'd': |
| 229 | buf += StringPrintf("%d", operand); |
| 230 | break; |
Ian Rogers | 7caad77 | 2012-03-30 01:07:54 -0700 | [diff] [blame] | 231 | case 'p': { |
| 232 | SwitchTable *tabRec = reinterpret_cast<SwitchTable*>(operand); |
| 233 | buf += StringPrintf("0x%08x", tabRec->offset); |
| 234 | break; |
| 235 | } |
Ian Rogers | b5d09b2 | 2012-03-06 22:14:17 -0800 | [diff] [blame] | 236 | case 'r': |
buzbee | f0504cd | 2012-11-13 16:31:10 -0800 | [diff] [blame] | 237 | if (X86_FPREG(operand) || X86_DOUBLEREG(operand)) { |
| 238 | int fp_reg = operand & X86_FP_REG_MASK; |
Ian Rogers | b5d09b2 | 2012-03-06 22:14:17 -0800 | [diff] [blame] | 239 | buf += StringPrintf("xmm%d", fp_reg); |
buzbee | e88dfbf | 2012-03-05 11:19:57 -0800 | [diff] [blame] | 240 | } else { |
Ian Rogers | b5d09b2 | 2012-03-06 22:14:17 -0800 | [diff] [blame] | 241 | DCHECK_LT(static_cast<size_t>(operand), sizeof(x86RegName)); |
| 242 | buf += x86RegName[operand]; |
buzbee | e88dfbf | 2012-03-05 11:19:57 -0800 | [diff] [blame] | 243 | } |
Ian Rogers | b5d09b2 | 2012-03-06 22:14:17 -0800 | [diff] [blame] | 244 | break; |
Ian Rogers | b3ab25b | 2012-03-19 01:12:01 -0700 | [diff] [blame] | 245 | case 't': |
| 246 | buf += StringPrintf("0x%08x (L%p)", |
Bill Buzbee | a114add | 2012-05-03 15:00:40 -0700 | [diff] [blame] | 247 | reinterpret_cast<uint32_t>(baseAddr) |
| 248 | + lir->offset + operand, lir->target); |
Ian Rogers | b5d09b2 | 2012-03-06 22:14:17 -0800 | [diff] [blame] | 249 | break; |
| 250 | default: |
| 251 | buf += StringPrintf("DecodeError '%c'", fmt[i]); |
| 252 | break; |
buzbee | e88dfbf | 2012-03-05 11:19:57 -0800 | [diff] [blame] | 253 | } |
Ian Rogers | b5d09b2 | 2012-03-06 22:14:17 -0800 | [diff] [blame] | 254 | i++; |
| 255 | } |
buzbee | e88dfbf | 2012-03-05 11:19:57 -0800 | [diff] [blame] | 256 | } |
Ian Rogers | b5d09b2 | 2012-03-06 22:14:17 -0800 | [diff] [blame] | 257 | } |
| 258 | return buf; |
buzbee | e88dfbf | 2012-03-05 11:19:57 -0800 | [diff] [blame] | 259 | } |
| 260 | |
| 261 | void oatDumpResourceMask(LIR *lir, u8 mask, const char *prefix) |
| 262 | { |
Bill Buzbee | a114add | 2012-05-03 15:00:40 -0700 | [diff] [blame] | 263 | char buf[256]; |
| 264 | buf[0] = 0; |
| 265 | LIR *x86LIR = (LIR *) lir; |
buzbee | e88dfbf | 2012-03-05 11:19:57 -0800 | [diff] [blame] | 266 | |
Bill Buzbee | a114add | 2012-05-03 15:00:40 -0700 | [diff] [blame] | 267 | if (mask == ENCODE_ALL) { |
| 268 | strcpy(buf, "all"); |
| 269 | } else { |
| 270 | char num[8]; |
| 271 | int i; |
buzbee | e88dfbf | 2012-03-05 11:19:57 -0800 | [diff] [blame] | 272 | |
buzbee | ec13743 | 2012-11-13 12:13:16 -0800 | [diff] [blame] | 273 | for (i = 0; i < kX86RegEnd; i++) { |
Bill Buzbee | a114add | 2012-05-03 15:00:40 -0700 | [diff] [blame] | 274 | if (mask & (1ULL << i)) { |
| 275 | sprintf(num, "%d ", i); |
| 276 | strcat(buf, num); |
| 277 | } |
buzbee | e88dfbf | 2012-03-05 11:19:57 -0800 | [diff] [blame] | 278 | } |
Bill Buzbee | a114add | 2012-05-03 15:00:40 -0700 | [diff] [blame] | 279 | |
| 280 | if (mask & ENCODE_CCODE) { |
| 281 | strcat(buf, "cc "); |
buzbee | e88dfbf | 2012-03-05 11:19:57 -0800 | [diff] [blame] | 282 | } |
Bill Buzbee | a114add | 2012-05-03 15:00:40 -0700 | [diff] [blame] | 283 | /* Memory bits */ |
| 284 | if (x86LIR && (mask & ENCODE_DALVIK_REG)) { |
| 285 | sprintf(buf + strlen(buf), "dr%d%s", x86LIR->aliasInfo & 0xffff, |
| 286 | (x86LIR->aliasInfo & 0x80000000) ? "(+1)" : ""); |
| 287 | } |
| 288 | if (mask & ENCODE_LITERAL) { |
| 289 | strcat(buf, "lit "); |
| 290 | } |
| 291 | |
| 292 | if (mask & ENCODE_HEAP_REF) { |
| 293 | strcat(buf, "heap "); |
| 294 | } |
| 295 | if (mask & ENCODE_MUST_NOT_ALIAS) { |
| 296 | strcat(buf, "noalias "); |
| 297 | } |
| 298 | } |
| 299 | if (buf[0]) { |
| 300 | LOG(INFO) << prefix << ": " << buf; |
| 301 | } |
buzbee | e88dfbf | 2012-03-05 11:19:57 -0800 | [diff] [blame] | 302 | } |
| 303 | |
| 304 | } // namespace art |