blob: 3645643f14f4fe82a733d89badae00d6c06806ec [file] [log] [blame]
buzbeee3acd072012-02-25 17:03:10 -08001/*
2 * Copyright (C) 2012 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
19/*
20 * This file contains codegen and support common to all supported
21 * Mips variants. It is included by:
22 *
23 * Codegen-$(TARGET_ARCH_VARIANT).c
24 *
25 * which combines this common code with specific support found in the
26 * applicable directory below this one.
27 */
28
29/* Track exercised opcodes */
30static int opcodeCoverage[kNumPackedOpcodes];
31
32static void setMemRefType(MipsLIR *lir, bool isLoad, int memType)
33{
34 /* MIPSTODO simplify setMemRefType() */
35 u8 *maskPtr;
36 u8 mask = ENCODE_MEM;;
37 DCHECK(EncodingMap[lir->opcode].flags & (IS_LOAD | IS_STORE));
38
39 if (isLoad) {
40 maskPtr = &lir->useMask;
41 } else {
42 maskPtr = &lir->defMask;
43 }
44 /* Clear out the memref flags */
45 *maskPtr &= ~mask;
46 /* ..and then add back the one we need */
47 switch(memType) {
48 case kLiteral:
49 DCHECK(isLoad);
50 *maskPtr |= ENCODE_LITERAL;
51 break;
52 case kDalvikReg:
53 *maskPtr |= ENCODE_DALVIK_REG;
54 break;
55 case kHeapRef:
56 *maskPtr |= ENCODE_HEAP_REF;
57 break;
58 case kMustNotAlias:
59 /* Currently only loads can be marked as kMustNotAlias */
60 DCHECK(!(EncodingMap[lir->opcode].flags & IS_STORE));
61 *maskPtr |= ENCODE_MUST_NOT_ALIAS;
62 break;
63 default:
64 LOG(FATAL) << "Oat: invalid memref kind - " << memType;
65 }
66}
67
68/*
69 * Mark load/store instructions that access Dalvik registers through rFP +
70 * offset.
71 */
72STATIC void annotateDalvikRegAccess(MipsLIR *lir, int regId, bool isLoad)
73{
74 /* MIPSTODO simplify annotateDalvikRegAccess() */
75 setMemRefType(lir, isLoad, kDalvikReg);
76
77 /*
78 * Store the Dalvik register id in aliasInfo. Mark he MSB if it is a 64-bit
79 * access.
80 */
81 lir->aliasInfo = regId;
82 if (DOUBLEREG(lir->operands[0])) {
83 lir->aliasInfo |= 0x80000000;
84 }
85}
86
87/*
88 * Decode the register id
89 */
90STATIC inline u8 getRegMaskCommon(int reg)
91{
92 u8 seed;
93 int shift;
94 int regId = reg & 0x1f;
95
96 /*
97 * Each double register is equal to a pair of single-precision FP registers
98 */
99 if (!DOUBLEREG(reg)) {
100 seed = 1;
101 } else {
102 DCHECK_EQ((regId & 1), 0); /* double registers must be even */
103 seed = 3;
104 }
105
106 if (FPREG(reg)) {
107 DCHECK_LT(regId, 16); /* only 16 fp regs */
108 shift = kFPReg0;
109 } else if (EXTRAREG(reg)) {
110 DCHECK_LT(regId, 3); /* only 3 extra regs */
111 shift = kFPRegEnd;
112 } else {
113 shift = 0;
114 }
115
116 /* Expand the double register id into single offset */
117 shift += regId;
118 return (seed << shift);
119}
120
121/*
122 * Mark the corresponding bit(s).
123 */
124STATIC inline void setupRegMask(u8 *mask, int reg)
125{
126 *mask |= getRegMaskCommon(reg);
127}
128
129/*
130 * Set up the proper fields in the resource mask
131 */
132STATIC void setupResourceMasks(MipsLIR *lir)
133{
134 /* MIPSTODO simplify setupResourceMasks() */
135 int opcode = lir->opcode;
136 int flags;
137
138 if (opcode <= 0) {
139 lir->useMask = lir->defMask = 0;
140 return;
141 }
142
143 flags = EncodingMap[lir->opcode].flags;
144
145 // TODO: do we need this for MIPS? if so, add to inst table defs
146#if 0
147 if (flags & NEEDS_FIXUP) {
148 lir->flags.pcRelFixup = true;
149 }
150#endif
151
152 /* Set up the mask for resources that are updated */
153 if (flags & (IS_LOAD | IS_STORE)) {
154 /* Default to heap - will catch specialized classes later */
155 setMemRefType(lir, flags & IS_LOAD, kHeapRef);
156 }
157
158 /*
159 * Conservatively assume the branch here will call out a function that in
160 * turn will trash everything.
161 */
162 if (flags & IS_BRANCH) {
163 lir->defMask = lir->useMask = ENCODE_ALL;
164 return;
165 }
166
167 if (flags & REG_DEF0) {
168 setupRegMask(&lir->defMask, lir->operands[0]);
169 }
170
171 if (flags & REG_DEF1) {
172 setupRegMask(&lir->defMask, lir->operands[1]);
173 }
174
175 if (flags & REG_DEF_SP) {
176 lir->defMask |= ENCODE_REG_SP;
177 }
178
179 if (flags & REG_DEF_LR) {
180 lir->defMask |= ENCODE_REG_LR;
181 }
182
183 if (flags & REG_DEF_LIST0) {
184 lir->defMask |= ENCODE_REG_LIST(lir->operands[0]);
185 }
186
187 if (flags & REG_DEF_LIST1) {
188 lir->defMask |= ENCODE_REG_LIST(lir->operands[1]);
189 }
190
191 if (flags & SETS_CCODES) {
192 lir->defMask |= ENCODE_CCODE;
193 }
194
195 // TODO: needed for MIPS?
196 /* Conservatively treat the IT block */
197 if (flags & IS_IT) {
198 lir->defMask = ENCODE_ALL;
199 }
200
201 if (flags & (REG_USE0 | REG_USE1 | REG_USE2 | REG_USE3)) {
202 int i;
203
204 for (i = 0; i < 4; i++) {
205 if (flags & (1 << (kRegUse0 + i))) {
206 setupRegMask(&lir->useMask, lir->operands[i]);
207 }
208 }
209 }
210
211 if (flags & REG_USE_PC) {
212 lir->useMask |= ENCODE_REG_PC;
213 }
214
215 if (flags & REG_USE_SP) {
216 lir->useMask |= ENCODE_REG_SP;
217 }
218
219 if (flags & REG_USE_LIST0) {
220 lir->useMask |= ENCODE_REG_LIST(lir->operands[0]);
221 }
222
223 if (flags & REG_USE_LIST1) {
224 lir->useMask |= ENCODE_REG_LIST(lir->operands[1]);
225 }
226
227 if (flags & USES_CCODES) {
228 lir->useMask |= ENCODE_CCODE;
229 }
230}
231
232/*
233 * Set up the accurate resource mask for branch instructions
234 */
235static void relaxBranchMasks(MipsLIR *lir)
236{
237 int flags = EncodingMap[lir->opcode].flags;
238
239 /* Make sure only branch instructions are passed here */
240 DCHECK(flags & IS_BRANCH);
241
242 lir->defMask |= ENCODE_REG_PC;
243 lir->useMask |= ENCODE_REG_PC;
244
245
246 if (flags & REG_DEF_LR) {
247 lir->defMask |= ENCODE_REG_LR;
248 }
249
250 if (flags & (REG_USE0 | REG_USE1 | REG_USE2 | REG_USE3)) {
251 int i;
252
253 for (i = 0; i < 4; i++) {
254 if (flags & (1 << (kRegUse0 + i))) {
255 setupRegMask(&lir->useMask, lir->operands[i]);
256 }
257 }
258 }
259
260 if (flags & USES_CCODES) {
261 lir->useMask |= ENCODE_CCODE;
262 }
263}
264
265/*
266 * The following are building blocks to construct low-level IRs with 0 - 4
267 * operands.
268 */
269static MipsLIR *newLIR0(CompilationUnit *cUnit, MipsOpCode opcode)
270{
271 MipsLIR *insn = (MipsLIR *) oatNew(cUnit, sizeof(MipsLIR), true, kAllocLIR);
272 DCHECK(isPseudoOpCode(opcode) || (EncodingMap[opcode].flags & NO_OPERAND));
273 insn->opcode = opcode;
274 setupResourceMasks(insn);
275 insn->generic.dalvikOffset = cUnit->currentDalvikOffset;
276 oatAppendLIR(cUnit, (LIR *) insn);
277 return insn;
278}
279
280static MipsLIR *newLIR1(CompilationUnit *cUnit, MipsOpCode opcode,
281 int dest)
282{
283 MipsLIR *insn = (MipsLIR *) oatNew(cUnit, sizeof(MipsLIR), true, kAllocLIR);
284 DCHECK(isPseudoOpCode(opcode) || (EncodingMap[opcode].flags & IS_UNARY_OP));
285 insn->opcode = opcode;
286 insn->operands[0] = dest;
287 setupResourceMasks(insn);
288 insn->generic.dalvikOffset = cUnit->currentDalvikOffset;
289 oatAppendLIR(cUnit, (LIR *) insn);
290 return insn;
291}
292
293static MipsLIR *newLIR2(CompilationUnit *cUnit, MipsOpCode opcode,
294 int dest, int src1)
295{
296 MipsLIR *insn = (MipsLIR *) oatNew(cUnit, sizeof(MipsLIR), true, kAllocLIR);
297 DCHECK(isPseudoOpCode(opcode) ||
298 (EncodingMap[opcode].flags & IS_BINARY_OP));
299 insn->opcode = opcode;
300 insn->operands[0] = dest;
301 insn->operands[1] = src1;
302 setupResourceMasks(insn);
303 insn->generic.dalvikOffset = cUnit->currentDalvikOffset;
304 oatAppendLIR(cUnit, (LIR *) insn);
305 return insn;
306}
307
308static MipsLIR *newLIR3(CompilationUnit *cUnit, MipsOpCode opcode,
309 int dest, int src1, int src2)
310{
311 MipsLIR *insn = (MipsLIR *) oatNew(cUnit, sizeof(MipsLIR), true, kAllocLIR);
312 if (!(EncodingMap[opcode].flags & IS_TERTIARY_OP)) {
313 LOG(FATAL) << "Bad LIR3: " << EncodingMap[opcode].name;
314 }
315 DCHECK(isPseudoOpCode(opcode) ||
316 (EncodingMap[opcode].flags & IS_TERTIARY_OP));
317 insn->opcode = opcode;
318 insn->operands[0] = dest;
319 insn->operands[1] = src1;
320 insn->operands[2] = src2;
321 setupResourceMasks(insn);
322 insn->generic.dalvikOffset = cUnit->currentDalvikOffset;
323 oatAppendLIR(cUnit, (LIR *) insn);
324 return insn;
325}
326
327static MipsLIR *newLIR4(CompilationUnit *cUnit, MipsOpCode opcode,
328 int dest, int src1, int src2, int info)
329{
330 MipsLIR *insn = (MipsLIR *) oatNew(cUnit, sizeof(MipsLIR), true, kAllocLIR);
331 DCHECK(isPseudoOpCode(opcode) ||
332 (EncodingMap[opcode].flags & IS_QUAD_OP));
333 insn->opcode = opcode;
334 insn->operands[0] = dest;
335 insn->operands[1] = src1;
336 insn->operands[2] = src2;
337 insn->operands[3] = info;
338 setupResourceMasks(insn);
339 insn->generic.dalvikOffset = cUnit->currentDalvikOffset;
340 oatAppendLIR(cUnit, (LIR *) insn);
341 return insn;
342}
343
344/*
345 * The following are building blocks to insert constants into the pool or
346 * instruction streams.
347 */
348
349/* Add a 32-bit constant either in the constant pool or mixed with code */
350static MipsLIR *addWordData(CompilationUnit *cUnit, LIR **constantListP,
351 int value)
352{
353 /* Add the constant to the literal pool */
354 if (constantListP) {
355 MipsLIR *newValue = (MipsLIR *) oatNew(cUnit, sizeof(MipsLIR), true,
356 kAllocData);
357 newValue->operands[0] = value;
358 newValue->generic.next = *constantListP;
359 *constantListP = (LIR *) newValue;
360 return newValue;
361 } else {
362 /* Add the constant in the middle of code stream */
363 newLIR1(cUnit, kMips32BitData, value);
364 }
365 return NULL;
366}
367
368/*
369 * Generate an kMipsPseudoBarrier marker to indicate the boundary of special
370 * blocks.
371 */
372static void genBarrier(CompilationUnit *cUnit)
373{
374 MipsLIR *barrier = newLIR0(cUnit, kMipsPseudoBarrier);
375 /* Mark all resources as being clobbered */
376 barrier->defMask = -1;
377}
378
379} // namespace art