blob: bd95afbf76efa3a99ad342f5f945e84074aa448f [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
buzbeee88dfbf2012-03-05 11:19:57 -080027bool genNegLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
28 RegLocation rlSrc)
29{
30 UNIMPLEMENTED(WARNING) << "genNegLong";
31#if 0
32 rlSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
33 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
34 /*
35 * [v1 v0] = -[a1 a0]
36 * negu v0,a0
37 * negu v1,a1
38 * sltu t1,r_zero
39 * subu v1,v1,t1
40 */
41
42 opRegReg(cUnit, kOpNeg, rlResult.lowReg, rlSrc.lowReg);
43 opRegReg(cUnit, kOpNeg, rlResult.highReg, rlSrc.highReg);
44 int tReg = oatAllocTemp(cUnit);
buzbeea7678db2012-03-05 15:35:46 -080045 newLIR3(cUnit, kX86Sltu, tReg, r_ZERO, rlResult.lowReg);
buzbeee88dfbf2012-03-05 11:19:57 -080046 opRegRegReg(cUnit, kOpSub, rlResult.highReg, rlResult.highReg, tReg);
47 oatFreeTemp(cUnit, tReg);
48 storeValueWide(cUnit, rlDest, rlResult);
49#endif
50 return false;
51}
52
53void genDebuggerUpdate(CompilationUnit* cUnit, int32_t offset);
54
Ian Rogersf7d9ad32012-03-13 18:45:39 -070055void spillCoreRegs(CompilationUnit* cUnit) {
56 if (cUnit->numCoreSpills == 0) {
57 return;
58 }
59 // Spill mask not including fake return address register
60 uint32_t mask = cUnit->coreSpillMask & ~(1 << rRET);
61 int offset = cUnit->frameSize - 4;
62 for (int reg = 0; mask; mask >>= 1, reg++) {
63 if (mask & 0x1) {
64 offset -= 4;
65 storeWordDisp(cUnit, rSP, offset, reg);
buzbeee88dfbf2012-03-05 11:19:57 -080066 }
Ian Rogersf7d9ad32012-03-13 18:45:39 -070067 }
buzbeee88dfbf2012-03-05 11:19:57 -080068}
69
Ian Rogersf7d9ad32012-03-13 18:45:39 -070070void unSpillCoreRegs(CompilationUnit* cUnit) {
71 if (cUnit->numCoreSpills == 0) {
72 return;
73 }
74 // Spill mask not including fake return address register
75 uint32_t mask = cUnit->coreSpillMask & ~(1 << rRET);
76 int offset = cUnit->frameSize - 4;
77 for (int reg = 0; mask; mask >>= 1, reg++) {
78 if (mask & 0x1) {
79 offset -= 4;
80 loadWordDisp(cUnit, rSP, offset, reg);
buzbeee88dfbf2012-03-05 11:19:57 -080081 }
Ian Rogersf7d9ad32012-03-13 18:45:39 -070082 }
Ian Rogersb5d09b22012-03-06 22:14:17 -080083}
84
85void opRegThreadMem(CompilationUnit* cUnit, OpKind op, int rDest, int threadOffset) {
86 X86OpCode opcode = kX86Bkpt;
87 switch (op) {
88 case kOpCmp: opcode = kX86Cmp32RT; break;
89 default:
90 LOG(FATAL) << "Bad opcode: " << op;
91 break;
92 }
Ian Rogersb5d09b22012-03-06 22:14:17 -080093 newLIR2(cUnit, opcode, rDest, threadOffset);
buzbeee88dfbf2012-03-05 11:19:57 -080094}
95
96void genEntrySequence(CompilationUnit* cUnit, BasicBlock* bb)
97{
buzbeee88dfbf2012-03-05 11:19:57 -080098 /*
Ian Rogersb5d09b22012-03-06 22:14:17 -080099 * On entry, rARG0, rARG1, rARG2 are live. Let the register
buzbeee88dfbf2012-03-05 11:19:57 -0800100 * allocation mechanism know so it doesn't try to use any of them when
101 * expanding the frame or flushing. This leaves the utility
Ian Rogersb5d09b22012-03-06 22:14:17 -0800102 * code with no spare temps.
buzbeee88dfbf2012-03-05 11:19:57 -0800103 */
104 oatLockTemp(cUnit, rARG0);
105 oatLockTemp(cUnit, rARG1);
106 oatLockTemp(cUnit, rARG2);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800107
108 /* Build frame, return address already on stack */
109 opRegImm(cUnit, kOpSub, rSP, cUnit->frameSize - 4);
buzbeee88dfbf2012-03-05 11:19:57 -0800110
111 /*
112 * We can safely skip the stack overflow check if we're
113 * a leaf *and* our frame size < fudge factor.
114 */
115 bool skipOverflowCheck = ((cUnit->attrs & METHOD_IS_LEAF) &&
116 ((size_t)cUnit->frameSize <
117 Thread::kStackOverflowReservedBytes));
118 newLIR0(cUnit, kPseudoMethodEntry);
buzbeee88dfbf2012-03-05 11:19:57 -0800119 /* Spill core callee saves */
120 spillCoreRegs(cUnit);
121 /* NOTE: promotion of FP regs currently unsupported, thus no FP spill */
122 DCHECK_EQ(cUnit->numFPSpills, 0);
123 if (!skipOverflowCheck) {
Ian Rogersb5d09b22012-03-06 22:14:17 -0800124 // cmp rSP, fs:[stack_end_]; jcc throw_launchpad
125 LIR* tgt = rawLIR(cUnit, 0, kPseudoThrowTarget, kThrowStackOverflow, 0, 0, 0, 0);
126 opRegThreadMem(cUnit, kOpCmp, rSP, Thread::StackEndOffset().Int32Value());
127 opCondBranch(cUnit, kCondUlt, tgt);
128 // Remember branch target - will process later
129 oatInsertGrowableList(cUnit, &cUnit->throwLaunchpads, (intptr_t)tgt);
buzbeee88dfbf2012-03-05 11:19:57 -0800130 }
buzbee9c044ce2012-03-18 13:24:07 -0700131
buzbeee88dfbf2012-03-05 11:19:57 -0800132 flushIns(cUnit);
133
134 if (cUnit->genDebugger) {
135 // Refresh update debugger callout
Ian Rogersb5d09b22012-03-06 22:14:17 -0800136 UNIMPLEMENTED(WARNING) << "genDebugger";
137#if 0
buzbeee88dfbf2012-03-05 11:19:57 -0800138 loadWordDisp(cUnit, rSELF,
139 OFFSETOF_MEMBER(Thread, pUpdateDebuggerFromCode), rSUSPEND);
140 genDebuggerUpdate(cUnit, DEBUGGER_METHOD_ENTRY);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800141#endif
buzbeee88dfbf2012-03-05 11:19:57 -0800142 }
143
144 oatFreeTemp(cUnit, rARG0);
145 oatFreeTemp(cUnit, rARG1);
146 oatFreeTemp(cUnit, rARG2);
buzbeee88dfbf2012-03-05 11:19:57 -0800147}
148
Ian Rogersb5d09b22012-03-06 22:14:17 -0800149void genExitSequence(CompilationUnit* cUnit, BasicBlock* bb) {
150 /*
151 * In the exit path, rRET0/rRET1 are live - make sure they aren't
152 * allocated by the register utilities as temps.
153 */
154 oatLockTemp(cUnit, rRET0);
155 oatLockTemp(cUnit, rRET1);
buzbeee88dfbf2012-03-05 11:19:57 -0800156
Ian Rogersb5d09b22012-03-06 22:14:17 -0800157 newLIR0(cUnit, kPseudoMethodExit);
158 /* If we're compiling for the debugger, generate an update callout */
159 if (cUnit->genDebugger) {
160 genDebuggerUpdate(cUnit, DEBUGGER_METHOD_EXIT);
161 }
162 unSpillCoreRegs(cUnit);
163 /* Remove frame except for return address */
164 opRegImm(cUnit, kOpAdd, rSP, cUnit->frameSize - 4);
165 newLIR0(cUnit, kX86Ret);
buzbeee88dfbf2012-03-05 11:19:57 -0800166}
167
168/*
169 * Nop any unconditional branches that go to the next instruction.
170 * Note: new redundant branches may be inserted later, and we'll
171 * use a check in final instruction assembly to nop those out.
172 */
Ian Rogersb5d09b22012-03-06 22:14:17 -0800173void removeRedundantBranches(CompilationUnit* cUnit) {
174 LIR* thisLIR;
buzbeee88dfbf2012-03-05 11:19:57 -0800175
Ian Rogersb5d09b22012-03-06 22:14:17 -0800176 for (thisLIR = (LIR*) cUnit->firstLIRInsn;
177 thisLIR != (LIR*) cUnit->lastLIRInsn;
178 thisLIR = NEXT_LIR(thisLIR)) {
buzbeee88dfbf2012-03-05 11:19:57 -0800179
Ian Rogersb5d09b22012-03-06 22:14:17 -0800180 /* Branch to the next instruction */
Ian Rogersb41b33b2012-03-20 14:22:54 -0700181 if (thisLIR->opcode == kX86Jmp8 || thisLIR->opcode == kX86Jmp32) {
Ian Rogersb5d09b22012-03-06 22:14:17 -0800182 LIR* nextLIR = thisLIR;
buzbeee88dfbf2012-03-05 11:19:57 -0800183
Ian Rogersb5d09b22012-03-06 22:14:17 -0800184 while (true) {
185 nextLIR = NEXT_LIR(nextLIR);
buzbeee88dfbf2012-03-05 11:19:57 -0800186
Ian Rogersb5d09b22012-03-06 22:14:17 -0800187 /*
188 * Is the branch target the next instruction?
189 */
190 if (nextLIR == (LIR*) thisLIR->target) {
191 thisLIR->flags.isNop = true;
192 break;
buzbeee88dfbf2012-03-05 11:19:57 -0800193 }
Ian Rogersb5d09b22012-03-06 22:14:17 -0800194
195 /*
196 * Found real useful stuff between the branch and the target.
197 * Need to explicitly check the lastLIRInsn here because it
198 * might be the last real instruction.
199 */
200 if (!isPseudoOpcode(nextLIR->opcode) ||
201 (nextLIR = (LIR*) cUnit->lastLIRInsn))
202 break;
203 }
buzbeee88dfbf2012-03-05 11:19:57 -0800204 }
Ian Rogersb5d09b22012-03-06 22:14:17 -0800205 }
buzbeee88dfbf2012-03-05 11:19:57 -0800206}
207
208
209/* Common initialization routine for an architecture family */
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700210bool oatArchInit() {
211 int i;
buzbeee88dfbf2012-03-05 11:19:57 -0800212
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700213 for (i = 0; i < kX86Last; i++) {
214 if (EncodingMap[i].opcode != i) {
215 LOG(FATAL) << "Encoding order for " << EncodingMap[i].name
216 << " is wrong: expecting " << i << ", seeing " << (int)EncodingMap[i].opcode;
buzbeee88dfbf2012-03-05 11:19:57 -0800217 }
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700218 }
buzbeee88dfbf2012-03-05 11:19:57 -0800219
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700220 return oatArchVariantInit();
buzbeee88dfbf2012-03-05 11:19:57 -0800221}
222
223} // namespace art