1 /* 2 * Copyright (C) 2011 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 #ifndef ART_COMPILER_UTILS_ARM_ASSEMBLER_ARM_H_ 18 #define ART_COMPILER_UTILS_ARM_ASSEMBLER_ARM_H_ 19 20 #include <vector> 21 22 #include "base/bit_utils.h" 23 #include "base/logging.h" 24 #include "base/value_object.h" 25 #include "constants_arm.h" 26 #include "utils/arm/managed_register_arm.h" 27 #include "utils/assembler.h" 28 #include "offsets.h" 29 30 namespace art { 31 namespace arm { 32 33 class Arm32Assembler; 34 class Thumb2Assembler; 35 36 class ShifterOperand { 37 public: 38 ShifterOperand() : type_(kUnknown), rm_(kNoRegister), rs_(kNoRegister), 39 is_rotate_(false), is_shift_(false), shift_(kNoShift), rotate_(0), immed_(0) { 40 } 41 42 explicit ShifterOperand(uint32_t immed); 43 44 // Data-processing operands - Register 45 explicit ShifterOperand(Register rm) : type_(kRegister), rm_(rm), rs_(kNoRegister), 46 is_rotate_(false), is_shift_(false), shift_(kNoShift), rotate_(0), immed_(0) { 47 } 48 49 ShifterOperand(uint32_t rotate, uint32_t immed8) : type_(kImmediate), rm_(kNoRegister), 50 rs_(kNoRegister), 51 is_rotate_(true), is_shift_(false), shift_(kNoShift), rotate_(rotate), immed_(immed8) { 52 } 53 54 ShifterOperand(Register rm, Shift shift, uint32_t shift_imm = 0) : type_(kRegister), rm_(rm), 55 rs_(kNoRegister), 56 is_rotate_(false), is_shift_(true), shift_(shift), rotate_(0), immed_(shift_imm) { 57 } 58 59 // Data-processing operands - Logical shift/rotate by register 60 ShifterOperand(Register rm, Shift shift, Register rs) : type_(kRegister), rm_(rm), 61 rs_(rs), 62 is_rotate_(false), is_shift_(true), shift_(shift), rotate_(0), immed_(0) { 63 } 64 65 bool is_valid() const { return (type_ == kImmediate) || (type_ == kRegister); } 66 67 uint32_t type() const { 68 CHECK(is_valid()); 69 return type_; 70 } 71 72 uint32_t encodingArm() const; 73 uint32_t encodingThumb() const; 74 75 bool IsEmpty() const { 76 return type_ == kUnknown; 77 } 78 79 bool IsImmediate() const { 80 return type_ == kImmediate; 81 } 82 83 bool IsRegister() const { 84 return type_ == kRegister; 85 } 86 87 bool IsShift() const { 88 return is_shift_; 89 } 90 91 uint32_t GetImmediate() const { 92 return immed_; 93 } 94 95 Shift GetShift() const { 96 return shift_; 97 } 98 99 Register GetRegister() const { 100 return rm_; 101 } 102 103 Register GetSecondRegister() const { 104 return rs_; 105 } 106 107 enum Type { 108 kUnknown = -1, 109 kRegister, 110 kImmediate 111 }; 112 113 private: 114 Type type_; 115 Register rm_; 116 Register rs_; 117 bool is_rotate_; 118 bool is_shift_; 119 Shift shift_; 120 uint32_t rotate_; 121 uint32_t immed_; 122 123 friend class Arm32Assembler; 124 friend class Thumb2Assembler; 125 126 #ifdef SOURCE_ASSEMBLER_SUPPORT 127 friend class BinaryAssembler; 128 #endif 129 }; 130 131 132 enum LoadOperandType { 133 kLoadSignedByte, 134 kLoadUnsignedByte, 135 kLoadSignedHalfword, 136 kLoadUnsignedHalfword, 137 kLoadWord, 138 kLoadWordPair, 139 kLoadSWord, 140 kLoadDWord 141 }; 142 143 144 enum StoreOperandType { 145 kStoreByte, 146 kStoreHalfword, 147 kStoreWord, 148 kStoreWordPair, 149 kStoreSWord, 150 kStoreDWord 151 }; 152 153 154 // Load/store multiple addressing mode. 155 enum BlockAddressMode { 156 // bit encoding P U W 157 DA = (0|0|0) << 21, // decrement after 158 IA = (0|4|0) << 21, // increment after 159 DB = (8|0|0) << 21, // decrement before 160 IB = (8|4|0) << 21, // increment before 161 DA_W = (0|0|1) << 21, // decrement after with writeback to base 162 IA_W = (0|4|1) << 21, // increment after with writeback to base 163 DB_W = (8|0|1) << 21, // decrement before with writeback to base 164 IB_W = (8|4|1) << 21 // increment before with writeback to base 165 }; 166 inline std::ostream& operator<<(std::ostream& os, const BlockAddressMode& rhs) { 167 os << static_cast<int>(rhs); 168 return os; 169 } 170 171 class Address : public ValueObject { 172 public: 173 // Memory operand addressing mode (in ARM encoding form. For others we need 174 // to adjust) 175 enum Mode { 176 // bit encoding P U W 177 Offset = (8|4|0) << 21, // offset (w/o writeback to base) 178 PreIndex = (8|4|1) << 21, // pre-indexed addressing with writeback 179 PostIndex = (0|4|0) << 21, // post-indexed addressing with writeback 180 NegOffset = (8|0|0) << 21, // negative offset (w/o writeback to base) 181 NegPreIndex = (8|0|1) << 21, // negative pre-indexed with writeback 182 NegPostIndex = (0|0|0) << 21 // negative post-indexed with writeback 183 }; 184 185 Address(Register rn, int32_t offset = 0, Mode am = Offset) : rn_(rn), rm_(R0), 186 offset_(offset), 187 am_(am), is_immed_offset_(true), shift_(LSL) { 188 } 189 190 Address(Register rn, Register rm, Mode am = Offset) : rn_(rn), rm_(rm), offset_(0), 191 am_(am), is_immed_offset_(false), shift_(LSL) { 192 CHECK_NE(rm, PC); 193 } 194 195 Address(Register rn, Register rm, Shift shift, uint32_t count, Mode am = Offset) : 196 rn_(rn), rm_(rm), offset_(count), 197 am_(am), is_immed_offset_(false), shift_(shift) { 198 CHECK_NE(rm, PC); 199 } 200 201 // LDR(literal) - pc relative load. 202 explicit Address(int32_t offset) : 203 rn_(PC), rm_(R0), offset_(offset), 204 am_(Offset), is_immed_offset_(false), shift_(LSL) { 205 } 206 207 static bool CanHoldLoadOffsetArm(LoadOperandType type, int offset); 208 static bool CanHoldStoreOffsetArm(StoreOperandType type, int offset); 209 210 static bool CanHoldLoadOffsetThumb(LoadOperandType type, int offset); 211 static bool CanHoldStoreOffsetThumb(StoreOperandType type, int offset); 212 213 uint32_t encodingArm() const; 214 uint32_t encodingThumb(bool is_32bit) const; 215 216 uint32_t encoding3() const; 217 uint32_t vencoding() const; 218 219 uint32_t encodingThumbLdrdStrd() const; 220 221 Register GetRegister() const { 222 return rn_; 223 } 224 225 Register GetRegisterOffset() const { 226 return rm_; 227 } 228 229 int32_t GetOffset() const { 230 return offset_; 231 } 232 233 Mode GetMode() const { 234 return am_; 235 } 236 237 bool IsImmediate() const { 238 return is_immed_offset_; 239 } 240 241 Shift GetShift() const { 242 return shift_; 243 } 244 245 int32_t GetShiftCount() const { 246 CHECK(!is_immed_offset_); 247 return offset_; 248 } 249 250 private: 251 const Register rn_; 252 const Register rm_; 253 const int32_t offset_; // Used as shift amount for register offset. 254 const Mode am_; 255 const bool is_immed_offset_; 256 const Shift shift_; 257 }; 258 inline std::ostream& operator<<(std::ostream& os, const Address::Mode& rhs) { 259 os << static_cast<int>(rhs); 260 return os; 261 } 262 263 // Instruction encoding bits. 264 enum { 265 H = 1 << 5, // halfword (or byte) 266 L = 1 << 20, // load (or store) 267 S = 1 << 20, // set condition code (or leave unchanged) 268 W = 1 << 21, // writeback base register (or leave unchanged) 269 A = 1 << 21, // accumulate in multiply instruction (or not) 270 B = 1 << 22, // unsigned byte (or word) 271 N = 1 << 22, // long (or short) 272 U = 1 << 23, // positive (or negative) offset/index 273 P = 1 << 24, // offset/pre-indexed addressing (or post-indexed addressing) 274 I = 1 << 25, // immediate shifter operand (or not) 275 276 B0 = 1, 277 B1 = 1 << 1, 278 B2 = 1 << 2, 279 B3 = 1 << 3, 280 B4 = 1 << 4, 281 B5 = 1 << 5, 282 B6 = 1 << 6, 283 B7 = 1 << 7, 284 B8 = 1 << 8, 285 B9 = 1 << 9, 286 B10 = 1 << 10, 287 B11 = 1 << 11, 288 B12 = 1 << 12, 289 B13 = 1 << 13, 290 B14 = 1 << 14, 291 B15 = 1 << 15, 292 B16 = 1 << 16, 293 B17 = 1 << 17, 294 B18 = 1 << 18, 295 B19 = 1 << 19, 296 B20 = 1 << 20, 297 B21 = 1 << 21, 298 B22 = 1 << 22, 299 B23 = 1 << 23, 300 B24 = 1 << 24, 301 B25 = 1 << 25, 302 B26 = 1 << 26, 303 B27 = 1 << 27, 304 B28 = 1 << 28, 305 B29 = 1 << 29, 306 B30 = 1 << 30, 307 B31 = 1 << 31, 308 309 // Instruction bit masks. 310 RdMask = 15 << 12, // in str instruction 311 CondMask = 15 << 28, 312 CoprocessorMask = 15 << 8, 313 OpCodeMask = 15 << 21, // in data-processing instructions 314 Imm24Mask = (1 << 24) - 1, 315 Off12Mask = (1 << 12) - 1, 316 317 // ldrex/strex register field encodings. 318 kLdExRnShift = 16, 319 kLdExRtShift = 12, 320 kStrExRnShift = 16, 321 kStrExRdShift = 12, 322 kStrExRtShift = 0, 323 }; 324 325 // IfThen state for IT instructions. 326 enum ItState { 327 kItOmitted, 328 kItThen, 329 kItT = kItThen, 330 kItElse, 331 kItE = kItElse 332 }; 333 334 constexpr uint32_t kNoItCondition = 3; 335 constexpr uint32_t kInvalidModifiedImmediate = -1; 336 337 extern const char* kRegisterNames[]; 338 extern const char* kConditionNames[]; 339 340 // This is an abstract ARM assembler. Subclasses provide assemblers for the individual 341 // instruction sets (ARM32, Thumb2, etc.) 342 // 343 class ArmAssembler : public Assembler { 344 public: 345 virtual ~ArmAssembler() {} 346 347 // Is this assembler for the thumb instruction set? 348 virtual bool IsThumb() const = 0; 349 350 // Data-processing instructions. 351 virtual void and_(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) = 0; 352 353 virtual void eor(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) = 0; 354 355 virtual void sub(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) = 0; 356 virtual void subs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) = 0; 357 358 virtual void rsb(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) = 0; 359 virtual void rsbs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) = 0; 360 361 virtual void add(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) = 0; 362 363 virtual void adds(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) = 0; 364 365 virtual void adc(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) = 0; 366 367 virtual void sbc(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) = 0; 368 369 virtual void rsc(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) = 0; 370 371 virtual void tst(Register rn, const ShifterOperand& so, Condition cond = AL) = 0; 372 373 virtual void teq(Register rn, const ShifterOperand& so, Condition cond = AL) = 0; 374 375 virtual void cmp(Register rn, const ShifterOperand& so, Condition cond = AL) = 0; 376 377 virtual void cmn(Register rn, const ShifterOperand& so, Condition cond = AL) = 0; 378 379 virtual void orr(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) = 0; 380 virtual void orrs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) = 0; 381 382 virtual void mov(Register rd, const ShifterOperand& so, Condition cond = AL) = 0; 383 virtual void movs(Register rd, const ShifterOperand& so, Condition cond = AL) = 0; 384 385 virtual void bic(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) = 0; 386 387 virtual void mvn(Register rd, const ShifterOperand& so, Condition cond = AL) = 0; 388 virtual void mvns(Register rd, const ShifterOperand& so, Condition cond = AL) = 0; 389 390 // Miscellaneous data-processing instructions. 391 virtual void clz(Register rd, Register rm, Condition cond = AL) = 0; 392 virtual void movw(Register rd, uint16_t imm16, Condition cond = AL) = 0; 393 virtual void movt(Register rd, uint16_t imm16, Condition cond = AL) = 0; 394 395 // Multiply instructions. 396 virtual void mul(Register rd, Register rn, Register rm, Condition cond = AL) = 0; 397 virtual void mla(Register rd, Register rn, Register rm, Register ra, 398 Condition cond = AL) = 0; 399 virtual void mls(Register rd, Register rn, Register rm, Register ra, 400 Condition cond = AL) = 0; 401 virtual void umull(Register rd_lo, Register rd_hi, Register rn, Register rm, 402 Condition cond = AL) = 0; 403 404 virtual void sdiv(Register rd, Register rn, Register rm, Condition cond = AL) = 0; 405 virtual void udiv(Register rd, Register rn, Register rm, Condition cond = AL) = 0; 406 407 // Bit field extract instructions. 408 virtual void sbfx(Register rd, Register rn, uint32_t lsb, uint32_t width, 409 Condition cond = AL) = 0; 410 virtual void ubfx(Register rd, Register rn, uint32_t lsb, uint32_t width, 411 Condition cond = AL) = 0; 412 413 // Load/store instructions. 414 virtual void ldr(Register rd, const Address& ad, Condition cond = AL) = 0; 415 virtual void str(Register rd, const Address& ad, Condition cond = AL) = 0; 416 417 virtual void ldrb(Register rd, const Address& ad, Condition cond = AL) = 0; 418 virtual void strb(Register rd, const Address& ad, Condition cond = AL) = 0; 419 420 virtual void ldrh(Register rd, const Address& ad, Condition cond = AL) = 0; 421 virtual void strh(Register rd, const Address& ad, Condition cond = AL) = 0; 422 423 virtual void ldrsb(Register rd, const Address& ad, Condition cond = AL) = 0; 424 virtual void ldrsh(Register rd, const Address& ad, Condition cond = AL) = 0; 425 426 virtual void ldrd(Register rd, const Address& ad, Condition cond = AL) = 0; 427 virtual void strd(Register rd, const Address& ad, Condition cond = AL) = 0; 428 429 virtual void ldm(BlockAddressMode am, Register base, 430 RegList regs, Condition cond = AL) = 0; 431 virtual void stm(BlockAddressMode am, Register base, 432 RegList regs, Condition cond = AL) = 0; 433 434 virtual void ldrex(Register rd, Register rn, Condition cond = AL) = 0; 435 virtual void strex(Register rd, Register rt, Register rn, Condition cond = AL) = 0; 436 virtual void ldrexd(Register rt, Register rt2, Register rn, Condition cond = AL) = 0; 437 virtual void strexd(Register rd, Register rt, Register rt2, Register rn, Condition cond = AL) = 0; 438 439 // Miscellaneous instructions. 440 virtual void clrex(Condition cond = AL) = 0; 441 virtual void nop(Condition cond = AL) = 0; 442 443 // Note that gdb sets breakpoints using the undefined instruction 0xe7f001f0. 444 virtual void bkpt(uint16_t imm16) = 0; 445 virtual void svc(uint32_t imm24) = 0; 446 447 virtual void it(Condition firstcond ATTRIBUTE_UNUSED, 448 ItState i1 ATTRIBUTE_UNUSED = kItOmitted, 449 ItState i2 ATTRIBUTE_UNUSED = kItOmitted, 450 ItState i3 ATTRIBUTE_UNUSED = kItOmitted) { 451 // Ignored if not supported. 452 } 453 454 virtual void cbz(Register rn, Label* target) = 0; 455 virtual void cbnz(Register rn, Label* target) = 0; 456 457 // Floating point instructions (VFPv3-D16 and VFPv3-D32 profiles). 458 virtual void vmovsr(SRegister sn, Register rt, Condition cond = AL) = 0; 459 virtual void vmovrs(Register rt, SRegister sn, Condition cond = AL) = 0; 460 virtual void vmovsrr(SRegister sm, Register rt, Register rt2, Condition cond = AL) = 0; 461 virtual void vmovrrs(Register rt, Register rt2, SRegister sm, Condition cond = AL) = 0; 462 virtual void vmovdrr(DRegister dm, Register rt, Register rt2, Condition cond = AL) = 0; 463 virtual void vmovrrd(Register rt, Register rt2, DRegister dm, Condition cond = AL) = 0; 464 virtual void vmovs(SRegister sd, SRegister sm, Condition cond = AL) = 0; 465 virtual void vmovd(DRegister dd, DRegister dm, Condition cond = AL) = 0; 466 467 // Returns false if the immediate cannot be encoded. 468 virtual bool vmovs(SRegister sd, float s_imm, Condition cond = AL) = 0; 469 virtual bool vmovd(DRegister dd, double d_imm, Condition cond = AL) = 0; 470 471 virtual void vldrs(SRegister sd, const Address& ad, Condition cond = AL) = 0; 472 virtual void vstrs(SRegister sd, const Address& ad, Condition cond = AL) = 0; 473 virtual void vldrd(DRegister dd, const Address& ad, Condition cond = AL) = 0; 474 virtual void vstrd(DRegister dd, const Address& ad, Condition cond = AL) = 0; 475 476 virtual void vadds(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) = 0; 477 virtual void vaddd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) = 0; 478 virtual void vsubs(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) = 0; 479 virtual void vsubd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) = 0; 480 virtual void vmuls(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) = 0; 481 virtual void vmuld(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) = 0; 482 virtual void vmlas(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) = 0; 483 virtual void vmlad(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) = 0; 484 virtual void vmlss(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) = 0; 485 virtual void vmlsd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) = 0; 486 virtual void vdivs(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL) = 0; 487 virtual void vdivd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL) = 0; 488 489 virtual void vabss(SRegister sd, SRegister sm, Condition cond = AL) = 0; 490 virtual void vabsd(DRegister dd, DRegister dm, Condition cond = AL) = 0; 491 virtual void vnegs(SRegister sd, SRegister sm, Condition cond = AL) = 0; 492 virtual void vnegd(DRegister dd, DRegister dm, Condition cond = AL) = 0; 493 virtual void vsqrts(SRegister sd, SRegister sm, Condition cond = AL) = 0; 494 virtual void vsqrtd(DRegister dd, DRegister dm, Condition cond = AL) = 0; 495 496 virtual void vcvtsd(SRegister sd, DRegister dm, Condition cond = AL) = 0; 497 virtual void vcvtds(DRegister dd, SRegister sm, Condition cond = AL) = 0; 498 virtual void vcvtis(SRegister sd, SRegister sm, Condition cond = AL) = 0; 499 virtual void vcvtid(SRegister sd, DRegister dm, Condition cond = AL) = 0; 500 virtual void vcvtsi(SRegister sd, SRegister sm, Condition cond = AL) = 0; 501 virtual void vcvtdi(DRegister dd, SRegister sm, Condition cond = AL) = 0; 502 virtual void vcvtus(SRegister sd, SRegister sm, Condition cond = AL) = 0; 503 virtual void vcvtud(SRegister sd, DRegister dm, Condition cond = AL) = 0; 504 virtual void vcvtsu(SRegister sd, SRegister sm, Condition cond = AL) = 0; 505 virtual void vcvtdu(DRegister dd, SRegister sm, Condition cond = AL) = 0; 506 507 virtual void vcmps(SRegister sd, SRegister sm, Condition cond = AL) = 0; 508 virtual void vcmpd(DRegister dd, DRegister dm, Condition cond = AL) = 0; 509 virtual void vcmpsz(SRegister sd, Condition cond = AL) = 0; 510 virtual void vcmpdz(DRegister dd, Condition cond = AL) = 0; 511 virtual void vmstat(Condition cond = AL) = 0; // VMRS APSR_nzcv, FPSCR 512 513 virtual void vpushs(SRegister reg, int nregs, Condition cond = AL) = 0; 514 virtual void vpushd(DRegister reg, int nregs, Condition cond = AL) = 0; 515 virtual void vpops(SRegister reg, int nregs, Condition cond = AL) = 0; 516 virtual void vpopd(DRegister reg, int nregs, Condition cond = AL) = 0; 517 518 // Branch instructions. 519 virtual void b(Label* label, Condition cond = AL) = 0; 520 virtual void bl(Label* label, Condition cond = AL) = 0; 521 virtual void blx(Register rm, Condition cond = AL) = 0; 522 virtual void bx(Register rm, Condition cond = AL) = 0; 523 524 // Memory barriers. 525 virtual void dmb(DmbOptions flavor) = 0; 526 527 void Pad(uint32_t bytes); 528 529 // Macros. 530 // Most of these are pure virtual as they need to be implemented per instruction set. 531 532 // Add signed constant value to rd. May clobber IP. 533 virtual void AddConstant(Register rd, int32_t value, Condition cond = AL) = 0; 534 virtual void AddConstant(Register rd, Register rn, int32_t value, 535 Condition cond = AL) = 0; 536 virtual void AddConstantSetFlags(Register rd, Register rn, int32_t value, 537 Condition cond = AL) = 0; 538 539 // Load and Store. May clobber IP. 540 virtual void LoadImmediate(Register rd, int32_t value, Condition cond = AL) = 0; 541 void LoadSImmediate(SRegister sd, float value, Condition cond = AL) { 542 if (!vmovs(sd, value, cond)) { 543 int32_t int_value = bit_cast<int32_t, float>(value); 544 if (int_value == bit_cast<int32_t, float>(0.0f)) { 545 // 0.0 is quite common, so we special case it by loading 546 // 2.0 in `sd` and then substracting it. 547 bool success = vmovs(sd, 2.0, cond); 548 CHECK(success); 549 vsubs(sd, sd, sd, cond); 550 } else { 551 LoadImmediate(IP, int_value, cond); 552 vmovsr(sd, IP, cond); 553 } 554 } 555 } 556 557 void LoadDImmediate(DRegister sd, double value, Condition cond = AL) { 558 if (!vmovd(sd, value, cond)) { 559 uint64_t int_value = bit_cast<uint64_t, double>(value); 560 if (int_value == bit_cast<uint64_t, double>(0.0)) { 561 // 0.0 is quite common, so we special case it by loading 562 // 2.0 in `sd` and then substracting it. 563 bool success = vmovd(sd, 2.0, cond); 564 CHECK(success); 565 vsubd(sd, sd, sd, cond); 566 } else { 567 if (sd < 16) { 568 SRegister low = static_cast<SRegister>(sd << 1); 569 SRegister high = static_cast<SRegister>(low + 1); 570 LoadSImmediate(low, bit_cast<float, uint32_t>(Low32Bits(int_value)), cond); 571 if (High32Bits(int_value) == Low32Bits(int_value)) { 572 vmovs(high, low); 573 } else { 574 LoadSImmediate(high, bit_cast<float, uint32_t>(High32Bits(int_value)), cond); 575 } 576 } else { 577 LOG(FATAL) << "Unimplemented loading of double into a D register " 578 << "that cannot be split into two S registers"; 579 } 580 } 581 } 582 } 583 584 virtual void MarkExceptionHandler(Label* label) = 0; 585 virtual void LoadFromOffset(LoadOperandType type, 586 Register reg, 587 Register base, 588 int32_t offset, 589 Condition cond = AL) = 0; 590 virtual void StoreToOffset(StoreOperandType type, 591 Register reg, 592 Register base, 593 int32_t offset, 594 Condition cond = AL) = 0; 595 virtual void LoadSFromOffset(SRegister reg, 596 Register base, 597 int32_t offset, 598 Condition cond = AL) = 0; 599 virtual void StoreSToOffset(SRegister reg, 600 Register base, 601 int32_t offset, 602 Condition cond = AL) = 0; 603 virtual void LoadDFromOffset(DRegister reg, 604 Register base, 605 int32_t offset, 606 Condition cond = AL) = 0; 607 virtual void StoreDToOffset(DRegister reg, 608 Register base, 609 int32_t offset, 610 Condition cond = AL) = 0; 611 612 virtual void Push(Register rd, Condition cond = AL) = 0; 613 virtual void Pop(Register rd, Condition cond = AL) = 0; 614 615 virtual void PushList(RegList regs, Condition cond = AL) = 0; 616 virtual void PopList(RegList regs, Condition cond = AL) = 0; 617 618 virtual void Mov(Register rd, Register rm, Condition cond = AL) = 0; 619 620 // Convenience shift instructions. Use mov instruction with shifter operand 621 // for variants setting the status flags or using a register shift count. 622 virtual void Lsl(Register rd, Register rm, uint32_t shift_imm, bool setcc = false, 623 Condition cond = AL) = 0; 624 virtual void Lsr(Register rd, Register rm, uint32_t shift_imm, bool setcc = false, 625 Condition cond = AL) = 0; 626 virtual void Asr(Register rd, Register rm, uint32_t shift_imm, bool setcc = false, 627 Condition cond = AL) = 0; 628 virtual void Ror(Register rd, Register rm, uint32_t shift_imm, bool setcc = false, 629 Condition cond = AL) = 0; 630 virtual void Rrx(Register rd, Register rm, bool setcc = false, 631 Condition cond = AL) = 0; 632 633 virtual void Lsl(Register rd, Register rm, Register rn, bool setcc = false, 634 Condition cond = AL) = 0; 635 virtual void Lsr(Register rd, Register rm, Register rn, bool setcc = false, 636 Condition cond = AL) = 0; 637 virtual void Asr(Register rd, Register rm, Register rn, bool setcc = false, 638 Condition cond = AL) = 0; 639 virtual void Ror(Register rd, Register rm, Register rn, bool setcc = false, 640 Condition cond = AL) = 0; 641 642 // Returns whether the `immediate` can fit in a `ShifterOperand`. If yes, 643 // `shifter_op` contains the operand. 644 virtual bool ShifterOperandCanHold(Register rd, 645 Register rn, 646 Opcode opcode, 647 uint32_t immediate, 648 ShifterOperand* shifter_op) = 0; 649 650 static bool IsInstructionForExceptionHandling(uintptr_t pc); 651 652 virtual void Bind(Label* label) = 0; 653 654 virtual void CompareAndBranchIfZero(Register r, Label* label) = 0; 655 virtual void CompareAndBranchIfNonZero(Register r, Label* label) = 0; 656 657 // 658 // Overridden common assembler high-level functionality 659 // 660 661 // Emit code that will create an activation on the stack 662 void BuildFrame(size_t frame_size, ManagedRegister method_reg, 663 const std::vector<ManagedRegister>& callee_save_regs, 664 const ManagedRegisterEntrySpills& entry_spills) OVERRIDE; 665 666 // Emit code that will remove an activation from the stack 667 void RemoveFrame(size_t frame_size, const std::vector<ManagedRegister>& callee_save_regs) 668 OVERRIDE; 669 670 void IncreaseFrameSize(size_t adjust) OVERRIDE; 671 void DecreaseFrameSize(size_t adjust) OVERRIDE; 672 673 // Store routines 674 void Store(FrameOffset offs, ManagedRegister src, size_t size) OVERRIDE; 675 void StoreRef(FrameOffset dest, ManagedRegister src) OVERRIDE; 676 void StoreRawPtr(FrameOffset dest, ManagedRegister src) OVERRIDE; 677 678 void StoreImmediateToFrame(FrameOffset dest, uint32_t imm, ManagedRegister scratch) OVERRIDE; 679 680 void StoreImmediateToThread32(ThreadOffset<4> dest, uint32_t imm, ManagedRegister scratch) 681 OVERRIDE; 682 683 void StoreStackOffsetToThread32(ThreadOffset<4> thr_offs, FrameOffset fr_offs, 684 ManagedRegister scratch) OVERRIDE; 685 686 void StoreStackPointerToThread32(ThreadOffset<4> thr_offs) OVERRIDE; 687 688 void StoreSpanning(FrameOffset dest, ManagedRegister src, FrameOffset in_off, 689 ManagedRegister scratch) OVERRIDE; 690 691 // Load routines 692 void Load(ManagedRegister dest, FrameOffset src, size_t size) OVERRIDE; 693 694 void LoadFromThread32(ManagedRegister dest, ThreadOffset<4> src, size_t size) OVERRIDE; 695 696 void LoadRef(ManagedRegister dest, FrameOffset src) OVERRIDE; 697 698 void LoadRef(ManagedRegister dest, ManagedRegister base, MemberOffset offs, 699 bool poison_reference) OVERRIDE; 700 701 void LoadRawPtr(ManagedRegister dest, ManagedRegister base, Offset offs) OVERRIDE; 702 703 void LoadRawPtrFromThread32(ManagedRegister dest, ThreadOffset<4> offs) OVERRIDE; 704 705 // Copying routines 706 void Move(ManagedRegister dest, ManagedRegister src, size_t size) OVERRIDE; 707 708 void CopyRawPtrFromThread32(FrameOffset fr_offs, ThreadOffset<4> thr_offs, 709 ManagedRegister scratch) OVERRIDE; 710 711 void CopyRawPtrToThread32(ThreadOffset<4> thr_offs, FrameOffset fr_offs, ManagedRegister scratch) 712 OVERRIDE; 713 714 void CopyRef(FrameOffset dest, FrameOffset src, ManagedRegister scratch) OVERRIDE; 715 716 void Copy(FrameOffset dest, FrameOffset src, ManagedRegister scratch, size_t size) OVERRIDE; 717 718 void Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset, ManagedRegister scratch, 719 size_t size) OVERRIDE; 720 721 void Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src, ManagedRegister scratch, 722 size_t size) OVERRIDE; 723 724 void Copy(FrameOffset dest, FrameOffset src_base, Offset src_offset, ManagedRegister scratch, 725 size_t size) OVERRIDE; 726 727 void Copy(ManagedRegister dest, Offset dest_offset, ManagedRegister src, Offset src_offset, 728 ManagedRegister scratch, size_t size) OVERRIDE; 729 730 void Copy(FrameOffset dest, Offset dest_offset, FrameOffset src, Offset src_offset, 731 ManagedRegister scratch, size_t size) OVERRIDE; 732 733 // Sign extension 734 void SignExtend(ManagedRegister mreg, size_t size) OVERRIDE; 735 736 // Zero extension 737 void ZeroExtend(ManagedRegister mreg, size_t size) OVERRIDE; 738 739 // Exploit fast access in managed code to Thread::Current() 740 void GetCurrentThread(ManagedRegister tr) OVERRIDE; 741 void GetCurrentThread(FrameOffset dest_offset, ManagedRegister scratch) OVERRIDE; 742 743 // Set up out_reg to hold a Object** into the handle scope, or to be null if the 744 // value is null and null_allowed. in_reg holds a possibly stale reference 745 // that can be used to avoid loading the handle scope entry to see if the value is 746 // null. 747 void CreateHandleScopeEntry(ManagedRegister out_reg, FrameOffset handlescope_offset, 748 ManagedRegister in_reg, bool null_allowed) OVERRIDE; 749 750 // Set up out_off to hold a Object** into the handle scope, or to be null if the 751 // value is null and null_allowed. 752 void CreateHandleScopeEntry(FrameOffset out_off, FrameOffset handlescope_offset, 753 ManagedRegister scratch, bool null_allowed) OVERRIDE; 754 755 // src holds a handle scope entry (Object**) load this into dst 756 void LoadReferenceFromHandleScope(ManagedRegister dst, ManagedRegister src) OVERRIDE; 757 758 // Heap::VerifyObject on src. In some cases (such as a reference to this) we 759 // know that src may not be null. 760 void VerifyObject(ManagedRegister src, bool could_be_null) OVERRIDE; 761 void VerifyObject(FrameOffset src, bool could_be_null) OVERRIDE; 762 763 // Call to address held at [base+offset] 764 void Call(ManagedRegister base, Offset offset, ManagedRegister scratch) OVERRIDE; 765 void Call(FrameOffset base, Offset offset, ManagedRegister scratch) OVERRIDE; 766 void CallFromThread32(ThreadOffset<4> offset, ManagedRegister scratch) OVERRIDE; 767 768 // Generate code to check if Thread::Current()->exception_ is non-null 769 // and branch to a ExceptionSlowPath if it is. 770 void ExceptionPoll(ManagedRegister scratch, size_t stack_adjust) OVERRIDE; 771 772 static uint32_t ModifiedImmediate(uint32_t value); 773 774 static bool IsLowRegister(Register r) { 775 return r < R8; 776 } 777 778 static bool IsHighRegister(Register r) { 779 return r >= R8; 780 } 781 782 protected: 783 // Returns whether or not the given register is used for passing parameters. 784 static int RegisterCompare(const Register* reg1, const Register* reg2) { 785 return *reg1 - *reg2; 786 } 787 }; 788 789 // Slowpath entered when Thread::Current()->_exception is non-null 790 class ArmExceptionSlowPath FINAL : public SlowPath { 791 public: 792 explicit ArmExceptionSlowPath(ArmManagedRegister scratch, size_t stack_adjust) 793 : scratch_(scratch), stack_adjust_(stack_adjust) { 794 } 795 void Emit(Assembler *sp_asm) OVERRIDE; 796 private: 797 const ArmManagedRegister scratch_; 798 const size_t stack_adjust_; 799 }; 800 801 } // namespace arm 802 } // namespace art 803 804 #endif // ART_COMPILER_UTILS_ARM_ASSEMBLER_ARM_H_ 805