1 /*
2 * Copyright (C) 2009 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 "libdex/DexOpcodes.h"
19 #include "MipsLIR.h"
20
21 /* For dumping instructions */
22 #define MIPS_REG_COUNT 32
23 static const char *mipsRegName[MIPS_REG_COUNT] = {
24 "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
25 "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
26 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
27 "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra"
28 };
29
30 /*
31 * Interpret a format string and build a string no longer than size
32 * See format key in Assemble.c.
33 */
buildInsnString(const char * fmt,MipsLIR * lir,char * buf,unsigned char * baseAddr,int size)34 static void buildInsnString(const char *fmt, MipsLIR *lir, char* buf,
35 unsigned char *baseAddr, int size)
36 {
37 int i;
38 char *bufEnd = &buf[size-1];
39 const char *fmtEnd = &fmt[strlen(fmt)];
40 char tbuf[256];
41 char nc;
42 while (fmt < fmtEnd) {
43 int operand;
44 if (*fmt == '!') {
45 fmt++;
46 assert(fmt < fmtEnd);
47 nc = *fmt++;
48 if (nc=='!') {
49 strcpy(tbuf, "!");
50 } else {
51 assert(fmt < fmtEnd);
52 assert((unsigned)(nc-'0') < 4);
53 operand = lir->operands[nc-'0'];
54 switch(*fmt++) {
55 case 'b':
56 strcpy(tbuf,"0000");
57 for (i=3; i>= 0; i--) {
58 tbuf[i] += operand & 1;
59 operand >>= 1;
60 }
61 break;
62 case 's':
63 sprintf(tbuf,"$f%d",operand & FP_REG_MASK);
64 break;
65 case 'S':
66 assert(((operand & FP_REG_MASK) & 1) == 0);
67 sprintf(tbuf,"$f%d",operand & FP_REG_MASK);
68 break;
69 case 'h':
70 sprintf(tbuf,"%04x", operand);
71 break;
72 case 'M':
73 case 'd':
74 sprintf(tbuf,"%d", operand);
75 break;
76 case 'D':
77 sprintf(tbuf,"%d", operand+1);
78 break;
79 case 'E':
80 sprintf(tbuf,"%d", operand*4);
81 break;
82 case 'F':
83 sprintf(tbuf,"%d", operand*2);
84 break;
85 case 'c':
86 switch (operand) {
87 case kMipsCondEq:
88 strcpy(tbuf, "eq");
89 break;
90 case kMipsCondNe:
91 strcpy(tbuf, "ne");
92 break;
93 case kMipsCondLt:
94 strcpy(tbuf, "lt");
95 break;
96 case kMipsCondGe:
97 strcpy(tbuf, "ge");
98 break;
99 case kMipsCondGt:
100 strcpy(tbuf, "gt");
101 break;
102 case kMipsCondLe:
103 strcpy(tbuf, "le");
104 break;
105 case kMipsCondCs:
106 strcpy(tbuf, "cs");
107 break;
108 case kMipsCondMi:
109 strcpy(tbuf, "mi");
110 break;
111 default:
112 strcpy(tbuf, "");
113 break;
114 }
115 break;
116 case 't':
117 sprintf(tbuf,"0x%08x (L%p)",
118 (int) baseAddr + lir->generic.offset + 4 +
119 (operand << 2),
120 lir->generic.target);
121 break;
122 case 'T':
123 sprintf(tbuf,"0x%08x",
124 (int) (operand << 2));
125 break;
126 case 'u': {
127 int offset_1 = lir->operands[0];
128 int offset_2 = NEXT_LIR(lir)->operands[0];
129 intptr_t target =
130 ((((intptr_t) baseAddr + lir->generic.offset + 4) &
131 ~3) + (offset_1 << 21 >> 9) + (offset_2 << 1)) &
132 0xfffffffc;
133 sprintf(tbuf, "%p", (void *) target);
134 break;
135 }
136
137 /* Nothing to print for BLX_2 */
138 case 'v':
139 strcpy(tbuf, "see above");
140 break;
141 case 'r':
142 assert(operand >= 0 && operand < MIPS_REG_COUNT);
143 strcpy(tbuf, mipsRegName[operand]);
144 break;
145 default:
146 strcpy(tbuf,"DecodeError");
147 break;
148 }
149 if (buf+strlen(tbuf) <= bufEnd) {
150 strcpy(buf, tbuf);
151 buf += strlen(tbuf);
152 } else {
153 break;
154 }
155 }
156 } else {
157 *buf++ = *fmt++;
158 }
159 if (buf == bufEnd)
160 break;
161 }
162 *buf = 0;
163 }
164
dvmDumpResourceMask(LIR * lir,u8 mask,const char * prefix)165 void dvmDumpResourceMask(LIR *lir, u8 mask, const char *prefix)
166 {
167 char buf[256];
168 buf[0] = 0;
169 MipsLIR *mipsLIR = (MipsLIR *) lir;
170
171 if (mask == ENCODE_ALL) {
172 strcpy(buf, "all");
173 } else {
174 char num[8];
175 int i;
176
177 for (i = 0; i < kRegEnd; i++) {
178 if (mask & (1ULL << i)) {
179 sprintf(num, "%d ", i);
180 strcat(buf, num);
181 }
182 }
183
184 if (mask & ENCODE_CCODE) {
185 strcat(buf, "cc ");
186 }
187 if (mask & ENCODE_FP_STATUS) {
188 strcat(buf, "fpcc ");
189 }
190 /* Memory bits */
191 if (mipsLIR && (mask & ENCODE_DALVIK_REG)) {
192 sprintf(buf + strlen(buf), "dr%d%s", mipsLIR->aliasInfo & 0xffff,
193 (mipsLIR->aliasInfo & 0x80000000) ? "(+1)" : "");
194 }
195 if (mask & ENCODE_LITERAL) {
196 strcat(buf, "lit ");
197 }
198
199 if (mask & ENCODE_HEAP_REF) {
200 strcat(buf, "heap ");
201 }
202 if (mask & ENCODE_MUST_NOT_ALIAS) {
203 strcat(buf, "noalias ");
204 }
205 }
206 if (buf[0]) {
207 ALOGD("%s: %s", prefix, buf);
208 }
209 }
210
211 /*
212 * Debugging macros
213 */
214 #define DUMP_RESOURCE_MASK(X)
215 #define DUMP_SSA_REP(X)
216
217 /* Pretty-print a LIR instruction */
dvmDumpLIRInsn(LIR * arg,unsigned char * baseAddr)218 void dvmDumpLIRInsn(LIR *arg, unsigned char *baseAddr)
219 {
220 MipsLIR *lir = (MipsLIR *) arg;
221 char buf[256];
222 char opName[256];
223 int offset = lir->generic.offset;
224 int dest = lir->operands[0];
225 const bool dumpNop = false;
226
227 /* Handle pseudo-ops individually, and all regular insns as a group */
228 switch(lir->opcode) {
229 case kMipsChainingCellBottom:
230 ALOGD("-------- end of chaining cells (0x%04x)", offset);
231 break;
232 case kMipsPseudoBarrier:
233 ALOGD("-------- BARRIER");
234 break;
235 case kMipsPseudoExtended:
236 /* intentional fallthrough */
237 case kMipsPseudoSSARep:
238 DUMP_SSA_REP(ALOGD("-------- %s", (char *) dest));
239 break;
240 case kMipsPseudoChainingCellBackwardBranch:
241 ALOGD("L%p:", lir);
242 ALOGD("-------- chaining cell (backward branch): 0x%04x", dest);
243 break;
244 case kMipsPseudoChainingCellNormal:
245 ALOGD("L%p:", lir);
246 ALOGD("-------- chaining cell (normal): 0x%04x", dest);
247 break;
248 case kMipsPseudoChainingCellHot:
249 ALOGD("L%p:", lir);
250 ALOGD("-------- chaining cell (hot): 0x%04x", dest);
251 break;
252 case kMipsPseudoChainingCellInvokePredicted:
253 ALOGD("L%p:", lir);
254 ALOGD("-------- chaining cell (predicted): %s%s",
255 dest ? ((Method *) dest)->clazz->descriptor : "",
256 dest ? ((Method *) dest)->name : "N/A");
257 break;
258 case kMipsPseudoChainingCellInvokeSingleton:
259 ALOGD("L%p:", lir);
260 ALOGD("-------- chaining cell (invoke singleton): %s%s/%p",
261 ((Method *)dest)->clazz->descriptor,
262 ((Method *)dest)->name,
263 ((Method *)dest)->insns);
264 break;
265 case kMipsPseudoEntryBlock:
266 ALOGD("-------- entry offset: 0x%04x", dest);
267 break;
268 case kMipsPseudoDalvikByteCodeBoundary:
269 ALOGD("-------- dalvik offset: 0x%04x @ %s", dest,
270 (char *) lir->operands[1]);
271 break;
272 case kMipsPseudoExitBlock:
273 ALOGD("-------- exit offset: 0x%04x", dest);
274 break;
275 case kMipsPseudoPseudoAlign4:
276 ALOGD("%p (%04x): .align4", baseAddr + offset, offset);
277 break;
278 case kMipsPseudoPCReconstructionCell:
279 ALOGD("L%p:", lir);
280 ALOGD("-------- reconstruct dalvik PC : 0x%04x @ +0x%04x", dest,
281 lir->operands[1]);
282 break;
283 case kMipsPseudoPCReconstructionBlockLabel:
284 /* Do nothing */
285 break;
286 case kMipsPseudoEHBlockLabel:
287 ALOGD("Exception_Handling:");
288 break;
289 case kMipsPseudoTargetLabel:
290 case kMipsPseudoNormalBlockLabel:
291 ALOGD("L%p:", lir);
292 break;
293 default:
294 if (lir->flags.isNop && !dumpNop) {
295 break;
296 }
297 buildInsnString(EncodingMap[lir->opcode].name, lir, opName,
298 baseAddr, 256);
299 buildInsnString(EncodingMap[lir->opcode].fmt, lir, buf, baseAddr,
300 256);
301 ALOGD("%p (%04x): %08x %-9s%s%s",
302 baseAddr + offset, offset, *(u4 *)(baseAddr + offset), opName, buf,
303 lir->flags.isNop ? "(nop)" : "");
304 break;
305 }
306
307 if (lir->useMask && (!lir->flags.isNop || dumpNop)) {
308 DUMP_RESOURCE_MASK(dvmDumpResourceMask((LIR *) lir,
309 lir->useMask, "use"));
310 }
311 if (lir->defMask && (!lir->flags.isNop || dumpNop)) {
312 DUMP_RESOURCE_MASK(dvmDumpResourceMask((LIR *) lir,
313 lir->defMask, "def"));
314 }
315 }
316
317 /* Dump instructions and constant pool contents */
dvmCompilerCodegenDump(CompilationUnit * cUnit)318 void dvmCompilerCodegenDump(CompilationUnit *cUnit)
319 {
320 ALOGD("Dumping LIR insns");
321 LIR *lirInsn;
322 MipsLIR *mipsLIR;
323
324 ALOGD("installed code is at %p", cUnit->baseAddr);
325 ALOGD("total size is %d bytes", cUnit->totalSize);
326 for (lirInsn = cUnit->firstLIRInsn; lirInsn; lirInsn = lirInsn->next) {
327 dvmDumpLIRInsn(lirInsn, (unsigned char *) cUnit->baseAddr);
328 }
329 for (lirInsn = cUnit->classPointerList; lirInsn; lirInsn = lirInsn->next) {
330 mipsLIR = (MipsLIR *) lirInsn;
331 ALOGD("%p (%04x): .class (%s)",
332 (char*)cUnit->baseAddr + mipsLIR->generic.offset,
333 mipsLIR->generic.offset,
334 ((CallsiteInfo *) mipsLIR->operands[0])->classDescriptor);
335 }
336 for (lirInsn = cUnit->literalList; lirInsn; lirInsn = lirInsn->next) {
337 mipsLIR = (MipsLIR *) lirInsn;
338 ALOGD("%p (%04x): .word (%#x)",
339 (char*)cUnit->baseAddr + mipsLIR->generic.offset,
340 mipsLIR->generic.offset,
341 mipsLIR->operands[0]);
342 }
343 }
344
345 /* Target-specific cache flushing */
dvmCompilerCacheFlush(long start,long end,long flags)346 void dvmCompilerCacheFlush(long start, long end, long flags)
347 {
348 cacheflush(start, end, flags);
349 }
350
351 /* Target-specific cache clearing */
dvmCompilerCacheClear(char * start,size_t size)352 void dvmCompilerCacheClear(char *start, size_t size)
353 {
354 /* 0x66 is an invalid opcode for mips. */
355 memset(start, 0x66, size);
356 }
357