fp_x86.cc revision 02959eae949f37445c184ae6f3df4d068ff309e0
1/* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "codegen_x86.h" 18#include "dex/quick/mir_to_lir-inl.h" 19#include "x86_lir.h" 20 21namespace art { 22 23void X86Mir2Lir::GenArithOpFloat(Instruction::Code opcode, 24 RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) { 25 X86OpCode op = kX86Nop; 26 RegLocation rl_result; 27 28 /* 29 * Don't attempt to optimize register usage since these opcodes call out to 30 * the handlers. 31 */ 32 switch (opcode) { 33 case Instruction::ADD_FLOAT_2ADDR: 34 case Instruction::ADD_FLOAT: 35 op = kX86AddssRR; 36 break; 37 case Instruction::SUB_FLOAT_2ADDR: 38 case Instruction::SUB_FLOAT: 39 op = kX86SubssRR; 40 break; 41 case Instruction::DIV_FLOAT_2ADDR: 42 case Instruction::DIV_FLOAT: 43 op = kX86DivssRR; 44 break; 45 case Instruction::MUL_FLOAT_2ADDR: 46 case Instruction::MUL_FLOAT: 47 op = kX86MulssRR; 48 break; 49 case Instruction::REM_FLOAT_2ADDR: 50 case Instruction::REM_FLOAT: 51 GenRemFP(rl_dest, rl_src1, rl_src2, false /* is_double */); 52 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); 62 RegStorage r_dest = rl_result.reg; 63 RegStorage r_src1 = rl_src1.reg; 64 RegStorage r_src2 = rl_src2.reg; 65 if (r_dest == r_src2) { 66 r_src2 = AllocTempSingle(); 67 OpRegCopy(r_src2, r_dest); 68 } 69 OpRegCopy(r_dest, r_src1); 70 NewLIR2(op, r_dest.GetReg(), r_src2.GetReg()); 71 StoreValue(rl_dest, rl_result); 72} 73 74void X86Mir2Lir::GenArithOpDouble(Instruction::Code opcode, 75 RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) { 76 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); 82 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: 104 GenRemFP(rl_dest, rl_src1, rl_src2, true /* is_double */); 105 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); 113 rl_src2 = LoadValueWide(rl_src2, kFPReg); 114 rl_result = EvalLoc(rl_dest, kFPReg, true); 115 if (rl_result.reg == rl_src2.reg) { 116 rl_src2.reg = AllocTempDouble(); 117 OpRegCopy(rl_src2.reg, rl_result.reg); 118 } 119 OpRegCopy(rl_result.reg, rl_src1.reg); 120 NewLIR2(op, rl_result.reg.GetReg(), rl_src2.reg.GetReg()); 121 StoreValueWide(rl_dest, rl_result); 122} 123 124void 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 132 // All memory accesses below reference dalvik regs. 133 ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg); 134 135 // If the source is in physical register, then put it in its location on stack. 136 if (rl_src.location == kLocPhysReg) { 137 RegisterInfo* reg_info = GetRegInfo(rl_src.reg); 138 139 if (reg_info != nullptr && reg_info->IsTemp()) { 140 // Calling FlushSpecificReg because it will only write back VR if it is dirty. 141 FlushSpecificReg(reg_info); 142 // ResetDef to prevent NullifyRange from removing stores. 143 ResetDef(rl_src.reg); 144 } 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. 147 StoreBaseDisp(TargetReg(kSp), src_v_reg_offset, rl_src.reg, k64); 148 } 149 } 150 151 // Push the source virtual register onto the x87 stack. 152 LIR *fild64 = NewLIR2NoDest(kX86Fild64M, TargetReg(kSp).GetReg(), 153 src_v_reg_offset + LOWORD_OFFSET); 154 AnnotateDalvikRegAccess(fild64, (src_v_reg_offset + LOWORD_OFFSET) >> 2, 155 true /* is_load */, true /* is64bit */); 156 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; 160 LIR *fstp = NewLIR2NoDest(opcode, TargetReg(kSp).GetReg(), displacement); 161 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 */ 171 RegLocation rl_result = is_double ? UpdateLocWideTyped(rl_dest, kFPReg) : 172 UpdateLocTyped(rl_dest, kFPReg); 173 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 */ 179 rl_result = EvalLoc(rl_dest, kFPReg, true); 180 if (is_double) { 181 LoadBaseDisp(TargetReg(kSp), dest_v_reg_offset, rl_result.reg, k64); 182 183 StoreFinalValueWide(rl_dest, rl_result); 184 } else { 185 Load32Disp(TargetReg(kSp), dest_v_reg_offset, rl_result.reg); 186 187 StoreFinalValue(rl_dest, rl_result); 188 } 189 } 190} 191 192void X86Mir2Lir::GenConversion(Instruction::Code opcode, RegLocation rl_dest, 193 RegLocation rl_src) { 194 RegisterClass rcSrc = kFPReg; 195 X86OpCode op = kX86Nop; 196 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); 216 // 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); 219 RegStorage temp_reg = AllocTempSingle(); 220 221 LoadConstant(rl_result.reg, 0x7fffffff); 222 NewLIR2(kX86Cvtsi2ssRR, temp_reg.GetReg(), rl_result.reg.GetReg()); 223 NewLIR2(kX86ComissRR, rl_src.reg.GetReg(), temp_reg.GetReg()); 224 LIR* branch_pos_overflow = NewLIR2(kX86Jcc8, 0, kX86CondA); 225 LIR* branch_na_n = NewLIR2(kX86Jcc8, 0, kX86CondP); 226 NewLIR2(kX86Cvttss2siRR, rl_result.reg.GetReg(), rl_src.reg.GetReg()); 227 LIR* branch_normal = NewLIR1(kX86Jmp8, 0); 228 branch_na_n->target = NewLIR0(kPseudoTargetLabel); 229 NewLIR2(kX86Xor32RR, rl_result.reg.GetReg(), rl_result.reg.GetReg()); 230 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); 237 // 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); 240 RegStorage temp_reg = AllocTempDouble(); 241 242 LoadConstant(rl_result.reg, 0x7fffffff); 243 NewLIR2(kX86Cvtsi2sdRR, temp_reg.GetReg(), rl_result.reg.GetReg()); 244 NewLIR2(kX86ComisdRR, rl_src.reg.GetReg(), temp_reg.GetReg()); 245 LIR* branch_pos_overflow = NewLIR2(kX86Jcc8, 0, kX86CondA); 246 LIR* branch_na_n = NewLIR2(kX86Jcc8, 0, kX86CondP); 247 NewLIR2(kX86Cvttsd2siRR, rl_result.reg.GetReg(), rl_src.reg.GetReg()); 248 LIR* branch_normal = NewLIR1(kX86Jmp8, 0); 249 branch_na_n->target = NewLIR0(kPseudoTargetLabel); 250 NewLIR2(kX86Xor32RR, rl_result.reg.GetReg(), rl_result.reg.GetReg()); 251 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: 257 if (Gen64Bit()) { 258 rcSrc = kCoreReg; 259 op = kX86Cvtsqi2sdRR; 260 break; 261 } 262 GenLongToFP(rl_dest, rl_src, true /* is_double */); 263 return; 264 case Instruction::LONG_TO_FLOAT: 265 if (Gen64Bit()) { 266 rcSrc = kCoreReg; 267 op = kX86Cvtsqi2ssRR; 268 break; 269 } 270 GenLongToFP(rl_dest, rl_src, false /* is_double */); 271 return; 272 case Instruction::FLOAT_TO_LONG: 273 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); 293 } else { 294 GenConversionCall(QUICK_ENTRYPOINT_OFFSET(4, pF2l), rl_dest, rl_src); 295 } 296 return; 297 case Instruction::DOUBLE_TO_LONG: 298 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); 318 } else { 319 GenConversionCall(QUICK_ENTRYPOINT_OFFSET(4, pD2l), rl_dest, rl_src); 320 } 321 return; 322 default: 323 LOG(INFO) << "Unexpected opcode: " << opcode; 324 } 325 // At this point, target will be either float or double. 326 DCHECK(rl_dest.fp); 327 if (rl_src.wide) { 328 rl_src = LoadValueWide(rl_src, rcSrc); 329 } else { 330 rl_src = LoadValue(rl_src, rcSrc); 331 } 332 rl_result = EvalLoc(rl_dest, kFPReg, true); 333 NewLIR2(op, rl_result.reg.GetReg(), rl_src.reg.GetReg()); 334 if (rl_dest.wide) { 335 StoreValueWide(rl_dest, rl_result); 336 } else { 337 StoreValue(rl_dest, rl_result); 338 } 339} 340 341void 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 445void 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); 449 if (single) { 450 rl_src1 = LoadValue(rl_src1, kFPReg); 451 rl_src2 = LoadValue(rl_src2, kFPReg); 452 } else { 453 rl_src1 = LoadValueWide(rl_src1, kFPReg); 454 rl_src2 = LoadValueWide(rl_src2, kFPReg); 455 } 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); 459 LoadConstantNoClobber(rl_result.reg, unordered_gt ? 1 : 0); 460 if (single) { 461 NewLIR2(kX86UcomissRR, rl_src1.reg.GetReg(), rl_src2.reg.GetReg()); 462 } else { 463 NewLIR2(kX86UcomisdRR, rl_src1.reg.GetReg(), rl_src2.reg.GetReg()); 464 } 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. 470 if (!IsByteRegister(rl_result.reg)) { 471 LIR* branch2 = NULL; 472 if (unordered_gt) { 473 branch2 = NewLIR2(kX86Jcc8, 0, kX86CondA); 474 NewLIR2(kX86Mov32RI, rl_result.reg.GetReg(), 0x0); 475 } else { 476 branch2 = NewLIR2(kX86Jcc8, 0, kX86CondBe); 477 NewLIR2(kX86Mov32RI, rl_result.reg.GetReg(), 0x1); 478 } 479 branch2->target = NewLIR0(kPseudoTargetLabel); 480 } else { 481 NewLIR2(kX86Set8R, rl_result.reg.GetReg(), kX86CondA /* above - unsigned > */); 482 } 483 NewLIR2(kX86Sbb32RI, rl_result.reg.GetReg(), 0); 484 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) { 492 LIR* taken = &block_label_list_[bb->taken]; 493 LIR* not_taken = &block_label_list_[bb->fall_through]; 494 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); 502 NewLIR2(kX86UcomisdRR, rl_src1.reg.GetReg(), rl_src2.reg.GetReg()); 503 } 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); 508 NewLIR2(kX86UcomissRR, rl_src1.reg.GetReg(), rl_src2.reg.GetReg()); 509 } 510 ConditionCode ccode = mir->meta.ccode; 511 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 } 529 ccode = kCondUlt; 530 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 } 550 ccode = kCondUge; 551 break; 552 default: 553 LOG(FATAL) << "Unexpected ccode: " << ccode; 554 } 555 OpCondBranch(ccode, taken); 556} 557 558void X86Mir2Lir::GenNegFloat(RegLocation rl_dest, RegLocation rl_src) { 559 RegLocation rl_result; 560 rl_src = LoadValue(rl_src, kCoreReg); 561 rl_result = EvalLoc(rl_dest, kCoreReg, true); 562 OpRegRegImm(kOpAdd, rl_result.reg, rl_src.reg, 0x80000000); 563 StoreValue(rl_dest, rl_result); 564} 565 566void X86Mir2Lir::GenNegDouble(RegLocation rl_dest, RegLocation rl_src) { 567 RegLocation rl_result; 568 rl_src = LoadValueWide(rl_src, kCoreReg); 569 rl_result = EvalLocWide(rl_dest, kCoreReg, true); 570 if (Gen64Bit()) { 571 OpRegCopy(rl_result.reg, rl_src.reg); 572 // Flip sign bit. 573 NewLIR2(kX86Rol64RI, rl_result.reg.GetReg(), 1); 574 NewLIR2(kX86Xor64RI, rl_result.reg.GetReg(), 1); 575 NewLIR2(kX86Ror64RI, rl_result.reg.GetReg(), 1); 576 } else { 577 OpRegRegImm(kOpAdd, rl_result.reg.GetHigh(), rl_src.reg.GetHigh(), 0x80000000); 578 OpRegCopy(rl_result.reg, rl_src.reg); 579 } 580 StoreValueWide(rl_dest, rl_result); 581} 582 583bool X86Mir2Lir::GenInlinedSqrt(CallInfo* info) { 584 RegLocation rl_src = info->args[0]; 585 RegLocation rl_dest = InlineTargetWide(info); // double place for result 586 rl_src = LoadValueWide(rl_src, kFPReg); 587 RegLocation rl_result = EvalLoc(rl_dest, kFPReg, true); 588 NewLIR2(kX86SqrtsdRR, rl_result.reg.GetReg(), rl_src.reg.GetReg()); 589 StoreValueWide(rl_dest, rl_result); 590 return true; 591} 592 593bool X86Mir2Lir::GenInlinedAbsFloat(CallInfo* info) { 594 // Get the argument 595 RegLocation rl_src = info->args[0]; 596 597 // Get the inlined intrinsic target virtual register 598 RegLocation rl_dest = InlineTarget(info); 599 600 // Get the virtual register number 601 DCHECK_NE(rl_src.s_reg_low, INVALID_SREG); 602 if (rl_dest.s_reg_low == INVALID_SREG) { 603 // Result is unused, the code is dead. Inlining successful, no code generated. 604 return true; 605 } 606 int v_src_reg = mir_graph_->SRegToVReg(rl_src.s_reg_low); 607 int v_dst_reg = mir_graph_->SRegToVReg(rl_dest.s_reg_low); 608 609 // if argument is the same as inlined intrinsic target 610 if (v_src_reg == v_dst_reg) { 611 rl_src = UpdateLoc(rl_src); 612 613 // if argument is in the physical register 614 if (rl_src.location == kLocPhysReg) { 615 rl_src = LoadValue(rl_src, kCoreReg); 616 OpRegImm(kOpAnd, rl_src.reg, 0x7fffffff); 617 StoreValue(rl_dest, rl_src); 618 return true; 619 } 620 // the argument is in memory 621 DCHECK((rl_src.location == kLocDalvikFrame) || 622 (rl_src.location == kLocCompilerTemp)); 623 624 // Operate directly into memory. 625 int displacement = SRegOffset(rl_dest.s_reg_low); 626 ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg); 627 LIR *lir = NewLIR3(kX86And32MI, TargetReg(kSp).GetReg(), displacement, 0x7fffffff); 628 AnnotateDalvikRegAccess(lir, displacement >> 2, false /*is_load */, false /* is_64bit */); 629 AnnotateDalvikRegAccess(lir, displacement >> 2, true /* is_load */, false /* is_64bit*/); 630 return true; 631 } else { 632 rl_src = LoadValue(rl_src, kCoreReg); 633 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); 634 OpRegRegImm(kOpAnd, rl_result.reg, rl_src.reg, 0x7fffffff); 635 StoreValue(rl_dest, rl_result); 636 return true; 637 } 638} 639 640bool X86Mir2Lir::GenInlinedAbsDouble(CallInfo* info) { 641 RegLocation rl_src = info->args[0]; 642 RegLocation rl_dest = InlineTargetWide(info); 643 DCHECK_NE(rl_src.s_reg_low, INVALID_SREG); 644 if (rl_dest.s_reg_low == INVALID_SREG) { 645 // Result is unused, the code is dead. Inlining successful, no code generated. 646 return true; 647 } 648 int v_src_reg = mir_graph_->SRegToVReg(rl_src.s_reg_low); 649 int v_dst_reg = mir_graph_->SRegToVReg(rl_dest.s_reg_low); 650 rl_src = UpdateLocWide(rl_src); 651 652 // if argument is in the physical XMM register 653 if (rl_src.location == kLocPhysReg && rl_src.reg.IsFloat()) { 654 RegLocation rl_result = EvalLoc(rl_dest, kFPReg, true); 655 if (rl_result.reg != rl_src.reg) { 656 LoadConstantWide(rl_result.reg, 0x7fffffffffffffff); 657 NewLIR2(kX86PandRR, rl_result.reg.GetReg(), rl_src.reg.GetReg()); 658 } else { 659 RegStorage sign_mask = AllocTempDouble(); 660 LoadConstantWide(sign_mask, 0x7fffffffffffffff); 661 NewLIR2(kX86PandRR, rl_result.reg.GetReg(), sign_mask.GetReg()); 662 FreeTemp(sign_mask); 663 } 664 StoreValueWide(rl_dest, rl_result); 665 return true; 666 } else if (v_src_reg == v_dst_reg) { 667 // if argument is the same as inlined intrinsic target 668 // if argument is in the physical register 669 if (rl_src.location == kLocPhysReg) { 670 rl_src = LoadValueWide(rl_src, kCoreReg); 671 OpRegImm(kOpAnd, rl_src.reg.GetHigh(), 0x7fffffff); 672 StoreValueWide(rl_dest, rl_src); 673 return true; 674 } 675 // the argument is in memory 676 DCHECK((rl_src.location == kLocDalvikFrame) || 677 (rl_src.location == kLocCompilerTemp)); 678 679 // Operate directly into memory. 680 int displacement = SRegOffset(rl_dest.s_reg_low); 681 ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg); 682 LIR *lir = NewLIR3(kX86And32MI, TargetReg(kSp).GetReg(), displacement + HIWORD_OFFSET, 0x7fffffff); 683 AnnotateDalvikRegAccess(lir, (displacement + HIWORD_OFFSET) >> 2, true /* is_load */, true /* is_64bit*/); 684 AnnotateDalvikRegAccess(lir, (displacement + HIWORD_OFFSET) >> 2, false /*is_load */, true /* is_64bit */); 685 return true; 686 } else { 687 rl_src = LoadValueWide(rl_src, kCoreReg); 688 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); 689 OpRegCopyWide(rl_result.reg, rl_src.reg); 690 OpRegImm(kOpAnd, rl_result.reg.GetHigh(), 0x7fffffff); 691 StoreValueWide(rl_dest, rl_result); 692 return true; 693 } 694} 695 696} // namespace art 697