blob: 07eb672eebb03f43f27e27ea85c206a491298fc9 [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
118 /* Set up the mask for resources that are updated */
119 if (flags & (IS_LOAD | IS_STORE)) {
120 /* Default to heap - will catch specialized classes later */
121 setMemRefType(lir, flags & IS_LOAD, kHeapRef);
122 }
123
124 /*
125 * Conservatively assume the branch here will call out a function that in
126 * turn will trash everything.
127 */
128 if (flags & IS_BRANCH) {
129 lir->defMask = lir->useMask = ENCODE_ALL;
130 return;
131 }
132
133 if (flags & REG_DEF0) {
134 setupRegMask(&lir->defMask, lir->operands[0]);
135 }
136
137 if (flags & REG_DEF1) {
138 setupRegMask(&lir->defMask, lir->operands[1]);
139 }
140
141 if (flags & REG_DEF_SP) {
142 lir->defMask |= ENCODE_REG_SP;
143 }
144
145 if (flags & REG_DEF_LR) {
146 lir->defMask |= ENCODE_REG_LR;
147 }
148
149 if (flags & REG_DEF_LIST0) {
150 lir->defMask |= ENCODE_REG_LIST(lir->operands[0]);
151 }
152
153 if (flags & REG_DEF_LIST1) {
154 lir->defMask |= ENCODE_REG_LIST(lir->operands[1]);
155 }
156
buzbee5de34942012-03-01 14:51:57 -0800157#if defined(TARGET_ARM)
buzbee31a4a6f2012-02-28 15:36:15 -0800158 if (flags & REG_DEF_FPCS_LIST0) {
159 lir->defMask |= ENCODE_REG_FPCS_LIST(lir->operands[0]);
160 }
161
162 if (flags & REG_DEF_FPCS_LIST2) {
163 for (int i = 0; i < lir->operands[2]; i++) {
164 setupRegMask(&lir->defMask, lir->operands[1] + i);
165 }
166 }
buzbee5de34942012-03-01 14:51:57 -0800167#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800168
169 if (flags & SETS_CCODES) {
170 lir->defMask |= ENCODE_CCODE;
171 }
172
173#if defined(TARGET_ARM)
174 /* Conservatively treat the IT block */
175 if (flags & IS_IT) {
176 lir->defMask = ENCODE_ALL;
177 }
178#endif
179
180 if (flags & (REG_USE0 | REG_USE1 | REG_USE2 | REG_USE3)) {
181 int i;
182
183 for (i = 0; i < 4; i++) {
184 if (flags & (1 << (kRegUse0 + i))) {
185 setupRegMask(&lir->useMask, lir->operands[i]);
186 }
187 }
188 }
189
190 if (flags & REG_USE_PC) {
191 lir->useMask |= ENCODE_REG_PC;
192 }
193
194 if (flags & REG_USE_SP) {
195 lir->useMask |= ENCODE_REG_SP;
196 }
197
198 if (flags & REG_USE_LIST0) {
199 lir->useMask |= ENCODE_REG_LIST(lir->operands[0]);
200 }
201
202 if (flags & REG_USE_LIST1) {
203 lir->useMask |= ENCODE_REG_LIST(lir->operands[1]);
204 }
205
buzbee5de34942012-03-01 14:51:57 -0800206#if defined(TARGET_ARM)
buzbee31a4a6f2012-02-28 15:36:15 -0800207 if (flags & REG_USE_FPCS_LIST0) {
208 lir->useMask |= ENCODE_REG_FPCS_LIST(lir->operands[0]);
209 }
210
211 if (flags & REG_USE_FPCS_LIST2) {
212 for (int i = 0; i < lir->operands[2]; i++) {
213 setupRegMask(&lir->useMask, lir->operands[1] + i);
214 }
215 }
buzbee5de34942012-03-01 14:51:57 -0800216#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800217
218 if (flags & USES_CCODES) {
219 lir->useMask |= ENCODE_CCODE;
220 }
221
222#if defined(TARGET_ARM)
223 /* Fixup for kThumbPush/lr and kThumbPop/pc */
224 if (opcode == kThumbPush || opcode == kThumbPop) {
225 u8 r8Mask = getRegMaskCommon(r8);
226 if ((opcode == kThumbPush) && (lir->useMask & r8Mask)) {
227 lir->useMask &= ~r8Mask;
228 lir->useMask |= ENCODE_REG_LR;
229 } else if ((opcode == kThumbPop) && (lir->defMask & r8Mask)) {
230 lir->defMask &= ~r8Mask;
231 lir->defMask |= ENCODE_REG_PC;
232 }
233 }
234#endif
235}
236
237/*
buzbee5de34942012-03-01 14:51:57 -0800238 * Debugging macros
239 */
240#define DUMP_RESOURCE_MASK(X)
241#define DUMP_SSA_REP(X)
242
243/* Pretty-print a LIR instruction */
244void oatDumpLIRInsn(CompilationUnit* cUnit, LIR* arg, unsigned char* baseAddr)
245{
246 LIR* lir = (LIR*) arg;
247 int offset = lir->offset;
248 int dest = lir->operands[0];
249 const bool dumpNop = false;
250
251 /* Handle pseudo-ops individually, and all regular insns as a group */
252 switch(lir->opcode) {
253 case kPseudoMethodEntry:
254 LOG(INFO) << "-------- method entry " <<
255 PrettyMethod(cUnit->method_idx, *cUnit->dex_file);
256 break;
257 case kPseudoMethodExit:
258 LOG(INFO) << "-------- Method_Exit";
259 break;
260 case kPseudoBarrier:
261 LOG(INFO) << "-------- BARRIER";
262 break;
263 case kPseudoExtended:
264 LOG(INFO) << "-------- " << (char* ) dest;
265 break;
266 case kPseudoSSARep:
267 DUMP_SSA_REP(LOG(INFO) << "-------- kMirOpPhi: " << (char* ) dest);
268 break;
269 case kPseudoEntryBlock:
270 LOG(INFO) << "-------- entry offset: 0x" << std::hex << dest;
271 break;
272 case kPseudoDalvikByteCodeBoundary:
273 LOG(INFO) << "-------- dalvik offset: 0x" << std::hex <<
274 lir->dalvikOffset << " @ " << (char* )lir->operands[0];
275 break;
276 case kPseudoExitBlock:
277 LOG(INFO) << "-------- exit offset: 0x" << std::hex << dest;
278 break;
279 case kPseudoPseudoAlign4:
280 LOG(INFO) << (intptr_t)baseAddr + offset << " (0x" << std::hex <<
281 offset << "): .align4";
282 break;
283 case kPseudoEHBlockLabel:
284 LOG(INFO) << "Exception_Handling:";
285 break;
286 case kPseudoTargetLabel:
287 case kPseudoNormalBlockLabel:
288 LOG(INFO) << "L" << (intptr_t)lir << ":";
289 break;
290 case kPseudoThrowTarget:
291 LOG(INFO) << "LT" << (intptr_t)lir << ":";
292 break;
293 case kPseudoSuspendTarget:
294 LOG(INFO) << "LS" << (intptr_t)lir << ":";
295 break;
296 case kPseudoCaseLabel:
297 LOG(INFO) << "LC" << (intptr_t)lir << ": Case target 0x" <<
298 std::hex << lir->operands[0] << "|" << std::dec <<
299 lir->operands[0];
300 break;
301 default:
302 if (lir->flags.isNop && !dumpNop) {
303 break;
304 } else {
305 std::string op_name(buildInsnString(EncodingMap[lir->opcode].name, lir, baseAddr));
306 std::string op_operands(buildInsnString(EncodingMap[lir->opcode].fmt, lir, baseAddr));
buzbeebe003642012-03-02 15:28:37 -0800307 LOG(INFO) << StringPrintf("%05x: %-9s%s%s", (unsigned int)(baseAddr + offset),
buzbee5de34942012-03-01 14:51:57 -0800308 op_name.c_str(), op_operands.c_str(), lir->flags.isNop ? "(nop)" : "");
309 }
310 break;
311 }
312
313 if (lir->useMask && (!lir->flags.isNop || dumpNop)) {
314 DUMP_RESOURCE_MASK(oatDumpResourceMask((LIR* ) lir,
315 lir->useMask, "use"));
316 }
317 if (lir->defMask && (!lir->flags.isNop || dumpNop)) {
318 DUMP_RESOURCE_MASK(oatDumpResourceMask((LIR* ) lir,
319 lir->defMask, "def"));
320 }
321}
322
323void oatDumpPromotionMap(CompilationUnit *cUnit)
324{
325 for (int i = 0; i < cUnit->numDalvikRegisters; i++) {
326 PromotionMap vRegMap = cUnit->promotionMap[i];
327 char buf[100];
328 if (vRegMap.fpLocation == kLocPhysReg) {
329 snprintf(buf, 100, " : s%d", vRegMap.fpReg & FP_REG_MASK);
330 } else {
331 buf[0] = 0;
332 }
333 char buf2[100];
334 snprintf(buf2, 100, "V[%02d] -> %s%d%s", i,
335 vRegMap.coreLocation == kLocPhysReg ?
336 "r" : "SP+", vRegMap.coreLocation == kLocPhysReg ?
337 vRegMap.coreReg : oatSRegOffset(cUnit, i), buf);
338 LOG(INFO) << buf2;
339 }
340}
341
342void oatDumpFullPromotionMap(CompilationUnit *cUnit)
343{
344 for (int i = 0; i < cUnit->numDalvikRegisters; i++) {
345 PromotionMap vRegMap = cUnit->promotionMap[i];
346 LOG(INFO) << i << " -> " << "CL:" << (int)vRegMap.coreLocation <<
347 ", CR:" << (int)vRegMap.coreReg << ", FL:" <<
348 (int)vRegMap.fpLocation << ", FR:" << (int)vRegMap.fpReg <<
349 ", - " << (int)vRegMap.firstInPair;
350 }
351}
352
353/* Dump instructions and constant pool contents */
354void oatCodegenDump(CompilationUnit* cUnit)
355{
356 LOG(INFO) << "/*";
357 LOG(INFO) << "Dumping LIR insns for "
358 << PrettyMethod(cUnit->method_idx, *cUnit->dex_file);
359 LIR* lirInsn;
360 LIR* thisLIR;
361 int insnsSize = cUnit->insnsSize;
362
363 LOG(INFO) << "Regs (excluding ins) : " << cUnit->numRegs;
364 LOG(INFO) << "Ins : " << cUnit->numIns;
365 LOG(INFO) << "Outs : " << cUnit->numOuts;
366 LOG(INFO) << "CoreSpills : " << cUnit->numCoreSpills;
367 LOG(INFO) << "FPSpills : " << cUnit->numFPSpills;
368 LOG(INFO) << "Padding : " << cUnit->numPadding;
369 LOG(INFO) << "Frame size : " << cUnit->frameSize;
370 LOG(INFO) << "Start of ins : " << cUnit->insOffset;
371 LOG(INFO) << "Start of regs : " << cUnit->regsOffset;
372 LOG(INFO) << "code size is " << cUnit->totalSize <<
373 " bytes, Dalvik size is " << insnsSize * 2;
374 LOG(INFO) << "expansion factor: " <<
375 (float)cUnit->totalSize / (float)(insnsSize * 2);
376 oatDumpPromotionMap(cUnit);
377 for (lirInsn = cUnit->firstLIRInsn; lirInsn; lirInsn = lirInsn->next) {
378 oatDumpLIRInsn(cUnit, lirInsn, 0);
379 }
380 for (lirInsn = cUnit->classPointerList; lirInsn; lirInsn = lirInsn->next) {
381 thisLIR = (LIR*) lirInsn;
382 LOG(INFO) << StringPrintf("%x (%04x): .class (%s)",
383 thisLIR->offset, thisLIR->offset,
384 ((CallsiteInfo *) thisLIR->operands[0])->classDescriptor);
385 }
386 for (lirInsn = cUnit->literalList; lirInsn; lirInsn = lirInsn->next) {
387 thisLIR = (LIR*) lirInsn;
388 LOG(INFO) << StringPrintf("%x (%04x): .word (%#x)",
389 thisLIR->offset, thisLIR->offset, thisLIR->operands[0]);
390 }
391
392 const DexFile::MethodId& method_id =
393 cUnit->dex_file->GetMethodId(cUnit->method_idx);
394 std::string signature(cUnit->dex_file->GetMethodSignature(method_id));
395 std::string name(cUnit->dex_file->GetMethodName(method_id));
396 std::string descriptor(cUnit->dex_file->GetMethodDeclaringClassDescriptor(method_id));
397
398 // Dump mapping table
399 if (cUnit->mappingTable.size() > 0) {
400 std::string line(StringPrintf("\n MappingTable %s%s_%s_mappingTable[%zu] = {",
401 descriptor.c_str(), name.c_str(), signature.c_str(), cUnit->mappingTable.size()));
402 std::replace(line.begin(), line.end(), ';', '_');
403 LOG(INFO) << line;
404 for (uint32_t i = 0; i < cUnit->mappingTable.size(); i+=2) {
buzbee82488f52012-03-02 08:20:26 -0800405 line = StringPrintf(" {0x%05x, 0x%04x},",
buzbee5de34942012-03-01 14:51:57 -0800406 cUnit->mappingTable[i], cUnit->mappingTable[i+1]);
407 LOG(INFO) << line;
408 }
409 LOG(INFO) <<" };\n\n";
410 }
411}
412
buzbeea2ebdd72012-03-04 14:57:06 -0800413
414LIR* rawLIR(CompilationUnit* cUnit, int dalvikOffset, int opcode, int op0,
415 int op1, int op2, int op3, LIR* target)
416{
417 LIR* insn = (LIR* ) oatNew(cUnit, sizeof(LIR), true, kAllocLIR);
418 insn->dalvikOffset = dalvikOffset;
419 insn->opcode = opcode;
420 insn->operands[0] = op0;
421 insn->operands[1] = op1;
422 insn->operands[2] = op2;
423 insn->operands[3] = op3;
424 insn->target = target;
425 oatSetupResourceMasks(insn);
426 if (opcode == kPseudoTargetLabel) {
427 // Always make labels scheduling barriers
428 insn->defMask = ENCODE_ALL;
429 }
430 return insn;
431}
432
buzbee5de34942012-03-01 14:51:57 -0800433/*
buzbee31a4a6f2012-02-28 15:36:15 -0800434 * The following are building blocks to construct low-level IRs with 0 - 4
435 * operands.
436 */
buzbee5de34942012-03-01 14:51:57 -0800437LIR* newLIR0(CompilationUnit* cUnit, int opcode)
buzbee31a4a6f2012-02-28 15:36:15 -0800438{
buzbee31a4a6f2012-02-28 15:36:15 -0800439 DCHECK(isPseudoOpcode(opcode) || (EncodingMap[opcode].flags & NO_OPERAND));
buzbeea2ebdd72012-03-04 14:57:06 -0800440 LIR* insn = rawLIR(cUnit, cUnit->currentDalvikOffset, opcode);
buzbee31a4a6f2012-02-28 15:36:15 -0800441 oatAppendLIR(cUnit, (LIR*) insn);
442 return insn;
443}
444
buzbee5de34942012-03-01 14:51:57 -0800445LIR* newLIR1(CompilationUnit* cUnit, int opcode,
buzbee31a4a6f2012-02-28 15:36:15 -0800446 int dest)
447{
buzbee31a4a6f2012-02-28 15:36:15 -0800448 DCHECK(isPseudoOpcode(opcode) || (EncodingMap[opcode].flags & IS_UNARY_OP));
buzbeea2ebdd72012-03-04 14:57:06 -0800449 LIR* insn = rawLIR(cUnit, cUnit->currentDalvikOffset, opcode, dest);
buzbee31a4a6f2012-02-28 15:36:15 -0800450 oatAppendLIR(cUnit, (LIR*) insn);
451 return insn;
452}
453
buzbee5de34942012-03-01 14:51:57 -0800454LIR* newLIR2(CompilationUnit* cUnit, int opcode,
buzbee31a4a6f2012-02-28 15:36:15 -0800455 int dest, int src1)
456{
buzbee31a4a6f2012-02-28 15:36:15 -0800457 DCHECK(isPseudoOpcode(opcode) ||
458 (EncodingMap[opcode].flags & IS_BINARY_OP));
buzbeea2ebdd72012-03-04 14:57:06 -0800459 LIR* insn = rawLIR(cUnit, cUnit->currentDalvikOffset, opcode, dest, src1);
buzbee31a4a6f2012-02-28 15:36:15 -0800460 oatAppendLIR(cUnit, (LIR*) insn);
461 return insn;
462}
463
buzbee5de34942012-03-01 14:51:57 -0800464LIR* newLIR3(CompilationUnit* cUnit, int opcode,
buzbee31a4a6f2012-02-28 15:36:15 -0800465 int dest, int src1, int src2)
466{
buzbee31a4a6f2012-02-28 15:36:15 -0800467 DCHECK(isPseudoOpcode(opcode) ||
468 (EncodingMap[opcode].flags & IS_TERTIARY_OP))
469 << (int)opcode << " "
470 << PrettyMethod(cUnit->method_idx, *cUnit->dex_file) << " "
471 << cUnit->currentDalvikOffset;
buzbeea2ebdd72012-03-04 14:57:06 -0800472 LIR* insn = rawLIR(cUnit, cUnit->currentDalvikOffset, opcode, dest, src1,
473 src2);
buzbee31a4a6f2012-02-28 15:36:15 -0800474 oatAppendLIR(cUnit, (LIR*) insn);
475 return insn;
476}
477
buzbee5de34942012-03-01 14:51:57 -0800478LIR* newLIR4(CompilationUnit* cUnit, int opcode,
buzbee31a4a6f2012-02-28 15:36:15 -0800479 int dest, int src1, int src2, int info)
480{
buzbee31a4a6f2012-02-28 15:36:15 -0800481 DCHECK(isPseudoOpcode(opcode) ||
482 (EncodingMap[opcode].flags & IS_QUAD_OP));
buzbeea2ebdd72012-03-04 14:57:06 -0800483 LIR* insn = rawLIR(cUnit, cUnit->currentDalvikOffset, opcode, dest, src1,
484 src2, info);
buzbee31a4a6f2012-02-28 15:36:15 -0800485 oatAppendLIR(cUnit, (LIR*) insn);
486 return insn;
487}
buzbee31a4a6f2012-02-28 15:36:15 -0800488
489/*
490 * Search the existing constants in the literal pool for an exact or close match
491 * within specified delta (greater or equal to 0).
492 */
493LIR* scanLiteralPool(LIR* dataTarget, int value, unsigned int delta)
494{
495 while (dataTarget) {
496 if (((unsigned) (value - ((LIR* ) dataTarget)->operands[0])) <=
497 delta)
498 return (LIR* ) dataTarget;
499 dataTarget = dataTarget->next;
500 }
501 return NULL;
502}
503
504/* Search the existing constants in the literal pool for an exact wide match */
505LIR* scanLiteralPoolWide(LIR* dataTarget, int valLo, int valHi)
506{
507 bool loMatch = false;
508 LIR* loTarget = NULL;
509 while (dataTarget) {
510 if (loMatch && (((LIR*)dataTarget)->operands[0] == valHi)) {
511 return (LIR*)loTarget;
512 }
513 loMatch = false;
514 if (((LIR*)dataTarget)->operands[0] == valLo) {
515 loMatch = true;
516 loTarget = dataTarget;
517 }
518 dataTarget = dataTarget->next;
519 }
520 return NULL;
521}
522
523/*
524 * The following are building blocks to insert constants into the pool or
525 * instruction streams.
526 */
527
buzbee5de34942012-03-01 14:51:57 -0800528/* Add a 32-bit constant either in the constant pool */
buzbee31a4a6f2012-02-28 15:36:15 -0800529LIR* addWordData(CompilationUnit* cUnit, LIR* *constantListP,
530 int value)
531{
532 /* Add the constant to the literal pool */
533 if (constantListP) {
534 LIR* newValue = (LIR* ) oatNew(cUnit, sizeof(LIR), true,
535 kAllocData);
536 newValue->operands[0] = value;
537 newValue->next = *constantListP;
538 *constantListP = (LIR*) newValue;
539 return newValue;
buzbee31a4a6f2012-02-28 15:36:15 -0800540 }
541 return NULL;
542}
543
544/* Add a 64-bit constant to the constant pool or mixed with code */
545LIR* addWideData(CompilationUnit* cUnit, LIR* *constantListP,
546 int valLo, int valHi)
547{
buzbee31a4a6f2012-02-28 15:36:15 -0800548 //FIXME: hard-coded little endian, need BE variant
buzbee5de34942012-03-01 14:51:57 -0800549 // Insert high word into list first
550 addWordData(cUnit, constantListP, valHi);
551 return addWordData(cUnit, constantListP, valLo);
buzbee31a4a6f2012-02-28 15:36:15 -0800552}
553
554void pushWord(std::vector<uint16_t>&buf, int data) {
buzbeee3acd072012-02-25 17:03:10 -0800555 buf.push_back( data & 0xffff);
556 buf.push_back( (data >> 16) & 0xffff);
557}
558
559void alignBuffer(std::vector<uint16_t>&buf, size_t offset) {
560 while (buf.size() < (offset/2))
561 buf.push_back(0);
562}
563
564/* Write the literal pool to the output stream */
buzbee31a4a6f2012-02-28 15:36:15 -0800565void installLiteralPools(CompilationUnit* cUnit)
buzbeee3acd072012-02-25 17:03:10 -0800566{
567 alignBuffer(cUnit->codeBuffer, cUnit->dataOffset);
buzbee31a4a6f2012-02-28 15:36:15 -0800568 LIR* dataLIR = (LIR*) cUnit->literalList;
buzbeee3acd072012-02-25 17:03:10 -0800569 while (dataLIR != NULL) {
570 pushWord(cUnit->codeBuffer, dataLIR->operands[0]);
571 dataLIR = NEXT_LIR(dataLIR);
572 }
573}
574
575/* Write the switch tables to the output stream */
buzbee31a4a6f2012-02-28 15:36:15 -0800576void installSwitchTables(CompilationUnit* cUnit)
buzbeee3acd072012-02-25 17:03:10 -0800577{
578 GrowableListIterator iterator;
579 oatGrowableListIteratorInit(&cUnit->switchTables, &iterator);
580 while (true) {
581 SwitchTable* tabRec = (SwitchTable *) oatGrowableListIteratorNext(
582 &iterator);
583 if (tabRec == NULL) break;
584 alignBuffer(cUnit->codeBuffer, tabRec->offset);
buzbeec5159d52012-03-03 11:48:39 -0800585 /*
586 * For Arm, our reference point is the address of the bx
587 * instruction that does the launch, so we have to subtract
588 * the auto pc-advance. For other targets the reference point
589 * is a label, so we can use the offset as-is.
590 */
591#if defined(TARGET_ARM)
592 int bxOffset = tabRec->anchor->offset + 4;
593#else
594 int bxOffset = tabRec->anchor->offset;
595#endif
buzbeee3acd072012-02-25 17:03:10 -0800596 if (cUnit->printMe) {
597 LOG(INFO) << "Switch table for offset 0x" << std::hex << bxOffset;
598 }
599 if (tabRec->table[0] == kSparseSwitchSignature) {
600 int* keys = (int*)&(tabRec->table[2]);
601 for (int elems = 0; elems < tabRec->table[1]; elems++) {
buzbee31a4a6f2012-02-28 15:36:15 -0800602 int disp = tabRec->targets[elems]->offset - bxOffset;
buzbeee3acd072012-02-25 17:03:10 -0800603 if (cUnit->printMe) {
604 LOG(INFO) << " Case[" << elems << "] key: 0x" <<
605 std::hex << keys[elems] << ", disp: 0x" <<
606 std::hex << disp;
607 }
608 pushWord(cUnit->codeBuffer, keys[elems]);
609 pushWord(cUnit->codeBuffer,
buzbee31a4a6f2012-02-28 15:36:15 -0800610 tabRec->targets[elems]->offset - bxOffset);
buzbeee3acd072012-02-25 17:03:10 -0800611 }
612 } else {
613 DCHECK_EQ(tabRec->table[0], kPackedSwitchSignature);
614 for (int elems = 0; elems < tabRec->table[1]; elems++) {
buzbee31a4a6f2012-02-28 15:36:15 -0800615 int disp = tabRec->targets[elems]->offset - bxOffset;
buzbeee3acd072012-02-25 17:03:10 -0800616 if (cUnit->printMe) {
617 LOG(INFO) << " Case[" << elems << "] disp: 0x" <<
618 std::hex << disp;
619 }
620 pushWord(cUnit->codeBuffer,
buzbee31a4a6f2012-02-28 15:36:15 -0800621 tabRec->targets[elems]->offset - bxOffset);
buzbeee3acd072012-02-25 17:03:10 -0800622 }
623 }
624 }
625}
626
627/* Write the fill array dta to the output stream */
buzbee31a4a6f2012-02-28 15:36:15 -0800628void installFillArrayData(CompilationUnit* cUnit)
buzbeee3acd072012-02-25 17:03:10 -0800629{
630 GrowableListIterator iterator;
631 oatGrowableListIteratorInit(&cUnit->fillArrayData, &iterator);
632 while (true) {
633 FillArrayData *tabRec = (FillArrayData *) oatGrowableListIteratorNext(
634 &iterator);
635 if (tabRec == NULL) break;
636 alignBuffer(cUnit->codeBuffer, tabRec->offset);
637 for (int i = 0; i < ((tabRec->size + 1) / 2) ; i++) {
638 cUnit->codeBuffer.push_back( tabRec->table[i]);
639 }
640 }
641}
642
buzbee31a4a6f2012-02-28 15:36:15 -0800643int assignLiteralOffsetCommon(LIR* lir, int offset)
buzbeee3acd072012-02-25 17:03:10 -0800644{
645 for (;lir != NULL; lir = lir->next) {
646 lir->offset = offset;
647 offset += 4;
648 }
649 return offset;
650}
651
buzbee31a4a6f2012-02-28 15:36:15 -0800652void createMappingTable(CompilationUnit* cUnit)
buzbeee3acd072012-02-25 17:03:10 -0800653{
buzbee31a4a6f2012-02-28 15:36:15 -0800654 LIR* tgtLIR;
buzbeee3acd072012-02-25 17:03:10 -0800655 int currentDalvikOffset = -1;
656
buzbee31a4a6f2012-02-28 15:36:15 -0800657 for (tgtLIR = (LIR *) cUnit->firstLIRInsn;
buzbeee3acd072012-02-25 17:03:10 -0800658 tgtLIR;
659 tgtLIR = NEXT_LIR(tgtLIR)) {
660 if ((tgtLIR->opcode >= 0) && !tgtLIR->flags.isNop &&
buzbee31a4a6f2012-02-28 15:36:15 -0800661 (currentDalvikOffset != tgtLIR->dalvikOffset)) {
buzbeee3acd072012-02-25 17:03:10 -0800662 // Changed - need to emit a record
buzbee31a4a6f2012-02-28 15:36:15 -0800663 cUnit->mappingTable.push_back(tgtLIR->offset);
664 cUnit->mappingTable.push_back(tgtLIR->dalvikOffset);
665 currentDalvikOffset = tgtLIR->dalvikOffset;
buzbeee3acd072012-02-25 17:03:10 -0800666 }
667 }
668}
669
670/* Determine the offset of each literal field */
buzbee31a4a6f2012-02-28 15:36:15 -0800671int assignLiteralOffset(CompilationUnit* cUnit, int offset)
buzbeee3acd072012-02-25 17:03:10 -0800672{
673 offset = assignLiteralOffsetCommon(cUnit->literalList, offset);
674 return offset;
675}
676
buzbee31a4a6f2012-02-28 15:36:15 -0800677int assignSwitchTablesOffset(CompilationUnit* cUnit, int offset)
buzbeee3acd072012-02-25 17:03:10 -0800678{
679 GrowableListIterator iterator;
680 oatGrowableListIteratorInit(&cUnit->switchTables, &iterator);
681 while (true) {
682 SwitchTable *tabRec = (SwitchTable *) oatGrowableListIteratorNext(
683 &iterator);
684 if (tabRec == NULL) break;
685 tabRec->offset = offset;
686 if (tabRec->table[0] == kSparseSwitchSignature) {
687 offset += tabRec->table[1] * (sizeof(int) * 2);
688 } else {
689 DCHECK_EQ(tabRec->table[0], kPackedSwitchSignature);
690 offset += tabRec->table[1] * sizeof(int);
691 }
692 }
693 return offset;
694}
695
buzbee31a4a6f2012-02-28 15:36:15 -0800696int assignFillArrayDataOffset(CompilationUnit* cUnit, int offset)
buzbeee3acd072012-02-25 17:03:10 -0800697{
698 GrowableListIterator iterator;
699 oatGrowableListIteratorInit(&cUnit->fillArrayData, &iterator);
700 while (true) {
701 FillArrayData *tabRec = (FillArrayData *) oatGrowableListIteratorNext(
702 &iterator);
703 if (tabRec == NULL) break;
704 tabRec->offset = offset;
705 offset += tabRec->size;
706 // word align
707 offset = (offset + 3) & ~3;
708 }
709 return offset;
710}
711
712/*
713 * Walk the compilation unit and assign offsets to instructions
714 * and literals and compute the total size of the compiled unit.
715 */
716void oatAssignOffsets(CompilationUnit* cUnit)
717{
718 int offset = oatAssignInsnOffsets(cUnit);
719
720 /* Const values have to be word aligned */
721 offset = (offset + 3) & ~3;
722
723 /* Set up offsets for literals */
724 cUnit->dataOffset = offset;
725
726 offset = assignLiteralOffset(cUnit, offset);
727
728 offset = assignSwitchTablesOffset(cUnit, offset);
729
730 offset = assignFillArrayDataOffset(cUnit, offset);
731
732 cUnit->totalSize = offset;
733}
734
735/*
736 * Go over each instruction in the list and calculate the offset from the top
737 * before sending them off to the assembler. If out-of-range branch distance is
738 * seen rearrange the instructions a bit to correct it.
739 */
740void oatAssembleLIR(CompilationUnit* cUnit)
741{
742 oatAssignOffsets(cUnit);
743 /*
744 * Assemble here. Note that we generate code with optimistic assumptions
745 * and if found now to work, we'll have to redo the sequence and retry.
746 */
747
748 while (true) {
749 AssemblerStatus res = oatAssembleInstructions(cUnit, 0);
750 if (res == kSuccess) {
751 break;
752 } else {
753 cUnit->assemblerRetries++;
754 if (cUnit->assemblerRetries > MAX_ASSEMBLER_RETRIES) {
755 LOG(FATAL) << "Assembler error - too many retries";
756 }
757 // Redo offsets and try again
758 oatAssignOffsets(cUnit);
759 cUnit->codeBuffer.clear();
760 }
761 }
762
763 // Install literals
764 installLiteralPools(cUnit);
765
766 // Install switch tables
767 installSwitchTables(cUnit);
768
769 // Install fill array data
770 installFillArrayData(cUnit);
771
772 /*
773 * Create the mapping table
774 */
775 createMappingTable(cUnit);
776}
777
buzbee31a4a6f2012-02-28 15:36:15 -0800778/*
779 * Insert a kPseudoCaseLabel at the beginning of the Dalvik
780 * offset vaddr. This label will be used to fix up the case
781 * branch table during the assembly phase. Be sure to set
782 * all resource flags on this to prevent code motion across
783 * target boundaries. KeyVal is just there for debugging.
784 */
785LIR* insertCaseLabel(CompilationUnit* cUnit, int vaddr, int keyVal)
786{
787 std::map<unsigned int, LIR*>::iterator it;
788 it = cUnit->boundaryMap.find(vaddr);
789 if (it == cUnit->boundaryMap.end()) {
790 LOG(FATAL) << "Error: didn't find vaddr 0x" << std::hex << vaddr;
791 }
792 LIR* newLabel = (LIR*)oatNew(cUnit, sizeof(LIR), true, kAllocLIR);
793 newLabel->dalvikOffset = vaddr;
794 newLabel->opcode = kPseudoCaseLabel;
795 newLabel->operands[0] = keyVal;
796 oatInsertLIRAfter(it->second, (LIR*)newLabel);
797 return newLabel;
798}
799
800void markPackedCaseLabels(CompilationUnit* cUnit, SwitchTable *tabRec)
801{
802 const u2* table = tabRec->table;
803 int baseVaddr = tabRec->vaddr;
804 int *targets = (int*)&table[4];
805 int entries = table[1];
806 int lowKey = s4FromSwitchData(&table[2]);
807 for (int i = 0; i < entries; i++) {
808 tabRec->targets[i] = insertCaseLabel(cUnit, baseVaddr + targets[i],
809 i + lowKey);
810 }
811}
812
813void markSparseCaseLabels(CompilationUnit* cUnit, SwitchTable *tabRec)
814{
815 const u2* table = tabRec->table;
816 int baseVaddr = tabRec->vaddr;
817 int entries = table[1];
818 int* keys = (int*)&table[2];
819 int* targets = &keys[entries];
820 for (int i = 0; i < entries; i++) {
821 tabRec->targets[i] = insertCaseLabel(cUnit, baseVaddr + targets[i],
822 keys[i]);
823 }
824}
825
826void oatProcessSwitchTables(CompilationUnit* cUnit)
827{
828 GrowableListIterator iterator;
829 oatGrowableListIteratorInit(&cUnit->switchTables, &iterator);
830 while (true) {
831 SwitchTable *tabRec = (SwitchTable *) oatGrowableListIteratorNext(
832 &iterator);
833 if (tabRec == NULL) break;
834 if (tabRec->table[0] == kPackedSwitchSignature)
835 markPackedCaseLabels(cUnit, tabRec);
836 else if (tabRec->table[0] == kSparseSwitchSignature)
837 markSparseCaseLabels(cUnit, tabRec);
838 else {
839 LOG(FATAL) << "Invalid switch table";
840 }
841 }
842}
843
844//FIXME: Do we have endian issues here?
845
846void dumpSparseSwitchTable(const u2* table)
847 /*
848 * Sparse switch data format:
849 * ushort ident = 0x0200 magic value
850 * ushort size number of entries in the table; > 0
851 * int keys[size] keys, sorted low-to-high; 32-bit aligned
852 * int targets[size] branch targets, relative to switch opcode
853 *
854 * Total size is (2+size*4) 16-bit code units.
855 */
856{
857 u2 ident = table[0];
858 int entries = table[1];
859 int* keys = (int*)&table[2];
860 int* targets = &keys[entries];
861 LOG(INFO) << "Sparse switch table - ident:0x" << std::hex << ident <<
862 ", entries: " << std::dec << entries;
863 for (int i = 0; i < entries; i++) {
864 LOG(INFO) << " Key[" << keys[i] << "] -> 0x" << std::hex <<
865 targets[i];
866 }
867}
868
869void dumpPackedSwitchTable(const u2* table)
870 /*
871 * Packed switch data format:
872 * ushort ident = 0x0100 magic value
873 * ushort size number of entries in the table
874 * int first_key first (and lowest) switch case value
875 * int targets[size] branch targets, relative to switch opcode
876 *
877 * Total size is (4+size*2) 16-bit code units.
878 */
879{
880 u2 ident = table[0];
881 int* targets = (int*)&table[4];
882 int entries = table[1];
883 int lowKey = s4FromSwitchData(&table[2]);
884 LOG(INFO) << "Packed switch table - ident:0x" << std::hex << ident <<
885 ", entries: " << std::dec << entries << ", lowKey: " << lowKey;
886 for (int i = 0; i < entries; i++) {
887 LOG(INFO) << " Key[" << (i + lowKey) << "] -> 0x" << std::hex <<
888 targets[i];
889 }
890}
buzbeee3acd072012-02-25 17:03:10 -0800891
892
893} // namespace art