blob: d8616a7bf3abd3cdebad7980737e6ce8c4d0629d [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"
Andreas Gampe0b9203e2015-01-22 20:39:27 -080018
19#include "base/logging.h"
Brian Carlstrom7940e442013-07-12 13:46:57 -070020#include "dex/quick/mir_to_lir-inl.h"
buzbeeb5860fb2014-06-21 15:31:01 -070021#include "dex/reg_storage_eq.h"
Brian Carlstrom7940e442013-07-12 13:46:57 -070022#include "x86_lir.h"
23
24namespace art {
25
26void X86Mir2Lir::GenArithOpFloat(Instruction::Code opcode,
27 RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) {
28 X86OpCode op = kX86Nop;
29 RegLocation rl_result;
30
31 /*
32 * Don't attempt to optimize register usage since these opcodes call out to
33 * the handlers.
34 */
35 switch (opcode) {
36 case Instruction::ADD_FLOAT_2ADDR:
37 case Instruction::ADD_FLOAT:
38 op = kX86AddssRR;
39 break;
40 case Instruction::SUB_FLOAT_2ADDR:
41 case Instruction::SUB_FLOAT:
42 op = kX86SubssRR;
43 break;
44 case Instruction::DIV_FLOAT_2ADDR:
45 case Instruction::DIV_FLOAT:
46 op = kX86DivssRR;
47 break;
48 case Instruction::MUL_FLOAT_2ADDR:
49 case Instruction::MUL_FLOAT:
50 op = kX86MulssRR;
51 break;
52 case Instruction::REM_FLOAT_2ADDR:
53 case Instruction::REM_FLOAT:
Alexei Zavjalovbd3682e2014-06-12 03:08:01 +070054 GenRemFP(rl_dest, rl_src1, rl_src2, false /* is_double */);
Brian Carlstrom7940e442013-07-12 13:46:57 -070055 return;
56 case Instruction::NEG_FLOAT:
57 GenNegFloat(rl_dest, rl_src1);
58 return;
59 default:
60 LOG(FATAL) << "Unexpected opcode: " << opcode;
61 }
62 rl_src1 = LoadValue(rl_src1, kFPReg);
63 rl_src2 = LoadValue(rl_src2, kFPReg);
64 rl_result = EvalLoc(rl_dest, kFPReg, true);
buzbee2700f7e2014-03-07 09:46:20 -080065 RegStorage r_dest = rl_result.reg;
66 RegStorage r_src1 = rl_src1.reg;
67 RegStorage r_src2 = rl_src2.reg;
Brian Carlstrom7940e442013-07-12 13:46:57 -070068 if (r_dest == r_src2) {
buzbee091cc402014-03-31 10:14:40 -070069 r_src2 = AllocTempSingle();
Brian Carlstrom7940e442013-07-12 13:46:57 -070070 OpRegCopy(r_src2, r_dest);
71 }
72 OpRegCopy(r_dest, r_src1);
buzbee2700f7e2014-03-07 09:46:20 -080073 NewLIR2(op, r_dest.GetReg(), r_src2.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -070074 StoreValue(rl_dest, rl_result);
75}
76
77void X86Mir2Lir::GenArithOpDouble(Instruction::Code opcode,
78 RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) {
buzbee091cc402014-03-31 10:14:40 -070079 DCHECK(rl_dest.wide);
80 DCHECK(rl_dest.fp);
81 DCHECK(rl_src1.wide);
82 DCHECK(rl_src1.fp);
83 DCHECK(rl_src2.wide);
84 DCHECK(rl_src2.fp);
Brian Carlstrom7940e442013-07-12 13:46:57 -070085 X86OpCode op = kX86Nop;
86 RegLocation rl_result;
87
88 switch (opcode) {
89 case Instruction::ADD_DOUBLE_2ADDR:
90 case Instruction::ADD_DOUBLE:
91 op = kX86AddsdRR;
92 break;
93 case Instruction::SUB_DOUBLE_2ADDR:
94 case Instruction::SUB_DOUBLE:
95 op = kX86SubsdRR;
96 break;
97 case Instruction::DIV_DOUBLE_2ADDR:
98 case Instruction::DIV_DOUBLE:
99 op = kX86DivsdRR;
100 break;
101 case Instruction::MUL_DOUBLE_2ADDR:
102 case Instruction::MUL_DOUBLE:
103 op = kX86MulsdRR;
104 break;
105 case Instruction::REM_DOUBLE_2ADDR:
106 case Instruction::REM_DOUBLE:
Alexei Zavjalovbd3682e2014-06-12 03:08:01 +0700107 GenRemFP(rl_dest, rl_src1, rl_src2, true /* is_double */);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700108 return;
109 case Instruction::NEG_DOUBLE:
110 GenNegDouble(rl_dest, rl_src1);
111 return;
112 default:
113 LOG(FATAL) << "Unexpected opcode: " << opcode;
114 }
115 rl_src1 = LoadValueWide(rl_src1, kFPReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700116 rl_src2 = LoadValueWide(rl_src2, kFPReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700117 rl_result = EvalLoc(rl_dest, kFPReg, true);
buzbee091cc402014-03-31 10:14:40 -0700118 if (rl_result.reg == rl_src2.reg) {
119 rl_src2.reg = AllocTempDouble();
120 OpRegCopy(rl_src2.reg, rl_result.reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700121 }
buzbee091cc402014-03-31 10:14:40 -0700122 OpRegCopy(rl_result.reg, rl_src1.reg);
123 NewLIR2(op, rl_result.reg.GetReg(), rl_src2.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700124 StoreValueWide(rl_dest, rl_result);
125}
126
Ningsheng Jian675e09b2014-10-23 13:48:36 +0800127void X86Mir2Lir::GenMultiplyByConstantFloat(RegLocation rl_dest, RegLocation rl_src1,
128 int32_t constant) {
129 // TODO: need x86 implementation.
130 UNUSED(rl_dest, rl_src1, constant);
131 LOG(FATAL) << "Unimplemented GenMultiplyByConstantFloat in x86";
132}
133
134void X86Mir2Lir::GenMultiplyByConstantDouble(RegLocation rl_dest, RegLocation rl_src1,
135 int64_t constant) {
136 // TODO: need x86 implementation.
137 UNUSED(rl_dest, rl_src1, constant);
138 LOG(FATAL) << "Unimplemented GenMultiplyByConstantDouble in x86";
139}
140
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800141void X86Mir2Lir::GenLongToFP(RegLocation rl_dest, RegLocation rl_src, bool is_double) {
142 // Compute offsets to the source and destination VRs on stack
143 int src_v_reg_offset = SRegOffset(rl_src.s_reg_low);
144 int dest_v_reg_offset = SRegOffset(rl_dest.s_reg_low);
145
146 // Update the in-register state of source.
147 rl_src = UpdateLocWide(rl_src);
148
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100149 // All memory accesses below reference dalvik regs.
150 ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
151
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800152 // If the source is in physical register, then put it in its location on stack.
153 if (rl_src.location == kLocPhysReg) {
buzbee091cc402014-03-31 10:14:40 -0700154 RegisterInfo* reg_info = GetRegInfo(rl_src.reg);
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800155
buzbee091cc402014-03-31 10:14:40 -0700156 if (reg_info != nullptr && reg_info->IsTemp()) {
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800157 // Calling FlushSpecificReg because it will only write back VR if it is dirty.
buzbee091cc402014-03-31 10:14:40 -0700158 FlushSpecificReg(reg_info);
159 // ResetDef to prevent NullifyRange from removing stores.
160 ResetDef(rl_src.reg);
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800161 } else {
162 // It must have been register promoted if it is not a temp but is still in physical
163 // register. Since we need it to be in memory to convert, we place it there now.
Ian Rogersb28c1c02014-11-08 11:21:21 -0800164 const RegStorage rs_rSP = cu_->target64 ? rs_rX86_SP_64 : rs_rX86_SP_32;
165 StoreBaseDisp(rs_rSP, src_v_reg_offset, rl_src.reg, k64, kNotVolatile);
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800166 }
167 }
168
169 // Push the source virtual register onto the x87 stack.
Ian Rogersb28c1c02014-11-08 11:21:21 -0800170 LIR *fild64 = NewLIR2NoDest(kX86Fild64M, rs_rX86_SP_32.GetReg(),
buzbee091cc402014-03-31 10:14:40 -0700171 src_v_reg_offset + LOWORD_OFFSET);
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800172 AnnotateDalvikRegAccess(fild64, (src_v_reg_offset + LOWORD_OFFSET) >> 2,
buzbee091cc402014-03-31 10:14:40 -0700173 true /* is_load */, true /* is64bit */);
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800174
175 // Now pop off x87 stack and store it in the destination VR's stack location.
176 int opcode = is_double ? kX86Fstp64M : kX86Fstp32M;
177 int displacement = is_double ? dest_v_reg_offset + LOWORD_OFFSET : dest_v_reg_offset;
Ian Rogersb28c1c02014-11-08 11:21:21 -0800178 LIR *fstp = NewLIR2NoDest(opcode, rs_rX86_SP_32.GetReg(), displacement);
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800179 AnnotateDalvikRegAccess(fstp, displacement >> 2, false /* is_load */, is_double);
180
181 /*
182 * The result is in a physical register if it was in a temp or was register
183 * promoted. For that reason it is enough to check if it is in physical
184 * register. If it is, then we must do all of the bookkeeping necessary to
185 * invalidate temp (if needed) and load in promoted register (if needed).
186 * If the result's location is in memory, then we do not need to do anything
187 * more since the fstp has already placed the correct value in memory.
188 */
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700189 RegLocation rl_result = is_double ? UpdateLocWideTyped(rl_dest) : UpdateLocTyped(rl_dest);
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800190 if (rl_result.location == kLocPhysReg) {
191 /*
192 * We already know that the result is in a physical register but do not know if it is the
193 * right class. So we call EvalLoc(Wide) first which will ensure that it will get moved to the
194 * correct register class.
195 */
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100196 rl_result = EvalLoc(rl_dest, kFPReg, true);
Ian Rogersb28c1c02014-11-08 11:21:21 -0800197 const RegStorage rs_rSP = cu_->target64 ? rs_rX86_SP_64 : rs_rX86_SP_32;
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800198 if (is_double) {
Ian Rogersb28c1c02014-11-08 11:21:21 -0800199 LoadBaseDisp(rs_rSP, dest_v_reg_offset, rl_result.reg, k64, kNotVolatile);
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800200
Maxim Kazantsev51a80d72014-03-06 11:33:26 +0700201 StoreFinalValueWide(rl_dest, rl_result);
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800202 } else {
Ian Rogersb28c1c02014-11-08 11:21:21 -0800203 Load32Disp(rs_rSP, 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());
Serguei Katkov5078d972014-06-20 16:45:52 +0700242 LIR* branch_pos_overflow = NewLIR2(kX86Jcc8, 0, kX86CondAe);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700243 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());
Serguei Katkov5078d972014-06-20 16:45:52 +0700263 LIR* branch_pos_overflow = NewLIR2(kX86Jcc8, 0, kX86CondAe);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700264 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:
Elena Sayapinadd644502014-07-01 18:39:52 +0700275 if (cu_->target64) {
Chao-ying Fua0147762014-06-06 18:38:49 -0700276 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:
Elena Sayapinadd644502014-07-01 18:39:52 +0700283 if (cu_->target64) {
Chao-ying Fua0147762014-06-06 18:38:49 -0700284 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:
Elena Sayapinadd644502014-07-01 18:39:52 +0700291 if (cu_->target64) {
Chao-ying Fua0147762014-06-06 18:38:49 -0700292 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());
Serguei Katkov5078d972014-06-20 16:45:52 +0700302 LIR* branch_pos_overflow = NewLIR2(kX86Jcc8, 0, kX86CondAe);
Chao-ying Fua0147762014-06-06 18:38:49 -0700303 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 {
Andreas Gampe98430592014-07-27 19:44:50 -0700312 GenConversionCall(kQuickF2l, rl_dest, rl_src);
Dmitry Petrochenko9ee801f2014-05-12 11:31:37 +0700313 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700314 return;
315 case Instruction::DOUBLE_TO_LONG:
Elena Sayapinadd644502014-07-01 18:39:52 +0700316 if (cu_->target64) {
Chao-ying Fua0147762014-06-06 18:38:49 -0700317 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());
Serguei Katkov5078d972014-06-20 16:45:52 +0700327 LIR* branch_pos_overflow = NewLIR2(kX86Jcc8, 0, kX86CondAe);
Chao-ying Fua0147762014-06-06 18:38:49 -0700328 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 {
Andreas Gampe98430592014-07-27 19:44:50 -0700337 GenConversionCall(kQuickD2l, rl_dest, rl_src);
Dmitry Petrochenko9ee801f2014-05-12 11:31:37 +0700338 }
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
Alexei Zavjalovbd3682e2014-06-12 03:08:01 +0700359void X86Mir2Lir::GenRemFP(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2, bool is_double) {
360 // Compute offsets to the source and destination VRs on stack.
361 int src1_v_reg_offset = SRegOffset(rl_src1.s_reg_low);
362 int src2_v_reg_offset = SRegOffset(rl_src2.s_reg_low);
363 int dest_v_reg_offset = SRegOffset(rl_dest.s_reg_low);
364
365 // Update the in-register state of sources.
366 rl_src1 = is_double ? UpdateLocWide(rl_src1) : UpdateLoc(rl_src1);
367 rl_src2 = is_double ? UpdateLocWide(rl_src2) : UpdateLoc(rl_src2);
368
369 // All memory accesses below reference dalvik regs.
370 ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
371
372 // If the source is in physical register, then put it in its location on stack.
Ian Rogersb28c1c02014-11-08 11:21:21 -0800373 const RegStorage rs_rSP = cu_->target64 ? rs_rX86_SP_64 : rs_rX86_SP_32;
Alexei Zavjalovbd3682e2014-06-12 03:08:01 +0700374 if (rl_src1.location == kLocPhysReg) {
375 RegisterInfo* reg_info = GetRegInfo(rl_src1.reg);
376
377 if (reg_info != nullptr && reg_info->IsTemp()) {
378 // Calling FlushSpecificReg because it will only write back VR if it is dirty.
379 FlushSpecificReg(reg_info);
380 // ResetDef to prevent NullifyRange from removing stores.
381 ResetDef(rl_src1.reg);
382 } else {
383 // It must have been register promoted if it is not a temp but is still in physical
384 // register. Since we need it to be in memory to convert, we place it there now.
Ian Rogersb28c1c02014-11-08 11:21:21 -0800385 StoreBaseDisp(rs_rSP, src1_v_reg_offset, rl_src1.reg, is_double ? k64 : k32,
Andreas Gampe3c12c512014-06-24 18:46:29 +0000386 kNotVolatile);
Alexei Zavjalovbd3682e2014-06-12 03:08:01 +0700387 }
388 }
389
390 if (rl_src2.location == kLocPhysReg) {
391 RegisterInfo* reg_info = GetRegInfo(rl_src2.reg);
392 if (reg_info != nullptr && reg_info->IsTemp()) {
393 FlushSpecificReg(reg_info);
394 ResetDef(rl_src2.reg);
395 } else {
Ian Rogersb28c1c02014-11-08 11:21:21 -0800396 StoreBaseDisp(rs_rSP, src2_v_reg_offset, rl_src2.reg, is_double ? k64 : k32,
Andreas Gampe3c12c512014-06-24 18:46:29 +0000397 kNotVolatile);
Alexei Zavjalovbd3682e2014-06-12 03:08:01 +0700398 }
399 }
400
401 int fld_opcode = is_double ? kX86Fld64M : kX86Fld32M;
402
403 // Push the source virtual registers onto the x87 stack.
Ian Rogersb28c1c02014-11-08 11:21:21 -0800404 LIR *fld_2 = NewLIR2NoDest(fld_opcode, rs_rSP.GetReg(),
Alexei Zavjalovbd3682e2014-06-12 03:08:01 +0700405 src2_v_reg_offset + LOWORD_OFFSET);
406 AnnotateDalvikRegAccess(fld_2, (src2_v_reg_offset + LOWORD_OFFSET) >> 2,
407 true /* is_load */, is_double /* is64bit */);
408
Ian Rogersb28c1c02014-11-08 11:21:21 -0800409 LIR *fld_1 = NewLIR2NoDest(fld_opcode, rs_rSP.GetReg(),
Alexei Zavjalovbd3682e2014-06-12 03:08:01 +0700410 src1_v_reg_offset + LOWORD_OFFSET);
411 AnnotateDalvikRegAccess(fld_1, (src1_v_reg_offset + LOWORD_OFFSET) >> 2,
412 true /* is_load */, is_double /* is64bit */);
413
414 FlushReg(rs_rAX);
415 Clobber(rs_rAX);
416 LockTemp(rs_rAX);
417
418 LIR* retry = NewLIR0(kPseudoTargetLabel);
419
420 // Divide ST(0) by ST(1) and place result to ST(0).
421 NewLIR0(kX86Fprem);
422
423 // Move FPU status word to AX.
424 NewLIR0(kX86Fstsw16R);
425
426 // Check if reduction is complete.
427 OpRegImm(kOpAnd, rs_rAX, 0x400);
428
429 // If no then continue to compute remainder.
430 LIR* branch = NewLIR2(kX86Jcc8, 0, kX86CondNe);
431 branch->target = retry;
432
433 FreeTemp(rs_rAX);
434
435 // Now store result in the destination VR's stack location.
436 int displacement = dest_v_reg_offset + LOWORD_OFFSET;
437 int opcode = is_double ? kX86Fst64M : kX86Fst32M;
Ian Rogersb28c1c02014-11-08 11:21:21 -0800438 LIR *fst = NewLIR2NoDest(opcode, rs_rSP.GetReg(), displacement);
Alexei Zavjalovbd3682e2014-06-12 03:08:01 +0700439 AnnotateDalvikRegAccess(fst, displacement >> 2, false /* is_load */, is_double /* is64bit */);
440
441 // Pop ST(1) and ST(0).
442 NewLIR0(kX86Fucompp);
443
444 /*
445 * The result is in a physical register if it was in a temp or was register
446 * promoted. For that reason it is enough to check if it is in physical
447 * register. If it is, then we must do all of the bookkeeping necessary to
448 * invalidate temp (if needed) and load in promoted register (if needed).
449 * If the result's location is in memory, then we do not need to do anything
450 * more since the fstp has already placed the correct value in memory.
451 */
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700452 RegLocation rl_result = is_double ? UpdateLocWideTyped(rl_dest) : UpdateLocTyped(rl_dest);
Alexei Zavjalovbd3682e2014-06-12 03:08:01 +0700453 if (rl_result.location == kLocPhysReg) {
454 rl_result = EvalLoc(rl_dest, kFPReg, true);
455 if (is_double) {
Ian Rogersb28c1c02014-11-08 11:21:21 -0800456 LoadBaseDisp(rs_rSP, dest_v_reg_offset, rl_result.reg, k64, kNotVolatile);
Alexei Zavjalovbd3682e2014-06-12 03:08:01 +0700457 StoreFinalValueWide(rl_dest, rl_result);
458 } else {
Ian Rogersb28c1c02014-11-08 11:21:21 -0800459 Load32Disp(rs_rSP, dest_v_reg_offset, rl_result.reg);
Alexei Zavjalovbd3682e2014-06-12 03:08:01 +0700460 StoreFinalValue(rl_dest, rl_result);
461 }
462 }
463}
464
Brian Carlstrom7940e442013-07-12 13:46:57 -0700465void X86Mir2Lir::GenCmpFP(Instruction::Code code, RegLocation rl_dest,
466 RegLocation rl_src1, RegLocation rl_src2) {
467 bool single = (code == Instruction::CMPL_FLOAT) || (code == Instruction::CMPG_FLOAT);
468 bool unordered_gt = (code == Instruction::CMPG_DOUBLE) || (code == Instruction::CMPG_FLOAT);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700469 if (single) {
470 rl_src1 = LoadValue(rl_src1, kFPReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700471 rl_src2 = LoadValue(rl_src2, kFPReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700472 } else {
473 rl_src1 = LoadValueWide(rl_src1, kFPReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700474 rl_src2 = LoadValueWide(rl_src2, kFPReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700475 }
476 // In case result vreg is also src vreg, break association to avoid useless copy by EvalLoc()
477 ClobberSReg(rl_dest.s_reg_low);
478 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
buzbee2700f7e2014-03-07 09:46:20 -0800479 LoadConstantNoClobber(rl_result.reg, unordered_gt ? 1 : 0);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700480 if (single) {
buzbee091cc402014-03-31 10:14:40 -0700481 NewLIR2(kX86UcomissRR, rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700482 } else {
buzbee091cc402014-03-31 10:14:40 -0700483 NewLIR2(kX86UcomisdRR, rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700484 }
485 LIR* branch = NULL;
486 if (unordered_gt) {
487 branch = NewLIR2(kX86Jcc8, 0, kX86CondPE);
488 }
489 // If the result reg can't be byte accessed, use a jump and move instead of a set.
Chao-ying Fu7e399fd2014-06-10 18:11:11 -0700490 if (!IsByteRegister(rl_result.reg)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700491 LIR* branch2 = NULL;
492 if (unordered_gt) {
493 branch2 = NewLIR2(kX86Jcc8, 0, kX86CondA);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000494 NewLIR2(kX86Mov32RI, rl_result.reg.GetReg(), 0x0);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700495 } else {
496 branch2 = NewLIR2(kX86Jcc8, 0, kX86CondBe);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000497 NewLIR2(kX86Mov32RI, rl_result.reg.GetReg(), 0x1);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700498 }
499 branch2->target = NewLIR0(kPseudoTargetLabel);
500 } else {
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000501 NewLIR2(kX86Set8R, rl_result.reg.GetReg(), kX86CondA /* above - unsigned > */);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700502 }
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000503 NewLIR2(kX86Sbb32RI, rl_result.reg.GetReg(), 0);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700504 if (unordered_gt) {
505 branch->target = NewLIR0(kPseudoTargetLabel);
506 }
507 StoreValue(rl_dest, rl_result);
508}
509
510void X86Mir2Lir::GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias,
511 bool is_double) {
buzbee0d829482013-10-11 15:24:55 -0700512 LIR* taken = &block_label_list_[bb->taken];
513 LIR* not_taken = &block_label_list_[bb->fall_through];
Brian Carlstrom7940e442013-07-12 13:46:57 -0700514 LIR* branch = NULL;
515 RegLocation rl_src1;
516 RegLocation rl_src2;
517 if (is_double) {
518 rl_src1 = mir_graph_->GetSrcWide(mir, 0);
519 rl_src2 = mir_graph_->GetSrcWide(mir, 2);
520 rl_src1 = LoadValueWide(rl_src1, kFPReg);
521 rl_src2 = LoadValueWide(rl_src2, kFPReg);
buzbee091cc402014-03-31 10:14:40 -0700522 NewLIR2(kX86UcomisdRR, rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700523 } else {
524 rl_src1 = mir_graph_->GetSrc(mir, 0);
525 rl_src2 = mir_graph_->GetSrc(mir, 1);
526 rl_src1 = LoadValue(rl_src1, kFPReg);
527 rl_src2 = LoadValue(rl_src2, kFPReg);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000528 NewLIR2(kX86UcomissRR, rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700529 }
Vladimir Markoa8946072014-01-22 10:30:44 +0000530 ConditionCode ccode = mir->meta.ccode;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700531 switch (ccode) {
532 case kCondEq:
533 if (!gt_bias) {
534 branch = NewLIR2(kX86Jcc8, 0, kX86CondPE);
535 branch->target = not_taken;
536 }
537 break;
538 case kCondNe:
539 if (!gt_bias) {
540 branch = NewLIR2(kX86Jcc8, 0, kX86CondPE);
541 branch->target = taken;
542 }
543 break;
544 case kCondLt:
545 if (gt_bias) {
546 branch = NewLIR2(kX86Jcc8, 0, kX86CondPE);
547 branch->target = not_taken;
548 }
Vladimir Marko58af1f92013-12-19 13:31:15 +0000549 ccode = kCondUlt;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700550 break;
551 case kCondLe:
552 if (gt_bias) {
553 branch = NewLIR2(kX86Jcc8, 0, kX86CondPE);
554 branch->target = not_taken;
555 }
556 ccode = kCondLs;
557 break;
558 case kCondGt:
559 if (gt_bias) {
560 branch = NewLIR2(kX86Jcc8, 0, kX86CondPE);
561 branch->target = taken;
562 }
563 ccode = kCondHi;
564 break;
565 case kCondGe:
566 if (gt_bias) {
567 branch = NewLIR2(kX86Jcc8, 0, kX86CondPE);
568 branch->target = taken;
569 }
Vladimir Marko58af1f92013-12-19 13:31:15 +0000570 ccode = kCondUge;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700571 break;
572 default:
573 LOG(FATAL) << "Unexpected ccode: " << ccode;
574 }
575 OpCondBranch(ccode, taken);
576}
577
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700578void X86Mir2Lir::GenNegFloat(RegLocation rl_dest, RegLocation rl_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700579 RegLocation rl_result;
580 rl_src = LoadValue(rl_src, kCoreReg);
581 rl_result = EvalLoc(rl_dest, kCoreReg, true);
buzbee2700f7e2014-03-07 09:46:20 -0800582 OpRegRegImm(kOpAdd, rl_result.reg, rl_src.reg, 0x80000000);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700583 StoreValue(rl_dest, rl_result);
584}
585
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700586void X86Mir2Lir::GenNegDouble(RegLocation rl_dest, RegLocation rl_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700587 RegLocation rl_result;
588 rl_src = LoadValueWide(rl_src, kCoreReg);
Elena Sayapinadd644502014-07-01 18:39:52 +0700589 if (cu_->target64) {
Pavel Vyssotskid4812a92014-11-11 12:37:56 +0600590 rl_result = EvalLocWide(rl_dest, kCoreReg, true);
Alexei Zavjalov02959ea2014-06-18 17:18:36 +0700591 OpRegCopy(rl_result.reg, rl_src.reg);
592 // Flip sign bit.
593 NewLIR2(kX86Rol64RI, rl_result.reg.GetReg(), 1);
594 NewLIR2(kX86Xor64RI, rl_result.reg.GetReg(), 1);
595 NewLIR2(kX86Ror64RI, rl_result.reg.GetReg(), 1);
Chao-ying Fua0147762014-06-06 18:38:49 -0700596 } else {
Pavel Vyssotskid4812a92014-11-11 12:37:56 +0600597 rl_result = ForceTempWide(rl_src);
598 OpRegRegImm(kOpAdd, rl_result.reg.GetHigh(), rl_result.reg.GetHigh(), 0x80000000);
Chao-ying Fua0147762014-06-06 18:38:49 -0700599 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700600 StoreValueWide(rl_dest, rl_result);
601}
602
603bool X86Mir2Lir::GenInlinedSqrt(CallInfo* info) {
Mark Mendellbff1ef02013-12-13 13:47:34 -0800604 RegLocation rl_dest = InlineTargetWide(info); // double place for result
Chao-ying Fuff87d7b2015-01-19 15:51:57 -0800605 if (rl_dest.s_reg_low == INVALID_SREG) {
606 // Result is unused, the code is dead. Inlining successful, no code generated.
607 return true;
608 }
609 RegLocation rl_src = info->args[0];
Mark Mendellbff1ef02013-12-13 13:47:34 -0800610 rl_src = LoadValueWide(rl_src, kFPReg);
611 RegLocation rl_result = EvalLoc(rl_dest, kFPReg, true);
buzbee091cc402014-03-31 10:14:40 -0700612 NewLIR2(kX86SqrtsdRR, rl_result.reg.GetReg(), rl_src.reg.GetReg());
Mark Mendellbff1ef02013-12-13 13:47:34 -0800613 StoreValueWide(rl_dest, rl_result);
614 return true;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700615}
616
Yixin Shou7071c8d2014-03-05 06:07:48 -0500617bool X86Mir2Lir::GenInlinedAbsFloat(CallInfo* info) {
618 // Get the argument
619 RegLocation rl_src = info->args[0];
620
621 // Get the inlined intrinsic target virtual register
622 RegLocation rl_dest = InlineTarget(info);
623
624 // Get the virtual register number
625 DCHECK_NE(rl_src.s_reg_low, INVALID_SREG);
626 if (rl_dest.s_reg_low == INVALID_SREG) {
627 // Result is unused, the code is dead. Inlining successful, no code generated.
628 return true;
629 }
630 int v_src_reg = mir_graph_->SRegToVReg(rl_src.s_reg_low);
631 int v_dst_reg = mir_graph_->SRegToVReg(rl_dest.s_reg_low);
632
633 // if argument is the same as inlined intrinsic target
634 if (v_src_reg == v_dst_reg) {
635 rl_src = UpdateLoc(rl_src);
636
637 // if argument is in the physical register
638 if (rl_src.location == kLocPhysReg) {
639 rl_src = LoadValue(rl_src, kCoreReg);
640 OpRegImm(kOpAnd, rl_src.reg, 0x7fffffff);
641 StoreValue(rl_dest, rl_src);
642 return true;
643 }
644 // the argument is in memory
645 DCHECK((rl_src.location == kLocDalvikFrame) ||
646 (rl_src.location == kLocCompilerTemp));
647
648 // Operate directly into memory.
649 int displacement = SRegOffset(rl_dest.s_reg_low);
650 ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
Ian Rogersb28c1c02014-11-08 11:21:21 -0800651 LIR *lir = NewLIR3(kX86And32MI, rs_rX86_SP_32.GetReg(), displacement, 0x7fffffff);
Yixin Shou7071c8d2014-03-05 06:07:48 -0500652 AnnotateDalvikRegAccess(lir, displacement >> 2, false /*is_load */, false /* is_64bit */);
653 AnnotateDalvikRegAccess(lir, displacement >> 2, true /* is_load */, false /* is_64bit*/);
654 return true;
655 } else {
656 rl_src = LoadValue(rl_src, kCoreReg);
657 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
658 OpRegRegImm(kOpAnd, rl_result.reg, rl_src.reg, 0x7fffffff);
659 StoreValue(rl_dest, rl_result);
660 return true;
661 }
662}
663
664bool X86Mir2Lir::GenInlinedAbsDouble(CallInfo* info) {
665 RegLocation rl_src = info->args[0];
666 RegLocation rl_dest = InlineTargetWide(info);
667 DCHECK_NE(rl_src.s_reg_low, INVALID_SREG);
668 if (rl_dest.s_reg_low == INVALID_SREG) {
669 // Result is unused, the code is dead. Inlining successful, no code generated.
670 return true;
671 }
nikolay serdjukc5e4ce12014-06-10 17:07:10 +0700672 if (cu_->target64) {
673 rl_src = LoadValueWide(rl_src, kCoreReg);
674 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
675 OpRegCopyWide(rl_result.reg, rl_src.reg);
676 OpRegImm(kOpLsl, rl_result.reg, 1);
677 OpRegImm(kOpLsr, rl_result.reg, 1);
678 StoreValueWide(rl_dest, rl_result);
679 return true;
680 }
Yixin Shou7071c8d2014-03-05 06:07:48 -0500681 int v_src_reg = mir_graph_->SRegToVReg(rl_src.s_reg_low);
682 int v_dst_reg = mir_graph_->SRegToVReg(rl_dest.s_reg_low);
683 rl_src = UpdateLocWide(rl_src);
684
685 // if argument is in the physical XMM register
686 if (rl_src.location == kLocPhysReg && rl_src.reg.IsFloat()) {
687 RegLocation rl_result = EvalLoc(rl_dest, kFPReg, true);
688 if (rl_result.reg != rl_src.reg) {
689 LoadConstantWide(rl_result.reg, 0x7fffffffffffffff);
690 NewLIR2(kX86PandRR, rl_result.reg.GetReg(), rl_src.reg.GetReg());
691 } else {
692 RegStorage sign_mask = AllocTempDouble();
693 LoadConstantWide(sign_mask, 0x7fffffffffffffff);
694 NewLIR2(kX86PandRR, rl_result.reg.GetReg(), sign_mask.GetReg());
695 FreeTemp(sign_mask);
696 }
697 StoreValueWide(rl_dest, rl_result);
698 return true;
699 } else if (v_src_reg == v_dst_reg) {
700 // if argument is the same as inlined intrinsic target
701 // if argument is in the physical register
702 if (rl_src.location == kLocPhysReg) {
703 rl_src = LoadValueWide(rl_src, kCoreReg);
704 OpRegImm(kOpAnd, rl_src.reg.GetHigh(), 0x7fffffff);
705 StoreValueWide(rl_dest, rl_src);
706 return true;
707 }
708 // the argument is in memory
709 DCHECK((rl_src.location == kLocDalvikFrame) ||
710 (rl_src.location == kLocCompilerTemp));
711
712 // Operate directly into memory.
713 int displacement = SRegOffset(rl_dest.s_reg_low);
714 ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
Ian Rogersb28c1c02014-11-08 11:21:21 -0800715 LIR *lir = NewLIR3(kX86And32MI, rs_rX86_SP_32.GetReg(), displacement + HIWORD_OFFSET, 0x7fffffff);
Yixin Shou7071c8d2014-03-05 06:07:48 -0500716 AnnotateDalvikRegAccess(lir, (displacement + HIWORD_OFFSET) >> 2, true /* is_load */, true /* is_64bit*/);
717 AnnotateDalvikRegAccess(lir, (displacement + HIWORD_OFFSET) >> 2, false /*is_load */, true /* is_64bit */);
718 return true;
719 } else {
720 rl_src = LoadValueWide(rl_src, kCoreReg);
721 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
722 OpRegCopyWide(rl_result.reg, rl_src.reg);
723 OpRegImm(kOpAnd, rl_result.reg.GetHigh(), 0x7fffffff);
724 StoreValueWide(rl_dest, rl_result);
725 return true;
726 }
727}
Brian Carlstrom7940e442013-07-12 13:46:57 -0700728
Alexei Zavjalov1222c962014-07-16 00:54:13 +0700729bool X86Mir2Lir::GenInlinedMinMaxFP(CallInfo* info, bool is_min, bool is_double) {
730 if (is_double) {
Chao-ying Fuff87d7b2015-01-19 15:51:57 -0800731 RegLocation rl_dest = InlineTargetWide(info);
732 if (rl_dest.s_reg_low == INVALID_SREG) {
733 // Result is unused, the code is dead. Inlining successful, no code generated.
734 return true;
735 }
Alexei Zavjalov1222c962014-07-16 00:54:13 +0700736 RegLocation rl_src1 = LoadValueWide(info->args[0], kFPReg);
737 RegLocation rl_src2 = LoadValueWide(info->args[2], kFPReg);
Alexei Zavjalov1222c962014-07-16 00:54:13 +0700738 RegLocation rl_result = EvalLocWide(rl_dest, kFPReg, true);
739
740 // Avoid src2 corruption by OpRegCopyWide.
741 if (rl_result.reg == rl_src2.reg) {
742 std::swap(rl_src2.reg, rl_src1.reg);
743 }
744
745 OpRegCopyWide(rl_result.reg, rl_src1.reg);
746 NewLIR2(kX86UcomisdRR, rl_result.reg.GetReg(), rl_src2.reg.GetReg());
747 // If either arg is NaN, return NaN.
748 LIR* branch_nan = NewLIR2(kX86Jcc8, 0, kX86CondP);
749 // Min/Max branches.
750 LIR* branch_cond1 = NewLIR2(kX86Jcc8, 0, (is_min) ? kX86CondA : kX86CondB);
751 LIR* branch_cond2 = NewLIR2(kX86Jcc8, 0, (is_min) ? kX86CondB : kX86CondA);
752 // If equal, we need to resolve situations like min/max(0.0, -0.0) == -0.0/0.0.
753 NewLIR2((is_min) ? kX86OrpdRR : kX86AndpdRR, rl_result.reg.GetReg(), rl_src2.reg.GetReg());
754 LIR* branch_exit_equal = NewLIR1(kX86Jmp8, 0);
755 // Handle NaN.
756 branch_nan->target = NewLIR0(kPseudoTargetLabel);
757 LoadConstantWide(rl_result.reg, INT64_C(0x7ff8000000000000));
Razvan A Lupusorue5beb182014-08-14 13:49:57 +0800758
759 // The base_of_code_ compiler temp is non-null when it is reserved
760 // for being able to do data accesses relative to method start.
761 if (base_of_code_ != nullptr) {
762 // Loading from the constant pool may have used base of code register.
763 // However, the code here generates logic in diamond shape and not all
764 // paths load base of code register. Therefore, we ensure it is clobbered so
765 // that the temp caching system does not believe it is live at merge point.
766 RegLocation rl_method = mir_graph_->GetRegLocation(base_of_code_->s_reg_low);
767 if (rl_method.wide) {
768 rl_method = UpdateLocWide(rl_method);
769 } else {
770 rl_method = UpdateLoc(rl_method);
771 }
772 if (rl_method.location == kLocPhysReg) {
773 Clobber(rl_method.reg);
774 }
775 }
776
Alexei Zavjalov1222c962014-07-16 00:54:13 +0700777 LIR* branch_exit_nan = NewLIR1(kX86Jmp8, 0);
778 // Handle Min/Max. Copy greater/lesser value from src2.
779 branch_cond1->target = NewLIR0(kPseudoTargetLabel);
780 OpRegCopyWide(rl_result.reg, rl_src2.reg);
781 // Right operand is already in result reg.
782 branch_cond2->target = NewLIR0(kPseudoTargetLabel);
783 // Exit.
784 branch_exit_nan->target = NewLIR0(kPseudoTargetLabel);
785 branch_exit_equal->target = NewLIR0(kPseudoTargetLabel);
786 StoreValueWide(rl_dest, rl_result);
787 } else {
Chao-ying Fuff87d7b2015-01-19 15:51:57 -0800788 RegLocation rl_dest = InlineTarget(info);
789 if (rl_dest.s_reg_low == INVALID_SREG) {
790 // Result is unused, the code is dead. Inlining successful, no code generated.
791 return true;
792 }
Alexei Zavjalov1222c962014-07-16 00:54:13 +0700793 RegLocation rl_src1 = LoadValue(info->args[0], kFPReg);
794 RegLocation rl_src2 = LoadValue(info->args[1], kFPReg);
Alexei Zavjalov1222c962014-07-16 00:54:13 +0700795 RegLocation rl_result = EvalLoc(rl_dest, kFPReg, true);
796
797 // Avoid src2 corruption by OpRegCopyWide.
798 if (rl_result.reg == rl_src2.reg) {
799 std::swap(rl_src2.reg, rl_src1.reg);
800 }
801
802 OpRegCopy(rl_result.reg, rl_src1.reg);
803 NewLIR2(kX86UcomissRR, rl_result.reg.GetReg(), rl_src2.reg.GetReg());
804 // If either arg is NaN, return NaN.
805 LIR* branch_nan = NewLIR2(kX86Jcc8, 0, kX86CondP);
806 // Min/Max branches.
807 LIR* branch_cond1 = NewLIR2(kX86Jcc8, 0, (is_min) ? kX86CondA : kX86CondB);
808 LIR* branch_cond2 = NewLIR2(kX86Jcc8, 0, (is_min) ? kX86CondB : kX86CondA);
809 // If equal, we need to resolve situations like min/max(0.0, -0.0) == -0.0/0.0.
810 NewLIR2((is_min) ? kX86OrpsRR : kX86AndpsRR, rl_result.reg.GetReg(), rl_src2.reg.GetReg());
811 LIR* branch_exit_equal = NewLIR1(kX86Jmp8, 0);
812 // Handle NaN.
813 branch_nan->target = NewLIR0(kPseudoTargetLabel);
814 LoadConstantNoClobber(rl_result.reg, 0x7fc00000);
815 LIR* branch_exit_nan = NewLIR1(kX86Jmp8, 0);
816 // Handle Min/Max. Copy greater/lesser value from src2.
817 branch_cond1->target = NewLIR0(kPseudoTargetLabel);
818 OpRegCopy(rl_result.reg, rl_src2.reg);
819 // Right operand is already in result reg.
820 branch_cond2->target = NewLIR0(kPseudoTargetLabel);
821 // Exit.
822 branch_exit_nan->target = NewLIR0(kPseudoTargetLabel);
823 branch_exit_equal->target = NewLIR0(kPseudoTargetLabel);
824 StoreValue(rl_dest, rl_result);
825 }
826 return true;
827}
828
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700829} // namespace art