blob: 22037f3011a3e3bfbbf04e59ba31c77ebc411569 [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
buzbee1bc37c62012-11-20 13:35:41 -080017#include "x86_lir.h"
18#include "../codegen_util.h"
19#include "../ralloc_util.h"
20
buzbeee88dfbf2012-03-05 11:19:57 -080021namespace art {
22
buzbeeb046e162012-10-30 15:48:42 -070023/* This file contains codegen for the X86 ISA */
buzbeee88dfbf2012-03-05 11:19:57 -080024
buzbeefa57c472012-11-21 12:06:18 -080025void GenBarrier(CompilationUnit *cu);
26void LoadPair(CompilationUnit *cu, int base, int low_reg, int high_reg);
27LIR *LoadWordDisp(CompilationUnit *cu, int rBase, int displacement, int r_dest);
28LIR *StoreWordDisp(CompilationUnit *cu, int rBase, int displacement, int r_src);
29LIR *LoadConstant(CompilationUnit *cu, int r_dest, int value);
buzbeee88dfbf2012-03-05 11:19:57 -080030
buzbeefa57c472012-11-21 12:06:18 -080031LIR *FpRegCopy(CompilationUnit *cu, int r_dest, int r_src)
buzbeee88dfbf2012-03-05 11:19:57 -080032{
Bill Buzbeea114add2012-05-03 15:00:40 -070033 int opcode;
34 /* must be both DOUBLE or both not DOUBLE */
buzbeefa57c472012-11-21 12:06:18 -080035 DCHECK_EQ(X86_DOUBLEREG(r_dest), X86_DOUBLEREG(r_src));
36 if (X86_DOUBLEREG(r_dest)) {
Bill Buzbeea114add2012-05-03 15:00:40 -070037 opcode = kX86MovsdRR;
38 } else {
buzbeefa57c472012-11-21 12:06:18 -080039 if (X86_SINGLEREG(r_dest)) {
40 if (X86_SINGLEREG(r_src)) {
Bill Buzbeea114add2012-05-03 15:00:40 -070041 opcode = kX86MovssRR;
42 } else { // Fpr <- Gpr
43 opcode = kX86MovdxrRR;
44 }
45 } else { // Gpr <- Fpr
buzbeefa57c472012-11-21 12:06:18 -080046 DCHECK(X86_SINGLEREG(r_src));
Bill Buzbeea114add2012-05-03 15:00:40 -070047 opcode = kX86MovdrxRR;
buzbeee88dfbf2012-03-05 11:19:57 -080048 }
Bill Buzbeea114add2012-05-03 15:00:40 -070049 }
buzbeeec137432012-11-13 12:13:16 -080050 DCHECK_NE((EncodingMap[opcode].flags & IS_BINARY_OP), 0ULL);
buzbeefa57c472012-11-21 12:06:18 -080051 LIR* res = RawLIR(cu, cu->current_dalvik_offset, opcode, r_dest, r_src);
52 if (r_dest == r_src) {
53 res->flags.is_nop = true;
Bill Buzbeea114add2012-05-03 15:00:40 -070054 }
55 return res;
buzbeee88dfbf2012-03-05 11:19:57 -080056}
57
58/*
59 * Load a immediate using a shortcut if possible; otherwise
60 * grab from the per-translation literal pool. If target is
61 * a high register, build constant into a low register and copy.
62 *
63 * No additional register clobbering operation performed. Use this version when
buzbeefa57c472012-11-21 12:06:18 -080064 * 1) r_dest is freshly returned from AllocTemp or
buzbeee88dfbf2012-03-05 11:19:57 -080065 * 2) The codegen is under fixed register usage
66 */
buzbeefa57c472012-11-21 12:06:18 -080067LIR *LoadConstantNoClobber(CompilationUnit *cu, int r_dest, int value)
Bill Buzbeea114add2012-05-03 15:00:40 -070068{
buzbeefa57c472012-11-21 12:06:18 -080069 int r_dest_save = r_dest;
70 if (X86_FPREG(r_dest)) {
Ian Rogersb41b33b2012-03-20 14:22:54 -070071 if (value == 0) {
buzbeefa57c472012-11-21 12:06:18 -080072 return NewLIR2(cu, kX86XorpsRR, r_dest, r_dest);
Ian Rogersb41b33b2012-03-20 14:22:54 -070073 }
buzbeefa57c472012-11-21 12:06:18 -080074 DCHECK(X86_SINGLEREG(r_dest));
75 r_dest = AllocTemp(cu);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -070076 }
buzbeee88dfbf2012-03-05 11:19:57 -080077
Ian Rogersb41b33b2012-03-20 14:22:54 -070078 LIR *res;
Ian Rogers6cbb2bd2012-03-16 13:45:30 -070079 if (value == 0) {
buzbeefa57c472012-11-21 12:06:18 -080080 res = NewLIR2(cu, kX86Xor32RR, r_dest, r_dest);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -070081 } else {
Ian Rogers2e9f7ed2012-09-26 11:30:43 -070082 // Note, there is no byte immediate form of a 32 bit immediate move.
buzbeefa57c472012-11-21 12:06:18 -080083 res = NewLIR2(cu, kX86Mov32RI, r_dest, value);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -070084 }
buzbeee88dfbf2012-03-05 11:19:57 -080085
buzbeefa57c472012-11-21 12:06:18 -080086 if (X86_FPREG(r_dest_save)) {
87 NewLIR2(cu, kX86MovdxrRR, r_dest_save, r_dest);
88 FreeTemp(cu, r_dest);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -070089 }
buzbeee88dfbf2012-03-05 11:19:57 -080090
Ian Rogers6cbb2bd2012-03-16 13:45:30 -070091 return res;
buzbeee88dfbf2012-03-05 11:19:57 -080092}
93
buzbeefa57c472012-11-21 12:06:18 -080094LIR* OpBranchUnconditional(CompilationUnit *cu, OpKind op)
Bill Buzbeea114add2012-05-03 15:00:40 -070095{
Ian Rogersb5d09b22012-03-06 22:14:17 -080096 CHECK_EQ(op, kOpUncondBr);
buzbeefa57c472012-11-21 12:06:18 -080097 return NewLIR1(cu, kX86Jmp8, 0 /* offset to be patched */ );
buzbeee88dfbf2012-03-05 11:19:57 -080098}
99
buzbeefa57c472012-11-21 12:06:18 -0800100LIR *LoadMultiple(CompilationUnit *cu, int rBase, int r_mask);
buzbeee88dfbf2012-03-05 11:19:57 -0800101
buzbee52a77fc2012-11-20 19:50:46 -0800102X86ConditionCode X86ConditionEncoding(ConditionCode cond);
buzbeefa57c472012-11-21 12:06:18 -0800103LIR* OpCondBranch(CompilationUnit* cu, ConditionCode cc, LIR* target)
buzbeea7678db2012-03-05 15:35:46 -0800104{
buzbeefa57c472012-11-21 12:06:18 -0800105 LIR* branch = NewLIR2(cu, kX86Jcc8, 0 /* offset to be patched */,
buzbee52a77fc2012-11-20 19:50:46 -0800106 X86ConditionEncoding(cc));
Ian Rogersb5d09b22012-03-06 22:14:17 -0800107 branch->target = target;
108 return branch;
buzbeea7678db2012-03-05 15:35:46 -0800109}
110
buzbeefa57c472012-11-21 12:06:18 -0800111LIR *OpReg(CompilationUnit *cu, OpKind op, int r_dest_src)
Bill Buzbeea114add2012-05-03 15:00:40 -0700112{
Ian Rogersb5d09b22012-03-06 22:14:17 -0800113 X86OpCode opcode = kX86Bkpt;
114 switch (op) {
115 case kOpNeg: opcode = kX86Neg32R; break;
jeffhao1395b1e2012-06-13 18:05:13 -0700116 case kOpNot: opcode = kX86Not32R; break;
Ian Rogersb5d09b22012-03-06 22:14:17 -0800117 case kOpBlx: opcode = kX86CallR; break;
118 default:
buzbee52a77fc2012-11-20 19:50:46 -0800119 LOG(FATAL) << "Bad case in OpReg " << op;
Ian Rogersb5d09b22012-03-06 22:14:17 -0800120 }
buzbeefa57c472012-11-21 12:06:18 -0800121 return NewLIR1(cu, opcode, r_dest_src);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800122}
123
buzbeefa57c472012-11-21 12:06:18 -0800124LIR *OpRegImm(CompilationUnit *cu, OpKind op, int r_dest_src1, int value)
Bill Buzbeea114add2012-05-03 15:00:40 -0700125{
Ian Rogersb5d09b22012-03-06 22:14:17 -0800126 X86OpCode opcode = kX86Bkpt;
buzbeefa57c472012-11-21 12:06:18 -0800127 bool byte_imm = IS_SIMM8(value);
128 DCHECK(!X86_FPREG(r_dest_src1));
Ian Rogersb5d09b22012-03-06 22:14:17 -0800129 switch (op) {
130 case kOpLsl: opcode = kX86Sal32RI; break;
131 case kOpLsr: opcode = kX86Shr32RI; break;
132 case kOpAsr: opcode = kX86Sar32RI; break;
buzbeefa57c472012-11-21 12:06:18 -0800133 case kOpAdd: opcode = byte_imm ? kX86Add32RI8 : kX86Add32RI; break;
134 case kOpOr: opcode = byte_imm ? kX86Or32RI8 : kX86Or32RI; break;
135 case kOpAdc: opcode = byte_imm ? kX86Adc32RI8 : kX86Adc32RI; break;
Ian Rogersb5d09b22012-03-06 22:14:17 -0800136 //case kOpSbb: opcode = kX86Sbb32RI; break;
buzbeefa57c472012-11-21 12:06:18 -0800137 case kOpAnd: opcode = byte_imm ? kX86And32RI8 : kX86And32RI; break;
138 case kOpSub: opcode = byte_imm ? kX86Sub32RI8 : kX86Sub32RI; break;
139 case kOpXor: opcode = byte_imm ? kX86Xor32RI8 : kX86Xor32RI; break;
140 case kOpCmp: opcode = byte_imm ? kX86Cmp32RI8 : kX86Cmp32RI; break;
141 case kOpMov: return LoadConstantNoClobber(cu, r_dest_src1, value);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800142 case kOpMul:
buzbeefa57c472012-11-21 12:06:18 -0800143 opcode = byte_imm ? kX86Imul32RRI8 : kX86Imul32RRI;
144 return NewLIR3(cu, opcode, r_dest_src1, r_dest_src1, value);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800145 default:
buzbee52a77fc2012-11-20 19:50:46 -0800146 LOG(FATAL) << "Bad case in OpRegImm " << op;
Ian Rogersb5d09b22012-03-06 22:14:17 -0800147 }
buzbeefa57c472012-11-21 12:06:18 -0800148 return NewLIR2(cu, opcode, r_dest_src1, value);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800149}
150
buzbeefa57c472012-11-21 12:06:18 -0800151LIR *OpRegReg(CompilationUnit *cu, OpKind op, int r_dest_src1, int r_src2)
buzbeee88dfbf2012-03-05 11:19:57 -0800152{
buzbeea7678db2012-03-05 15:35:46 -0800153 X86OpCode opcode = kX86Nop;
Ian Rogersd36c52e2012-04-09 16:29:25 -0700154 bool src2_must_be_cx = false;
buzbeee88dfbf2012-03-05 11:19:57 -0800155 switch (op) {
Ian Rogersb5d09b22012-03-06 22:14:17 -0800156 // X86 unary opcodes
157 case kOpMvn:
buzbeefa57c472012-11-21 12:06:18 -0800158 OpRegCopy(cu, r_dest_src1, r_src2);
159 return OpReg(cu, kOpNot, r_dest_src1);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800160 case kOpNeg:
buzbeefa57c472012-11-21 12:06:18 -0800161 OpRegCopy(cu, r_dest_src1, r_src2);
162 return OpReg(cu, kOpNeg, r_dest_src1);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800163 // X86 binary opcodes
164 case kOpSub: opcode = kX86Sub32RR; break;
165 case kOpSbc: opcode = kX86Sbb32RR; break;
Ian Rogersd36c52e2012-04-09 16:29:25 -0700166 case kOpLsl: opcode = kX86Sal32RC; src2_must_be_cx = true; break;
167 case kOpLsr: opcode = kX86Shr32RC; src2_must_be_cx = true; break;
168 case kOpAsr: opcode = kX86Sar32RC; src2_must_be_cx = true; break;
Ian Rogersb5d09b22012-03-06 22:14:17 -0800169 case kOpMov: opcode = kX86Mov32RR; break;
170 case kOpCmp: opcode = kX86Cmp32RR; break;
171 case kOpAdd: opcode = kX86Add32RR; break;
172 case kOpAdc: opcode = kX86Adc32RR; break;
173 case kOpAnd: opcode = kX86And32RR; break;
174 case kOpOr: opcode = kX86Or32RR; break;
175 case kOpXor: opcode = kX86Xor32RR; break;
jeffhao703f2cd2012-07-13 17:25:52 -0700176 case kOp2Byte:
177 // Use shifts instead of a byte operand if the source can't be byte accessed.
buzbeefa57c472012-11-21 12:06:18 -0800178 if (r_src2 >= 4) {
179 NewLIR2(cu, kX86Mov32RR, r_dest_src1, r_src2);
180 NewLIR2(cu, kX86Sal32RI, r_dest_src1, 24);
181 return NewLIR2(cu, kX86Sar32RI, r_dest_src1, 24);
jeffhao703f2cd2012-07-13 17:25:52 -0700182 } else {
183 opcode = kX86Movsx8RR;
184 }
185 break;
Ian Rogersb5d09b22012-03-06 22:14:17 -0800186 case kOp2Short: opcode = kX86Movsx16RR; break;
187 case kOp2Char: opcode = kX86Movzx16RR; break;
188 case kOpMul: opcode = kX86Imul32RR; break;
189 default:
buzbee52a77fc2012-11-20 19:50:46 -0800190 LOG(FATAL) << "Bad case in OpRegReg " << op;
Ian Rogersb5d09b22012-03-06 22:14:17 -0800191 break;
buzbeee88dfbf2012-03-05 11:19:57 -0800192 }
buzbeefa57c472012-11-21 12:06:18 -0800193 CHECK(!src2_must_be_cx || r_src2 == rCX);
194 return NewLIR2(cu, opcode, r_dest_src1, r_src2);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800195}
196
buzbeefa57c472012-11-21 12:06:18 -0800197LIR* OpRegMem(CompilationUnit *cu, OpKind op, int r_dest, int rBase,
Bill Buzbeea114add2012-05-03 15:00:40 -0700198 int offset)
199{
Ian Rogersb5d09b22012-03-06 22:14:17 -0800200 X86OpCode opcode = kX86Nop;
201 switch (op) {
202 // X86 binary opcodes
203 case kOpSub: opcode = kX86Sub32RM; break;
204 case kOpMov: opcode = kX86Mov32RM; break;
205 case kOpCmp: opcode = kX86Cmp32RM; break;
206 case kOpAdd: opcode = kX86Add32RM; break;
207 case kOpAnd: opcode = kX86And32RM; break;
208 case kOpOr: opcode = kX86Or32RM; break;
209 case kOpXor: opcode = kX86Xor32RM; break;
210 case kOp2Byte: opcode = kX86Movsx8RM; break;
211 case kOp2Short: opcode = kX86Movsx16RM; break;
212 case kOp2Char: opcode = kX86Movzx16RM; break;
213 case kOpMul:
214 default:
buzbee52a77fc2012-11-20 19:50:46 -0800215 LOG(FATAL) << "Bad case in OpRegMem " << op;
Ian Rogersb5d09b22012-03-06 22:14:17 -0800216 break;
217 }
buzbeefa57c472012-11-21 12:06:18 -0800218 return NewLIR3(cu, opcode, r_dest, rBase, offset);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800219}
220
buzbeefa57c472012-11-21 12:06:18 -0800221LIR* OpRegRegReg(CompilationUnit *cu, OpKind op, int r_dest, int r_src1,
222 int r_src2)
Bill Buzbeea114add2012-05-03 15:00:40 -0700223{
buzbeefa57c472012-11-21 12:06:18 -0800224 if (r_dest != r_src1 && r_dest != r_src2) {
Ian Rogersb5d09b22012-03-06 22:14:17 -0800225 if (op == kOpAdd) { // lea special case, except can't encode rbp as base
buzbeefa57c472012-11-21 12:06:18 -0800226 if (r_src1 == r_src2) {
227 OpRegCopy(cu, r_dest, r_src1);
228 return OpRegImm(cu, kOpLsl, r_dest, 1);
229 } else if (r_src1 != rBP) {
230 return NewLIR5(cu, kX86Lea32RA, r_dest, r_src1 /* base */,
231 r_src2 /* index */, 0 /* scale */, 0 /* disp */);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800232 } else {
buzbeefa57c472012-11-21 12:06:18 -0800233 return NewLIR5(cu, kX86Lea32RA, r_dest, r_src2 /* base */,
234 r_src1 /* index */, 0 /* scale */, 0 /* disp */);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800235 }
236 } else {
buzbeefa57c472012-11-21 12:06:18 -0800237 OpRegCopy(cu, r_dest, r_src1);
238 return OpRegReg(cu, op, r_dest, r_src2);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800239 }
buzbeefa57c472012-11-21 12:06:18 -0800240 } else if (r_dest == r_src1) {
241 return OpRegReg(cu, op, r_dest, r_src2);
242 } else { // r_dest == r_src2
Ian Rogersb5d09b22012-03-06 22:14:17 -0800243 switch (op) {
244 case kOpSub: // non-commutative
buzbeefa57c472012-11-21 12:06:18 -0800245 OpReg(cu, kOpNeg, r_dest);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800246 op = kOpAdd;
247 break;
248 case kOpSbc:
249 case kOpLsl: case kOpLsr: case kOpAsr: case kOpRor: {
buzbeefa57c472012-11-21 12:06:18 -0800250 int t_reg = AllocTemp(cu);
251 OpRegCopy(cu, t_reg, r_src1);
252 OpRegReg(cu, op, t_reg, r_src2);
253 LIR* res = OpRegCopy(cu, r_dest, t_reg);
254 FreeTemp(cu, t_reg);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800255 return res;
256 }
257 case kOpAdd: // commutative
258 case kOpOr:
259 case kOpAdc:
260 case kOpAnd:
261 case kOpXor:
262 break;
263 default:
buzbee52a77fc2012-11-20 19:50:46 -0800264 LOG(FATAL) << "Bad case in OpRegRegReg " << op;
Ian Rogersb5d09b22012-03-06 22:14:17 -0800265 }
buzbeefa57c472012-11-21 12:06:18 -0800266 return OpRegReg(cu, op, r_dest, r_src1);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800267 }
268}
269
buzbeefa57c472012-11-21 12:06:18 -0800270LIR* OpRegRegImm(CompilationUnit *cu, OpKind op, int r_dest, int r_src,
Bill Buzbeea114add2012-05-03 15:00:40 -0700271 int value)
272{
Ian Rogersb5d09b22012-03-06 22:14:17 -0800273 if (op == kOpMul) {
274 X86OpCode opcode = IS_SIMM8(value) ? kX86Imul32RRI8 : kX86Imul32RRI;
buzbeefa57c472012-11-21 12:06:18 -0800275 return NewLIR3(cu, opcode, r_dest, r_src, value);
Ian Rogersb41b33b2012-03-20 14:22:54 -0700276 } else if (op == kOpAnd) {
buzbeefa57c472012-11-21 12:06:18 -0800277 if (value == 0xFF && r_src < 4) {
278 return NewLIR2(cu, kX86Movzx8RR, r_dest, r_src);
Ian Rogersb41b33b2012-03-20 14:22:54 -0700279 } else if (value == 0xFFFF) {
buzbeefa57c472012-11-21 12:06:18 -0800280 return NewLIR2(cu, kX86Movzx16RR, r_dest, r_src);
Ian Rogersb41b33b2012-03-20 14:22:54 -0700281 }
Ian Rogersb5d09b22012-03-06 22:14:17 -0800282 }
buzbeefa57c472012-11-21 12:06:18 -0800283 if (r_dest != r_src) {
Ian Rogers7caad772012-03-30 01:07:54 -0700284 if (false && op == kOpLsl && value >= 0 && value <= 3) { // lea shift special case
285 // TODO: fix bug in LEA encoding when disp == 0
buzbeefa57c472012-11-21 12:06:18 -0800286 return NewLIR5(cu, kX86Lea32RA, r_dest, r5sib_no_base /* base */,
287 r_src /* index */, value /* scale */, 0 /* disp */);
Ian Rogersb41b33b2012-03-20 14:22:54 -0700288 } else if (op == kOpAdd) { // lea add special case
buzbeefa57c472012-11-21 12:06:18 -0800289 return NewLIR5(cu, kX86Lea32RA, r_dest, r_src /* base */,
Ian Rogersb5d09b22012-03-06 22:14:17 -0800290 r4sib_no_index /* index */, 0 /* scale */, value /* disp */);
291 }
buzbeefa57c472012-11-21 12:06:18 -0800292 OpRegCopy(cu, r_dest, r_src);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800293 }
buzbeefa57c472012-11-21 12:06:18 -0800294 return OpRegImm(cu, op, r_dest, value);
buzbeee88dfbf2012-03-05 11:19:57 -0800295}
296
buzbeefa57c472012-11-21 12:06:18 -0800297LIR* OpThreadMem(CompilationUnit* cu, OpKind op, int thread_offset)
Bill Buzbeea114add2012-05-03 15:00:40 -0700298{
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700299 X86OpCode opcode = kX86Bkpt;
300 switch (op) {
301 case kOpBlx: opcode = kX86CallT; break;
302 default:
303 LOG(FATAL) << "Bad opcode: " << op;
304 break;
305 }
buzbeefa57c472012-11-21 12:06:18 -0800306 return NewLIR1(cu, opcode, thread_offset);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700307}
308
buzbeefa57c472012-11-21 12:06:18 -0800309LIR* OpMem(CompilationUnit* cu, OpKind op, int rBase, int disp)
Bill Buzbeea114add2012-05-03 15:00:40 -0700310{
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700311 X86OpCode opcode = kX86Bkpt;
312 switch (op) {
313 case kOpBlx: opcode = kX86CallM; break;
314 default:
315 LOG(FATAL) << "Bad opcode: " << op;
316 break;
317 }
buzbeefa57c472012-11-21 12:06:18 -0800318 return NewLIR2(cu, opcode, rBase, disp);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700319}
320
buzbeefa57c472012-11-21 12:06:18 -0800321LIR *LoadConstantValueWide(CompilationUnit *cu, int r_dest_lo,
322 int r_dest_hi, int val_lo, int val_hi)
buzbeee88dfbf2012-03-05 11:19:57 -0800323{
324 LIR *res;
buzbeefa57c472012-11-21 12:06:18 -0800325 if (X86_FPREG(r_dest_lo)) {
326 DCHECK(X86_FPREG(r_dest_hi)); // ignore r_dest_hi
327 if (val_lo == 0 && val_hi == 0) {
328 return NewLIR2(cu, kX86XorpsRR, r_dest_lo, r_dest_lo);
Ian Rogersb41b33b2012-03-20 14:22:54 -0700329 } else {
buzbeefa57c472012-11-21 12:06:18 -0800330 if (val_lo == 0) {
331 res = NewLIR2(cu, kX86XorpsRR, r_dest_lo, r_dest_lo);
Ian Rogersb41b33b2012-03-20 14:22:54 -0700332 } else {
buzbeefa57c472012-11-21 12:06:18 -0800333 res = LoadConstantNoClobber(cu, r_dest_lo, val_lo);
Ian Rogersb41b33b2012-03-20 14:22:54 -0700334 }
buzbeefa57c472012-11-21 12:06:18 -0800335 if (val_hi != 0) {
336 LoadConstantNoClobber(cu, r_dest_hi, val_hi);
337 NewLIR2(cu, kX86PsllqRI, r_dest_hi, 32);
338 NewLIR2(cu, kX86OrpsRR, r_dest_lo, r_dest_hi);
Ian Rogersb41b33b2012-03-20 14:22:54 -0700339 }
340 }
341 } else {
buzbeefa57c472012-11-21 12:06:18 -0800342 res = LoadConstantNoClobber(cu, r_dest_lo, val_lo);
343 LoadConstantNoClobber(cu, r_dest_hi, val_hi);
Ian Rogersb41b33b2012-03-20 14:22:54 -0700344 }
buzbeee88dfbf2012-03-05 11:19:57 -0800345 return res;
346}
347
buzbeefa57c472012-11-21 12:06:18 -0800348LIR *LoadMultiple(CompilationUnit *cu, int rBase, int r_mask)
buzbeee88dfbf2012-03-05 11:19:57 -0800349{
buzbee52a77fc2012-11-20 19:50:46 -0800350 UNIMPLEMENTED(FATAL) << "LoadMultiple";
buzbeefa57c472012-11-21 12:06:18 -0800351 NewLIR0(cu, kX86Bkpt);
Bill Buzbeea114add2012-05-03 15:00:40 -0700352 return NULL;
buzbeee88dfbf2012-03-05 11:19:57 -0800353}
354
buzbeefa57c472012-11-21 12:06:18 -0800355LIR *StoreMultiple(CompilationUnit *cu, int rBase, int r_mask)
buzbeee88dfbf2012-03-05 11:19:57 -0800356{
buzbee52a77fc2012-11-20 19:50:46 -0800357 UNIMPLEMENTED(FATAL) << "StoreMultiple";
buzbeefa57c472012-11-21 12:06:18 -0800358 NewLIR0(cu, kX86Bkpt);
Bill Buzbeea114add2012-05-03 15:00:40 -0700359 return NULL;
buzbeee88dfbf2012-03-05 11:19:57 -0800360}
361
buzbeefa57c472012-11-21 12:06:18 -0800362LIR* LoadBaseIndexedDisp(CompilationUnit *cu, int rBase, int r_index, int scale,
363 int displacement, int r_dest, int r_dest_hi, OpSize size, int s_reg) {
Ian Rogersb5d09b22012-03-06 22:14:17 -0800364 LIR *load = NULL;
365 LIR *load2 = NULL;
buzbeefa57c472012-11-21 12:06:18 -0800366 bool is_array = r_index != INVALID_REG;
Ian Rogersb5d09b22012-03-06 22:14:17 -0800367 bool pair = false;
368 bool is64bit = false;
369 X86OpCode opcode = kX86Nop;
370 switch (size) {
371 case kLong:
372 case kDouble:
373 is64bit = true;
buzbeefa57c472012-11-21 12:06:18 -0800374 if (X86_FPREG(r_dest)) {
375 opcode = is_array ? kX86MovsdRA : kX86MovsdRM;
376 if (X86_SINGLEREG(r_dest)) {
377 DCHECK(X86_FPREG(r_dest_hi));
378 DCHECK_EQ(r_dest, (r_dest_hi - 1));
379 r_dest = S2d(r_dest, r_dest_hi);
buzbeee88dfbf2012-03-05 11:19:57 -0800380 }
buzbeefa57c472012-11-21 12:06:18 -0800381 r_dest_hi = r_dest + 1;
Ian Rogersb5d09b22012-03-06 22:14:17 -0800382 } else {
383 pair = true;
buzbeefa57c472012-11-21 12:06:18 -0800384 opcode = is_array ? kX86Mov32RA : kX86Mov32RM;
Ian Rogersb5d09b22012-03-06 22:14:17 -0800385 }
386 // TODO: double store is to unaligned address
387 DCHECK_EQ((displacement & 0x3), 0);
388 break;
389 case kWord:
390 case kSingle:
buzbeefa57c472012-11-21 12:06:18 -0800391 opcode = is_array ? kX86Mov32RA : kX86Mov32RM;
392 if (X86_FPREG(r_dest)) {
393 opcode = is_array ? kX86MovssRA : kX86MovssRM;
394 DCHECK(X86_SINGLEREG(r_dest));
Ian Rogersb5d09b22012-03-06 22:14:17 -0800395 }
396 DCHECK_EQ((displacement & 0x3), 0);
397 break;
398 case kUnsignedHalf:
buzbeefa57c472012-11-21 12:06:18 -0800399 opcode = is_array ? kX86Movzx16RA : kX86Movzx16RM;
Ian Rogersb5d09b22012-03-06 22:14:17 -0800400 DCHECK_EQ((displacement & 0x1), 0);
401 break;
402 case kSignedHalf:
buzbeefa57c472012-11-21 12:06:18 -0800403 opcode = is_array ? kX86Movsx16RA : kX86Movsx16RM;
Ian Rogersb5d09b22012-03-06 22:14:17 -0800404 DCHECK_EQ((displacement & 0x1), 0);
405 break;
406 case kUnsignedByte:
buzbeefa57c472012-11-21 12:06:18 -0800407 opcode = is_array ? kX86Movzx8RA : kX86Movzx8RM;
Ian Rogersb5d09b22012-03-06 22:14:17 -0800408 break;
409 case kSignedByte:
buzbeefa57c472012-11-21 12:06:18 -0800410 opcode = is_array ? kX86Movsx8RA : kX86Movsx8RM;
Ian Rogersb5d09b22012-03-06 22:14:17 -0800411 break;
412 default:
buzbee52a77fc2012-11-20 19:50:46 -0800413 LOG(FATAL) << "Bad case in LoadBaseIndexedDispBody";
Ian Rogersb5d09b22012-03-06 22:14:17 -0800414 }
415
buzbeefa57c472012-11-21 12:06:18 -0800416 if (!is_array) {
Ian Rogersb5d09b22012-03-06 22:14:17 -0800417 if (!pair) {
buzbeefa57c472012-11-21 12:06:18 -0800418 load = NewLIR3(cu, opcode, r_dest, rBase, displacement + LOWORD_OFFSET);
buzbeee88dfbf2012-03-05 11:19:57 -0800419 } else {
buzbeefa57c472012-11-21 12:06:18 -0800420 if (rBase == r_dest) {
421 load2 = NewLIR3(cu, opcode, r_dest_hi, rBase,
jeffhaofdffdf82012-07-11 16:08:43 -0700422 displacement + HIWORD_OFFSET);
buzbeefa57c472012-11-21 12:06:18 -0800423 load = NewLIR3(cu, opcode, r_dest, rBase, displacement + LOWORD_OFFSET);
jeffhaofdffdf82012-07-11 16:08:43 -0700424 } else {
buzbeefa57c472012-11-21 12:06:18 -0800425 load = NewLIR3(cu, opcode, r_dest, rBase, displacement + LOWORD_OFFSET);
426 load2 = NewLIR3(cu, opcode, r_dest_hi, rBase,
jeffhaofdffdf82012-07-11 16:08:43 -0700427 displacement + HIWORD_OFFSET);
428 }
buzbeee88dfbf2012-03-05 11:19:57 -0800429 }
buzbeef0504cd2012-11-13 16:31:10 -0800430 if (rBase == rX86_SP) {
buzbee52a77fc2012-11-20 19:50:46 -0800431 AnnotateDalvikRegAccess(load, (displacement + (pair ? LOWORD_OFFSET : 0))
buzbeefa57c472012-11-21 12:06:18 -0800432 >> 2, true /* is_load */, is64bit);
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700433 if (pair) {
buzbee52a77fc2012-11-20 19:50:46 -0800434 AnnotateDalvikRegAccess(load2, (displacement + HIWORD_OFFSET) >> 2,
buzbeefa57c472012-11-21 12:06:18 -0800435 true /* is_load */, is64bit);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800436 }
buzbeee88dfbf2012-03-05 11:19:57 -0800437 }
Ian Rogersb5d09b22012-03-06 22:14:17 -0800438 } else {
439 if (!pair) {
buzbeefa57c472012-11-21 12:06:18 -0800440 load = NewLIR5(cu, opcode, r_dest, rBase, r_index, scale,
Bill Buzbeea114add2012-05-03 15:00:40 -0700441 displacement + LOWORD_OFFSET);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800442 } else {
buzbeefa57c472012-11-21 12:06:18 -0800443 if (rBase == r_dest) {
444 load2 = NewLIR5(cu, opcode, r_dest_hi, rBase, r_index, scale,
jeffhaofdffdf82012-07-11 16:08:43 -0700445 displacement + HIWORD_OFFSET);
buzbeefa57c472012-11-21 12:06:18 -0800446 load = NewLIR5(cu, opcode, r_dest, rBase, r_index, scale,
jeffhaofdffdf82012-07-11 16:08:43 -0700447 displacement + LOWORD_OFFSET);
448 } else {
buzbeefa57c472012-11-21 12:06:18 -0800449 load = NewLIR5(cu, opcode, r_dest, rBase, r_index, scale,
jeffhaofdffdf82012-07-11 16:08:43 -0700450 displacement + LOWORD_OFFSET);
buzbeefa57c472012-11-21 12:06:18 -0800451 load2 = NewLIR5(cu, opcode, r_dest_hi, rBase, r_index, scale,
jeffhaofdffdf82012-07-11 16:08:43 -0700452 displacement + HIWORD_OFFSET);
453 }
Ian Rogersb5d09b22012-03-06 22:14:17 -0800454 }
455 }
456
457 return load;
buzbeee88dfbf2012-03-05 11:19:57 -0800458}
459
jeffhao5772bab2012-05-18 11:51:26 -0700460/* Load value from base + scaled index. */
buzbeefa57c472012-11-21 12:06:18 -0800461LIR *LoadBaseIndexed(CompilationUnit *cu, int rBase,
462 int r_index, int r_dest, int scale, OpSize size) {
463 return LoadBaseIndexedDisp(cu, rBase, r_index, scale, 0,
464 r_dest, INVALID_REG, size, INVALID_SREG);
jeffhao5772bab2012-05-18 11:51:26 -0700465}
466
buzbeefa57c472012-11-21 12:06:18 -0800467LIR *LoadBaseDisp(CompilationUnit *cu, int rBase, int displacement,
468 int r_dest, OpSize size, int s_reg) {
469 return LoadBaseIndexedDisp(cu, rBase, INVALID_REG, 0, displacement,
470 r_dest, INVALID_REG, size, s_reg);
buzbeee88dfbf2012-03-05 11:19:57 -0800471}
472
buzbeefa57c472012-11-21 12:06:18 -0800473LIR *LoadBaseDispWide(CompilationUnit *cu, int rBase, int displacement,
474 int r_dest_lo, int r_dest_hi, int s_reg) {
475 return LoadBaseIndexedDisp(cu, rBase, INVALID_REG, 0, displacement,
476 r_dest_lo, r_dest_hi, kLong, s_reg);
buzbeee88dfbf2012-03-05 11:19:57 -0800477}
478
buzbeefa57c472012-11-21 12:06:18 -0800479LIR* StoreBaseIndexedDisp(CompilationUnit *cu, int rBase, int r_index, int scale,
480 int displacement, int r_src, int r_src_hi, OpSize size, int s_reg) {
Ian Rogersb5d09b22012-03-06 22:14:17 -0800481 LIR *store = NULL;
jeffhaoe2962482012-06-28 11:29:57 -0700482 LIR *store2 = NULL;
buzbeefa57c472012-11-21 12:06:18 -0800483 bool is_array = r_index != INVALID_REG;
Ian Rogersb5d09b22012-03-06 22:14:17 -0800484 bool pair = false;
jeffhaoe2962482012-06-28 11:29:57 -0700485 bool is64bit = false;
Ian Rogersb41b33b2012-03-20 14:22:54 -0700486 X86OpCode opcode = kX86Nop;
Ian Rogersb5d09b22012-03-06 22:14:17 -0800487 switch (size) {
488 case kLong:
489 case kDouble:
jeffhaoe2962482012-06-28 11:29:57 -0700490 is64bit = true;
buzbeefa57c472012-11-21 12:06:18 -0800491 if (X86_FPREG(r_src)) {
492 opcode = is_array ? kX86MovsdAR : kX86MovsdMR;
493 if (X86_SINGLEREG(r_src)) {
494 DCHECK(X86_FPREG(r_src_hi));
495 DCHECK_EQ(r_src, (r_src_hi - 1));
496 r_src = S2d(r_src, r_src_hi);
buzbeee88dfbf2012-03-05 11:19:57 -0800497 }
buzbeefa57c472012-11-21 12:06:18 -0800498 r_src_hi = r_src + 1;
Ian Rogersb5d09b22012-03-06 22:14:17 -0800499 } else {
500 pair = true;
buzbeefa57c472012-11-21 12:06:18 -0800501 opcode = is_array ? kX86Mov32AR : kX86Mov32MR;
Ian Rogersb5d09b22012-03-06 22:14:17 -0800502 }
503 // TODO: double store is to unaligned address
504 DCHECK_EQ((displacement & 0x3), 0);
505 break;
506 case kWord:
507 case kSingle:
buzbeefa57c472012-11-21 12:06:18 -0800508 opcode = is_array ? kX86Mov32AR : kX86Mov32MR;
509 if (X86_FPREG(r_src)) {
510 opcode = is_array ? kX86MovssAR : kX86MovssMR;
511 DCHECK(X86_SINGLEREG(r_src));
Ian Rogersb5d09b22012-03-06 22:14:17 -0800512 }
513 DCHECK_EQ((displacement & 0x3), 0);
514 break;
515 case kUnsignedHalf:
516 case kSignedHalf:
buzbeefa57c472012-11-21 12:06:18 -0800517 opcode = is_array ? kX86Mov16AR : kX86Mov16MR;
Ian Rogersb5d09b22012-03-06 22:14:17 -0800518 DCHECK_EQ((displacement & 0x1), 0);
519 break;
520 case kUnsignedByte:
521 case kSignedByte:
buzbeefa57c472012-11-21 12:06:18 -0800522 opcode = is_array ? kX86Mov8AR : kX86Mov8MR;
Ian Rogersb5d09b22012-03-06 22:14:17 -0800523 break;
524 default:
buzbee52a77fc2012-11-20 19:50:46 -0800525 LOG(FATAL) << "Bad case in LoadBaseIndexedDispBody";
Ian Rogersb5d09b22012-03-06 22:14:17 -0800526 }
buzbeee88dfbf2012-03-05 11:19:57 -0800527
buzbeefa57c472012-11-21 12:06:18 -0800528 if (!is_array) {
Ian Rogersb41b33b2012-03-20 14:22:54 -0700529 if (!pair) {
buzbeefa57c472012-11-21 12:06:18 -0800530 store = NewLIR3(cu, opcode, rBase, displacement + LOWORD_OFFSET, r_src);
Ian Rogersb41b33b2012-03-20 14:22:54 -0700531 } else {
buzbeefa57c472012-11-21 12:06:18 -0800532 store = NewLIR3(cu, opcode, rBase, displacement + LOWORD_OFFSET, r_src);
533 store2 = NewLIR3(cu, opcode, rBase, displacement + HIWORD_OFFSET, r_src_hi);
jeffhaoe2962482012-06-28 11:29:57 -0700534 }
buzbeef0504cd2012-11-13 16:31:10 -0800535 if (rBase == rX86_SP) {
buzbee52a77fc2012-11-20 19:50:46 -0800536 AnnotateDalvikRegAccess(store, (displacement + (pair ? LOWORD_OFFSET : 0))
buzbeefa57c472012-11-21 12:06:18 -0800537 >> 2, false /* is_load */, is64bit);
jeffhaoe2962482012-06-28 11:29:57 -0700538 if (pair) {
buzbee52a77fc2012-11-20 19:50:46 -0800539 AnnotateDalvikRegAccess(store2, (displacement + HIWORD_OFFSET) >> 2,
buzbeefa57c472012-11-21 12:06:18 -0800540 false /* is_load */, is64bit);
jeffhaoe2962482012-06-28 11:29:57 -0700541 }
Ian Rogersb41b33b2012-03-20 14:22:54 -0700542 }
Ian Rogersb5d09b22012-03-06 22:14:17 -0800543 } else {
Ian Rogersb41b33b2012-03-20 14:22:54 -0700544 if (!pair) {
buzbeefa57c472012-11-21 12:06:18 -0800545 store = NewLIR5(cu, opcode, rBase, r_index, scale,
546 displacement + LOWORD_OFFSET, r_src);
Ian Rogersb41b33b2012-03-20 14:22:54 -0700547 } else {
buzbeefa57c472012-11-21 12:06:18 -0800548 store = NewLIR5(cu, opcode, rBase, r_index, scale,
549 displacement + LOWORD_OFFSET, r_src);
550 store2 = NewLIR5(cu, opcode, rBase, r_index, scale,
551 displacement + HIWORD_OFFSET, r_src_hi);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800552 }
553 }
Ian Rogersb41b33b2012-03-20 14:22:54 -0700554
555 return store;
buzbeee88dfbf2012-03-05 11:19:57 -0800556}
557
Ian Rogersc6f3bb82012-03-21 20:40:33 -0700558/* store value base base + scaled index. */
buzbeefa57c472012-11-21 12:06:18 -0800559LIR *StoreBaseIndexed(CompilationUnit *cu, int rBase, int r_index, int r_src,
Bill Buzbeea114add2012-05-03 15:00:40 -0700560 int scale, OpSize size)
Ian Rogersc6f3bb82012-03-21 20:40:33 -0700561{
buzbeefa57c472012-11-21 12:06:18 -0800562 return StoreBaseIndexedDisp(cu, rBase, r_index, scale, 0,
563 r_src, INVALID_REG, size, INVALID_SREG);
Ian Rogersc6f3bb82012-03-21 20:40:33 -0700564}
565
buzbeefa57c472012-11-21 12:06:18 -0800566LIR *StoreBaseDisp(CompilationUnit *cu, int rBase, int displacement,
567 int r_src, OpSize size)
Bill Buzbeea114add2012-05-03 15:00:40 -0700568{
buzbeefa57c472012-11-21 12:06:18 -0800569 return StoreBaseIndexedDisp(cu, rBase, INVALID_REG, 0,
570 displacement, r_src, INVALID_REG, size,
Bill Buzbeea114add2012-05-03 15:00:40 -0700571 INVALID_SREG);
buzbeee88dfbf2012-03-05 11:19:57 -0800572}
573
buzbeefa57c472012-11-21 12:06:18 -0800574LIR *StoreBaseDispWide(CompilationUnit *cu, int rBase, int displacement,
575 int r_src_lo, int r_src_hi)
Bill Buzbeea114add2012-05-03 15:00:40 -0700576{
buzbeefa57c472012-11-21 12:06:18 -0800577 return StoreBaseIndexedDisp(cu, rBase, INVALID_REG, 0, displacement,
578 r_src_lo, r_src_hi, kLong, INVALID_SREG);
buzbeee88dfbf2012-03-05 11:19:57 -0800579}
580
buzbeefa57c472012-11-21 12:06:18 -0800581void LoadPair(CompilationUnit *cu, int base, int low_reg, int high_reg)
buzbeee88dfbf2012-03-05 11:19:57 -0800582{
buzbeefa57c472012-11-21 12:06:18 -0800583 LoadBaseDispWide(cu, base, 0, low_reg, high_reg, INVALID_SREG);
buzbeee88dfbf2012-03-05 11:19:57 -0800584}
585
586} // namespace art