utility_x86.cc revision 2f244e9faccfcca68af3c5484c397a01a1c3a342
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/dataflow_iterator-inl.h" 20#include "x86_lir.h" 21 22namespace art { 23 24/* This file contains codegen for the X86 ISA */ 25 26LIR* X86Mir2Lir::OpFpRegCopy(RegStorage r_dest, RegStorage r_src) { 27 int opcode; 28 /* must be both DOUBLE or both not DOUBLE */ 29 DCHECK(r_dest.IsFloat() || r_src.IsFloat()); 30 DCHECK_EQ(r_dest.IsDouble(), r_src.IsDouble()); 31 if (r_dest.IsDouble()) { 32 opcode = kX86MovsdRR; 33 } else { 34 if (r_dest.IsSingle()) { 35 if (r_src.IsSingle()) { 36 opcode = kX86MovssRR; 37 } else { // Fpr <- Gpr 38 opcode = kX86MovdxrRR; 39 } 40 } else { // Gpr <- Fpr 41 DCHECK(r_src.IsSingle()) << "Raw: 0x" << std::hex << r_src.GetRawBits(); 42 opcode = kX86MovdrxRR; 43 } 44 } 45 DCHECK_NE((EncodingMap[opcode].flags & IS_BINARY_OP), 0ULL); 46 LIR* res = RawLIR(current_dalvik_offset_, opcode, r_dest.GetReg(), r_src.GetReg()); 47 if (r_dest == r_src) { 48 res->flags.is_nop = true; 49 } 50 return res; 51} 52 53bool X86Mir2Lir::InexpensiveConstantInt(int32_t value) { 54 return true; 55} 56 57bool X86Mir2Lir::InexpensiveConstantFloat(int32_t value) { 58 return false; 59} 60 61bool X86Mir2Lir::InexpensiveConstantLong(int64_t value) { 62 return true; 63} 64 65bool X86Mir2Lir::InexpensiveConstantDouble(int64_t value) { 66 return value == 0; 67} 68 69/* 70 * Load a immediate using a shortcut if possible; otherwise 71 * grab from the per-translation literal pool. If target is 72 * a high register, build constant into a low register and copy. 73 * 74 * No additional register clobbering operation performed. Use this version when 75 * 1) r_dest is freshly returned from AllocTemp or 76 * 2) The codegen is under fixed register usage 77 */ 78LIR* X86Mir2Lir::LoadConstantNoClobber(RegStorage r_dest, int value) { 79 RegStorage r_dest_save = r_dest; 80 if (r_dest.IsFloat()) { 81 if (value == 0) { 82 return NewLIR2(kX86XorpsRR, r_dest.GetReg(), r_dest.GetReg()); 83 } 84 r_dest = AllocTemp(); 85 } 86 87 LIR *res; 88 if (value == 0) { 89 res = NewLIR2(kX86Xor32RR, r_dest.GetReg(), r_dest.GetReg()); 90 } else { 91 // Note, there is no byte immediate form of a 32 bit immediate move. 92 res = NewLIR2(kX86Mov32RI, r_dest.GetReg(), value); 93 } 94 95 if (r_dest_save.IsFloat()) { 96 NewLIR2(kX86MovdxrRR, r_dest_save.GetReg(), r_dest.GetReg()); 97 FreeTemp(r_dest); 98 } 99 100 return res; 101} 102 103LIR* X86Mir2Lir::OpUnconditionalBranch(LIR* target) { 104 LIR* res = NewLIR1(kX86Jmp8, 0 /* offset to be patched during assembly*/); 105 res->target = target; 106 return res; 107} 108 109LIR* X86Mir2Lir::OpCondBranch(ConditionCode cc, LIR* target) { 110 LIR* branch = NewLIR2(kX86Jcc8, 0 /* offset to be patched */, 111 X86ConditionEncoding(cc)); 112 branch->target = target; 113 return branch; 114} 115 116LIR* X86Mir2Lir::OpReg(OpKind op, RegStorage r_dest_src) { 117 X86OpCode opcode = kX86Bkpt; 118 switch (op) { 119 case kOpNeg: opcode = kX86Neg32R; break; 120 case kOpNot: opcode = kX86Not32R; break; 121 case kOpRev: opcode = kX86Bswap32R; break; 122 case kOpBlx: opcode = kX86CallR; break; 123 default: 124 LOG(FATAL) << "Bad case in OpReg " << op; 125 } 126 return NewLIR1(opcode, r_dest_src.GetReg()); 127} 128 129LIR* X86Mir2Lir::OpRegImm(OpKind op, RegStorage r_dest_src1, int value) { 130 X86OpCode opcode = kX86Bkpt; 131 bool byte_imm = IS_SIMM8(value); 132 DCHECK(!r_dest_src1.IsFloat()); 133 switch (op) { 134 case kOpLsl: opcode = kX86Sal32RI; break; 135 case kOpLsr: opcode = kX86Shr32RI; break; 136 case kOpAsr: opcode = kX86Sar32RI; break; 137 case kOpAdd: opcode = byte_imm ? kX86Add32RI8 : kX86Add32RI; break; 138 case kOpOr: opcode = byte_imm ? kX86Or32RI8 : kX86Or32RI; break; 139 case kOpAdc: opcode = byte_imm ? kX86Adc32RI8 : kX86Adc32RI; break; 140 // case kOpSbb: opcode = kX86Sbb32RI; break; 141 case kOpAnd: opcode = byte_imm ? kX86And32RI8 : kX86And32RI; break; 142 case kOpSub: opcode = byte_imm ? kX86Sub32RI8 : kX86Sub32RI; break; 143 case kOpXor: opcode = byte_imm ? kX86Xor32RI8 : kX86Xor32RI; break; 144 case kOpCmp: opcode = byte_imm ? kX86Cmp32RI8 : kX86Cmp32RI; break; 145 case kOpMov: 146 /* 147 * Moving the constant zero into register can be specialized as an xor of the register. 148 * However, that sets eflags while the move does not. For that reason here, always do 149 * the move and if caller is flexible, they should be calling LoadConstantNoClobber instead. 150 */ 151 opcode = kX86Mov32RI; 152 break; 153 case kOpMul: 154 opcode = byte_imm ? kX86Imul32RRI8 : kX86Imul32RRI; 155 return NewLIR3(opcode, r_dest_src1.GetReg(), r_dest_src1.GetReg(), value); 156 default: 157 LOG(FATAL) << "Bad case in OpRegImm " << op; 158 } 159 return NewLIR2(opcode, r_dest_src1.GetReg(), value); 160} 161 162LIR* X86Mir2Lir::OpRegReg(OpKind op, RegStorage r_dest_src1, RegStorage r_src2) { 163 X86OpCode opcode = kX86Nop; 164 bool src2_must_be_cx = false; 165 switch (op) { 166 // X86 unary opcodes 167 case kOpMvn: 168 OpRegCopy(r_dest_src1, r_src2); 169 return OpReg(kOpNot, r_dest_src1); 170 case kOpNeg: 171 OpRegCopy(r_dest_src1, r_src2); 172 return OpReg(kOpNeg, r_dest_src1); 173 case kOpRev: 174 OpRegCopy(r_dest_src1, r_src2); 175 return OpReg(kOpRev, r_dest_src1); 176 case kOpRevsh: 177 OpRegCopy(r_dest_src1, r_src2); 178 OpReg(kOpRev, r_dest_src1); 179 return OpRegImm(kOpAsr, r_dest_src1, 16); 180 // X86 binary opcodes 181 case kOpSub: opcode = kX86Sub32RR; break; 182 case kOpSbc: opcode = kX86Sbb32RR; break; 183 case kOpLsl: opcode = kX86Sal32RC; src2_must_be_cx = true; break; 184 case kOpLsr: opcode = kX86Shr32RC; src2_must_be_cx = true; break; 185 case kOpAsr: opcode = kX86Sar32RC; src2_must_be_cx = true; break; 186 case kOpMov: opcode = kX86Mov32RR; break; 187 case kOpCmp: opcode = kX86Cmp32RR; break; 188 case kOpAdd: opcode = kX86Add32RR; break; 189 case kOpAdc: opcode = kX86Adc32RR; break; 190 case kOpAnd: opcode = kX86And32RR; break; 191 case kOpOr: opcode = kX86Or32RR; break; 192 case kOpXor: opcode = kX86Xor32RR; break; 193 case kOp2Byte: 194 // TODO: there are several instances of this check. A utility function perhaps? 195 // TODO: Similar to Arm's reg < 8 check. Perhaps add attribute checks to RegStorage? 196 // Use shifts instead of a byte operand if the source can't be byte accessed. 197 if (r_src2.GetRegNum() >= rs_rX86_SP.GetRegNum()) { 198 NewLIR2(kX86Mov32RR, r_dest_src1.GetReg(), r_src2.GetReg()); 199 NewLIR2(kX86Sal32RI, r_dest_src1.GetReg(), 24); 200 return NewLIR2(kX86Sar32RI, r_dest_src1.GetReg(), 24); 201 } else { 202 opcode = kX86Movsx8RR; 203 } 204 break; 205 case kOp2Short: opcode = kX86Movsx16RR; break; 206 case kOp2Char: opcode = kX86Movzx16RR; break; 207 case kOpMul: opcode = kX86Imul32RR; break; 208 default: 209 LOG(FATAL) << "Bad case in OpRegReg " << op; 210 break; 211 } 212 CHECK(!src2_must_be_cx || r_src2.GetReg() == rs_rCX.GetReg()); 213 return NewLIR2(opcode, r_dest_src1.GetReg(), r_src2.GetReg()); 214} 215 216LIR* X86Mir2Lir::OpMovRegMem(RegStorage r_dest, RegStorage r_base, int offset, MoveType move_type) { 217 DCHECK(!r_base.IsFloat()); 218 X86OpCode opcode = kX86Nop; 219 int dest = r_dest.IsPair() ? r_dest.GetLowReg() : r_dest.GetReg(); 220 switch (move_type) { 221 case kMov8GP: 222 CHECK(!r_dest.IsFloat()); 223 opcode = kX86Mov8RM; 224 break; 225 case kMov16GP: 226 CHECK(!r_dest.IsFloat()); 227 opcode = kX86Mov16RM; 228 break; 229 case kMov32GP: 230 CHECK(!r_dest.IsFloat()); 231 opcode = kX86Mov32RM; 232 break; 233 case kMov32FP: 234 CHECK(r_dest.IsFloat()); 235 opcode = kX86MovssRM; 236 break; 237 case kMov64FP: 238 CHECK(r_dest.IsFloat()); 239 opcode = kX86MovsdRM; 240 break; 241 case kMovU128FP: 242 CHECK(r_dest.IsFloat()); 243 opcode = kX86MovupsRM; 244 break; 245 case kMovA128FP: 246 CHECK(r_dest.IsFloat()); 247 opcode = kX86MovapsRM; 248 break; 249 case kMovLo128FP: 250 CHECK(r_dest.IsFloat()); 251 opcode = kX86MovlpsRM; 252 break; 253 case kMovHi128FP: 254 CHECK(r_dest.IsFloat()); 255 opcode = kX86MovhpsRM; 256 break; 257 case kMov64GP: 258 case kMovLo64FP: 259 case kMovHi64FP: 260 default: 261 LOG(FATAL) << "Bad case in OpMovRegMem"; 262 break; 263 } 264 265 return NewLIR3(opcode, dest, r_base.GetReg(), offset); 266} 267 268LIR* X86Mir2Lir::OpMovMemReg(RegStorage r_base, int offset, RegStorage r_src, MoveType move_type) { 269 DCHECK(!r_base.IsFloat()); 270 int src = r_src.IsPair() ? r_src.GetLowReg() : r_src.GetReg(); 271 272 X86OpCode opcode = kX86Nop; 273 switch (move_type) { 274 case kMov8GP: 275 CHECK(!r_src.IsFloat()); 276 opcode = kX86Mov8MR; 277 break; 278 case kMov16GP: 279 CHECK(!r_src.IsFloat()); 280 opcode = kX86Mov16MR; 281 break; 282 case kMov32GP: 283 CHECK(!r_src.IsFloat()); 284 opcode = kX86Mov32MR; 285 break; 286 case kMov32FP: 287 CHECK(r_src.IsFloat()); 288 opcode = kX86MovssMR; 289 break; 290 case kMov64FP: 291 CHECK(r_src.IsFloat()); 292 opcode = kX86MovsdMR; 293 break; 294 case kMovU128FP: 295 CHECK(r_src.IsFloat()); 296 opcode = kX86MovupsMR; 297 break; 298 case kMovA128FP: 299 CHECK(r_src.IsFloat()); 300 opcode = kX86MovapsMR; 301 break; 302 case kMovLo128FP: 303 CHECK(r_src.IsFloat()); 304 opcode = kX86MovlpsMR; 305 break; 306 case kMovHi128FP: 307 CHECK(r_src.IsFloat()); 308 opcode = kX86MovhpsMR; 309 break; 310 case kMov64GP: 311 case kMovLo64FP: 312 case kMovHi64FP: 313 default: 314 LOG(FATAL) << "Bad case in OpMovMemReg"; 315 break; 316 } 317 318 return NewLIR3(opcode, r_base.GetReg(), offset, src); 319} 320 321LIR* X86Mir2Lir::OpCondRegReg(OpKind op, ConditionCode cc, RegStorage r_dest, RegStorage r_src) { 322 // The only conditional reg to reg operation supported is Cmov 323 DCHECK_EQ(op, kOpCmov); 324 return NewLIR3(kX86Cmov32RRC, r_dest.GetReg(), r_src.GetReg(), X86ConditionEncoding(cc)); 325} 326 327LIR* X86Mir2Lir::OpRegMem(OpKind op, RegStorage r_dest, RegStorage r_base, int offset) { 328 X86OpCode opcode = kX86Nop; 329 switch (op) { 330 // X86 binary opcodes 331 case kOpSub: opcode = kX86Sub32RM; break; 332 case kOpMov: opcode = kX86Mov32RM; break; 333 case kOpCmp: opcode = kX86Cmp32RM; break; 334 case kOpAdd: opcode = kX86Add32RM; break; 335 case kOpAnd: opcode = kX86And32RM; break; 336 case kOpOr: opcode = kX86Or32RM; break; 337 case kOpXor: opcode = kX86Xor32RM; break; 338 case kOp2Byte: opcode = kX86Movsx8RM; break; 339 case kOp2Short: opcode = kX86Movsx16RM; break; 340 case kOp2Char: opcode = kX86Movzx16RM; break; 341 case kOpMul: 342 default: 343 LOG(FATAL) << "Bad case in OpRegMem " << op; 344 break; 345 } 346 LIR *l = NewLIR3(opcode, r_dest.GetReg(), r_base.GetReg(), offset); 347 if (r_base == rs_rX86_SP) { 348 AnnotateDalvikRegAccess(l, offset >> 2, true /* is_load */, false /* is_64bit */); 349 } 350 return l; 351} 352 353LIR* X86Mir2Lir::OpMemReg(OpKind op, RegLocation rl_dest, int r_value) { 354 DCHECK_NE(rl_dest.location, kLocPhysReg); 355 int displacement = SRegOffset(rl_dest.s_reg_low); 356 X86OpCode opcode = kX86Nop; 357 switch (op) { 358 case kOpSub: opcode = kX86Sub32MR; break; 359 case kOpMov: opcode = kX86Mov32MR; break; 360 case kOpCmp: opcode = kX86Cmp32MR; break; 361 case kOpAdd: opcode = kX86Add32MR; break; 362 case kOpAnd: opcode = kX86And32MR; break; 363 case kOpOr: opcode = kX86Or32MR; break; 364 case kOpXor: opcode = kX86Xor32MR; break; 365 case kOpLsl: opcode = kX86Sal32MC; break; 366 case kOpLsr: opcode = kX86Shr32MC; break; 367 case kOpAsr: opcode = kX86Sar32MC; break; 368 default: 369 LOG(FATAL) << "Bad case in OpMemReg " << op; 370 break; 371 } 372 LIR *l = NewLIR3(opcode, rs_rX86_SP.GetReg(), displacement, r_value); 373 AnnotateDalvikRegAccess(l, displacement >> 2, true /* is_load */, false /* is_64bit */); 374 AnnotateDalvikRegAccess(l, displacement >> 2, false /* is_load */, false /* is_64bit */); 375 return l; 376} 377 378LIR* X86Mir2Lir::OpRegMem(OpKind op, RegStorage r_dest, RegLocation rl_value) { 379 DCHECK_NE(rl_value.location, kLocPhysReg); 380 int displacement = SRegOffset(rl_value.s_reg_low); 381 X86OpCode opcode = kX86Nop; 382 switch (op) { 383 case kOpSub: opcode = kX86Sub32RM; break; 384 case kOpMov: opcode = kX86Mov32RM; break; 385 case kOpCmp: opcode = kX86Cmp32RM; break; 386 case kOpAdd: opcode = kX86Add32RM; break; 387 case kOpAnd: opcode = kX86And32RM; break; 388 case kOpOr: opcode = kX86Or32RM; break; 389 case kOpXor: opcode = kX86Xor32RM; break; 390 case kOpMul: opcode = kX86Imul32RM; break; 391 default: 392 LOG(FATAL) << "Bad case in OpRegMem " << op; 393 break; 394 } 395 LIR *l = NewLIR3(opcode, r_dest.GetReg(), rs_rX86_SP.GetReg(), displacement); 396 AnnotateDalvikRegAccess(l, displacement >> 2, true /* is_load */, false /* is_64bit */); 397 return l; 398} 399 400LIR* X86Mir2Lir::OpRegRegReg(OpKind op, RegStorage r_dest, RegStorage r_src1, 401 RegStorage r_src2) { 402 if (r_dest != r_src1 && r_dest != r_src2) { 403 if (op == kOpAdd) { // lea special case, except can't encode rbp as base 404 if (r_src1 == r_src2) { 405 OpRegCopy(r_dest, r_src1); 406 return OpRegImm(kOpLsl, r_dest, 1); 407 } else if (r_src1 != rs_rBP) { 408 return NewLIR5(kX86Lea32RA, r_dest.GetReg(), r_src1.GetReg() /* base */, 409 r_src2.GetReg() /* index */, 0 /* scale */, 0 /* disp */); 410 } else { 411 return NewLIR5(kX86Lea32RA, r_dest.GetReg(), r_src2.GetReg() /* base */, 412 r_src1.GetReg() /* index */, 0 /* scale */, 0 /* disp */); 413 } 414 } else { 415 OpRegCopy(r_dest, r_src1); 416 return OpRegReg(op, r_dest, r_src2); 417 } 418 } else if (r_dest == r_src1) { 419 return OpRegReg(op, r_dest, r_src2); 420 } else { // r_dest == r_src2 421 switch (op) { 422 case kOpSub: // non-commutative 423 OpReg(kOpNeg, r_dest); 424 op = kOpAdd; 425 break; 426 case kOpSbc: 427 case kOpLsl: case kOpLsr: case kOpAsr: case kOpRor: { 428 RegStorage t_reg = AllocTemp(); 429 OpRegCopy(t_reg, r_src1); 430 OpRegReg(op, t_reg, r_src2); 431 LIR* res = OpRegCopyNoInsert(r_dest, t_reg); 432 AppendLIR(res); 433 FreeTemp(t_reg); 434 return res; 435 } 436 case kOpAdd: // commutative 437 case kOpOr: 438 case kOpAdc: 439 case kOpAnd: 440 case kOpXor: 441 break; 442 default: 443 LOG(FATAL) << "Bad case in OpRegRegReg " << op; 444 } 445 return OpRegReg(op, r_dest, r_src1); 446 } 447} 448 449LIR* X86Mir2Lir::OpRegRegImm(OpKind op, RegStorage r_dest, RegStorage r_src, int value) { 450 if (op == kOpMul) { 451 X86OpCode opcode = IS_SIMM8(value) ? kX86Imul32RRI8 : kX86Imul32RRI; 452 return NewLIR3(opcode, r_dest.GetReg(), r_src.GetReg(), value); 453 } else if (op == kOpAnd) { 454 if (value == 0xFF && r_src.Low4()) { 455 return NewLIR2(kX86Movzx8RR, r_dest.GetReg(), r_src.GetReg()); 456 } else if (value == 0xFFFF) { 457 return NewLIR2(kX86Movzx16RR, r_dest.GetReg(), r_src.GetReg()); 458 } 459 } 460 if (r_dest != r_src) { 461 if (false && op == kOpLsl && value >= 0 && value <= 3) { // lea shift special case 462 // TODO: fix bug in LEA encoding when disp == 0 463 return NewLIR5(kX86Lea32RA, r_dest.GetReg(), r5sib_no_base /* base */, 464 r_src.GetReg() /* index */, value /* scale */, 0 /* disp */); 465 } else if (op == kOpAdd) { // lea add special case 466 return NewLIR5(kX86Lea32RA, r_dest.GetReg(), r_src.GetReg() /* base */, 467 r4sib_no_index /* index */, 0 /* scale */, value /* disp */); 468 } 469 OpRegCopy(r_dest, r_src); 470 } 471 return OpRegImm(op, r_dest, value); 472} 473 474LIR* X86Mir2Lir::OpThreadMem(OpKind op, ThreadOffset<4> thread_offset) { 475 DCHECK_EQ(kX86, cu_->instruction_set); 476 X86OpCode opcode = kX86Bkpt; 477 switch (op) { 478 case kOpBlx: opcode = kX86CallT; break; 479 case kOpBx: opcode = kX86JmpT; break; 480 default: 481 LOG(FATAL) << "Bad opcode: " << op; 482 break; 483 } 484 return NewLIR1(opcode, thread_offset.Int32Value()); 485} 486 487LIR* X86Mir2Lir::OpThreadMem(OpKind op, ThreadOffset<8> thread_offset) { 488 DCHECK_EQ(kX86_64, cu_->instruction_set); 489 X86OpCode opcode = kX86Bkpt; 490 switch (op) { 491 case kOpBlx: opcode = kX86CallT; break; 492 case kOpBx: opcode = kX86JmpT; break; 493 default: 494 LOG(FATAL) << "Bad opcode: " << op; 495 break; 496 } 497 return NewLIR1(opcode, thread_offset.Int32Value()); 498} 499 500LIR* X86Mir2Lir::OpMem(OpKind op, RegStorage r_base, int disp) { 501 X86OpCode opcode = kX86Bkpt; 502 switch (op) { 503 case kOpBlx: opcode = kX86CallM; break; 504 default: 505 LOG(FATAL) << "Bad opcode: " << op; 506 break; 507 } 508 return NewLIR2(opcode, r_base.GetReg(), disp); 509} 510 511LIR* X86Mir2Lir::LoadConstantWide(RegStorage r_dest, int64_t value) { 512 int32_t val_lo = Low32Bits(value); 513 int32_t val_hi = High32Bits(value); 514 int32_t low_reg_val = r_dest.IsPair() ? r_dest.GetLowReg() : r_dest.GetReg(); 515 LIR *res; 516 bool is_fp = RegStorage::IsFloat(low_reg_val); 517 // TODO: clean this up once we fully recognize 64-bit storage containers. 518 if (is_fp) { 519 if (value == 0) { 520 return NewLIR2(kX86XorpsRR, low_reg_val, low_reg_val); 521 } else if (base_of_code_ != nullptr) { 522 // We will load the value from the literal area. 523 LIR* data_target = ScanLiteralPoolWide(literal_list_, val_lo, val_hi); 524 if (data_target == NULL) { 525 data_target = AddWideData(&literal_list_, val_lo, val_hi); 526 } 527 528 // Address the start of the method 529 RegLocation rl_method = mir_graph_->GetRegLocation(base_of_code_->s_reg_low); 530 rl_method = LoadValue(rl_method, kCoreReg); 531 532 // Load the proper value from the literal area. 533 // We don't know the proper offset for the value, so pick one that will force 534 // 4 byte offset. We will fix this up in the assembler later to have the right 535 // value. 536 res = LoadBaseDisp(rl_method.reg, 256 /* bogus */, RegStorage::Solo64(low_reg_val), 537 kDouble); 538 res->target = data_target; 539 res->flags.fixup = kFixupLoad; 540 SetMemRefType(res, true, kLiteral); 541 store_method_addr_used_ = true; 542 } else { 543 if (val_lo == 0) { 544 res = NewLIR2(kX86XorpsRR, low_reg_val, low_reg_val); 545 } else { 546 res = LoadConstantNoClobber(RegStorage::Solo32(low_reg_val), val_lo); 547 } 548 if (val_hi != 0) { 549 RegStorage r_dest_hi = AllocTempDouble(); 550 LoadConstantNoClobber(r_dest_hi, val_hi); 551 NewLIR2(kX86PunpckldqRR, low_reg_val, r_dest_hi.GetReg()); 552 FreeTemp(r_dest_hi); 553 } 554 } 555 } else { 556 res = LoadConstantNoClobber(r_dest.GetLow(), val_lo); 557 LoadConstantNoClobber(r_dest.GetHigh(), val_hi); 558 } 559 return res; 560} 561 562LIR* X86Mir2Lir::LoadBaseIndexedDisp(RegStorage r_base, RegStorage r_index, int scale, 563 int displacement, RegStorage r_dest, OpSize size) { 564 LIR *load = NULL; 565 LIR *load2 = NULL; 566 bool is_array = r_index.Valid(); 567 bool pair = r_dest.IsPair(); 568 bool is64bit = ((size == k64) || (size == kDouble)); 569 X86OpCode opcode = kX86Nop; 570 switch (size) { 571 case k64: 572 case kDouble: 573 if (r_dest.IsFloat()) { 574 opcode = is_array ? kX86MovsdRA : kX86MovsdRM; 575 } else { 576 opcode = is_array ? kX86Mov32RA : kX86Mov32RM; 577 } 578 // TODO: double store is to unaligned address 579 DCHECK_EQ((displacement & 0x3), 0); 580 break; 581 case k32: 582 case kSingle: 583 case kReference: // TODO: update for reference decompression on 64-bit targets. 584 opcode = is_array ? kX86Mov32RA : kX86Mov32RM; 585 if (r_dest.IsFloat()) { 586 opcode = is_array ? kX86MovssRA : kX86MovssRM; 587 DCHECK(r_dest.IsFloat()); 588 } 589 DCHECK_EQ((displacement & 0x3), 0); 590 break; 591 case kUnsignedHalf: 592 opcode = is_array ? kX86Movzx16RA : kX86Movzx16RM; 593 DCHECK_EQ((displacement & 0x1), 0); 594 break; 595 case kSignedHalf: 596 opcode = is_array ? kX86Movsx16RA : kX86Movsx16RM; 597 DCHECK_EQ((displacement & 0x1), 0); 598 break; 599 case kUnsignedByte: 600 opcode = is_array ? kX86Movzx8RA : kX86Movzx8RM; 601 break; 602 case kSignedByte: 603 opcode = is_array ? kX86Movsx8RA : kX86Movsx8RM; 604 break; 605 default: 606 LOG(FATAL) << "Bad case in LoadBaseIndexedDispBody"; 607 } 608 609 if (!is_array) { 610 if (!pair) { 611 load = NewLIR3(opcode, r_dest.GetReg(), r_base.GetReg(), displacement + LOWORD_OFFSET); 612 } else { 613 DCHECK(!r_dest.IsFloat()); // Make sure we're not still using a pair here. 614 if (r_base == r_dest.GetLow()) { 615 load2 = NewLIR3(opcode, r_dest.GetHighReg(), r_base.GetReg(), 616 displacement + HIWORD_OFFSET); 617 load = NewLIR3(opcode, r_dest.GetLowReg(), r_base.GetReg(), displacement + LOWORD_OFFSET); 618 } else { 619 load = NewLIR3(opcode, r_dest.GetLowReg(), r_base.GetReg(), displacement + LOWORD_OFFSET); 620 load2 = NewLIR3(opcode, r_dest.GetHighReg(), r_base.GetReg(), 621 displacement + HIWORD_OFFSET); 622 } 623 } 624 if (r_base == rs_rX86_SP) { 625 AnnotateDalvikRegAccess(load, (displacement + (pair ? LOWORD_OFFSET : 0)) >> 2, 626 true /* is_load */, is64bit); 627 if (pair) { 628 AnnotateDalvikRegAccess(load2, (displacement + HIWORD_OFFSET) >> 2, 629 true /* is_load */, is64bit); 630 } 631 } 632 } else { 633 if (!pair) { 634 load = NewLIR5(opcode, r_dest.GetReg(), r_base.GetReg(), r_index.GetReg(), scale, 635 displacement + LOWORD_OFFSET); 636 } else { 637 DCHECK(!r_dest.IsFloat()); // Make sure we're not still using a pair here. 638 if (r_base == r_dest.GetLow()) { 639 if (r_dest.GetHigh() == r_index) { 640 // We can't use either register for the first load. 641 RegStorage temp = AllocTemp(); 642 load2 = NewLIR5(opcode, temp.GetReg(), r_base.GetReg(), r_index.GetReg(), scale, 643 displacement + HIWORD_OFFSET); 644 load = NewLIR5(opcode, r_dest.GetLowReg(), r_base.GetReg(), r_index.GetReg(), scale, 645 displacement + LOWORD_OFFSET); 646 OpRegCopy(r_dest.GetHigh(), temp); 647 FreeTemp(temp); 648 } else { 649 load2 = NewLIR5(opcode, r_dest.GetHighReg(), r_base.GetReg(), r_index.GetReg(), scale, 650 displacement + HIWORD_OFFSET); 651 load = NewLIR5(opcode, r_dest.GetLowReg(), r_base.GetReg(), r_index.GetReg(), scale, 652 displacement + LOWORD_OFFSET); 653 } 654 } else { 655 if (r_dest.GetLow() == r_index) { 656 // We can't use either register for the first load. 657 RegStorage temp = AllocTemp(); 658 load = NewLIR5(opcode, temp.GetReg(), r_base.GetReg(), r_index.GetReg(), scale, 659 displacement + LOWORD_OFFSET); 660 load2 = NewLIR5(opcode, r_dest.GetHighReg(), r_base.GetReg(), r_index.GetReg(), scale, 661 displacement + HIWORD_OFFSET); 662 OpRegCopy(r_dest.GetLow(), temp); 663 FreeTemp(temp); 664 } else { 665 load = NewLIR5(opcode, r_dest.GetLowReg(), r_base.GetReg(), r_index.GetReg(), scale, 666 displacement + LOWORD_OFFSET); 667 load2 = NewLIR5(opcode, r_dest.GetHighReg(), r_base.GetReg(), r_index.GetReg(), scale, 668 displacement + HIWORD_OFFSET); 669 } 670 } 671 } 672 } 673 674 return load; 675} 676 677/* Load value from base + scaled index. */ 678LIR* X86Mir2Lir::LoadBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_dest, 679 int scale, OpSize size) { 680 return LoadBaseIndexedDisp(r_base, r_index, scale, 0, r_dest, size); 681} 682 683LIR* X86Mir2Lir::LoadBaseDispVolatile(RegStorage r_base, int displacement, RegStorage r_dest, 684 OpSize size) { 685 // LoadBaseDisp() will emit correct insn for atomic load on x86 686 // assuming r_dest is correctly prepared using RegClassForFieldLoadStore(). 687 return LoadBaseDisp(r_base, displacement, r_dest, size); 688} 689 690LIR* X86Mir2Lir::LoadBaseDisp(RegStorage r_base, int displacement, RegStorage r_dest, 691 OpSize size) { 692 // TODO: base this on target. 693 if (size == kWord) { 694 size = k32; 695 } 696 return LoadBaseIndexedDisp(r_base, RegStorage::InvalidReg(), 0, displacement, r_dest, 697 size); 698} 699 700LIR* X86Mir2Lir::StoreBaseIndexedDisp(RegStorage r_base, RegStorage r_index, int scale, 701 int displacement, RegStorage r_src, OpSize size) { 702 LIR *store = NULL; 703 LIR *store2 = NULL; 704 bool is_array = r_index.Valid(); 705 bool pair = r_src.IsPair(); 706 bool is64bit = (size == k64) || (size == kDouble); 707 X86OpCode opcode = kX86Nop; 708 switch (size) { 709 case k64: 710 case kDouble: 711 if (r_src.IsFloat()) { 712 opcode = is_array ? kX86MovsdAR : kX86MovsdMR; 713 } else { 714 opcode = is_array ? kX86Mov32AR : kX86Mov32MR; 715 } 716 // TODO: double store is to unaligned address 717 DCHECK_EQ((displacement & 0x3), 0); 718 break; 719 case k32: 720 case kSingle: 721 case kReference: 722 opcode = is_array ? kX86Mov32AR : kX86Mov32MR; 723 if (r_src.IsFloat()) { 724 opcode = is_array ? kX86MovssAR : kX86MovssMR; 725 DCHECK(r_src.IsSingle()); 726 } 727 DCHECK_EQ((displacement & 0x3), 0); 728 break; 729 case kUnsignedHalf: 730 case kSignedHalf: 731 opcode = is_array ? kX86Mov16AR : kX86Mov16MR; 732 DCHECK_EQ((displacement & 0x1), 0); 733 break; 734 case kUnsignedByte: 735 case kSignedByte: 736 opcode = is_array ? kX86Mov8AR : kX86Mov8MR; 737 break; 738 default: 739 LOG(FATAL) << "Bad case in StoreBaseIndexedDispBody"; 740 } 741 742 if (!is_array) { 743 if (!pair) { 744 store = NewLIR3(opcode, r_base.GetReg(), displacement + LOWORD_OFFSET, r_src.GetReg()); 745 } else { 746 DCHECK(!r_src.IsFloat()); // Make sure we're not still using a pair here. 747 store = NewLIR3(opcode, r_base.GetReg(), displacement + LOWORD_OFFSET, r_src.GetLowReg()); 748 store2 = NewLIR3(opcode, r_base.GetReg(), displacement + HIWORD_OFFSET, r_src.GetHighReg()); 749 } 750 if (r_base == rs_rX86_SP) { 751 AnnotateDalvikRegAccess(store, (displacement + (pair ? LOWORD_OFFSET : 0)) >> 2, 752 false /* is_load */, is64bit); 753 if (pair) { 754 AnnotateDalvikRegAccess(store2, (displacement + HIWORD_OFFSET) >> 2, 755 false /* is_load */, is64bit); 756 } 757 } 758 } else { 759 if (!pair) { 760 store = NewLIR5(opcode, r_base.GetReg(), r_index.GetReg(), scale, 761 displacement + LOWORD_OFFSET, r_src.GetReg()); 762 } else { 763 DCHECK(!r_src.IsFloat()); // Make sure we're not still using a pair here. 764 store = NewLIR5(opcode, r_base.GetReg(), r_index.GetReg(), scale, 765 displacement + LOWORD_OFFSET, r_src.GetLowReg()); 766 store2 = NewLIR5(opcode, r_base.GetReg(), r_index.GetReg(), scale, 767 displacement + HIWORD_OFFSET, r_src.GetHighReg()); 768 } 769 } 770 return store; 771} 772 773/* store value base base + scaled index. */ 774LIR* X86Mir2Lir::StoreBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_src, 775 int scale, OpSize size) { 776 return StoreBaseIndexedDisp(r_base, r_index, scale, 0, r_src, size); 777} 778 779LIR* X86Mir2Lir::StoreBaseDispVolatile(RegStorage r_base, int displacement, 780 RegStorage r_src, OpSize size) { 781 // StoreBaseDisp() will emit correct insn for atomic store on x86 782 // assuming r_dest is correctly prepared using RegClassForFieldLoadStore(). 783 return StoreBaseDisp(r_base, displacement, r_src, size); 784} 785 786LIR* X86Mir2Lir::StoreBaseDisp(RegStorage r_base, int displacement, 787 RegStorage r_src, OpSize size) { 788 // TODO: base this on target. 789 if (size == kWord) { 790 size = k32; 791 } 792 return StoreBaseIndexedDisp(r_base, RegStorage::InvalidReg(), 0, displacement, r_src, size); 793} 794 795LIR* X86Mir2Lir::OpCmpMemImmBranch(ConditionCode cond, RegStorage temp_reg, RegStorage base_reg, 796 int offset, int check_value, LIR* target) { 797 NewLIR3(IS_SIMM8(check_value) ? kX86Cmp32MI8 : kX86Cmp32MI, base_reg.GetReg(), offset, 798 check_value); 799 LIR* branch = OpCondBranch(cond, target); 800 return branch; 801} 802 803void X86Mir2Lir::AnalyzeMIR() { 804 // Assume we don't need a pointer to the base of the code. 805 cu_->NewTimingSplit("X86 MIR Analysis"); 806 store_method_addr_ = false; 807 808 // Walk the MIR looking for interesting items. 809 PreOrderDfsIterator iter(mir_graph_); 810 BasicBlock* curr_bb = iter.Next(); 811 while (curr_bb != NULL) { 812 AnalyzeBB(curr_bb); 813 curr_bb = iter.Next(); 814 } 815 816 // Did we need a pointer to the method code? 817 if (store_method_addr_) { 818 base_of_code_ = mir_graph_->GetNewCompilerTemp(kCompilerTempVR, false); 819 } else { 820 base_of_code_ = nullptr; 821 } 822} 823 824void X86Mir2Lir::AnalyzeBB(BasicBlock * bb) { 825 if (bb->block_type == kDead) { 826 // Ignore dead blocks 827 return; 828 } 829 830 for (MIR *mir = bb->first_mir_insn; mir != NULL; mir = mir->next) { 831 int opcode = mir->dalvikInsn.opcode; 832 if (opcode >= kMirOpFirst) { 833 AnalyzeExtendedMIR(opcode, bb, mir); 834 } else { 835 AnalyzeMIR(opcode, bb, mir); 836 } 837 } 838} 839 840 841void X86Mir2Lir::AnalyzeExtendedMIR(int opcode, BasicBlock * bb, MIR *mir) { 842 switch (opcode) { 843 // Instructions referencing doubles. 844 case kMirOpFusedCmplDouble: 845 case kMirOpFusedCmpgDouble: 846 AnalyzeFPInstruction(opcode, bb, mir); 847 break; 848 default: 849 // Ignore the rest. 850 break; 851 } 852} 853 854void X86Mir2Lir::AnalyzeMIR(int opcode, BasicBlock * bb, MIR *mir) { 855 // Looking for 856 // - Do we need a pointer to the code (used for packed switches and double lits)? 857 858 switch (opcode) { 859 // Instructions referencing doubles. 860 case Instruction::CMPL_DOUBLE: 861 case Instruction::CMPG_DOUBLE: 862 case Instruction::NEG_DOUBLE: 863 case Instruction::ADD_DOUBLE: 864 case Instruction::SUB_DOUBLE: 865 case Instruction::MUL_DOUBLE: 866 case Instruction::DIV_DOUBLE: 867 case Instruction::REM_DOUBLE: 868 case Instruction::ADD_DOUBLE_2ADDR: 869 case Instruction::SUB_DOUBLE_2ADDR: 870 case Instruction::MUL_DOUBLE_2ADDR: 871 case Instruction::DIV_DOUBLE_2ADDR: 872 case Instruction::REM_DOUBLE_2ADDR: 873 AnalyzeFPInstruction(opcode, bb, mir); 874 break; 875 876 // Packed switches and array fills need a pointer to the base of the method. 877 case Instruction::FILL_ARRAY_DATA: 878 case Instruction::PACKED_SWITCH: 879 store_method_addr_ = true; 880 break; 881 default: 882 // Other instructions are not interesting yet. 883 break; 884 } 885} 886 887void X86Mir2Lir::AnalyzeFPInstruction(int opcode, BasicBlock * bb, MIR *mir) { 888 // Look at all the uses, and see if they are double constants. 889 uint64_t attrs = MIRGraph::GetDataFlowAttributes(static_cast<Instruction::Code>(opcode)); 890 int next_sreg = 0; 891 if (attrs & DF_UA) { 892 if (attrs & DF_A_WIDE) { 893 AnalyzeDoubleUse(mir_graph_->GetSrcWide(mir, next_sreg)); 894 next_sreg += 2; 895 } else { 896 next_sreg++; 897 } 898 } 899 if (attrs & DF_UB) { 900 if (attrs & DF_B_WIDE) { 901 AnalyzeDoubleUse(mir_graph_->GetSrcWide(mir, next_sreg)); 902 next_sreg += 2; 903 } else { 904 next_sreg++; 905 } 906 } 907 if (attrs & DF_UC) { 908 if (attrs & DF_C_WIDE) { 909 AnalyzeDoubleUse(mir_graph_->GetSrcWide(mir, next_sreg)); 910 } 911 } 912} 913 914void X86Mir2Lir::AnalyzeDoubleUse(RegLocation use) { 915 // If this is a double literal, we will want it in the literal pool. 916 if (use.is_const) { 917 store_method_addr_ = true; 918 } 919} 920 921RegLocation X86Mir2Lir::UpdateLocTyped(RegLocation loc, int reg_class) { 922 loc = UpdateLoc(loc); 923 if ((loc.location == kLocPhysReg) && (loc.fp != loc.reg.IsFloat())) { 924 if (GetRegInfo(loc.reg)->IsTemp()) { 925 Clobber(loc.reg); 926 FreeTemp(loc.reg); 927 loc.reg = RegStorage::InvalidReg(); 928 loc.location = kLocDalvikFrame; 929 } 930 } 931 return loc; 932} 933 934RegLocation X86Mir2Lir::UpdateLocWideTyped(RegLocation loc, int reg_class) { 935 loc = UpdateLocWide(loc); 936 if ((loc.location == kLocPhysReg) && (loc.fp != loc.reg.IsFloat())) { 937 if (GetRegInfo(loc.reg)->IsTemp()) { 938 Clobber(loc.reg); 939 FreeTemp(loc.reg); 940 loc.reg = RegStorage::InvalidReg(); 941 loc.location = kLocDalvikFrame; 942 } 943 } 944 return loc; 945} 946 947} // namespace art 948