blob: 89c5648d0af0d3000a894c38f19ca0776966e635 [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"
buzbeeb5860fb2014-06-21 15:31:01 -070019#include "dex/reg_storage_eq.h"
Brian Carlstrom7940e442013-07-12 13:46:57 -070020#include "x86_lir.h"
21
22namespace art {
23
24void X86Mir2Lir::GenArithOpFloat(Instruction::Code opcode,
25 RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) {
26 X86OpCode op = kX86Nop;
27 RegLocation rl_result;
28
29 /*
30 * Don't attempt to optimize register usage since these opcodes call out to
31 * the handlers.
32 */
33 switch (opcode) {
34 case Instruction::ADD_FLOAT_2ADDR:
35 case Instruction::ADD_FLOAT:
36 op = kX86AddssRR;
37 break;
38 case Instruction::SUB_FLOAT_2ADDR:
39 case Instruction::SUB_FLOAT:
40 op = kX86SubssRR;
41 break;
42 case Instruction::DIV_FLOAT_2ADDR:
43 case Instruction::DIV_FLOAT:
44 op = kX86DivssRR;
45 break;
46 case Instruction::MUL_FLOAT_2ADDR:
47 case Instruction::MUL_FLOAT:
48 op = kX86MulssRR;
49 break;
50 case Instruction::REM_FLOAT_2ADDR:
51 case Instruction::REM_FLOAT:
Alexei Zavjalovbd3682e2014-06-12 03:08:01 +070052 GenRemFP(rl_dest, rl_src1, rl_src2, false /* is_double */);
Brian Carlstrom7940e442013-07-12 13:46:57 -070053 return;
54 case Instruction::NEG_FLOAT:
55 GenNegFloat(rl_dest, rl_src1);
56 return;
57 default:
58 LOG(FATAL) << "Unexpected opcode: " << opcode;
59 }
60 rl_src1 = LoadValue(rl_src1, kFPReg);
61 rl_src2 = LoadValue(rl_src2, kFPReg);
62 rl_result = EvalLoc(rl_dest, kFPReg, true);
buzbee2700f7e2014-03-07 09:46:20 -080063 RegStorage r_dest = rl_result.reg;
64 RegStorage r_src1 = rl_src1.reg;
65 RegStorage r_src2 = rl_src2.reg;
Brian Carlstrom7940e442013-07-12 13:46:57 -070066 if (r_dest == r_src2) {
buzbee091cc402014-03-31 10:14:40 -070067 r_src2 = AllocTempSingle();
Brian Carlstrom7940e442013-07-12 13:46:57 -070068 OpRegCopy(r_src2, r_dest);
69 }
70 OpRegCopy(r_dest, r_src1);
buzbee2700f7e2014-03-07 09:46:20 -080071 NewLIR2(op, r_dest.GetReg(), r_src2.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -070072 StoreValue(rl_dest, rl_result);
73}
74
75void X86Mir2Lir::GenArithOpDouble(Instruction::Code opcode,
76 RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) {
buzbee091cc402014-03-31 10:14:40 -070077 DCHECK(rl_dest.wide);
78 DCHECK(rl_dest.fp);
79 DCHECK(rl_src1.wide);
80 DCHECK(rl_src1.fp);
81 DCHECK(rl_src2.wide);
82 DCHECK(rl_src2.fp);
Brian Carlstrom7940e442013-07-12 13:46:57 -070083 X86OpCode op = kX86Nop;
84 RegLocation rl_result;
85
86 switch (opcode) {
87 case Instruction::ADD_DOUBLE_2ADDR:
88 case Instruction::ADD_DOUBLE:
89 op = kX86AddsdRR;
90 break;
91 case Instruction::SUB_DOUBLE_2ADDR:
92 case Instruction::SUB_DOUBLE:
93 op = kX86SubsdRR;
94 break;
95 case Instruction::DIV_DOUBLE_2ADDR:
96 case Instruction::DIV_DOUBLE:
97 op = kX86DivsdRR;
98 break;
99 case Instruction::MUL_DOUBLE_2ADDR:
100 case Instruction::MUL_DOUBLE:
101 op = kX86MulsdRR;
102 break;
103 case Instruction::REM_DOUBLE_2ADDR:
104 case Instruction::REM_DOUBLE:
Alexei Zavjalovbd3682e2014-06-12 03:08:01 +0700105 GenRemFP(rl_dest, rl_src1, rl_src2, true /* is_double */);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700106 return;
107 case Instruction::NEG_DOUBLE:
108 GenNegDouble(rl_dest, rl_src1);
109 return;
110 default:
111 LOG(FATAL) << "Unexpected opcode: " << opcode;
112 }
113 rl_src1 = LoadValueWide(rl_src1, kFPReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700114 rl_src2 = LoadValueWide(rl_src2, kFPReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700115 rl_result = EvalLoc(rl_dest, kFPReg, true);
buzbee091cc402014-03-31 10:14:40 -0700116 if (rl_result.reg == rl_src2.reg) {
117 rl_src2.reg = AllocTempDouble();
118 OpRegCopy(rl_src2.reg, rl_result.reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700119 }
buzbee091cc402014-03-31 10:14:40 -0700120 OpRegCopy(rl_result.reg, rl_src1.reg);
121 NewLIR2(op, rl_result.reg.GetReg(), rl_src2.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700122 StoreValueWide(rl_dest, rl_result);
123}
124
Ningsheng Jian675e09b2014-10-23 13:48:36 +0800125void X86Mir2Lir::GenMultiplyByConstantFloat(RegLocation rl_dest, RegLocation rl_src1,
126 int32_t constant) {
127 // TODO: need x86 implementation.
128 UNUSED(rl_dest, rl_src1, constant);
129 LOG(FATAL) << "Unimplemented GenMultiplyByConstantFloat in x86";
130}
131
132void X86Mir2Lir::GenMultiplyByConstantDouble(RegLocation rl_dest, RegLocation rl_src1,
133 int64_t constant) {
134 // TODO: need x86 implementation.
135 UNUSED(rl_dest, rl_src1, constant);
136 LOG(FATAL) << "Unimplemented GenMultiplyByConstantDouble in x86";
137}
138
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800139void X86Mir2Lir::GenLongToFP(RegLocation rl_dest, RegLocation rl_src, bool is_double) {
140 // Compute offsets to the source and destination VRs on stack
141 int src_v_reg_offset = SRegOffset(rl_src.s_reg_low);
142 int dest_v_reg_offset = SRegOffset(rl_dest.s_reg_low);
143
144 // Update the in-register state of source.
145 rl_src = UpdateLocWide(rl_src);
146
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100147 // All memory accesses below reference dalvik regs.
148 ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
149
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800150 // 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.
Ian Rogersb28c1c02014-11-08 11:21:21 -0800162 const RegStorage rs_rSP = cu_->target64 ? rs_rX86_SP_64 : rs_rX86_SP_32;
163 StoreBaseDisp(rs_rSP, src_v_reg_offset, rl_src.reg, k64, kNotVolatile);
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800164 }
165 }
166
167 // Push the source virtual register onto the x87 stack.
Ian Rogersb28c1c02014-11-08 11:21:21 -0800168 LIR *fild64 = NewLIR2NoDest(kX86Fild64M, rs_rX86_SP_32.GetReg(),
buzbee091cc402014-03-31 10:14:40 -0700169 src_v_reg_offset + LOWORD_OFFSET);
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800170 AnnotateDalvikRegAccess(fild64, (src_v_reg_offset + LOWORD_OFFSET) >> 2,
buzbee091cc402014-03-31 10:14:40 -0700171 true /* is_load */, true /* is64bit */);
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800172
173 // Now pop off x87 stack and store it in the destination VR's stack location.
174 int opcode = is_double ? kX86Fstp64M : kX86Fstp32M;
175 int displacement = is_double ? dest_v_reg_offset + LOWORD_OFFSET : dest_v_reg_offset;
Ian Rogersb28c1c02014-11-08 11:21:21 -0800176 LIR *fstp = NewLIR2NoDest(opcode, rs_rX86_SP_32.GetReg(), displacement);
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800177 AnnotateDalvikRegAccess(fstp, displacement >> 2, false /* is_load */, is_double);
178
179 /*
180 * The result is in a physical register if it was in a temp or was register
181 * promoted. For that reason it is enough to check if it is in physical
182 * register. If it is, then we must do all of the bookkeeping necessary to
183 * invalidate temp (if needed) and load in promoted register (if needed).
184 * If the result's location is in memory, then we do not need to do anything
185 * more since the fstp has already placed the correct value in memory.
186 */
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700187 RegLocation rl_result = is_double ? UpdateLocWideTyped(rl_dest) : UpdateLocTyped(rl_dest);
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 */
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100194 rl_result = EvalLoc(rl_dest, kFPReg, true);
Ian Rogersb28c1c02014-11-08 11:21:21 -0800195 const RegStorage rs_rSP = cu_->target64 ? rs_rX86_SP_64 : rs_rX86_SP_32;
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800196 if (is_double) {
Ian Rogersb28c1c02014-11-08 11:21:21 -0800197 LoadBaseDisp(rs_rSP, dest_v_reg_offset, rl_result.reg, k64, kNotVolatile);
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 {
Ian Rogersb28c1c02014-11-08 11:21:21 -0800201 Load32Disp(rs_rSP, dest_v_reg_offset, rl_result.reg);
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800202
Maxim Kazantsev51a80d72014-03-06 11:33:26 +0700203 StoreFinalValue(rl_dest, rl_result);
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800204 }
205 }
206}
207
Brian Carlstrom7940e442013-07-12 13:46:57 -0700208void X86Mir2Lir::GenConversion(Instruction::Code opcode, RegLocation rl_dest,
209 RegLocation rl_src) {
210 RegisterClass rcSrc = kFPReg;
211 X86OpCode op = kX86Nop;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700212 RegLocation rl_result;
213 switch (opcode) {
214 case Instruction::INT_TO_FLOAT:
215 rcSrc = kCoreReg;
216 op = kX86Cvtsi2ssRR;
217 break;
218 case Instruction::DOUBLE_TO_FLOAT:
219 rcSrc = kFPReg;
220 op = kX86Cvtsd2ssRR;
221 break;
222 case Instruction::FLOAT_TO_DOUBLE:
223 rcSrc = kFPReg;
224 op = kX86Cvtss2sdRR;
225 break;
226 case Instruction::INT_TO_DOUBLE:
227 rcSrc = kCoreReg;
228 op = kX86Cvtsi2sdRR;
229 break;
230 case Instruction::FLOAT_TO_INT: {
231 rl_src = LoadValue(rl_src, kFPReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700232 // In case result vreg is also src vreg, break association to avoid useless copy by EvalLoc()
233 ClobberSReg(rl_dest.s_reg_low);
234 rl_result = EvalLoc(rl_dest, kCoreReg, true);
buzbee091cc402014-03-31 10:14:40 -0700235 RegStorage temp_reg = AllocTempSingle();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700236
buzbee2700f7e2014-03-07 09:46:20 -0800237 LoadConstant(rl_result.reg, 0x7fffffff);
buzbee091cc402014-03-31 10:14:40 -0700238 NewLIR2(kX86Cvtsi2ssRR, temp_reg.GetReg(), rl_result.reg.GetReg());
239 NewLIR2(kX86ComissRR, rl_src.reg.GetReg(), temp_reg.GetReg());
Serguei Katkov5078d972014-06-20 16:45:52 +0700240 LIR* branch_pos_overflow = NewLIR2(kX86Jcc8, 0, kX86CondAe);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700241 LIR* branch_na_n = NewLIR2(kX86Jcc8, 0, kX86CondP);
buzbee091cc402014-03-31 10:14:40 -0700242 NewLIR2(kX86Cvttss2siRR, rl_result.reg.GetReg(), rl_src.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700243 LIR* branch_normal = NewLIR1(kX86Jmp8, 0);
244 branch_na_n->target = NewLIR0(kPseudoTargetLabel);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000245 NewLIR2(kX86Xor32RR, rl_result.reg.GetReg(), rl_result.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700246 branch_pos_overflow->target = NewLIR0(kPseudoTargetLabel);
247 branch_normal->target = NewLIR0(kPseudoTargetLabel);
248 StoreValue(rl_dest, rl_result);
249 return;
250 }
251 case Instruction::DOUBLE_TO_INT: {
252 rl_src = LoadValueWide(rl_src, kFPReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700253 // In case result vreg is also src vreg, break association to avoid useless copy by EvalLoc()
254 ClobberSReg(rl_dest.s_reg_low);
255 rl_result = EvalLoc(rl_dest, kCoreReg, true);
buzbee091cc402014-03-31 10:14:40 -0700256 RegStorage temp_reg = AllocTempDouble();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700257
buzbee2700f7e2014-03-07 09:46:20 -0800258 LoadConstant(rl_result.reg, 0x7fffffff);
buzbee091cc402014-03-31 10:14:40 -0700259 NewLIR2(kX86Cvtsi2sdRR, temp_reg.GetReg(), rl_result.reg.GetReg());
260 NewLIR2(kX86ComisdRR, rl_src.reg.GetReg(), temp_reg.GetReg());
Serguei Katkov5078d972014-06-20 16:45:52 +0700261 LIR* branch_pos_overflow = NewLIR2(kX86Jcc8, 0, kX86CondAe);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700262 LIR* branch_na_n = NewLIR2(kX86Jcc8, 0, kX86CondP);
buzbee091cc402014-03-31 10:14:40 -0700263 NewLIR2(kX86Cvttsd2siRR, rl_result.reg.GetReg(), rl_src.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700264 LIR* branch_normal = NewLIR1(kX86Jmp8, 0);
265 branch_na_n->target = NewLIR0(kPseudoTargetLabel);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000266 NewLIR2(kX86Xor32RR, rl_result.reg.GetReg(), rl_result.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700267 branch_pos_overflow->target = NewLIR0(kPseudoTargetLabel);
268 branch_normal->target = NewLIR0(kPseudoTargetLabel);
269 StoreValue(rl_dest, rl_result);
270 return;
271 }
272 case Instruction::LONG_TO_DOUBLE:
Elena Sayapinadd644502014-07-01 18:39:52 +0700273 if (cu_->target64) {
Chao-ying Fua0147762014-06-06 18:38:49 -0700274 rcSrc = kCoreReg;
275 op = kX86Cvtsqi2sdRR;
276 break;
277 }
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800278 GenLongToFP(rl_dest, rl_src, true /* is_double */);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700279 return;
280 case Instruction::LONG_TO_FLOAT:
Elena Sayapinadd644502014-07-01 18:39:52 +0700281 if (cu_->target64) {
Chao-ying Fua0147762014-06-06 18:38:49 -0700282 rcSrc = kCoreReg;
283 op = kX86Cvtsqi2ssRR;
284 break;
285 }
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800286 GenLongToFP(rl_dest, rl_src, false /* is_double */);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700287 return;
288 case Instruction::FLOAT_TO_LONG:
Elena Sayapinadd644502014-07-01 18:39:52 +0700289 if (cu_->target64) {
Chao-ying Fua0147762014-06-06 18:38:49 -0700290 rl_src = LoadValue(rl_src, kFPReg);
291 // If result vreg is also src vreg, break association to avoid useless copy by EvalLoc()
292 ClobberSReg(rl_dest.s_reg_low);
293 rl_result = EvalLoc(rl_dest, kCoreReg, true);
294 RegStorage temp_reg = AllocTempSingle();
295
296 // Set 0x7fffffffffffffff to rl_result
297 LoadConstantWide(rl_result.reg, 0x7fffffffffffffff);
298 NewLIR2(kX86Cvtsqi2ssRR, temp_reg.GetReg(), rl_result.reg.GetReg());
299 NewLIR2(kX86ComissRR, rl_src.reg.GetReg(), temp_reg.GetReg());
Serguei Katkov5078d972014-06-20 16:45:52 +0700300 LIR* branch_pos_overflow = NewLIR2(kX86Jcc8, 0, kX86CondAe);
Chao-ying Fua0147762014-06-06 18:38:49 -0700301 LIR* branch_na_n = NewLIR2(kX86Jcc8, 0, kX86CondP);
302 NewLIR2(kX86Cvttss2sqiRR, rl_result.reg.GetReg(), rl_src.reg.GetReg());
303 LIR* branch_normal = NewLIR1(kX86Jmp8, 0);
304 branch_na_n->target = NewLIR0(kPseudoTargetLabel);
305 NewLIR2(kX86Xor64RR, rl_result.reg.GetReg(), rl_result.reg.GetReg());
306 branch_pos_overflow->target = NewLIR0(kPseudoTargetLabel);
307 branch_normal->target = NewLIR0(kPseudoTargetLabel);
308 StoreValueWide(rl_dest, rl_result);
Dmitry Petrochenko9ee801f2014-05-12 11:31:37 +0700309 } else {
Andreas Gampe98430592014-07-27 19:44:50 -0700310 GenConversionCall(kQuickF2l, rl_dest, rl_src);
Dmitry Petrochenko9ee801f2014-05-12 11:31:37 +0700311 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700312 return;
313 case Instruction::DOUBLE_TO_LONG:
Elena Sayapinadd644502014-07-01 18:39:52 +0700314 if (cu_->target64) {
Chao-ying Fua0147762014-06-06 18:38:49 -0700315 rl_src = LoadValueWide(rl_src, kFPReg);
316 // If result vreg is also src vreg, break association to avoid useless copy by EvalLoc()
317 ClobberSReg(rl_dest.s_reg_low);
318 rl_result = EvalLoc(rl_dest, kCoreReg, true);
319 RegStorage temp_reg = AllocTempDouble();
320
321 // Set 0x7fffffffffffffff to rl_result
322 LoadConstantWide(rl_result.reg, 0x7fffffffffffffff);
323 NewLIR2(kX86Cvtsqi2sdRR, temp_reg.GetReg(), rl_result.reg.GetReg());
324 NewLIR2(kX86ComisdRR, rl_src.reg.GetReg(), temp_reg.GetReg());
Serguei Katkov5078d972014-06-20 16:45:52 +0700325 LIR* branch_pos_overflow = NewLIR2(kX86Jcc8, 0, kX86CondAe);
Chao-ying Fua0147762014-06-06 18:38:49 -0700326 LIR* branch_na_n = NewLIR2(kX86Jcc8, 0, kX86CondP);
327 NewLIR2(kX86Cvttsd2sqiRR, rl_result.reg.GetReg(), rl_src.reg.GetReg());
328 LIR* branch_normal = NewLIR1(kX86Jmp8, 0);
329 branch_na_n->target = NewLIR0(kPseudoTargetLabel);
330 NewLIR2(kX86Xor64RR, rl_result.reg.GetReg(), rl_result.reg.GetReg());
331 branch_pos_overflow->target = NewLIR0(kPseudoTargetLabel);
332 branch_normal->target = NewLIR0(kPseudoTargetLabel);
333 StoreValueWide(rl_dest, rl_result);
Dmitry Petrochenko9ee801f2014-05-12 11:31:37 +0700334 } else {
Andreas Gampe98430592014-07-27 19:44:50 -0700335 GenConversionCall(kQuickD2l, rl_dest, rl_src);
Dmitry Petrochenko9ee801f2014-05-12 11:31:37 +0700336 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700337 return;
338 default:
339 LOG(INFO) << "Unexpected opcode: " << opcode;
340 }
buzbee091cc402014-03-31 10:14:40 -0700341 // At this point, target will be either float or double.
342 DCHECK(rl_dest.fp);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700343 if (rl_src.wide) {
344 rl_src = LoadValueWide(rl_src, rcSrc);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700345 } else {
346 rl_src = LoadValue(rl_src, rcSrc);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700347 }
buzbee091cc402014-03-31 10:14:40 -0700348 rl_result = EvalLoc(rl_dest, kFPReg, true);
349 NewLIR2(op, rl_result.reg.GetReg(), rl_src.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700350 if (rl_dest.wide) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700351 StoreValueWide(rl_dest, rl_result);
352 } else {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700353 StoreValue(rl_dest, rl_result);
354 }
355}
356
Alexei Zavjalovbd3682e2014-06-12 03:08:01 +0700357void X86Mir2Lir::GenRemFP(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2, bool is_double) {
358 // Compute offsets to the source and destination VRs on stack.
359 int src1_v_reg_offset = SRegOffset(rl_src1.s_reg_low);
360 int src2_v_reg_offset = SRegOffset(rl_src2.s_reg_low);
361 int dest_v_reg_offset = SRegOffset(rl_dest.s_reg_low);
362
363 // Update the in-register state of sources.
364 rl_src1 = is_double ? UpdateLocWide(rl_src1) : UpdateLoc(rl_src1);
365 rl_src2 = is_double ? UpdateLocWide(rl_src2) : UpdateLoc(rl_src2);
366
367 // All memory accesses below reference dalvik regs.
368 ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
369
370 // If the source is in physical register, then put it in its location on stack.
Ian Rogersb28c1c02014-11-08 11:21:21 -0800371 const RegStorage rs_rSP = cu_->target64 ? rs_rX86_SP_64 : rs_rX86_SP_32;
Alexei Zavjalovbd3682e2014-06-12 03:08:01 +0700372 if (rl_src1.location == kLocPhysReg) {
373 RegisterInfo* reg_info = GetRegInfo(rl_src1.reg);
374
375 if (reg_info != nullptr && reg_info->IsTemp()) {
376 // Calling FlushSpecificReg because it will only write back VR if it is dirty.
377 FlushSpecificReg(reg_info);
378 // ResetDef to prevent NullifyRange from removing stores.
379 ResetDef(rl_src1.reg);
380 } else {
381 // It must have been register promoted if it is not a temp but is still in physical
382 // register. Since we need it to be in memory to convert, we place it there now.
Ian Rogersb28c1c02014-11-08 11:21:21 -0800383 StoreBaseDisp(rs_rSP, src1_v_reg_offset, rl_src1.reg, is_double ? k64 : k32,
Andreas Gampe3c12c512014-06-24 18:46:29 +0000384 kNotVolatile);
Alexei Zavjalovbd3682e2014-06-12 03:08:01 +0700385 }
386 }
387
388 if (rl_src2.location == kLocPhysReg) {
389 RegisterInfo* reg_info = GetRegInfo(rl_src2.reg);
390 if (reg_info != nullptr && reg_info->IsTemp()) {
391 FlushSpecificReg(reg_info);
392 ResetDef(rl_src2.reg);
393 } else {
Ian Rogersb28c1c02014-11-08 11:21:21 -0800394 StoreBaseDisp(rs_rSP, src2_v_reg_offset, rl_src2.reg, is_double ? k64 : k32,
Andreas Gampe3c12c512014-06-24 18:46:29 +0000395 kNotVolatile);
Alexei Zavjalovbd3682e2014-06-12 03:08:01 +0700396 }
397 }
398
399 int fld_opcode = is_double ? kX86Fld64M : kX86Fld32M;
400
401 // Push the source virtual registers onto the x87 stack.
Ian Rogersb28c1c02014-11-08 11:21:21 -0800402 LIR *fld_2 = NewLIR2NoDest(fld_opcode, rs_rSP.GetReg(),
Alexei Zavjalovbd3682e2014-06-12 03:08:01 +0700403 src2_v_reg_offset + LOWORD_OFFSET);
404 AnnotateDalvikRegAccess(fld_2, (src2_v_reg_offset + LOWORD_OFFSET) >> 2,
405 true /* is_load */, is_double /* is64bit */);
406
Ian Rogersb28c1c02014-11-08 11:21:21 -0800407 LIR *fld_1 = NewLIR2NoDest(fld_opcode, rs_rSP.GetReg(),
Alexei Zavjalovbd3682e2014-06-12 03:08:01 +0700408 src1_v_reg_offset + LOWORD_OFFSET);
409 AnnotateDalvikRegAccess(fld_1, (src1_v_reg_offset + LOWORD_OFFSET) >> 2,
410 true /* is_load */, is_double /* is64bit */);
411
412 FlushReg(rs_rAX);
413 Clobber(rs_rAX);
414 LockTemp(rs_rAX);
415
416 LIR* retry = NewLIR0(kPseudoTargetLabel);
417
418 // Divide ST(0) by ST(1) and place result to ST(0).
419 NewLIR0(kX86Fprem);
420
421 // Move FPU status word to AX.
422 NewLIR0(kX86Fstsw16R);
423
424 // Check if reduction is complete.
425 OpRegImm(kOpAnd, rs_rAX, 0x400);
426
427 // If no then continue to compute remainder.
428 LIR* branch = NewLIR2(kX86Jcc8, 0, kX86CondNe);
429 branch->target = retry;
430
431 FreeTemp(rs_rAX);
432
433 // Now store result in the destination VR's stack location.
434 int displacement = dest_v_reg_offset + LOWORD_OFFSET;
435 int opcode = is_double ? kX86Fst64M : kX86Fst32M;
Ian Rogersb28c1c02014-11-08 11:21:21 -0800436 LIR *fst = NewLIR2NoDest(opcode, rs_rSP.GetReg(), displacement);
Alexei Zavjalovbd3682e2014-06-12 03:08:01 +0700437 AnnotateDalvikRegAccess(fst, displacement >> 2, false /* is_load */, is_double /* is64bit */);
438
439 // Pop ST(1) and ST(0).
440 NewLIR0(kX86Fucompp);
441
442 /*
443 * The result is in a physical register if it was in a temp or was register
444 * promoted. For that reason it is enough to check if it is in physical
445 * register. If it is, then we must do all of the bookkeeping necessary to
446 * invalidate temp (if needed) and load in promoted register (if needed).
447 * If the result's location is in memory, then we do not need to do anything
448 * more since the fstp has already placed the correct value in memory.
449 */
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700450 RegLocation rl_result = is_double ? UpdateLocWideTyped(rl_dest) : UpdateLocTyped(rl_dest);
Alexei Zavjalovbd3682e2014-06-12 03:08:01 +0700451 if (rl_result.location == kLocPhysReg) {
452 rl_result = EvalLoc(rl_dest, kFPReg, true);
453 if (is_double) {
Ian Rogersb28c1c02014-11-08 11:21:21 -0800454 LoadBaseDisp(rs_rSP, dest_v_reg_offset, rl_result.reg, k64, kNotVolatile);
Alexei Zavjalovbd3682e2014-06-12 03:08:01 +0700455 StoreFinalValueWide(rl_dest, rl_result);
456 } else {
Ian Rogersb28c1c02014-11-08 11:21:21 -0800457 Load32Disp(rs_rSP, dest_v_reg_offset, rl_result.reg);
Alexei Zavjalovbd3682e2014-06-12 03:08:01 +0700458 StoreFinalValue(rl_dest, rl_result);
459 }
460 }
461}
462
Brian Carlstrom7940e442013-07-12 13:46:57 -0700463void X86Mir2Lir::GenCmpFP(Instruction::Code code, RegLocation rl_dest,
464 RegLocation rl_src1, RegLocation rl_src2) {
465 bool single = (code == Instruction::CMPL_FLOAT) || (code == Instruction::CMPG_FLOAT);
466 bool unordered_gt = (code == Instruction::CMPG_DOUBLE) || (code == Instruction::CMPG_FLOAT);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700467 if (single) {
468 rl_src1 = LoadValue(rl_src1, kFPReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700469 rl_src2 = LoadValue(rl_src2, kFPReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700470 } else {
471 rl_src1 = LoadValueWide(rl_src1, kFPReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700472 rl_src2 = LoadValueWide(rl_src2, kFPReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700473 }
474 // In case result vreg is also src vreg, break association to avoid useless copy by EvalLoc()
475 ClobberSReg(rl_dest.s_reg_low);
476 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
buzbee2700f7e2014-03-07 09:46:20 -0800477 LoadConstantNoClobber(rl_result.reg, unordered_gt ? 1 : 0);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700478 if (single) {
buzbee091cc402014-03-31 10:14:40 -0700479 NewLIR2(kX86UcomissRR, rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700480 } else {
buzbee091cc402014-03-31 10:14:40 -0700481 NewLIR2(kX86UcomisdRR, rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700482 }
483 LIR* branch = NULL;
484 if (unordered_gt) {
485 branch = NewLIR2(kX86Jcc8, 0, kX86CondPE);
486 }
487 // 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 -0700488 if (!IsByteRegister(rl_result.reg)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700489 LIR* branch2 = NULL;
490 if (unordered_gt) {
491 branch2 = NewLIR2(kX86Jcc8, 0, kX86CondA);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000492 NewLIR2(kX86Mov32RI, rl_result.reg.GetReg(), 0x0);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700493 } else {
494 branch2 = NewLIR2(kX86Jcc8, 0, kX86CondBe);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000495 NewLIR2(kX86Mov32RI, rl_result.reg.GetReg(), 0x1);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700496 }
497 branch2->target = NewLIR0(kPseudoTargetLabel);
498 } else {
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000499 NewLIR2(kX86Set8R, rl_result.reg.GetReg(), kX86CondA /* above - unsigned > */);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700500 }
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000501 NewLIR2(kX86Sbb32RI, rl_result.reg.GetReg(), 0);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700502 if (unordered_gt) {
503 branch->target = NewLIR0(kPseudoTargetLabel);
504 }
505 StoreValue(rl_dest, rl_result);
506}
507
508void X86Mir2Lir::GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias,
509 bool is_double) {
buzbee0d829482013-10-11 15:24:55 -0700510 LIR* taken = &block_label_list_[bb->taken];
511 LIR* not_taken = &block_label_list_[bb->fall_through];
Brian Carlstrom7940e442013-07-12 13:46:57 -0700512 LIR* branch = NULL;
513 RegLocation rl_src1;
514 RegLocation rl_src2;
515 if (is_double) {
516 rl_src1 = mir_graph_->GetSrcWide(mir, 0);
517 rl_src2 = mir_graph_->GetSrcWide(mir, 2);
518 rl_src1 = LoadValueWide(rl_src1, kFPReg);
519 rl_src2 = LoadValueWide(rl_src2, kFPReg);
buzbee091cc402014-03-31 10:14:40 -0700520 NewLIR2(kX86UcomisdRR, rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700521 } else {
522 rl_src1 = mir_graph_->GetSrc(mir, 0);
523 rl_src2 = mir_graph_->GetSrc(mir, 1);
524 rl_src1 = LoadValue(rl_src1, kFPReg);
525 rl_src2 = LoadValue(rl_src2, kFPReg);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000526 NewLIR2(kX86UcomissRR, rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700527 }
Vladimir Markoa8946072014-01-22 10:30:44 +0000528 ConditionCode ccode = mir->meta.ccode;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700529 switch (ccode) {
530 case kCondEq:
531 if (!gt_bias) {
532 branch = NewLIR2(kX86Jcc8, 0, kX86CondPE);
533 branch->target = not_taken;
534 }
535 break;
536 case kCondNe:
537 if (!gt_bias) {
538 branch = NewLIR2(kX86Jcc8, 0, kX86CondPE);
539 branch->target = taken;
540 }
541 break;
542 case kCondLt:
543 if (gt_bias) {
544 branch = NewLIR2(kX86Jcc8, 0, kX86CondPE);
545 branch->target = not_taken;
546 }
Vladimir Marko58af1f92013-12-19 13:31:15 +0000547 ccode = kCondUlt;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700548 break;
549 case kCondLe:
550 if (gt_bias) {
551 branch = NewLIR2(kX86Jcc8, 0, kX86CondPE);
552 branch->target = not_taken;
553 }
554 ccode = kCondLs;
555 break;
556 case kCondGt:
557 if (gt_bias) {
558 branch = NewLIR2(kX86Jcc8, 0, kX86CondPE);
559 branch->target = taken;
560 }
561 ccode = kCondHi;
562 break;
563 case kCondGe:
564 if (gt_bias) {
565 branch = NewLIR2(kX86Jcc8, 0, kX86CondPE);
566 branch->target = taken;
567 }
Vladimir Marko58af1f92013-12-19 13:31:15 +0000568 ccode = kCondUge;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700569 break;
570 default:
571 LOG(FATAL) << "Unexpected ccode: " << ccode;
572 }
573 OpCondBranch(ccode, taken);
574}
575
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700576void X86Mir2Lir::GenNegFloat(RegLocation rl_dest, RegLocation rl_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700577 RegLocation rl_result;
578 rl_src = LoadValue(rl_src, kCoreReg);
579 rl_result = EvalLoc(rl_dest, kCoreReg, true);
buzbee2700f7e2014-03-07 09:46:20 -0800580 OpRegRegImm(kOpAdd, rl_result.reg, rl_src.reg, 0x80000000);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700581 StoreValue(rl_dest, rl_result);
582}
583
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700584void X86Mir2Lir::GenNegDouble(RegLocation rl_dest, RegLocation rl_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700585 RegLocation rl_result;
586 rl_src = LoadValueWide(rl_src, kCoreReg);
Elena Sayapinadd644502014-07-01 18:39:52 +0700587 if (cu_->target64) {
Pavel Vyssotskid4812a92014-11-11 12:37:56 +0600588 rl_result = EvalLocWide(rl_dest, kCoreReg, true);
Alexei Zavjalov02959ea2014-06-18 17:18:36 +0700589 OpRegCopy(rl_result.reg, rl_src.reg);
590 // Flip sign bit.
591 NewLIR2(kX86Rol64RI, rl_result.reg.GetReg(), 1);
592 NewLIR2(kX86Xor64RI, rl_result.reg.GetReg(), 1);
593 NewLIR2(kX86Ror64RI, rl_result.reg.GetReg(), 1);
Chao-ying Fua0147762014-06-06 18:38:49 -0700594 } else {
Pavel Vyssotskid4812a92014-11-11 12:37:56 +0600595 rl_result = ForceTempWide(rl_src);
596 OpRegRegImm(kOpAdd, rl_result.reg.GetHigh(), rl_result.reg.GetHigh(), 0x80000000);
Chao-ying Fua0147762014-06-06 18:38:49 -0700597 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700598 StoreValueWide(rl_dest, rl_result);
599}
600
601bool X86Mir2Lir::GenInlinedSqrt(CallInfo* info) {
Mark Mendellbff1ef02013-12-13 13:47:34 -0800602 RegLocation rl_dest = InlineTargetWide(info); // double place for result
Chao-ying Fuff87d7b2015-01-19 15:51:57 -0800603 if (rl_dest.s_reg_low == INVALID_SREG) {
604 // Result is unused, the code is dead. Inlining successful, no code generated.
605 return true;
606 }
607 RegLocation rl_src = info->args[0];
Mark Mendellbff1ef02013-12-13 13:47:34 -0800608 rl_src = LoadValueWide(rl_src, kFPReg);
609 RegLocation rl_result = EvalLoc(rl_dest, kFPReg, true);
buzbee091cc402014-03-31 10:14:40 -0700610 NewLIR2(kX86SqrtsdRR, rl_result.reg.GetReg(), rl_src.reg.GetReg());
Mark Mendellbff1ef02013-12-13 13:47:34 -0800611 StoreValueWide(rl_dest, rl_result);
612 return true;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700613}
614
Yixin Shou7071c8d2014-03-05 06:07:48 -0500615bool X86Mir2Lir::GenInlinedAbsFloat(CallInfo* info) {
616 // Get the argument
617 RegLocation rl_src = info->args[0];
618
619 // Get the inlined intrinsic target virtual register
620 RegLocation rl_dest = InlineTarget(info);
621
622 // Get the virtual register number
623 DCHECK_NE(rl_src.s_reg_low, INVALID_SREG);
624 if (rl_dest.s_reg_low == INVALID_SREG) {
625 // Result is unused, the code is dead. Inlining successful, no code generated.
626 return true;
627 }
628 int v_src_reg = mir_graph_->SRegToVReg(rl_src.s_reg_low);
629 int v_dst_reg = mir_graph_->SRegToVReg(rl_dest.s_reg_low);
630
631 // if argument is the same as inlined intrinsic target
632 if (v_src_reg == v_dst_reg) {
633 rl_src = UpdateLoc(rl_src);
634
635 // if argument is in the physical register
636 if (rl_src.location == kLocPhysReg) {
637 rl_src = LoadValue(rl_src, kCoreReg);
638 OpRegImm(kOpAnd, rl_src.reg, 0x7fffffff);
639 StoreValue(rl_dest, rl_src);
640 return true;
641 }
642 // the argument is in memory
643 DCHECK((rl_src.location == kLocDalvikFrame) ||
644 (rl_src.location == kLocCompilerTemp));
645
646 // Operate directly into memory.
647 int displacement = SRegOffset(rl_dest.s_reg_low);
648 ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
Ian Rogersb28c1c02014-11-08 11:21:21 -0800649 LIR *lir = NewLIR3(kX86And32MI, rs_rX86_SP_32.GetReg(), displacement, 0x7fffffff);
Yixin Shou7071c8d2014-03-05 06:07:48 -0500650 AnnotateDalvikRegAccess(lir, displacement >> 2, false /*is_load */, false /* is_64bit */);
651 AnnotateDalvikRegAccess(lir, displacement >> 2, true /* is_load */, false /* is_64bit*/);
652 return true;
653 } else {
654 rl_src = LoadValue(rl_src, kCoreReg);
655 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
656 OpRegRegImm(kOpAnd, rl_result.reg, rl_src.reg, 0x7fffffff);
657 StoreValue(rl_dest, rl_result);
658 return true;
659 }
660}
661
662bool X86Mir2Lir::GenInlinedAbsDouble(CallInfo* info) {
663 RegLocation rl_src = info->args[0];
664 RegLocation rl_dest = InlineTargetWide(info);
665 DCHECK_NE(rl_src.s_reg_low, INVALID_SREG);
666 if (rl_dest.s_reg_low == INVALID_SREG) {
667 // Result is unused, the code is dead. Inlining successful, no code generated.
668 return true;
669 }
nikolay serdjukc5e4ce12014-06-10 17:07:10 +0700670 if (cu_->target64) {
671 rl_src = LoadValueWide(rl_src, kCoreReg);
672 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
673 OpRegCopyWide(rl_result.reg, rl_src.reg);
674 OpRegImm(kOpLsl, rl_result.reg, 1);
675 OpRegImm(kOpLsr, rl_result.reg, 1);
676 StoreValueWide(rl_dest, rl_result);
677 return true;
678 }
Yixin Shou7071c8d2014-03-05 06:07:48 -0500679 int v_src_reg = mir_graph_->SRegToVReg(rl_src.s_reg_low);
680 int v_dst_reg = mir_graph_->SRegToVReg(rl_dest.s_reg_low);
681 rl_src = UpdateLocWide(rl_src);
682
683 // if argument is in the physical XMM register
684 if (rl_src.location == kLocPhysReg && rl_src.reg.IsFloat()) {
685 RegLocation rl_result = EvalLoc(rl_dest, kFPReg, true);
686 if (rl_result.reg != rl_src.reg) {
687 LoadConstantWide(rl_result.reg, 0x7fffffffffffffff);
688 NewLIR2(kX86PandRR, rl_result.reg.GetReg(), rl_src.reg.GetReg());
689 } else {
690 RegStorage sign_mask = AllocTempDouble();
691 LoadConstantWide(sign_mask, 0x7fffffffffffffff);
692 NewLIR2(kX86PandRR, rl_result.reg.GetReg(), sign_mask.GetReg());
693 FreeTemp(sign_mask);
694 }
695 StoreValueWide(rl_dest, rl_result);
696 return true;
697 } else if (v_src_reg == v_dst_reg) {
698 // if argument is the same as inlined intrinsic target
699 // if argument is in the physical register
700 if (rl_src.location == kLocPhysReg) {
701 rl_src = LoadValueWide(rl_src, kCoreReg);
702 OpRegImm(kOpAnd, rl_src.reg.GetHigh(), 0x7fffffff);
703 StoreValueWide(rl_dest, rl_src);
704 return true;
705 }
706 // the argument is in memory
707 DCHECK((rl_src.location == kLocDalvikFrame) ||
708 (rl_src.location == kLocCompilerTemp));
709
710 // Operate directly into memory.
711 int displacement = SRegOffset(rl_dest.s_reg_low);
712 ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
Ian Rogersb28c1c02014-11-08 11:21:21 -0800713 LIR *lir = NewLIR3(kX86And32MI, rs_rX86_SP_32.GetReg(), displacement + HIWORD_OFFSET, 0x7fffffff);
Yixin Shou7071c8d2014-03-05 06:07:48 -0500714 AnnotateDalvikRegAccess(lir, (displacement + HIWORD_OFFSET) >> 2, true /* is_load */, true /* is_64bit*/);
715 AnnotateDalvikRegAccess(lir, (displacement + HIWORD_OFFSET) >> 2, false /*is_load */, true /* is_64bit */);
716 return true;
717 } else {
718 rl_src = LoadValueWide(rl_src, kCoreReg);
719 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
720 OpRegCopyWide(rl_result.reg, rl_src.reg);
721 OpRegImm(kOpAnd, rl_result.reg.GetHigh(), 0x7fffffff);
722 StoreValueWide(rl_dest, rl_result);
723 return true;
724 }
725}
Brian Carlstrom7940e442013-07-12 13:46:57 -0700726
Alexei Zavjalov1222c962014-07-16 00:54:13 +0700727bool X86Mir2Lir::GenInlinedMinMaxFP(CallInfo* info, bool is_min, bool is_double) {
728 if (is_double) {
Chao-ying Fuff87d7b2015-01-19 15:51:57 -0800729 RegLocation rl_dest = InlineTargetWide(info);
730 if (rl_dest.s_reg_low == INVALID_SREG) {
731 // Result is unused, the code is dead. Inlining successful, no code generated.
732 return true;
733 }
Alexei Zavjalov1222c962014-07-16 00:54:13 +0700734 RegLocation rl_src1 = LoadValueWide(info->args[0], kFPReg);
735 RegLocation rl_src2 = LoadValueWide(info->args[2], kFPReg);
Alexei Zavjalov1222c962014-07-16 00:54:13 +0700736 RegLocation rl_result = EvalLocWide(rl_dest, kFPReg, true);
737
738 // Avoid src2 corruption by OpRegCopyWide.
739 if (rl_result.reg == rl_src2.reg) {
740 std::swap(rl_src2.reg, rl_src1.reg);
741 }
742
743 OpRegCopyWide(rl_result.reg, rl_src1.reg);
744 NewLIR2(kX86UcomisdRR, rl_result.reg.GetReg(), rl_src2.reg.GetReg());
745 // If either arg is NaN, return NaN.
746 LIR* branch_nan = NewLIR2(kX86Jcc8, 0, kX86CondP);
747 // Min/Max branches.
748 LIR* branch_cond1 = NewLIR2(kX86Jcc8, 0, (is_min) ? kX86CondA : kX86CondB);
749 LIR* branch_cond2 = NewLIR2(kX86Jcc8, 0, (is_min) ? kX86CondB : kX86CondA);
750 // If equal, we need to resolve situations like min/max(0.0, -0.0) == -0.0/0.0.
751 NewLIR2((is_min) ? kX86OrpdRR : kX86AndpdRR, rl_result.reg.GetReg(), rl_src2.reg.GetReg());
752 LIR* branch_exit_equal = NewLIR1(kX86Jmp8, 0);
753 // Handle NaN.
754 branch_nan->target = NewLIR0(kPseudoTargetLabel);
755 LoadConstantWide(rl_result.reg, INT64_C(0x7ff8000000000000));
Razvan A Lupusorue5beb182014-08-14 13:49:57 +0800756
757 // The base_of_code_ compiler temp is non-null when it is reserved
758 // for being able to do data accesses relative to method start.
759 if (base_of_code_ != nullptr) {
760 // Loading from the constant pool may have used base of code register.
761 // However, the code here generates logic in diamond shape and not all
762 // paths load base of code register. Therefore, we ensure it is clobbered so
763 // that the temp caching system does not believe it is live at merge point.
764 RegLocation rl_method = mir_graph_->GetRegLocation(base_of_code_->s_reg_low);
765 if (rl_method.wide) {
766 rl_method = UpdateLocWide(rl_method);
767 } else {
768 rl_method = UpdateLoc(rl_method);
769 }
770 if (rl_method.location == kLocPhysReg) {
771 Clobber(rl_method.reg);
772 }
773 }
774
Alexei Zavjalov1222c962014-07-16 00:54:13 +0700775 LIR* branch_exit_nan = NewLIR1(kX86Jmp8, 0);
776 // Handle Min/Max. Copy greater/lesser value from src2.
777 branch_cond1->target = NewLIR0(kPseudoTargetLabel);
778 OpRegCopyWide(rl_result.reg, rl_src2.reg);
779 // Right operand is already in result reg.
780 branch_cond2->target = NewLIR0(kPseudoTargetLabel);
781 // Exit.
782 branch_exit_nan->target = NewLIR0(kPseudoTargetLabel);
783 branch_exit_equal->target = NewLIR0(kPseudoTargetLabel);
784 StoreValueWide(rl_dest, rl_result);
785 } else {
Chao-ying Fuff87d7b2015-01-19 15:51:57 -0800786 RegLocation rl_dest = InlineTarget(info);
787 if (rl_dest.s_reg_low == INVALID_SREG) {
788 // Result is unused, the code is dead. Inlining successful, no code generated.
789 return true;
790 }
Alexei Zavjalov1222c962014-07-16 00:54:13 +0700791 RegLocation rl_src1 = LoadValue(info->args[0], kFPReg);
792 RegLocation rl_src2 = LoadValue(info->args[1], kFPReg);
Alexei Zavjalov1222c962014-07-16 00:54:13 +0700793 RegLocation rl_result = EvalLoc(rl_dest, kFPReg, true);
794
795 // Avoid src2 corruption by OpRegCopyWide.
796 if (rl_result.reg == rl_src2.reg) {
797 std::swap(rl_src2.reg, rl_src1.reg);
798 }
799
800 OpRegCopy(rl_result.reg, rl_src1.reg);
801 NewLIR2(kX86UcomissRR, rl_result.reg.GetReg(), rl_src2.reg.GetReg());
802 // If either arg is NaN, return NaN.
803 LIR* branch_nan = NewLIR2(kX86Jcc8, 0, kX86CondP);
804 // Min/Max branches.
805 LIR* branch_cond1 = NewLIR2(kX86Jcc8, 0, (is_min) ? kX86CondA : kX86CondB);
806 LIR* branch_cond2 = NewLIR2(kX86Jcc8, 0, (is_min) ? kX86CondB : kX86CondA);
807 // If equal, we need to resolve situations like min/max(0.0, -0.0) == -0.0/0.0.
808 NewLIR2((is_min) ? kX86OrpsRR : kX86AndpsRR, rl_result.reg.GetReg(), rl_src2.reg.GetReg());
809 LIR* branch_exit_equal = NewLIR1(kX86Jmp8, 0);
810 // Handle NaN.
811 branch_nan->target = NewLIR0(kPseudoTargetLabel);
812 LoadConstantNoClobber(rl_result.reg, 0x7fc00000);
813 LIR* branch_exit_nan = NewLIR1(kX86Jmp8, 0);
814 // Handle Min/Max. Copy greater/lesser value from src2.
815 branch_cond1->target = NewLIR0(kPseudoTargetLabel);
816 OpRegCopy(rl_result.reg, rl_src2.reg);
817 // Right operand is already in result reg.
818 branch_cond2->target = NewLIR0(kPseudoTargetLabel);
819 // Exit.
820 branch_exit_nan->target = NewLIR0(kPseudoTargetLabel);
821 branch_exit_equal->target = NewLIR0(kPseudoTargetLabel);
822 StoreValue(rl_dest, rl_result);
823 }
824 return true;
825}
826
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700827} // namespace art