blob: f2c9c71656bc1fa475269f4b138f7b221d035d65 [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{
buzbeee88dfbf2012-03-05 11:19:57 -080030 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
31 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
32 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
33 /*
34 * [v1 v0] = [a1 a0] + [a3 a2];
Ian Rogersf7d9ad32012-03-13 18:45:39 -070035 * add v0,a2,a0
36 * adc v1,a3,a1
buzbeee88dfbf2012-03-05 11:19:57 -080037 */
38
39 opRegRegReg(cUnit, kOpAdd, rlResult.lowReg, rlSrc2.lowReg, rlSrc1.lowReg);
Ian Rogersf7d9ad32012-03-13 18:45:39 -070040 opRegRegReg(cUnit, kOpAdc, rlResult.highReg, rlSrc2.highReg, rlSrc1.highReg);
buzbeee88dfbf2012-03-05 11:19:57 -080041 storeValueWide(cUnit, rlDest, rlResult);
buzbeee88dfbf2012-03-05 11:19:57 -080042 return false;
43}
44
45bool genSubLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
46 RegLocation rlSrc1, RegLocation rlSrc2)
47{
buzbeee88dfbf2012-03-05 11:19:57 -080048 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
49 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
50 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
51 /*
52 * [v1 v0] = [a1 a0] - [a3 a2];
Ian Rogersf7d9ad32012-03-13 18:45:39 -070053 * sub v0,a0,a2
54 * sbb v1,a1,a3
buzbeee88dfbf2012-03-05 11:19:57 -080055 */
56
57 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, rlSrc1.lowReg, rlSrc2.lowReg);
Ian Rogersf7d9ad32012-03-13 18:45:39 -070058 opRegRegReg(cUnit, kOpSbc, rlResult.highReg, rlSrc1.highReg, rlSrc2.highReg);
buzbeee88dfbf2012-03-05 11:19:57 -080059 storeValueWide(cUnit, rlDest, rlResult);
buzbeee88dfbf2012-03-05 11:19:57 -080060 return false;
61}
62
63bool genNegLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
64 RegLocation rlSrc)
65{
66 UNIMPLEMENTED(WARNING) << "genNegLong";
67#if 0
68 rlSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
69 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
70 /*
71 * [v1 v0] = -[a1 a0]
72 * negu v0,a0
73 * negu v1,a1
74 * sltu t1,r_zero
75 * subu v1,v1,t1
76 */
77
78 opRegReg(cUnit, kOpNeg, rlResult.lowReg, rlSrc.lowReg);
79 opRegReg(cUnit, kOpNeg, rlResult.highReg, rlSrc.highReg);
80 int tReg = oatAllocTemp(cUnit);
buzbeea7678db2012-03-05 15:35:46 -080081 newLIR3(cUnit, kX86Sltu, tReg, r_ZERO, rlResult.lowReg);
buzbeee88dfbf2012-03-05 11:19:57 -080082 opRegRegReg(cUnit, kOpSub, rlResult.highReg, rlResult.highReg, tReg);
83 oatFreeTemp(cUnit, tReg);
84 storeValueWide(cUnit, rlDest, rlResult);
85#endif
86 return false;
87}
88
89void genDebuggerUpdate(CompilationUnit* cUnit, int32_t offset);
90
91/*
92 * In the Arm code a it is typical to use the link register
buzbeea7678db2012-03-05 15:35:46 -080093 * to hold the target address. However, for X86 we must
buzbeee88dfbf2012-03-05 11:19:57 -080094 * ensure that all branch instructions can be restarted if
95 * there is a trap in the shadow. Allocate a temp register.
96 */
97int loadHelper(CompilationUnit* cUnit, int offset)
98{
buzbeea7678db2012-03-05 15:35:46 -080099 UNIMPLEMENTED(WARNING);
100 return 0;
101#if 0
buzbeee88dfbf2012-03-05 11:19:57 -0800102 int tReg = oatAllocTemp(cUnit);
103 loadWordDisp(cUnit, rSELF, offset, tReg);
104 return tReg;
buzbeea7678db2012-03-05 15:35:46 -0800105#endif
buzbeee88dfbf2012-03-05 11:19:57 -0800106}
107
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700108void spillCoreRegs(CompilationUnit* cUnit) {
109 if (cUnit->numCoreSpills == 0) {
110 return;
111 }
112 // Spill mask not including fake return address register
113 uint32_t mask = cUnit->coreSpillMask & ~(1 << rRET);
114 int offset = cUnit->frameSize - 4;
115 for (int reg = 0; mask; mask >>= 1, reg++) {
116 if (mask & 0x1) {
117 offset -= 4;
118 storeWordDisp(cUnit, rSP, offset, reg);
buzbeee88dfbf2012-03-05 11:19:57 -0800119 }
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700120 }
buzbeee88dfbf2012-03-05 11:19:57 -0800121}
122
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700123void unSpillCoreRegs(CompilationUnit* cUnit) {
124 if (cUnit->numCoreSpills == 0) {
125 return;
126 }
127 // Spill mask not including fake return address register
128 uint32_t mask = cUnit->coreSpillMask & ~(1 << rRET);
129 int offset = cUnit->frameSize - 4;
130 for (int reg = 0; mask; mask >>= 1, reg++) {
131 if (mask & 0x1) {
132 offset -= 4;
133 loadWordDisp(cUnit, rSP, offset, reg);
buzbeee88dfbf2012-03-05 11:19:57 -0800134 }
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700135 }
Ian Rogersb5d09b22012-03-06 22:14:17 -0800136}
137
138void opRegThreadMem(CompilationUnit* cUnit, OpKind op, int rDest, int threadOffset) {
139 X86OpCode opcode = kX86Bkpt;
140 switch (op) {
141 case kOpCmp: opcode = kX86Cmp32RT; break;
142 default:
143 LOG(FATAL) << "Bad opcode: " << op;
144 break;
145 }
146 DCHECK((EncodingMap[opcode].flags & IS_BINARY_OP) != 0);
147 newLIR2(cUnit, opcode, rDest, threadOffset);
buzbeee88dfbf2012-03-05 11:19:57 -0800148}
149
150void genEntrySequence(CompilationUnit* cUnit, BasicBlock* bb)
151{
buzbeee88dfbf2012-03-05 11:19:57 -0800152 /*
Ian Rogersb5d09b22012-03-06 22:14:17 -0800153 * On entry, rARG0, rARG1, rARG2 are live. Let the register
buzbeee88dfbf2012-03-05 11:19:57 -0800154 * allocation mechanism know so it doesn't try to use any of them when
155 * expanding the frame or flushing. This leaves the utility
Ian Rogersb5d09b22012-03-06 22:14:17 -0800156 * code with no spare temps.
buzbeee88dfbf2012-03-05 11:19:57 -0800157 */
158 oatLockTemp(cUnit, rARG0);
159 oatLockTemp(cUnit, rARG1);
160 oatLockTemp(cUnit, rARG2);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800161
162 /* Build frame, return address already on stack */
163 opRegImm(cUnit, kOpSub, rSP, cUnit->frameSize - 4);
buzbeee88dfbf2012-03-05 11:19:57 -0800164
165 /*
166 * We can safely skip the stack overflow check if we're
167 * a leaf *and* our frame size < fudge factor.
168 */
169 bool skipOverflowCheck = ((cUnit->attrs & METHOD_IS_LEAF) &&
170 ((size_t)cUnit->frameSize <
171 Thread::kStackOverflowReservedBytes));
172 newLIR0(cUnit, kPseudoMethodEntry);
buzbeee88dfbf2012-03-05 11:19:57 -0800173 /* Spill core callee saves */
174 spillCoreRegs(cUnit);
175 /* NOTE: promotion of FP regs currently unsupported, thus no FP spill */
176 DCHECK_EQ(cUnit->numFPSpills, 0);
177 if (!skipOverflowCheck) {
Ian Rogersb5d09b22012-03-06 22:14:17 -0800178 // cmp rSP, fs:[stack_end_]; jcc throw_launchpad
179 LIR* tgt = rawLIR(cUnit, 0, kPseudoThrowTarget, kThrowStackOverflow, 0, 0, 0, 0);
180 opRegThreadMem(cUnit, kOpCmp, rSP, Thread::StackEndOffset().Int32Value());
181 opCondBranch(cUnit, kCondUlt, tgt);
182 // Remember branch target - will process later
183 oatInsertGrowableList(cUnit, &cUnit->throwLaunchpads, (intptr_t)tgt);
buzbeee88dfbf2012-03-05 11:19:57 -0800184 }
Ian Rogersb5d09b22012-03-06 22:14:17 -0800185 /* Spill Method* */
buzbeee88dfbf2012-03-05 11:19:57 -0800186 storeBaseDisp(cUnit, rSP, 0, rARG0, kWord);
187 flushIns(cUnit);
188
189 if (cUnit->genDebugger) {
190 // Refresh update debugger callout
Ian Rogersb5d09b22012-03-06 22:14:17 -0800191 UNIMPLEMENTED(WARNING) << "genDebugger";
192#if 0
buzbeee88dfbf2012-03-05 11:19:57 -0800193 loadWordDisp(cUnit, rSELF,
194 OFFSETOF_MEMBER(Thread, pUpdateDebuggerFromCode), rSUSPEND);
195 genDebuggerUpdate(cUnit, DEBUGGER_METHOD_ENTRY);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800196#endif
buzbeee88dfbf2012-03-05 11:19:57 -0800197 }
198
199 oatFreeTemp(cUnit, rARG0);
200 oatFreeTemp(cUnit, rARG1);
201 oatFreeTemp(cUnit, rARG2);
buzbeee88dfbf2012-03-05 11:19:57 -0800202}
203
Ian Rogersb5d09b22012-03-06 22:14:17 -0800204void genExitSequence(CompilationUnit* cUnit, BasicBlock* bb) {
205 /*
206 * In the exit path, rRET0/rRET1 are live - make sure they aren't
207 * allocated by the register utilities as temps.
208 */
209 oatLockTemp(cUnit, rRET0);
210 oatLockTemp(cUnit, rRET1);
buzbeee88dfbf2012-03-05 11:19:57 -0800211
Ian Rogersb5d09b22012-03-06 22:14:17 -0800212 newLIR0(cUnit, kPseudoMethodExit);
213 /* If we're compiling for the debugger, generate an update callout */
214 if (cUnit->genDebugger) {
215 genDebuggerUpdate(cUnit, DEBUGGER_METHOD_EXIT);
216 }
217 unSpillCoreRegs(cUnit);
218 /* Remove frame except for return address */
219 opRegImm(cUnit, kOpAdd, rSP, cUnit->frameSize - 4);
220 newLIR0(cUnit, kX86Ret);
buzbeee88dfbf2012-03-05 11:19:57 -0800221}
222
223/*
224 * Nop any unconditional branches that go to the next instruction.
225 * Note: new redundant branches may be inserted later, and we'll
226 * use a check in final instruction assembly to nop those out.
227 */
Ian Rogersb5d09b22012-03-06 22:14:17 -0800228void removeRedundantBranches(CompilationUnit* cUnit) {
229 LIR* thisLIR;
buzbeee88dfbf2012-03-05 11:19:57 -0800230
Ian Rogersb5d09b22012-03-06 22:14:17 -0800231 for (thisLIR = (LIR*) cUnit->firstLIRInsn;
232 thisLIR != (LIR*) cUnit->lastLIRInsn;
233 thisLIR = NEXT_LIR(thisLIR)) {
buzbeee88dfbf2012-03-05 11:19:57 -0800234
Ian Rogersb5d09b22012-03-06 22:14:17 -0800235 /* Branch to the next instruction */
236 if (thisLIR->opcode == kX86Jmp) {
237 LIR* nextLIR = thisLIR;
buzbeee88dfbf2012-03-05 11:19:57 -0800238
Ian Rogersb5d09b22012-03-06 22:14:17 -0800239 while (true) {
240 nextLIR = NEXT_LIR(nextLIR);
buzbeee88dfbf2012-03-05 11:19:57 -0800241
Ian Rogersb5d09b22012-03-06 22:14:17 -0800242 /*
243 * Is the branch target the next instruction?
244 */
245 if (nextLIR == (LIR*) thisLIR->target) {
246 thisLIR->flags.isNop = true;
247 break;
buzbeee88dfbf2012-03-05 11:19:57 -0800248 }
Ian Rogersb5d09b22012-03-06 22:14:17 -0800249
250 /*
251 * Found real useful stuff between the branch and the target.
252 * Need to explicitly check the lastLIRInsn here because it
253 * might be the last real instruction.
254 */
255 if (!isPseudoOpcode(nextLIR->opcode) ||
256 (nextLIR = (LIR*) cUnit->lastLIRInsn))
257 break;
258 }
buzbeee88dfbf2012-03-05 11:19:57 -0800259 }
Ian Rogersb5d09b22012-03-06 22:14:17 -0800260 }
buzbeee88dfbf2012-03-05 11:19:57 -0800261}
262
263
264/* Common initialization routine for an architecture family */
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700265bool oatArchInit() {
266 int i;
buzbeee88dfbf2012-03-05 11:19:57 -0800267
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700268 for (i = 0; i < kX86Last; i++) {
269 if (EncodingMap[i].opcode != i) {
270 LOG(FATAL) << "Encoding order for " << EncodingMap[i].name
271 << " is wrong: expecting " << i << ", seeing " << (int)EncodingMap[i].opcode;
buzbeee88dfbf2012-03-05 11:19:57 -0800272 }
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700273 }
buzbeee88dfbf2012-03-05 11:19:57 -0800274
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700275 return oatArchVariantInit();
buzbeee88dfbf2012-03-05 11:19:57 -0800276}
277
278} // namespace art