blob: 3614dce66a541b8897ad120afb3770fe6852e234 [file] [log] [blame]
buzbeee88dfbf2012-03-05 11:19:57 -08001/*
2 * Copyright (C) 2012 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#include "../../Dalvik.h"
18#include "../../CompilerInternals.h"
19#include "X86LIR.h"
20#include "Codegen.h"
21#include <sys/mman.h> /* for protection change */
22
23namespace art {
24
25#define MAX_ASSEMBLER_RETRIES 50
26
27/*
28 * opcode: MipsOpCode enum
29 * skeleton: pre-designated bit-pattern for this opcode
30 * k0: key to applying ds/de
31 * ds: dest start bit position
32 * de: dest end bit position
33 * k1: key to applying s1s/s1e
34 * s1s: src1 start bit position
35 * s1e: src1 end bit position
36 * k2: key to applying s2s/s2e
37 * s2s: src2 start bit position
38 * s2e: src2 end bit position
39 * operands: number of operands (for sanity check purposes)
40 * name: mnemonic name
41 * fmt: for pretty-printing
42 */
43#define ENCODING_MAP(opcode, skeleton, k0, ds, de, k1, s1s, s1e, k2, s2s, s2e, \
44 k3, k3s, k3e, flags, name, fmt, size) \
45 {skeleton, {{k0, ds, de}, {k1, s1s, s1e}, {k2, s2s, s2e}, \
46 {k3, k3s, k3e}}, opcode, flags, name, fmt, size}
47
48/* Instruction dump string format keys: !pf, where "!" is the start
49 * of the key, "p" is which numeric operand to use and "f" is the
50 * print format.
51 *
52 * [p]ositions:
53 * 0 -> operands[0] (dest)
54 * 1 -> operands[1] (src1)
55 * 2 -> operands[2] (src2)
56 * 3 -> operands[3] (extra)
57 *
58 * [f]ormats:
59 * h -> 4-digit hex
60 * d -> decimal
61 * E -> decimal*4
62 * F -> decimal*2
63 * c -> branch condition (beq, bne, etc.)
64 * t -> pc-relative target
65 * T -> pc-region target
66 * u -> 1st half of bl[x] target
67 * v -> 2nd half ob bl[x] target
68 * R -> register list
69 * s -> single precision floating point register
70 * S -> double precision floating point register
71 * m -> Thumb2 modified immediate
72 * n -> complimented Thumb2 modified immediate
73 * M -> Thumb2 16-bit zero-extended immediate
74 * b -> 4-digit binary
75 * N -> append a NOP
76 *
77 * [!] escape. To insert "!", use "!!"
78 */
79/* NOTE: must be kept in sync with enum MipsOpcode from LIR.h */
80/*
81 * TUNING: We're currently punting on the branch delay slots. All branch
82 * instructions in this map are given a size of 8, which during assembly
83 * is expanded to include a nop. This scheme should be replaced with
84 * an assembler pass to fill those slots when possible.
85 */
86MipsEncodingMap EncodingMap[kX86Last] = {
87};
88
89
90/*
91 * Assemble the LIR into binary instruction format. Note that we may
92 * discover that pc-relative displacements may not fit the selected
93 * instruction. In those cases we will try to substitute a new code
94 * sequence or request that the trace be shortened and retried.
95 */
96AssemblerStatus oatAssembleInstructions(CompilationUnit *cUnit,
97 intptr_t startAddr)
98{
99 UNIMPLEMENTED(WARNING) << "oatAssembleInstructions";
100 return kSuccess;
101#if 0
102 LIR *lir;
103 AssemblerStatus res = kSuccess; // Assume success
104
105 for (lir = (LIR *) cUnit->firstLIRInsn; lir; lir = NEXT_LIR(lir)) {
106 if (lir->opcode < 0) {
107 continue;
108 }
109
110
111 if (lir->flags.isNop) {
112 continue;
113 }
114
115 if (lir->flags.pcRelFixup) {
116 if (lir->opcode == kMipsDelta) {
117 /*
118 * The "Delta" pseudo-ops load the difference between
119 * two pc-relative locations into a the target register
120 * found in operands[0]. The delta is determined by
121 * (label2 - label1), where label1 is a standard
122 * kPseudoTargetLabel and is stored in operands[2].
123 * If operands[3] is null, then label2 is a kPseudoTargetLabel
124 * and is found in lir->target. If operands[3] is non-NULL,
125 * then it is a Switch/Data table.
126 */
127 int offset1 = ((LIR*)lir->operands[2])->offset;
128 SwitchTable *tabRec = (SwitchTable*)lir->operands[3];
129 int offset2 = tabRec ? tabRec->offset : lir->target->offset;
130 int delta = offset2 - offset1;
131 if ((delta & 0xffff) == delta) {
132 // Fits
133 lir->operands[1] = delta;
134 } else {
135 // Doesn't fit - must expand to kMipsDelta[Hi|Lo] pair
136 LIR *newDeltaHi =
137 rawLIR(cUnit, lir->dalvikOffset, kMipsDeltaHi,
138 lir->operands[0], 0, lir->operands[2],
139 lir->operands[3], lir->target);
140 oatInsertLIRBefore((LIR*)lir, (LIR*)newDeltaHi);
141 LIR *newDeltaLo =
142 rawLIR(cUnit, lir->dalvikOffset, kMipsDeltaLo,
143 lir->operands[0], 0, lir->operands[2],
144 lir->operands[3], lir->target);
145 oatInsertLIRBefore((LIR*)lir, (LIR*)newDeltaLo);
146 lir->flags.isNop = true;
147 res = kRetryAll;
148 }
149 } else if (lir->opcode == kMipsDeltaLo) {
150 int offset1 = ((LIR*)lir->operands[2])->offset;
151 SwitchTable *tabRec = (SwitchTable*)lir->operands[3];
152 int offset2 = tabRec ? tabRec->offset : lir->target->offset;
153 int delta = offset2 - offset1;
154 lir->operands[1] = delta & 0xffff;
155 } else if (lir->opcode == kMipsDeltaHi) {
156 int offset1 = ((LIR*)lir->operands[2])->offset;
157 SwitchTable *tabRec = (SwitchTable*)lir->operands[3];
158 int offset2 = tabRec ? tabRec->offset : lir->target->offset;
159 int delta = offset2 - offset1;
160 lir->operands[1] = (delta >> 16) & 0xffff;
161 } else if (lir->opcode == kMipsB || lir->opcode == kMipsBal) {
162 LIR *targetLIR = (LIR *) lir->target;
163 intptr_t pc = lir->offset + 4;
164 intptr_t target = targetLIR->offset;
165 int delta = target - pc;
166 if (delta & 0x3) {
167 LOG(FATAL) << "PC-rel offset not multiple of 4: " << delta;
168 }
169 if (delta > 131068 || delta < -131069) {
170 res = kRetryAll;
171 convertShortToLongBranch(cUnit, lir);
172 } else {
173 lir->operands[0] = delta >> 2;
174 }
175 } else if (lir->opcode >= kMipsBeqz && lir->opcode <= kMipsBnez) {
176 LIR *targetLIR = (LIR *) lir->target;
177 intptr_t pc = lir->offset + 4;
178 intptr_t target = targetLIR->offset;
179 int delta = target - pc;
180 if (delta & 0x3) {
181 LOG(FATAL) << "PC-rel offset not multiple of 4: " << delta;
182 }
183 if (delta > 131068 || delta < -131069) {
184 res = kRetryAll;
185 convertShortToLongBranch(cUnit, lir);
186 } else {
187 lir->operands[1] = delta >> 2;
188 }
189 } else if (lir->opcode == kMipsBeq || lir->opcode == kMipsBne) {
190 LIR *targetLIR = (LIR *) lir->target;
191 intptr_t pc = lir->offset + 4;
192 intptr_t target = targetLIR->offset;
193 int delta = target - pc;
194 if (delta & 0x3) {
195 LOG(FATAL) << "PC-rel offset not multiple of 4: " << delta;
196 }
197 if (delta > 131068 || delta < -131069) {
198 res = kRetryAll;
199 convertShortToLongBranch(cUnit, lir);
200 } else {
201 lir->operands[2] = delta >> 2;
202 }
203 } else if (lir->opcode == kMipsJal) {
204 intptr_t curPC = (startAddr + lir->offset + 4) & ~3;
205 intptr_t target = lir->operands[0];
206 /* ensure PC-region branch can be used */
207 DCHECK_EQ((curPC & 0xF0000000), (target & 0xF0000000));
208 if (target & 0x3) {
209 LOG(FATAL) << "Jump target not multiple of 4: " << target;
210 }
211 lir->operands[0] = target >> 2;
212 } else if (lir->opcode == kMipsLahi) { /* ld address hi (via lui) */
213 LIR *targetLIR = (LIR *) lir->target;
214 intptr_t target = startAddr + targetLIR->offset;
215 lir->operands[1] = target >> 16;
216 } else if (lir->opcode == kMipsLalo) { /* ld address lo (via ori) */
217 LIR *targetLIR = (LIR *) lir->target;
218 intptr_t target = startAddr + targetLIR->offset;
219 lir->operands[2] = lir->operands[2] + target;
220 }
221 }
222
223 /*
224 * If one of the pc-relative instructions expanded we'll have
225 * to make another pass. Don't bother to fully assemble the
226 * instruction.
227 */
228 if (res != kSuccess) {
229 continue;
230 }
231 const MipsEncodingMap *encoder = &EncodingMap[lir->opcode];
232 u4 bits = encoder->skeleton;
233 int i;
234 for (i = 0; i < 4; i++) {
235 u4 operand;
236 u4 value;
237 operand = lir->operands[i];
238 switch(encoder->fieldLoc[i].kind) {
239 case kFmtUnused:
240 break;
241 case kFmtBitBlt:
242 if (encoder->fieldLoc[i].start == 0 && encoder->fieldLoc[i].end == 31) {
243 value = operand;
244 } else {
245 value = (operand << encoder->fieldLoc[i].start) &
246 ((1 << (encoder->fieldLoc[i].end + 1)) - 1);
247 }
248 bits |= value;
249 break;
250 case kFmtBlt5_2:
251 value = (operand & 0x1f);
252 bits |= (value << encoder->fieldLoc[i].start);
253 bits |= (value << encoder->fieldLoc[i].end);
254 break;
255 case kFmtDfp: {
256 DCHECK(DOUBLEREG(operand));
257 DCHECK((operand & 0x1) == 0);
258 value = ((operand & FP_REG_MASK) << encoder->fieldLoc[i].start) &
259 ((1 << (encoder->fieldLoc[i].end + 1)) - 1);
260 bits |= value;
261 break;
262 }
263 case kFmtSfp:
264 DCHECK(SINGLEREG(operand));
265 value = ((operand & FP_REG_MASK) << encoder->fieldLoc[i].start) &
266 ((1 << (encoder->fieldLoc[i].end + 1)) - 1);
267 bits |= value;
268 break;
269 default:
270 LOG(FATAL) << "Bad encoder format: "
271 << (int)encoder->fieldLoc[i].kind;
272 }
273 }
274 // FIXME: need multi-endian handling here
275 cUnit->codeBuffer.push_back((bits >> 16) & 0xffff);
276 cUnit->codeBuffer.push_back(bits & 0xffff);
277 // TUNING: replace with proper delay slot handling
278 if (encoder->size == 8) {
279 const MipsEncodingMap *encoder = &EncodingMap[kMipsNop];
280 u4 bits = encoder->skeleton;
281 cUnit->codeBuffer.push_back((bits >> 16) & 0xffff);
282 cUnit->codeBuffer.push_back(bits & 0xffff);
283 }
284 }
285 return res;
286#endif
287}
288
289int oatGetInsnSize(LIR* lir)
290{
291 return EncodingMap[lir->opcode].size;
292}
293/*
294 * Target-dependent offset assignment.
295 * independent.
296 */
297int oatAssignInsnOffsets(CompilationUnit* cUnit)
298{
299 LIR* x86LIR;
300 int offset = 0;
301
302 for (x86LIR = (LIR *) cUnit->firstLIRInsn;
303 x86LIR;
304 x86LIR = NEXT_LIR(x86LIR)) {
305 x86LIR->offset = offset;
306 if (x86LIR->opcode >= 0) {
307 if (!x86LIR->flags.isNop) {
308 offset += x86LIR->flags.size;
309 }
310 } else if (x86LIR->opcode == kPseudoPseudoAlign4) {
311 if (offset & 0x2) {
312 offset += 2;
313 x86LIR->operands[0] = 1;
314 } else {
315 x86LIR->operands[0] = 0;
316 }
317 }
318 /* Pseudo opcodes don't consume space */
319 }
320
321 return offset;
322}
323
324} // namespace art