blob: 20bb7bf117020e4b8fec452a4ec03e90b6eb2255 [file] [log] [blame]
Brian Carlstrom7940e442013-07-12 13:46:57 -07001/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "codegen_x86.h"
18#include "dex/quick/mir_to_lir-inl.h"
19#include "x86_lir.h"
20
21namespace art {
22
23void X86Mir2Lir::GenArithOpFloat(Instruction::Code opcode,
24 RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) {
25 X86OpCode op = kX86Nop;
26 RegLocation rl_result;
27
28 /*
29 * Don't attempt to optimize register usage since these opcodes call out to
30 * the handlers.
31 */
32 switch (opcode) {
33 case Instruction::ADD_FLOAT_2ADDR:
34 case Instruction::ADD_FLOAT:
35 op = kX86AddssRR;
36 break;
37 case Instruction::SUB_FLOAT_2ADDR:
38 case Instruction::SUB_FLOAT:
39 op = kX86SubssRR;
40 break;
41 case Instruction::DIV_FLOAT_2ADDR:
42 case Instruction::DIV_FLOAT:
43 op = kX86DivssRR;
44 break;
45 case Instruction::MUL_FLOAT_2ADDR:
46 case Instruction::MUL_FLOAT:
47 op = kX86MulssRR;
48 break;
49 case Instruction::REM_FLOAT_2ADDR:
50 case Instruction::REM_FLOAT:
Alexei Zavjalovbd3682e2014-06-12 03:08:01 +070051 GenRemFP(rl_dest, rl_src1, rl_src2, false /* is_double */);
Brian Carlstrom7940e442013-07-12 13:46:57 -070052 return;
53 case Instruction::NEG_FLOAT:
54 GenNegFloat(rl_dest, rl_src1);
55 return;
56 default:
57 LOG(FATAL) << "Unexpected opcode: " << opcode;
58 }
59 rl_src1 = LoadValue(rl_src1, kFPReg);
60 rl_src2 = LoadValue(rl_src2, kFPReg);
61 rl_result = EvalLoc(rl_dest, kFPReg, true);
buzbee2700f7e2014-03-07 09:46:20 -080062 RegStorage r_dest = rl_result.reg;
63 RegStorage r_src1 = rl_src1.reg;
64 RegStorage r_src2 = rl_src2.reg;
Brian Carlstrom7940e442013-07-12 13:46:57 -070065 if (r_dest == r_src2) {
buzbee091cc402014-03-31 10:14:40 -070066 r_src2 = AllocTempSingle();
Brian Carlstrom7940e442013-07-12 13:46:57 -070067 OpRegCopy(r_src2, r_dest);
68 }
69 OpRegCopy(r_dest, r_src1);
buzbee2700f7e2014-03-07 09:46:20 -080070 NewLIR2(op, r_dest.GetReg(), r_src2.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -070071 StoreValue(rl_dest, rl_result);
72}
73
74void X86Mir2Lir::GenArithOpDouble(Instruction::Code opcode,
75 RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) {
buzbee091cc402014-03-31 10:14:40 -070076 DCHECK(rl_dest.wide);
77 DCHECK(rl_dest.fp);
78 DCHECK(rl_src1.wide);
79 DCHECK(rl_src1.fp);
80 DCHECK(rl_src2.wide);
81 DCHECK(rl_src2.fp);
Brian Carlstrom7940e442013-07-12 13:46:57 -070082 X86OpCode op = kX86Nop;
83 RegLocation rl_result;
84
85 switch (opcode) {
86 case Instruction::ADD_DOUBLE_2ADDR:
87 case Instruction::ADD_DOUBLE:
88 op = kX86AddsdRR;
89 break;
90 case Instruction::SUB_DOUBLE_2ADDR:
91 case Instruction::SUB_DOUBLE:
92 op = kX86SubsdRR;
93 break;
94 case Instruction::DIV_DOUBLE_2ADDR:
95 case Instruction::DIV_DOUBLE:
96 op = kX86DivsdRR;
97 break;
98 case Instruction::MUL_DOUBLE_2ADDR:
99 case Instruction::MUL_DOUBLE:
100 op = kX86MulsdRR;
101 break;
102 case Instruction::REM_DOUBLE_2ADDR:
103 case Instruction::REM_DOUBLE:
Alexei Zavjalovbd3682e2014-06-12 03:08:01 +0700104 GenRemFP(rl_dest, rl_src1, rl_src2, true /* is_double */);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700105 return;
106 case Instruction::NEG_DOUBLE:
107 GenNegDouble(rl_dest, rl_src1);
108 return;
109 default:
110 LOG(FATAL) << "Unexpected opcode: " << opcode;
111 }
112 rl_src1 = LoadValueWide(rl_src1, kFPReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700113 rl_src2 = LoadValueWide(rl_src2, kFPReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700114 rl_result = EvalLoc(rl_dest, kFPReg, true);
buzbee091cc402014-03-31 10:14:40 -0700115 if (rl_result.reg == rl_src2.reg) {
116 rl_src2.reg = AllocTempDouble();
117 OpRegCopy(rl_src2.reg, rl_result.reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700118 }
buzbee091cc402014-03-31 10:14:40 -0700119 OpRegCopy(rl_result.reg, rl_src1.reg);
120 NewLIR2(op, rl_result.reg.GetReg(), rl_src2.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700121 StoreValueWide(rl_dest, rl_result);
122}
123
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800124void X86Mir2Lir::GenLongToFP(RegLocation rl_dest, RegLocation rl_src, bool is_double) {
125 // Compute offsets to the source and destination VRs on stack
126 int src_v_reg_offset = SRegOffset(rl_src.s_reg_low);
127 int dest_v_reg_offset = SRegOffset(rl_dest.s_reg_low);
128
129 // Update the in-register state of source.
130 rl_src = UpdateLocWide(rl_src);
131
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100132 // All memory accesses below reference dalvik regs.
133 ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
134
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800135 // If the source is in physical register, then put it in its location on stack.
136 if (rl_src.location == kLocPhysReg) {
buzbee091cc402014-03-31 10:14:40 -0700137 RegisterInfo* reg_info = GetRegInfo(rl_src.reg);
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800138
buzbee091cc402014-03-31 10:14:40 -0700139 if (reg_info != nullptr && reg_info->IsTemp()) {
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800140 // Calling FlushSpecificReg because it will only write back VR if it is dirty.
buzbee091cc402014-03-31 10:14:40 -0700141 FlushSpecificReg(reg_info);
142 // ResetDef to prevent NullifyRange from removing stores.
143 ResetDef(rl_src.reg);
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800144 } else {
145 // It must have been register promoted if it is not a temp but is still in physical
146 // register. Since we need it to be in memory to convert, we place it there now.
Vladimir Marko455759b2014-05-06 20:49:36 +0100147 StoreBaseDisp(TargetReg(kSp), src_v_reg_offset, rl_src.reg, k64);
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800148 }
149 }
150
151 // Push the source virtual register onto the x87 stack.
buzbee091cc402014-03-31 10:14:40 -0700152 LIR *fild64 = NewLIR2NoDest(kX86Fild64M, TargetReg(kSp).GetReg(),
153 src_v_reg_offset + LOWORD_OFFSET);
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800154 AnnotateDalvikRegAccess(fild64, (src_v_reg_offset + LOWORD_OFFSET) >> 2,
buzbee091cc402014-03-31 10:14:40 -0700155 true /* is_load */, true /* is64bit */);
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800156
157 // Now pop off x87 stack and store it in the destination VR's stack location.
158 int opcode = is_double ? kX86Fstp64M : kX86Fstp32M;
159 int displacement = is_double ? dest_v_reg_offset + LOWORD_OFFSET : dest_v_reg_offset;
buzbee2700f7e2014-03-07 09:46:20 -0800160 LIR *fstp = NewLIR2NoDest(opcode, TargetReg(kSp).GetReg(), displacement);
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -0800161 AnnotateDalvikRegAccess(fstp, displacement >> 2, false /* is_load */, is_double);
162
163 /*
164 * The result is in a physical register if it was in a temp or was register
165 * promoted. For that reason it is enough to check if it is in physical
166 * register. If it is, then we must do all of the bookkeeping necessary to
167 * invalidate temp (if needed) and load in promoted register (if needed).
168 * If the result's location is in memory, then we do not need to do anything
169 * more since the fstp has already placed the correct value in memory.
170 */
buzbee30adc732014-05-09 15:10:18 -0700171 RegLocation rl_result = is_double ? UpdateLocWideTyped(rl_dest, kFPReg) :
172 UpdateLocTyped(rl_dest, kFPReg);
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) {
Vladimir Marko3bf7c602014-05-07 14:55:43 +0100181 LoadBaseDisp(TargetReg(kSp), dest_v_reg_offset, rl_result.reg, k64);
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 {
buzbee695d13a2014-04-19 13:32:20 -0700185 Load32Disp(TargetReg(kSp), 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());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700224 LIR* branch_pos_overflow = NewLIR2(kX86Jcc8, 0, kX86CondA);
225 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());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700245 LIR* branch_pos_overflow = NewLIR2(kX86Jcc8, 0, kX86CondA);
246 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:
Chao-ying Fua0147762014-06-06 18:38:49 -0700257 if (Gen64Bit()) {
258 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:
Chao-ying Fua0147762014-06-06 18:38:49 -0700265 if (Gen64Bit()) {
266 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:
Chao-ying Fua0147762014-06-06 18:38:49 -0700273 if (Gen64Bit()) {
274 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());
284 LIR* branch_pos_overflow = NewLIR2(kX86Jcc8, 0, kX86CondA);
285 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 {
294 GenConversionCall(QUICK_ENTRYPOINT_OFFSET(4, pF2l), rl_dest, rl_src);
295 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700296 return;
297 case Instruction::DOUBLE_TO_LONG:
Chao-ying Fua0147762014-06-06 18:38:49 -0700298 if (Gen64Bit()) {
299 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());
309 LIR* branch_pos_overflow = NewLIR2(kX86Jcc8, 0, kX86CondA);
310 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 {
319 GenConversionCall(QUICK_ENTRYPOINT_OFFSET(4, pD2l), rl_dest, rl_src);
320 }
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.
366 StoreBaseDisp(TargetReg(kSp), src1_v_reg_offset, rl_src1.reg, is_double ? k64 : k32);
367 }
368 }
369
370 if (rl_src2.location == kLocPhysReg) {
371 RegisterInfo* reg_info = GetRegInfo(rl_src2.reg);
372 if (reg_info != nullptr && reg_info->IsTemp()) {
373 FlushSpecificReg(reg_info);
374 ResetDef(rl_src2.reg);
375 } else {
376 StoreBaseDisp(TargetReg(kSp), src2_v_reg_offset, rl_src2.reg, is_double ? k64 : k32);
377 }
378 }
379
380 int fld_opcode = is_double ? kX86Fld64M : kX86Fld32M;
381
382 // Push the source virtual registers onto the x87 stack.
383 LIR *fld_2 = NewLIR2NoDest(fld_opcode, TargetReg(kSp).GetReg(),
384 src2_v_reg_offset + LOWORD_OFFSET);
385 AnnotateDalvikRegAccess(fld_2, (src2_v_reg_offset + LOWORD_OFFSET) >> 2,
386 true /* is_load */, is_double /* is64bit */);
387
388 LIR *fld_1 = NewLIR2NoDest(fld_opcode, TargetReg(kSp).GetReg(),
389 src1_v_reg_offset + LOWORD_OFFSET);
390 AnnotateDalvikRegAccess(fld_1, (src1_v_reg_offset + LOWORD_OFFSET) >> 2,
391 true /* is_load */, is_double /* is64bit */);
392
393 FlushReg(rs_rAX);
394 Clobber(rs_rAX);
395 LockTemp(rs_rAX);
396
397 LIR* retry = NewLIR0(kPseudoTargetLabel);
398
399 // Divide ST(0) by ST(1) and place result to ST(0).
400 NewLIR0(kX86Fprem);
401
402 // Move FPU status word to AX.
403 NewLIR0(kX86Fstsw16R);
404
405 // Check if reduction is complete.
406 OpRegImm(kOpAnd, rs_rAX, 0x400);
407
408 // If no then continue to compute remainder.
409 LIR* branch = NewLIR2(kX86Jcc8, 0, kX86CondNe);
410 branch->target = retry;
411
412 FreeTemp(rs_rAX);
413
414 // Now store result in the destination VR's stack location.
415 int displacement = dest_v_reg_offset + LOWORD_OFFSET;
416 int opcode = is_double ? kX86Fst64M : kX86Fst32M;
417 LIR *fst = NewLIR2NoDest(opcode, TargetReg(kSp).GetReg(), displacement);
418 AnnotateDalvikRegAccess(fst, displacement >> 2, false /* is_load */, is_double /* is64bit */);
419
420 // Pop ST(1) and ST(0).
421 NewLIR0(kX86Fucompp);
422
423 /*
424 * The result is in a physical register if it was in a temp or was register
425 * promoted. For that reason it is enough to check if it is in physical
426 * register. If it is, then we must do all of the bookkeeping necessary to
427 * invalidate temp (if needed) and load in promoted register (if needed).
428 * If the result's location is in memory, then we do not need to do anything
429 * more since the fstp has already placed the correct value in memory.
430 */
431 RegLocation rl_result = is_double ? UpdateLocWideTyped(rl_dest, kFPReg) :
432 UpdateLocTyped(rl_dest, kFPReg);
433 if (rl_result.location == kLocPhysReg) {
434 rl_result = EvalLoc(rl_dest, kFPReg, true);
435 if (is_double) {
436 LoadBaseDisp(TargetReg(kSp), dest_v_reg_offset, rl_result.reg, k64);
437 StoreFinalValueWide(rl_dest, rl_result);
438 } else {
439 Load32Disp(TargetReg(kSp), dest_v_reg_offset, rl_result.reg);
440 StoreFinalValue(rl_dest, rl_result);
441 }
442 }
443}
444
Brian Carlstrom7940e442013-07-12 13:46:57 -0700445void X86Mir2Lir::GenCmpFP(Instruction::Code code, RegLocation rl_dest,
446 RegLocation rl_src1, RegLocation rl_src2) {
447 bool single = (code == Instruction::CMPL_FLOAT) || (code == Instruction::CMPG_FLOAT);
448 bool unordered_gt = (code == Instruction::CMPG_DOUBLE) || (code == Instruction::CMPG_FLOAT);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700449 if (single) {
450 rl_src1 = LoadValue(rl_src1, kFPReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700451 rl_src2 = LoadValue(rl_src2, kFPReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700452 } else {
453 rl_src1 = LoadValueWide(rl_src1, kFPReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700454 rl_src2 = LoadValueWide(rl_src2, kFPReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700455 }
456 // In case result vreg is also src vreg, break association to avoid useless copy by EvalLoc()
457 ClobberSReg(rl_dest.s_reg_low);
458 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
buzbee2700f7e2014-03-07 09:46:20 -0800459 LoadConstantNoClobber(rl_result.reg, unordered_gt ? 1 : 0);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700460 if (single) {
buzbee091cc402014-03-31 10:14:40 -0700461 NewLIR2(kX86UcomissRR, rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700462 } else {
buzbee091cc402014-03-31 10:14:40 -0700463 NewLIR2(kX86UcomisdRR, rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700464 }
465 LIR* branch = NULL;
466 if (unordered_gt) {
467 branch = NewLIR2(kX86Jcc8, 0, kX86CondPE);
468 }
469 // 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 -0700470 if (!IsByteRegister(rl_result.reg)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700471 LIR* branch2 = NULL;
472 if (unordered_gt) {
473 branch2 = NewLIR2(kX86Jcc8, 0, kX86CondA);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000474 NewLIR2(kX86Mov32RI, rl_result.reg.GetReg(), 0x0);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700475 } else {
476 branch2 = NewLIR2(kX86Jcc8, 0, kX86CondBe);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000477 NewLIR2(kX86Mov32RI, rl_result.reg.GetReg(), 0x1);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700478 }
479 branch2->target = NewLIR0(kPseudoTargetLabel);
480 } else {
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000481 NewLIR2(kX86Set8R, rl_result.reg.GetReg(), kX86CondA /* above - unsigned > */);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700482 }
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000483 NewLIR2(kX86Sbb32RI, rl_result.reg.GetReg(), 0);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700484 if (unordered_gt) {
485 branch->target = NewLIR0(kPseudoTargetLabel);
486 }
487 StoreValue(rl_dest, rl_result);
488}
489
490void X86Mir2Lir::GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias,
491 bool is_double) {
buzbee0d829482013-10-11 15:24:55 -0700492 LIR* taken = &block_label_list_[bb->taken];
493 LIR* not_taken = &block_label_list_[bb->fall_through];
Brian Carlstrom7940e442013-07-12 13:46:57 -0700494 LIR* branch = NULL;
495 RegLocation rl_src1;
496 RegLocation rl_src2;
497 if (is_double) {
498 rl_src1 = mir_graph_->GetSrcWide(mir, 0);
499 rl_src2 = mir_graph_->GetSrcWide(mir, 2);
500 rl_src1 = LoadValueWide(rl_src1, kFPReg);
501 rl_src2 = LoadValueWide(rl_src2, kFPReg);
buzbee091cc402014-03-31 10:14:40 -0700502 NewLIR2(kX86UcomisdRR, rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700503 } else {
504 rl_src1 = mir_graph_->GetSrc(mir, 0);
505 rl_src2 = mir_graph_->GetSrc(mir, 1);
506 rl_src1 = LoadValue(rl_src1, kFPReg);
507 rl_src2 = LoadValue(rl_src2, kFPReg);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000508 NewLIR2(kX86UcomissRR, rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700509 }
Vladimir Markoa8946072014-01-22 10:30:44 +0000510 ConditionCode ccode = mir->meta.ccode;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700511 switch (ccode) {
512 case kCondEq:
513 if (!gt_bias) {
514 branch = NewLIR2(kX86Jcc8, 0, kX86CondPE);
515 branch->target = not_taken;
516 }
517 break;
518 case kCondNe:
519 if (!gt_bias) {
520 branch = NewLIR2(kX86Jcc8, 0, kX86CondPE);
521 branch->target = taken;
522 }
523 break;
524 case kCondLt:
525 if (gt_bias) {
526 branch = NewLIR2(kX86Jcc8, 0, kX86CondPE);
527 branch->target = not_taken;
528 }
Vladimir Marko58af1f92013-12-19 13:31:15 +0000529 ccode = kCondUlt;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700530 break;
531 case kCondLe:
532 if (gt_bias) {
533 branch = NewLIR2(kX86Jcc8, 0, kX86CondPE);
534 branch->target = not_taken;
535 }
536 ccode = kCondLs;
537 break;
538 case kCondGt:
539 if (gt_bias) {
540 branch = NewLIR2(kX86Jcc8, 0, kX86CondPE);
541 branch->target = taken;
542 }
543 ccode = kCondHi;
544 break;
545 case kCondGe:
546 if (gt_bias) {
547 branch = NewLIR2(kX86Jcc8, 0, kX86CondPE);
548 branch->target = taken;
549 }
Vladimir Marko58af1f92013-12-19 13:31:15 +0000550 ccode = kCondUge;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700551 break;
552 default:
553 LOG(FATAL) << "Unexpected ccode: " << ccode;
554 }
555 OpCondBranch(ccode, taken);
556}
557
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700558void X86Mir2Lir::GenNegFloat(RegLocation rl_dest, RegLocation rl_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700559 RegLocation rl_result;
560 rl_src = LoadValue(rl_src, kCoreReg);
561 rl_result = EvalLoc(rl_dest, kCoreReg, true);
buzbee2700f7e2014-03-07 09:46:20 -0800562 OpRegRegImm(kOpAdd, rl_result.reg, rl_src.reg, 0x80000000);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700563 StoreValue(rl_dest, rl_result);
564}
565
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700566void X86Mir2Lir::GenNegDouble(RegLocation rl_dest, RegLocation rl_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700567 RegLocation rl_result;
568 rl_src = LoadValueWide(rl_src, kCoreReg);
Chao-ying Fua0147762014-06-06 18:38:49 -0700569 rl_result = EvalLocWide(rl_dest, kCoreReg, true);
570 if (Gen64Bit()) {
571 LoadConstantWide(rl_result.reg, 0x8000000000000000);
572 OpRegReg(kOpAdd, rl_result.reg, rl_src.reg);
573 } else {
574 OpRegRegImm(kOpAdd, rl_result.reg.GetHigh(), rl_src.reg.GetHigh(), 0x80000000);
575 OpRegCopy(rl_result.reg, rl_src.reg);
576 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700577 StoreValueWide(rl_dest, rl_result);
578}
579
580bool X86Mir2Lir::GenInlinedSqrt(CallInfo* info) {
Mark Mendellbff1ef02013-12-13 13:47:34 -0800581 RegLocation rl_src = info->args[0];
582 RegLocation rl_dest = InlineTargetWide(info); // double place for result
583 rl_src = LoadValueWide(rl_src, kFPReg);
584 RegLocation rl_result = EvalLoc(rl_dest, kFPReg, true);
buzbee091cc402014-03-31 10:14:40 -0700585 NewLIR2(kX86SqrtsdRR, rl_result.reg.GetReg(), rl_src.reg.GetReg());
Mark Mendellbff1ef02013-12-13 13:47:34 -0800586 StoreValueWide(rl_dest, rl_result);
587 return true;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700588}
589
Yixin Shou7071c8d2014-03-05 06:07:48 -0500590bool X86Mir2Lir::GenInlinedAbsFloat(CallInfo* info) {
591 // Get the argument
592 RegLocation rl_src = info->args[0];
593
594 // Get the inlined intrinsic target virtual register
595 RegLocation rl_dest = InlineTarget(info);
596
597 // Get the virtual register number
598 DCHECK_NE(rl_src.s_reg_low, INVALID_SREG);
599 if (rl_dest.s_reg_low == INVALID_SREG) {
600 // Result is unused, the code is dead. Inlining successful, no code generated.
601 return true;
602 }
603 int v_src_reg = mir_graph_->SRegToVReg(rl_src.s_reg_low);
604 int v_dst_reg = mir_graph_->SRegToVReg(rl_dest.s_reg_low);
605
606 // if argument is the same as inlined intrinsic target
607 if (v_src_reg == v_dst_reg) {
608 rl_src = UpdateLoc(rl_src);
609
610 // if argument is in the physical register
611 if (rl_src.location == kLocPhysReg) {
612 rl_src = LoadValue(rl_src, kCoreReg);
613 OpRegImm(kOpAnd, rl_src.reg, 0x7fffffff);
614 StoreValue(rl_dest, rl_src);
615 return true;
616 }
617 // the argument is in memory
618 DCHECK((rl_src.location == kLocDalvikFrame) ||
619 (rl_src.location == kLocCompilerTemp));
620
621 // Operate directly into memory.
622 int displacement = SRegOffset(rl_dest.s_reg_low);
623 ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
624 LIR *lir = NewLIR3(kX86And32MI, TargetReg(kSp).GetReg(), displacement, 0x7fffffff);
625 AnnotateDalvikRegAccess(lir, displacement >> 2, false /*is_load */, false /* is_64bit */);
626 AnnotateDalvikRegAccess(lir, displacement >> 2, true /* is_load */, false /* is_64bit*/);
627 return true;
628 } else {
629 rl_src = LoadValue(rl_src, kCoreReg);
630 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
631 OpRegRegImm(kOpAnd, rl_result.reg, rl_src.reg, 0x7fffffff);
632 StoreValue(rl_dest, rl_result);
633 return true;
634 }
635}
636
637bool X86Mir2Lir::GenInlinedAbsDouble(CallInfo* info) {
638 RegLocation rl_src = info->args[0];
639 RegLocation rl_dest = InlineTargetWide(info);
640 DCHECK_NE(rl_src.s_reg_low, INVALID_SREG);
641 if (rl_dest.s_reg_low == INVALID_SREG) {
642 // Result is unused, the code is dead. Inlining successful, no code generated.
643 return true;
644 }
645 int v_src_reg = mir_graph_->SRegToVReg(rl_src.s_reg_low);
646 int v_dst_reg = mir_graph_->SRegToVReg(rl_dest.s_reg_low);
647 rl_src = UpdateLocWide(rl_src);
648
649 // if argument is in the physical XMM register
650 if (rl_src.location == kLocPhysReg && rl_src.reg.IsFloat()) {
651 RegLocation rl_result = EvalLoc(rl_dest, kFPReg, true);
652 if (rl_result.reg != rl_src.reg) {
653 LoadConstantWide(rl_result.reg, 0x7fffffffffffffff);
654 NewLIR2(kX86PandRR, rl_result.reg.GetReg(), rl_src.reg.GetReg());
655 } else {
656 RegStorage sign_mask = AllocTempDouble();
657 LoadConstantWide(sign_mask, 0x7fffffffffffffff);
658 NewLIR2(kX86PandRR, rl_result.reg.GetReg(), sign_mask.GetReg());
659 FreeTemp(sign_mask);
660 }
661 StoreValueWide(rl_dest, rl_result);
662 return true;
663 } else if (v_src_reg == v_dst_reg) {
664 // if argument is the same as inlined intrinsic target
665 // if argument is in the physical register
666 if (rl_src.location == kLocPhysReg) {
667 rl_src = LoadValueWide(rl_src, kCoreReg);
668 OpRegImm(kOpAnd, rl_src.reg.GetHigh(), 0x7fffffff);
669 StoreValueWide(rl_dest, rl_src);
670 return true;
671 }
672 // the argument is in memory
673 DCHECK((rl_src.location == kLocDalvikFrame) ||
674 (rl_src.location == kLocCompilerTemp));
675
676 // Operate directly into memory.
677 int displacement = SRegOffset(rl_dest.s_reg_low);
678 ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
679 LIR *lir = NewLIR3(kX86And32MI, TargetReg(kSp).GetReg(), displacement + HIWORD_OFFSET, 0x7fffffff);
680 AnnotateDalvikRegAccess(lir, (displacement + HIWORD_OFFSET) >> 2, true /* is_load */, true /* is_64bit*/);
681 AnnotateDalvikRegAccess(lir, (displacement + HIWORD_OFFSET) >> 2, false /*is_load */, true /* is_64bit */);
682 return true;
683 } else {
684 rl_src = LoadValueWide(rl_src, kCoreReg);
685 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
686 OpRegCopyWide(rl_result.reg, rl_src.reg);
687 OpRegImm(kOpAnd, rl_result.reg.GetHigh(), 0x7fffffff);
688 StoreValueWide(rl_dest, rl_result);
689 return true;
690 }
691}
Brian Carlstrom7940e442013-07-12 13:46:57 -0700692
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700693} // namespace art