blob: 2d15318b44bb59b35828eaa73004ac4595910c04 [file] [log] [blame]
buzbeee88dfbf2012-03-05 11:19:57 -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
17/*
18 * This file contains x86-specific codegen factory support.
19 * It is included by
20 *
21 * Codegen-$(TARGET_ARCH_VARIANT).c
22 *
23 */
24
25namespace art {
26
27bool genAddLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
28 RegLocation rlSrc1, RegLocation rlSrc2)
29{
30 UNIMPLEMENTED(WARNING) << "genAddLong";
31#if 0
32 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
33 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
34 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
35 /*
36 * [v1 v0] = [a1 a0] + [a3 a2];
37 * addu v0,a2,a0
38 * addu t1,a3,a1
39 * sltu v1,v0,a2
40 * addu v1,v1,t1
41 */
42
43 opRegRegReg(cUnit, kOpAdd, rlResult.lowReg, rlSrc2.lowReg, rlSrc1.lowReg);
44 int tReg = oatAllocTemp(cUnit);
45 opRegRegReg(cUnit, kOpAdd, tReg, rlSrc2.highReg, rlSrc1.highReg);
buzbeea7678db2012-03-05 15:35:46 -080046 newLIR3(cUnit, kX86Sltu, rlResult.highReg, rlResult.lowReg, rlSrc2.lowReg);
buzbeee88dfbf2012-03-05 11:19:57 -080047 opRegRegReg(cUnit, kOpAdd, rlResult.highReg, rlResult.highReg, tReg);
48 oatFreeTemp(cUnit, tReg);
49 storeValueWide(cUnit, rlDest, rlResult);
50#endif
51 return false;
52}
53
54bool genSubLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
55 RegLocation rlSrc1, RegLocation rlSrc2)
56{
57 UNIMPLEMENTED(WARNING) << "genSubLong";
58#if 0
59 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
60 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
61 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
62 /*
63 * [v1 v0] = [a1 a0] - [a3 a2];
64 * subu v0,a0,a2
65 * subu v1,a1,a3
66 * sltu t1,a0,v0
67 * subu v1,v1,t1
68 */
69
70 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, rlSrc1.lowReg, rlSrc2.lowReg);
71 opRegRegReg(cUnit, kOpSub, rlResult.highReg, rlSrc1.highReg, rlSrc2.highReg);
72 int tReg = oatAllocTemp(cUnit);
buzbeea7678db2012-03-05 15:35:46 -080073 newLIR3(cUnit, kX86Sltu, tReg, rlSrc1.lowReg, rlResult.lowReg);
buzbeee88dfbf2012-03-05 11:19:57 -080074 opRegRegReg(cUnit, kOpSub, rlResult.highReg, rlResult.highReg, tReg);
75 oatFreeTemp(cUnit, tReg);
76 storeValueWide(cUnit, rlDest, rlResult);
77#endif
78 return false;
79}
80
81bool genNegLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
82 RegLocation rlSrc)
83{
84 UNIMPLEMENTED(WARNING) << "genNegLong";
85#if 0
86 rlSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
87 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
88 /*
89 * [v1 v0] = -[a1 a0]
90 * negu v0,a0
91 * negu v1,a1
92 * sltu t1,r_zero
93 * subu v1,v1,t1
94 */
95
96 opRegReg(cUnit, kOpNeg, rlResult.lowReg, rlSrc.lowReg);
97 opRegReg(cUnit, kOpNeg, rlResult.highReg, rlSrc.highReg);
98 int tReg = oatAllocTemp(cUnit);
buzbeea7678db2012-03-05 15:35:46 -080099 newLIR3(cUnit, kX86Sltu, tReg, r_ZERO, rlResult.lowReg);
buzbeee88dfbf2012-03-05 11:19:57 -0800100 opRegRegReg(cUnit, kOpSub, rlResult.highReg, rlResult.highReg, tReg);
101 oatFreeTemp(cUnit, tReg);
102 storeValueWide(cUnit, rlDest, rlResult);
103#endif
104 return false;
105}
106
107void genDebuggerUpdate(CompilationUnit* cUnit, int32_t offset);
108
109/*
110 * In the Arm code a it is typical to use the link register
buzbeea7678db2012-03-05 15:35:46 -0800111 * to hold the target address. However, for X86 we must
buzbeee88dfbf2012-03-05 11:19:57 -0800112 * ensure that all branch instructions can be restarted if
113 * there is a trap in the shadow. Allocate a temp register.
114 */
115int loadHelper(CompilationUnit* cUnit, int offset)
116{
buzbeea7678db2012-03-05 15:35:46 -0800117 UNIMPLEMENTED(WARNING);
118 return 0;
119#if 0
buzbeee88dfbf2012-03-05 11:19:57 -0800120 int tReg = oatAllocTemp(cUnit);
121 loadWordDisp(cUnit, rSELF, offset, tReg);
122 return tReg;
buzbeea7678db2012-03-05 15:35:46 -0800123#endif
buzbeee88dfbf2012-03-05 11:19:57 -0800124}
125
126void spillCoreRegs(CompilationUnit* cUnit)
127{
128 if (cUnit->numCoreSpills == 0) {
129 return;
130 }
buzbeee88dfbf2012-03-05 11:19:57 -0800131 uint32_t mask = cUnit->coreSpillMask;
Ian Rogersb5d09b22012-03-06 22:14:17 -0800132 int offset = cUnit->frameSize - 4;
buzbeee88dfbf2012-03-05 11:19:57 -0800133 for (int reg = 0; mask; mask >>= 1, reg++) {
134 if (mask & 0x1) {
135 offset -= 4;
136 storeWordDisp(cUnit, rSP, offset, reg);
137 }
138 }
buzbeee88dfbf2012-03-05 11:19:57 -0800139}
140
141void unSpillCoreRegs(CompilationUnit* cUnit)
142{
143 if (cUnit->numCoreSpills == 0) {
144 return;
145 }
buzbeee88dfbf2012-03-05 11:19:57 -0800146 uint32_t mask = cUnit->coreSpillMask;
Ian Rogersb5d09b22012-03-06 22:14:17 -0800147 int offset = cUnit->frameSize - 4;
buzbeee88dfbf2012-03-05 11:19:57 -0800148 for (int reg = 0; mask; mask >>= 1, reg++) {
149 if (mask & 0x1) {
150 offset -= 4;
151 loadWordDisp(cUnit, rSP, offset, reg);
152 }
153 }
Ian Rogersb5d09b22012-03-06 22:14:17 -0800154}
155
156void opRegThreadMem(CompilationUnit* cUnit, OpKind op, int rDest, int threadOffset) {
157 X86OpCode opcode = kX86Bkpt;
158 switch (op) {
159 case kOpCmp: opcode = kX86Cmp32RT; break;
160 default:
161 LOG(FATAL) << "Bad opcode: " << op;
162 break;
163 }
164 DCHECK((EncodingMap[opcode].flags & IS_BINARY_OP) != 0);
165 newLIR2(cUnit, opcode, rDest, threadOffset);
buzbeee88dfbf2012-03-05 11:19:57 -0800166}
167
168void genEntrySequence(CompilationUnit* cUnit, BasicBlock* bb)
169{
buzbeee88dfbf2012-03-05 11:19:57 -0800170 /*
Ian Rogersb5d09b22012-03-06 22:14:17 -0800171 * On entry, rARG0, rARG1, rARG2 are live. Let the register
buzbeee88dfbf2012-03-05 11:19:57 -0800172 * allocation mechanism know so it doesn't try to use any of them when
173 * expanding the frame or flushing. This leaves the utility
Ian Rogersb5d09b22012-03-06 22:14:17 -0800174 * code with no spare temps.
buzbeee88dfbf2012-03-05 11:19:57 -0800175 */
176 oatLockTemp(cUnit, rARG0);
177 oatLockTemp(cUnit, rARG1);
178 oatLockTemp(cUnit, rARG2);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800179
180 /* Build frame, return address already on stack */
181 opRegImm(cUnit, kOpSub, rSP, cUnit->frameSize - 4);
buzbeee88dfbf2012-03-05 11:19:57 -0800182
183 /*
184 * We can safely skip the stack overflow check if we're
185 * a leaf *and* our frame size < fudge factor.
186 */
187 bool skipOverflowCheck = ((cUnit->attrs & METHOD_IS_LEAF) &&
188 ((size_t)cUnit->frameSize <
189 Thread::kStackOverflowReservedBytes));
190 newLIR0(cUnit, kPseudoMethodEntry);
buzbeee88dfbf2012-03-05 11:19:57 -0800191 /* Spill core callee saves */
192 spillCoreRegs(cUnit);
193 /* NOTE: promotion of FP regs currently unsupported, thus no FP spill */
194 DCHECK_EQ(cUnit->numFPSpills, 0);
195 if (!skipOverflowCheck) {
Ian Rogersb5d09b22012-03-06 22:14:17 -0800196 // cmp rSP, fs:[stack_end_]; jcc throw_launchpad
197 LIR* tgt = rawLIR(cUnit, 0, kPseudoThrowTarget, kThrowStackOverflow, 0, 0, 0, 0);
198 opRegThreadMem(cUnit, kOpCmp, rSP, Thread::StackEndOffset().Int32Value());
199 opCondBranch(cUnit, kCondUlt, tgt);
200 // Remember branch target - will process later
201 oatInsertGrowableList(cUnit, &cUnit->throwLaunchpads, (intptr_t)tgt);
buzbeee88dfbf2012-03-05 11:19:57 -0800202 }
Ian Rogersb5d09b22012-03-06 22:14:17 -0800203 /* Spill Method* */
buzbeee88dfbf2012-03-05 11:19:57 -0800204 storeBaseDisp(cUnit, rSP, 0, rARG0, kWord);
205 flushIns(cUnit);
206
207 if (cUnit->genDebugger) {
208 // Refresh update debugger callout
Ian Rogersb5d09b22012-03-06 22:14:17 -0800209 UNIMPLEMENTED(WARNING) << "genDebugger";
210#if 0
buzbeee88dfbf2012-03-05 11:19:57 -0800211 loadWordDisp(cUnit, rSELF,
212 OFFSETOF_MEMBER(Thread, pUpdateDebuggerFromCode), rSUSPEND);
213 genDebuggerUpdate(cUnit, DEBUGGER_METHOD_ENTRY);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800214#endif
buzbeee88dfbf2012-03-05 11:19:57 -0800215 }
216
217 oatFreeTemp(cUnit, rARG0);
218 oatFreeTemp(cUnit, rARG1);
219 oatFreeTemp(cUnit, rARG2);
buzbeee88dfbf2012-03-05 11:19:57 -0800220}
221
Ian Rogersb5d09b22012-03-06 22:14:17 -0800222void genExitSequence(CompilationUnit* cUnit, BasicBlock* bb) {
223 /*
224 * In the exit path, rRET0/rRET1 are live - make sure they aren't
225 * allocated by the register utilities as temps.
226 */
227 oatLockTemp(cUnit, rRET0);
228 oatLockTemp(cUnit, rRET1);
buzbeee88dfbf2012-03-05 11:19:57 -0800229
Ian Rogersb5d09b22012-03-06 22:14:17 -0800230 newLIR0(cUnit, kPseudoMethodExit);
231 /* If we're compiling for the debugger, generate an update callout */
232 if (cUnit->genDebugger) {
233 genDebuggerUpdate(cUnit, DEBUGGER_METHOD_EXIT);
234 }
235 unSpillCoreRegs(cUnit);
236 /* Remove frame except for return address */
237 opRegImm(cUnit, kOpAdd, rSP, cUnit->frameSize - 4);
238 newLIR0(cUnit, kX86Ret);
buzbeee88dfbf2012-03-05 11:19:57 -0800239}
240
241/*
242 * Nop any unconditional branches that go to the next instruction.
243 * Note: new redundant branches may be inserted later, and we'll
244 * use a check in final instruction assembly to nop those out.
245 */
Ian Rogersb5d09b22012-03-06 22:14:17 -0800246void removeRedundantBranches(CompilationUnit* cUnit) {
247 LIR* thisLIR;
buzbeee88dfbf2012-03-05 11:19:57 -0800248
Ian Rogersb5d09b22012-03-06 22:14:17 -0800249 for (thisLIR = (LIR*) cUnit->firstLIRInsn;
250 thisLIR != (LIR*) cUnit->lastLIRInsn;
251 thisLIR = NEXT_LIR(thisLIR)) {
buzbeee88dfbf2012-03-05 11:19:57 -0800252
Ian Rogersb5d09b22012-03-06 22:14:17 -0800253 /* Branch to the next instruction */
254 if (thisLIR->opcode == kX86Jmp) {
255 LIR* nextLIR = thisLIR;
buzbeee88dfbf2012-03-05 11:19:57 -0800256
Ian Rogersb5d09b22012-03-06 22:14:17 -0800257 while (true) {
258 nextLIR = NEXT_LIR(nextLIR);
buzbeee88dfbf2012-03-05 11:19:57 -0800259
Ian Rogersb5d09b22012-03-06 22:14:17 -0800260 /*
261 * Is the branch target the next instruction?
262 */
263 if (nextLIR == (LIR*) thisLIR->target) {
264 thisLIR->flags.isNop = true;
265 break;
buzbeee88dfbf2012-03-05 11:19:57 -0800266 }
Ian Rogersb5d09b22012-03-06 22:14:17 -0800267
268 /*
269 * Found real useful stuff between the branch and the target.
270 * Need to explicitly check the lastLIRInsn here because it
271 * might be the last real instruction.
272 */
273 if (!isPseudoOpcode(nextLIR->opcode) ||
274 (nextLIR = (LIR*) cUnit->lastLIRInsn))
275 break;
276 }
buzbeee88dfbf2012-03-05 11:19:57 -0800277 }
Ian Rogersb5d09b22012-03-06 22:14:17 -0800278 }
buzbeee88dfbf2012-03-05 11:19:57 -0800279}
280
281
282/* Common initialization routine for an architecture family */
283bool oatArchInit()
284{
285 int i;
286
287 for (i = 0; i < kX86Last; i++) {
288 if (EncodingMap[i].opcode != i) {
289 LOG(FATAL) << "Encoding order for " << EncodingMap[i].name <<
290 " is wrong: expecting " << i << ", seeing " <<
291 (int)EncodingMap[i].opcode;
292 }
293 }
294
295 return oatArchVariantInit();
296}
297
298} // namespace art