blob: bbf7c38518445c395fdec15287cb4820cac7ddc1 [file] [log] [blame]
buzbeee3acd072012-02-25 17:03:10 -08001/*
2 * Copyright (C) 2011 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
17namespace art {
18
buzbee31a4a6f2012-02-28 15:36:15 -080019void setMemRefType(LIR* lir, bool isLoad, int memType)
20{
21 u8 *maskPtr;
22 u8 mask = ENCODE_MEM;;
23 DCHECK(EncodingMap[lir->opcode].flags & (IS_LOAD | IS_STORE));
24 if (isLoad) {
25 maskPtr = &lir->useMask;
26 } else {
27 maskPtr = &lir->defMask;
28 }
29 /* Clear out the memref flags */
30 *maskPtr &= ~mask;
31 /* ..and then add back the one we need */
32 switch(memType) {
33 case kLiteral:
34 DCHECK(isLoad);
35 *maskPtr |= ENCODE_LITERAL;
36 break;
37 case kDalvikReg:
38 *maskPtr |= ENCODE_DALVIK_REG;
39 break;
40 case kHeapRef:
41 *maskPtr |= ENCODE_HEAP_REF;
42 break;
43 case kMustNotAlias:
44 /* Currently only loads can be marked as kMustNotAlias */
45 DCHECK(!(EncodingMap[lir->opcode].flags & IS_STORE));
46 *maskPtr |= ENCODE_MUST_NOT_ALIAS;
47 break;
48 default:
49 LOG(FATAL) << "Oat: invalid memref kind - " << memType;
50 }
51}
52
53/*
54 * Mark load/store instructions that access Dalvik registers through r5FP +
55 * offset.
56 */
57void annotateDalvikRegAccess(LIR* lir, int regId, bool isLoad)
58{
59 setMemRefType(lir, isLoad, kDalvikReg);
60
61 /*
62 * Store the Dalvik register id in aliasInfo. Mark he MSB if it is a 64-bit
63 * access.
64 */
65 lir->aliasInfo = regId;
66 if (DOUBLEREG(lir->operands[0])) {
67 lir->aliasInfo |= 0x80000000;
68 }
69}
70
71/*
72 * Decode the register id.
73 */
74inline u8 getRegMaskCommon(int reg)
75{
76 u8 seed;
77 int shift;
78 int regId = reg & 0x1f;
79
80 /*
81 * Each double register is equal to a pair of single-precision FP registers
82 */
83 seed = DOUBLEREG(reg) ? 3 : 1;
84 /* FP register starts at bit position 16 */
85 shift = FPREG(reg) ? kFPReg0 : 0;
86 /* Expand the double register id into single offset */
87 shift += regId;
88 return (seed << shift);
89}
90
91/*
92 * Mark the corresponding bit(s).
93 */
94inline void setupRegMask(u8* mask, int reg)
95{
96 *mask |= getRegMaskCommon(reg);
97}
98
99/*
100 * Set up the proper fields in the resource mask
101 */
102void setupResourceMasks(LIR* lir)
103{
104 int opcode = lir->opcode;
105 int flags;
106
107 if (opcode <= 0) {
108 lir->useMask = lir->defMask = 0;
109 return;
110 }
111
112 flags = EncodingMap[lir->opcode].flags;
113
114 if (flags & NEEDS_FIXUP) {
115 lir->flags.pcRelFixup = true;
116 }
117
buzbeee88dfbf2012-03-05 11:19:57 -0800118 /* Get the starting size of the instruction's template */
119 lir->flags.size = oatGetInsnSize(lir);
120
buzbee31a4a6f2012-02-28 15:36:15 -0800121 /* Set up the mask for resources that are updated */
122 if (flags & (IS_LOAD | IS_STORE)) {
123 /* Default to heap - will catch specialized classes later */
124 setMemRefType(lir, flags & IS_LOAD, kHeapRef);
125 }
126
127 /*
128 * Conservatively assume the branch here will call out a function that in
129 * turn will trash everything.
130 */
131 if (flags & IS_BRANCH) {
132 lir->defMask = lir->useMask = ENCODE_ALL;
133 return;
134 }
135
136 if (flags & REG_DEF0) {
137 setupRegMask(&lir->defMask, lir->operands[0]);
138 }
139
140 if (flags & REG_DEF1) {
141 setupRegMask(&lir->defMask, lir->operands[1]);
142 }
143
144 if (flags & REG_DEF_SP) {
145 lir->defMask |= ENCODE_REG_SP;
146 }
147
buzbeea7678db2012-03-05 15:35:46 -0800148#if !defined(TARGET_X86)
buzbee31a4a6f2012-02-28 15:36:15 -0800149 if (flags & REG_DEF_LR) {
150 lir->defMask |= ENCODE_REG_LR;
151 }
buzbeea7678db2012-03-05 15:35:46 -0800152#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800153
154 if (flags & REG_DEF_LIST0) {
155 lir->defMask |= ENCODE_REG_LIST(lir->operands[0]);
156 }
157
158 if (flags & REG_DEF_LIST1) {
159 lir->defMask |= ENCODE_REG_LIST(lir->operands[1]);
160 }
161
buzbee5de34942012-03-01 14:51:57 -0800162#if defined(TARGET_ARM)
buzbee31a4a6f2012-02-28 15:36:15 -0800163 if (flags & REG_DEF_FPCS_LIST0) {
164 lir->defMask |= ENCODE_REG_FPCS_LIST(lir->operands[0]);
165 }
166
167 if (flags & REG_DEF_FPCS_LIST2) {
168 for (int i = 0; i < lir->operands[2]; i++) {
169 setupRegMask(&lir->defMask, lir->operands[1] + i);
170 }
171 }
buzbee5de34942012-03-01 14:51:57 -0800172#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800173
174 if (flags & SETS_CCODES) {
175 lir->defMask |= ENCODE_CCODE;
176 }
177
178#if defined(TARGET_ARM)
179 /* Conservatively treat the IT block */
180 if (flags & IS_IT) {
181 lir->defMask = ENCODE_ALL;
182 }
183#endif
184
185 if (flags & (REG_USE0 | REG_USE1 | REG_USE2 | REG_USE3)) {
186 int i;
187
188 for (i = 0; i < 4; i++) {
189 if (flags & (1 << (kRegUse0 + i))) {
190 setupRegMask(&lir->useMask, lir->operands[i]);
191 }
192 }
193 }
194
buzbeea7678db2012-03-05 15:35:46 -0800195#if defined(TARGET_ARM)
buzbee31a4a6f2012-02-28 15:36:15 -0800196 if (flags & REG_USE_PC) {
197 lir->useMask |= ENCODE_REG_PC;
198 }
buzbeea7678db2012-03-05 15:35:46 -0800199#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800200
201 if (flags & REG_USE_SP) {
202 lir->useMask |= ENCODE_REG_SP;
203 }
204
205 if (flags & REG_USE_LIST0) {
206 lir->useMask |= ENCODE_REG_LIST(lir->operands[0]);
207 }
208
209 if (flags & REG_USE_LIST1) {
210 lir->useMask |= ENCODE_REG_LIST(lir->operands[1]);
211 }
212
buzbee5de34942012-03-01 14:51:57 -0800213#if defined(TARGET_ARM)
buzbee31a4a6f2012-02-28 15:36:15 -0800214 if (flags & REG_USE_FPCS_LIST0) {
215 lir->useMask |= ENCODE_REG_FPCS_LIST(lir->operands[0]);
216 }
217
218 if (flags & REG_USE_FPCS_LIST2) {
219 for (int i = 0; i < lir->operands[2]; i++) {
220 setupRegMask(&lir->useMask, lir->operands[1] + i);
221 }
222 }
buzbee5de34942012-03-01 14:51:57 -0800223#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800224
225 if (flags & USES_CCODES) {
226 lir->useMask |= ENCODE_CCODE;
227 }
228
229#if defined(TARGET_ARM)
230 /* Fixup for kThumbPush/lr and kThumbPop/pc */
231 if (opcode == kThumbPush || opcode == kThumbPop) {
232 u8 r8Mask = getRegMaskCommon(r8);
233 if ((opcode == kThumbPush) && (lir->useMask & r8Mask)) {
234 lir->useMask &= ~r8Mask;
235 lir->useMask |= ENCODE_REG_LR;
236 } else if ((opcode == kThumbPop) && (lir->defMask & r8Mask)) {
237 lir->defMask &= ~r8Mask;
238 lir->defMask |= ENCODE_REG_PC;
239 }
240 }
241#endif
242}
243
244/*
buzbee5de34942012-03-01 14:51:57 -0800245 * Debugging macros
246 */
247#define DUMP_RESOURCE_MASK(X)
248#define DUMP_SSA_REP(X)
249
250/* Pretty-print a LIR instruction */
251void oatDumpLIRInsn(CompilationUnit* cUnit, LIR* arg, unsigned char* baseAddr)
252{
253 LIR* lir = (LIR*) arg;
254 int offset = lir->offset;
255 int dest = lir->operands[0];
buzbee86a4bce2012-03-06 18:15:00 -0800256 const bool dumpNop = (cUnit->enableDebug & (1 << kDebugShowNops));
buzbee5de34942012-03-01 14:51:57 -0800257
258 /* Handle pseudo-ops individually, and all regular insns as a group */
259 switch(lir->opcode) {
260 case kPseudoMethodEntry:
261 LOG(INFO) << "-------- method entry " <<
262 PrettyMethod(cUnit->method_idx, *cUnit->dex_file);
263 break;
264 case kPseudoMethodExit:
265 LOG(INFO) << "-------- Method_Exit";
266 break;
267 case kPseudoBarrier:
268 LOG(INFO) << "-------- BARRIER";
269 break;
270 case kPseudoExtended:
271 LOG(INFO) << "-------- " << (char* ) dest;
272 break;
273 case kPseudoSSARep:
274 DUMP_SSA_REP(LOG(INFO) << "-------- kMirOpPhi: " << (char* ) dest);
275 break;
276 case kPseudoEntryBlock:
277 LOG(INFO) << "-------- entry offset: 0x" << std::hex << dest;
278 break;
279 case kPseudoDalvikByteCodeBoundary:
280 LOG(INFO) << "-------- dalvik offset: 0x" << std::hex <<
281 lir->dalvikOffset << " @ " << (char* )lir->operands[0];
282 break;
283 case kPseudoExitBlock:
284 LOG(INFO) << "-------- exit offset: 0x" << std::hex << dest;
285 break;
286 case kPseudoPseudoAlign4:
287 LOG(INFO) << (intptr_t)baseAddr + offset << " (0x" << std::hex <<
288 offset << "): .align4";
289 break;
290 case kPseudoEHBlockLabel:
291 LOG(INFO) << "Exception_Handling:";
292 break;
293 case kPseudoTargetLabel:
294 case kPseudoNormalBlockLabel:
295 LOG(INFO) << "L" << (intptr_t)lir << ":";
296 break;
297 case kPseudoThrowTarget:
298 LOG(INFO) << "LT" << (intptr_t)lir << ":";
299 break;
300 case kPseudoSuspendTarget:
301 LOG(INFO) << "LS" << (intptr_t)lir << ":";
302 break;
303 case kPseudoCaseLabel:
304 LOG(INFO) << "LC" << (intptr_t)lir << ": Case target 0x" <<
305 std::hex << lir->operands[0] << "|" << std::dec <<
306 lir->operands[0];
307 break;
308 default:
309 if (lir->flags.isNop && !dumpNop) {
310 break;
311 } else {
312 std::string op_name(buildInsnString(EncodingMap[lir->opcode].name, lir, baseAddr));
313 std::string op_operands(buildInsnString(EncodingMap[lir->opcode].fmt, lir, baseAddr));
buzbeebe003642012-03-02 15:28:37 -0800314 LOG(INFO) << StringPrintf("%05x: %-9s%s%s", (unsigned int)(baseAddr + offset),
buzbee5de34942012-03-01 14:51:57 -0800315 op_name.c_str(), op_operands.c_str(), lir->flags.isNop ? "(nop)" : "");
316 }
317 break;
318 }
319
320 if (lir->useMask && (!lir->flags.isNop || dumpNop)) {
321 DUMP_RESOURCE_MASK(oatDumpResourceMask((LIR* ) lir,
322 lir->useMask, "use"));
323 }
324 if (lir->defMask && (!lir->flags.isNop || dumpNop)) {
325 DUMP_RESOURCE_MASK(oatDumpResourceMask((LIR* ) lir,
326 lir->defMask, "def"));
327 }
328}
329
330void oatDumpPromotionMap(CompilationUnit *cUnit)
331{
332 for (int i = 0; i < cUnit->numDalvikRegisters; i++) {
333 PromotionMap vRegMap = cUnit->promotionMap[i];
334 char buf[100];
335 if (vRegMap.fpLocation == kLocPhysReg) {
336 snprintf(buf, 100, " : s%d", vRegMap.fpReg & FP_REG_MASK);
337 } else {
338 buf[0] = 0;
339 }
340 char buf2[100];
341 snprintf(buf2, 100, "V[%02d] -> %s%d%s", i,
342 vRegMap.coreLocation == kLocPhysReg ?
343 "r" : "SP+", vRegMap.coreLocation == kLocPhysReg ?
344 vRegMap.coreReg : oatSRegOffset(cUnit, i), buf);
345 LOG(INFO) << buf2;
346 }
347}
348
349void oatDumpFullPromotionMap(CompilationUnit *cUnit)
350{
351 for (int i = 0; i < cUnit->numDalvikRegisters; i++) {
352 PromotionMap vRegMap = cUnit->promotionMap[i];
353 LOG(INFO) << i << " -> " << "CL:" << (int)vRegMap.coreLocation <<
354 ", CR:" << (int)vRegMap.coreReg << ", FL:" <<
355 (int)vRegMap.fpLocation << ", FR:" << (int)vRegMap.fpReg <<
356 ", - " << (int)vRegMap.firstInPair;
357 }
358}
359
360/* Dump instructions and constant pool contents */
361void oatCodegenDump(CompilationUnit* cUnit)
362{
363 LOG(INFO) << "/*";
364 LOG(INFO) << "Dumping LIR insns for "
365 << PrettyMethod(cUnit->method_idx, *cUnit->dex_file);
366 LIR* lirInsn;
367 LIR* thisLIR;
368 int insnsSize = cUnit->insnsSize;
369
370 LOG(INFO) << "Regs (excluding ins) : " << cUnit->numRegs;
371 LOG(INFO) << "Ins : " << cUnit->numIns;
372 LOG(INFO) << "Outs : " << cUnit->numOuts;
373 LOG(INFO) << "CoreSpills : " << cUnit->numCoreSpills;
374 LOG(INFO) << "FPSpills : " << cUnit->numFPSpills;
buzbee5de34942012-03-01 14:51:57 -0800375 LOG(INFO) << "Frame size : " << cUnit->frameSize;
buzbee5de34942012-03-01 14:51:57 -0800376 LOG(INFO) << "code size is " << cUnit->totalSize <<
377 " bytes, Dalvik size is " << insnsSize * 2;
378 LOG(INFO) << "expansion factor: " <<
379 (float)cUnit->totalSize / (float)(insnsSize * 2);
380 oatDumpPromotionMap(cUnit);
381 for (lirInsn = cUnit->firstLIRInsn; lirInsn; lirInsn = lirInsn->next) {
382 oatDumpLIRInsn(cUnit, lirInsn, 0);
383 }
384 for (lirInsn = cUnit->classPointerList; lirInsn; lirInsn = lirInsn->next) {
385 thisLIR = (LIR*) lirInsn;
386 LOG(INFO) << StringPrintf("%x (%04x): .class (%s)",
387 thisLIR->offset, thisLIR->offset,
388 ((CallsiteInfo *) thisLIR->operands[0])->classDescriptor);
389 }
390 for (lirInsn = cUnit->literalList; lirInsn; lirInsn = lirInsn->next) {
391 thisLIR = (LIR*) lirInsn;
392 LOG(INFO) << StringPrintf("%x (%04x): .word (%#x)",
393 thisLIR->offset, thisLIR->offset, thisLIR->operands[0]);
394 }
395
396 const DexFile::MethodId& method_id =
397 cUnit->dex_file->GetMethodId(cUnit->method_idx);
398 std::string signature(cUnit->dex_file->GetMethodSignature(method_id));
399 std::string name(cUnit->dex_file->GetMethodName(method_id));
400 std::string descriptor(cUnit->dex_file->GetMethodDeclaringClassDescriptor(method_id));
401
402 // Dump mapping table
403 if (cUnit->mappingTable.size() > 0) {
404 std::string line(StringPrintf("\n MappingTable %s%s_%s_mappingTable[%zu] = {",
405 descriptor.c_str(), name.c_str(), signature.c_str(), cUnit->mappingTable.size()));
406 std::replace(line.begin(), line.end(), ';', '_');
407 LOG(INFO) << line;
408 for (uint32_t i = 0; i < cUnit->mappingTable.size(); i+=2) {
buzbee82488f52012-03-02 08:20:26 -0800409 line = StringPrintf(" {0x%05x, 0x%04x},",
buzbee5de34942012-03-01 14:51:57 -0800410 cUnit->mappingTable[i], cUnit->mappingTable[i+1]);
411 LOG(INFO) << line;
412 }
413 LOG(INFO) <<" };\n\n";
414 }
415}
416
buzbeea2ebdd72012-03-04 14:57:06 -0800417
418LIR* rawLIR(CompilationUnit* cUnit, int dalvikOffset, int opcode, int op0,
419 int op1, int op2, int op3, LIR* target)
420{
421 LIR* insn = (LIR* ) oatNew(cUnit, sizeof(LIR), true, kAllocLIR);
422 insn->dalvikOffset = dalvikOffset;
423 insn->opcode = opcode;
424 insn->operands[0] = op0;
425 insn->operands[1] = op1;
426 insn->operands[2] = op2;
427 insn->operands[3] = op3;
428 insn->target = target;
429 oatSetupResourceMasks(insn);
430 if (opcode == kPseudoTargetLabel) {
431 // Always make labels scheduling barriers
432 insn->defMask = ENCODE_ALL;
433 }
434 return insn;
435}
436
buzbee5de34942012-03-01 14:51:57 -0800437/*
buzbee31a4a6f2012-02-28 15:36:15 -0800438 * The following are building blocks to construct low-level IRs with 0 - 4
439 * operands.
440 */
buzbee5de34942012-03-01 14:51:57 -0800441LIR* newLIR0(CompilationUnit* cUnit, int opcode)
buzbee31a4a6f2012-02-28 15:36:15 -0800442{
buzbee31a4a6f2012-02-28 15:36:15 -0800443 DCHECK(isPseudoOpcode(opcode) || (EncodingMap[opcode].flags & NO_OPERAND));
buzbeea2ebdd72012-03-04 14:57:06 -0800444 LIR* insn = rawLIR(cUnit, cUnit->currentDalvikOffset, opcode);
buzbee31a4a6f2012-02-28 15:36:15 -0800445 oatAppendLIR(cUnit, (LIR*) insn);
446 return insn;
447}
448
buzbee5de34942012-03-01 14:51:57 -0800449LIR* newLIR1(CompilationUnit* cUnit, int opcode,
buzbee31a4a6f2012-02-28 15:36:15 -0800450 int dest)
451{
buzbee31a4a6f2012-02-28 15:36:15 -0800452 DCHECK(isPseudoOpcode(opcode) || (EncodingMap[opcode].flags & IS_UNARY_OP));
buzbeea2ebdd72012-03-04 14:57:06 -0800453 LIR* insn = rawLIR(cUnit, cUnit->currentDalvikOffset, opcode, dest);
buzbee31a4a6f2012-02-28 15:36:15 -0800454 oatAppendLIR(cUnit, (LIR*) insn);
455 return insn;
456}
457
buzbee5de34942012-03-01 14:51:57 -0800458LIR* newLIR2(CompilationUnit* cUnit, int opcode,
buzbee31a4a6f2012-02-28 15:36:15 -0800459 int dest, int src1)
460{
buzbee31a4a6f2012-02-28 15:36:15 -0800461 DCHECK(isPseudoOpcode(opcode) ||
462 (EncodingMap[opcode].flags & IS_BINARY_OP));
buzbeea2ebdd72012-03-04 14:57:06 -0800463 LIR* insn = rawLIR(cUnit, cUnit->currentDalvikOffset, opcode, dest, src1);
buzbee31a4a6f2012-02-28 15:36:15 -0800464 oatAppendLIR(cUnit, (LIR*) insn);
465 return insn;
466}
467
buzbee5de34942012-03-01 14:51:57 -0800468LIR* newLIR3(CompilationUnit* cUnit, int opcode,
buzbee31a4a6f2012-02-28 15:36:15 -0800469 int dest, int src1, int src2)
470{
buzbee31a4a6f2012-02-28 15:36:15 -0800471 DCHECK(isPseudoOpcode(opcode) ||
472 (EncodingMap[opcode].flags & IS_TERTIARY_OP))
473 << (int)opcode << " "
474 << PrettyMethod(cUnit->method_idx, *cUnit->dex_file) << " "
475 << cUnit->currentDalvikOffset;
buzbeea2ebdd72012-03-04 14:57:06 -0800476 LIR* insn = rawLIR(cUnit, cUnit->currentDalvikOffset, opcode, dest, src1,
477 src2);
buzbee31a4a6f2012-02-28 15:36:15 -0800478 oatAppendLIR(cUnit, (LIR*) insn);
479 return insn;
480}
481
buzbee5de34942012-03-01 14:51:57 -0800482LIR* newLIR4(CompilationUnit* cUnit, int opcode,
buzbee31a4a6f2012-02-28 15:36:15 -0800483 int dest, int src1, int src2, int info)
484{
buzbee31a4a6f2012-02-28 15:36:15 -0800485 DCHECK(isPseudoOpcode(opcode) ||
486 (EncodingMap[opcode].flags & IS_QUAD_OP));
buzbeea2ebdd72012-03-04 14:57:06 -0800487 LIR* insn = rawLIR(cUnit, cUnit->currentDalvikOffset, opcode, dest, src1,
488 src2, info);
buzbee31a4a6f2012-02-28 15:36:15 -0800489 oatAppendLIR(cUnit, (LIR*) insn);
490 return insn;
491}
buzbee31a4a6f2012-02-28 15:36:15 -0800492
493/*
494 * Search the existing constants in the literal pool for an exact or close match
495 * within specified delta (greater or equal to 0).
496 */
497LIR* scanLiteralPool(LIR* dataTarget, int value, unsigned int delta)
498{
499 while (dataTarget) {
500 if (((unsigned) (value - ((LIR* ) dataTarget)->operands[0])) <=
501 delta)
502 return (LIR* ) dataTarget;
503 dataTarget = dataTarget->next;
504 }
505 return NULL;
506}
507
508/* Search the existing constants in the literal pool for an exact wide match */
509LIR* scanLiteralPoolWide(LIR* dataTarget, int valLo, int valHi)
510{
511 bool loMatch = false;
512 LIR* loTarget = NULL;
513 while (dataTarget) {
514 if (loMatch && (((LIR*)dataTarget)->operands[0] == valHi)) {
515 return (LIR*)loTarget;
516 }
517 loMatch = false;
518 if (((LIR*)dataTarget)->operands[0] == valLo) {
519 loMatch = true;
520 loTarget = dataTarget;
521 }
522 dataTarget = dataTarget->next;
523 }
524 return NULL;
525}
526
527/*
528 * The following are building blocks to insert constants into the pool or
529 * instruction streams.
530 */
531
buzbee5de34942012-03-01 14:51:57 -0800532/* Add a 32-bit constant either in the constant pool */
buzbee31a4a6f2012-02-28 15:36:15 -0800533LIR* addWordData(CompilationUnit* cUnit, LIR* *constantListP,
534 int value)
535{
536 /* Add the constant to the literal pool */
537 if (constantListP) {
538 LIR* newValue = (LIR* ) oatNew(cUnit, sizeof(LIR), true,
539 kAllocData);
540 newValue->operands[0] = value;
541 newValue->next = *constantListP;
542 *constantListP = (LIR*) newValue;
543 return newValue;
buzbee31a4a6f2012-02-28 15:36:15 -0800544 }
545 return NULL;
546}
547
548/* Add a 64-bit constant to the constant pool or mixed with code */
549LIR* addWideData(CompilationUnit* cUnit, LIR* *constantListP,
550 int valLo, int valHi)
551{
buzbee31a4a6f2012-02-28 15:36:15 -0800552 //FIXME: hard-coded little endian, need BE variant
buzbee5de34942012-03-01 14:51:57 -0800553 // Insert high word into list first
554 addWordData(cUnit, constantListP, valHi);
555 return addWordData(cUnit, constantListP, valLo);
buzbee31a4a6f2012-02-28 15:36:15 -0800556}
557
558void pushWord(std::vector<uint16_t>&buf, int data) {
buzbeee3acd072012-02-25 17:03:10 -0800559 buf.push_back( data & 0xffff);
560 buf.push_back( (data >> 16) & 0xffff);
561}
562
563void alignBuffer(std::vector<uint16_t>&buf, size_t offset) {
564 while (buf.size() < (offset/2))
565 buf.push_back(0);
566}
567
568/* Write the literal pool to the output stream */
buzbee31a4a6f2012-02-28 15:36:15 -0800569void installLiteralPools(CompilationUnit* cUnit)
buzbeee3acd072012-02-25 17:03:10 -0800570{
571 alignBuffer(cUnit->codeBuffer, cUnit->dataOffset);
buzbee31a4a6f2012-02-28 15:36:15 -0800572 LIR* dataLIR = (LIR*) cUnit->literalList;
buzbeee3acd072012-02-25 17:03:10 -0800573 while (dataLIR != NULL) {
574 pushWord(cUnit->codeBuffer, dataLIR->operands[0]);
575 dataLIR = NEXT_LIR(dataLIR);
576 }
577}
578
579/* Write the switch tables to the output stream */
buzbee31a4a6f2012-02-28 15:36:15 -0800580void installSwitchTables(CompilationUnit* cUnit)
buzbeee3acd072012-02-25 17:03:10 -0800581{
582 GrowableListIterator iterator;
583 oatGrowableListIteratorInit(&cUnit->switchTables, &iterator);
584 while (true) {
585 SwitchTable* tabRec = (SwitchTable *) oatGrowableListIteratorNext(
586 &iterator);
587 if (tabRec == NULL) break;
588 alignBuffer(cUnit->codeBuffer, tabRec->offset);
buzbeec5159d52012-03-03 11:48:39 -0800589 /*
590 * For Arm, our reference point is the address of the bx
591 * instruction that does the launch, so we have to subtract
592 * the auto pc-advance. For other targets the reference point
593 * is a label, so we can use the offset as-is.
594 */
595#if defined(TARGET_ARM)
596 int bxOffset = tabRec->anchor->offset + 4;
597#else
598 int bxOffset = tabRec->anchor->offset;
599#endif
buzbeee3acd072012-02-25 17:03:10 -0800600 if (cUnit->printMe) {
601 LOG(INFO) << "Switch table for offset 0x" << std::hex << bxOffset;
602 }
Elliott Hughesadb8c672012-03-06 16:49:32 -0800603 if (tabRec->table[0] == Instruction::kSparseSwitchSignature) {
buzbeee3acd072012-02-25 17:03:10 -0800604 int* keys = (int*)&(tabRec->table[2]);
605 for (int elems = 0; elems < tabRec->table[1]; elems++) {
buzbee31a4a6f2012-02-28 15:36:15 -0800606 int disp = tabRec->targets[elems]->offset - bxOffset;
buzbeee3acd072012-02-25 17:03:10 -0800607 if (cUnit->printMe) {
608 LOG(INFO) << " Case[" << elems << "] key: 0x" <<
609 std::hex << keys[elems] << ", disp: 0x" <<
610 std::hex << disp;
611 }
612 pushWord(cUnit->codeBuffer, keys[elems]);
613 pushWord(cUnit->codeBuffer,
buzbee31a4a6f2012-02-28 15:36:15 -0800614 tabRec->targets[elems]->offset - bxOffset);
buzbeee3acd072012-02-25 17:03:10 -0800615 }
616 } else {
Elliott Hughesadb8c672012-03-06 16:49:32 -0800617 DCHECK_EQ(static_cast<int>(tabRec->table[0]), static_cast<int>(Instruction::kPackedSwitchSignature));
buzbeee3acd072012-02-25 17:03:10 -0800618 for (int elems = 0; elems < tabRec->table[1]; elems++) {
buzbee31a4a6f2012-02-28 15:36:15 -0800619 int disp = tabRec->targets[elems]->offset - bxOffset;
buzbeee3acd072012-02-25 17:03:10 -0800620 if (cUnit->printMe) {
621 LOG(INFO) << " Case[" << elems << "] disp: 0x" <<
622 std::hex << disp;
623 }
624 pushWord(cUnit->codeBuffer,
buzbee31a4a6f2012-02-28 15:36:15 -0800625 tabRec->targets[elems]->offset - bxOffset);
buzbeee3acd072012-02-25 17:03:10 -0800626 }
627 }
628 }
629}
630
631/* Write the fill array dta to the output stream */
buzbee31a4a6f2012-02-28 15:36:15 -0800632void installFillArrayData(CompilationUnit* cUnit)
buzbeee3acd072012-02-25 17:03:10 -0800633{
634 GrowableListIterator iterator;
635 oatGrowableListIteratorInit(&cUnit->fillArrayData, &iterator);
636 while (true) {
637 FillArrayData *tabRec = (FillArrayData *) oatGrowableListIteratorNext(
638 &iterator);
639 if (tabRec == NULL) break;
640 alignBuffer(cUnit->codeBuffer, tabRec->offset);
641 for (int i = 0; i < ((tabRec->size + 1) / 2) ; i++) {
642 cUnit->codeBuffer.push_back( tabRec->table[i]);
643 }
644 }
645}
646
buzbee31a4a6f2012-02-28 15:36:15 -0800647int assignLiteralOffsetCommon(LIR* lir, int offset)
buzbeee3acd072012-02-25 17:03:10 -0800648{
649 for (;lir != NULL; lir = lir->next) {
650 lir->offset = offset;
651 offset += 4;
652 }
653 return offset;
654}
655
buzbee31a4a6f2012-02-28 15:36:15 -0800656void createMappingTable(CompilationUnit* cUnit)
buzbeee3acd072012-02-25 17:03:10 -0800657{
buzbee31a4a6f2012-02-28 15:36:15 -0800658 LIR* tgtLIR;
buzbeee3acd072012-02-25 17:03:10 -0800659 int currentDalvikOffset = -1;
660
buzbee31a4a6f2012-02-28 15:36:15 -0800661 for (tgtLIR = (LIR *) cUnit->firstLIRInsn;
buzbeee3acd072012-02-25 17:03:10 -0800662 tgtLIR;
663 tgtLIR = NEXT_LIR(tgtLIR)) {
664 if ((tgtLIR->opcode >= 0) && !tgtLIR->flags.isNop &&
buzbee31a4a6f2012-02-28 15:36:15 -0800665 (currentDalvikOffset != tgtLIR->dalvikOffset)) {
buzbeee3acd072012-02-25 17:03:10 -0800666 // Changed - need to emit a record
buzbee31a4a6f2012-02-28 15:36:15 -0800667 cUnit->mappingTable.push_back(tgtLIR->offset);
668 cUnit->mappingTable.push_back(tgtLIR->dalvikOffset);
669 currentDalvikOffset = tgtLIR->dalvikOffset;
buzbeee3acd072012-02-25 17:03:10 -0800670 }
671 }
672}
673
674/* Determine the offset of each literal field */
buzbee31a4a6f2012-02-28 15:36:15 -0800675int assignLiteralOffset(CompilationUnit* cUnit, int offset)
buzbeee3acd072012-02-25 17:03:10 -0800676{
677 offset = assignLiteralOffsetCommon(cUnit->literalList, offset);
678 return offset;
679}
680
buzbee31a4a6f2012-02-28 15:36:15 -0800681int assignSwitchTablesOffset(CompilationUnit* cUnit, int offset)
buzbeee3acd072012-02-25 17:03:10 -0800682{
683 GrowableListIterator iterator;
684 oatGrowableListIteratorInit(&cUnit->switchTables, &iterator);
685 while (true) {
686 SwitchTable *tabRec = (SwitchTable *) oatGrowableListIteratorNext(
687 &iterator);
688 if (tabRec == NULL) break;
689 tabRec->offset = offset;
Elliott Hughesadb8c672012-03-06 16:49:32 -0800690 if (tabRec->table[0] == Instruction::kSparseSwitchSignature) {
buzbeee3acd072012-02-25 17:03:10 -0800691 offset += tabRec->table[1] * (sizeof(int) * 2);
692 } else {
Elliott Hughesadb8c672012-03-06 16:49:32 -0800693 DCHECK_EQ(static_cast<int>(tabRec->table[0]), static_cast<int>(Instruction::kPackedSwitchSignature));
buzbeee3acd072012-02-25 17:03:10 -0800694 offset += tabRec->table[1] * sizeof(int);
695 }
696 }
697 return offset;
698}
699
buzbee31a4a6f2012-02-28 15:36:15 -0800700int assignFillArrayDataOffset(CompilationUnit* cUnit, int offset)
buzbeee3acd072012-02-25 17:03:10 -0800701{
702 GrowableListIterator iterator;
703 oatGrowableListIteratorInit(&cUnit->fillArrayData, &iterator);
704 while (true) {
705 FillArrayData *tabRec = (FillArrayData *) oatGrowableListIteratorNext(
706 &iterator);
707 if (tabRec == NULL) break;
708 tabRec->offset = offset;
709 offset += tabRec->size;
710 // word align
711 offset = (offset + 3) & ~3;
712 }
713 return offset;
714}
715
716/*
717 * Walk the compilation unit and assign offsets to instructions
718 * and literals and compute the total size of the compiled unit.
719 */
720void oatAssignOffsets(CompilationUnit* cUnit)
721{
722 int offset = oatAssignInsnOffsets(cUnit);
723
724 /* Const values have to be word aligned */
725 offset = (offset + 3) & ~3;
726
727 /* Set up offsets for literals */
728 cUnit->dataOffset = offset;
729
730 offset = assignLiteralOffset(cUnit, offset);
731
732 offset = assignSwitchTablesOffset(cUnit, offset);
733
734 offset = assignFillArrayDataOffset(cUnit, offset);
735
736 cUnit->totalSize = offset;
737}
738
739/*
740 * Go over each instruction in the list and calculate the offset from the top
741 * before sending them off to the assembler. If out-of-range branch distance is
742 * seen rearrange the instructions a bit to correct it.
743 */
744void oatAssembleLIR(CompilationUnit* cUnit)
745{
746 oatAssignOffsets(cUnit);
747 /*
748 * Assemble here. Note that we generate code with optimistic assumptions
749 * and if found now to work, we'll have to redo the sequence and retry.
750 */
751
752 while (true) {
753 AssemblerStatus res = oatAssembleInstructions(cUnit, 0);
754 if (res == kSuccess) {
755 break;
756 } else {
757 cUnit->assemblerRetries++;
758 if (cUnit->assemblerRetries > MAX_ASSEMBLER_RETRIES) {
759 LOG(FATAL) << "Assembler error - too many retries";
760 }
761 // Redo offsets and try again
762 oatAssignOffsets(cUnit);
763 cUnit->codeBuffer.clear();
764 }
765 }
766
767 // Install literals
768 installLiteralPools(cUnit);
769
770 // Install switch tables
771 installSwitchTables(cUnit);
772
773 // Install fill array data
774 installFillArrayData(cUnit);
775
776 /*
777 * Create the mapping table
778 */
779 createMappingTable(cUnit);
780}
781
buzbee31a4a6f2012-02-28 15:36:15 -0800782/*
783 * Insert a kPseudoCaseLabel at the beginning of the Dalvik
784 * offset vaddr. This label will be used to fix up the case
785 * branch table during the assembly phase. Be sure to set
786 * all resource flags on this to prevent code motion across
787 * target boundaries. KeyVal is just there for debugging.
788 */
789LIR* insertCaseLabel(CompilationUnit* cUnit, int vaddr, int keyVal)
790{
791 std::map<unsigned int, LIR*>::iterator it;
792 it = cUnit->boundaryMap.find(vaddr);
793 if (it == cUnit->boundaryMap.end()) {
794 LOG(FATAL) << "Error: didn't find vaddr 0x" << std::hex << vaddr;
795 }
796 LIR* newLabel = (LIR*)oatNew(cUnit, sizeof(LIR), true, kAllocLIR);
797 newLabel->dalvikOffset = vaddr;
798 newLabel->opcode = kPseudoCaseLabel;
799 newLabel->operands[0] = keyVal;
800 oatInsertLIRAfter(it->second, (LIR*)newLabel);
801 return newLabel;
802}
803
804void markPackedCaseLabels(CompilationUnit* cUnit, SwitchTable *tabRec)
805{
806 const u2* table = tabRec->table;
807 int baseVaddr = tabRec->vaddr;
808 int *targets = (int*)&table[4];
809 int entries = table[1];
810 int lowKey = s4FromSwitchData(&table[2]);
811 for (int i = 0; i < entries; i++) {
812 tabRec->targets[i] = insertCaseLabel(cUnit, baseVaddr + targets[i],
813 i + lowKey);
814 }
815}
816
817void markSparseCaseLabels(CompilationUnit* cUnit, SwitchTable *tabRec)
818{
819 const u2* table = tabRec->table;
820 int baseVaddr = tabRec->vaddr;
821 int entries = table[1];
822 int* keys = (int*)&table[2];
823 int* targets = &keys[entries];
824 for (int i = 0; i < entries; i++) {
825 tabRec->targets[i] = insertCaseLabel(cUnit, baseVaddr + targets[i],
826 keys[i]);
827 }
828}
829
830void oatProcessSwitchTables(CompilationUnit* cUnit)
831{
832 GrowableListIterator iterator;
833 oatGrowableListIteratorInit(&cUnit->switchTables, &iterator);
834 while (true) {
835 SwitchTable *tabRec = (SwitchTable *) oatGrowableListIteratorNext(
836 &iterator);
837 if (tabRec == NULL) break;
Elliott Hughesadb8c672012-03-06 16:49:32 -0800838 if (tabRec->table[0] == Instruction::kPackedSwitchSignature) {
buzbee31a4a6f2012-02-28 15:36:15 -0800839 markPackedCaseLabels(cUnit, tabRec);
Elliott Hughesadb8c672012-03-06 16:49:32 -0800840 } else if (tabRec->table[0] == Instruction::kSparseSwitchSignature) {
buzbee31a4a6f2012-02-28 15:36:15 -0800841 markSparseCaseLabels(cUnit, tabRec);
Elliott Hughesadb8c672012-03-06 16:49:32 -0800842 } else {
buzbee31a4a6f2012-02-28 15:36:15 -0800843 LOG(FATAL) << "Invalid switch table";
844 }
845 }
846}
847
848//FIXME: Do we have endian issues here?
849
850void dumpSparseSwitchTable(const u2* table)
851 /*
852 * Sparse switch data format:
853 * ushort ident = 0x0200 magic value
854 * ushort size number of entries in the table; > 0
855 * int keys[size] keys, sorted low-to-high; 32-bit aligned
856 * int targets[size] branch targets, relative to switch opcode
857 *
858 * Total size is (2+size*4) 16-bit code units.
859 */
860{
861 u2 ident = table[0];
862 int entries = table[1];
863 int* keys = (int*)&table[2];
864 int* targets = &keys[entries];
865 LOG(INFO) << "Sparse switch table - ident:0x" << std::hex << ident <<
866 ", entries: " << std::dec << entries;
867 for (int i = 0; i < entries; i++) {
868 LOG(INFO) << " Key[" << keys[i] << "] -> 0x" << std::hex <<
869 targets[i];
870 }
871}
872
873void dumpPackedSwitchTable(const u2* table)
874 /*
875 * Packed switch data format:
876 * ushort ident = 0x0100 magic value
877 * ushort size number of entries in the table
878 * int first_key first (and lowest) switch case value
879 * int targets[size] branch targets, relative to switch opcode
880 *
881 * Total size is (4+size*2) 16-bit code units.
882 */
883{
884 u2 ident = table[0];
885 int* targets = (int*)&table[4];
886 int entries = table[1];
887 int lowKey = s4FromSwitchData(&table[2]);
888 LOG(INFO) << "Packed switch table - ident:0x" << std::hex << ident <<
889 ", entries: " << std::dec << entries << ", lowKey: " << lowKey;
890 for (int i = 0; i < entries; i++) {
891 LOG(INFO) << " Key[" << (i + lowKey) << "] -> 0x" << std::hex <<
892 targets[i];
893 }
894}
buzbeee3acd072012-02-25 17:03:10 -0800895
896
897} // namespace art