blob: 7f80311bff6a839e0989488afc3dd7467fda294b [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
148 if (flags & REG_DEF_LR) {
149 lir->defMask |= ENCODE_REG_LR;
150 }
151
152 if (flags & REG_DEF_LIST0) {
153 lir->defMask |= ENCODE_REG_LIST(lir->operands[0]);
154 }
155
156 if (flags & REG_DEF_LIST1) {
157 lir->defMask |= ENCODE_REG_LIST(lir->operands[1]);
158 }
159
buzbee5de34942012-03-01 14:51:57 -0800160#if defined(TARGET_ARM)
buzbee31a4a6f2012-02-28 15:36:15 -0800161 if (flags & REG_DEF_FPCS_LIST0) {
162 lir->defMask |= ENCODE_REG_FPCS_LIST(lir->operands[0]);
163 }
164
165 if (flags & REG_DEF_FPCS_LIST2) {
166 for (int i = 0; i < lir->operands[2]; i++) {
167 setupRegMask(&lir->defMask, lir->operands[1] + i);
168 }
169 }
buzbee5de34942012-03-01 14:51:57 -0800170#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800171
172 if (flags & SETS_CCODES) {
173 lir->defMask |= ENCODE_CCODE;
174 }
175
176#if defined(TARGET_ARM)
177 /* Conservatively treat the IT block */
178 if (flags & IS_IT) {
179 lir->defMask = ENCODE_ALL;
180 }
181#endif
182
183 if (flags & (REG_USE0 | REG_USE1 | REG_USE2 | REG_USE3)) {
184 int i;
185
186 for (i = 0; i < 4; i++) {
187 if (flags & (1 << (kRegUse0 + i))) {
188 setupRegMask(&lir->useMask, lir->operands[i]);
189 }
190 }
191 }
192
193 if (flags & REG_USE_PC) {
194 lir->useMask |= ENCODE_REG_PC;
195 }
196
197 if (flags & REG_USE_SP) {
198 lir->useMask |= ENCODE_REG_SP;
199 }
200
201 if (flags & REG_USE_LIST0) {
202 lir->useMask |= ENCODE_REG_LIST(lir->operands[0]);
203 }
204
205 if (flags & REG_USE_LIST1) {
206 lir->useMask |= ENCODE_REG_LIST(lir->operands[1]);
207 }
208
buzbee5de34942012-03-01 14:51:57 -0800209#if defined(TARGET_ARM)
buzbee31a4a6f2012-02-28 15:36:15 -0800210 if (flags & REG_USE_FPCS_LIST0) {
211 lir->useMask |= ENCODE_REG_FPCS_LIST(lir->operands[0]);
212 }
213
214 if (flags & REG_USE_FPCS_LIST2) {
215 for (int i = 0; i < lir->operands[2]; i++) {
216 setupRegMask(&lir->useMask, lir->operands[1] + i);
217 }
218 }
buzbee5de34942012-03-01 14:51:57 -0800219#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800220
221 if (flags & USES_CCODES) {
222 lir->useMask |= ENCODE_CCODE;
223 }
224
225#if defined(TARGET_ARM)
226 /* Fixup for kThumbPush/lr and kThumbPop/pc */
227 if (opcode == kThumbPush || opcode == kThumbPop) {
228 u8 r8Mask = getRegMaskCommon(r8);
229 if ((opcode == kThumbPush) && (lir->useMask & r8Mask)) {
230 lir->useMask &= ~r8Mask;
231 lir->useMask |= ENCODE_REG_LR;
232 } else if ((opcode == kThumbPop) && (lir->defMask & r8Mask)) {
233 lir->defMask &= ~r8Mask;
234 lir->defMask |= ENCODE_REG_PC;
235 }
236 }
237#endif
238}
239
240/*
buzbee5de34942012-03-01 14:51:57 -0800241 * Debugging macros
242 */
243#define DUMP_RESOURCE_MASK(X)
244#define DUMP_SSA_REP(X)
245
246/* Pretty-print a LIR instruction */
247void oatDumpLIRInsn(CompilationUnit* cUnit, LIR* arg, unsigned char* baseAddr)
248{
249 LIR* lir = (LIR*) arg;
250 int offset = lir->offset;
251 int dest = lir->operands[0];
252 const bool dumpNop = false;
253
254 /* Handle pseudo-ops individually, and all regular insns as a group */
255 switch(lir->opcode) {
256 case kPseudoMethodEntry:
257 LOG(INFO) << "-------- method entry " <<
258 PrettyMethod(cUnit->method_idx, *cUnit->dex_file);
259 break;
260 case kPseudoMethodExit:
261 LOG(INFO) << "-------- Method_Exit";
262 break;
263 case kPseudoBarrier:
264 LOG(INFO) << "-------- BARRIER";
265 break;
266 case kPseudoExtended:
267 LOG(INFO) << "-------- " << (char* ) dest;
268 break;
269 case kPseudoSSARep:
270 DUMP_SSA_REP(LOG(INFO) << "-------- kMirOpPhi: " << (char* ) dest);
271 break;
272 case kPseudoEntryBlock:
273 LOG(INFO) << "-------- entry offset: 0x" << std::hex << dest;
274 break;
275 case kPseudoDalvikByteCodeBoundary:
276 LOG(INFO) << "-------- dalvik offset: 0x" << std::hex <<
277 lir->dalvikOffset << " @ " << (char* )lir->operands[0];
278 break;
279 case kPseudoExitBlock:
280 LOG(INFO) << "-------- exit offset: 0x" << std::hex << dest;
281 break;
282 case kPseudoPseudoAlign4:
283 LOG(INFO) << (intptr_t)baseAddr + offset << " (0x" << std::hex <<
284 offset << "): .align4";
285 break;
286 case kPseudoEHBlockLabel:
287 LOG(INFO) << "Exception_Handling:";
288 break;
289 case kPseudoTargetLabel:
290 case kPseudoNormalBlockLabel:
291 LOG(INFO) << "L" << (intptr_t)lir << ":";
292 break;
293 case kPseudoThrowTarget:
294 LOG(INFO) << "LT" << (intptr_t)lir << ":";
295 break;
296 case kPseudoSuspendTarget:
297 LOG(INFO) << "LS" << (intptr_t)lir << ":";
298 break;
299 case kPseudoCaseLabel:
300 LOG(INFO) << "LC" << (intptr_t)lir << ": Case target 0x" <<
301 std::hex << lir->operands[0] << "|" << std::dec <<
302 lir->operands[0];
303 break;
304 default:
305 if (lir->flags.isNop && !dumpNop) {
306 break;
307 } else {
308 std::string op_name(buildInsnString(EncodingMap[lir->opcode].name, lir, baseAddr));
309 std::string op_operands(buildInsnString(EncodingMap[lir->opcode].fmt, lir, baseAddr));
buzbeebe003642012-03-02 15:28:37 -0800310 LOG(INFO) << StringPrintf("%05x: %-9s%s%s", (unsigned int)(baseAddr + offset),
buzbee5de34942012-03-01 14:51:57 -0800311 op_name.c_str(), op_operands.c_str(), lir->flags.isNop ? "(nop)" : "");
312 }
313 break;
314 }
315
316 if (lir->useMask && (!lir->flags.isNop || dumpNop)) {
317 DUMP_RESOURCE_MASK(oatDumpResourceMask((LIR* ) lir,
318 lir->useMask, "use"));
319 }
320 if (lir->defMask && (!lir->flags.isNop || dumpNop)) {
321 DUMP_RESOURCE_MASK(oatDumpResourceMask((LIR* ) lir,
322 lir->defMask, "def"));
323 }
324}
325
326void oatDumpPromotionMap(CompilationUnit *cUnit)
327{
328 for (int i = 0; i < cUnit->numDalvikRegisters; i++) {
329 PromotionMap vRegMap = cUnit->promotionMap[i];
330 char buf[100];
331 if (vRegMap.fpLocation == kLocPhysReg) {
332 snprintf(buf, 100, " : s%d", vRegMap.fpReg & FP_REG_MASK);
333 } else {
334 buf[0] = 0;
335 }
336 char buf2[100];
337 snprintf(buf2, 100, "V[%02d] -> %s%d%s", i,
338 vRegMap.coreLocation == kLocPhysReg ?
339 "r" : "SP+", vRegMap.coreLocation == kLocPhysReg ?
340 vRegMap.coreReg : oatSRegOffset(cUnit, i), buf);
341 LOG(INFO) << buf2;
342 }
343}
344
345void oatDumpFullPromotionMap(CompilationUnit *cUnit)
346{
347 for (int i = 0; i < cUnit->numDalvikRegisters; i++) {
348 PromotionMap vRegMap = cUnit->promotionMap[i];
349 LOG(INFO) << i << " -> " << "CL:" << (int)vRegMap.coreLocation <<
350 ", CR:" << (int)vRegMap.coreReg << ", FL:" <<
351 (int)vRegMap.fpLocation << ", FR:" << (int)vRegMap.fpReg <<
352 ", - " << (int)vRegMap.firstInPair;
353 }
354}
355
356/* Dump instructions and constant pool contents */
357void oatCodegenDump(CompilationUnit* cUnit)
358{
359 LOG(INFO) << "/*";
360 LOG(INFO) << "Dumping LIR insns for "
361 << PrettyMethod(cUnit->method_idx, *cUnit->dex_file);
362 LIR* lirInsn;
363 LIR* thisLIR;
364 int insnsSize = cUnit->insnsSize;
365
366 LOG(INFO) << "Regs (excluding ins) : " << cUnit->numRegs;
367 LOG(INFO) << "Ins : " << cUnit->numIns;
368 LOG(INFO) << "Outs : " << cUnit->numOuts;
369 LOG(INFO) << "CoreSpills : " << cUnit->numCoreSpills;
370 LOG(INFO) << "FPSpills : " << cUnit->numFPSpills;
371 LOG(INFO) << "Padding : " << cUnit->numPadding;
372 LOG(INFO) << "Frame size : " << cUnit->frameSize;
373 LOG(INFO) << "Start of ins : " << cUnit->insOffset;
374 LOG(INFO) << "Start of regs : " << cUnit->regsOffset;
375 LOG(INFO) << "code size is " << cUnit->totalSize <<
376 " bytes, Dalvik size is " << insnsSize * 2;
377 LOG(INFO) << "expansion factor: " <<
378 (float)cUnit->totalSize / (float)(insnsSize * 2);
379 oatDumpPromotionMap(cUnit);
380 for (lirInsn = cUnit->firstLIRInsn; lirInsn; lirInsn = lirInsn->next) {
381 oatDumpLIRInsn(cUnit, lirInsn, 0);
382 }
383 for (lirInsn = cUnit->classPointerList; lirInsn; lirInsn = lirInsn->next) {
384 thisLIR = (LIR*) lirInsn;
385 LOG(INFO) << StringPrintf("%x (%04x): .class (%s)",
386 thisLIR->offset, thisLIR->offset,
387 ((CallsiteInfo *) thisLIR->operands[0])->classDescriptor);
388 }
389 for (lirInsn = cUnit->literalList; lirInsn; lirInsn = lirInsn->next) {
390 thisLIR = (LIR*) lirInsn;
391 LOG(INFO) << StringPrintf("%x (%04x): .word (%#x)",
392 thisLIR->offset, thisLIR->offset, thisLIR->operands[0]);
393 }
394
395 const DexFile::MethodId& method_id =
396 cUnit->dex_file->GetMethodId(cUnit->method_idx);
397 std::string signature(cUnit->dex_file->GetMethodSignature(method_id));
398 std::string name(cUnit->dex_file->GetMethodName(method_id));
399 std::string descriptor(cUnit->dex_file->GetMethodDeclaringClassDescriptor(method_id));
400
401 // Dump mapping table
402 if (cUnit->mappingTable.size() > 0) {
403 std::string line(StringPrintf("\n MappingTable %s%s_%s_mappingTable[%zu] = {",
404 descriptor.c_str(), name.c_str(), signature.c_str(), cUnit->mappingTable.size()));
405 std::replace(line.begin(), line.end(), ';', '_');
406 LOG(INFO) << line;
407 for (uint32_t i = 0; i < cUnit->mappingTable.size(); i+=2) {
buzbee82488f52012-03-02 08:20:26 -0800408 line = StringPrintf(" {0x%05x, 0x%04x},",
buzbee5de34942012-03-01 14:51:57 -0800409 cUnit->mappingTable[i], cUnit->mappingTable[i+1]);
410 LOG(INFO) << line;
411 }
412 LOG(INFO) <<" };\n\n";
413 }
414}
415
buzbeea2ebdd72012-03-04 14:57:06 -0800416
417LIR* rawLIR(CompilationUnit* cUnit, int dalvikOffset, int opcode, int op0,
418 int op1, int op2, int op3, LIR* target)
419{
420 LIR* insn = (LIR* ) oatNew(cUnit, sizeof(LIR), true, kAllocLIR);
421 insn->dalvikOffset = dalvikOffset;
422 insn->opcode = opcode;
423 insn->operands[0] = op0;
424 insn->operands[1] = op1;
425 insn->operands[2] = op2;
426 insn->operands[3] = op3;
427 insn->target = target;
428 oatSetupResourceMasks(insn);
429 if (opcode == kPseudoTargetLabel) {
430 // Always make labels scheduling barriers
431 insn->defMask = ENCODE_ALL;
432 }
433 return insn;
434}
435
buzbee5de34942012-03-01 14:51:57 -0800436/*
buzbee31a4a6f2012-02-28 15:36:15 -0800437 * The following are building blocks to construct low-level IRs with 0 - 4
438 * operands.
439 */
buzbee5de34942012-03-01 14:51:57 -0800440LIR* newLIR0(CompilationUnit* cUnit, int opcode)
buzbee31a4a6f2012-02-28 15:36:15 -0800441{
buzbee31a4a6f2012-02-28 15:36:15 -0800442 DCHECK(isPseudoOpcode(opcode) || (EncodingMap[opcode].flags & NO_OPERAND));
buzbeea2ebdd72012-03-04 14:57:06 -0800443 LIR* insn = rawLIR(cUnit, cUnit->currentDalvikOffset, opcode);
buzbee31a4a6f2012-02-28 15:36:15 -0800444 oatAppendLIR(cUnit, (LIR*) insn);
445 return insn;
446}
447
buzbee5de34942012-03-01 14:51:57 -0800448LIR* newLIR1(CompilationUnit* cUnit, int opcode,
buzbee31a4a6f2012-02-28 15:36:15 -0800449 int dest)
450{
buzbee31a4a6f2012-02-28 15:36:15 -0800451 DCHECK(isPseudoOpcode(opcode) || (EncodingMap[opcode].flags & IS_UNARY_OP));
buzbeea2ebdd72012-03-04 14:57:06 -0800452 LIR* insn = rawLIR(cUnit, cUnit->currentDalvikOffset, opcode, dest);
buzbee31a4a6f2012-02-28 15:36:15 -0800453 oatAppendLIR(cUnit, (LIR*) insn);
454 return insn;
455}
456
buzbee5de34942012-03-01 14:51:57 -0800457LIR* newLIR2(CompilationUnit* cUnit, int opcode,
buzbee31a4a6f2012-02-28 15:36:15 -0800458 int dest, int src1)
459{
buzbee31a4a6f2012-02-28 15:36:15 -0800460 DCHECK(isPseudoOpcode(opcode) ||
461 (EncodingMap[opcode].flags & IS_BINARY_OP));
buzbeea2ebdd72012-03-04 14:57:06 -0800462 LIR* insn = rawLIR(cUnit, cUnit->currentDalvikOffset, opcode, dest, src1);
buzbee31a4a6f2012-02-28 15:36:15 -0800463 oatAppendLIR(cUnit, (LIR*) insn);
464 return insn;
465}
466
buzbee5de34942012-03-01 14:51:57 -0800467LIR* newLIR3(CompilationUnit* cUnit, int opcode,
buzbee31a4a6f2012-02-28 15:36:15 -0800468 int dest, int src1, int src2)
469{
buzbee31a4a6f2012-02-28 15:36:15 -0800470 DCHECK(isPseudoOpcode(opcode) ||
471 (EncodingMap[opcode].flags & IS_TERTIARY_OP))
472 << (int)opcode << " "
473 << PrettyMethod(cUnit->method_idx, *cUnit->dex_file) << " "
474 << cUnit->currentDalvikOffset;
buzbeea2ebdd72012-03-04 14:57:06 -0800475 LIR* insn = rawLIR(cUnit, cUnit->currentDalvikOffset, opcode, dest, src1,
476 src2);
buzbee31a4a6f2012-02-28 15:36:15 -0800477 oatAppendLIR(cUnit, (LIR*) insn);
478 return insn;
479}
480
buzbee5de34942012-03-01 14:51:57 -0800481LIR* newLIR4(CompilationUnit* cUnit, int opcode,
buzbee31a4a6f2012-02-28 15:36:15 -0800482 int dest, int src1, int src2, int info)
483{
buzbee31a4a6f2012-02-28 15:36:15 -0800484 DCHECK(isPseudoOpcode(opcode) ||
485 (EncodingMap[opcode].flags & IS_QUAD_OP));
buzbeea2ebdd72012-03-04 14:57:06 -0800486 LIR* insn = rawLIR(cUnit, cUnit->currentDalvikOffset, opcode, dest, src1,
487 src2, info);
buzbee31a4a6f2012-02-28 15:36:15 -0800488 oatAppendLIR(cUnit, (LIR*) insn);
489 return insn;
490}
buzbee31a4a6f2012-02-28 15:36:15 -0800491
492/*
493 * Search the existing constants in the literal pool for an exact or close match
494 * within specified delta (greater or equal to 0).
495 */
496LIR* scanLiteralPool(LIR* dataTarget, int value, unsigned int delta)
497{
498 while (dataTarget) {
499 if (((unsigned) (value - ((LIR* ) dataTarget)->operands[0])) <=
500 delta)
501 return (LIR* ) dataTarget;
502 dataTarget = dataTarget->next;
503 }
504 return NULL;
505}
506
507/* Search the existing constants in the literal pool for an exact wide match */
508LIR* scanLiteralPoolWide(LIR* dataTarget, int valLo, int valHi)
509{
510 bool loMatch = false;
511 LIR* loTarget = NULL;
512 while (dataTarget) {
513 if (loMatch && (((LIR*)dataTarget)->operands[0] == valHi)) {
514 return (LIR*)loTarget;
515 }
516 loMatch = false;
517 if (((LIR*)dataTarget)->operands[0] == valLo) {
518 loMatch = true;
519 loTarget = dataTarget;
520 }
521 dataTarget = dataTarget->next;
522 }
523 return NULL;
524}
525
526/*
527 * The following are building blocks to insert constants into the pool or
528 * instruction streams.
529 */
530
buzbee5de34942012-03-01 14:51:57 -0800531/* Add a 32-bit constant either in the constant pool */
buzbee31a4a6f2012-02-28 15:36:15 -0800532LIR* addWordData(CompilationUnit* cUnit, LIR* *constantListP,
533 int value)
534{
535 /* Add the constant to the literal pool */
536 if (constantListP) {
537 LIR* newValue = (LIR* ) oatNew(cUnit, sizeof(LIR), true,
538 kAllocData);
539 newValue->operands[0] = value;
540 newValue->next = *constantListP;
541 *constantListP = (LIR*) newValue;
542 return newValue;
buzbee31a4a6f2012-02-28 15:36:15 -0800543 }
544 return NULL;
545}
546
547/* Add a 64-bit constant to the constant pool or mixed with code */
548LIR* addWideData(CompilationUnit* cUnit, LIR* *constantListP,
549 int valLo, int valHi)
550{
buzbee31a4a6f2012-02-28 15:36:15 -0800551 //FIXME: hard-coded little endian, need BE variant
buzbee5de34942012-03-01 14:51:57 -0800552 // Insert high word into list first
553 addWordData(cUnit, constantListP, valHi);
554 return addWordData(cUnit, constantListP, valLo);
buzbee31a4a6f2012-02-28 15:36:15 -0800555}
556
557void pushWord(std::vector<uint16_t>&buf, int data) {
buzbeee3acd072012-02-25 17:03:10 -0800558 buf.push_back( data & 0xffff);
559 buf.push_back( (data >> 16) & 0xffff);
560}
561
562void alignBuffer(std::vector<uint16_t>&buf, size_t offset) {
563 while (buf.size() < (offset/2))
564 buf.push_back(0);
565}
566
567/* Write the literal pool to the output stream */
buzbee31a4a6f2012-02-28 15:36:15 -0800568void installLiteralPools(CompilationUnit* cUnit)
buzbeee3acd072012-02-25 17:03:10 -0800569{
570 alignBuffer(cUnit->codeBuffer, cUnit->dataOffset);
buzbee31a4a6f2012-02-28 15:36:15 -0800571 LIR* dataLIR = (LIR*) cUnit->literalList;
buzbeee3acd072012-02-25 17:03:10 -0800572 while (dataLIR != NULL) {
573 pushWord(cUnit->codeBuffer, dataLIR->operands[0]);
574 dataLIR = NEXT_LIR(dataLIR);
575 }
576}
577
578/* Write the switch tables to the output stream */
buzbee31a4a6f2012-02-28 15:36:15 -0800579void installSwitchTables(CompilationUnit* cUnit)
buzbeee3acd072012-02-25 17:03:10 -0800580{
581 GrowableListIterator iterator;
582 oatGrowableListIteratorInit(&cUnit->switchTables, &iterator);
583 while (true) {
584 SwitchTable* tabRec = (SwitchTable *) oatGrowableListIteratorNext(
585 &iterator);
586 if (tabRec == NULL) break;
587 alignBuffer(cUnit->codeBuffer, tabRec->offset);
buzbeec5159d52012-03-03 11:48:39 -0800588 /*
589 * For Arm, our reference point is the address of the bx
590 * instruction that does the launch, so we have to subtract
591 * the auto pc-advance. For other targets the reference point
592 * is a label, so we can use the offset as-is.
593 */
594#if defined(TARGET_ARM)
595 int bxOffset = tabRec->anchor->offset + 4;
596#else
597 int bxOffset = tabRec->anchor->offset;
598#endif
buzbeee3acd072012-02-25 17:03:10 -0800599 if (cUnit->printMe) {
600 LOG(INFO) << "Switch table for offset 0x" << std::hex << bxOffset;
601 }
602 if (tabRec->table[0] == kSparseSwitchSignature) {
603 int* keys = (int*)&(tabRec->table[2]);
604 for (int elems = 0; elems < tabRec->table[1]; elems++) {
buzbee31a4a6f2012-02-28 15:36:15 -0800605 int disp = tabRec->targets[elems]->offset - bxOffset;
buzbeee3acd072012-02-25 17:03:10 -0800606 if (cUnit->printMe) {
607 LOG(INFO) << " Case[" << elems << "] key: 0x" <<
608 std::hex << keys[elems] << ", disp: 0x" <<
609 std::hex << disp;
610 }
611 pushWord(cUnit->codeBuffer, keys[elems]);
612 pushWord(cUnit->codeBuffer,
buzbee31a4a6f2012-02-28 15:36:15 -0800613 tabRec->targets[elems]->offset - bxOffset);
buzbeee3acd072012-02-25 17:03:10 -0800614 }
615 } else {
616 DCHECK_EQ(tabRec->table[0], kPackedSwitchSignature);
617 for (int elems = 0; elems < tabRec->table[1]; elems++) {
buzbee31a4a6f2012-02-28 15:36:15 -0800618 int disp = tabRec->targets[elems]->offset - bxOffset;
buzbeee3acd072012-02-25 17:03:10 -0800619 if (cUnit->printMe) {
620 LOG(INFO) << " Case[" << elems << "] disp: 0x" <<
621 std::hex << disp;
622 }
623 pushWord(cUnit->codeBuffer,
buzbee31a4a6f2012-02-28 15:36:15 -0800624 tabRec->targets[elems]->offset - bxOffset);
buzbeee3acd072012-02-25 17:03:10 -0800625 }
626 }
627 }
628}
629
630/* Write the fill array dta to the output stream */
buzbee31a4a6f2012-02-28 15:36:15 -0800631void installFillArrayData(CompilationUnit* cUnit)
buzbeee3acd072012-02-25 17:03:10 -0800632{
633 GrowableListIterator iterator;
634 oatGrowableListIteratorInit(&cUnit->fillArrayData, &iterator);
635 while (true) {
636 FillArrayData *tabRec = (FillArrayData *) oatGrowableListIteratorNext(
637 &iterator);
638 if (tabRec == NULL) break;
639 alignBuffer(cUnit->codeBuffer, tabRec->offset);
640 for (int i = 0; i < ((tabRec->size + 1) / 2) ; i++) {
641 cUnit->codeBuffer.push_back( tabRec->table[i]);
642 }
643 }
644}
645
buzbee31a4a6f2012-02-28 15:36:15 -0800646int assignLiteralOffsetCommon(LIR* lir, int offset)
buzbeee3acd072012-02-25 17:03:10 -0800647{
648 for (;lir != NULL; lir = lir->next) {
649 lir->offset = offset;
650 offset += 4;
651 }
652 return offset;
653}
654
buzbee31a4a6f2012-02-28 15:36:15 -0800655void createMappingTable(CompilationUnit* cUnit)
buzbeee3acd072012-02-25 17:03:10 -0800656{
buzbee31a4a6f2012-02-28 15:36:15 -0800657 LIR* tgtLIR;
buzbeee3acd072012-02-25 17:03:10 -0800658 int currentDalvikOffset = -1;
659
buzbee31a4a6f2012-02-28 15:36:15 -0800660 for (tgtLIR = (LIR *) cUnit->firstLIRInsn;
buzbeee3acd072012-02-25 17:03:10 -0800661 tgtLIR;
662 tgtLIR = NEXT_LIR(tgtLIR)) {
663 if ((tgtLIR->opcode >= 0) && !tgtLIR->flags.isNop &&
buzbee31a4a6f2012-02-28 15:36:15 -0800664 (currentDalvikOffset != tgtLIR->dalvikOffset)) {
buzbeee3acd072012-02-25 17:03:10 -0800665 // Changed - need to emit a record
buzbee31a4a6f2012-02-28 15:36:15 -0800666 cUnit->mappingTable.push_back(tgtLIR->offset);
667 cUnit->mappingTable.push_back(tgtLIR->dalvikOffset);
668 currentDalvikOffset = tgtLIR->dalvikOffset;
buzbeee3acd072012-02-25 17:03:10 -0800669 }
670 }
671}
672
673/* Determine the offset of each literal field */
buzbee31a4a6f2012-02-28 15:36:15 -0800674int assignLiteralOffset(CompilationUnit* cUnit, int offset)
buzbeee3acd072012-02-25 17:03:10 -0800675{
676 offset = assignLiteralOffsetCommon(cUnit->literalList, offset);
677 return offset;
678}
679
buzbee31a4a6f2012-02-28 15:36:15 -0800680int assignSwitchTablesOffset(CompilationUnit* cUnit, int offset)
buzbeee3acd072012-02-25 17:03:10 -0800681{
682 GrowableListIterator iterator;
683 oatGrowableListIteratorInit(&cUnit->switchTables, &iterator);
684 while (true) {
685 SwitchTable *tabRec = (SwitchTable *) oatGrowableListIteratorNext(
686 &iterator);
687 if (tabRec == NULL) break;
688 tabRec->offset = offset;
689 if (tabRec->table[0] == kSparseSwitchSignature) {
690 offset += tabRec->table[1] * (sizeof(int) * 2);
691 } else {
692 DCHECK_EQ(tabRec->table[0], kPackedSwitchSignature);
693 offset += tabRec->table[1] * sizeof(int);
694 }
695 }
696 return offset;
697}
698
buzbee31a4a6f2012-02-28 15:36:15 -0800699int assignFillArrayDataOffset(CompilationUnit* cUnit, int offset)
buzbeee3acd072012-02-25 17:03:10 -0800700{
701 GrowableListIterator iterator;
702 oatGrowableListIteratorInit(&cUnit->fillArrayData, &iterator);
703 while (true) {
704 FillArrayData *tabRec = (FillArrayData *) oatGrowableListIteratorNext(
705 &iterator);
706 if (tabRec == NULL) break;
707 tabRec->offset = offset;
708 offset += tabRec->size;
709 // word align
710 offset = (offset + 3) & ~3;
711 }
712 return offset;
713}
714
715/*
716 * Walk the compilation unit and assign offsets to instructions
717 * and literals and compute the total size of the compiled unit.
718 */
719void oatAssignOffsets(CompilationUnit* cUnit)
720{
721 int offset = oatAssignInsnOffsets(cUnit);
722
723 /* Const values have to be word aligned */
724 offset = (offset + 3) & ~3;
725
726 /* Set up offsets for literals */
727 cUnit->dataOffset = offset;
728
729 offset = assignLiteralOffset(cUnit, offset);
730
731 offset = assignSwitchTablesOffset(cUnit, offset);
732
733 offset = assignFillArrayDataOffset(cUnit, offset);
734
735 cUnit->totalSize = offset;
736}
737
738/*
739 * Go over each instruction in the list and calculate the offset from the top
740 * before sending them off to the assembler. If out-of-range branch distance is
741 * seen rearrange the instructions a bit to correct it.
742 */
743void oatAssembleLIR(CompilationUnit* cUnit)
744{
745 oatAssignOffsets(cUnit);
746 /*
747 * Assemble here. Note that we generate code with optimistic assumptions
748 * and if found now to work, we'll have to redo the sequence and retry.
749 */
750
751 while (true) {
752 AssemblerStatus res = oatAssembleInstructions(cUnit, 0);
753 if (res == kSuccess) {
754 break;
755 } else {
756 cUnit->assemblerRetries++;
757 if (cUnit->assemblerRetries > MAX_ASSEMBLER_RETRIES) {
758 LOG(FATAL) << "Assembler error - too many retries";
759 }
760 // Redo offsets and try again
761 oatAssignOffsets(cUnit);
762 cUnit->codeBuffer.clear();
763 }
764 }
765
766 // Install literals
767 installLiteralPools(cUnit);
768
769 // Install switch tables
770 installSwitchTables(cUnit);
771
772 // Install fill array data
773 installFillArrayData(cUnit);
774
775 /*
776 * Create the mapping table
777 */
778 createMappingTable(cUnit);
779}
780
buzbee31a4a6f2012-02-28 15:36:15 -0800781/*
782 * Insert a kPseudoCaseLabel at the beginning of the Dalvik
783 * offset vaddr. This label will be used to fix up the case
784 * branch table during the assembly phase. Be sure to set
785 * all resource flags on this to prevent code motion across
786 * target boundaries. KeyVal is just there for debugging.
787 */
788LIR* insertCaseLabel(CompilationUnit* cUnit, int vaddr, int keyVal)
789{
790 std::map<unsigned int, LIR*>::iterator it;
791 it = cUnit->boundaryMap.find(vaddr);
792 if (it == cUnit->boundaryMap.end()) {
793 LOG(FATAL) << "Error: didn't find vaddr 0x" << std::hex << vaddr;
794 }
795 LIR* newLabel = (LIR*)oatNew(cUnit, sizeof(LIR), true, kAllocLIR);
796 newLabel->dalvikOffset = vaddr;
797 newLabel->opcode = kPseudoCaseLabel;
798 newLabel->operands[0] = keyVal;
799 oatInsertLIRAfter(it->second, (LIR*)newLabel);
800 return newLabel;
801}
802
803void markPackedCaseLabels(CompilationUnit* cUnit, SwitchTable *tabRec)
804{
805 const u2* table = tabRec->table;
806 int baseVaddr = tabRec->vaddr;
807 int *targets = (int*)&table[4];
808 int entries = table[1];
809 int lowKey = s4FromSwitchData(&table[2]);
810 for (int i = 0; i < entries; i++) {
811 tabRec->targets[i] = insertCaseLabel(cUnit, baseVaddr + targets[i],
812 i + lowKey);
813 }
814}
815
816void markSparseCaseLabels(CompilationUnit* cUnit, SwitchTable *tabRec)
817{
818 const u2* table = tabRec->table;
819 int baseVaddr = tabRec->vaddr;
820 int entries = table[1];
821 int* keys = (int*)&table[2];
822 int* targets = &keys[entries];
823 for (int i = 0; i < entries; i++) {
824 tabRec->targets[i] = insertCaseLabel(cUnit, baseVaddr + targets[i],
825 keys[i]);
826 }
827}
828
829void oatProcessSwitchTables(CompilationUnit* cUnit)
830{
831 GrowableListIterator iterator;
832 oatGrowableListIteratorInit(&cUnit->switchTables, &iterator);
833 while (true) {
834 SwitchTable *tabRec = (SwitchTable *) oatGrowableListIteratorNext(
835 &iterator);
836 if (tabRec == NULL) break;
837 if (tabRec->table[0] == kPackedSwitchSignature)
838 markPackedCaseLabels(cUnit, tabRec);
839 else if (tabRec->table[0] == kSparseSwitchSignature)
840 markSparseCaseLabels(cUnit, tabRec);
841 else {
842 LOG(FATAL) << "Invalid switch table";
843 }
844 }
845}
846
847//FIXME: Do we have endian issues here?
848
849void dumpSparseSwitchTable(const u2* table)
850 /*
851 * Sparse switch data format:
852 * ushort ident = 0x0200 magic value
853 * ushort size number of entries in the table; > 0
854 * int keys[size] keys, sorted low-to-high; 32-bit aligned
855 * int targets[size] branch targets, relative to switch opcode
856 *
857 * Total size is (2+size*4) 16-bit code units.
858 */
859{
860 u2 ident = table[0];
861 int entries = table[1];
862 int* keys = (int*)&table[2];
863 int* targets = &keys[entries];
864 LOG(INFO) << "Sparse switch table - ident:0x" << std::hex << ident <<
865 ", entries: " << std::dec << entries;
866 for (int i = 0; i < entries; i++) {
867 LOG(INFO) << " Key[" << keys[i] << "] -> 0x" << std::hex <<
868 targets[i];
869 }
870}
871
872void dumpPackedSwitchTable(const u2* table)
873 /*
874 * Packed switch data format:
875 * ushort ident = 0x0100 magic value
876 * ushort size number of entries in the table
877 * int first_key first (and lowest) switch case value
878 * int targets[size] branch targets, relative to switch opcode
879 *
880 * Total size is (4+size*2) 16-bit code units.
881 */
882{
883 u2 ident = table[0];
884 int* targets = (int*)&table[4];
885 int entries = table[1];
886 int lowKey = s4FromSwitchData(&table[2]);
887 LOG(INFO) << "Packed switch table - ident:0x" << std::hex << ident <<
888 ", entries: " << std::dec << entries << ", lowKey: " << lowKey;
889 for (int i = 0; i < entries; i++) {
890 LOG(INFO) << " Key[" << (i + lowKey) << "] -> 0x" << std::hex <<
891 targets[i];
892 }
893}
buzbeee3acd072012-02-25 17:03:10 -0800894
895
896} // namespace art