blob: dc1323817aece9af3429f02f67f196a79a98c05c [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
Ian Rogers7caad772012-03-30 01:07:54 -070027bool genAddLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
28 RegLocation rlSrc1, RegLocation rlSrc2)
29{
30 oatFlushAllRegs(cUnit);
31 oatLockCallTemps(cUnit); // Prepare for explicit register usage
32 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
Ian Rogersfc700ed2012-04-04 11:21:26 -070033 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
Ian Rogers7caad772012-03-30 01:07:54 -070034 // Compute (r1:r0) = (r1:r0) + (r2:r3)
35 opRegReg(cUnit, kOpAdd, r0, r2); // r0 = r0 + r2
36 opRegReg(cUnit, kOpAdc, r1, r3); // r1 = r1 + r3 + CF
37 RegLocation rlResult = {kLocPhysReg, 1, 0, 0, 0, 0, 1, r0, r1, INVALID_SREG};
38 storeValueWide(cUnit, rlDest, rlResult);
39 return false;
40}
41
42bool genSubLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
43 RegLocation rlSrc1, RegLocation rlSrc2)
44{
45 oatFlushAllRegs(cUnit);
46 oatLockCallTemps(cUnit); // Prepare for explicit register usage
47 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
Ian Rogersfc700ed2012-04-04 11:21:26 -070048 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
Ian Rogers7caad772012-03-30 01:07:54 -070049 // Compute (r1:r0) = (r1:r0) + (r2:r3)
50 opRegReg(cUnit, kOpSub, r0, r2); // r0 = r0 - r2
51 opRegReg(cUnit, kOpSbc, r1, r3); // r1 = r1 - r3 - CF
52 RegLocation rlResult = {kLocPhysReg, 1, 0, 0, 0, 0, 1, r0, r1, INVALID_SREG};
53 storeValueWide(cUnit, rlDest, rlResult);
54 return false;
55}
56
57bool genAndLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
58 RegLocation rlSrc1, RegLocation rlSrc2)
59{
60 oatFlushAllRegs(cUnit);
61 oatLockCallTemps(cUnit); // Prepare for explicit register usage
62 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
Ian Rogersfc700ed2012-04-04 11:21:26 -070063 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
Ian Rogers7caad772012-03-30 01:07:54 -070064 // Compute (r1:r0) = (r1:r0) + (r2:r3)
65 opRegReg(cUnit, kOpAnd, r0, r2); // r0 = r0 - r2
66 opRegReg(cUnit, kOpAnd, r1, r3); // r1 = r1 - r3 - CF
67 RegLocation rlResult = {kLocPhysReg, 1, 0, 0, 0, 0, 1, r0, r1, INVALID_SREG};
68 storeValueWide(cUnit, rlDest, rlResult);
69 return false;
70}
71
72bool genOrLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
Bill Buzbeea114add2012-05-03 15:00:40 -070073 RegLocation rlSrc1, RegLocation rlSrc2)
Ian Rogers7caad772012-03-30 01:07:54 -070074{
75 oatFlushAllRegs(cUnit);
76 oatLockCallTemps(cUnit); // Prepare for explicit register usage
77 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
Ian Rogersfc700ed2012-04-04 11:21:26 -070078 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
Ian Rogers7caad772012-03-30 01:07:54 -070079 // Compute (r1:r0) = (r1:r0) + (r2:r3)
80 opRegReg(cUnit, kOpOr, r0, r2); // r0 = r0 - r2
81 opRegReg(cUnit, kOpOr, r1, r3); // r1 = r1 - r3 - CF
82 RegLocation rlResult = {kLocPhysReg, 1, 0, 0, 0, 0, 1, r0, r1, INVALID_SREG};
83 storeValueWide(cUnit, rlDest, rlResult);
84 return false;
85}
86
87bool genXorLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
88 RegLocation rlSrc1, RegLocation rlSrc2)
89{
90 oatFlushAllRegs(cUnit);
91 oatLockCallTemps(cUnit); // Prepare for explicit register usage
92 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
Ian Rogersfc700ed2012-04-04 11:21:26 -070093 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
Ian Rogers7caad772012-03-30 01:07:54 -070094 // Compute (r1:r0) = (r1:r0) + (r2:r3)
95 opRegReg(cUnit, kOpXor, r0, r2); // r0 = r0 - r2
96 opRegReg(cUnit, kOpXor, r1, r3); // r1 = r1 - r3 - CF
97 RegLocation rlResult = {kLocPhysReg, 1, 0, 0, 0, 0, 1, r0, r1, INVALID_SREG};
98 storeValueWide(cUnit, rlDest, rlResult);
99 return false;
100}
101
buzbeee88dfbf2012-03-05 11:19:57 -0800102bool genNegLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
103 RegLocation rlSrc)
104{
Ian Rogers7caad772012-03-30 01:07:54 -0700105 oatFlushAllRegs(cUnit);
106 oatLockCallTemps(cUnit); // Prepare for explicit register usage
107 loadValueDirectWideFixed(cUnit, rlSrc, r0, r1);
108 // Compute (r1:r0) = -(r1:r0)
109 opRegReg(cUnit, kOpNeg, r0, r0); // r0 = -r0
110 opRegImm(cUnit, kOpAdc, r1, 0); // r1 = r1 + CF
111 opRegReg(cUnit, kOpNeg, r1, r1); // r1 = -r1
112 RegLocation rlResult = {kLocPhysReg, 1, 0, 0, 0, 0, 1, r0, r1, INVALID_SREG};
113 storeValueWide(cUnit, rlDest, rlResult);
114 return false;
buzbeee88dfbf2012-03-05 11:19:57 -0800115}
116
117void genDebuggerUpdate(CompilationUnit* cUnit, int32_t offset);
118
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700119void spillCoreRegs(CompilationUnit* cUnit) {
120 if (cUnit->numCoreSpills == 0) {
121 return;
122 }
123 // Spill mask not including fake return address register
124 uint32_t mask = cUnit->coreSpillMask & ~(1 << rRET);
125 int offset = cUnit->frameSize - 4;
126 for (int reg = 0; mask; mask >>= 1, reg++) {
127 if (mask & 0x1) {
128 offset -= 4;
129 storeWordDisp(cUnit, rSP, offset, reg);
buzbeee88dfbf2012-03-05 11:19:57 -0800130 }
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700131 }
buzbeee88dfbf2012-03-05 11:19:57 -0800132}
133
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700134void unSpillCoreRegs(CompilationUnit* cUnit) {
135 if (cUnit->numCoreSpills == 0) {
136 return;
137 }
138 // Spill mask not including fake return address register
139 uint32_t mask = cUnit->coreSpillMask & ~(1 << rRET);
140 int offset = cUnit->frameSize - 4;
141 for (int reg = 0; mask; mask >>= 1, reg++) {
142 if (mask & 0x1) {
143 offset -= 4;
144 loadWordDisp(cUnit, rSP, offset, reg);
buzbeee88dfbf2012-03-05 11:19:57 -0800145 }
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700146 }
Ian Rogersb5d09b22012-03-06 22:14:17 -0800147}
148
149void opRegThreadMem(CompilationUnit* cUnit, OpKind op, int rDest, int threadOffset) {
150 X86OpCode opcode = kX86Bkpt;
151 switch (op) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700152 case kOpCmp: opcode = kX86Cmp32RT; break;
153 default:
154 LOG(FATAL) << "Bad opcode: " << op;
155 break;
Ian Rogersb5d09b22012-03-06 22:14:17 -0800156 }
Ian Rogersb5d09b22012-03-06 22:14:17 -0800157 newLIR2(cUnit, opcode, rDest, threadOffset);
buzbeee88dfbf2012-03-05 11:19:57 -0800158}
159
160void genEntrySequence(CompilationUnit* cUnit, BasicBlock* bb)
161{
Bill Buzbeea114add2012-05-03 15:00:40 -0700162 /*
163 * On entry, rARG0, rARG1, rARG2 are live. Let the register
164 * allocation mechanism know so it doesn't try to use any of them when
165 * expanding the frame or flushing. This leaves the utility
166 * code with no spare temps.
167 */
168 oatLockTemp(cUnit, rARG0);
169 oatLockTemp(cUnit, rARG1);
170 oatLockTemp(cUnit, rARG2);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800171
Bill Buzbeea114add2012-05-03 15:00:40 -0700172 /* Build frame, return address already on stack */
173 opRegImm(cUnit, kOpSub, rSP, cUnit->frameSize - 4);
buzbeee88dfbf2012-03-05 11:19:57 -0800174
Bill Buzbeea114add2012-05-03 15:00:40 -0700175 /*
176 * We can safely skip the stack overflow check if we're
177 * a leaf *and* our frame size < fudge factor.
178 */
179 bool skipOverflowCheck = ((cUnit->attrs & METHOD_IS_LEAF) &&
180 ((size_t)cUnit->frameSize <
181 Thread::kStackOverflowReservedBytes));
182 newLIR0(cUnit, kPseudoMethodEntry);
183 /* Spill core callee saves */
184 spillCoreRegs(cUnit);
185 /* NOTE: promotion of FP regs currently unsupported, thus no FP spill */
186 DCHECK_EQ(cUnit->numFPSpills, 0);
187 if (!skipOverflowCheck) {
188 // cmp rSP, fs:[stack_end_]; jcc throw_launchpad
189 LIR* tgt = rawLIR(cUnit, 0, kPseudoThrowTarget, kThrowStackOverflow, 0, 0, 0, 0);
190 opRegThreadMem(cUnit, kOpCmp, rSP, Thread::StackEndOffset().Int32Value());
191 opCondBranch(cUnit, kCondUlt, tgt);
192 // Remember branch target - will process later
193 oatInsertGrowableList(cUnit, &cUnit->throwLaunchpads, (intptr_t)tgt);
194 }
buzbee9c044ce2012-03-18 13:24:07 -0700195
Bill Buzbeea114add2012-05-03 15:00:40 -0700196 flushIns(cUnit);
buzbeee88dfbf2012-03-05 11:19:57 -0800197
Bill Buzbeea114add2012-05-03 15:00:40 -0700198 if (cUnit->genDebugger) {
199 // Refresh update debugger callout
200 UNIMPLEMENTED(WARNING) << "genDebugger";
Ian Rogersb5d09b22012-03-06 22:14:17 -0800201#if 0
Bill Buzbeea114add2012-05-03 15:00:40 -0700202 loadWordDisp(cUnit, rSELF,
203 OFFSETOF_MEMBER(Thread, pUpdateDebuggerFromCode), rSUSPEND);
204 genDebuggerUpdate(cUnit, DEBUGGER_METHOD_ENTRY);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800205#endif
Bill Buzbeea114add2012-05-03 15:00:40 -0700206 }
buzbeee88dfbf2012-03-05 11:19:57 -0800207
Bill Buzbeea114add2012-05-03 15:00:40 -0700208 oatFreeTemp(cUnit, rARG0);
209 oatFreeTemp(cUnit, rARG1);
210 oatFreeTemp(cUnit, rARG2);
buzbeee88dfbf2012-03-05 11:19:57 -0800211}
212
Ian Rogersb5d09b22012-03-06 22:14:17 -0800213void genExitSequence(CompilationUnit* cUnit, BasicBlock* bb) {
214 /*
215 * In the exit path, rRET0/rRET1 are live - make sure they aren't
216 * allocated by the register utilities as temps.
217 */
218 oatLockTemp(cUnit, rRET0);
219 oatLockTemp(cUnit, rRET1);
buzbeee88dfbf2012-03-05 11:19:57 -0800220
Ian Rogersb5d09b22012-03-06 22:14:17 -0800221 newLIR0(cUnit, kPseudoMethodExit);
222 /* If we're compiling for the debugger, generate an update callout */
223 if (cUnit->genDebugger) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700224 genDebuggerUpdate(cUnit, DEBUGGER_METHOD_EXIT);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800225 }
226 unSpillCoreRegs(cUnit);
227 /* Remove frame except for return address */
228 opRegImm(cUnit, kOpAdd, rSP, cUnit->frameSize - 4);
229 newLIR0(cUnit, kX86Ret);
buzbeee88dfbf2012-03-05 11:19:57 -0800230}
231
232/*
233 * Nop any unconditional branches that go to the next instruction.
234 * Note: new redundant branches may be inserted later, and we'll
235 * use a check in final instruction assembly to nop those out.
236 */
Ian Rogersb5d09b22012-03-06 22:14:17 -0800237void removeRedundantBranches(CompilationUnit* cUnit) {
238 LIR* thisLIR;
buzbeee88dfbf2012-03-05 11:19:57 -0800239
Ian Rogersb5d09b22012-03-06 22:14:17 -0800240 for (thisLIR = (LIR*) cUnit->firstLIRInsn;
Bill Buzbeea114add2012-05-03 15:00:40 -0700241 thisLIR != (LIR*) cUnit->lastLIRInsn;
242 thisLIR = NEXT_LIR(thisLIR)) {
buzbeee88dfbf2012-03-05 11:19:57 -0800243
Bill Buzbeea114add2012-05-03 15:00:40 -0700244 /* Branch to the next instruction */
245 if (thisLIR->opcode == kX86Jmp8 || thisLIR->opcode == kX86Jmp32) {
246 LIR* nextLIR = thisLIR;
buzbeee88dfbf2012-03-05 11:19:57 -0800247
Bill Buzbeea114add2012-05-03 15:00:40 -0700248 while (true) {
249 nextLIR = NEXT_LIR(nextLIR);
buzbeee88dfbf2012-03-05 11:19:57 -0800250
Bill Buzbeea114add2012-05-03 15:00:40 -0700251 /*
252 * Is the branch target the next instruction?
253 */
254 if (nextLIR == (LIR*) thisLIR->target) {
255 thisLIR->flags.isNop = true;
256 break;
257 }
Ian Rogersb5d09b22012-03-06 22:14:17 -0800258
Bill Buzbeea114add2012-05-03 15:00:40 -0700259 /*
260 * Found real useful stuff between the branch and the target.
261 * Need to explicitly check the lastLIRInsn here because it
262 * might be the last real instruction.
263 */
264 if (!isPseudoOpcode(nextLIR->opcode) ||
265 (nextLIR = (LIR*) cUnit->lastLIRInsn))
266 break;
Ian Rogersb5d09b22012-03-06 22:14:17 -0800267 }
buzbeee88dfbf2012-03-05 11:19:57 -0800268 }
Ian Rogersb5d09b22012-03-06 22:14:17 -0800269 }
buzbeee88dfbf2012-03-05 11:19:57 -0800270}
271
272
273/* Common initialization routine for an architecture family */
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700274bool oatArchInit() {
275 int i;
buzbeee88dfbf2012-03-05 11:19:57 -0800276
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700277 for (i = 0; i < kX86Last; i++) {
278 if (EncodingMap[i].opcode != i) {
279 LOG(FATAL) << "Encoding order for " << EncodingMap[i].name
Bill Buzbeea114add2012-05-03 15:00:40 -0700280 << " is wrong: expecting " << i << ", seeing "
281 << (int)EncodingMap[i].opcode;
buzbeee88dfbf2012-03-05 11:19:57 -0800282 }
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700283 }
buzbeee88dfbf2012-03-05 11:19:57 -0800284
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700285 return oatArchVariantInit();
buzbeee88dfbf2012-03-05 11:19:57 -0800286}
287
288} // namespace art