blob: 0ed68484f4330ee6c88974e3c073c01d7cea4426 [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
buzbeeb046e162012-10-30 15:48:42 -070017/* This file contains x86-specific codegen factory support. */
buzbeee88dfbf2012-03-05 11:19:57 -080018
19namespace art {
20
buzbee408ad162012-06-06 16:45:18 -070021bool genAddLong(CompilationUnit* cUnit, RegLocation rlDest,
Ian Rogers7caad772012-03-30 01:07:54 -070022 RegLocation rlSrc1, RegLocation rlSrc2)
23{
24 oatFlushAllRegs(cUnit);
25 oatLockCallTemps(cUnit); // Prepare for explicit register usage
26 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
Ian Rogersfc700ed2012-04-04 11:21:26 -070027 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
Ian Rogers7caad772012-03-30 01:07:54 -070028 // Compute (r1:r0) = (r1:r0) + (r2:r3)
29 opRegReg(cUnit, kOpAdd, r0, r2); // r0 = r0 + r2
30 opRegReg(cUnit, kOpAdc, r1, r3); // r1 = r1 + r3 + CF
buzbee2cfc6392012-05-07 14:51:40 -070031 RegLocation rlResult = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, r0, r1,
32 INVALID_SREG, INVALID_SREG};
Ian Rogers7caad772012-03-30 01:07:54 -070033 storeValueWide(cUnit, rlDest, rlResult);
34 return false;
35}
36
buzbee408ad162012-06-06 16:45:18 -070037bool genSubLong(CompilationUnit* cUnit, RegLocation rlDest,
Ian Rogers7caad772012-03-30 01:07:54 -070038 RegLocation rlSrc1, RegLocation rlSrc2)
39{
40 oatFlushAllRegs(cUnit);
41 oatLockCallTemps(cUnit); // Prepare for explicit register usage
42 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
Ian Rogersfc700ed2012-04-04 11:21:26 -070043 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
Ian Rogers7caad772012-03-30 01:07:54 -070044 // Compute (r1:r0) = (r1:r0) + (r2:r3)
45 opRegReg(cUnit, kOpSub, r0, r2); // r0 = r0 - r2
46 opRegReg(cUnit, kOpSbc, r1, r3); // r1 = r1 - r3 - CF
buzbee2cfc6392012-05-07 14:51:40 -070047 RegLocation rlResult = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, r0, r1,
48 INVALID_SREG, INVALID_SREG};
Ian Rogers7caad772012-03-30 01:07:54 -070049 storeValueWide(cUnit, rlDest, rlResult);
50 return false;
51}
52
buzbee408ad162012-06-06 16:45:18 -070053bool genAndLong(CompilationUnit* cUnit, RegLocation rlDest,
Ian Rogers7caad772012-03-30 01:07:54 -070054 RegLocation rlSrc1, RegLocation rlSrc2)
55{
56 oatFlushAllRegs(cUnit);
57 oatLockCallTemps(cUnit); // Prepare for explicit register usage
58 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
Ian Rogersfc700ed2012-04-04 11:21:26 -070059 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
Ian Rogers7caad772012-03-30 01:07:54 -070060 // Compute (r1:r0) = (r1:r0) + (r2:r3)
61 opRegReg(cUnit, kOpAnd, r0, r2); // r0 = r0 - r2
62 opRegReg(cUnit, kOpAnd, r1, r3); // r1 = r1 - r3 - CF
buzbee2cfc6392012-05-07 14:51:40 -070063 RegLocation rlResult = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, r0, r1,
64 INVALID_SREG, INVALID_SREG};
Ian Rogers7caad772012-03-30 01:07:54 -070065 storeValueWide(cUnit, rlDest, rlResult);
66 return false;
67}
68
buzbee408ad162012-06-06 16:45:18 -070069bool genOrLong(CompilationUnit* cUnit, RegLocation rlDest,
Bill Buzbeea114add2012-05-03 15:00:40 -070070 RegLocation rlSrc1, RegLocation rlSrc2)
Ian Rogers7caad772012-03-30 01:07:54 -070071{
72 oatFlushAllRegs(cUnit);
73 oatLockCallTemps(cUnit); // Prepare for explicit register usage
74 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
Ian Rogersfc700ed2012-04-04 11:21:26 -070075 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
Ian Rogers7caad772012-03-30 01:07:54 -070076 // Compute (r1:r0) = (r1:r0) + (r2:r3)
77 opRegReg(cUnit, kOpOr, r0, r2); // r0 = r0 - r2
78 opRegReg(cUnit, kOpOr, r1, r3); // r1 = r1 - r3 - CF
buzbee2cfc6392012-05-07 14:51:40 -070079 RegLocation rlResult = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, r0, r1,
80 INVALID_SREG, INVALID_SREG};
Ian Rogers7caad772012-03-30 01:07:54 -070081 storeValueWide(cUnit, rlDest, rlResult);
82 return false;
83}
84
buzbee408ad162012-06-06 16:45:18 -070085bool genXorLong(CompilationUnit* cUnit, RegLocation rlDest,
Ian Rogers7caad772012-03-30 01:07:54 -070086 RegLocation rlSrc1, RegLocation rlSrc2)
87{
88 oatFlushAllRegs(cUnit);
89 oatLockCallTemps(cUnit); // Prepare for explicit register usage
90 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
Ian Rogersfc700ed2012-04-04 11:21:26 -070091 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
Ian Rogers7caad772012-03-30 01:07:54 -070092 // Compute (r1:r0) = (r1:r0) + (r2:r3)
93 opRegReg(cUnit, kOpXor, r0, r2); // r0 = r0 - r2
94 opRegReg(cUnit, kOpXor, r1, r3); // r1 = r1 - r3 - CF
buzbee2cfc6392012-05-07 14:51:40 -070095 RegLocation rlResult = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, r0, r1,
96 INVALID_SREG, INVALID_SREG};
Ian Rogers7caad772012-03-30 01:07:54 -070097 storeValueWide(cUnit, rlDest, rlResult);
98 return false;
99}
100
buzbee408ad162012-06-06 16:45:18 -0700101bool genNegLong(CompilationUnit* cUnit, RegLocation rlDest,
buzbeee88dfbf2012-03-05 11:19:57 -0800102 RegLocation rlSrc)
103{
Ian Rogers7caad772012-03-30 01:07:54 -0700104 oatFlushAllRegs(cUnit);
105 oatLockCallTemps(cUnit); // Prepare for explicit register usage
106 loadValueDirectWideFixed(cUnit, rlSrc, r0, r1);
107 // Compute (r1:r0) = -(r1:r0)
108 opRegReg(cUnit, kOpNeg, r0, r0); // r0 = -r0
109 opRegImm(cUnit, kOpAdc, r1, 0); // r1 = r1 + CF
110 opRegReg(cUnit, kOpNeg, r1, r1); // r1 = -r1
buzbee2cfc6392012-05-07 14:51:40 -0700111 RegLocation rlResult = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, r0, r1,
112 INVALID_SREG, INVALID_SREG};
Ian Rogers7caad772012-03-30 01:07:54 -0700113 storeValueWide(cUnit, rlDest, rlResult);
114 return false;
buzbeee88dfbf2012-03-05 11:19:57 -0800115}
116
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700117void spillCoreRegs(CompilationUnit* cUnit) {
118 if (cUnit->numCoreSpills == 0) {
119 return;
120 }
121 // Spill mask not including fake return address register
122 uint32_t mask = cUnit->coreSpillMask & ~(1 << rRET);
jeffhao703f2cd2012-07-13 17:25:52 -0700123 int offset = cUnit->frameSize - (4 * cUnit->numCoreSpills);
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700124 for (int reg = 0; mask; mask >>= 1, reg++) {
125 if (mask & 0x1) {
buzbeef0504cd2012-11-13 16:31:10 -0800126 storeWordDisp(cUnit, rX86_SP, offset, reg);
jeffhao703f2cd2012-07-13 17:25:52 -0700127 offset += 4;
buzbeee88dfbf2012-03-05 11:19:57 -0800128 }
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700129 }
buzbeee88dfbf2012-03-05 11:19:57 -0800130}
131
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700132void unSpillCoreRegs(CompilationUnit* cUnit) {
133 if (cUnit->numCoreSpills == 0) {
134 return;
135 }
136 // Spill mask not including fake return address register
137 uint32_t mask = cUnit->coreSpillMask & ~(1 << rRET);
jeffhao703f2cd2012-07-13 17:25:52 -0700138 int offset = cUnit->frameSize - (4 * cUnit->numCoreSpills);
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700139 for (int reg = 0; mask; mask >>= 1, reg++) {
140 if (mask & 0x1) {
buzbeef0504cd2012-11-13 16:31:10 -0800141 loadWordDisp(cUnit, rX86_SP, offset, reg);
jeffhao703f2cd2012-07-13 17:25:52 -0700142 offset += 4;
buzbeee88dfbf2012-03-05 11:19:57 -0800143 }
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700144 }
Ian Rogersb5d09b22012-03-06 22:14:17 -0800145}
146
147void opRegThreadMem(CompilationUnit* cUnit, OpKind op, int rDest, int threadOffset) {
148 X86OpCode opcode = kX86Bkpt;
149 switch (op) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700150 case kOpCmp: opcode = kX86Cmp32RT; break;
151 default:
152 LOG(FATAL) << "Bad opcode: " << op;
153 break;
Ian Rogersb5d09b22012-03-06 22:14:17 -0800154 }
Ian Rogersb5d09b22012-03-06 22:14:17 -0800155 newLIR2(cUnit, opcode, rDest, threadOffset);
buzbeee88dfbf2012-03-05 11:19:57 -0800156}
157
buzbeead8f15e2012-06-18 14:49:45 -0700158void genEntrySequence(CompilationUnit* cUnit, RegLocation* argLocs,
159 RegLocation rlMethod)
buzbeee88dfbf2012-03-05 11:19:57 -0800160{
Bill Buzbeea114add2012-05-03 15:00:40 -0700161 /*
buzbeef0504cd2012-11-13 16:31:10 -0800162 * On entry, rX86_ARG0, rX86_ARG1, rX86_ARG2 are live. Let the register
Bill Buzbeea114add2012-05-03 15:00:40 -0700163 * allocation mechanism know so it doesn't try to use any of them when
164 * expanding the frame or flushing. This leaves the utility
165 * code with no spare temps.
166 */
buzbeef0504cd2012-11-13 16:31:10 -0800167 oatLockTemp(cUnit, rX86_ARG0);
168 oatLockTemp(cUnit, rX86_ARG1);
169 oatLockTemp(cUnit, rX86_ARG2);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800170
Bill Buzbeea114add2012-05-03 15:00:40 -0700171 /* Build frame, return address already on stack */
buzbeef0504cd2012-11-13 16:31:10 -0800172 opRegImm(cUnit, kOpSub, rX86_SP, cUnit->frameSize - 4);
buzbeee88dfbf2012-03-05 11:19:57 -0800173
Bill Buzbeea114add2012-05-03 15:00:40 -0700174 /*
175 * We can safely skip the stack overflow check if we're
176 * a leaf *and* our frame size < fudge factor.
177 */
178 bool skipOverflowCheck = ((cUnit->attrs & METHOD_IS_LEAF) &&
179 ((size_t)cUnit->frameSize <
180 Thread::kStackOverflowReservedBytes));
181 newLIR0(cUnit, kPseudoMethodEntry);
182 /* Spill core callee saves */
183 spillCoreRegs(cUnit);
184 /* NOTE: promotion of FP regs currently unsupported, thus no FP spill */
185 DCHECK_EQ(cUnit->numFPSpills, 0);
186 if (!skipOverflowCheck) {
buzbeef0504cd2012-11-13 16:31:10 -0800187 // cmp rX86_SP, fs:[stack_end_]; jcc throw_launchpad
Bill Buzbeea114add2012-05-03 15:00:40 -0700188 LIR* tgt = rawLIR(cUnit, 0, kPseudoThrowTarget, kThrowStackOverflow, 0, 0, 0, 0);
buzbeef0504cd2012-11-13 16:31:10 -0800189 opRegThreadMem(cUnit, kOpCmp, rX86_SP, Thread::StackEndOffset().Int32Value());
Bill Buzbeea114add2012-05-03 15:00:40 -0700190 opCondBranch(cUnit, kCondUlt, tgt);
191 // Remember branch target - will process later
192 oatInsertGrowableList(cUnit, &cUnit->throwLaunchpads, (intptr_t)tgt);
193 }
buzbee9c044ce2012-03-18 13:24:07 -0700194
buzbeead8f15e2012-06-18 14:49:45 -0700195 flushIns(cUnit, argLocs, rlMethod);
buzbeee88dfbf2012-03-05 11:19:57 -0800196
buzbeef0504cd2012-11-13 16:31:10 -0800197 oatFreeTemp(cUnit, rX86_ARG0);
198 oatFreeTemp(cUnit, rX86_ARG1);
199 oatFreeTemp(cUnit, rX86_ARG2);
buzbeee88dfbf2012-03-05 11:19:57 -0800200}
201
buzbee2cfc6392012-05-07 14:51:40 -0700202void genExitSequence(CompilationUnit* cUnit) {
Ian Rogersb5d09b22012-03-06 22:14:17 -0800203 /*
buzbeef0504cd2012-11-13 16:31:10 -0800204 * In the exit path, rX86_RET0/rX86_RET1 are live - make sure they aren't
Ian Rogersb5d09b22012-03-06 22:14:17 -0800205 * allocated by the register utilities as temps.
206 */
buzbeef0504cd2012-11-13 16:31:10 -0800207 oatLockTemp(cUnit, rX86_RET0);
208 oatLockTemp(cUnit, rX86_RET1);
buzbeee88dfbf2012-03-05 11:19:57 -0800209
Ian Rogersb5d09b22012-03-06 22:14:17 -0800210 newLIR0(cUnit, kPseudoMethodExit);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800211 unSpillCoreRegs(cUnit);
212 /* Remove frame except for return address */
buzbeef0504cd2012-11-13 16:31:10 -0800213 opRegImm(cUnit, kOpAdd, rX86_SP, cUnit->frameSize - 4);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800214 newLIR0(cUnit, kX86Ret);
buzbeee88dfbf2012-03-05 11:19:57 -0800215}
216
217/*
218 * Nop any unconditional branches that go to the next instruction.
219 * Note: new redundant branches may be inserted later, and we'll
220 * use a check in final instruction assembly to nop those out.
221 */
Ian Rogersb5d09b22012-03-06 22:14:17 -0800222void removeRedundantBranches(CompilationUnit* cUnit) {
223 LIR* thisLIR;
buzbeee88dfbf2012-03-05 11:19:57 -0800224
Ian Rogersb5d09b22012-03-06 22:14:17 -0800225 for (thisLIR = (LIR*) cUnit->firstLIRInsn;
Bill Buzbeea114add2012-05-03 15:00:40 -0700226 thisLIR != (LIR*) cUnit->lastLIRInsn;
227 thisLIR = NEXT_LIR(thisLIR)) {
buzbeee88dfbf2012-03-05 11:19:57 -0800228
Bill Buzbeea114add2012-05-03 15:00:40 -0700229 /* Branch to the next instruction */
230 if (thisLIR->opcode == kX86Jmp8 || thisLIR->opcode == kX86Jmp32) {
231 LIR* nextLIR = thisLIR;
buzbeee88dfbf2012-03-05 11:19:57 -0800232
Bill Buzbeea114add2012-05-03 15:00:40 -0700233 while (true) {
234 nextLIR = NEXT_LIR(nextLIR);
buzbeee88dfbf2012-03-05 11:19:57 -0800235
Bill Buzbeea114add2012-05-03 15:00:40 -0700236 /*
237 * Is the branch target the next instruction?
238 */
239 if (nextLIR == (LIR*) thisLIR->target) {
240 thisLIR->flags.isNop = true;
241 break;
242 }
Ian Rogersb5d09b22012-03-06 22:14:17 -0800243
Bill Buzbeea114add2012-05-03 15:00:40 -0700244 /*
245 * Found real useful stuff between the branch and the target.
246 * Need to explicitly check the lastLIRInsn here because it
247 * might be the last real instruction.
248 */
249 if (!isPseudoOpcode(nextLIR->opcode) ||
250 (nextLIR = (LIR*) cUnit->lastLIRInsn))
251 break;
Ian Rogersb5d09b22012-03-06 22:14:17 -0800252 }
buzbeee88dfbf2012-03-05 11:19:57 -0800253 }
Ian Rogersb5d09b22012-03-06 22:14:17 -0800254 }
buzbeee88dfbf2012-03-05 11:19:57 -0800255}
256
257
258/* Common initialization routine for an architecture family */
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700259bool oatArchInit() {
260 int i;
buzbeee88dfbf2012-03-05 11:19:57 -0800261
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700262 for (i = 0; i < kX86Last; i++) {
263 if (EncodingMap[i].opcode != i) {
264 LOG(FATAL) << "Encoding order for " << EncodingMap[i].name
Bill Buzbeea114add2012-05-03 15:00:40 -0700265 << " is wrong: expecting " << i << ", seeing "
266 << (int)EncodingMap[i].opcode;
buzbeee88dfbf2012-03-05 11:19:57 -0800267 }
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700268 }
buzbeee88dfbf2012-03-05 11:19:57 -0800269
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700270 return oatArchVariantInit();
buzbeee88dfbf2012-03-05 11:19:57 -0800271}
272
buzbeeb046e162012-10-30 15:48:42 -0700273// Not used in x86
274int loadHelper(CompilationUnit* cUnit, int offset)
275{
276 LOG(FATAL) << "Unexpected use of loadHelper in x86";
277 return INVALID_REG;
278}
279
280
281
buzbeee88dfbf2012-03-05 11:19:57 -0800282} // namespace art