diff options
Diffstat (limited to 'compiler/utils/arm')
| -rw-r--r-- | compiler/utils/arm/assembler_arm.cc | 30 | ||||
| -rw-r--r-- | compiler/utils/arm/assembler_arm.h | 41 | ||||
| -rw-r--r-- | compiler/utils/arm/assembler_arm32.cc | 51 | ||||
| -rw-r--r-- | compiler/utils/arm/assembler_arm32.h | 7 | ||||
| -rw-r--r-- | compiler/utils/arm/assembler_arm32_test.cc | 11 | ||||
| -rw-r--r-- | compiler/utils/arm/assembler_thumb2.cc | 110 | ||||
| -rw-r--r-- | compiler/utils/arm/assembler_thumb2.h | 6 | ||||
| -rw-r--r-- | compiler/utils/arm/assembler_thumb2_test.cc | 10 |
8 files changed, 167 insertions, 99 deletions
diff --git a/compiler/utils/arm/assembler_arm.cc b/compiler/utils/arm/assembler_arm.cc index 0f28591775..05287732c5 100644 --- a/compiler/utils/arm/assembler_arm.cc +++ b/compiler/utils/arm/assembler_arm.cc @@ -165,36 +165,6 @@ uint32_t ShifterOperand::encodingThumb() const { return 0; } -bool ShifterOperand::CanHoldThumb(Register rd, Register rn, Opcode opcode, - uint32_t immediate, ShifterOperand* shifter_op) { - shifter_op->type_ = kImmediate; - shifter_op->immed_ = immediate; - shifter_op->is_shift_ = false; - shifter_op->is_rotate_ = false; - switch (opcode) { - case ADD: - case SUB: - if (rn == SP) { - if (rd == SP) { - return immediate < (1 << 9); // 9 bits allowed. - } else { - return immediate < (1 << 12); // 12 bits. - } - } - if (immediate < (1 << 12)) { // Less than (or equal to) 12 bits can always be done. - return true; - } - return ArmAssembler::ModifiedImmediate(immediate) != kInvalidModifiedImmediate; - - case MOV: - // TODO: Support less than or equal to 12bits. - return ArmAssembler::ModifiedImmediate(immediate) != kInvalidModifiedImmediate; - case MVN: - default: - return ArmAssembler::ModifiedImmediate(immediate) != kInvalidModifiedImmediate; - } -} - uint32_t Address::encodingArm() const { CHECK(IsAbsoluteUint(12, offset_)); uint32_t encoding; diff --git a/compiler/utils/arm/assembler_arm.h b/compiler/utils/arm/assembler_arm.h index d288b700ed..c86ec4b3d6 100644 --- a/compiler/utils/arm/assembler_arm.h +++ b/compiler/utils/arm/assembler_arm.h @@ -30,6 +30,9 @@ namespace art { namespace arm { +class Arm32Assembler; +class Thumb2Assembler; + class ShifterOperand { public: ShifterOperand() : type_(kUnknown), rm_(kNoRegister), rs_(kNoRegister), @@ -103,33 +106,6 @@ class ShifterOperand { kImmediate }; - static bool CanHoldArm(uint32_t immediate, ShifterOperand* shifter_op) { - // Avoid the more expensive test for frequent small immediate values. - if (immediate < (1 << kImmed8Bits)) { - shifter_op->type_ = kImmediate; - shifter_op->is_rotate_ = true; - shifter_op->rotate_ = 0; - shifter_op->immed_ = immediate; - return true; - } - // Note that immediate must be unsigned for the test to work correctly. - for (int rot = 0; rot < 16; rot++) { - uint32_t imm8 = (immediate << 2*rot) | (immediate >> (32 - 2*rot)); - if (imm8 < (1 << kImmed8Bits)) { - shifter_op->type_ = kImmediate; - shifter_op->is_rotate_ = true; - shifter_op->rotate_ = rot; - shifter_op->immed_ = imm8; - return true; - } - } - return false; - } - - static bool CanHoldThumb(Register rd, Register rn, Opcode opcode, - uint32_t immediate, ShifterOperand* shifter_op); - - private: Type type_; Register rm_; @@ -140,6 +116,9 @@ class ShifterOperand { uint32_t rotate_; uint32_t immed_; + friend class Arm32Assembler; + friend class Thumb2Assembler; + #ifdef SOURCE_ASSEMBLER_SUPPORT friend class BinaryAssembler; #endif @@ -611,6 +590,14 @@ class ArmAssembler : public Assembler { virtual void Ror(Register rd, Register rm, Register rn, bool setcc = false, Condition cond = AL) = 0; + // Returns whether the `immediate` can fit in a `ShifterOperand`. If yes, + // `shifter_op` contains the operand. + virtual bool ShifterOperandCanHold(Register rd, + Register rn, + Opcode opcode, + uint32_t immediate, + ShifterOperand* shifter_op) = 0; + static bool IsInstructionForExceptionHandling(uintptr_t pc); virtual void Bind(Label* label) = 0; diff --git a/compiler/utils/arm/assembler_arm32.cc b/compiler/utils/arm/assembler_arm32.cc index a541763881..8f6d45ab53 100644 --- a/compiler/utils/arm/assembler_arm32.cc +++ b/compiler/utils/arm/assembler_arm32.cc @@ -25,6 +25,37 @@ namespace art { namespace arm { +bool Arm32Assembler::ShifterOperandCanHoldArm32(uint32_t immediate, ShifterOperand* shifter_op) { + // Avoid the more expensive test for frequent small immediate values. + if (immediate < (1 << kImmed8Bits)) { + shifter_op->type_ = ShifterOperand::kImmediate; + shifter_op->is_rotate_ = true; + shifter_op->rotate_ = 0; + shifter_op->immed_ = immediate; + return true; + } + // Note that immediate must be unsigned for the test to work correctly. + for (int rot = 0; rot < 16; rot++) { + uint32_t imm8 = (immediate << 2*rot) | (immediate >> (32 - 2*rot)); + if (imm8 < (1 << kImmed8Bits)) { + shifter_op->type_ = ShifterOperand::kImmediate; + shifter_op->is_rotate_ = true; + shifter_op->rotate_ = rot; + shifter_op->immed_ = imm8; + return true; + } + } + return false; +} + +bool Arm32Assembler::ShifterOperandCanHold(Register rd ATTRIBUTE_UNUSED, + Register rn ATTRIBUTE_UNUSED, + Opcode opcode ATTRIBUTE_UNUSED, + uint32_t immediate, + ShifterOperand* shifter_op) { + return ShifterOperandCanHoldArm32(immediate, shifter_op); +} + void Arm32Assembler::and_(Register rd, Register rn, const ShifterOperand& so, Condition cond) { EmitType01(cond, so.type(), AND, 0, rn, rd, so); @@ -1291,16 +1322,16 @@ void Arm32Assembler::AddConstant(Register rd, Register rn, int32_t value, // positive values and sub for negatives ones, which would slightly improve // the readability of generated code for some constants. ShifterOperand shifter_op; - if (ShifterOperand::CanHoldArm(value, &shifter_op)) { + if (ShifterOperandCanHoldArm32(value, &shifter_op)) { add(rd, rn, shifter_op, cond); - } else if (ShifterOperand::CanHoldArm(-value, &shifter_op)) { + } else if (ShifterOperandCanHoldArm32(-value, &shifter_op)) { sub(rd, rn, shifter_op, cond); } else { CHECK(rn != IP); - if (ShifterOperand::CanHoldArm(~value, &shifter_op)) { + if (ShifterOperandCanHoldArm32(~value, &shifter_op)) { mvn(IP, shifter_op, cond); add(rd, rn, ShifterOperand(IP), cond); - } else if (ShifterOperand::CanHoldArm(~(-value), &shifter_op)) { + } else if (ShifterOperandCanHoldArm32(~(-value), &shifter_op)) { mvn(IP, shifter_op, cond); sub(rd, rn, ShifterOperand(IP), cond); } else { @@ -1318,16 +1349,16 @@ void Arm32Assembler::AddConstant(Register rd, Register rn, int32_t value, void Arm32Assembler::AddConstantSetFlags(Register rd, Register rn, int32_t value, Condition cond) { ShifterOperand shifter_op; - if (ShifterOperand::CanHoldArm(value, &shifter_op)) { + if (ShifterOperandCanHoldArm32(value, &shifter_op)) { adds(rd, rn, shifter_op, cond); - } else if (ShifterOperand::CanHoldArm(-value, &shifter_op)) { + } else if (ShifterOperandCanHoldArm32(-value, &shifter_op)) { subs(rd, rn, shifter_op, cond); } else { CHECK(rn != IP); - if (ShifterOperand::CanHoldArm(~value, &shifter_op)) { + if (ShifterOperandCanHoldArm32(~value, &shifter_op)) { mvn(IP, shifter_op, cond); adds(rd, rn, ShifterOperand(IP), cond); - } else if (ShifterOperand::CanHoldArm(~(-value), &shifter_op)) { + } else if (ShifterOperandCanHoldArm32(~(-value), &shifter_op)) { mvn(IP, shifter_op, cond); subs(rd, rn, ShifterOperand(IP), cond); } else { @@ -1343,9 +1374,9 @@ void Arm32Assembler::AddConstantSetFlags(Register rd, Register rn, int32_t value void Arm32Assembler::LoadImmediate(Register rd, int32_t value, Condition cond) { ShifterOperand shifter_op; - if (ShifterOperand::CanHoldArm(value, &shifter_op)) { + if (ShifterOperandCanHoldArm32(value, &shifter_op)) { mov(rd, shifter_op, cond); - } else if (ShifterOperand::CanHoldArm(~value, &shifter_op)) { + } else if (ShifterOperandCanHoldArm32(~value, &shifter_op)) { mvn(rd, shifter_op, cond); } else { movw(rd, Low16Bits(value), cond); diff --git a/compiler/utils/arm/assembler_arm32.h b/compiler/utils/arm/assembler_arm32.h index 0b009e16d9..6c8d41587b 100644 --- a/compiler/utils/arm/assembler_arm32.h +++ b/compiler/utils/arm/assembler_arm32.h @@ -273,6 +273,12 @@ class Arm32Assembler FINAL : public ArmAssembler { int32_t offset, Condition cond = AL) OVERRIDE; + bool ShifterOperandCanHold(Register rd, + Register rn, + Opcode opcode, + uint32_t immediate, + ShifterOperand* shifter_op) OVERRIDE; + static bool IsInstructionForExceptionHandling(uintptr_t pc); @@ -359,6 +365,7 @@ class Arm32Assembler FINAL : public ArmAssembler { static int DecodeBranchOffset(int32_t inst); int32_t EncodeTstOffset(int offset, int32_t inst); int DecodeTstOffset(int32_t inst); + bool ShifterOperandCanHoldArm32(uint32_t immediate, ShifterOperand* shifter_op); }; } // namespace arm diff --git a/compiler/utils/arm/assembler_arm32_test.cc b/compiler/utils/arm/assembler_arm32_test.cc index 837fe1ec18..951792d45b 100644 --- a/compiler/utils/arm/assembler_arm32_test.cc +++ b/compiler/utils/arm/assembler_arm32_test.cc @@ -49,7 +49,8 @@ class AssemblerArm32Test : public AssemblerArmTest<arm::Arm32Assembler, } std::string GetAssemblerParameters() OVERRIDE { - return " -march=armv7-a -mcpu=cortex-a15"; // Arm-v7a, cortex-a15 (means we have sdiv). + // Arm-v7a, cortex-a15 (means we have sdiv). + return " -march=armv7-a -mcpu=cortex-a15 -mfpu=neon"; } const char* GetAssemblyHeader() OVERRIDE { @@ -688,4 +689,12 @@ TEST_F(AssemblerArm32Test, Bx) { T2Helper(&arm::Arm32Assembler::bx, true, "bx{cond} {reg1}", "bx"); } +TEST_F(AssemblerArm32Test, Vmstat) { + GetAssembler()->vmstat(); + + const char* expected = "vmrs APSR_nzcv, FPSCR\n"; + + DriverStr(expected, "vmrs"); +} + } // namespace art diff --git a/compiler/utils/arm/assembler_thumb2.cc b/compiler/utils/arm/assembler_thumb2.cc index a377cb2892..479186c5d7 100644 --- a/compiler/utils/arm/assembler_thumb2.cc +++ b/compiler/utils/arm/assembler_thumb2.cc @@ -25,6 +25,39 @@ namespace art { namespace arm { +bool Thumb2Assembler::ShifterOperandCanHold(Register rd, + Register rn, + Opcode opcode, + uint32_t immediate, + ShifterOperand* shifter_op) { + shifter_op->type_ = ShifterOperand::kImmediate; + shifter_op->immed_ = immediate; + shifter_op->is_shift_ = false; + shifter_op->is_rotate_ = false; + switch (opcode) { + case ADD: + case SUB: + if (rn == SP) { + if (rd == SP) { + return immediate < (1 << 9); // 9 bits allowed. + } else { + return immediate < (1 << 12); // 12 bits. + } + } + if (immediate < (1 << 12)) { // Less than (or equal to) 12 bits can always be done. + return true; + } + return ArmAssembler::ModifiedImmediate(immediate) != kInvalidModifiedImmediate; + + case MOV: + // TODO: Support less than or equal to 12bits. + return ArmAssembler::ModifiedImmediate(immediate) != kInvalidModifiedImmediate; + case MVN: + default: + return ArmAssembler::ModifiedImmediate(immediate) != kInvalidModifiedImmediate; + } +} + void Thumb2Assembler::and_(Register rd, Register rn, const ShifterOperand& so, Condition cond) { EmitDataProcessing(cond, AND, 0, rn, rd, so); @@ -374,16 +407,11 @@ void Thumb2Assembler::ldm(BlockAddressMode am, Register base, RegList regs, Condition cond) { - if (__builtin_popcount(regs) == 1) { + CHECK_NE(regs, 0u); // Do not use ldm if there's nothing to load. + if (IsPowerOfTwo(regs)) { // Thumb doesn't support one reg in the list. // Find the register number. - int reg = 0; - while (reg < 16) { - if ((regs & (1 << reg)) != 0) { - break; - } - ++reg; - } + int reg = CTZ(static_cast<uint32_t>(regs)); CHECK_LT(reg, 16); CHECK(am == DB_W); // Only writeback is supported. ldr(static_cast<Register>(reg), Address(base, kRegisterSize, Address::PostIndex), cond); @@ -397,16 +425,11 @@ void Thumb2Assembler::stm(BlockAddressMode am, Register base, RegList regs, Condition cond) { - if (__builtin_popcount(regs) == 1) { + CHECK_NE(regs, 0u); // Do not use stm if there's nothing to store. + if (IsPowerOfTwo(regs)) { // Thumb doesn't support one reg in the list. // Find the register number. - int reg = 0; - while (reg < 16) { - if ((regs & (1 << reg)) != 0) { - break; - } - ++reg; - } + int reg = CTZ(static_cast<uint32_t>(regs)); CHECK_LT(reg, 16); CHECK(am == IA || am == IA_W); Address::Mode strmode = am == IA ? Address::PreIndex : Address::Offset; @@ -813,6 +836,7 @@ void Thumb2Assembler::Emit32BitDataProcessing(Condition cond ATTRIBUTE_UNUSED, if (thumb_opcode == 255U /* 0b11111111 */) { LOG(FATAL) << "Invalid thumb2 opcode " << opcode; + UNREACHABLE(); } int32_t encoding = 0; @@ -842,6 +866,7 @@ void Thumb2Assembler::Emit32BitDataProcessing(Condition cond ATTRIBUTE_UNUSED, uint32_t imm = ModifiedImmediate(so.encodingThumb()); if (imm == kInvalidModifiedImmediate) { LOG(FATAL) << "Immediate value cannot fit in thumb2 modified immediate"; + UNREACHABLE(); } encoding = B31 | B30 | B29 | B28 | thumb_opcode << 21 | @@ -979,6 +1004,7 @@ void Thumb2Assembler::Emit16BitDataProcessing(Condition cond, if (thumb_opcode == 255U /* 0b11111111 */) { LOG(FATAL) << "Invalid thumb1 opcode " << opcode; + UNREACHABLE(); } int16_t encoding = dp_opcode << 14 | @@ -1116,7 +1142,7 @@ void Thumb2Assembler::Emit16BitAddSub(Condition cond ATTRIBUTE_UNUSED, break; default: LOG(FATAL) << "This opcode is not an ADD or SUB: " << opcode; - return; + UNREACHABLE(); } int16_t encoding = dp_opcode << 14 | @@ -1157,6 +1183,7 @@ void Thumb2Assembler::EmitShift(Register rd, Register rm, Shift shift, uint8_t a case RRX: opcode = 3U /* 0b11 */; amount = 0; break; default: LOG(FATAL) << "Unsupported thumb2 shift opcode"; + UNREACHABLE(); } // 32 bit. int32_t encoding = B31 | B30 | B29 | B27 | B25 | B22 | @@ -1174,7 +1201,8 @@ void Thumb2Assembler::EmitShift(Register rd, Register rm, Shift shift, uint8_t a case LSR: opcode = 1U /* 0b01 */; break; case ASR: opcode = 2U /* 0b10 */; break; default: - LOG(FATAL) << "Unsupported thumb2 shift opcode"; + LOG(FATAL) << "Unsupported thumb2 shift opcode"; + UNREACHABLE(); } int16_t encoding = opcode << 11 | amount << 6 | static_cast<int16_t>(rm) << 3 | static_cast<int16_t>(rd); @@ -1198,6 +1226,7 @@ void Thumb2Assembler::EmitShift(Register rd, Register rn, Shift shift, Register case ROR: opcode = 3U /* 0b11 */; break; default: LOG(FATAL) << "Unsupported thumb2 shift opcode"; + UNREACHABLE(); } // 32 bit. int32_t encoding = B31 | B30 | B29 | B28 | B27 | B25 | @@ -1212,7 +1241,8 @@ void Thumb2Assembler::EmitShift(Register rd, Register rn, Shift shift, Register case LSR: opcode = 3U /* 0b0011 */; break; case ASR: opcode = 4U /* 0b0100 */; break; default: - LOG(FATAL) << "Unsupported thumb2 shift opcode"; + LOG(FATAL) << "Unsupported thumb2 shift opcode"; + UNREACHABLE(); } int16_t encoding = B14 | opcode << 6 | static_cast<int16_t>(rm) << 3 | static_cast<int16_t>(rd); @@ -1241,6 +1271,7 @@ void Thumb2Assembler::Branch::Emit(AssemblerBuffer* buffer) const { } else { if (x) { LOG(FATAL) << "Invalid use of BX"; + UNREACHABLE(); } else { if (cond_ == AL) { // Can use the T4 encoding allowing a 24 bit offset. @@ -1469,6 +1500,15 @@ void Thumb2Assembler::EmitMultiMemOp(Condition cond, CheckCondition(cond); bool must_be_32bit = force_32bit_; + if (!must_be_32bit && base == SP && bam == (load ? IA_W : DB_W) && + (regs & 0xff00 & ~(1 << (load ? PC : LR))) == 0) { + // Use 16-bit PUSH/POP. + int16_t encoding = B15 | B13 | B12 | (load ? B11 : 0) | B10 | + ((regs & (1 << (load ? PC : LR))) != 0 ? B8 : 0) | (regs & 0x00ff); + Emit16(encoding); + return; + } + if ((regs & 0xff00) != 0) { must_be_32bit = true; } @@ -1495,6 +1535,7 @@ void Thumb2Assembler::EmitMultiMemOp(Condition cond, case DA_W: case IB_W: LOG(FATAL) << "LDM/STM mode not supported on thumb: " << bam; + UNREACHABLE(); } if (load) { // Cannot have SP in the list. @@ -1981,8 +2022,13 @@ void Thumb2Assembler::EmitVFPds(Condition cond, int32_t opcode, void Thumb2Assembler::vmstat(Condition cond) { // VMRS APSR_nzcv, FPSCR. + CHECK_NE(cond, kNoCondition); CheckCondition(cond); - UNIMPLEMENTED(FATAL) << "Unimplemented thumb instruction"; + int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | + B27 | B26 | B25 | B23 | B22 | B21 | B20 | B16 | + (static_cast<int32_t>(PC)*B12) | + B11 | B9 | B4; + Emit32(encoding); } @@ -2068,6 +2114,7 @@ void Thumb2Assembler::cbz(Register rn, Label* label) { CheckCondition(AL); if (label->IsBound()) { LOG(FATAL) << "cbz can only be used to branch forwards"; + UNREACHABLE(); } else { uint16_t branchid = EmitCompareAndBranch(rn, static_cast<uint16_t>(label->position_), false); label->LinkTo(branchid); @@ -2079,6 +2126,7 @@ void Thumb2Assembler::cbnz(Register rn, Label* label) { CheckCondition(AL); if (label->IsBound()) { LOG(FATAL) << "cbnz can only be used to branch forwards"; + UNREACHABLE(); } else { uint16_t branchid = EmitCompareAndBranch(rn, static_cast<uint16_t>(label->position_), true); label->LinkTo(branchid); @@ -2360,16 +2408,16 @@ void Thumb2Assembler::AddConstant(Register rd, Register rn, int32_t value, // positive values and sub for negatives ones, which would slightly improve // the readability of generated code for some constants. ShifterOperand shifter_op; - if (ShifterOperand::CanHoldThumb(rd, rn, ADD, value, &shifter_op)) { + if (ShifterOperandCanHold(rd, rn, ADD, value, &shifter_op)) { add(rd, rn, shifter_op, cond); - } else if (ShifterOperand::CanHoldThumb(rd, rn, SUB, -value, &shifter_op)) { + } else if (ShifterOperandCanHold(rd, rn, SUB, -value, &shifter_op)) { sub(rd, rn, shifter_op, cond); } else { CHECK(rn != IP); - if (ShifterOperand::CanHoldThumb(rd, rn, MVN, ~value, &shifter_op)) { + if (ShifterOperandCanHold(rd, rn, MVN, ~value, &shifter_op)) { mvn(IP, shifter_op, cond); add(rd, rn, ShifterOperand(IP), cond); - } else if (ShifterOperand::CanHoldThumb(rd, rn, MVN, ~(-value), &shifter_op)) { + } else if (ShifterOperandCanHold(rd, rn, MVN, ~(-value), &shifter_op)) { mvn(IP, shifter_op, cond); sub(rd, rn, ShifterOperand(IP), cond); } else { @@ -2387,16 +2435,16 @@ void Thumb2Assembler::AddConstant(Register rd, Register rn, int32_t value, void Thumb2Assembler::AddConstantSetFlags(Register rd, Register rn, int32_t value, Condition cond) { ShifterOperand shifter_op; - if (ShifterOperand::CanHoldThumb(rd, rn, ADD, value, &shifter_op)) { + if (ShifterOperandCanHold(rd, rn, ADD, value, &shifter_op)) { adds(rd, rn, shifter_op, cond); - } else if (ShifterOperand::CanHoldThumb(rd, rn, ADD, -value, &shifter_op)) { + } else if (ShifterOperandCanHold(rd, rn, ADD, -value, &shifter_op)) { subs(rd, rn, shifter_op, cond); } else { CHECK(rn != IP); - if (ShifterOperand::CanHoldThumb(rd, rn, MVN, ~value, &shifter_op)) { + if (ShifterOperandCanHold(rd, rn, MVN, ~value, &shifter_op)) { mvn(IP, shifter_op, cond); adds(rd, rn, ShifterOperand(IP), cond); - } else if (ShifterOperand::CanHoldThumb(rd, rn, MVN, ~(-value), &shifter_op)) { + } else if (ShifterOperandCanHold(rd, rn, MVN, ~(-value), &shifter_op)) { mvn(IP, shifter_op, cond); subs(rd, rn, ShifterOperand(IP), cond); } else { @@ -2410,11 +2458,12 @@ void Thumb2Assembler::AddConstantSetFlags(Register rd, Register rn, int32_t valu } } + void Thumb2Assembler::LoadImmediate(Register rd, int32_t value, Condition cond) { ShifterOperand shifter_op; - if (ShifterOperand::CanHoldThumb(rd, R0, MOV, value, &shifter_op)) { + if (ShifterOperandCanHold(rd, R0, MOV, value, &shifter_op)) { mov(rd, shifter_op, cond); - } else if (ShifterOperand::CanHoldThumb(rd, R0, MVN, ~value, &shifter_op)) { + } else if (ShifterOperandCanHold(rd, R0, MVN, ~value, &shifter_op)) { mvn(rd, shifter_op, cond); } else { movw(rd, Low16Bits(value), cond); @@ -2425,6 +2474,7 @@ void Thumb2Assembler::LoadImmediate(Register rd, int32_t value, Condition cond) } } + // Implementation note: this method must emit at most one instruction when // Address::CanHoldLoadOffsetThumb. void Thumb2Assembler::LoadFromOffset(LoadOperandType type, diff --git a/compiler/utils/arm/assembler_thumb2.h b/compiler/utils/arm/assembler_thumb2.h index cfa251acf2..48a3a7eeb2 100644 --- a/compiler/utils/arm/assembler_thumb2.h +++ b/compiler/utils/arm/assembler_thumb2.h @@ -304,6 +304,12 @@ class Thumb2Assembler FINAL : public ArmAssembler { int32_t offset, Condition cond = AL) OVERRIDE; + bool ShifterOperandCanHold(Register rd, + Register rn, + Opcode opcode, + uint32_t immediate, + ShifterOperand* shifter_op) OVERRIDE; + static bool IsInstructionForExceptionHandling(uintptr_t pc); diff --git a/compiler/utils/arm/assembler_thumb2_test.cc b/compiler/utils/arm/assembler_thumb2_test.cc index 65d6d45296..6ae95a40e6 100644 --- a/compiler/utils/arm/assembler_thumb2_test.cc +++ b/compiler/utils/arm/assembler_thumb2_test.cc @@ -30,7 +30,7 @@ class AssemblerThumb2Test : public AssemblerTest<arm::Thumb2Assembler, } std::string GetAssemblerParameters() OVERRIDE { - return " -mthumb"; + return " -mthumb -mfpu=neon"; } std::string GetDisassembleParameters() OVERRIDE { @@ -156,4 +156,12 @@ TEST_F(AssemblerThumb2Test, Ubfx) { DriverStr(expected, "ubfx"); } +TEST_F(AssemblerThumb2Test, Vmstat) { + GetAssembler()->vmstat(); + + const char* expected = "vmrs APSR_nzcv, FPSCR\n"; + + DriverStr(expected, "vmrs"); +} + } // namespace art |