blob: 254d90fa8c69208cf6e634823e9a3cfe762a3018 [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
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800125void X86Mir2Lir::GenLongToFP(RegLocation rl_dest, RegLocation rl_src, bool is_double) {
126 // Compute offsets to the source and destination VRs on stack
127 int src_v_reg_offset = SRegOffset(rl_src.s_reg_low);
128 int dest_v_reg_offset = SRegOffset(rl_dest.s_reg_low);
129
130 // Update the in-register state of source.
131 rl_src = UpdateLocWide(rl_src);
132
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100133 // All memory accesses below reference dalvik regs.
134 ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
135
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800136 // If the source is in physical register, then put it in its location on stack.
137 if (rl_src.location == kLocPhysReg) {
buzbee091cc402014-03-31 10:14:40 -0700138 RegisterInfo* reg_info = GetRegInfo(rl_src.reg);
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800139
buzbee091cc402014-03-31 10:14:40 -0700140 if (reg_info != nullptr && reg_info->IsTemp()) {
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800141 // Calling FlushSpecificReg because it will only write back VR if it is dirty.
buzbee091cc402014-03-31 10:14:40 -0700142 FlushSpecificReg(reg_info);
143 // ResetDef to prevent NullifyRange from removing stores.
144 ResetDef(rl_src.reg);
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800145 } else {
146 // It must have been register promoted if it is not a temp but is still in physical
147 // register. Since we need it to be in memory to convert, we place it there now.
Chao-ying Fua77ee512014-07-01 17:43:41 -0700148 StoreBaseDisp(rs_rX86_SP, src_v_reg_offset, rl_src.reg, k64, kNotVolatile);
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800149 }
150 }
151
152 // Push the source virtual register onto the x87 stack.
Chao-ying Fua77ee512014-07-01 17:43:41 -0700153 LIR *fild64 = NewLIR2NoDest(kX86Fild64M, rs_rX86_SP.GetReg(),
buzbee091cc402014-03-31 10:14:40 -0700154 src_v_reg_offset + LOWORD_OFFSET);
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800155 AnnotateDalvikRegAccess(fild64, (src_v_reg_offset + LOWORD_OFFSET) >> 2,
buzbee091cc402014-03-31 10:14:40 -0700156 true /* is_load */, true /* is64bit */);
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800157
158 // Now pop off x87 stack and store it in the destination VR's stack location.
159 int opcode = is_double ? kX86Fstp64M : kX86Fstp32M;
160 int displacement = is_double ? dest_v_reg_offset + LOWORD_OFFSET : dest_v_reg_offset;
Chao-ying Fua77ee512014-07-01 17:43:41 -0700161 LIR *fstp = NewLIR2NoDest(opcode, rs_rX86_SP.GetReg(), displacement);
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800162 AnnotateDalvikRegAccess(fstp, displacement >> 2, false /* is_load */, is_double);
163
164 /*
165 * The result is in a physical register if it was in a temp or was register
166 * promoted. For that reason it is enough to check if it is in physical
167 * register. If it is, then we must do all of the bookkeeping necessary to
168 * invalidate temp (if needed) and load in promoted register (if needed).
169 * If the result's location is in memory, then we do not need to do anything
170 * more since the fstp has already placed the correct value in memory.
171 */
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700172 RegLocation rl_result = is_double ? UpdateLocWideTyped(rl_dest) : UpdateLocTyped(rl_dest);
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800173 if (rl_result.location == kLocPhysReg) {
174 /*
175 * We already know that the result is in a physical register but do not know if it is the
176 * right class. So we call EvalLoc(Wide) first which will ensure that it will get moved to the
177 * correct register class.
178 */
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100179 rl_result = EvalLoc(rl_dest, kFPReg, true);
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800180 if (is_double) {
Chao-ying Fua77ee512014-07-01 17:43:41 -0700181 LoadBaseDisp(rs_rX86_SP, dest_v_reg_offset, rl_result.reg, k64, kNotVolatile);
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800182
Maxim Kazantsev51a80d72014-03-06 11:33:26 +0700183 StoreFinalValueWide(rl_dest, rl_result);
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800184 } else {
Chao-ying Fua77ee512014-07-01 17:43:41 -0700185 Load32Disp(rs_rX86_SP, dest_v_reg_offset, rl_result.reg);
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800186
Maxim Kazantsev51a80d72014-03-06 11:33:26 +0700187 StoreFinalValue(rl_dest, rl_result);
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800188 }
189 }
190}
191
Brian Carlstrom7940e442013-07-12 13:46:57 -0700192void X86Mir2Lir::GenConversion(Instruction::Code opcode, RegLocation rl_dest,
193 RegLocation rl_src) {
194 RegisterClass rcSrc = kFPReg;
195 X86OpCode op = kX86Nop;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700196 RegLocation rl_result;
197 switch (opcode) {
198 case Instruction::INT_TO_FLOAT:
199 rcSrc = kCoreReg;
200 op = kX86Cvtsi2ssRR;
201 break;
202 case Instruction::DOUBLE_TO_FLOAT:
203 rcSrc = kFPReg;
204 op = kX86Cvtsd2ssRR;
205 break;
206 case Instruction::FLOAT_TO_DOUBLE:
207 rcSrc = kFPReg;
208 op = kX86Cvtss2sdRR;
209 break;
210 case Instruction::INT_TO_DOUBLE:
211 rcSrc = kCoreReg;
212 op = kX86Cvtsi2sdRR;
213 break;
214 case Instruction::FLOAT_TO_INT: {
215 rl_src = LoadValue(rl_src, kFPReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700216 // In case result vreg is also src vreg, break association to avoid useless copy by EvalLoc()
217 ClobberSReg(rl_dest.s_reg_low);
218 rl_result = EvalLoc(rl_dest, kCoreReg, true);
buzbee091cc402014-03-31 10:14:40 -0700219 RegStorage temp_reg = AllocTempSingle();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700220
buzbee2700f7e2014-03-07 09:46:20 -0800221 LoadConstant(rl_result.reg, 0x7fffffff);
buzbee091cc402014-03-31 10:14:40 -0700222 NewLIR2(kX86Cvtsi2ssRR, temp_reg.GetReg(), rl_result.reg.GetReg());
223 NewLIR2(kX86ComissRR, rl_src.reg.GetReg(), temp_reg.GetReg());
Serguei Katkov5078d972014-06-20 16:45:52 +0700224 LIR* branch_pos_overflow = NewLIR2(kX86Jcc8, 0, kX86CondAe);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700225 LIR* branch_na_n = NewLIR2(kX86Jcc8, 0, kX86CondP);
buzbee091cc402014-03-31 10:14:40 -0700226 NewLIR2(kX86Cvttss2siRR, rl_result.reg.GetReg(), rl_src.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700227 LIR* branch_normal = NewLIR1(kX86Jmp8, 0);
228 branch_na_n->target = NewLIR0(kPseudoTargetLabel);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000229 NewLIR2(kX86Xor32RR, rl_result.reg.GetReg(), rl_result.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700230 branch_pos_overflow->target = NewLIR0(kPseudoTargetLabel);
231 branch_normal->target = NewLIR0(kPseudoTargetLabel);
232 StoreValue(rl_dest, rl_result);
233 return;
234 }
235 case Instruction::DOUBLE_TO_INT: {
236 rl_src = LoadValueWide(rl_src, kFPReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700237 // In case result vreg is also src vreg, break association to avoid useless copy by EvalLoc()
238 ClobberSReg(rl_dest.s_reg_low);
239 rl_result = EvalLoc(rl_dest, kCoreReg, true);
buzbee091cc402014-03-31 10:14:40 -0700240 RegStorage temp_reg = AllocTempDouble();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700241
buzbee2700f7e2014-03-07 09:46:20 -0800242 LoadConstant(rl_result.reg, 0x7fffffff);
buzbee091cc402014-03-31 10:14:40 -0700243 NewLIR2(kX86Cvtsi2sdRR, temp_reg.GetReg(), rl_result.reg.GetReg());
244 NewLIR2(kX86ComisdRR, rl_src.reg.GetReg(), temp_reg.GetReg());
Serguei Katkov5078d972014-06-20 16:45:52 +0700245 LIR* branch_pos_overflow = NewLIR2(kX86Jcc8, 0, kX86CondAe);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700246 LIR* branch_na_n = NewLIR2(kX86Jcc8, 0, kX86CondP);
buzbee091cc402014-03-31 10:14:40 -0700247 NewLIR2(kX86Cvttsd2siRR, rl_result.reg.GetReg(), rl_src.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700248 LIR* branch_normal = NewLIR1(kX86Jmp8, 0);
249 branch_na_n->target = NewLIR0(kPseudoTargetLabel);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000250 NewLIR2(kX86Xor32RR, rl_result.reg.GetReg(), rl_result.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700251 branch_pos_overflow->target = NewLIR0(kPseudoTargetLabel);
252 branch_normal->target = NewLIR0(kPseudoTargetLabel);
253 StoreValue(rl_dest, rl_result);
254 return;
255 }
256 case Instruction::LONG_TO_DOUBLE:
Elena Sayapinadd644502014-07-01 18:39:52 +0700257 if (cu_->target64) {
Chao-ying Fua0147762014-06-06 18:38:49 -0700258 rcSrc = kCoreReg;
259 op = kX86Cvtsqi2sdRR;
260 break;
261 }
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800262 GenLongToFP(rl_dest, rl_src, true /* is_double */);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700263 return;
264 case Instruction::LONG_TO_FLOAT:
Elena Sayapinadd644502014-07-01 18:39:52 +0700265 if (cu_->target64) {
Chao-ying Fua0147762014-06-06 18:38:49 -0700266 rcSrc = kCoreReg;
267 op = kX86Cvtsqi2ssRR;
268 break;
269 }
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800270 GenLongToFP(rl_dest, rl_src, false /* is_double */);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700271 return;
272 case Instruction::FLOAT_TO_LONG:
Elena Sayapinadd644502014-07-01 18:39:52 +0700273 if (cu_->target64) {
Chao-ying Fua0147762014-06-06 18:38:49 -0700274 rl_src = LoadValue(rl_src, kFPReg);
275 // If result vreg is also src vreg, break association to avoid useless copy by EvalLoc()
276 ClobberSReg(rl_dest.s_reg_low);
277 rl_result = EvalLoc(rl_dest, kCoreReg, true);
278 RegStorage temp_reg = AllocTempSingle();
279
280 // Set 0x7fffffffffffffff to rl_result
281 LoadConstantWide(rl_result.reg, 0x7fffffffffffffff);
282 NewLIR2(kX86Cvtsqi2ssRR, temp_reg.GetReg(), rl_result.reg.GetReg());
283 NewLIR2(kX86ComissRR, rl_src.reg.GetReg(), temp_reg.GetReg());
Serguei Katkov5078d972014-06-20 16:45:52 +0700284 LIR* branch_pos_overflow = NewLIR2(kX86Jcc8, 0, kX86CondAe);
Chao-ying Fua0147762014-06-06 18:38:49 -0700285 LIR* branch_na_n = NewLIR2(kX86Jcc8, 0, kX86CondP);
286 NewLIR2(kX86Cvttss2sqiRR, rl_result.reg.GetReg(), rl_src.reg.GetReg());
287 LIR* branch_normal = NewLIR1(kX86Jmp8, 0);
288 branch_na_n->target = NewLIR0(kPseudoTargetLabel);
289 NewLIR2(kX86Xor64RR, rl_result.reg.GetReg(), rl_result.reg.GetReg());
290 branch_pos_overflow->target = NewLIR0(kPseudoTargetLabel);
291 branch_normal->target = NewLIR0(kPseudoTargetLabel);
292 StoreValueWide(rl_dest, rl_result);
Dmitry Petrochenko9ee801f2014-05-12 11:31:37 +0700293 } else {
Andreas Gampe98430592014-07-27 19:44:50 -0700294 GenConversionCall(kQuickF2l, rl_dest, rl_src);
Dmitry Petrochenko9ee801f2014-05-12 11:31:37 +0700295 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700296 return;
297 case Instruction::DOUBLE_TO_LONG:
Elena Sayapinadd644502014-07-01 18:39:52 +0700298 if (cu_->target64) {
Chao-ying Fua0147762014-06-06 18:38:49 -0700299 rl_src = LoadValueWide(rl_src, kFPReg);
300 // If result vreg is also src vreg, break association to avoid useless copy by EvalLoc()
301 ClobberSReg(rl_dest.s_reg_low);
302 rl_result = EvalLoc(rl_dest, kCoreReg, true);
303 RegStorage temp_reg = AllocTempDouble();
304
305 // Set 0x7fffffffffffffff to rl_result
306 LoadConstantWide(rl_result.reg, 0x7fffffffffffffff);
307 NewLIR2(kX86Cvtsqi2sdRR, temp_reg.GetReg(), rl_result.reg.GetReg());
308 NewLIR2(kX86ComisdRR, rl_src.reg.GetReg(), temp_reg.GetReg());
Serguei Katkov5078d972014-06-20 16:45:52 +0700309 LIR* branch_pos_overflow = NewLIR2(kX86Jcc8, 0, kX86CondAe);
Chao-ying Fua0147762014-06-06 18:38:49 -0700310 LIR* branch_na_n = NewLIR2(kX86Jcc8, 0, kX86CondP);
311 NewLIR2(kX86Cvttsd2sqiRR, rl_result.reg.GetReg(), rl_src.reg.GetReg());
312 LIR* branch_normal = NewLIR1(kX86Jmp8, 0);
313 branch_na_n->target = NewLIR0(kPseudoTargetLabel);
314 NewLIR2(kX86Xor64RR, rl_result.reg.GetReg(), rl_result.reg.GetReg());
315 branch_pos_overflow->target = NewLIR0(kPseudoTargetLabel);
316 branch_normal->target = NewLIR0(kPseudoTargetLabel);
317 StoreValueWide(rl_dest, rl_result);
Dmitry Petrochenko9ee801f2014-05-12 11:31:37 +0700318 } else {
Andreas Gampe98430592014-07-27 19:44:50 -0700319 GenConversionCall(kQuickD2l, rl_dest, rl_src);
Dmitry Petrochenko9ee801f2014-05-12 11:31:37 +0700320 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700321 return;
322 default:
323 LOG(INFO) << "Unexpected opcode: " << opcode;
324 }
buzbee091cc402014-03-31 10:14:40 -0700325 // At this point, target will be either float or double.
326 DCHECK(rl_dest.fp);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700327 if (rl_src.wide) {
328 rl_src = LoadValueWide(rl_src, rcSrc);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700329 } else {
330 rl_src = LoadValue(rl_src, rcSrc);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700331 }
buzbee091cc402014-03-31 10:14:40 -0700332 rl_result = EvalLoc(rl_dest, kFPReg, true);
333 NewLIR2(op, rl_result.reg.GetReg(), rl_src.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700334 if (rl_dest.wide) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700335 StoreValueWide(rl_dest, rl_result);
336 } else {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700337 StoreValue(rl_dest, rl_result);
338 }
339}
340
Alexei Zavjalovbd3682e2014-06-12 03:08:01 +0700341void X86Mir2Lir::GenRemFP(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2, bool is_double) {
342 // Compute offsets to the source and destination VRs on stack.
343 int src1_v_reg_offset = SRegOffset(rl_src1.s_reg_low);
344 int src2_v_reg_offset = SRegOffset(rl_src2.s_reg_low);
345 int dest_v_reg_offset = SRegOffset(rl_dest.s_reg_low);
346
347 // Update the in-register state of sources.
348 rl_src1 = is_double ? UpdateLocWide(rl_src1) : UpdateLoc(rl_src1);
349 rl_src2 = is_double ? UpdateLocWide(rl_src2) : UpdateLoc(rl_src2);
350
351 // All memory accesses below reference dalvik regs.
352 ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
353
354 // If the source is in physical register, then put it in its location on stack.
355 if (rl_src1.location == kLocPhysReg) {
356 RegisterInfo* reg_info = GetRegInfo(rl_src1.reg);
357
358 if (reg_info != nullptr && reg_info->IsTemp()) {
359 // Calling FlushSpecificReg because it will only write back VR if it is dirty.
360 FlushSpecificReg(reg_info);
361 // ResetDef to prevent NullifyRange from removing stores.
362 ResetDef(rl_src1.reg);
363 } else {
364 // It must have been register promoted if it is not a temp but is still in physical
365 // register. Since we need it to be in memory to convert, we place it there now.
Chao-ying Fua77ee512014-07-01 17:43:41 -0700366 StoreBaseDisp(rs_rX86_SP, src1_v_reg_offset, rl_src1.reg, is_double ? k64 : k32,
Andreas Gampe3c12c512014-06-24 18:46:29 +0000367 kNotVolatile);
Alexei Zavjalovbd3682e2014-06-12 03:08:01 +0700368 }
369 }
370
371 if (rl_src2.location == kLocPhysReg) {
372 RegisterInfo* reg_info = GetRegInfo(rl_src2.reg);
373 if (reg_info != nullptr && reg_info->IsTemp()) {
374 FlushSpecificReg(reg_info);
375 ResetDef(rl_src2.reg);
376 } else {
Chao-ying Fua77ee512014-07-01 17:43:41 -0700377 StoreBaseDisp(rs_rX86_SP, src2_v_reg_offset, rl_src2.reg, is_double ? k64 : k32,
Andreas Gampe3c12c512014-06-24 18:46:29 +0000378 kNotVolatile);
Alexei Zavjalovbd3682e2014-06-12 03:08:01 +0700379 }
380 }
381
382 int fld_opcode = is_double ? kX86Fld64M : kX86Fld32M;
383
384 // Push the source virtual registers onto the x87 stack.
Chao-ying Fua77ee512014-07-01 17:43:41 -0700385 LIR *fld_2 = NewLIR2NoDest(fld_opcode, rs_rX86_SP.GetReg(),
Alexei Zavjalovbd3682e2014-06-12 03:08:01 +0700386 src2_v_reg_offset + LOWORD_OFFSET);
387 AnnotateDalvikRegAccess(fld_2, (src2_v_reg_offset + LOWORD_OFFSET) >> 2,
388 true /* is_load */, is_double /* is64bit */);
389
Chao-ying Fua77ee512014-07-01 17:43:41 -0700390 LIR *fld_1 = NewLIR2NoDest(fld_opcode, rs_rX86_SP.GetReg(),
Alexei Zavjalovbd3682e2014-06-12 03:08:01 +0700391 src1_v_reg_offset + LOWORD_OFFSET);
392 AnnotateDalvikRegAccess(fld_1, (src1_v_reg_offset + LOWORD_OFFSET) >> 2,
393 true /* is_load */, is_double /* is64bit */);
394
395 FlushReg(rs_rAX);
396 Clobber(rs_rAX);
397 LockTemp(rs_rAX);
398
399 LIR* retry = NewLIR0(kPseudoTargetLabel);
400
401 // Divide ST(0) by ST(1) and place result to ST(0).
402 NewLIR0(kX86Fprem);
403
404 // Move FPU status word to AX.
405 NewLIR0(kX86Fstsw16R);
406
407 // Check if reduction is complete.
408 OpRegImm(kOpAnd, rs_rAX, 0x400);
409
410 // If no then continue to compute remainder.
411 LIR* branch = NewLIR2(kX86Jcc8, 0, kX86CondNe);
412 branch->target = retry;
413
414 FreeTemp(rs_rAX);
415
416 // Now store result in the destination VR's stack location.
417 int displacement = dest_v_reg_offset + LOWORD_OFFSET;
418 int opcode = is_double ? kX86Fst64M : kX86Fst32M;
Chao-ying Fua77ee512014-07-01 17:43:41 -0700419 LIR *fst = NewLIR2NoDest(opcode, rs_rX86_SP.GetReg(), displacement);
Alexei Zavjalovbd3682e2014-06-12 03:08:01 +0700420 AnnotateDalvikRegAccess(fst, displacement >> 2, false /* is_load */, is_double /* is64bit */);
421
422 // Pop ST(1) and ST(0).
423 NewLIR0(kX86Fucompp);
424
425 /*
426 * The result is in a physical register if it was in a temp or was register
427 * promoted. For that reason it is enough to check if it is in physical
428 * register. If it is, then we must do all of the bookkeeping necessary to
429 * invalidate temp (if needed) and load in promoted register (if needed).
430 * If the result's location is in memory, then we do not need to do anything
431 * more since the fstp has already placed the correct value in memory.
432 */
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700433 RegLocation rl_result = is_double ? UpdateLocWideTyped(rl_dest) : UpdateLocTyped(rl_dest);
Alexei Zavjalovbd3682e2014-06-12 03:08:01 +0700434 if (rl_result.location == kLocPhysReg) {
435 rl_result = EvalLoc(rl_dest, kFPReg, true);
436 if (is_double) {
Chao-ying Fua77ee512014-07-01 17:43:41 -0700437 LoadBaseDisp(rs_rX86_SP, dest_v_reg_offset, rl_result.reg, k64, kNotVolatile);
Alexei Zavjalovbd3682e2014-06-12 03:08:01 +0700438 StoreFinalValueWide(rl_dest, rl_result);
439 } else {
Chao-ying Fua77ee512014-07-01 17:43:41 -0700440 Load32Disp(rs_rX86_SP, dest_v_reg_offset, rl_result.reg);
Alexei Zavjalovbd3682e2014-06-12 03:08:01 +0700441 StoreFinalValue(rl_dest, rl_result);
442 }
443 }
444}
445
Brian Carlstrom7940e442013-07-12 13:46:57 -0700446void X86Mir2Lir::GenCmpFP(Instruction::Code code, RegLocation rl_dest,
447 RegLocation rl_src1, RegLocation rl_src2) {
448 bool single = (code == Instruction::CMPL_FLOAT) || (code == Instruction::CMPG_FLOAT);
449 bool unordered_gt = (code == Instruction::CMPG_DOUBLE) || (code == Instruction::CMPG_FLOAT);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700450 if (single) {
451 rl_src1 = LoadValue(rl_src1, kFPReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700452 rl_src2 = LoadValue(rl_src2, kFPReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700453 } else {
454 rl_src1 = LoadValueWide(rl_src1, kFPReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700455 rl_src2 = LoadValueWide(rl_src2, kFPReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700456 }
457 // In case result vreg is also src vreg, break association to avoid useless copy by EvalLoc()
458 ClobberSReg(rl_dest.s_reg_low);
459 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
buzbee2700f7e2014-03-07 09:46:20 -0800460 LoadConstantNoClobber(rl_result.reg, unordered_gt ? 1 : 0);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700461 if (single) {
buzbee091cc402014-03-31 10:14:40 -0700462 NewLIR2(kX86UcomissRR, rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700463 } else {
buzbee091cc402014-03-31 10:14:40 -0700464 NewLIR2(kX86UcomisdRR, rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700465 }
466 LIR* branch = NULL;
467 if (unordered_gt) {
468 branch = NewLIR2(kX86Jcc8, 0, kX86CondPE);
469 }
470 // 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 -0700471 if (!IsByteRegister(rl_result.reg)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700472 LIR* branch2 = NULL;
473 if (unordered_gt) {
474 branch2 = NewLIR2(kX86Jcc8, 0, kX86CondA);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000475 NewLIR2(kX86Mov32RI, rl_result.reg.GetReg(), 0x0);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700476 } else {
477 branch2 = NewLIR2(kX86Jcc8, 0, kX86CondBe);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000478 NewLIR2(kX86Mov32RI, rl_result.reg.GetReg(), 0x1);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700479 }
480 branch2->target = NewLIR0(kPseudoTargetLabel);
481 } else {
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000482 NewLIR2(kX86Set8R, rl_result.reg.GetReg(), kX86CondA /* above - unsigned > */);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700483 }
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000484 NewLIR2(kX86Sbb32RI, rl_result.reg.GetReg(), 0);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700485 if (unordered_gt) {
486 branch->target = NewLIR0(kPseudoTargetLabel);
487 }
488 StoreValue(rl_dest, rl_result);
489}
490
491void X86Mir2Lir::GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias,
492 bool is_double) {
buzbee0d829482013-10-11 15:24:55 -0700493 LIR* taken = &block_label_list_[bb->taken];
494 LIR* not_taken = &block_label_list_[bb->fall_through];
Brian Carlstrom7940e442013-07-12 13:46:57 -0700495 LIR* branch = NULL;
496 RegLocation rl_src1;
497 RegLocation rl_src2;
498 if (is_double) {
499 rl_src1 = mir_graph_->GetSrcWide(mir, 0);
500 rl_src2 = mir_graph_->GetSrcWide(mir, 2);
501 rl_src1 = LoadValueWide(rl_src1, kFPReg);
502 rl_src2 = LoadValueWide(rl_src2, kFPReg);
buzbee091cc402014-03-31 10:14:40 -0700503 NewLIR2(kX86UcomisdRR, rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700504 } else {
505 rl_src1 = mir_graph_->GetSrc(mir, 0);
506 rl_src2 = mir_graph_->GetSrc(mir, 1);
507 rl_src1 = LoadValue(rl_src1, kFPReg);
508 rl_src2 = LoadValue(rl_src2, kFPReg);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000509 NewLIR2(kX86UcomissRR, rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700510 }
Vladimir Markoa8946072014-01-22 10:30:44 +0000511 ConditionCode ccode = mir->meta.ccode;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700512 switch (ccode) {
513 case kCondEq:
514 if (!gt_bias) {
515 branch = NewLIR2(kX86Jcc8, 0, kX86CondPE);
516 branch->target = not_taken;
517 }
518 break;
519 case kCondNe:
520 if (!gt_bias) {
521 branch = NewLIR2(kX86Jcc8, 0, kX86CondPE);
522 branch->target = taken;
523 }
524 break;
525 case kCondLt:
526 if (gt_bias) {
527 branch = NewLIR2(kX86Jcc8, 0, kX86CondPE);
528 branch->target = not_taken;
529 }
Vladimir Marko58af1f92013-12-19 13:31:15 +0000530 ccode = kCondUlt;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700531 break;
532 case kCondLe:
533 if (gt_bias) {
534 branch = NewLIR2(kX86Jcc8, 0, kX86CondPE);
535 branch->target = not_taken;
536 }
537 ccode = kCondLs;
538 break;
539 case kCondGt:
540 if (gt_bias) {
541 branch = NewLIR2(kX86Jcc8, 0, kX86CondPE);
542 branch->target = taken;
543 }
544 ccode = kCondHi;
545 break;
546 case kCondGe:
547 if (gt_bias) {
548 branch = NewLIR2(kX86Jcc8, 0, kX86CondPE);
549 branch->target = taken;
550 }
Vladimir Marko58af1f92013-12-19 13:31:15 +0000551 ccode = kCondUge;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700552 break;
553 default:
554 LOG(FATAL) << "Unexpected ccode: " << ccode;
555 }
556 OpCondBranch(ccode, taken);
557}
558
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700559void X86Mir2Lir::GenNegFloat(RegLocation rl_dest, RegLocation rl_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700560 RegLocation rl_result;
561 rl_src = LoadValue(rl_src, kCoreReg);
562 rl_result = EvalLoc(rl_dest, kCoreReg, true);
buzbee2700f7e2014-03-07 09:46:20 -0800563 OpRegRegImm(kOpAdd, rl_result.reg, rl_src.reg, 0x80000000);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700564 StoreValue(rl_dest, rl_result);
565}
566
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700567void X86Mir2Lir::GenNegDouble(RegLocation rl_dest, RegLocation rl_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700568 RegLocation rl_result;
569 rl_src = LoadValueWide(rl_src, kCoreReg);
Chao-ying Fua0147762014-06-06 18:38:49 -0700570 rl_result = EvalLocWide(rl_dest, kCoreReg, true);
Elena Sayapinadd644502014-07-01 18:39:52 +0700571 if (cu_->target64) {
Alexei Zavjalov02959ea2014-06-18 17:18:36 +0700572 OpRegCopy(rl_result.reg, rl_src.reg);
573 // Flip sign bit.
574 NewLIR2(kX86Rol64RI, rl_result.reg.GetReg(), 1);
575 NewLIR2(kX86Xor64RI, rl_result.reg.GetReg(), 1);
576 NewLIR2(kX86Ror64RI, rl_result.reg.GetReg(), 1);
Chao-ying Fua0147762014-06-06 18:38:49 -0700577 } else {
578 OpRegRegImm(kOpAdd, rl_result.reg.GetHigh(), rl_src.reg.GetHigh(), 0x80000000);
579 OpRegCopy(rl_result.reg, rl_src.reg);
580 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700581 StoreValueWide(rl_dest, rl_result);
582}
583
584bool X86Mir2Lir::GenInlinedSqrt(CallInfo* info) {
Mark Mendellbff1ef02013-12-13 13:47:34 -0800585 RegLocation rl_src = info->args[0];
586 RegLocation rl_dest = InlineTargetWide(info); // double place for result
587 rl_src = LoadValueWide(rl_src, kFPReg);
588 RegLocation rl_result = EvalLoc(rl_dest, kFPReg, true);
buzbee091cc402014-03-31 10:14:40 -0700589 NewLIR2(kX86SqrtsdRR, rl_result.reg.GetReg(), rl_src.reg.GetReg());
Mark Mendellbff1ef02013-12-13 13:47:34 -0800590 StoreValueWide(rl_dest, rl_result);
591 return true;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700592}
593
Yixin Shou7071c8d2014-03-05 06:07:48 -0500594bool X86Mir2Lir::GenInlinedAbsFloat(CallInfo* info) {
595 // Get the argument
596 RegLocation rl_src = info->args[0];
597
598 // Get the inlined intrinsic target virtual register
599 RegLocation rl_dest = InlineTarget(info);
600
601 // Get the virtual register number
602 DCHECK_NE(rl_src.s_reg_low, INVALID_SREG);
603 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 int v_src_reg = mir_graph_->SRegToVReg(rl_src.s_reg_low);
608 int v_dst_reg = mir_graph_->SRegToVReg(rl_dest.s_reg_low);
609
610 // if argument is the same as inlined intrinsic target
611 if (v_src_reg == v_dst_reg) {
612 rl_src = UpdateLoc(rl_src);
613
614 // if argument is in the physical register
615 if (rl_src.location == kLocPhysReg) {
616 rl_src = LoadValue(rl_src, kCoreReg);
617 OpRegImm(kOpAnd, rl_src.reg, 0x7fffffff);
618 StoreValue(rl_dest, rl_src);
619 return true;
620 }
621 // the argument is in memory
622 DCHECK((rl_src.location == kLocDalvikFrame) ||
623 (rl_src.location == kLocCompilerTemp));
624
625 // Operate directly into memory.
626 int displacement = SRegOffset(rl_dest.s_reg_low);
627 ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
Chao-ying Fua77ee512014-07-01 17:43:41 -0700628 LIR *lir = NewLIR3(kX86And32MI, rs_rX86_SP.GetReg(), displacement, 0x7fffffff);
Yixin Shou7071c8d2014-03-05 06:07:48 -0500629 AnnotateDalvikRegAccess(lir, displacement >> 2, false /*is_load */, false /* is_64bit */);
630 AnnotateDalvikRegAccess(lir, displacement >> 2, true /* is_load */, false /* is_64bit*/);
631 return true;
632 } else {
633 rl_src = LoadValue(rl_src, kCoreReg);
634 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
635 OpRegRegImm(kOpAnd, rl_result.reg, rl_src.reg, 0x7fffffff);
636 StoreValue(rl_dest, rl_result);
637 return true;
638 }
639}
640
641bool X86Mir2Lir::GenInlinedAbsDouble(CallInfo* info) {
642 RegLocation rl_src = info->args[0];
643 RegLocation rl_dest = InlineTargetWide(info);
644 DCHECK_NE(rl_src.s_reg_low, INVALID_SREG);
645 if (rl_dest.s_reg_low == INVALID_SREG) {
646 // Result is unused, the code is dead. Inlining successful, no code generated.
647 return true;
648 }
nikolay serdjukc5e4ce12014-06-10 17:07:10 +0700649 if (cu_->target64) {
650 rl_src = LoadValueWide(rl_src, kCoreReg);
651 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
652 OpRegCopyWide(rl_result.reg, rl_src.reg);
653 OpRegImm(kOpLsl, rl_result.reg, 1);
654 OpRegImm(kOpLsr, rl_result.reg, 1);
655 StoreValueWide(rl_dest, rl_result);
656 return true;
657 }
Yixin Shou7071c8d2014-03-05 06:07:48 -0500658 int v_src_reg = mir_graph_->SRegToVReg(rl_src.s_reg_low);
659 int v_dst_reg = mir_graph_->SRegToVReg(rl_dest.s_reg_low);
660 rl_src = UpdateLocWide(rl_src);
661
662 // if argument is in the physical XMM register
663 if (rl_src.location == kLocPhysReg && rl_src.reg.IsFloat()) {
664 RegLocation rl_result = EvalLoc(rl_dest, kFPReg, true);
665 if (rl_result.reg != rl_src.reg) {
666 LoadConstantWide(rl_result.reg, 0x7fffffffffffffff);
667 NewLIR2(kX86PandRR, rl_result.reg.GetReg(), rl_src.reg.GetReg());
668 } else {
669 RegStorage sign_mask = AllocTempDouble();
670 LoadConstantWide(sign_mask, 0x7fffffffffffffff);
671 NewLIR2(kX86PandRR, rl_result.reg.GetReg(), sign_mask.GetReg());
672 FreeTemp(sign_mask);
673 }
674 StoreValueWide(rl_dest, rl_result);
675 return true;
676 } else if (v_src_reg == v_dst_reg) {
677 // if argument is the same as inlined intrinsic target
678 // if argument is in the physical register
679 if (rl_src.location == kLocPhysReg) {
680 rl_src = LoadValueWide(rl_src, kCoreReg);
681 OpRegImm(kOpAnd, rl_src.reg.GetHigh(), 0x7fffffff);
682 StoreValueWide(rl_dest, rl_src);
683 return true;
684 }
685 // the argument is in memory
686 DCHECK((rl_src.location == kLocDalvikFrame) ||
687 (rl_src.location == kLocCompilerTemp));
688
689 // Operate directly into memory.
690 int displacement = SRegOffset(rl_dest.s_reg_low);
691 ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
Chao-ying Fua77ee512014-07-01 17:43:41 -0700692 LIR *lir = NewLIR3(kX86And32MI, rs_rX86_SP.GetReg(), displacement + HIWORD_OFFSET, 0x7fffffff);
Yixin Shou7071c8d2014-03-05 06:07:48 -0500693 AnnotateDalvikRegAccess(lir, (displacement + HIWORD_OFFSET) >> 2, true /* is_load */, true /* is_64bit*/);
694 AnnotateDalvikRegAccess(lir, (displacement + HIWORD_OFFSET) >> 2, false /*is_load */, true /* is_64bit */);
695 return true;
696 } else {
697 rl_src = LoadValueWide(rl_src, kCoreReg);
698 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
699 OpRegCopyWide(rl_result.reg, rl_src.reg);
700 OpRegImm(kOpAnd, rl_result.reg.GetHigh(), 0x7fffffff);
701 StoreValueWide(rl_dest, rl_result);
702 return true;
703 }
704}
Brian Carlstrom7940e442013-07-12 13:46:57 -0700705
Alexei Zavjalov1222c962014-07-16 00:54:13 +0700706bool X86Mir2Lir::GenInlinedMinMaxFP(CallInfo* info, bool is_min, bool is_double) {
707 if (is_double) {
708 RegLocation rl_src1 = LoadValueWide(info->args[0], kFPReg);
709 RegLocation rl_src2 = LoadValueWide(info->args[2], kFPReg);
710 RegLocation rl_dest = InlineTargetWide(info);
711 RegLocation rl_result = EvalLocWide(rl_dest, kFPReg, true);
712
713 // Avoid src2 corruption by OpRegCopyWide.
714 if (rl_result.reg == rl_src2.reg) {
715 std::swap(rl_src2.reg, rl_src1.reg);
716 }
717
718 OpRegCopyWide(rl_result.reg, rl_src1.reg);
719 NewLIR2(kX86UcomisdRR, rl_result.reg.GetReg(), rl_src2.reg.GetReg());
720 // If either arg is NaN, return NaN.
721 LIR* branch_nan = NewLIR2(kX86Jcc8, 0, kX86CondP);
722 // Min/Max branches.
723 LIR* branch_cond1 = NewLIR2(kX86Jcc8, 0, (is_min) ? kX86CondA : kX86CondB);
724 LIR* branch_cond2 = NewLIR2(kX86Jcc8, 0, (is_min) ? kX86CondB : kX86CondA);
725 // If equal, we need to resolve situations like min/max(0.0, -0.0) == -0.0/0.0.
726 NewLIR2((is_min) ? kX86OrpdRR : kX86AndpdRR, rl_result.reg.GetReg(), rl_src2.reg.GetReg());
727 LIR* branch_exit_equal = NewLIR1(kX86Jmp8, 0);
728 // Handle NaN.
729 branch_nan->target = NewLIR0(kPseudoTargetLabel);
730 LoadConstantWide(rl_result.reg, INT64_C(0x7ff8000000000000));
Razvan A Lupusorue5beb182014-08-14 13:49:57 +0800731
732 // The base_of_code_ compiler temp is non-null when it is reserved
733 // for being able to do data accesses relative to method start.
734 if (base_of_code_ != nullptr) {
735 // Loading from the constant pool may have used base of code register.
736 // However, the code here generates logic in diamond shape and not all
737 // paths load base of code register. Therefore, we ensure it is clobbered so
738 // that the temp caching system does not believe it is live at merge point.
739 RegLocation rl_method = mir_graph_->GetRegLocation(base_of_code_->s_reg_low);
740 if (rl_method.wide) {
741 rl_method = UpdateLocWide(rl_method);
742 } else {
743 rl_method = UpdateLoc(rl_method);
744 }
745 if (rl_method.location == kLocPhysReg) {
746 Clobber(rl_method.reg);
747 }
748 }
749
Alexei Zavjalov1222c962014-07-16 00:54:13 +0700750 LIR* branch_exit_nan = NewLIR1(kX86Jmp8, 0);
751 // Handle Min/Max. Copy greater/lesser value from src2.
752 branch_cond1->target = NewLIR0(kPseudoTargetLabel);
753 OpRegCopyWide(rl_result.reg, rl_src2.reg);
754 // Right operand is already in result reg.
755 branch_cond2->target = NewLIR0(kPseudoTargetLabel);
756 // Exit.
757 branch_exit_nan->target = NewLIR0(kPseudoTargetLabel);
758 branch_exit_equal->target = NewLIR0(kPseudoTargetLabel);
759 StoreValueWide(rl_dest, rl_result);
760 } else {
761 RegLocation rl_src1 = LoadValue(info->args[0], kFPReg);
762 RegLocation rl_src2 = LoadValue(info->args[1], kFPReg);
763 RegLocation rl_dest = InlineTarget(info);
764 RegLocation rl_result = EvalLoc(rl_dest, kFPReg, true);
765
766 // Avoid src2 corruption by OpRegCopyWide.
767 if (rl_result.reg == rl_src2.reg) {
768 std::swap(rl_src2.reg, rl_src1.reg);
769 }
770
771 OpRegCopy(rl_result.reg, rl_src1.reg);
772 NewLIR2(kX86UcomissRR, rl_result.reg.GetReg(), rl_src2.reg.GetReg());
773 // If either arg is NaN, return NaN.
774 LIR* branch_nan = NewLIR2(kX86Jcc8, 0, kX86CondP);
775 // Min/Max branches.
776 LIR* branch_cond1 = NewLIR2(kX86Jcc8, 0, (is_min) ? kX86CondA : kX86CondB);
777 LIR* branch_cond2 = NewLIR2(kX86Jcc8, 0, (is_min) ? kX86CondB : kX86CondA);
778 // If equal, we need to resolve situations like min/max(0.0, -0.0) == -0.0/0.0.
779 NewLIR2((is_min) ? kX86OrpsRR : kX86AndpsRR, rl_result.reg.GetReg(), rl_src2.reg.GetReg());
780 LIR* branch_exit_equal = NewLIR1(kX86Jmp8, 0);
781 // Handle NaN.
782 branch_nan->target = NewLIR0(kPseudoTargetLabel);
783 LoadConstantNoClobber(rl_result.reg, 0x7fc00000);
784 LIR* branch_exit_nan = NewLIR1(kX86Jmp8, 0);
785 // Handle Min/Max. Copy greater/lesser value from src2.
786 branch_cond1->target = NewLIR0(kPseudoTargetLabel);
787 OpRegCopy(rl_result.reg, rl_src2.reg);
788 // Right operand is already in result reg.
789 branch_cond2->target = NewLIR0(kPseudoTargetLabel);
790 // Exit.
791 branch_exit_nan->target = NewLIR0(kPseudoTargetLabel);
792 branch_exit_equal->target = NewLIR0(kPseudoTargetLabel);
793 StoreValue(rl_dest, rl_result);
794 }
795 return true;
796}
797
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700798} // namespace art