blob: e51774e7b2fce5727e6ee43612861b6325807f32 [file] [log] [blame]
buzbee67bf8852011-08-17 17:51:35 -07001/*
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
17#include "../../CompilerInternals.h"
18#include "ArmLIR.h"
19
20static const char* coreRegNames[16] = {
21 "r0",
22 "r1",
23 "r2",
24 "r3",
25 "r4",
26 "r5",
27 "r6",
28 "r7",
29 "r8",
30 "rSELF",
31 "r10",
32 "r11",
33 "r12",
34 "sp",
35 "lr",
36 "pc",
37};
38
39
40static const char* shiftNames[4] = {
41 "lsl",
42 "lsr",
43 "asr",
44 "ror"};
45
46/* Decode and print a ARM register name */
47static char* decodeRegList(ArmOpcode opcode, int vector, char* buf)
48{
49 int i;
50 bool printed = false;
51 buf[0] = 0;
52 for (i = 0; i < 16; i++, vector >>= 1) {
53 if (vector & 0x1) {
54 int regId = i;
55 if (opcode == kThumbPush && i == 8) {
56 regId = r14lr;
57 } else if (opcode == kThumbPop && i == 8) {
58 regId = r15pc;
59 }
60 if (printed) {
61 sprintf(buf + strlen(buf), ", r%d", regId);
62 } else {
63 printed = true;
64 sprintf(buf, "r%d", regId);
65 }
66 }
67 }
68 return buf;
69}
70
71static char* decodeFPCSRegList(int count, int base, char* buf)
72{
73 sprintf(buf, "s%d", base);
74 for (int i = 1; i < count; i++) {
75 sprintf(buf + strlen(buf), ", s%d",base + i);
76 }
77 return buf;
78}
79
80static int expandImmediate(int value)
81{
82 int mode = (value & 0xf00) >> 8;
83 u4 bits = value & 0xff;
84 switch(mode) {
85 case 0:
86 return bits;
87 case 1:
88 return (bits << 16) | bits;
89 case 2:
90 return (bits << 24) | (bits << 8);
91 case 3:
92 return (bits << 24) | (bits << 16) | (bits << 8) | bits;
93 default:
94 break;
95 }
96 bits = (bits | 0x80) << 24;
97 return bits >> (((value & 0xf80) >> 7) - 8);
98}
99
100const char* ccNames[] = {"eq","ne","cs","cc","mi","pl","vs","vc",
101 "hi","ls","ge","lt","gt","le","al","nv"};
102/*
103 * Interpret a format string and build a string no longer than size
104 * See format key in Assemble.c.
105 */
106static void buildInsnString(const char* fmt, ArmLIR* lir, char* buf,
107 unsigned char* baseAddr, int size)
108{
109 int i;
110 char* bufEnd = &buf[size-1];
111 const char* fmtEnd = &fmt[strlen(fmt)];
112 char tbuf[256];
113 const char* name;
114 char nc;
115 while (fmt < fmtEnd) {
116 int operand;
117 if (*fmt == '!') {
118 fmt++;
119 assert(fmt < fmtEnd);
120 nc = *fmt++;
121 if (nc=='!') {
122 strcpy(tbuf, "!");
123 } else {
124 assert(fmt < fmtEnd);
125 assert((unsigned)(nc-'0') < 4);
126 operand = lir->operands[nc-'0'];
127 switch(*fmt++) {
128 case 'H':
129 if (operand != 0) {
130 sprintf(tbuf, ", %s %d",shiftNames[operand & 0x3],
131 operand >> 2);
132 } else {
133 strcpy(tbuf,"");
134 }
135 break;
136 case 'B':
137 switch (operand) {
138 case kSY:
139 name = "sy";
140 break;
141 case kST:
142 name = "st";
143 break;
144 case kISH:
145 name = "ish";
146 break;
147 case kISHST:
148 name = "ishst";
149 break;
150 case kNSH:
151 name = "nsh";
152 break;
153 case kNSHST:
154 name = "shst";
155 break;
156 default:
157 name = "DecodeError2";
158 break;
159 }
160 strcpy(tbuf, name);
161 break;
162 case 'b':
163 strcpy(tbuf,"0000");
164 for (i=3; i>= 0; i--) {
165 tbuf[i] += operand & 1;
166 operand >>= 1;
167 }
168 break;
169 case 'n':
170 operand = ~expandImmediate(operand);
171 sprintf(tbuf,"%d [%#x]", operand, operand);
172 break;
173 case 'm':
174 operand = expandImmediate(operand);
175 sprintf(tbuf,"%d [%#x]", operand, operand);
176 break;
177 case 's':
178 sprintf(tbuf,"s%d",operand & FP_REG_MASK);
179 break;
180 case 'S':
181 sprintf(tbuf,"d%d",(operand & FP_REG_MASK) >> 1);
182 break;
183 case 'h':
184 sprintf(tbuf,"%04x", operand);
185 break;
186 case 'M':
187 case 'd':
188 sprintf(tbuf,"%d", operand);
189 break;
190 case 'C':
191 sprintf(tbuf,"%s",coreRegNames[operand]);
192 break;
193 case 'E':
194 sprintf(tbuf,"%d", operand*4);
195 break;
196 case 'F':
197 sprintf(tbuf,"%d", operand*2);
198 break;
199 case 'c':
200 strcpy(tbuf, ccNames[operand]);
201 break;
202 case 't':
203 sprintf(tbuf,"0x%08x (L%p)",
204 (int) baseAddr + lir->generic.offset + 4 +
205 (operand << 1),
206 lir->generic.target);
207 break;
208 case 'u': {
209 int offset_1 = lir->operands[0];
210 int offset_2 = NEXT_LIR(lir)->operands[0];
211 intptr_t target =
212 ((((intptr_t) baseAddr + lir->generic.offset + 4) &
213 ~3) + (offset_1 << 21 >> 9) + (offset_2 << 1)) &
214 0xfffffffc;
215 sprintf(tbuf, "%p", (void *) target);
216 break;
217 }
218
219 /* Nothing to print for BLX_2 */
220 case 'v':
221 strcpy(tbuf, "see above");
222 break;
223 case 'R':
224 decodeRegList(lir->opcode, operand, tbuf);
225 break;
226 case 'P':
227 decodeFPCSRegList(operand, 16, tbuf);
228 break;
229 case 'Q':
230 decodeFPCSRegList(operand, 0, tbuf);
231 break;
232 default:
233 strcpy(tbuf,"DecodeError1");
234 break;
235 }
236 if (buf+strlen(tbuf) <= bufEnd) {
237 strcpy(buf, tbuf);
238 buf += strlen(tbuf);
239 } else {
240 break;
241 }
242 }
243 } else {
244 *buf++ = *fmt++;
245 }
246 if (buf == bufEnd)
247 break;
248 }
249 *buf = 0;
250}
251
252void oatDumpResourceMask(LIR* lir, u8 mask, const char* prefix)
253{
254 char buf[256];
255 buf[0] = 0;
256 ArmLIR* armLIR = (ArmLIR*) lir;
257
258 if (mask == ENCODE_ALL) {
259 strcpy(buf, "all");
260 } else {
261 char num[8];
262 int i;
263
264 for (i = 0; i < kRegEnd; i++) {
265 if (mask & (1ULL << i)) {
266 sprintf(num, "%d ", i);
267 strcat(buf, num);
268 }
269 }
270
271 if (mask & ENCODE_CCODE) {
272 strcat(buf, "cc ");
273 }
274 if (mask & ENCODE_FP_STATUS) {
275 strcat(buf, "fpcc ");
276 }
277
278 /* Memory bits */
279 if (armLIR && (mask & ENCODE_DALVIK_REG)) {
280 sprintf(buf + strlen(buf), "dr%d%s", armLIR->aliasInfo & 0xffff,
281 (armLIR->aliasInfo & 0x80000000) ? "(+1)" : "");
282 }
283 if (mask & ENCODE_LITERAL) {
284 strcat(buf, "lit ");
285 }
286
287 if (mask & ENCODE_HEAP_REF) {
288 strcat(buf, "heap ");
289 }
290 if (mask & ENCODE_MUST_NOT_ALIAS) {
291 strcat(buf, "noalias ");
292 }
293 }
294 if (buf[0]) {
295 LOG(INFO) << prefix << ": " << buf;
296 }
297}
298
299/*
300 * Debugging macros
301 */
302#define DUMP_RESOURCE_MASK(X)
303#define DUMP_SSA_REP(X)
304
305/* Pretty-print a LIR instruction */
306void oatDumpLIRInsn(CompilationUnit* cUnit, LIR* arg, unsigned char* baseAddr)
307{
308 ArmLIR* lir = (ArmLIR*) arg;
309 if (lir->flags.isNop)
310 return;
buzbee67bf8852011-08-17 17:51:35 -0700311 int offset = lir->generic.offset;
312 int dest = lir->operands[0];
313 const bool dumpNop = false;
314
315 /* Handle pseudo-ops individually, and all regular insns as a group */
316 switch(lir->opcode) {
317 case kArmPseudoMethodEntry:
318 LOG(INFO) << "-------- method entry " <<
buzbeedfd3d702011-08-28 12:56:51 -0700319 art::PrettyMethod(cUnit->method);
buzbee67bf8852011-08-17 17:51:35 -0700320 break;
321 case kArmPseudoMethodExit:
322 LOG(INFO) << "-------- Method_Exit";
323 break;
324 case kArmPseudoBarrier:
325 LOG(INFO) << "-------- BARRIER";
326 break;
327 case kArmPseudoExtended:
328 LOG(INFO) << "-------- " << (char* ) dest;
329 break;
330 case kArmPseudoSSARep:
331 DUMP_SSA_REP(LOG(INFO) << "-------- kMirOpPhi: " << (char* ) dest);
332 break;
333 case kArmPseudoEntryBlock:
334 LOG(INFO) << "-------- entry offset: 0x" << std::hex << dest;
335 break;
336 case kArmPseudoDalvikByteCodeBoundary:
337 LOG(INFO) << "-------- dalvik offset: 0x" << std::hex <<
338 lir->generic.dalvikOffset << " @ " << (char* )lir->operands[0];
339 break;
340 case kArmPseudoExitBlock:
341 LOG(INFO) << "-------- exit offset: 0x" << std::hex << dest;
342 break;
343 case kArmPseudoPseudoAlign4:
344 LOG(INFO) << (intptr_t)baseAddr + offset << " (0x" << std::hex <<
345 offset << "): .align4";
346 break;
347 case kArmPseudoEHBlockLabel:
348 LOG(INFO) << "Exception_Handling:";
349 break;
350 case kArmPseudoTargetLabel:
351 case kArmPseudoNormalBlockLabel:
352 LOG(INFO) << "L" << (intptr_t)lir << ":";
353 break;
354 case kArmPseudoCaseLabel:
355 LOG(INFO) << "LC" << (intptr_t)lir << ": Case target 0x" <<
356 std::hex << lir->operands[0] << "|" << std::dec <<
357 lir->operands[0];
358 break;
359 default:
360 if (lir->flags.isNop && !dumpNop) {
361 break;
buzbee3ea4ec52011-08-22 17:37:19 -0700362 } else {
363 // TODO: rewrite using string
364 char opOperands[256];
365 char opName[256];
366 buildInsnString(EncodingMap[lir->opcode].name, lir, opName,
367 baseAddr, 256);
368 buildInsnString(EncodingMap[lir->opcode].fmt, lir, opOperands,
369 baseAddr, 256);
370 char tBuf[256];
371 snprintf(tBuf, 256, "%p (%04x): %-8s%s%s", baseAddr + offset, offset,
372 opName, opOperands, lir->flags.isNop ? "(nop)" : "");
373 LOG(INFO) << tBuf;
buzbee67bf8852011-08-17 17:51:35 -0700374 }
buzbee67bf8852011-08-17 17:51:35 -0700375 break;
376 }
377
378 if (lir->useMask && (!lir->flags.isNop || dumpNop)) {
379 DUMP_RESOURCE_MASK(oatDumpResourceMask((LIR* ) lir,
380 lir->useMask, "use"));
381 }
382 if (lir->defMask && (!lir->flags.isNop || dumpNop)) {
383 DUMP_RESOURCE_MASK(oatDumpResourceMask((LIR* ) lir,
384 lir->defMask, "def"));
385 }
386}
387
388/* Dump instructions and constant pool contents */
389void oatCodegenDump(CompilationUnit* cUnit)
390{
391 const Method *method = cUnit->method;
392 LOG(INFO) << "/*";
buzbeedfd3d702011-08-28 12:56:51 -0700393 LOG(INFO) << "Dumping LIR insns for " << art::PrettyMethod(cUnit->method);
buzbee67bf8852011-08-17 17:51:35 -0700394 LIR* lirInsn;
395 ArmLIR* armLIR;
396 int insnsSize = cUnit->insnsSize;
397
398 LOG(INFO) << "Regs (excluding ins) : " << cUnit->numRegs;
399 LOG(INFO) << "Ins : " << cUnit->numIns;
400 LOG(INFO) << "Outs : " << cUnit->numOuts;
401 LOG(INFO) << "Spills : " << cUnit->numSpills;
402 LOG(INFO) << "Padding : " << cUnit->numPadding;
403 LOG(INFO) << "Frame size : " << cUnit->frameSize;
404 LOG(INFO) << "Start of ins : " << cUnit->insOffset;
405 LOG(INFO) << "Start of regs : " << cUnit->regsOffset;
406 LOG(INFO) << "code size is " << cUnit->totalSize <<
407 " bytes, Dalvik size is " << insnsSize * 2;
408 LOG(INFO) << "expansion factor: " <<
409 (float)cUnit->totalSize / (float)(insnsSize * 2);
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700410 for (int i = 0; i < method->NumRegisters(); i++) {
buzbee67bf8852011-08-17 17:51:35 -0700411 RegLocation loc = cUnit->regLocation[i];
412 char buf[100];
413 if (loc.fpLocation == kLocPhysReg) {
414 snprintf(buf, 100, " : s%d", loc.fpLowReg & FP_REG_MASK);
415 } else {
416 buf[0] = 0;
417 }
418 char buf2[100];
419 snprintf(buf2, 100, "V[%02d] -> %s%d%s", i,
420 loc.location == kLocPhysReg ?
421 "r" : "SP+", loc.location == kLocPhysReg ?
422 loc.lowReg : loc.spOffset, buf);
423 LOG(INFO) << buf2;
424
425 }
426 for (lirInsn = cUnit->firstLIRInsn; lirInsn; lirInsn = lirInsn->next) {
buzbeec143c552011-08-20 17:38:58 -0700427 oatDumpLIRInsn(cUnit, lirInsn, 0);
buzbee67bf8852011-08-17 17:51:35 -0700428 }
429 for (lirInsn = cUnit->classPointerList; lirInsn; lirInsn = lirInsn->next) {
430 armLIR = (ArmLIR*) lirInsn;
431 char buf[100];
buzbeec143c552011-08-20 17:38:58 -0700432 snprintf(buf, 100, "%x (%04x): .class (%s)",
433 armLIR->generic.offset, armLIR->generic.offset,
buzbee67bf8852011-08-17 17:51:35 -0700434 ((CallsiteInfo *) armLIR->operands[0])->classDescriptor);
435 LOG(INFO) << buf;
436 }
437 for (lirInsn = cUnit->literalList; lirInsn; lirInsn = lirInsn->next) {
438 armLIR = (ArmLIR*) lirInsn;
439 char buf[100];
buzbeec143c552011-08-20 17:38:58 -0700440 snprintf(buf, 100, "%x (%04x): .word (%#x)",
441 armLIR->generic.offset, armLIR->generic.offset,
buzbee67bf8852011-08-17 17:51:35 -0700442 armLIR->operands[0]);
443 LOG(INFO) << buf;
444
445 }
446
447 int linebreak = 0;
buzbeec143c552011-08-20 17:38:58 -0700448 std::string signature = method->GetSignature()->ToModifiedUtf8();
449 std::string name = method->GetName()->ToModifiedUtf8();
450 std::string descriptor = method->GetDeclaringClass()->GetDescriptor()->
451 ToModifiedUtf8();
452
buzbee3ea4ec52011-08-22 17:37:19 -0700453 char buf[256];
buzbee67bf8852011-08-17 17:51:35 -0700454 LOG(INFO) << "*/";
buzbeec143c552011-08-20 17:38:58 -0700455 sprintf(buf,"\n u1 %s%s_%s_code[] = {", descriptor.c_str(),
456 name.c_str(), signature.c_str());
buzbee67bf8852011-08-17 17:51:35 -0700457 for (unsigned int i = 0; i < strlen(buf); i++)
458 if (buf[i] == ';') buf[i] = '_';
459 LOG(INFO) << buf;
460 strcpy(buf," ");
buzbee3ea4ec52011-08-22 17:37:19 -0700461 u1* pLiterals = (u1*)&cUnit->codeBuffer[0];
462 for (int i = 0; i < cUnit->totalSize; i++) {
463 sprintf(buf+strlen(buf),"0x%02x,", pLiterals[i]);
buzbee67bf8852011-08-17 17:51:35 -0700464 if (++linebreak == 8) {
465 linebreak = 0;
466 LOG(INFO) << buf;
467 strcpy(buf," ");
468 }
469 }
470 if (strlen(buf) > 8) {
471 LOG(INFO) << buf;
472 }
473 LOG(INFO) << " };\n\n";
474
475 // Dump mapping table
buzbee4ef76522011-09-08 10:00:32 -0700476 if (cUnit->mappingTable.size() > 0) {
buzbee67bf8852011-08-17 17:51:35 -0700477 sprintf(buf,"\n MappingTable %s%s_%s_mappingTable[%d] = {",
buzbeec143c552011-08-20 17:38:58 -0700478 descriptor.c_str(), name.c_str(), signature.c_str(),
buzbee4ef76522011-09-08 10:00:32 -0700479 cUnit->mappingTable.size());
buzbee67bf8852011-08-17 17:51:35 -0700480 for (unsigned int i = 0; i < strlen(buf); i++)
481 if (buf[i] == ';') buf[i] = '_';
482 LOG(INFO) << buf;
483 strcpy(buf," ");
buzbee4ef76522011-09-08 10:00:32 -0700484 for (uint32_t i = 0; i < cUnit->mappingTable.size(); i+=2) {
buzbee67bf8852011-08-17 17:51:35 -0700485 sprintf(buf+strlen(buf)," {0x%08x, 0x%04x},",
buzbee4ef76522011-09-08 10:00:32 -0700486 cUnit->mappingTable[i], cUnit->mappingTable[i+1]);
buzbee67bf8852011-08-17 17:51:35 -0700487 LOG(INFO) << buf;
488 strcpy(buf," ");
489 }
490 LOG(INFO) <<" };\n\n";
491 }
492}