blob: c3580f76ae05e5b3b7e8977cfd7a10dc7de56126 [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
Dmitry Petrochenko9ee801f2014-05-12 11:31:37 +070052 if (Is64BitInstructionSet(cu_->instruction_set)) {
53 CallRuntimeHelperRegLocationRegLocation(QUICK_ENTRYPOINT_OFFSET(8, pFmodf), rl_src1, rl_src2,
54 false);
55 } else {
56 CallRuntimeHelperRegLocationRegLocation(QUICK_ENTRYPOINT_OFFSET(4, pFmodf), rl_src1, rl_src2,
57 false);
58 }
buzbeea0cd2d72014-06-01 09:33:49 -070059 rl_result = GetReturn(kFPReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -070060 StoreValue(rl_dest, rl_result);
61 return;
62 case Instruction::NEG_FLOAT:
63 GenNegFloat(rl_dest, rl_src1);
64 return;
65 default:
66 LOG(FATAL) << "Unexpected opcode: " << opcode;
67 }
68 rl_src1 = LoadValue(rl_src1, kFPReg);
69 rl_src2 = LoadValue(rl_src2, kFPReg);
70 rl_result = EvalLoc(rl_dest, kFPReg, true);
buzbee2700f7e2014-03-07 09:46:20 -080071 RegStorage r_dest = rl_result.reg;
72 RegStorage r_src1 = rl_src1.reg;
73 RegStorage r_src2 = rl_src2.reg;
Brian Carlstrom7940e442013-07-12 13:46:57 -070074 if (r_dest == r_src2) {
buzbee091cc402014-03-31 10:14:40 -070075 r_src2 = AllocTempSingle();
Brian Carlstrom7940e442013-07-12 13:46:57 -070076 OpRegCopy(r_src2, r_dest);
77 }
78 OpRegCopy(r_dest, r_src1);
buzbee2700f7e2014-03-07 09:46:20 -080079 NewLIR2(op, r_dest.GetReg(), r_src2.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -070080 StoreValue(rl_dest, rl_result);
81}
82
83void X86Mir2Lir::GenArithOpDouble(Instruction::Code opcode,
84 RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) {
buzbee091cc402014-03-31 10:14:40 -070085 DCHECK(rl_dest.wide);
86 DCHECK(rl_dest.fp);
87 DCHECK(rl_src1.wide);
88 DCHECK(rl_src1.fp);
89 DCHECK(rl_src2.wide);
90 DCHECK(rl_src2.fp);
Brian Carlstrom7940e442013-07-12 13:46:57 -070091 X86OpCode op = kX86Nop;
92 RegLocation rl_result;
93
94 switch (opcode) {
95 case Instruction::ADD_DOUBLE_2ADDR:
96 case Instruction::ADD_DOUBLE:
97 op = kX86AddsdRR;
98 break;
99 case Instruction::SUB_DOUBLE_2ADDR:
100 case Instruction::SUB_DOUBLE:
101 op = kX86SubsdRR;
102 break;
103 case Instruction::DIV_DOUBLE_2ADDR:
104 case Instruction::DIV_DOUBLE:
105 op = kX86DivsdRR;
106 break;
107 case Instruction::MUL_DOUBLE_2ADDR:
108 case Instruction::MUL_DOUBLE:
109 op = kX86MulsdRR;
110 break;
111 case Instruction::REM_DOUBLE_2ADDR:
112 case Instruction::REM_DOUBLE:
113 FlushAllRegs(); // Send everything to home location
Dmitry Petrochenko9ee801f2014-05-12 11:31:37 +0700114 if (Is64BitInstructionSet(cu_->instruction_set)) {
115 CallRuntimeHelperRegLocationRegLocation(QUICK_ENTRYPOINT_OFFSET(8, pFmod), rl_src1, rl_src2,
116 false);
117 } else {
118 CallRuntimeHelperRegLocationRegLocation(QUICK_ENTRYPOINT_OFFSET(4, pFmod), rl_src1, rl_src2,
119 false);
120 }
buzbeea0cd2d72014-06-01 09:33:49 -0700121 rl_result = GetReturnWide(kFPReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700122 StoreValueWide(rl_dest, rl_result);
123 return;
124 case Instruction::NEG_DOUBLE:
125 GenNegDouble(rl_dest, rl_src1);
126 return;
127 default:
128 LOG(FATAL) << "Unexpected opcode: " << opcode;
129 }
130 rl_src1 = LoadValueWide(rl_src1, kFPReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700131 rl_src2 = LoadValueWide(rl_src2, kFPReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700132 rl_result = EvalLoc(rl_dest, kFPReg, true);
buzbee091cc402014-03-31 10:14:40 -0700133 if (rl_result.reg == rl_src2.reg) {
134 rl_src2.reg = AllocTempDouble();
135 OpRegCopy(rl_src2.reg, rl_result.reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700136 }
buzbee091cc402014-03-31 10:14:40 -0700137 OpRegCopy(rl_result.reg, rl_src1.reg);
138 NewLIR2(op, rl_result.reg.GetReg(), rl_src2.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700139 StoreValueWide(rl_dest, rl_result);
140}
141
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800142void X86Mir2Lir::GenLongToFP(RegLocation rl_dest, RegLocation rl_src, bool is_double) {
143 // Compute offsets to the source and destination VRs on stack
144 int src_v_reg_offset = SRegOffset(rl_src.s_reg_low);
145 int dest_v_reg_offset = SRegOffset(rl_dest.s_reg_low);
146
147 // Update the in-register state of source.
148 rl_src = UpdateLocWide(rl_src);
149
150 // If the source is in physical register, then put it in its location on stack.
151 if (rl_src.location == kLocPhysReg) {
buzbee091cc402014-03-31 10:14:40 -0700152 RegisterInfo* reg_info = GetRegInfo(rl_src.reg);
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800153
buzbee091cc402014-03-31 10:14:40 -0700154 if (reg_info != nullptr && reg_info->IsTemp()) {
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800155 // Calling FlushSpecificReg because it will only write back VR if it is dirty.
buzbee091cc402014-03-31 10:14:40 -0700156 FlushSpecificReg(reg_info);
157 // ResetDef to prevent NullifyRange from removing stores.
158 ResetDef(rl_src.reg);
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800159 } else {
160 // It must have been register promoted if it is not a temp but is still in physical
161 // register. Since we need it to be in memory to convert, we place it there now.
Vladimir Marko455759b2014-05-06 20:49:36 +0100162 StoreBaseDisp(TargetReg(kSp), src_v_reg_offset, rl_src.reg, k64);
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800163 }
164 }
165
166 // Push the source virtual register onto the x87 stack.
buzbee091cc402014-03-31 10:14:40 -0700167 LIR *fild64 = NewLIR2NoDest(kX86Fild64M, TargetReg(kSp).GetReg(),
168 src_v_reg_offset + LOWORD_OFFSET);
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800169 AnnotateDalvikRegAccess(fild64, (src_v_reg_offset + LOWORD_OFFSET) >> 2,
buzbee091cc402014-03-31 10:14:40 -0700170 true /* is_load */, true /* is64bit */);
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800171
172 // Now pop off x87 stack and store it in the destination VR's stack location.
173 int opcode = is_double ? kX86Fstp64M : kX86Fstp32M;
174 int displacement = is_double ? dest_v_reg_offset + LOWORD_OFFSET : dest_v_reg_offset;
buzbee2700f7e2014-03-07 09:46:20 -0800175 LIR *fstp = NewLIR2NoDest(opcode, TargetReg(kSp).GetReg(), displacement);
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800176 AnnotateDalvikRegAccess(fstp, displacement >> 2, false /* is_load */, is_double);
177
178 /*
179 * The result is in a physical register if it was in a temp or was register
180 * promoted. For that reason it is enough to check if it is in physical
181 * register. If it is, then we must do all of the bookkeeping necessary to
182 * invalidate temp (if needed) and load in promoted register (if needed).
183 * If the result's location is in memory, then we do not need to do anything
184 * more since the fstp has already placed the correct value in memory.
185 */
buzbee30adc732014-05-09 15:10:18 -0700186 RegLocation rl_result = is_double ? UpdateLocWideTyped(rl_dest, kFPReg) :
187 UpdateLocTyped(rl_dest, kFPReg);
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800188 if (rl_result.location == kLocPhysReg) {
189 /*
190 * We already know that the result is in a physical register but do not know if it is the
191 * right class. So we call EvalLoc(Wide) first which will ensure that it will get moved to the
192 * correct register class.
193 */
194 if (is_double) {
195 rl_result = EvalLocWide(rl_dest, kFPReg, true);
196
Vladimir Marko3bf7c602014-05-07 14:55:43 +0100197 LoadBaseDisp(TargetReg(kSp), dest_v_reg_offset, rl_result.reg, k64);
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800198
Maxim Kazantsev51a80d72014-03-06 11:33:26 +0700199 StoreFinalValueWide(rl_dest, rl_result);
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800200 } else {
201 rl_result = EvalLoc(rl_dest, kFPReg, true);
202
buzbee695d13a2014-04-19 13:32:20 -0700203 Load32Disp(TargetReg(kSp), dest_v_reg_offset, rl_result.reg);
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800204
Maxim Kazantsev51a80d72014-03-06 11:33:26 +0700205 StoreFinalValue(rl_dest, rl_result);
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800206 }
207 }
208}
209
Brian Carlstrom7940e442013-07-12 13:46:57 -0700210void X86Mir2Lir::GenConversion(Instruction::Code opcode, RegLocation rl_dest,
211 RegLocation rl_src) {
212 RegisterClass rcSrc = kFPReg;
213 X86OpCode op = kX86Nop;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700214 RegLocation rl_result;
215 switch (opcode) {
216 case Instruction::INT_TO_FLOAT:
217 rcSrc = kCoreReg;
218 op = kX86Cvtsi2ssRR;
219 break;
220 case Instruction::DOUBLE_TO_FLOAT:
221 rcSrc = kFPReg;
222 op = kX86Cvtsd2ssRR;
223 break;
224 case Instruction::FLOAT_TO_DOUBLE:
225 rcSrc = kFPReg;
226 op = kX86Cvtss2sdRR;
227 break;
228 case Instruction::INT_TO_DOUBLE:
229 rcSrc = kCoreReg;
230 op = kX86Cvtsi2sdRR;
231 break;
232 case Instruction::FLOAT_TO_INT: {
233 rl_src = LoadValue(rl_src, kFPReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700234 // In case result vreg is also src vreg, break association to avoid useless copy by EvalLoc()
235 ClobberSReg(rl_dest.s_reg_low);
236 rl_result = EvalLoc(rl_dest, kCoreReg, true);
buzbee091cc402014-03-31 10:14:40 -0700237 RegStorage temp_reg = AllocTempSingle();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700238
buzbee2700f7e2014-03-07 09:46:20 -0800239 LoadConstant(rl_result.reg, 0x7fffffff);
buzbee091cc402014-03-31 10:14:40 -0700240 NewLIR2(kX86Cvtsi2ssRR, temp_reg.GetReg(), rl_result.reg.GetReg());
241 NewLIR2(kX86ComissRR, rl_src.reg.GetReg(), temp_reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700242 LIR* branch_pos_overflow = NewLIR2(kX86Jcc8, 0, kX86CondA);
243 LIR* branch_na_n = NewLIR2(kX86Jcc8, 0, kX86CondP);
buzbee091cc402014-03-31 10:14:40 -0700244 NewLIR2(kX86Cvttss2siRR, rl_result.reg.GetReg(), rl_src.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700245 LIR* branch_normal = NewLIR1(kX86Jmp8, 0);
246 branch_na_n->target = NewLIR0(kPseudoTargetLabel);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000247 NewLIR2(kX86Xor32RR, rl_result.reg.GetReg(), rl_result.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700248 branch_pos_overflow->target = NewLIR0(kPseudoTargetLabel);
249 branch_normal->target = NewLIR0(kPseudoTargetLabel);
250 StoreValue(rl_dest, rl_result);
251 return;
252 }
253 case Instruction::DOUBLE_TO_INT: {
254 rl_src = LoadValueWide(rl_src, kFPReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700255 // In case result vreg is also src vreg, break association to avoid useless copy by EvalLoc()
256 ClobberSReg(rl_dest.s_reg_low);
257 rl_result = EvalLoc(rl_dest, kCoreReg, true);
buzbee091cc402014-03-31 10:14:40 -0700258 RegStorage temp_reg = AllocTempDouble();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700259
buzbee2700f7e2014-03-07 09:46:20 -0800260 LoadConstant(rl_result.reg, 0x7fffffff);
buzbee091cc402014-03-31 10:14:40 -0700261 NewLIR2(kX86Cvtsi2sdRR, temp_reg.GetReg(), rl_result.reg.GetReg());
262 NewLIR2(kX86ComisdRR, rl_src.reg.GetReg(), temp_reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700263 LIR* branch_pos_overflow = NewLIR2(kX86Jcc8, 0, kX86CondA);
264 LIR* branch_na_n = NewLIR2(kX86Jcc8, 0, kX86CondP);
buzbee091cc402014-03-31 10:14:40 -0700265 NewLIR2(kX86Cvttsd2siRR, rl_result.reg.GetReg(), rl_src.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700266 LIR* branch_normal = NewLIR1(kX86Jmp8, 0);
267 branch_na_n->target = NewLIR0(kPseudoTargetLabel);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000268 NewLIR2(kX86Xor32RR, rl_result.reg.GetReg(), rl_result.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700269 branch_pos_overflow->target = NewLIR0(kPseudoTargetLabel);
270 branch_normal->target = NewLIR0(kPseudoTargetLabel);
271 StoreValue(rl_dest, rl_result);
272 return;
273 }
274 case Instruction::LONG_TO_DOUBLE:
Chao-ying Fua0147762014-06-06 18:38:49 -0700275 if (Gen64Bit()) {
276 rcSrc = kCoreReg;
277 op = kX86Cvtsqi2sdRR;
278 break;
279 }
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800280 GenLongToFP(rl_dest, rl_src, true /* is_double */);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700281 return;
282 case Instruction::LONG_TO_FLOAT:
Chao-ying Fua0147762014-06-06 18:38:49 -0700283 if (Gen64Bit()) {
284 rcSrc = kCoreReg;
285 op = kX86Cvtsqi2ssRR;
286 break;
287 }
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800288 GenLongToFP(rl_dest, rl_src, false /* is_double */);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700289 return;
290 case Instruction::FLOAT_TO_LONG:
Chao-ying Fua0147762014-06-06 18:38:49 -0700291 if (Gen64Bit()) {
292 rl_src = LoadValue(rl_src, kFPReg);
293 // If result vreg is also src vreg, break association to avoid useless copy by EvalLoc()
294 ClobberSReg(rl_dest.s_reg_low);
295 rl_result = EvalLoc(rl_dest, kCoreReg, true);
296 RegStorage temp_reg = AllocTempSingle();
297
298 // Set 0x7fffffffffffffff to rl_result
299 LoadConstantWide(rl_result.reg, 0x7fffffffffffffff);
300 NewLIR2(kX86Cvtsqi2ssRR, temp_reg.GetReg(), rl_result.reg.GetReg());
301 NewLIR2(kX86ComissRR, rl_src.reg.GetReg(), temp_reg.GetReg());
302 LIR* branch_pos_overflow = NewLIR2(kX86Jcc8, 0, kX86CondA);
303 LIR* branch_na_n = NewLIR2(kX86Jcc8, 0, kX86CondP);
304 NewLIR2(kX86Cvttss2sqiRR, rl_result.reg.GetReg(), rl_src.reg.GetReg());
305 LIR* branch_normal = NewLIR1(kX86Jmp8, 0);
306 branch_na_n->target = NewLIR0(kPseudoTargetLabel);
307 NewLIR2(kX86Xor64RR, rl_result.reg.GetReg(), rl_result.reg.GetReg());
308 branch_pos_overflow->target = NewLIR0(kPseudoTargetLabel);
309 branch_normal->target = NewLIR0(kPseudoTargetLabel);
310 StoreValueWide(rl_dest, rl_result);
Dmitry Petrochenko9ee801f2014-05-12 11:31:37 +0700311 } else {
312 GenConversionCall(QUICK_ENTRYPOINT_OFFSET(4, pF2l), rl_dest, rl_src);
313 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700314 return;
315 case Instruction::DOUBLE_TO_LONG:
Chao-ying Fua0147762014-06-06 18:38:49 -0700316 if (Gen64Bit()) {
317 rl_src = LoadValueWide(rl_src, kFPReg);
318 // If result vreg is also src vreg, break association to avoid useless copy by EvalLoc()
319 ClobberSReg(rl_dest.s_reg_low);
320 rl_result = EvalLoc(rl_dest, kCoreReg, true);
321 RegStorage temp_reg = AllocTempDouble();
322
323 // Set 0x7fffffffffffffff to rl_result
324 LoadConstantWide(rl_result.reg, 0x7fffffffffffffff);
325 NewLIR2(kX86Cvtsqi2sdRR, temp_reg.GetReg(), rl_result.reg.GetReg());
326 NewLIR2(kX86ComisdRR, rl_src.reg.GetReg(), temp_reg.GetReg());
327 LIR* branch_pos_overflow = NewLIR2(kX86Jcc8, 0, kX86CondA);
328 LIR* branch_na_n = NewLIR2(kX86Jcc8, 0, kX86CondP);
329 NewLIR2(kX86Cvttsd2sqiRR, rl_result.reg.GetReg(), rl_src.reg.GetReg());
330 LIR* branch_normal = NewLIR1(kX86Jmp8, 0);
331 branch_na_n->target = NewLIR0(kPseudoTargetLabel);
332 NewLIR2(kX86Xor64RR, rl_result.reg.GetReg(), rl_result.reg.GetReg());
333 branch_pos_overflow->target = NewLIR0(kPseudoTargetLabel);
334 branch_normal->target = NewLIR0(kPseudoTargetLabel);
335 StoreValueWide(rl_dest, rl_result);
Dmitry Petrochenko9ee801f2014-05-12 11:31:37 +0700336 } else {
337 GenConversionCall(QUICK_ENTRYPOINT_OFFSET(4, pD2l), rl_dest, rl_src);
338 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700339 return;
340 default:
341 LOG(INFO) << "Unexpected opcode: " << opcode;
342 }
buzbee091cc402014-03-31 10:14:40 -0700343 // At this point, target will be either float or double.
344 DCHECK(rl_dest.fp);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700345 if (rl_src.wide) {
346 rl_src = LoadValueWide(rl_src, rcSrc);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700347 } else {
348 rl_src = LoadValue(rl_src, rcSrc);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700349 }
buzbee091cc402014-03-31 10:14:40 -0700350 rl_result = EvalLoc(rl_dest, kFPReg, true);
351 NewLIR2(op, rl_result.reg.GetReg(), rl_src.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700352 if (rl_dest.wide) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700353 StoreValueWide(rl_dest, rl_result);
354 } else {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700355 StoreValue(rl_dest, rl_result);
356 }
357}
358
359void X86Mir2Lir::GenCmpFP(Instruction::Code code, RegLocation rl_dest,
360 RegLocation rl_src1, RegLocation rl_src2) {
361 bool single = (code == Instruction::CMPL_FLOAT) || (code == Instruction::CMPG_FLOAT);
362 bool unordered_gt = (code == Instruction::CMPG_DOUBLE) || (code == Instruction::CMPG_FLOAT);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700363 if (single) {
364 rl_src1 = LoadValue(rl_src1, kFPReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700365 rl_src2 = LoadValue(rl_src2, kFPReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700366 } else {
367 rl_src1 = LoadValueWide(rl_src1, kFPReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700368 rl_src2 = LoadValueWide(rl_src2, kFPReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700369 }
370 // In case result vreg is also src vreg, break association to avoid useless copy by EvalLoc()
371 ClobberSReg(rl_dest.s_reg_low);
372 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
buzbee2700f7e2014-03-07 09:46:20 -0800373 LoadConstantNoClobber(rl_result.reg, unordered_gt ? 1 : 0);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700374 if (single) {
buzbee091cc402014-03-31 10:14:40 -0700375 NewLIR2(kX86UcomissRR, rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700376 } else {
buzbee091cc402014-03-31 10:14:40 -0700377 NewLIR2(kX86UcomisdRR, rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700378 }
379 LIR* branch = NULL;
380 if (unordered_gt) {
381 branch = NewLIR2(kX86Jcc8, 0, kX86CondPE);
382 }
383 // If the result reg can't be byte accessed, use a jump and move instead of a set.
buzbee091cc402014-03-31 10:14:40 -0700384 if (rl_result.reg.GetReg() >= rs_rX86_SP.GetReg()) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700385 LIR* branch2 = NULL;
386 if (unordered_gt) {
387 branch2 = NewLIR2(kX86Jcc8, 0, kX86CondA);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000388 NewLIR2(kX86Mov32RI, rl_result.reg.GetReg(), 0x0);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700389 } else {
390 branch2 = NewLIR2(kX86Jcc8, 0, kX86CondBe);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000391 NewLIR2(kX86Mov32RI, rl_result.reg.GetReg(), 0x1);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700392 }
393 branch2->target = NewLIR0(kPseudoTargetLabel);
394 } else {
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000395 NewLIR2(kX86Set8R, rl_result.reg.GetReg(), kX86CondA /* above - unsigned > */);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700396 }
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000397 NewLIR2(kX86Sbb32RI, rl_result.reg.GetReg(), 0);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700398 if (unordered_gt) {
399 branch->target = NewLIR0(kPseudoTargetLabel);
400 }
401 StoreValue(rl_dest, rl_result);
402}
403
404void X86Mir2Lir::GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias,
405 bool is_double) {
buzbee0d829482013-10-11 15:24:55 -0700406 LIR* taken = &block_label_list_[bb->taken];
407 LIR* not_taken = &block_label_list_[bb->fall_through];
Brian Carlstrom7940e442013-07-12 13:46:57 -0700408 LIR* branch = NULL;
409 RegLocation rl_src1;
410 RegLocation rl_src2;
411 if (is_double) {
412 rl_src1 = mir_graph_->GetSrcWide(mir, 0);
413 rl_src2 = mir_graph_->GetSrcWide(mir, 2);
414 rl_src1 = LoadValueWide(rl_src1, kFPReg);
415 rl_src2 = LoadValueWide(rl_src2, kFPReg);
buzbee091cc402014-03-31 10:14:40 -0700416 NewLIR2(kX86UcomisdRR, rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700417 } else {
418 rl_src1 = mir_graph_->GetSrc(mir, 0);
419 rl_src2 = mir_graph_->GetSrc(mir, 1);
420 rl_src1 = LoadValue(rl_src1, kFPReg);
421 rl_src2 = LoadValue(rl_src2, kFPReg);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000422 NewLIR2(kX86UcomissRR, rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700423 }
Vladimir Markoa8946072014-01-22 10:30:44 +0000424 ConditionCode ccode = mir->meta.ccode;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700425 switch (ccode) {
426 case kCondEq:
427 if (!gt_bias) {
428 branch = NewLIR2(kX86Jcc8, 0, kX86CondPE);
429 branch->target = not_taken;
430 }
431 break;
432 case kCondNe:
433 if (!gt_bias) {
434 branch = NewLIR2(kX86Jcc8, 0, kX86CondPE);
435 branch->target = taken;
436 }
437 break;
438 case kCondLt:
439 if (gt_bias) {
440 branch = NewLIR2(kX86Jcc8, 0, kX86CondPE);
441 branch->target = not_taken;
442 }
Vladimir Marko58af1f92013-12-19 13:31:15 +0000443 ccode = kCondUlt;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700444 break;
445 case kCondLe:
446 if (gt_bias) {
447 branch = NewLIR2(kX86Jcc8, 0, kX86CondPE);
448 branch->target = not_taken;
449 }
450 ccode = kCondLs;
451 break;
452 case kCondGt:
453 if (gt_bias) {
454 branch = NewLIR2(kX86Jcc8, 0, kX86CondPE);
455 branch->target = taken;
456 }
457 ccode = kCondHi;
458 break;
459 case kCondGe:
460 if (gt_bias) {
461 branch = NewLIR2(kX86Jcc8, 0, kX86CondPE);
462 branch->target = taken;
463 }
Vladimir Marko58af1f92013-12-19 13:31:15 +0000464 ccode = kCondUge;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700465 break;
466 default:
467 LOG(FATAL) << "Unexpected ccode: " << ccode;
468 }
469 OpCondBranch(ccode, taken);
470}
471
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700472void X86Mir2Lir::GenNegFloat(RegLocation rl_dest, RegLocation rl_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700473 RegLocation rl_result;
474 rl_src = LoadValue(rl_src, kCoreReg);
475 rl_result = EvalLoc(rl_dest, kCoreReg, true);
buzbee2700f7e2014-03-07 09:46:20 -0800476 OpRegRegImm(kOpAdd, rl_result.reg, rl_src.reg, 0x80000000);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700477 StoreValue(rl_dest, rl_result);
478}
479
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700480void X86Mir2Lir::GenNegDouble(RegLocation rl_dest, RegLocation rl_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700481 RegLocation rl_result;
482 rl_src = LoadValueWide(rl_src, kCoreReg);
Chao-ying Fua0147762014-06-06 18:38:49 -0700483 rl_result = EvalLocWide(rl_dest, kCoreReg, true);
484 if (Gen64Bit()) {
485 LoadConstantWide(rl_result.reg, 0x8000000000000000);
486 OpRegReg(kOpAdd, rl_result.reg, rl_src.reg);
487 } else {
488 OpRegRegImm(kOpAdd, rl_result.reg.GetHigh(), rl_src.reg.GetHigh(), 0x80000000);
489 OpRegCopy(rl_result.reg, rl_src.reg);
490 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700491 StoreValueWide(rl_dest, rl_result);
492}
493
494bool X86Mir2Lir::GenInlinedSqrt(CallInfo* info) {
Mark Mendellbff1ef02013-12-13 13:47:34 -0800495 RegLocation rl_src = info->args[0];
496 RegLocation rl_dest = InlineTargetWide(info); // double place for result
497 rl_src = LoadValueWide(rl_src, kFPReg);
498 RegLocation rl_result = EvalLoc(rl_dest, kFPReg, true);
buzbee091cc402014-03-31 10:14:40 -0700499 NewLIR2(kX86SqrtsdRR, rl_result.reg.GetReg(), rl_src.reg.GetReg());
Mark Mendellbff1ef02013-12-13 13:47:34 -0800500 StoreValueWide(rl_dest, rl_result);
501 return true;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700502}
503
504
505
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700506} // namespace art