blob: 001a93d19987221fcf8acdb186d416936e734d80 [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
buzbee408ad162012-06-06 16:45:18 -070027bool genAddLong(CompilationUnit* cUnit, RegLocation rlDest,
Ian Rogers7caad772012-03-30 01:07:54 -070028 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
buzbee2cfc6392012-05-07 14:51:40 -070037 RegLocation rlResult = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, r0, r1,
38 INVALID_SREG, INVALID_SREG};
Ian Rogers7caad772012-03-30 01:07:54 -070039 storeValueWide(cUnit, rlDest, rlResult);
40 return false;
41}
42
buzbee408ad162012-06-06 16:45:18 -070043bool genSubLong(CompilationUnit* cUnit, RegLocation rlDest,
Ian Rogers7caad772012-03-30 01:07:54 -070044 RegLocation rlSrc1, RegLocation rlSrc2)
45{
46 oatFlushAllRegs(cUnit);
47 oatLockCallTemps(cUnit); // Prepare for explicit register usage
48 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
Ian Rogersfc700ed2012-04-04 11:21:26 -070049 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
Ian Rogers7caad772012-03-30 01:07:54 -070050 // Compute (r1:r0) = (r1:r0) + (r2:r3)
51 opRegReg(cUnit, kOpSub, r0, r2); // r0 = r0 - r2
52 opRegReg(cUnit, kOpSbc, r1, r3); // r1 = r1 - r3 - CF
buzbee2cfc6392012-05-07 14:51:40 -070053 RegLocation rlResult = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, r0, r1,
54 INVALID_SREG, INVALID_SREG};
Ian Rogers7caad772012-03-30 01:07:54 -070055 storeValueWide(cUnit, rlDest, rlResult);
56 return false;
57}
58
buzbee408ad162012-06-06 16:45:18 -070059bool genAndLong(CompilationUnit* cUnit, RegLocation rlDest,
Ian Rogers7caad772012-03-30 01:07:54 -070060 RegLocation rlSrc1, RegLocation rlSrc2)
61{
62 oatFlushAllRegs(cUnit);
63 oatLockCallTemps(cUnit); // Prepare for explicit register usage
64 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
Ian Rogersfc700ed2012-04-04 11:21:26 -070065 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
Ian Rogers7caad772012-03-30 01:07:54 -070066 // Compute (r1:r0) = (r1:r0) + (r2:r3)
67 opRegReg(cUnit, kOpAnd, r0, r2); // r0 = r0 - r2
68 opRegReg(cUnit, kOpAnd, r1, r3); // r1 = r1 - r3 - CF
buzbee2cfc6392012-05-07 14:51:40 -070069 RegLocation rlResult = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, r0, r1,
70 INVALID_SREG, INVALID_SREG};
Ian Rogers7caad772012-03-30 01:07:54 -070071 storeValueWide(cUnit, rlDest, rlResult);
72 return false;
73}
74
buzbee408ad162012-06-06 16:45:18 -070075bool genOrLong(CompilationUnit* cUnit, RegLocation rlDest,
Bill Buzbeea114add2012-05-03 15:00:40 -070076 RegLocation rlSrc1, RegLocation rlSrc2)
Ian Rogers7caad772012-03-30 01:07:54 -070077{
78 oatFlushAllRegs(cUnit);
79 oatLockCallTemps(cUnit); // Prepare for explicit register usage
80 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
Ian Rogersfc700ed2012-04-04 11:21:26 -070081 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
Ian Rogers7caad772012-03-30 01:07:54 -070082 // Compute (r1:r0) = (r1:r0) + (r2:r3)
83 opRegReg(cUnit, kOpOr, r0, r2); // r0 = r0 - r2
84 opRegReg(cUnit, kOpOr, r1, r3); // r1 = r1 - r3 - CF
buzbee2cfc6392012-05-07 14:51:40 -070085 RegLocation rlResult = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, r0, r1,
86 INVALID_SREG, INVALID_SREG};
Ian Rogers7caad772012-03-30 01:07:54 -070087 storeValueWide(cUnit, rlDest, rlResult);
88 return false;
89}
90
buzbee408ad162012-06-06 16:45:18 -070091bool genXorLong(CompilationUnit* cUnit, RegLocation rlDest,
Ian Rogers7caad772012-03-30 01:07:54 -070092 RegLocation rlSrc1, RegLocation rlSrc2)
93{
94 oatFlushAllRegs(cUnit);
95 oatLockCallTemps(cUnit); // Prepare for explicit register usage
96 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
Ian Rogersfc700ed2012-04-04 11:21:26 -070097 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
Ian Rogers7caad772012-03-30 01:07:54 -070098 // Compute (r1:r0) = (r1:r0) + (r2:r3)
99 opRegReg(cUnit, kOpXor, r0, r2); // r0 = r0 - r2
100 opRegReg(cUnit, kOpXor, r1, r3); // r1 = r1 - r3 - CF
buzbee2cfc6392012-05-07 14:51:40 -0700101 RegLocation rlResult = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, r0, r1,
102 INVALID_SREG, INVALID_SREG};
Ian Rogers7caad772012-03-30 01:07:54 -0700103 storeValueWide(cUnit, rlDest, rlResult);
104 return false;
105}
106
buzbee408ad162012-06-06 16:45:18 -0700107bool genNegLong(CompilationUnit* cUnit, RegLocation rlDest,
buzbeee88dfbf2012-03-05 11:19:57 -0800108 RegLocation rlSrc)
109{
Ian Rogers7caad772012-03-30 01:07:54 -0700110 oatFlushAllRegs(cUnit);
111 oatLockCallTemps(cUnit); // Prepare for explicit register usage
112 loadValueDirectWideFixed(cUnit, rlSrc, r0, r1);
113 // Compute (r1:r0) = -(r1:r0)
114 opRegReg(cUnit, kOpNeg, r0, r0); // r0 = -r0
115 opRegImm(cUnit, kOpAdc, r1, 0); // r1 = r1 + CF
116 opRegReg(cUnit, kOpNeg, r1, r1); // r1 = -r1
buzbee2cfc6392012-05-07 14:51:40 -0700117 RegLocation rlResult = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, r0, r1,
118 INVALID_SREG, INVALID_SREG};
Ian Rogers7caad772012-03-30 01:07:54 -0700119 storeValueWide(cUnit, rlDest, rlResult);
120 return false;
buzbeee88dfbf2012-03-05 11:19:57 -0800121}
122
123void genDebuggerUpdate(CompilationUnit* cUnit, int32_t offset);
124
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700125void spillCoreRegs(CompilationUnit* cUnit) {
126 if (cUnit->numCoreSpills == 0) {
127 return;
128 }
129 // Spill mask not including fake return address register
130 uint32_t mask = cUnit->coreSpillMask & ~(1 << rRET);
jeffhao703f2cd2012-07-13 17:25:52 -0700131 int offset = cUnit->frameSize - (4 * cUnit->numCoreSpills);
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700132 for (int reg = 0; mask; mask >>= 1, reg++) {
133 if (mask & 0x1) {
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700134 storeWordDisp(cUnit, rSP, offset, reg);
jeffhao703f2cd2012-07-13 17:25:52 -0700135 offset += 4;
buzbeee88dfbf2012-03-05 11:19:57 -0800136 }
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700137 }
buzbeee88dfbf2012-03-05 11:19:57 -0800138}
139
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700140void unSpillCoreRegs(CompilationUnit* cUnit) {
141 if (cUnit->numCoreSpills == 0) {
142 return;
143 }
144 // Spill mask not including fake return address register
145 uint32_t mask = cUnit->coreSpillMask & ~(1 << rRET);
jeffhao703f2cd2012-07-13 17:25:52 -0700146 int offset = cUnit->frameSize - (4 * cUnit->numCoreSpills);
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700147 for (int reg = 0; mask; mask >>= 1, reg++) {
148 if (mask & 0x1) {
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700149 loadWordDisp(cUnit, rSP, offset, reg);
jeffhao703f2cd2012-07-13 17:25:52 -0700150 offset += 4;
buzbeee88dfbf2012-03-05 11:19:57 -0800151 }
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700152 }
Ian Rogersb5d09b22012-03-06 22:14:17 -0800153}
154
155void opRegThreadMem(CompilationUnit* cUnit, OpKind op, int rDest, int threadOffset) {
156 X86OpCode opcode = kX86Bkpt;
157 switch (op) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700158 case kOpCmp: opcode = kX86Cmp32RT; break;
159 default:
160 LOG(FATAL) << "Bad opcode: " << op;
161 break;
Ian Rogersb5d09b22012-03-06 22:14:17 -0800162 }
Ian Rogersb5d09b22012-03-06 22:14:17 -0800163 newLIR2(cUnit, opcode, rDest, threadOffset);
buzbeee88dfbf2012-03-05 11:19:57 -0800164}
165
buzbeead8f15e2012-06-18 14:49:45 -0700166void genEntrySequence(CompilationUnit* cUnit, RegLocation* argLocs,
167 RegLocation rlMethod)
buzbeee88dfbf2012-03-05 11:19:57 -0800168{
Bill Buzbeea114add2012-05-03 15:00:40 -0700169 /*
170 * On entry, rARG0, rARG1, rARG2 are live. Let the register
171 * allocation mechanism know so it doesn't try to use any of them when
172 * expanding the frame or flushing. This leaves the utility
173 * code with no spare temps.
174 */
175 oatLockTemp(cUnit, rARG0);
176 oatLockTemp(cUnit, rARG1);
177 oatLockTemp(cUnit, rARG2);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800178
Bill Buzbeea114add2012-05-03 15:00:40 -0700179 /* Build frame, return address already on stack */
180 opRegImm(cUnit, kOpSub, rSP, cUnit->frameSize - 4);
buzbeee88dfbf2012-03-05 11:19:57 -0800181
Bill Buzbeea114add2012-05-03 15:00:40 -0700182 /*
183 * We can safely skip the stack overflow check if we're
184 * a leaf *and* our frame size < fudge factor.
185 */
186 bool skipOverflowCheck = ((cUnit->attrs & METHOD_IS_LEAF) &&
187 ((size_t)cUnit->frameSize <
188 Thread::kStackOverflowReservedBytes));
189 newLIR0(cUnit, kPseudoMethodEntry);
190 /* Spill core callee saves */
191 spillCoreRegs(cUnit);
192 /* NOTE: promotion of FP regs currently unsupported, thus no FP spill */
193 DCHECK_EQ(cUnit->numFPSpills, 0);
194 if (!skipOverflowCheck) {
195 // cmp rSP, fs:[stack_end_]; jcc throw_launchpad
196 LIR* tgt = rawLIR(cUnit, 0, kPseudoThrowTarget, kThrowStackOverflow, 0, 0, 0, 0);
197 opRegThreadMem(cUnit, kOpCmp, rSP, Thread::StackEndOffset().Int32Value());
198 opCondBranch(cUnit, kCondUlt, tgt);
199 // Remember branch target - will process later
200 oatInsertGrowableList(cUnit, &cUnit->throwLaunchpads, (intptr_t)tgt);
201 }
buzbee9c044ce2012-03-18 13:24:07 -0700202
buzbeead8f15e2012-06-18 14:49:45 -0700203 flushIns(cUnit, argLocs, rlMethod);
buzbeee88dfbf2012-03-05 11:19:57 -0800204
Bill Buzbeea114add2012-05-03 15:00:40 -0700205 if (cUnit->genDebugger) {
206 // Refresh update debugger callout
207 UNIMPLEMENTED(WARNING) << "genDebugger";
Ian Rogersb5d09b22012-03-06 22:14:17 -0800208#if 0
Bill Buzbeea114add2012-05-03 15:00:40 -0700209 loadWordDisp(cUnit, rSELF,
210 OFFSETOF_MEMBER(Thread, pUpdateDebuggerFromCode), rSUSPEND);
211 genDebuggerUpdate(cUnit, DEBUGGER_METHOD_ENTRY);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800212#endif
Bill Buzbeea114add2012-05-03 15:00:40 -0700213 }
buzbeee88dfbf2012-03-05 11:19:57 -0800214
Bill Buzbeea114add2012-05-03 15:00:40 -0700215 oatFreeTemp(cUnit, rARG0);
216 oatFreeTemp(cUnit, rARG1);
217 oatFreeTemp(cUnit, rARG2);
buzbeee88dfbf2012-03-05 11:19:57 -0800218}
219
buzbee2cfc6392012-05-07 14:51:40 -0700220void genExitSequence(CompilationUnit* cUnit) {
Ian Rogersb5d09b22012-03-06 22:14:17 -0800221 /*
222 * In the exit path, rRET0/rRET1 are live - make sure they aren't
223 * allocated by the register utilities as temps.
224 */
225 oatLockTemp(cUnit, rRET0);
226 oatLockTemp(cUnit, rRET1);
buzbeee88dfbf2012-03-05 11:19:57 -0800227
Ian Rogersb5d09b22012-03-06 22:14:17 -0800228 newLIR0(cUnit, kPseudoMethodExit);
229 /* If we're compiling for the debugger, generate an update callout */
230 if (cUnit->genDebugger) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700231 genDebuggerUpdate(cUnit, DEBUGGER_METHOD_EXIT);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800232 }
233 unSpillCoreRegs(cUnit);
234 /* Remove frame except for return address */
235 opRegImm(cUnit, kOpAdd, rSP, cUnit->frameSize - 4);
236 newLIR0(cUnit, kX86Ret);
buzbeee88dfbf2012-03-05 11:19:57 -0800237}
238
239/*
240 * Nop any unconditional branches that go to the next instruction.
241 * Note: new redundant branches may be inserted later, and we'll
242 * use a check in final instruction assembly to nop those out.
243 */
Ian Rogersb5d09b22012-03-06 22:14:17 -0800244void removeRedundantBranches(CompilationUnit* cUnit) {
245 LIR* thisLIR;
buzbeee88dfbf2012-03-05 11:19:57 -0800246
Ian Rogersb5d09b22012-03-06 22:14:17 -0800247 for (thisLIR = (LIR*) cUnit->firstLIRInsn;
Bill Buzbeea114add2012-05-03 15:00:40 -0700248 thisLIR != (LIR*) cUnit->lastLIRInsn;
249 thisLIR = NEXT_LIR(thisLIR)) {
buzbeee88dfbf2012-03-05 11:19:57 -0800250
Bill Buzbeea114add2012-05-03 15:00:40 -0700251 /* Branch to the next instruction */
252 if (thisLIR->opcode == kX86Jmp8 || thisLIR->opcode == kX86Jmp32) {
253 LIR* nextLIR = thisLIR;
buzbeee88dfbf2012-03-05 11:19:57 -0800254
Bill Buzbeea114add2012-05-03 15:00:40 -0700255 while (true) {
256 nextLIR = NEXT_LIR(nextLIR);
buzbeee88dfbf2012-03-05 11:19:57 -0800257
Bill Buzbeea114add2012-05-03 15:00:40 -0700258 /*
259 * Is the branch target the next instruction?
260 */
261 if (nextLIR == (LIR*) thisLIR->target) {
262 thisLIR->flags.isNop = true;
263 break;
264 }
Ian Rogersb5d09b22012-03-06 22:14:17 -0800265
Bill Buzbeea114add2012-05-03 15:00:40 -0700266 /*
267 * Found real useful stuff between the branch and the target.
268 * Need to explicitly check the lastLIRInsn here because it
269 * might be the last real instruction.
270 */
271 if (!isPseudoOpcode(nextLIR->opcode) ||
272 (nextLIR = (LIR*) cUnit->lastLIRInsn))
273 break;
Ian Rogersb5d09b22012-03-06 22:14:17 -0800274 }
buzbeee88dfbf2012-03-05 11:19:57 -0800275 }
Ian Rogersb5d09b22012-03-06 22:14:17 -0800276 }
buzbeee88dfbf2012-03-05 11:19:57 -0800277}
278
279
280/* Common initialization routine for an architecture family */
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700281bool oatArchInit() {
282 int i;
buzbeee88dfbf2012-03-05 11:19:57 -0800283
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700284 for (i = 0; i < kX86Last; i++) {
285 if (EncodingMap[i].opcode != i) {
286 LOG(FATAL) << "Encoding order for " << EncodingMap[i].name
Bill Buzbeea114add2012-05-03 15:00:40 -0700287 << " is wrong: expecting " << i << ", seeing "
288 << (int)EncodingMap[i].opcode;
buzbeee88dfbf2012-03-05 11:19:57 -0800289 }
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700290 }
buzbeee88dfbf2012-03-05 11:19:57 -0800291
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700292 return oatArchVariantInit();
buzbeee88dfbf2012-03-05 11:19:57 -0800293}
294
295} // namespace art