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 "dex/reg_storage_eq.h" 20 #include "x86_lir.h" 21 22 namespace art { 23 24 void 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: 52 GenRemFP(rl_dest, rl_src1, rl_src2, false /* is_double */); 53 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); 63 RegStorage r_dest = rl_result.reg; 64 RegStorage r_src1 = rl_src1.reg; 65 RegStorage r_src2 = rl_src2.reg; 66 if (r_dest == r_src2) { 67 r_src2 = AllocTempSingle(); 68 OpRegCopy(r_src2, r_dest); 69 } 70 OpRegCopy(r_dest, r_src1); 71 NewLIR2(op, r_dest.GetReg(), r_src2.GetReg()); 72 StoreValue(rl_dest, rl_result); 73 } 74 75 void X86Mir2Lir::GenArithOpDouble(Instruction::Code opcode, 76 RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) { 77 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); 83 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: 105 GenRemFP(rl_dest, rl_src1, rl_src2, true /* is_double */); 106 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); 114 rl_src2 = LoadValueWide(rl_src2, kFPReg); 115 rl_result = EvalLoc(rl_dest, kFPReg, true); 116 if (rl_result.reg == rl_src2.reg) { 117 rl_src2.reg = AllocTempDouble(); 118 OpRegCopy(rl_src2.reg, rl_result.reg); 119 } 120 OpRegCopy(rl_result.reg, rl_src1.reg); 121 NewLIR2(op, rl_result.reg.GetReg(), rl_src2.reg.GetReg()); 122 StoreValueWide(rl_dest, rl_result); 123 } 124 125 void 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 133 // All memory accesses below reference dalvik regs. 134 ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg); 135 136 // If the source is in physical register, then put it in its location on stack. 137 if (rl_src.location == kLocPhysReg) { 138 RegisterInfo* reg_info = GetRegInfo(rl_src.reg); 139 140 if (reg_info != nullptr && reg_info->IsTemp()) { 141 // Calling FlushSpecificReg because it will only write back VR if it is dirty. 142 FlushSpecificReg(reg_info); 143 // ResetDef to prevent NullifyRange from removing stores. 144 ResetDef(rl_src.reg); 145 } 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. 148 StoreBaseDisp(rs_rX86_SP, src_v_reg_offset, rl_src.reg, k64, kNotVolatile); 149 } 150 } 151 152 // Push the source virtual register onto the x87 stack. 153 LIR *fild64 = NewLIR2NoDest(kX86Fild64M, rs_rX86_SP.GetReg(), 154 src_v_reg_offset + LOWORD_OFFSET); 155 AnnotateDalvikRegAccess(fild64, (src_v_reg_offset + LOWORD_OFFSET) >> 2, 156 true /* is_load */, true /* is64bit */); 157 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; 161 LIR *fstp = NewLIR2NoDest(opcode, rs_rX86_SP.GetReg(), displacement); 162 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 */ 172 RegLocation rl_result = is_double ? UpdateLocWideTyped(rl_dest, kFPReg) : 173 UpdateLocTyped(rl_dest, kFPReg); 174 if (rl_result.location == kLocPhysReg) { 175 /* 176 * We already know that the result is in a physical register but do not know if it is the 177 * right class. So we call EvalLoc(Wide) first which will ensure that it will get moved to the 178 * correct register class. 179 */ 180 rl_result = EvalLoc(rl_dest, kFPReg, true); 181 if (is_double) { 182 LoadBaseDisp(rs_rX86_SP, dest_v_reg_offset, rl_result.reg, k64, kNotVolatile); 183 184 StoreFinalValueWide(rl_dest, rl_result); 185 } else { 186 Load32Disp(rs_rX86_SP, dest_v_reg_offset, rl_result.reg); 187 188 StoreFinalValue(rl_dest, rl_result); 189 } 190 } 191 } 192 193 void X86Mir2Lir::GenConversion(Instruction::Code opcode, RegLocation rl_dest, 194 RegLocation rl_src) { 195 RegisterClass rcSrc = kFPReg; 196 X86OpCode op = kX86Nop; 197 RegLocation rl_result; 198 switch (opcode) { 199 case Instruction::INT_TO_FLOAT: 200 rcSrc = kCoreReg; 201 op = kX86Cvtsi2ssRR; 202 break; 203 case Instruction::DOUBLE_TO_FLOAT: 204 rcSrc = kFPReg; 205 op = kX86Cvtsd2ssRR; 206 break; 207 case Instruction::FLOAT_TO_DOUBLE: 208 rcSrc = kFPReg; 209 op = kX86Cvtss2sdRR; 210 break; 211 case Instruction::INT_TO_DOUBLE: 212 rcSrc = kCoreReg; 213 op = kX86Cvtsi2sdRR; 214 break; 215 case Instruction::FLOAT_TO_INT: { 216 rl_src = LoadValue(rl_src, kFPReg); 217 // In case result vreg is also src vreg, break association to avoid useless copy by EvalLoc() 218 ClobberSReg(rl_dest.s_reg_low); 219 rl_result = EvalLoc(rl_dest, kCoreReg, true); 220 RegStorage temp_reg = AllocTempSingle(); 221 222 LoadConstant(rl_result.reg, 0x7fffffff); 223 NewLIR2(kX86Cvtsi2ssRR, temp_reg.GetReg(), rl_result.reg.GetReg()); 224 NewLIR2(kX86ComissRR, rl_src.reg.GetReg(), temp_reg.GetReg()); 225 LIR* branch_pos_overflow = NewLIR2(kX86Jcc8, 0, kX86CondAe); 226 LIR* branch_na_n = NewLIR2(kX86Jcc8, 0, kX86CondP); 227 NewLIR2(kX86Cvttss2siRR, rl_result.reg.GetReg(), rl_src.reg.GetReg()); 228 LIR* branch_normal = NewLIR1(kX86Jmp8, 0); 229 branch_na_n->target = NewLIR0(kPseudoTargetLabel); 230 NewLIR2(kX86Xor32RR, rl_result.reg.GetReg(), rl_result.reg.GetReg()); 231 branch_pos_overflow->target = NewLIR0(kPseudoTargetLabel); 232 branch_normal->target = NewLIR0(kPseudoTargetLabel); 233 StoreValue(rl_dest, rl_result); 234 return; 235 } 236 case Instruction::DOUBLE_TO_INT: { 237 rl_src = LoadValueWide(rl_src, kFPReg); 238 // In case result vreg is also src vreg, break association to avoid useless copy by EvalLoc() 239 ClobberSReg(rl_dest.s_reg_low); 240 rl_result = EvalLoc(rl_dest, kCoreReg, true); 241 RegStorage temp_reg = AllocTempDouble(); 242 243 LoadConstant(rl_result.reg, 0x7fffffff); 244 NewLIR2(kX86Cvtsi2sdRR, temp_reg.GetReg(), rl_result.reg.GetReg()); 245 NewLIR2(kX86ComisdRR, rl_src.reg.GetReg(), temp_reg.GetReg()); 246 LIR* branch_pos_overflow = NewLIR2(kX86Jcc8, 0, kX86CondAe); 247 LIR* branch_na_n = NewLIR2(kX86Jcc8, 0, kX86CondP); 248 NewLIR2(kX86Cvttsd2siRR, rl_result.reg.GetReg(), rl_src.reg.GetReg()); 249 LIR* branch_normal = NewLIR1(kX86Jmp8, 0); 250 branch_na_n->target = NewLIR0(kPseudoTargetLabel); 251 NewLIR2(kX86Xor32RR, rl_result.reg.GetReg(), rl_result.reg.GetReg()); 252 branch_pos_overflow->target = NewLIR0(kPseudoTargetLabel); 253 branch_normal->target = NewLIR0(kPseudoTargetLabel); 254 StoreValue(rl_dest, rl_result); 255 return; 256 } 257 case Instruction::LONG_TO_DOUBLE: 258 if (cu_->target64) { 259 rcSrc = kCoreReg; 260 op = kX86Cvtsqi2sdRR; 261 break; 262 } 263 GenLongToFP(rl_dest, rl_src, true /* is_double */); 264 return; 265 case Instruction::LONG_TO_FLOAT: 266 if (cu_->target64) { 267 rcSrc = kCoreReg; 268 op = kX86Cvtsqi2ssRR; 269 break; 270 } 271 GenLongToFP(rl_dest, rl_src, false /* is_double */); 272 return; 273 case Instruction::FLOAT_TO_LONG: 274 if (cu_->target64) { 275 rl_src = LoadValue(rl_src, kFPReg); 276 // If result vreg is also src vreg, break association to avoid useless copy by EvalLoc() 277 ClobberSReg(rl_dest.s_reg_low); 278 rl_result = EvalLoc(rl_dest, kCoreReg, true); 279 RegStorage temp_reg = AllocTempSingle(); 280 281 // Set 0x7fffffffffffffff to rl_result 282 LoadConstantWide(rl_result.reg, 0x7fffffffffffffff); 283 NewLIR2(kX86Cvtsqi2ssRR, temp_reg.GetReg(), rl_result.reg.GetReg()); 284 NewLIR2(kX86ComissRR, rl_src.reg.GetReg(), temp_reg.GetReg()); 285 LIR* branch_pos_overflow = NewLIR2(kX86Jcc8, 0, kX86CondAe); 286 LIR* branch_na_n = NewLIR2(kX86Jcc8, 0, kX86CondP); 287 NewLIR2(kX86Cvttss2sqiRR, rl_result.reg.GetReg(), rl_src.reg.GetReg()); 288 LIR* branch_normal = NewLIR1(kX86Jmp8, 0); 289 branch_na_n->target = NewLIR0(kPseudoTargetLabel); 290 NewLIR2(kX86Xor64RR, rl_result.reg.GetReg(), rl_result.reg.GetReg()); 291 branch_pos_overflow->target = NewLIR0(kPseudoTargetLabel); 292 branch_normal->target = NewLIR0(kPseudoTargetLabel); 293 StoreValueWide(rl_dest, rl_result); 294 } else { 295 GenConversionCall(kQuickF2l, rl_dest, rl_src); 296 } 297 return; 298 case Instruction::DOUBLE_TO_LONG: 299 if (cu_->target64) { 300 rl_src = LoadValueWide(rl_src, kFPReg); 301 // If result vreg is also src vreg, break association to avoid useless copy by EvalLoc() 302 ClobberSReg(rl_dest.s_reg_low); 303 rl_result = EvalLoc(rl_dest, kCoreReg, true); 304 RegStorage temp_reg = AllocTempDouble(); 305 306 // Set 0x7fffffffffffffff to rl_result 307 LoadConstantWide(rl_result.reg, 0x7fffffffffffffff); 308 NewLIR2(kX86Cvtsqi2sdRR, temp_reg.GetReg(), rl_result.reg.GetReg()); 309 NewLIR2(kX86ComisdRR, rl_src.reg.GetReg(), temp_reg.GetReg()); 310 LIR* branch_pos_overflow = NewLIR2(kX86Jcc8, 0, kX86CondAe); 311 LIR* branch_na_n = NewLIR2(kX86Jcc8, 0, kX86CondP); 312 NewLIR2(kX86Cvttsd2sqiRR, rl_result.reg.GetReg(), rl_src.reg.GetReg()); 313 LIR* branch_normal = NewLIR1(kX86Jmp8, 0); 314 branch_na_n->target = NewLIR0(kPseudoTargetLabel); 315 NewLIR2(kX86Xor64RR, rl_result.reg.GetReg(), rl_result.reg.GetReg()); 316 branch_pos_overflow->target = NewLIR0(kPseudoTargetLabel); 317 branch_normal->target = NewLIR0(kPseudoTargetLabel); 318 StoreValueWide(rl_dest, rl_result); 319 } else { 320 GenConversionCall(kQuickD2l, rl_dest, rl_src); 321 } 322 return; 323 default: 324 LOG(INFO) << "Unexpected opcode: " << opcode; 325 } 326 // At this point, target will be either float or double. 327 DCHECK(rl_dest.fp); 328 if (rl_src.wide) { 329 rl_src = LoadValueWide(rl_src, rcSrc); 330 } else { 331 rl_src = LoadValue(rl_src, rcSrc); 332 } 333 rl_result = EvalLoc(rl_dest, kFPReg, true); 334 NewLIR2(op, rl_result.reg.GetReg(), rl_src.reg.GetReg()); 335 if (rl_dest.wide) { 336 StoreValueWide(rl_dest, rl_result); 337 } else { 338 StoreValue(rl_dest, rl_result); 339 } 340 } 341 342 void X86Mir2Lir::GenRemFP(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2, bool is_double) { 343 // Compute offsets to the source and destination VRs on stack. 344 int src1_v_reg_offset = SRegOffset(rl_src1.s_reg_low); 345 int src2_v_reg_offset = SRegOffset(rl_src2.s_reg_low); 346 int dest_v_reg_offset = SRegOffset(rl_dest.s_reg_low); 347 348 // Update the in-register state of sources. 349 rl_src1 = is_double ? UpdateLocWide(rl_src1) : UpdateLoc(rl_src1); 350 rl_src2 = is_double ? UpdateLocWide(rl_src2) : UpdateLoc(rl_src2); 351 352 // All memory accesses below reference dalvik regs. 353 ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg); 354 355 // If the source is in physical register, then put it in its location on stack. 356 if (rl_src1.location == kLocPhysReg) { 357 RegisterInfo* reg_info = GetRegInfo(rl_src1.reg); 358 359 if (reg_info != nullptr && reg_info->IsTemp()) { 360 // Calling FlushSpecificReg because it will only write back VR if it is dirty. 361 FlushSpecificReg(reg_info); 362 // ResetDef to prevent NullifyRange from removing stores. 363 ResetDef(rl_src1.reg); 364 } else { 365 // It must have been register promoted if it is not a temp but is still in physical 366 // register. Since we need it to be in memory to convert, we place it there now. 367 StoreBaseDisp(rs_rX86_SP, src1_v_reg_offset, rl_src1.reg, is_double ? k64 : k32, 368 kNotVolatile); 369 } 370 } 371 372 if (rl_src2.location == kLocPhysReg) { 373 RegisterInfo* reg_info = GetRegInfo(rl_src2.reg); 374 if (reg_info != nullptr && reg_info->IsTemp()) { 375 FlushSpecificReg(reg_info); 376 ResetDef(rl_src2.reg); 377 } else { 378 StoreBaseDisp(rs_rX86_SP, src2_v_reg_offset, rl_src2.reg, is_double ? k64 : k32, 379 kNotVolatile); 380 } 381 } 382 383 int fld_opcode = is_double ? kX86Fld64M : kX86Fld32M; 384 385 // Push the source virtual registers onto the x87 stack. 386 LIR *fld_2 = NewLIR2NoDest(fld_opcode, rs_rX86_SP.GetReg(), 387 src2_v_reg_offset + LOWORD_OFFSET); 388 AnnotateDalvikRegAccess(fld_2, (src2_v_reg_offset + LOWORD_OFFSET) >> 2, 389 true /* is_load */, is_double /* is64bit */); 390 391 LIR *fld_1 = NewLIR2NoDest(fld_opcode, rs_rX86_SP.GetReg(), 392 src1_v_reg_offset + LOWORD_OFFSET); 393 AnnotateDalvikRegAccess(fld_1, (src1_v_reg_offset + LOWORD_OFFSET) >> 2, 394 true /* is_load */, is_double /* is64bit */); 395 396 FlushReg(rs_rAX); 397 Clobber(rs_rAX); 398 LockTemp(rs_rAX); 399 400 LIR* retry = NewLIR0(kPseudoTargetLabel); 401 402 // Divide ST(0) by ST(1) and place result to ST(0). 403 NewLIR0(kX86Fprem); 404 405 // Move FPU status word to AX. 406 NewLIR0(kX86Fstsw16R); 407 408 // Check if reduction is complete. 409 OpRegImm(kOpAnd, rs_rAX, 0x400); 410 411 // If no then continue to compute remainder. 412 LIR* branch = NewLIR2(kX86Jcc8, 0, kX86CondNe); 413 branch->target = retry; 414 415 FreeTemp(rs_rAX); 416 417 // Now store result in the destination VR's stack location. 418 int displacement = dest_v_reg_offset + LOWORD_OFFSET; 419 int opcode = is_double ? kX86Fst64M : kX86Fst32M; 420 LIR *fst = NewLIR2NoDest(opcode, rs_rX86_SP.GetReg(), displacement); 421 AnnotateDalvikRegAccess(fst, displacement >> 2, false /* is_load */, is_double /* is64bit */); 422 423 // Pop ST(1) and ST(0). 424 NewLIR0(kX86Fucompp); 425 426 /* 427 * The result is in a physical register if it was in a temp or was register 428 * promoted. For that reason it is enough to check if it is in physical 429 * register. If it is, then we must do all of the bookkeeping necessary to 430 * invalidate temp (if needed) and load in promoted register (if needed). 431 * If the result's location is in memory, then we do not need to do anything 432 * more since the fstp has already placed the correct value in memory. 433 */ 434 RegLocation rl_result = is_double ? UpdateLocWideTyped(rl_dest, kFPReg) : 435 UpdateLocTyped(rl_dest, kFPReg); 436 if (rl_result.location == kLocPhysReg) { 437 rl_result = EvalLoc(rl_dest, kFPReg, true); 438 if (is_double) { 439 LoadBaseDisp(rs_rX86_SP, dest_v_reg_offset, rl_result.reg, k64, kNotVolatile); 440 StoreFinalValueWide(rl_dest, rl_result); 441 } else { 442 Load32Disp(rs_rX86_SP, dest_v_reg_offset, rl_result.reg); 443 StoreFinalValue(rl_dest, rl_result); 444 } 445 } 446 } 447 448 void X86Mir2Lir::GenCmpFP(Instruction::Code code, RegLocation rl_dest, 449 RegLocation rl_src1, RegLocation rl_src2) { 450 bool single = (code == Instruction::CMPL_FLOAT) || (code == Instruction::CMPG_FLOAT); 451 bool unordered_gt = (code == Instruction::CMPG_DOUBLE) || (code == Instruction::CMPG_FLOAT); 452 if (single) { 453 rl_src1 = LoadValue(rl_src1, kFPReg); 454 rl_src2 = LoadValue(rl_src2, kFPReg); 455 } else { 456 rl_src1 = LoadValueWide(rl_src1, kFPReg); 457 rl_src2 = LoadValueWide(rl_src2, kFPReg); 458 } 459 // In case result vreg is also src vreg, break association to avoid useless copy by EvalLoc() 460 ClobberSReg(rl_dest.s_reg_low); 461 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); 462 LoadConstantNoClobber(rl_result.reg, unordered_gt ? 1 : 0); 463 if (single) { 464 NewLIR2(kX86UcomissRR, rl_src1.reg.GetReg(), rl_src2.reg.GetReg()); 465 } else { 466 NewLIR2(kX86UcomisdRR, rl_src1.reg.GetReg(), rl_src2.reg.GetReg()); 467 } 468 LIR* branch = NULL; 469 if (unordered_gt) { 470 branch = NewLIR2(kX86Jcc8, 0, kX86CondPE); 471 } 472 // If the result reg can't be byte accessed, use a jump and move instead of a set. 473 if (!IsByteRegister(rl_result.reg)) { 474 LIR* branch2 = NULL; 475 if (unordered_gt) { 476 branch2 = NewLIR2(kX86Jcc8, 0, kX86CondA); 477 NewLIR2(kX86Mov32RI, rl_result.reg.GetReg(), 0x0); 478 } else { 479 branch2 = NewLIR2(kX86Jcc8, 0, kX86CondBe); 480 NewLIR2(kX86Mov32RI, rl_result.reg.GetReg(), 0x1); 481 } 482 branch2->target = NewLIR0(kPseudoTargetLabel); 483 } else { 484 NewLIR2(kX86Set8R, rl_result.reg.GetReg(), kX86CondA /* above - unsigned > */); 485 } 486 NewLIR2(kX86Sbb32RI, rl_result.reg.GetReg(), 0); 487 if (unordered_gt) { 488 branch->target = NewLIR0(kPseudoTargetLabel); 489 } 490 StoreValue(rl_dest, rl_result); 491 } 492 493 void X86Mir2Lir::GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias, 494 bool is_double) { 495 LIR* taken = &block_label_list_[bb->taken]; 496 LIR* not_taken = &block_label_list_[bb->fall_through]; 497 LIR* branch = NULL; 498 RegLocation rl_src1; 499 RegLocation rl_src2; 500 if (is_double) { 501 rl_src1 = mir_graph_->GetSrcWide(mir, 0); 502 rl_src2 = mir_graph_->GetSrcWide(mir, 2); 503 rl_src1 = LoadValueWide(rl_src1, kFPReg); 504 rl_src2 = LoadValueWide(rl_src2, kFPReg); 505 NewLIR2(kX86UcomisdRR, rl_src1.reg.GetReg(), rl_src2.reg.GetReg()); 506 } else { 507 rl_src1 = mir_graph_->GetSrc(mir, 0); 508 rl_src2 = mir_graph_->GetSrc(mir, 1); 509 rl_src1 = LoadValue(rl_src1, kFPReg); 510 rl_src2 = LoadValue(rl_src2, kFPReg); 511 NewLIR2(kX86UcomissRR, rl_src1.reg.GetReg(), rl_src2.reg.GetReg()); 512 } 513 ConditionCode ccode = mir->meta.ccode; 514 switch (ccode) { 515 case kCondEq: 516 if (!gt_bias) { 517 branch = NewLIR2(kX86Jcc8, 0, kX86CondPE); 518 branch->target = not_taken; 519 } 520 break; 521 case kCondNe: 522 if (!gt_bias) { 523 branch = NewLIR2(kX86Jcc8, 0, kX86CondPE); 524 branch->target = taken; 525 } 526 break; 527 case kCondLt: 528 if (gt_bias) { 529 branch = NewLIR2(kX86Jcc8, 0, kX86CondPE); 530 branch->target = not_taken; 531 } 532 ccode = kCondUlt; 533 break; 534 case kCondLe: 535 if (gt_bias) { 536 branch = NewLIR2(kX86Jcc8, 0, kX86CondPE); 537 branch->target = not_taken; 538 } 539 ccode = kCondLs; 540 break; 541 case kCondGt: 542 if (gt_bias) { 543 branch = NewLIR2(kX86Jcc8, 0, kX86CondPE); 544 branch->target = taken; 545 } 546 ccode = kCondHi; 547 break; 548 case kCondGe: 549 if (gt_bias) { 550 branch = NewLIR2(kX86Jcc8, 0, kX86CondPE); 551 branch->target = taken; 552 } 553 ccode = kCondUge; 554 break; 555 default: 556 LOG(FATAL) << "Unexpected ccode: " << ccode; 557 } 558 OpCondBranch(ccode, taken); 559 } 560 561 void X86Mir2Lir::GenNegFloat(RegLocation rl_dest, RegLocation rl_src) { 562 RegLocation rl_result; 563 rl_src = LoadValue(rl_src, kCoreReg); 564 rl_result = EvalLoc(rl_dest, kCoreReg, true); 565 OpRegRegImm(kOpAdd, rl_result.reg, rl_src.reg, 0x80000000); 566 StoreValue(rl_dest, rl_result); 567 } 568 569 void X86Mir2Lir::GenNegDouble(RegLocation rl_dest, RegLocation rl_src) { 570 RegLocation rl_result; 571 rl_src = LoadValueWide(rl_src, kCoreReg); 572 rl_result = EvalLocWide(rl_dest, kCoreReg, true); 573 if (cu_->target64) { 574 OpRegCopy(rl_result.reg, rl_src.reg); 575 // Flip sign bit. 576 NewLIR2(kX86Rol64RI, rl_result.reg.GetReg(), 1); 577 NewLIR2(kX86Xor64RI, rl_result.reg.GetReg(), 1); 578 NewLIR2(kX86Ror64RI, rl_result.reg.GetReg(), 1); 579 } else { 580 OpRegRegImm(kOpAdd, rl_result.reg.GetHigh(), rl_src.reg.GetHigh(), 0x80000000); 581 OpRegCopy(rl_result.reg, rl_src.reg); 582 } 583 StoreValueWide(rl_dest, rl_result); 584 } 585 586 bool X86Mir2Lir::GenInlinedSqrt(CallInfo* info) { 587 RegLocation rl_src = info->args[0]; 588 RegLocation rl_dest = InlineTargetWide(info); // double place for result 589 rl_src = LoadValueWide(rl_src, kFPReg); 590 RegLocation rl_result = EvalLoc(rl_dest, kFPReg, true); 591 NewLIR2(kX86SqrtsdRR, rl_result.reg.GetReg(), rl_src.reg.GetReg()); 592 StoreValueWide(rl_dest, rl_result); 593 return true; 594 } 595 596 bool X86Mir2Lir::GenInlinedAbsFloat(CallInfo* info) { 597 // Get the argument 598 RegLocation rl_src = info->args[0]; 599 600 // Get the inlined intrinsic target virtual register 601 RegLocation rl_dest = InlineTarget(info); 602 603 // Get the virtual register number 604 DCHECK_NE(rl_src.s_reg_low, INVALID_SREG); 605 if (rl_dest.s_reg_low == INVALID_SREG) { 606 // Result is unused, the code is dead. Inlining successful, no code generated. 607 return true; 608 } 609 int v_src_reg = mir_graph_->SRegToVReg(rl_src.s_reg_low); 610 int v_dst_reg = mir_graph_->SRegToVReg(rl_dest.s_reg_low); 611 612 // if argument is the same as inlined intrinsic target 613 if (v_src_reg == v_dst_reg) { 614 rl_src = UpdateLoc(rl_src); 615 616 // if argument is in the physical register 617 if (rl_src.location == kLocPhysReg) { 618 rl_src = LoadValue(rl_src, kCoreReg); 619 OpRegImm(kOpAnd, rl_src.reg, 0x7fffffff); 620 StoreValue(rl_dest, rl_src); 621 return true; 622 } 623 // the argument is in memory 624 DCHECK((rl_src.location == kLocDalvikFrame) || 625 (rl_src.location == kLocCompilerTemp)); 626 627 // Operate directly into memory. 628 int displacement = SRegOffset(rl_dest.s_reg_low); 629 ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg); 630 LIR *lir = NewLIR3(kX86And32MI, rs_rX86_SP.GetReg(), displacement, 0x7fffffff); 631 AnnotateDalvikRegAccess(lir, displacement >> 2, false /*is_load */, false /* is_64bit */); 632 AnnotateDalvikRegAccess(lir, displacement >> 2, true /* is_load */, false /* is_64bit*/); 633 return true; 634 } else { 635 rl_src = LoadValue(rl_src, kCoreReg); 636 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); 637 OpRegRegImm(kOpAnd, rl_result.reg, rl_src.reg, 0x7fffffff); 638 StoreValue(rl_dest, rl_result); 639 return true; 640 } 641 } 642 643 bool X86Mir2Lir::GenInlinedAbsDouble(CallInfo* info) { 644 RegLocation rl_src = info->args[0]; 645 RegLocation rl_dest = InlineTargetWide(info); 646 DCHECK_NE(rl_src.s_reg_low, INVALID_SREG); 647 if (rl_dest.s_reg_low == INVALID_SREG) { 648 // Result is unused, the code is dead. Inlining successful, no code generated. 649 return true; 650 } 651 if (cu_->target64) { 652 rl_src = LoadValueWide(rl_src, kCoreReg); 653 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); 654 OpRegCopyWide(rl_result.reg, rl_src.reg); 655 OpRegImm(kOpLsl, rl_result.reg, 1); 656 OpRegImm(kOpLsr, rl_result.reg, 1); 657 StoreValueWide(rl_dest, rl_result); 658 return true; 659 } 660 int v_src_reg = mir_graph_->SRegToVReg(rl_src.s_reg_low); 661 int v_dst_reg = mir_graph_->SRegToVReg(rl_dest.s_reg_low); 662 rl_src = UpdateLocWide(rl_src); 663 664 // if argument is in the physical XMM register 665 if (rl_src.location == kLocPhysReg && rl_src.reg.IsFloat()) { 666 RegLocation rl_result = EvalLoc(rl_dest, kFPReg, true); 667 if (rl_result.reg != rl_src.reg) { 668 LoadConstantWide(rl_result.reg, 0x7fffffffffffffff); 669 NewLIR2(kX86PandRR, rl_result.reg.GetReg(), rl_src.reg.GetReg()); 670 } else { 671 RegStorage sign_mask = AllocTempDouble(); 672 LoadConstantWide(sign_mask, 0x7fffffffffffffff); 673 NewLIR2(kX86PandRR, rl_result.reg.GetReg(), sign_mask.GetReg()); 674 FreeTemp(sign_mask); 675 } 676 StoreValueWide(rl_dest, rl_result); 677 return true; 678 } else if (v_src_reg == v_dst_reg) { 679 // if argument is the same as inlined intrinsic target 680 // if argument is in the physical register 681 if (rl_src.location == kLocPhysReg) { 682 rl_src = LoadValueWide(rl_src, kCoreReg); 683 OpRegImm(kOpAnd, rl_src.reg.GetHigh(), 0x7fffffff); 684 StoreValueWide(rl_dest, rl_src); 685 return true; 686 } 687 // the argument is in memory 688 DCHECK((rl_src.location == kLocDalvikFrame) || 689 (rl_src.location == kLocCompilerTemp)); 690 691 // Operate directly into memory. 692 int displacement = SRegOffset(rl_dest.s_reg_low); 693 ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg); 694 LIR *lir = NewLIR3(kX86And32MI, rs_rX86_SP.GetReg(), displacement + HIWORD_OFFSET, 0x7fffffff); 695 AnnotateDalvikRegAccess(lir, (displacement + HIWORD_OFFSET) >> 2, true /* is_load */, true /* is_64bit*/); 696 AnnotateDalvikRegAccess(lir, (displacement + HIWORD_OFFSET) >> 2, false /*is_load */, true /* is_64bit */); 697 return true; 698 } else { 699 rl_src = LoadValueWide(rl_src, kCoreReg); 700 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); 701 OpRegCopyWide(rl_result.reg, rl_src.reg); 702 OpRegImm(kOpAnd, rl_result.reg.GetHigh(), 0x7fffffff); 703 StoreValueWide(rl_dest, rl_result); 704 return true; 705 } 706 } 707 708 bool X86Mir2Lir::GenInlinedMinMaxFP(CallInfo* info, bool is_min, bool is_double) { 709 if (is_double) { 710 RegLocation rl_src1 = LoadValueWide(info->args[0], kFPReg); 711 RegLocation rl_src2 = LoadValueWide(info->args[2], kFPReg); 712 RegLocation rl_dest = InlineTargetWide(info); 713 RegLocation rl_result = EvalLocWide(rl_dest, kFPReg, true); 714 715 // Avoid src2 corruption by OpRegCopyWide. 716 if (rl_result.reg == rl_src2.reg) { 717 std::swap(rl_src2.reg, rl_src1.reg); 718 } 719 720 OpRegCopyWide(rl_result.reg, rl_src1.reg); 721 NewLIR2(kX86UcomisdRR, rl_result.reg.GetReg(), rl_src2.reg.GetReg()); 722 // If either arg is NaN, return NaN. 723 LIR* branch_nan = NewLIR2(kX86Jcc8, 0, kX86CondP); 724 // Min/Max branches. 725 LIR* branch_cond1 = NewLIR2(kX86Jcc8, 0, (is_min) ? kX86CondA : kX86CondB); 726 LIR* branch_cond2 = NewLIR2(kX86Jcc8, 0, (is_min) ? kX86CondB : kX86CondA); 727 // If equal, we need to resolve situations like min/max(0.0, -0.0) == -0.0/0.0. 728 NewLIR2((is_min) ? kX86OrpdRR : kX86AndpdRR, rl_result.reg.GetReg(), rl_src2.reg.GetReg()); 729 LIR* branch_exit_equal = NewLIR1(kX86Jmp8, 0); 730 // Handle NaN. 731 branch_nan->target = NewLIR0(kPseudoTargetLabel); 732 LoadConstantWide(rl_result.reg, INT64_C(0x7ff8000000000000)); 733 LIR* branch_exit_nan = NewLIR1(kX86Jmp8, 0); 734 // Handle Min/Max. Copy greater/lesser value from src2. 735 branch_cond1->target = NewLIR0(kPseudoTargetLabel); 736 OpRegCopyWide(rl_result.reg, rl_src2.reg); 737 // Right operand is already in result reg. 738 branch_cond2->target = NewLIR0(kPseudoTargetLabel); 739 // Exit. 740 branch_exit_nan->target = NewLIR0(kPseudoTargetLabel); 741 branch_exit_equal->target = NewLIR0(kPseudoTargetLabel); 742 StoreValueWide(rl_dest, rl_result); 743 } else { 744 RegLocation rl_src1 = LoadValue(info->args[0], kFPReg); 745 RegLocation rl_src2 = LoadValue(info->args[1], kFPReg); 746 RegLocation rl_dest = InlineTarget(info); 747 RegLocation rl_result = EvalLoc(rl_dest, kFPReg, true); 748 749 // Avoid src2 corruption by OpRegCopyWide. 750 if (rl_result.reg == rl_src2.reg) { 751 std::swap(rl_src2.reg, rl_src1.reg); 752 } 753 754 OpRegCopy(rl_result.reg, rl_src1.reg); 755 NewLIR2(kX86UcomissRR, rl_result.reg.GetReg(), rl_src2.reg.GetReg()); 756 // If either arg is NaN, return NaN. 757 LIR* branch_nan = NewLIR2(kX86Jcc8, 0, kX86CondP); 758 // Min/Max branches. 759 LIR* branch_cond1 = NewLIR2(kX86Jcc8, 0, (is_min) ? kX86CondA : kX86CondB); 760 LIR* branch_cond2 = NewLIR2(kX86Jcc8, 0, (is_min) ? kX86CondB : kX86CondA); 761 // If equal, we need to resolve situations like min/max(0.0, -0.0) == -0.0/0.0. 762 NewLIR2((is_min) ? kX86OrpsRR : kX86AndpsRR, rl_result.reg.GetReg(), rl_src2.reg.GetReg()); 763 LIR* branch_exit_equal = NewLIR1(kX86Jmp8, 0); 764 // Handle NaN. 765 branch_nan->target = NewLIR0(kPseudoTargetLabel); 766 LoadConstantNoClobber(rl_result.reg, 0x7fc00000); 767 LIR* branch_exit_nan = NewLIR1(kX86Jmp8, 0); 768 // Handle Min/Max. Copy greater/lesser value from src2. 769 branch_cond1->target = NewLIR0(kPseudoTargetLabel); 770 OpRegCopy(rl_result.reg, rl_src2.reg); 771 // Right operand is already in result reg. 772 branch_cond2->target = NewLIR0(kPseudoTargetLabel); 773 // Exit. 774 branch_exit_nan->target = NewLIR0(kPseudoTargetLabel); 775 branch_exit_equal->target = NewLIR0(kPseudoTargetLabel); 776 StoreValue(rl_dest, rl_result); 777 } 778 return true; 779 } 780 781 } // namespace art 782