blob: 8dbb9a3506ee9f5d45fc89e232b500f8ec5a8be8 [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
buzbeee3acd072012-02-25 17:03:10 -080029static void setMemRefType(MipsLIR *lir, bool isLoad, int memType)
30{
31 /* MIPSTODO simplify setMemRefType() */
32 u8 *maskPtr;
33 u8 mask = ENCODE_MEM;;
34 DCHECK(EncodingMap[lir->opcode].flags & (IS_LOAD | IS_STORE));
35
36 if (isLoad) {
37 maskPtr = &lir->useMask;
38 } else {
39 maskPtr = &lir->defMask;
40 }
41 /* Clear out the memref flags */
42 *maskPtr &= ~mask;
43 /* ..and then add back the one we need */
44 switch(memType) {
45 case kLiteral:
46 DCHECK(isLoad);
47 *maskPtr |= ENCODE_LITERAL;
48 break;
49 case kDalvikReg:
50 *maskPtr |= ENCODE_DALVIK_REG;
51 break;
52 case kHeapRef:
53 *maskPtr |= ENCODE_HEAP_REF;
54 break;
55 case kMustNotAlias:
56 /* Currently only loads can be marked as kMustNotAlias */
57 DCHECK(!(EncodingMap[lir->opcode].flags & IS_STORE));
58 *maskPtr |= ENCODE_MUST_NOT_ALIAS;
59 break;
60 default:
61 LOG(FATAL) << "Oat: invalid memref kind - " << memType;
62 }
63}
64
65/*
66 * Mark load/store instructions that access Dalvik registers through rFP +
67 * offset.
68 */
69STATIC void annotateDalvikRegAccess(MipsLIR *lir, int regId, bool isLoad)
70{
71 /* MIPSTODO simplify annotateDalvikRegAccess() */
72 setMemRefType(lir, isLoad, kDalvikReg);
73
74 /*
75 * Store the Dalvik register id in aliasInfo. Mark he MSB if it is a 64-bit
76 * access.
77 */
78 lir->aliasInfo = regId;
79 if (DOUBLEREG(lir->operands[0])) {
80 lir->aliasInfo |= 0x80000000;
81 }
82}
83
84/*
85 * Decode the register id
86 */
87STATIC inline u8 getRegMaskCommon(int reg)
88{
89 u8 seed;
90 int shift;
91 int regId = reg & 0x1f;
92
93 /*
94 * Each double register is equal to a pair of single-precision FP registers
95 */
96 if (!DOUBLEREG(reg)) {
97 seed = 1;
98 } else {
99 DCHECK_EQ((regId & 1), 0); /* double registers must be even */
100 seed = 3;
101 }
102
103 if (FPREG(reg)) {
104 DCHECK_LT(regId, 16); /* only 16 fp regs */
105 shift = kFPReg0;
106 } else if (EXTRAREG(reg)) {
107 DCHECK_LT(regId, 3); /* only 3 extra regs */
108 shift = kFPRegEnd;
109 } else {
110 shift = 0;
111 }
112
113 /* Expand the double register id into single offset */
114 shift += regId;
115 return (seed << shift);
116}
117
118/*
119 * Mark the corresponding bit(s).
120 */
121STATIC inline void setupRegMask(u8 *mask, int reg)
122{
123 *mask |= getRegMaskCommon(reg);
124}
125
126/*
127 * Set up the proper fields in the resource mask
128 */
129STATIC void setupResourceMasks(MipsLIR *lir)
130{
131 /* MIPSTODO simplify setupResourceMasks() */
132 int opcode = lir->opcode;
133 int flags;
134
135 if (opcode <= 0) {
136 lir->useMask = lir->defMask = 0;
137 return;
138 }
139
140 flags = EncodingMap[lir->opcode].flags;
141
142 // TODO: do we need this for MIPS? if so, add to inst table defs
143#if 0
144 if (flags & NEEDS_FIXUP) {
145 lir->flags.pcRelFixup = true;
146 }
147#endif
148
149 /* Set up the mask for resources that are updated */
150 if (flags & (IS_LOAD | IS_STORE)) {
151 /* Default to heap - will catch specialized classes later */
152 setMemRefType(lir, flags & IS_LOAD, kHeapRef);
153 }
154
155 /*
156 * Conservatively assume the branch here will call out a function that in
157 * turn will trash everything.
158 */
159 if (flags & IS_BRANCH) {
160 lir->defMask = lir->useMask = ENCODE_ALL;
161 return;
162 }
163
164 if (flags & REG_DEF0) {
165 setupRegMask(&lir->defMask, lir->operands[0]);
166 }
167
168 if (flags & REG_DEF1) {
169 setupRegMask(&lir->defMask, lir->operands[1]);
170 }
171
172 if (flags & REG_DEF_SP) {
173 lir->defMask |= ENCODE_REG_SP;
174 }
175
176 if (flags & REG_DEF_LR) {
177 lir->defMask |= ENCODE_REG_LR;
178 }
179
180 if (flags & REG_DEF_LIST0) {
181 lir->defMask |= ENCODE_REG_LIST(lir->operands[0]);
182 }
183
184 if (flags & REG_DEF_LIST1) {
185 lir->defMask |= ENCODE_REG_LIST(lir->operands[1]);
186 }
187
188 if (flags & SETS_CCODES) {
189 lir->defMask |= ENCODE_CCODE;
190 }
191
192 // TODO: needed for MIPS?
193 /* Conservatively treat the IT block */
194 if (flags & IS_IT) {
195 lir->defMask = ENCODE_ALL;
196 }
197
198 if (flags & (REG_USE0 | REG_USE1 | REG_USE2 | REG_USE3)) {
199 int i;
200
201 for (i = 0; i < 4; i++) {
202 if (flags & (1 << (kRegUse0 + i))) {
203 setupRegMask(&lir->useMask, lir->operands[i]);
204 }
205 }
206 }
207
208 if (flags & REG_USE_PC) {
209 lir->useMask |= ENCODE_REG_PC;
210 }
211
212 if (flags & REG_USE_SP) {
213 lir->useMask |= ENCODE_REG_SP;
214 }
215
216 if (flags & REG_USE_LIST0) {
217 lir->useMask |= ENCODE_REG_LIST(lir->operands[0]);
218 }
219
220 if (flags & REG_USE_LIST1) {
221 lir->useMask |= ENCODE_REG_LIST(lir->operands[1]);
222 }
223
224 if (flags & USES_CCODES) {
225 lir->useMask |= ENCODE_CCODE;
226 }
227}
228
229/*
buzbeee3acd072012-02-25 17:03:10 -0800230 * The following are building blocks to construct low-level IRs with 0 - 4
231 * operands.
232 */
buzbee31a4a6f2012-02-28 15:36:15 -0800233MipsLIR *newLIR0(CompilationUnit *cUnit, MipsOpCode opcode)
buzbeee3acd072012-02-25 17:03:10 -0800234{
235 MipsLIR *insn = (MipsLIR *) oatNew(cUnit, sizeof(MipsLIR), true, kAllocLIR);
buzbee31a4a6f2012-02-28 15:36:15 -0800236 DCHECK(isPseudoOpcode(opcode) || (EncodingMap[opcode].flags & NO_OPERAND));
buzbeee3acd072012-02-25 17:03:10 -0800237 insn->opcode = opcode;
238 setupResourceMasks(insn);
239 insn->generic.dalvikOffset = cUnit->currentDalvikOffset;
240 oatAppendLIR(cUnit, (LIR *) insn);
241 return insn;
242}
243
buzbee31a4a6f2012-02-28 15:36:15 -0800244MipsLIR *newLIR1(CompilationUnit *cUnit, MipsOpCode opcode,
buzbeee3acd072012-02-25 17:03:10 -0800245 int dest)
246{
247 MipsLIR *insn = (MipsLIR *) oatNew(cUnit, sizeof(MipsLIR), true, kAllocLIR);
buzbee31a4a6f2012-02-28 15:36:15 -0800248 DCHECK(isPseudoOpcode(opcode) || (EncodingMap[opcode].flags & IS_UNARY_OP));
buzbeee3acd072012-02-25 17:03:10 -0800249 insn->opcode = opcode;
250 insn->operands[0] = dest;
251 setupResourceMasks(insn);
252 insn->generic.dalvikOffset = cUnit->currentDalvikOffset;
253 oatAppendLIR(cUnit, (LIR *) insn);
254 return insn;
255}
256
buzbee31a4a6f2012-02-28 15:36:15 -0800257MipsLIR *newLIR2(CompilationUnit *cUnit, MipsOpCode opcode,
buzbeee3acd072012-02-25 17:03:10 -0800258 int dest, int src1)
259{
260 MipsLIR *insn = (MipsLIR *) oatNew(cUnit, sizeof(MipsLIR), true, kAllocLIR);
buzbee31a4a6f2012-02-28 15:36:15 -0800261 DCHECK(isPseudoOpcode(opcode) ||
buzbeee3acd072012-02-25 17:03:10 -0800262 (EncodingMap[opcode].flags & IS_BINARY_OP));
263 insn->opcode = opcode;
264 insn->operands[0] = dest;
265 insn->operands[1] = src1;
266 setupResourceMasks(insn);
267 insn->generic.dalvikOffset = cUnit->currentDalvikOffset;
268 oatAppendLIR(cUnit, (LIR *) insn);
269 return insn;
270}
271
buzbee31a4a6f2012-02-28 15:36:15 -0800272MipsLIR *newLIR3(CompilationUnit *cUnit, MipsOpCode opcode,
buzbeee3acd072012-02-25 17:03:10 -0800273 int dest, int src1, int src2)
274{
275 MipsLIR *insn = (MipsLIR *) oatNew(cUnit, sizeof(MipsLIR), true, kAllocLIR);
276 if (!(EncodingMap[opcode].flags & IS_TERTIARY_OP)) {
277 LOG(FATAL) << "Bad LIR3: " << EncodingMap[opcode].name;
278 }
buzbee31a4a6f2012-02-28 15:36:15 -0800279 DCHECK(isPseudoOpcode(opcode) ||
buzbeee3acd072012-02-25 17:03:10 -0800280 (EncodingMap[opcode].flags & IS_TERTIARY_OP));
281 insn->opcode = opcode;
282 insn->operands[0] = dest;
283 insn->operands[1] = src1;
284 insn->operands[2] = src2;
285 setupResourceMasks(insn);
286 insn->generic.dalvikOffset = cUnit->currentDalvikOffset;
287 oatAppendLIR(cUnit, (LIR *) insn);
288 return insn;
289}
290
buzbee31a4a6f2012-02-28 15:36:15 -0800291MipsLIR *newLIR4(CompilationUnit *cUnit, MipsOpCode opcode,
buzbeee3acd072012-02-25 17:03:10 -0800292 int dest, int src1, int src2, int info)
293{
294 MipsLIR *insn = (MipsLIR *) oatNew(cUnit, sizeof(MipsLIR), true, kAllocLIR);
buzbee31a4a6f2012-02-28 15:36:15 -0800295 DCHECK(isPseudoOpcode(opcode) ||
buzbeee3acd072012-02-25 17:03:10 -0800296 (EncodingMap[opcode].flags & IS_QUAD_OP));
297 insn->opcode = opcode;
298 insn->operands[0] = dest;
299 insn->operands[1] = src1;
300 insn->operands[2] = src2;
301 insn->operands[3] = info;
302 setupResourceMasks(insn);
303 insn->generic.dalvikOffset = cUnit->currentDalvikOffset;
304 oatAppendLIR(cUnit, (LIR *) insn);
305 return insn;
306}
307
308/*
buzbee31a4a6f2012-02-28 15:36:15 -0800309 * Generate an kPseudoBarrier marker to indicate the boundary of special
buzbeee3acd072012-02-25 17:03:10 -0800310 * blocks.
311 */
312static void genBarrier(CompilationUnit *cUnit)
313{
buzbee31a4a6f2012-02-28 15:36:15 -0800314 MipsLIR *barrier = newLIR0(cUnit, kPseudoBarrier);
buzbeee3acd072012-02-25 17:03:10 -0800315 /* Mark all resources as being clobbered */
316 barrier->defMask = -1;
317}
318
319} // namespace art