blob: 1731703a3f4575c261b4da20cc10849a9addd349 [file] [log] [blame]
Brian Carlstrom7940e442013-07-12 13:46:57 -07001/*
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 "codegen_x86.h"
18#include "dex/quick/mir_to_lir-inl.h"
19#include "x86_lir.h"
20
21namespace art {
22
23void X86Mir2Lir::GenArithOpFloat(Instruction::Code opcode,
24 RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) {
25 X86OpCode op = kX86Nop;
26 RegLocation rl_result;
27
28 /*
29 * Don't attempt to optimize register usage since these opcodes call out to
30 * the handlers.
31 */
32 switch (opcode) {
33 case Instruction::ADD_FLOAT_2ADDR:
34 case Instruction::ADD_FLOAT:
35 op = kX86AddssRR;
36 break;
37 case Instruction::SUB_FLOAT_2ADDR:
38 case Instruction::SUB_FLOAT:
39 op = kX86SubssRR;
40 break;
41 case Instruction::DIV_FLOAT_2ADDR:
42 case Instruction::DIV_FLOAT:
43 op = kX86DivssRR;
44 break;
45 case Instruction::MUL_FLOAT_2ADDR:
46 case Instruction::MUL_FLOAT:
47 op = kX86MulssRR;
48 break;
49 case Instruction::REM_FLOAT_2ADDR:
50 case Instruction::REM_FLOAT:
51 FlushAllRegs(); // Send everything to home location
Ian Rogers7655f292013-07-29 11:07:13 -070052 CallRuntimeHelperRegLocationRegLocation(QUICK_ENTRYPOINT_OFFSET(pFmodf), rl_src1, rl_src2,
53 false);
Brian Carlstrom7940e442013-07-12 13:46:57 -070054 rl_result = GetReturn(true);
55 StoreValue(rl_dest, rl_result);
56 return;
57 case Instruction::NEG_FLOAT:
58 GenNegFloat(rl_dest, rl_src1);
59 return;
60 default:
61 LOG(FATAL) << "Unexpected opcode: " << opcode;
62 }
63 rl_src1 = LoadValue(rl_src1, kFPReg);
64 rl_src2 = LoadValue(rl_src2, kFPReg);
65 rl_result = EvalLoc(rl_dest, kFPReg, true);
66 int r_dest = rl_result.low_reg;
67 int r_src1 = rl_src1.low_reg;
68 int r_src2 = rl_src2.low_reg;
69 if (r_dest == r_src2) {
70 r_src2 = AllocTempFloat();
71 OpRegCopy(r_src2, r_dest);
72 }
73 OpRegCopy(r_dest, r_src1);
74 NewLIR2(op, r_dest, r_src2);
75 StoreValue(rl_dest, rl_result);
76}
77
78void X86Mir2Lir::GenArithOpDouble(Instruction::Code opcode,
79 RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) {
80 X86OpCode op = kX86Nop;
81 RegLocation rl_result;
82
83 switch (opcode) {
84 case Instruction::ADD_DOUBLE_2ADDR:
85 case Instruction::ADD_DOUBLE:
86 op = kX86AddsdRR;
87 break;
88 case Instruction::SUB_DOUBLE_2ADDR:
89 case Instruction::SUB_DOUBLE:
90 op = kX86SubsdRR;
91 break;
92 case Instruction::DIV_DOUBLE_2ADDR:
93 case Instruction::DIV_DOUBLE:
94 op = kX86DivsdRR;
95 break;
96 case Instruction::MUL_DOUBLE_2ADDR:
97 case Instruction::MUL_DOUBLE:
98 op = kX86MulsdRR;
99 break;
100 case Instruction::REM_DOUBLE_2ADDR:
101 case Instruction::REM_DOUBLE:
102 FlushAllRegs(); // Send everything to home location
Ian Rogers7655f292013-07-29 11:07:13 -0700103 CallRuntimeHelperRegLocationRegLocation(QUICK_ENTRYPOINT_OFFSET(pFmod), rl_src1, rl_src2,
104 false);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700105 rl_result = GetReturnWide(true);
106 StoreValueWide(rl_dest, rl_result);
107 return;
108 case Instruction::NEG_DOUBLE:
109 GenNegDouble(rl_dest, rl_src1);
110 return;
111 default:
112 LOG(FATAL) << "Unexpected opcode: " << opcode;
113 }
114 rl_src1 = LoadValueWide(rl_src1, kFPReg);
115 DCHECK(rl_src1.wide);
116 rl_src2 = LoadValueWide(rl_src2, kFPReg);
117 DCHECK(rl_src2.wide);
118 rl_result = EvalLoc(rl_dest, kFPReg, true);
119 DCHECK(rl_dest.wide);
120 DCHECK(rl_result.wide);
121 int r_dest = S2d(rl_result.low_reg, rl_result.high_reg);
122 int r_src1 = S2d(rl_src1.low_reg, rl_src1.high_reg);
123 int r_src2 = S2d(rl_src2.low_reg, rl_src2.high_reg);
124 if (r_dest == r_src2) {
125 r_src2 = AllocTempDouble() | X86_FP_DOUBLE;
126 OpRegCopy(r_src2, r_dest);
127 }
128 OpRegCopy(r_dest, r_src1);
129 NewLIR2(op, r_dest, r_src2);
130 StoreValueWide(rl_dest, rl_result);
131}
132
133void X86Mir2Lir::GenConversion(Instruction::Code opcode, RegLocation rl_dest,
134 RegLocation rl_src) {
135 RegisterClass rcSrc = kFPReg;
136 X86OpCode op = kX86Nop;
137 int src_reg;
138 RegLocation rl_result;
139 switch (opcode) {
140 case Instruction::INT_TO_FLOAT:
141 rcSrc = kCoreReg;
142 op = kX86Cvtsi2ssRR;
143 break;
144 case Instruction::DOUBLE_TO_FLOAT:
145 rcSrc = kFPReg;
146 op = kX86Cvtsd2ssRR;
147 break;
148 case Instruction::FLOAT_TO_DOUBLE:
149 rcSrc = kFPReg;
150 op = kX86Cvtss2sdRR;
151 break;
152 case Instruction::INT_TO_DOUBLE:
153 rcSrc = kCoreReg;
154 op = kX86Cvtsi2sdRR;
155 break;
156 case Instruction::FLOAT_TO_INT: {
157 rl_src = LoadValue(rl_src, kFPReg);
158 src_reg = rl_src.low_reg;
159 // In case result vreg is also src vreg, break association to avoid useless copy by EvalLoc()
160 ClobberSReg(rl_dest.s_reg_low);
161 rl_result = EvalLoc(rl_dest, kCoreReg, true);
162 int temp_reg = AllocTempFloat();
163
164 LoadConstant(rl_result.low_reg, 0x7fffffff);
165 NewLIR2(kX86Cvtsi2ssRR, temp_reg, rl_result.low_reg);
166 NewLIR2(kX86ComissRR, src_reg, temp_reg);
167 LIR* branch_pos_overflow = NewLIR2(kX86Jcc8, 0, kX86CondA);
168 LIR* branch_na_n = NewLIR2(kX86Jcc8, 0, kX86CondP);
169 NewLIR2(kX86Cvttss2siRR, rl_result.low_reg, src_reg);
170 LIR* branch_normal = NewLIR1(kX86Jmp8, 0);
171 branch_na_n->target = NewLIR0(kPseudoTargetLabel);
172 NewLIR2(kX86Xor32RR, rl_result.low_reg, rl_result.low_reg);
173 branch_pos_overflow->target = NewLIR0(kPseudoTargetLabel);
174 branch_normal->target = NewLIR0(kPseudoTargetLabel);
175 StoreValue(rl_dest, rl_result);
176 return;
177 }
178 case Instruction::DOUBLE_TO_INT: {
179 rl_src = LoadValueWide(rl_src, kFPReg);
180 src_reg = rl_src.low_reg;
181 // In case result vreg is also src vreg, break association to avoid useless copy by EvalLoc()
182 ClobberSReg(rl_dest.s_reg_low);
183 rl_result = EvalLoc(rl_dest, kCoreReg, true);
184 int temp_reg = AllocTempDouble() | X86_FP_DOUBLE;
185
186 LoadConstant(rl_result.low_reg, 0x7fffffff);
187 NewLIR2(kX86Cvtsi2sdRR, temp_reg, rl_result.low_reg);
188 NewLIR2(kX86ComisdRR, src_reg, temp_reg);
189 LIR* branch_pos_overflow = NewLIR2(kX86Jcc8, 0, kX86CondA);
190 LIR* branch_na_n = NewLIR2(kX86Jcc8, 0, kX86CondP);
191 NewLIR2(kX86Cvttsd2siRR, rl_result.low_reg, src_reg);
192 LIR* branch_normal = NewLIR1(kX86Jmp8, 0);
193 branch_na_n->target = NewLIR0(kPseudoTargetLabel);
194 NewLIR2(kX86Xor32RR, rl_result.low_reg, rl_result.low_reg);
195 branch_pos_overflow->target = NewLIR0(kPseudoTargetLabel);
196 branch_normal->target = NewLIR0(kPseudoTargetLabel);
197 StoreValue(rl_dest, rl_result);
198 return;
199 }
200 case Instruction::LONG_TO_DOUBLE:
Ian Rogers7655f292013-07-29 11:07:13 -0700201 GenConversionCall(QUICK_ENTRYPOINT_OFFSET(pL2d), rl_dest, rl_src);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700202 return;
203 case Instruction::LONG_TO_FLOAT:
204 // TODO: inline by using memory as a 64-bit source. Be careful about promoted registers.
Ian Rogers7655f292013-07-29 11:07:13 -0700205 GenConversionCall(QUICK_ENTRYPOINT_OFFSET(pL2f), rl_dest, rl_src);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700206 return;
207 case Instruction::FLOAT_TO_LONG:
Ian Rogers7655f292013-07-29 11:07:13 -0700208 GenConversionCall(QUICK_ENTRYPOINT_OFFSET(pF2l), rl_dest, rl_src);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700209 return;
210 case Instruction::DOUBLE_TO_LONG:
Ian Rogers7655f292013-07-29 11:07:13 -0700211 GenConversionCall(QUICK_ENTRYPOINT_OFFSET(pD2l), rl_dest, rl_src);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700212 return;
213 default:
214 LOG(INFO) << "Unexpected opcode: " << opcode;
215 }
216 if (rl_src.wide) {
217 rl_src = LoadValueWide(rl_src, rcSrc);
218 src_reg = S2d(rl_src.low_reg, rl_src.high_reg);
219 } else {
220 rl_src = LoadValue(rl_src, rcSrc);
221 src_reg = rl_src.low_reg;
222 }
223 if (rl_dest.wide) {
224 rl_result = EvalLoc(rl_dest, kFPReg, true);
225 NewLIR2(op, S2d(rl_result.low_reg, rl_result.high_reg), src_reg);
226 StoreValueWide(rl_dest, rl_result);
227 } else {
228 rl_result = EvalLoc(rl_dest, kFPReg, true);
229 NewLIR2(op, rl_result.low_reg, src_reg);
230 StoreValue(rl_dest, rl_result);
231 }
232}
233
234void X86Mir2Lir::GenCmpFP(Instruction::Code code, RegLocation rl_dest,
235 RegLocation rl_src1, RegLocation rl_src2) {
236 bool single = (code == Instruction::CMPL_FLOAT) || (code == Instruction::CMPG_FLOAT);
237 bool unordered_gt = (code == Instruction::CMPG_DOUBLE) || (code == Instruction::CMPG_FLOAT);
238 int src_reg1;
239 int src_reg2;
240 if (single) {
241 rl_src1 = LoadValue(rl_src1, kFPReg);
242 src_reg1 = rl_src1.low_reg;
243 rl_src2 = LoadValue(rl_src2, kFPReg);
244 src_reg2 = rl_src2.low_reg;
245 } else {
246 rl_src1 = LoadValueWide(rl_src1, kFPReg);
247 src_reg1 = S2d(rl_src1.low_reg, rl_src1.high_reg);
248 rl_src2 = LoadValueWide(rl_src2, kFPReg);
249 src_reg2 = S2d(rl_src2.low_reg, rl_src2.high_reg);
250 }
251 // In case result vreg is also src vreg, break association to avoid useless copy by EvalLoc()
252 ClobberSReg(rl_dest.s_reg_low);
253 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
254 LoadConstantNoClobber(rl_result.low_reg, unordered_gt ? 1 : 0);
255 if (single) {
256 NewLIR2(kX86UcomissRR, src_reg1, src_reg2);
257 } else {
258 NewLIR2(kX86UcomisdRR, src_reg1, src_reg2);
259 }
260 LIR* branch = NULL;
261 if (unordered_gt) {
262 branch = NewLIR2(kX86Jcc8, 0, kX86CondPE);
263 }
264 // If the result reg can't be byte accessed, use a jump and move instead of a set.
265 if (rl_result.low_reg >= 4) {
266 LIR* branch2 = NULL;
267 if (unordered_gt) {
268 branch2 = NewLIR2(kX86Jcc8, 0, kX86CondA);
269 NewLIR2(kX86Mov32RI, rl_result.low_reg, 0x0);
270 } else {
271 branch2 = NewLIR2(kX86Jcc8, 0, kX86CondBe);
272 NewLIR2(kX86Mov32RI, rl_result.low_reg, 0x1);
273 }
274 branch2->target = NewLIR0(kPseudoTargetLabel);
275 } else {
276 NewLIR2(kX86Set8R, rl_result.low_reg, kX86CondA /* above - unsigned > */);
277 }
278 NewLIR2(kX86Sbb32RI, rl_result.low_reg, 0);
279 if (unordered_gt) {
280 branch->target = NewLIR0(kPseudoTargetLabel);
281 }
282 StoreValue(rl_dest, rl_result);
283}
284
285void X86Mir2Lir::GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias,
286 bool is_double) {
buzbee0d829482013-10-11 15:24:55 -0700287 LIR* taken = &block_label_list_[bb->taken];
288 LIR* not_taken = &block_label_list_[bb->fall_through];
Brian Carlstrom7940e442013-07-12 13:46:57 -0700289 LIR* branch = NULL;
290 RegLocation rl_src1;
291 RegLocation rl_src2;
292 if (is_double) {
293 rl_src1 = mir_graph_->GetSrcWide(mir, 0);
294 rl_src2 = mir_graph_->GetSrcWide(mir, 2);
295 rl_src1 = LoadValueWide(rl_src1, kFPReg);
296 rl_src2 = LoadValueWide(rl_src2, kFPReg);
297 NewLIR2(kX86UcomisdRR, S2d(rl_src1.low_reg, rl_src1.high_reg),
298 S2d(rl_src2.low_reg, rl_src2.high_reg));
299 } else {
300 rl_src1 = mir_graph_->GetSrc(mir, 0);
301 rl_src2 = mir_graph_->GetSrc(mir, 1);
302 rl_src1 = LoadValue(rl_src1, kFPReg);
303 rl_src2 = LoadValue(rl_src2, kFPReg);
304 NewLIR2(kX86UcomissRR, rl_src1.low_reg, rl_src2.low_reg);
305 }
306 ConditionCode ccode = static_cast<ConditionCode>(mir->dalvikInsn.arg[0]);
307 switch (ccode) {
308 case kCondEq:
309 if (!gt_bias) {
310 branch = NewLIR2(kX86Jcc8, 0, kX86CondPE);
311 branch->target = not_taken;
312 }
313 break;
314 case kCondNe:
315 if (!gt_bias) {
316 branch = NewLIR2(kX86Jcc8, 0, kX86CondPE);
317 branch->target = taken;
318 }
319 break;
320 case kCondLt:
321 if (gt_bias) {
322 branch = NewLIR2(kX86Jcc8, 0, kX86CondPE);
323 branch->target = not_taken;
324 }
325 ccode = kCondCs;
326 break;
327 case kCondLe:
328 if (gt_bias) {
329 branch = NewLIR2(kX86Jcc8, 0, kX86CondPE);
330 branch->target = not_taken;
331 }
332 ccode = kCondLs;
333 break;
334 case kCondGt:
335 if (gt_bias) {
336 branch = NewLIR2(kX86Jcc8, 0, kX86CondPE);
337 branch->target = taken;
338 }
339 ccode = kCondHi;
340 break;
341 case kCondGe:
342 if (gt_bias) {
343 branch = NewLIR2(kX86Jcc8, 0, kX86CondPE);
344 branch->target = taken;
345 }
346 ccode = kCondCc;
347 break;
348 default:
349 LOG(FATAL) << "Unexpected ccode: " << ccode;
350 }
351 OpCondBranch(ccode, taken);
352}
353
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700354void X86Mir2Lir::GenNegFloat(RegLocation rl_dest, RegLocation rl_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700355 RegLocation rl_result;
356 rl_src = LoadValue(rl_src, kCoreReg);
357 rl_result = EvalLoc(rl_dest, kCoreReg, true);
358 OpRegRegImm(kOpAdd, rl_result.low_reg, rl_src.low_reg, 0x80000000);
359 StoreValue(rl_dest, rl_result);
360}
361
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700362void X86Mir2Lir::GenNegDouble(RegLocation rl_dest, RegLocation rl_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700363 RegLocation rl_result;
364 rl_src = LoadValueWide(rl_src, kCoreReg);
365 rl_result = EvalLoc(rl_dest, kCoreReg, true);
366 OpRegRegImm(kOpAdd, rl_result.high_reg, rl_src.high_reg, 0x80000000);
367 OpRegCopy(rl_result.low_reg, rl_src.low_reg);
368 StoreValueWide(rl_dest, rl_result);
369}
370
371bool X86Mir2Lir::GenInlinedSqrt(CallInfo* info) {
Mark Mendellbff1ef02013-12-13 13:47:34 -0800372 RegLocation rl_src = info->args[0];
373 RegLocation rl_dest = InlineTargetWide(info); // double place for result
374 rl_src = LoadValueWide(rl_src, kFPReg);
375 RegLocation rl_result = EvalLoc(rl_dest, kFPReg, true);
376 NewLIR2(kX86SqrtsdRR, S2d(rl_result.low_reg, rl_result.high_reg),
377 S2d(rl_src.low_reg, rl_src.high_reg));
378 StoreValueWide(rl_dest, rl_result);
379 return true;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700380}
381
382
383
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700384} // namespace art