diff options
author | 2015-07-30 15:07:22 +0100 | |
---|---|---|
committer | 2015-09-01 10:10:37 +0100 | |
commit | 73cf0fb75de2a449ce4fe329b5f1fb42eef1372f (patch) | |
tree | d5b0957414c355254babfcd1a797ce87a0eb85a2 | |
parent | 9ee5d6cdc14ac94b64ea1961bf221bad48746929 (diff) |
ART: Add 16-bit Thumb2 ROR, NEGS and CMP for high registers.
Also clean up the usage of set_cc flag. Define a SetCc
enumeration that specifies whether to set or keep condition
codes or whether we don't care and a 16-bit instruction
should be selected if one exists.
This reduces the size of Nexus 5 boot.oat by 44KiB (when
compiled with Optimizing which is not the default yet).
Change-Id: I047072dc197ea678bf2019c01bcb28943fa9b604
-rw-r--r-- | compiler/optimizing/code_generator_arm.cc | 12 | ||||
-rw-r--r-- | compiler/utils/arm/assembler_arm.cc | 6 | ||||
-rw-r--r-- | compiler/utils/arm/assembler_arm.h | 175 | ||||
-rw-r--r-- | compiler/utils/arm/assembler_arm32.cc | 182 | ||||
-rw-r--r-- | compiler/utils/arm/assembler_arm32.h | 83 | ||||
-rw-r--r-- | compiler/utils/arm/assembler_arm32_test.cc | 155 | ||||
-rw-r--r-- | compiler/utils/arm/assembler_arm_test.h | 24 | ||||
-rw-r--r-- | compiler/utils/arm/assembler_thumb2.cc | 424 | ||||
-rw-r--r-- | compiler/utils/arm/assembler_thumb2.h | 97 | ||||
-rw-r--r-- | compiler/utils/assembler_thumb_test.cc | 235 | ||||
-rw-r--r-- | compiler/utils/assembler_thumb_test_expected.cc.inc | 239 |
11 files changed, 1042 insertions, 590 deletions
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index 62026f31ab..9de9abffd8 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -2731,11 +2731,9 @@ void InstructionCodeGeneratorARM::VisitRem(HRem* rem) { Register temp = locations->GetTemp(0).AsRegister<Register>(); // temp = reg1 / reg2 (integer division) - // temp = temp * reg2 - // dest = reg1 - temp + // dest = reg1 - temp * reg2 __ sdiv(temp, reg1, reg2); - __ mul(temp, temp, reg2); - __ sub(out.AsRegister<Register>(), reg1, ShifterOperand(temp)); + __ mls(out.AsRegister<Register>(), temp, reg2, reg1); } else { InvokeRuntimeCallingConvention calling_convention; DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>()); @@ -2905,7 +2903,7 @@ void InstructionCodeGeneratorARM::HandleShift(HBinaryOperation* op) { // If the shift is > 32 bits, override the high part __ subs(temp, o_l, ShifterOperand(kArmBitsPerWord)); __ it(PL); - __ Lsl(o_h, low, temp, false, PL); + __ Lsl(o_h, low, temp, PL); // Shift the low part __ Lsl(o_l, low, o_l); } else if (op->IsShr()) { @@ -2919,7 +2917,7 @@ void InstructionCodeGeneratorARM::HandleShift(HBinaryOperation* op) { // If the shift is > 32 bits, override the low part __ subs(temp, o_h, ShifterOperand(kArmBitsPerWord)); __ it(PL); - __ Asr(o_l, high, temp, false, PL); + __ Asr(o_l, high, temp, PL); // Shift the high part __ Asr(o_h, high, o_h); } else { @@ -2931,7 +2929,7 @@ void InstructionCodeGeneratorARM::HandleShift(HBinaryOperation* op) { __ orr(o_l, o_l, ShifterOperand(temp)); __ subs(temp, o_h, ShifterOperand(kArmBitsPerWord)); __ it(PL); - __ Lsr(o_l, high, temp, false, PL); + __ Lsr(o_l, high, temp, PL); __ Lsr(o_h, high, o_h); } break; diff --git a/compiler/utils/arm/assembler_arm.cc b/compiler/utils/arm/assembler_arm.cc index 0e3e08c2da..807bedaa04 100644 --- a/compiler/utils/arm/assembler_arm.cc +++ b/compiler/utils/arm/assembler_arm.cc @@ -137,10 +137,14 @@ uint32_t ShifterOperand::encodingThumb() const { if (rs_ == kNoRegister) { // Immediate shift. if (shift_ == RRX) { + DCHECK_EQ(immed_, 0u); // RRX is encoded as an ROR with imm 0. return ROR << 4 | static_cast<uint32_t>(rm_); } else { - uint32_t imm3 = immed_ >> 2; + DCHECK((1 <= immed_ && immed_ <= 31) || + (immed_ == 0u && shift_ == LSL) || + (immed_ == 32u && (shift_ == ASR || shift_ == LSR))); + uint32_t imm3 = (immed_ >> 2) & 7 /* 0b111*/; uint32_t imm2 = immed_ & 3U /* 0b11 */; return imm3 << 12 | imm2 << 6 | shift_ << 4 | diff --git a/compiler/utils/arm/assembler_arm.h b/compiler/utils/arm/assembler_arm.h index ef60fefe4d..7825457d5c 100644 --- a/compiler/utils/arm/assembler_arm.h +++ b/compiler/utils/arm/assembler_arm.h @@ -375,6 +375,13 @@ enum ItState { kItE = kItElse }; +// Set condition codes request. +enum SetCc { + kCcDontCare, // Allows prioritizing 16-bit instructions on Thumb2 whether they set CCs or not. + kCcSet, + kCcKeep, +}; + constexpr uint32_t kNoItCondition = 3; constexpr uint32_t kInvalidModifiedImmediate = -1; @@ -392,25 +399,61 @@ class ArmAssembler : public Assembler { virtual bool IsThumb() const = 0; // Data-processing instructions. - virtual void and_(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) = 0; + virtual void and_(Register rd, Register rn, const ShifterOperand& so, + Condition cond = AL, SetCc set_cc = kCcDontCare) = 0; + + virtual void ands(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) { + and_(rd, rn, so, cond, kCcSet); + } - virtual void eor(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) = 0; + virtual void eor(Register rd, Register rn, const ShifterOperand& so, + Condition cond = AL, SetCc set_cc = kCcDontCare) = 0; - virtual void sub(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) = 0; - virtual void subs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) = 0; + virtual void eors(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) { + eor(rd, rn, so, cond, kCcSet); + } + + virtual void sub(Register rd, Register rn, const ShifterOperand& so, + Condition cond = AL, SetCc set_cc = kCcDontCare) = 0; + + virtual void subs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) { + sub(rd, rn, so, cond, kCcSet); + } - virtual void rsb(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) = 0; - virtual void rsbs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) = 0; + virtual void rsb(Register rd, Register rn, const ShifterOperand& so, + Condition cond = AL, SetCc set_cc = kCcDontCare) = 0; - virtual void add(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) = 0; + virtual void rsbs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) { + rsb(rd, rn, so, cond, kCcSet); + } + + virtual void add(Register rd, Register rn, const ShifterOperand& so, + Condition cond = AL, SetCc set_cc = kCcDontCare) = 0; + + virtual void adds(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) { + add(rd, rn, so, cond, kCcSet); + } + + virtual void adc(Register rd, Register rn, const ShifterOperand& so, + Condition cond = AL, SetCc set_cc = kCcDontCare) = 0; + + virtual void adcs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) { + adc(rd, rn, so, cond, kCcSet); + } - virtual void adds(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) = 0; + virtual void sbc(Register rd, Register rn, const ShifterOperand& so, + Condition cond = AL, SetCc set_cc = kCcDontCare) = 0; - virtual void adc(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) = 0; + virtual void sbcs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) { + sbc(rd, rn, so, cond, kCcSet); + } - virtual void sbc(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) = 0; + virtual void rsc(Register rd, Register rn, const ShifterOperand& so, + Condition cond = AL, SetCc set_cc = kCcDontCare) = 0; - virtual void rsc(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) = 0; + virtual void rscs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) { + rsc(rd, rn, so, cond, kCcSet); + } virtual void tst(Register rn, const ShifterOperand& so, Condition cond = AL) = 0; @@ -420,16 +463,33 @@ class ArmAssembler : public Assembler { virtual void cmn(Register rn, const ShifterOperand& so, Condition cond = AL) = 0; - virtual void orr(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) = 0; - virtual void orrs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) = 0; + virtual void orr(Register rd, Register rn, const ShifterOperand& so, + Condition cond = AL, SetCc set_cc = kCcDontCare) = 0; + + virtual void orrs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) { + orr(rd, rn, so, cond, kCcSet); + } + + virtual void mov(Register rd, const ShifterOperand& so, + Condition cond = AL, SetCc set_cc = kCcDontCare) = 0; + + virtual void movs(Register rd, const ShifterOperand& so, Condition cond = AL) { + mov(rd, so, cond, kCcSet); + } - virtual void mov(Register rd, const ShifterOperand& so, Condition cond = AL) = 0; - virtual void movs(Register rd, const ShifterOperand& so, Condition cond = AL) = 0; + virtual void bic(Register rd, Register rn, const ShifterOperand& so, + Condition cond = AL, SetCc set_cc = kCcDontCare) = 0; - virtual void bic(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) = 0; + virtual void bics(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) { + bic(rd, rn, so, cond, kCcSet); + } - virtual void mvn(Register rd, const ShifterOperand& so, Condition cond = AL) = 0; - virtual void mvns(Register rd, const ShifterOperand& so, Condition cond = AL) = 0; + virtual void mvn(Register rd, const ShifterOperand& so, + Condition cond = AL, SetCc set_cc = kCcDontCare) = 0; + + virtual void mvns(Register rd, const ShifterOperand& so, Condition cond = AL) { + mvn(rd, so, cond, kCcSet); + } // Miscellaneous data-processing instructions. virtual void clz(Register rd, Register rm, Condition cond = AL) = 0; @@ -697,25 +757,68 @@ class ArmAssembler : public Assembler { // Convenience shift instructions. Use mov instruction with shifter operand // for variants setting the status flags or using a register shift count. - virtual void Lsl(Register rd, Register rm, uint32_t shift_imm, bool setcc = false, - Condition cond = AL) = 0; - virtual void Lsr(Register rd, Register rm, uint32_t shift_imm, bool setcc = false, - Condition cond = AL) = 0; - virtual void Asr(Register rd, Register rm, uint32_t shift_imm, bool setcc = false, - Condition cond = AL) = 0; - virtual void Ror(Register rd, Register rm, uint32_t shift_imm, bool setcc = false, - Condition cond = AL) = 0; - virtual void Rrx(Register rd, Register rm, bool setcc = false, - Condition cond = AL) = 0; + virtual void Lsl(Register rd, Register rm, uint32_t shift_imm, + Condition cond = AL, SetCc set_cc = kCcDontCare) = 0; - virtual void Lsl(Register rd, Register rm, Register rn, bool setcc = false, - Condition cond = AL) = 0; - virtual void Lsr(Register rd, Register rm, Register rn, bool setcc = false, - Condition cond = AL) = 0; - virtual void Asr(Register rd, Register rm, Register rn, bool setcc = false, - Condition cond = AL) = 0; - virtual void Ror(Register rd, Register rm, Register rn, bool setcc = false, - Condition cond = AL) = 0; + void Lsls(Register rd, Register rm, uint32_t shift_imm, Condition cond = AL) { + Lsl(rd, rm, shift_imm, cond, kCcSet); + } + + virtual void Lsr(Register rd, Register rm, uint32_t shift_imm, + Condition cond = AL, SetCc set_cc = kCcDontCare) = 0; + + void Lsrs(Register rd, Register rm, uint32_t shift_imm, Condition cond = AL) { + Lsr(rd, rm, shift_imm, cond, kCcSet); + } + + virtual void Asr(Register rd, Register rm, uint32_t shift_imm, + Condition cond = AL, SetCc set_cc = kCcDontCare) = 0; + + void Asrs(Register rd, Register rm, uint32_t shift_imm, Condition cond = AL) { + Asr(rd, rm, shift_imm, cond, kCcSet); + } + + virtual void Ror(Register rd, Register rm, uint32_t shift_imm, + Condition cond = AL, SetCc set_cc = kCcDontCare) = 0; + + void Rors(Register rd, Register rm, uint32_t shift_imm, Condition cond = AL) { + Ror(rd, rm, shift_imm, cond, kCcSet); + } + + virtual void Rrx(Register rd, Register rm, + Condition cond = AL, SetCc set_cc = kCcDontCare) = 0; + + void Rrxs(Register rd, Register rm, Condition cond = AL) { + Rrx(rd, rm, cond, kCcSet); + } + + virtual void Lsl(Register rd, Register rm, Register rn, + Condition cond = AL, SetCc set_cc = kCcDontCare) = 0; + + void Lsls(Register rd, Register rm, Register rn, Condition cond = AL) { + Lsl(rd, rm, rn, cond, kCcSet); + } + + virtual void Lsr(Register rd, Register rm, Register rn, + Condition cond = AL, SetCc set_cc = kCcDontCare) = 0; + + void Lsrs(Register rd, Register rm, Register rn, Condition cond = AL) { + Lsr(rd, rm, rn, cond, kCcSet); + } + + virtual void Asr(Register rd, Register rm, Register rn, + Condition cond = AL, SetCc set_cc = kCcDontCare) = 0; + + void Asrs(Register rd, Register rm, Register rn, Condition cond = AL) { + Asr(rd, rm, rn, cond, kCcSet); + } + + virtual void Ror(Register rd, Register rm, Register rn, + Condition cond = AL, SetCc set_cc = kCcDontCare) = 0; + + void Rors(Register rd, Register rm, Register rn, Condition cond = AL) { + Ror(rd, rm, rn, cond, kCcSet); + } // Returns whether the `immediate` can fit in a `ShifterOperand`. If yes, // `shifter_op` contains the operand. diff --git a/compiler/utils/arm/assembler_arm32.cc b/compiler/utils/arm/assembler_arm32.cc index 6e60ddc260..d91ddee9b9 100644 --- a/compiler/utils/arm/assembler_arm32.cc +++ b/compiler/utils/arm/assembler_arm32.cc @@ -57,126 +57,94 @@ bool Arm32Assembler::ShifterOperandCanHold(Register rd ATTRIBUTE_UNUSED, } void Arm32Assembler::and_(Register rd, Register rn, const ShifterOperand& so, - Condition cond) { - EmitType01(cond, so.type(), AND, 0, rn, rd, so); + Condition cond, SetCc set_cc) { + EmitType01(cond, so.type(), AND, set_cc, rn, rd, so); } void Arm32Assembler::eor(Register rd, Register rn, const ShifterOperand& so, - Condition cond) { - EmitType01(cond, so.type(), EOR, 0, rn, rd, so); + Condition cond, SetCc set_cc) { + EmitType01(cond, so.type(), EOR, set_cc, rn, rd, so); } void Arm32Assembler::sub(Register rd, Register rn, const ShifterOperand& so, - Condition cond) { - EmitType01(cond, so.type(), SUB, 0, rn, rd, so); + Condition cond, SetCc set_cc) { + EmitType01(cond, so.type(), SUB, set_cc, rn, rd, so); } void Arm32Assembler::rsb(Register rd, Register rn, const ShifterOperand& so, - Condition cond) { - EmitType01(cond, so.type(), RSB, 0, rn, rd, so); + Condition cond, SetCc set_cc) { + EmitType01(cond, so.type(), RSB, set_cc, rn, rd, so); } -void Arm32Assembler::rsbs(Register rd, Register rn, const ShifterOperand& so, - Condition cond) { - EmitType01(cond, so.type(), RSB, 1, rn, rd, so); -} - - void Arm32Assembler::add(Register rd, Register rn, const ShifterOperand& so, - Condition cond) { - EmitType01(cond, so.type(), ADD, 0, rn, rd, so); -} - - -void Arm32Assembler::adds(Register rd, Register rn, const ShifterOperand& so, - Condition cond) { - EmitType01(cond, so.type(), ADD, 1, rn, rd, so); -} - - -void Arm32Assembler::subs(Register rd, Register rn, const ShifterOperand& so, - Condition cond) { - EmitType01(cond, so.type(), SUB, 1, rn, rd, so); + Condition cond, SetCc set_cc) { + EmitType01(cond, so.type(), ADD, set_cc, rn, rd, so); } void Arm32Assembler::adc(Register rd, Register rn, const ShifterOperand& so, - Condition cond) { - EmitType01(cond, so.type(), ADC, 0, rn, rd, so); + Condition cond, SetCc set_cc) { + EmitType01(cond, so.type(), ADC, set_cc, rn, rd, so); } void Arm32Assembler::sbc(Register rd, Register rn, const ShifterOperand& so, - Condition cond) { - EmitType01(cond, so.type(), SBC, 0, rn, rd, so); + Condition cond, SetCc set_cc) { + EmitType01(cond, so.type(), SBC, set_cc, rn, rd, so); } void Arm32Assembler::rsc(Register rd, Register rn, const ShifterOperand& so, - Condition cond) { - EmitType01(cond, so.type(), RSC, 0, rn, rd, so); + Condition cond, SetCc set_cc) { + EmitType01(cond, so.type(), RSC, set_cc, rn, rd, so); } void Arm32Assembler::tst(Register rn, const ShifterOperand& so, Condition cond) { CHECK_NE(rn, PC); // Reserve tst pc instruction for exception handler marker. - EmitType01(cond, so.type(), TST, 1, rn, R0, so); + EmitType01(cond, so.type(), TST, kCcSet, rn, R0, so); } void Arm32Assembler::teq(Register rn, const ShifterOperand& so, Condition cond) { CHECK_NE(rn, PC); // Reserve teq pc instruction for exception handler marker. - EmitType01(cond, so.type(), TEQ, 1, rn, R0, so); + EmitType01(cond, so.type(), TEQ, kCcSet, rn, R0, so); } void Arm32Assembler::cmp(Register rn, const ShifterOperand& so, Condition cond) { - EmitType01(cond, so.type(), CMP, 1, rn, R0, so); + EmitType01(cond, so.type(), CMP, kCcSet, rn, R0, so); } void Arm32Assembler::cmn(Register rn, const ShifterOperand& so, Condition cond) { - EmitType01(cond, so.type(), CMN, 1, rn, R0, so); -} - - -void Arm32Assembler::orr(Register rd, Register rn, - const ShifterOperand& so, Condition cond) { - EmitType01(cond, so.type(), ORR, 0, rn, rd, so); -} - - -void Arm32Assembler::orrs(Register rd, Register rn, - const ShifterOperand& so, Condition cond) { - EmitType01(cond, so.type(), ORR, 1, rn, rd, so); + EmitType01(cond, so.type(), CMN, kCcSet, rn, R0, so); } -void Arm32Assembler::mov(Register rd, const ShifterOperand& so, Condition cond) { - EmitType01(cond, so.type(), MOV, 0, R0, rd, so); +void Arm32Assembler::orr(Register rd, Register rn, const ShifterOperand& so, + Condition cond, SetCc set_cc) { + EmitType01(cond, so.type(), ORR, set_cc, rn, rd, so); } -void Arm32Assembler::movs(Register rd, const ShifterOperand& so, Condition cond) { - EmitType01(cond, so.type(), MOV, 1, R0, rd, so); +void Arm32Assembler::mov(Register rd, const ShifterOperand& so, + Condition cond, SetCc set_cc) { + EmitType01(cond, so.type(), MOV, set_cc, R0, rd, so); } void Arm32Assembler::bic(Register rd, Register rn, const ShifterOperand& so, - Condition cond) { - EmitType01(cond, so.type(), BIC, 0, rn, rd, so); -} - - -void Arm32Assembler::mvn(Register rd, const ShifterOperand& so, Condition cond) { - EmitType01(cond, so.type(), MVN, 0, R0, rd, so); + Condition cond, SetCc set_cc) { + EmitType01(cond, so.type(), BIC, set_cc, rn, rd, so); } -void Arm32Assembler::mvns(Register rd, const ShifterOperand& so, Condition cond) { - EmitType01(cond, so.type(), MVN, 1, R0, rd, so); +void Arm32Assembler::mvn(Register rd, const ShifterOperand& so, + Condition cond, SetCc set_cc) { + EmitType01(cond, so.type(), MVN, set_cc, R0, rd, so); } @@ -573,7 +541,7 @@ void Arm32Assembler::bl(Label* label, Condition cond) { void Arm32Assembler::MarkExceptionHandler(Label* label) { - EmitType01(AL, 1, TST, 1, PC, R0, ShifterOperand(0)); + EmitType01(AL, 1, TST, kCcSet, PC, R0, ShifterOperand(0)); Label l; b(&l); EmitBranch(AL, label, false); @@ -590,7 +558,7 @@ void Arm32Assembler::Emit(int32_t value) { void Arm32Assembler::EmitType01(Condition cond, int type, Opcode opcode, - int set_cc, + SetCc set_cc, Register rn, Register rd, const ShifterOperand& so) { @@ -599,7 +567,7 @@ void Arm32Assembler::EmitType01(Condition cond, int32_t encoding = static_cast<int32_t>(cond) << kConditionShift | type << kTypeShift | static_cast<int32_t>(opcode) << kOpcodeShift | - set_cc << kSShift | + (set_cc == kCcSet ? 1 : 0) << kSShift | static_cast<int32_t>(rn) << kRnShift | static_cast<int32_t>(rd) << kRdShift | so.encodingArm(); @@ -1158,96 +1126,60 @@ void Arm32Assembler::EmitVFPds(Condition cond, int32_t opcode, void Arm32Assembler::Lsl(Register rd, Register rm, uint32_t shift_imm, - bool setcc, Condition cond) { + Condition cond, SetCc set_cc) { CHECK_LE(shift_imm, 31u); - if (setcc) { - movs(rd, ShifterOperand(rm, LSL, shift_imm), cond); - } else { - mov(rd, ShifterOperand(rm, LSL, shift_imm), cond); - } + mov(rd, ShifterOperand(rm, LSL, shift_imm), cond, set_cc); } void Arm32Assembler::Lsr(Register rd, Register rm, uint32_t shift_imm, - bool setcc, Condition cond) { + Condition cond, SetCc set_cc) { CHECK(1u <= shift_imm && shift_imm <= 32u); if (shift_imm == 32) shift_imm = 0; // Comply to UAL syntax. - if (setcc) { - movs(rd, ShifterOperand(rm, LSR, shift_imm), cond); - } else { - mov(rd, ShifterOperand(rm, LSR, shift_imm), cond); - } + mov(rd, ShifterOperand(rm, LSR, shift_imm), cond, set_cc); } void Arm32Assembler::Asr(Register rd, Register rm, uint32_t shift_imm, - bool setcc, Condition cond) { + Condition cond, SetCc set_cc) { CHECK(1u <= shift_imm && shift_imm <= 32u); if (shift_imm == 32) shift_imm = 0; // Comply to UAL syntax. - if (setcc) { - movs(rd, ShifterOperand(rm, ASR, shift_imm), cond); - } else { - mov(rd, ShifterOperand(rm, ASR, shift_imm), cond); - } + mov(rd, ShifterOperand(rm, ASR, shift_imm), cond, set_cc); } void Arm32Assembler::Ror(Register rd, Register rm, uint32_t shift_imm, - bool setcc, Condition cond) { + Condition cond, SetCc set_cc) { CHECK(1u <= shift_imm && shift_imm <= 31u); - if (setcc) { - movs(rd, ShifterOperand(rm, ROR, shift_imm), cond); - } else { - mov(rd, ShifterOperand(rm, ROR, shift_imm), cond); - } + mov(rd, ShifterOperand(rm, ROR, shift_imm), cond, set_cc); } -void Arm32Assembler::Rrx(Register rd, Register rm, bool setcc, Condition cond) { - if (setcc) { - movs(rd, ShifterOperand(rm, ROR, 0), cond); - } else { - mov(rd, ShifterOperand(rm, ROR, 0), cond); - } +void Arm32Assembler::Rrx(Register rd, Register rm, Condition cond, SetCc set_cc) { + mov(rd, ShifterOperand(rm, ROR, 0), cond, set_cc); } void Arm32Assembler::Lsl(Register rd, Register rm, Register rn, - bool setcc, Condition cond) { - if (setcc) { - movs(rd, ShifterOperand(rm, LSL, rn), cond); - } else { - mov(rd, ShifterOperand(rm, LSL, rn), cond); - } + Condition cond, SetCc set_cc) { + mov(rd, ShifterOperand(rm, LSL, rn), cond, set_cc); } void Arm32Assembler::Lsr(Register rd, Register rm, Register rn, - bool setcc, Condition cond) { - if (setcc) { - movs(rd, ShifterOperand(rm, LSR, rn), cond); - } else { - mov(rd, ShifterOperand(rm, LSR, rn), cond); - } + Condition cond, SetCc set_cc) { + mov(rd, ShifterOperand(rm, LSR, rn), cond, set_cc); } void Arm32Assembler::Asr(Register rd, Register rm, Register rn, - bool setcc, Condition cond) { - if (setcc) { - movs(rd, ShifterOperand(rm, ASR, rn), cond); - } else { - mov(rd, ShifterOperand(rm, ASR, rn), cond); - } + Condition cond, SetCc set_cc) { + mov(rd, ShifterOperand(rm, ASR, rn), cond, set_cc); } void Arm32Assembler::Ror(Register rd, Register rm, Register rn, - bool setcc, Condition cond) { - if (setcc) { - movs(rd, ShifterOperand(rm, ROR, rn), cond); - } else { - mov(rd, ShifterOperand(rm, ROR, rn), cond); - } + Condition cond, SetCc set_cc) { + mov(rd, ShifterOperand(rm, ROR, rn), cond, set_cc); } void Arm32Assembler::vmstat(Condition cond) { // VMRS APSR_nzcv, FPSCR @@ -1434,24 +1366,24 @@ void Arm32Assembler::AddConstantSetFlags(Register rd, Register rn, int32_t value Condition cond) { ShifterOperand shifter_op; if (ShifterOperandCanHoldArm32(value, &shifter_op)) { - adds(rd, rn, shifter_op, cond); + add(rd, rn, shifter_op, cond, kCcSet); } else if (ShifterOperandCanHoldArm32(-value, &shifter_op)) { - subs(rd, rn, shifter_op, cond); + sub(rd, rn, shifter_op, cond, kCcSet); } else { CHECK(rn != IP); if (ShifterOperandCanHoldArm32(~value, &shifter_op)) { mvn(IP, shifter_op, cond); - adds(rd, rn, ShifterOperand(IP), cond); + add(rd, rn, ShifterOperand(IP), cond, kCcSet); } else if (ShifterOperandCanHoldArm32(~(-value), &shifter_op)) { mvn(IP, shifter_op, cond); - subs(rd, rn, ShifterOperand(IP), cond); + sub(rd, rn, ShifterOperand(IP), cond, kCcSet); } else { movw(IP, Low16Bits(value), cond); uint16_t value_high = High16Bits(value); if (value_high != 0) { movt(IP, value_high, cond); } - adds(rd, rn, ShifterOperand(IP), cond); + add(rd, rn, ShifterOperand(IP), cond, kCcSet); } } } diff --git a/compiler/utils/arm/assembler_arm32.h b/compiler/utils/arm/assembler_arm32.h index 1c38eec12c..b96bb74182 100644 --- a/compiler/utils/arm/assembler_arm32.h +++ b/compiler/utils/arm/assembler_arm32.h @@ -39,25 +39,29 @@ class Arm32Assembler FINAL : public ArmAssembler { } // Data-processing instructions. - void and_(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + virtual void and_(Register rd, Register rn, const ShifterOperand& so, + Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE; - void eor(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + virtual void eor(Register rd, Register rn, const ShifterOperand& so, + Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE; - void sub(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; - void subs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + virtual void sub(Register rd, Register rn, const ShifterOperand& so, + Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE; - void rsb(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; - void rsbs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + virtual void rsb(Register rd, Register rn, const ShifterOperand& so, + Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE; - void add(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + virtual void add(Register rd, Register rn, const ShifterOperand& so, + Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE; - void adds(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + virtual void adc(Register rd, Register rn, const ShifterOperand& so, + Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE; - void adc(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + virtual void sbc(Register rd, Register rn, const ShifterOperand& so, + Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE; - void sbc(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; - - void rsc(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + virtual void rsc(Register rd, Register rn, const ShifterOperand& so, + Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE; void tst(Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; @@ -67,16 +71,17 @@ class Arm32Assembler FINAL : public ArmAssembler { void cmn(Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; - void orr(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; - void orrs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + virtual void orr(Register rd, Register rn, const ShifterOperand& so, + Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE; - void mov(Register rd, const ShifterOperand& so, Condition cond = AL) OVERRIDE; - void movs(Register rd, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + virtual void mov(Register rd, const ShifterOperand& so, + Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE; - void bic(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + virtual void bic(Register rd, Register rn, const ShifterOperand& so, + Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE; - void mvn(Register rd, const ShifterOperand& so, Condition cond = AL) OVERRIDE; - void mvns(Register rd, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + virtual void mvn(Register rd, const ShifterOperand& so, + Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE; // Miscellaneous data-processing instructions. void clz(Register rd, Register rm, Condition cond = AL) OVERRIDE; @@ -204,25 +209,25 @@ class Arm32Assembler FINAL : public ArmAssembler { void bl(Label* label, Condition cond = AL) OVERRIDE; void blx(Register rm, Condition cond = AL) OVERRIDE; void bx(Register rm, Condition cond = AL) OVERRIDE; - void Lsl(Register rd, Register rm, uint32_t shift_imm, bool setcc = false, - Condition cond = AL) OVERRIDE; - void Lsr(Register rd, Register rm, uint32_t shift_imm, bool setcc = false, - Condition cond = AL) OVERRIDE; - void Asr(Register rd, Register rm, uint32_t shift_imm, bool setcc = false, - Condition cond = AL) OVERRIDE; - void Ror(Register rd, Register rm, uint32_t shift_imm, bool setcc = false, - Condition cond = AL) OVERRIDE; - void Rrx(Register rd, Register rm, bool setcc = false, - Condition cond = AL) OVERRIDE; - - void Lsl(Register rd, Register rm, Register rn, bool setcc = false, - Condition cond = AL) OVERRIDE; - void Lsr(Register rd, Register rm, Register rn, bool setcc = false, - Condition cond = AL) OVERRIDE; - void Asr(Register rd, Register rm, Register rn, bool setcc = false, - Condition cond = AL) OVERRIDE; - void Ror(Register rd, Register rm, Register rn, bool setcc = false, - Condition cond = AL) OVERRIDE; + virtual void Lsl(Register rd, Register rm, uint32_t shift_imm, + Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE; + virtual void Lsr(Register rd, Register rm, uint32_t shift_imm, + Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE; + virtual void Asr(Register rd, Register rm, uint32_t shift_imm, + Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE; + virtual void Ror(Register rd, Register rm, uint32_t shift_imm, + Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE; + virtual void Rrx(Register rd, Register rm, + Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE; + + virtual void Lsl(Register rd, Register rm, Register rn, + Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE; + virtual void Lsr(Register rd, Register rm, Register rn, + Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE; + virtual void Asr(Register rd, Register rm, Register rn, + Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE; + virtual void Ror(Register rd, Register rm, Register rn, + Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE; void Push(Register rd, Condition cond = AL) OVERRIDE; void Pop(Register rd, Condition cond = AL) OVERRIDE; @@ -305,7 +310,7 @@ class Arm32Assembler FINAL : public ArmAssembler { void EmitType01(Condition cond, int type, Opcode opcode, - int set_cc, + SetCc set_cc, Register rn, Register rd, const ShifterOperand& so); diff --git a/compiler/utils/arm/assembler_arm32_test.cc b/compiler/utils/arm/assembler_arm32_test.cc index efd517b83a..e6412ac684 100644 --- a/compiler/utils/arm/assembler_arm32_test.cc +++ b/compiler/utils/arm/assembler_arm32_test.cc @@ -42,7 +42,8 @@ static constexpr bool kUseSparseShiftImmediates = true; class AssemblerArm32Test : public AssemblerArmTest<arm::Arm32Assembler, arm::Register, arm::SRegister, - uint32_t, arm::ShifterOperand, arm::Condition> { + uint32_t, arm::ShifterOperand, arm::Condition, + arm::SetCc> { protected: std::string GetArchitectureString() OVERRIDE { return "arm"; @@ -125,6 +126,10 @@ class AssemblerArm32Test : public AssemblerArmTest<arm::Arm32Assembler, conditions_.push_back(arm::Condition::AL); } + set_ccs_.push_back(arm::kCcDontCare); + set_ccs_.push_back(arm::kCcSet); + set_ccs_.push_back(arm::kCcKeep); + shifter_operands_.push_back(arm::ShifterOperand(0)); shifter_operands_.push_back(arm::ShifterOperand(1)); shifter_operands_.push_back(arm::ShifterOperand(2)); @@ -240,6 +245,15 @@ class AssemblerArm32Test : public AssemblerArmTest<arm::Arm32Assembler, return oss.str(); } + std::vector<arm::SetCc>& GetSetCcs() OVERRIDE { + return set_ccs_; + } + + std::string GetSetCcString(arm::SetCc s) OVERRIDE { + // For arm32, kCcDontCare defaults to not setting condition codes. + return s == arm::kCcSet ? "s" : ""; + } + arm::Register GetPCRegister() OVERRIDE { return arm::R15; } @@ -369,12 +383,12 @@ class AssemblerArm32Test : public AssemblerArmTest<arm::Arm32Assembler, size_t cond_index = after_cond.find(COND_TOKEN); if (cond_index != std::string::npos) { - after_cond.replace(cond_index, ConstexprStrLen(IMM1_TOKEN), GetConditionString(c)); + after_cond.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c)); } cond_index = after_cond_filter.find(COND_TOKEN); if (cond_index != std::string::npos) { - after_cond_filter.replace(cond_index, ConstexprStrLen(IMM1_TOKEN), GetConditionString(c)); + after_cond_filter.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c)); } if (EvalFilterString(after_cond_filter)) { continue; @@ -384,6 +398,30 @@ class AssemblerArm32Test : public AssemblerArmTest<arm::Arm32Assembler, } } + void TemplateHelper(std::function<void(arm::SetCc)> f, int depth ATTRIBUTE_UNUSED, + bool without_pc ATTRIBUTE_UNUSED, std::string fmt, std::string filter, + std::ostringstream& oss) { + for (arm::SetCc s : GetSetCcs()) { + std::string after_cond = fmt; + std::string after_cond_filter = filter; + + size_t cond_index = after_cond.find(SET_CC_TOKEN); + if (cond_index != std::string::npos) { + after_cond.replace(cond_index, ConstexprStrLen(SET_CC_TOKEN), GetSetCcString(s)); + } + + cond_index = after_cond_filter.find(SET_CC_TOKEN); + if (cond_index != std::string::npos) { + after_cond_filter.replace(cond_index, ConstexprStrLen(SET_CC_TOKEN), GetSetCcString(s)); + } + if (EvalFilterString(after_cond_filter)) { + continue; + } + + ExecuteAndPrint([&] () { f(s); }, after_cond, oss); + } + } + template <typename... Args> void TemplateHelper(std::function<void(arm::Register, Args...)> f, int depth, bool without_pc, std::string fmt, std::string filter, std::ostringstream& oss) { @@ -449,12 +487,12 @@ class AssemblerArm32Test : public AssemblerArmTest<arm::Arm32Assembler, size_t cond_index = after_cond.find(COND_TOKEN); if (cond_index != std::string::npos) { - after_cond.replace(cond_index, ConstexprStrLen(IMM1_TOKEN), GetConditionString(c)); + after_cond.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c)); } cond_index = after_cond_filter.find(COND_TOKEN); if (cond_index != std::string::npos) { - after_cond_filter.replace(cond_index, ConstexprStrLen(IMM1_TOKEN), GetConditionString(c)); + after_cond_filter.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c)); } if (EvalFilterString(after_cond_filter)) { continue; @@ -466,25 +504,51 @@ class AssemblerArm32Test : public AssemblerArmTest<arm::Arm32Assembler, } } - template <typename T1, typename T2> - std::function<void(T1, T2)> GetBoundFunction2(void (arm::Arm32Assembler::*f)(T1, T2)) { + template <typename... Args> + void TemplateHelper(std::function<void(arm::SetCc, Args...)> f, int depth, bool without_pc, + std::string fmt, std::string filter, std::ostringstream& oss) { + for (arm::SetCc s : GetSetCcs()) { + std::string after_cond = fmt; + std::string after_cond_filter = filter; + + size_t cond_index = after_cond.find(SET_CC_TOKEN); + if (cond_index != std::string::npos) { + after_cond.replace(cond_index, ConstexprStrLen(SET_CC_TOKEN), GetSetCcString(s)); + } + + cond_index = after_cond_filter.find(SET_CC_TOKEN); + if (cond_index != std::string::npos) { + after_cond_filter.replace(cond_index, ConstexprStrLen(SET_CC_TOKEN), GetSetCcString(s)); + } + if (EvalFilterString(after_cond_filter)) { + continue; + } + + auto lambda = [&] (Args... args) { f(s, args...); }; // NOLINT [readability/braces] [4] + TemplateHelper(std::function<void(Args...)>(lambda), depth, without_pc, + after_cond, after_cond_filter, oss); + } + } + + template <typename Assembler, typename T1, typename T2> + std::function<void(T1, T2)> GetBoundFunction2(void (Assembler::*f)(T1, T2)) { return std::bind(f, GetAssembler(), _1, _2); } - template <typename T1, typename T2, typename T3> - std::function<void(T1, T2, T3)> GetBoundFunction3(void (arm::Arm32Assembler::*f)(T1, T2, T3)) { + template <typename Assembler, typename T1, typename T2, typename T3> + std::function<void(T1, T2, T3)> GetBoundFunction3(void (Assembler::*f)(T1, T2, T3)) { return std::bind(f, GetAssembler(), _1, _2, _3); } - template <typename T1, typename T2, typename T3, typename T4> + template <typename Assembler, typename T1, typename T2, typename T3, typename T4> std::function<void(T1, T2, T3, T4)> GetBoundFunction4( - void (arm::Arm32Assembler::*f)(T1, T2, T3, T4)) { + void (Assembler::*f)(T1, T2, T3, T4)) { return std::bind(f, GetAssembler(), _1, _2, _3, _4); } - template <typename T1, typename T2, typename T3, typename T4, typename T5> + template <typename Assembler, typename T1, typename T2, typename T3, typename T4, typename T5> std::function<void(T1, T2, T3, T4, T5)> GetBoundFunction5( - void (arm::Arm32Assembler::*f)(T1, T2, T3, T4, T5)) { + void (Assembler::*f)(T1, T2, T3, T4, T5)) { return std::bind(f, GetAssembler(), _1, _2, _3, _4, _5); } @@ -503,26 +567,26 @@ class AssemblerArm32Test : public AssemblerArmTest<arm::Arm32Assembler, DriverStr(oss.str(), test_name); } - template <typename... Args> - void T2Helper(void (arm::Arm32Assembler::*f)(Args...), bool without_pc, std::string fmt, + template <typename Assembler, typename... Args> + void T2Helper(void (Assembler::*f)(Args...), bool without_pc, std::string fmt, std::string test_name, std::string filter = "") { GenericTemplateHelper(GetBoundFunction2(f), without_pc, fmt, test_name, filter); } - template <typename... Args> - void T3Helper(void (arm::Arm32Assembler::*f)(Args...), bool without_pc, std::string fmt, + template <typename Assembler, typename... Args> + void T3Helper(void (Assembler::*f)(Args...), bool without_pc, std::string fmt, std::string test_name, std::string filter = "") { GenericTemplateHelper(GetBoundFunction3(f), without_pc, fmt, test_name, filter); } - template <typename... Args> - void T4Helper(void (arm::Arm32Assembler::*f)(Args...), bool without_pc, std::string fmt, + template <typename Assembler, typename... Args> + void T4Helper(void (Assembler::*f)(Args...), bool without_pc, std::string fmt, std::string test_name, std::string filter = "") { GenericTemplateHelper(GetBoundFunction4(f), without_pc, fmt, test_name, filter); } - template <typename... Args> - void T5Helper(void (arm::Arm32Assembler::*f)(Args...), bool without_pc, std::string fmt, + template <typename Assembler, typename... Args> + void T5Helper(void (Assembler::*f)(Args...), bool without_pc, std::string fmt, std::string test_name, std::string filter = "") { GenericTemplateHelper(GetBoundFunction5(f), without_pc, fmt, test_name, filter); } @@ -573,6 +637,7 @@ class AssemblerArm32Test : public AssemblerArmTest<arm::Arm32Assembler, std::vector<arm::Register*> registers_; std::vector<arm::Condition> conditions_; + std::vector<arm::SetCc> set_ccs_; std::vector<arm::ShifterOperand> shifter_operands_; }; @@ -656,15 +721,23 @@ TEST_F(AssemblerArm32Test, Udiv) { } TEST_F(AssemblerArm32Test, And) { - T4Helper(&arm::Arm32Assembler::and_, true, "and{cond} {reg1}, {reg2}, {shift}", "and"); + T5Helper(&arm::Arm32Assembler::and_, true, "and{cond}{s} {reg1}, {reg2}, {shift}", "and"); +} + +TEST_F(AssemblerArm32Test, Ands) { + T4Helper(&arm::Arm32Assembler::ands, true, "and{cond}s {reg1}, {reg2}, {shift}", "ands"); } TEST_F(AssemblerArm32Test, Eor) { - T4Helper(&arm::Arm32Assembler::eor, true, "eor{cond} {reg1}, {reg2}, {shift}", "eor"); + T5Helper(&arm::Arm32Assembler::eor, true, "eor{cond}{s} {reg1}, {reg2}, {shift}", "eor"); +} + +TEST_F(AssemblerArm32Test, Eors) { + T4Helper(&arm::Arm32Assembler::eors, true, "eor{cond}s {reg1}, {reg2}, {shift}", "eors"); } TEST_F(AssemblerArm32Test, Orr) { - T4Helper(&arm::Arm32Assembler::orr, true, "orr{cond} {reg1}, {reg2}, {shift}", "orr"); + T5Helper(&arm::Arm32Assembler::orr, true, "orr{cond}{s} {reg1}, {reg2}, {shift}", "orr"); } TEST_F(AssemblerArm32Test, Orrs) { @@ -672,11 +745,15 @@ TEST_F(AssemblerArm32Test, Orrs) { } TEST_F(AssemblerArm32Test, Bic) { - T4Helper(&arm::Arm32Assembler::bic, true, "bic{cond} {reg1}, {reg2}, {shift}", "bic"); + T5Helper(&arm::Arm32Assembler::bic, true, "bic{cond}{s} {reg1}, {reg2}, {shift}", "bic"); +} + +TEST_F(AssemblerArm32Test, Bics) { + T4Helper(&arm::Arm32Assembler::bics, true, "bic{cond}s {reg1}, {reg2}, {shift}", "bics"); } TEST_F(AssemblerArm32Test, Mov) { - T3Helper(&arm::Arm32Assembler::mov, true, "mov{cond} {reg1}, {shift}", "mov"); + T4Helper(&arm::Arm32Assembler::mov, true, "mov{cond}{s} {reg1}, {shift}", "mov"); } TEST_F(AssemblerArm32Test, Movs) { @@ -684,7 +761,7 @@ TEST_F(AssemblerArm32Test, Movs) { } TEST_F(AssemblerArm32Test, Mvn) { - T3Helper(&arm::Arm32Assembler::mvn, true, "mvn{cond} {reg1}, {shift}", "mvn"); + T4Helper(&arm::Arm32Assembler::mvn, true, "mvn{cond}{s} {reg1}, {shift}", "mvn"); } TEST_F(AssemblerArm32Test, Mvns) { @@ -692,7 +769,7 @@ TEST_F(AssemblerArm32Test, Mvns) { } TEST_F(AssemblerArm32Test, Add) { - T4Helper(&arm::Arm32Assembler::add, false, "add{cond} {reg1}, {reg2}, {shift}", "add"); + T5Helper(&arm::Arm32Assembler::add, false, "add{cond}{s} {reg1}, {reg2}, {shift}", "add"); } TEST_F(AssemblerArm32Test, Adds) { @@ -700,11 +777,15 @@ TEST_F(AssemblerArm32Test, Adds) { } TEST_F(AssemblerArm32Test, Adc) { - T4Helper(&arm::Arm32Assembler::adc, false, "adc{cond} {reg1}, {reg2}, {shift}", "adc"); + T5Helper(&arm::Arm32Assembler::adc, false, "adc{cond}{s} {reg1}, {reg2}, {shift}", "adc"); +} + +TEST_F(AssemblerArm32Test, Adcs) { + T4Helper(&arm::Arm32Assembler::adcs, false, "adc{cond}s {reg1}, {reg2}, {shift}", "adcs"); } TEST_F(AssemblerArm32Test, Sub) { - T4Helper(&arm::Arm32Assembler::sub, false, "sub{cond} {reg1}, {reg2}, {shift}", "sub"); + T5Helper(&arm::Arm32Assembler::sub, false, "sub{cond}{s} {reg1}, {reg2}, {shift}", "sub"); } TEST_F(AssemblerArm32Test, Subs) { @@ -712,11 +793,15 @@ TEST_F(AssemblerArm32Test, Subs) { } TEST_F(AssemblerArm32Test, Sbc) { - T4Helper(&arm::Arm32Assembler::sbc, false, "sbc{cond} {reg1}, {reg2}, {shift}", "sbc"); + T5Helper(&arm::Arm32Assembler::sbc, false, "sbc{cond}{s} {reg1}, {reg2}, {shift}", "sbc"); +} + +TEST_F(AssemblerArm32Test, Sbcs) { + T4Helper(&arm::Arm32Assembler::sbcs, false, "sbc{cond}s {reg1}, {reg2}, {shift}", "sbcs"); } TEST_F(AssemblerArm32Test, Rsb) { - T4Helper(&arm::Arm32Assembler::rsb, true, "rsb{cond} {reg1}, {reg2}, {shift}", "rsb"); + T5Helper(&arm::Arm32Assembler::rsb, true, "rsb{cond}{s} {reg1}, {reg2}, {shift}", "rsb"); } TEST_F(AssemblerArm32Test, Rsbs) { @@ -724,7 +809,11 @@ TEST_F(AssemblerArm32Test, Rsbs) { } TEST_F(AssemblerArm32Test, Rsc) { - T4Helper(&arm::Arm32Assembler::rsc, true, "rsc{cond} {reg1}, {reg2}, {shift}", "rsc"); + T5Helper(&arm::Arm32Assembler::rsc, true, "rsc{cond}{s} {reg1}, {reg2}, {shift}", "rsc"); +} + +TEST_F(AssemblerArm32Test, Rscs) { + T4Helper(&arm::Arm32Assembler::rscs, false, "rsc{cond}s {reg1}, {reg2}, {shift}", "rscs"); } /* TODO: Need better filter support. diff --git a/compiler/utils/arm/assembler_arm_test.h b/compiler/utils/arm/assembler_arm_test.h index 838abb696d..a85a05e044 100644 --- a/compiler/utils/arm/assembler_arm_test.h +++ b/compiler/utils/arm/assembler_arm_test.h @@ -21,7 +21,13 @@ namespace art { -template<typename Ass, typename Reg, typename FPReg, typename Imm, typename SOp, typename Cond> +template<typename Ass, + typename Reg, + typename FPReg, + typename Imm, + typename SOp, + typename Cond, + typename SetCc> class AssemblerArmTest : public AssemblerTest<Ass, Reg, FPReg, Imm> { public: typedef AssemblerTest<Ass, Reg, FPReg, Imm> Base; @@ -94,7 +100,7 @@ class AssemblerArmTest : public AssemblerTest<Ass, Reg, FPReg, Imm> { size_t cond_index = after_cond.find(COND_TOKEN); if (cond_index != std::string::npos) { - after_cond.replace(cond_index, ConstexprStrLen(IMM1_TOKEN), GetConditionString(c)); + after_cond.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c)); } for (Imm i : immediates1) { @@ -185,7 +191,7 @@ class AssemblerArmTest : public AssemblerTest<Ass, Reg, FPReg, Imm> { size_t cond_index = after_cond.find(COND_TOKEN); if (cond_index != std::string::npos) { - after_cond.replace(cond_index, ConstexprStrLen(IMM1_TOKEN), GetConditionString(c)); + after_cond.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c)); } for (std::pair<Imm, Imm>& pair : immediates) { @@ -271,7 +277,7 @@ class AssemblerArmTest : public AssemblerTest<Ass, Reg, FPReg, Imm> { size_t cond_index = after_cond.find(COND_TOKEN); if (cond_index != std::string::npos) { - after_cond.replace(cond_index, ConstexprStrLen(IMM1_TOKEN), GetConditionString(c)); + after_cond.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c)); } for (auto reg1 : reg1_registers) { @@ -337,7 +343,7 @@ class AssemblerArmTest : public AssemblerTest<Ass, Reg, FPReg, Imm> { size_t cond_index = after_cond.find(COND_TOKEN); if (cond_index != std::string::npos) { - after_cond.replace(cond_index, ConstexprStrLen(IMM1_TOKEN), GetConditionString(c)); + after_cond.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c)); } for (auto reg1 : reg1_registers) { @@ -401,7 +407,7 @@ class AssemblerArmTest : public AssemblerTest<Ass, Reg, FPReg, Imm> { size_t cond_index = after_cond.find(COND_TOKEN); if (cond_index != std::string::npos) { - after_cond.replace(cond_index, ConstexprStrLen(IMM1_TOKEN), GetConditionString(c)); + after_cond.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c)); } for (const SOp& shift : shifts) { @@ -457,7 +463,7 @@ class AssemblerArmTest : public AssemblerTest<Ass, Reg, FPReg, Imm> { size_t cond_index = after_cond.find(COND_TOKEN); if (cond_index != std::string::npos) { - after_cond.replace(cond_index, ConstexprStrLen(IMM1_TOKEN), GetConditionString(c)); + after_cond.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c)); } for (const SOp& shift : shifts) { @@ -511,6 +517,9 @@ class AssemblerArmTest : public AssemblerTest<Ass, Reg, FPReg, Imm> { virtual std::vector<Cond>& GetConditions() = 0; virtual std::string GetConditionString(Cond c) = 0; + virtual std::vector<SetCc>& GetSetCcs() = 0; + virtual std::string GetSetCcString(SetCc s) = 0; + virtual std::vector<SOp>& GetShiftOperands() = 0; virtual std::string GetShiftString(SOp sop) = 0; @@ -534,6 +543,7 @@ class AssemblerArmTest : public AssemblerTest<Ass, Reg, FPReg, Imm> { static constexpr const char* REG3_TOKEN = "{reg3}"; static constexpr const char* REG4_TOKEN = "{reg4}"; static constexpr const char* COND_TOKEN = "{cond}"; + static constexpr const char* SET_CC_TOKEN = "{s}"; static constexpr const char* SHIFT_TOKEN = "{shift}"; private: diff --git a/compiler/utils/arm/assembler_thumb2.cc b/compiler/utils/arm/assembler_thumb2.cc index b499dddb0c..619ef6ee30 100644 --- a/compiler/utils/arm/assembler_thumb2.cc +++ b/compiler/utils/arm/assembler_thumb2.cc @@ -417,128 +417,96 @@ bool Thumb2Assembler::ShifterOperandCanHold(Register rd ATTRIBUTE_UNUSED, } void Thumb2Assembler::and_(Register rd, Register rn, const ShifterOperand& so, - Condition cond) { - EmitDataProcessing(cond, AND, 0, rn, rd, so); + Condition cond, SetCc set_cc) { + EmitDataProcessing(cond, AND, set_cc, rn, rd, so); } void Thumb2Assembler::eor(Register rd, Register rn, const ShifterOperand& so, - Condition cond) { - EmitDataProcessing(cond, EOR, 0, rn, rd, so); + Condition cond, SetCc set_cc) { + EmitDataProcessing(cond, EOR, set_cc, rn, rd, so); } void Thumb2Assembler::sub(Register rd, Register rn, const ShifterOperand& so, - Condition cond) { - EmitDataProcessing(cond, SUB, 0, rn, rd, so); + Condition cond, SetCc set_cc) { + EmitDataProcessing(cond, SUB, set_cc, rn, rd, so); } void Thumb2Assembler::rsb(Register rd, Register rn, const ShifterOperand& so, - Condition cond) { - EmitDataProcessing(cond, RSB, 0, rn, rd, so); -} - - -void Thumb2Assembler::rsbs(Register rd, Register rn, const ShifterOperand& so, - Condition cond) { - EmitDataProcessing(cond, RSB, 1, rn, rd, so); + Condition cond, SetCc set_cc) { + EmitDataProcessing(cond, RSB, set_cc, rn, rd, so); } void Thumb2Assembler::add(Register rd, Register rn, const ShifterOperand& so, - Condition cond) { - EmitDataProcessing(cond, ADD, 0, rn, rd, so); -} - - -void Thumb2Assembler::adds(Register rd, Register rn, const ShifterOperand& so, - Condition cond) { - EmitDataProcessing(cond, ADD, 1, rn, rd, so); -} - - -void Thumb2Assembler::subs(Register rd, Register rn, const ShifterOperand& so, - Condition cond) { - EmitDataProcessing(cond, SUB, 1, rn, rd, so); + Condition cond, SetCc set_cc) { + EmitDataProcessing(cond, ADD, set_cc, rn, rd, so); } void Thumb2Assembler::adc(Register rd, Register rn, const ShifterOperand& so, - Condition cond) { - EmitDataProcessing(cond, ADC, 0, rn, rd, so); + Condition cond, SetCc set_cc) { + EmitDataProcessing(cond, ADC, set_cc, rn, rd, so); } void Thumb2Assembler::sbc(Register rd, Register rn, const ShifterOperand& so, - Condition cond) { - EmitDataProcessing(cond, SBC, 0, rn, rd, so); + Condition cond, SetCc set_cc) { + EmitDataProcessing(cond, SBC, set_cc, rn, rd, so); } void Thumb2Assembler::rsc(Register rd, Register rn, const ShifterOperand& so, - Condition cond) { - EmitDataProcessing(cond, RSC, 0, rn, rd, so); + Condition cond, SetCc set_cc) { + EmitDataProcessing(cond, RSC, set_cc, rn, rd, so); } void Thumb2Assembler::tst(Register rn, const ShifterOperand& so, Condition cond) { CHECK_NE(rn, PC); // Reserve tst pc instruction for exception handler marker. - EmitDataProcessing(cond, TST, 1, rn, R0, so); + EmitDataProcessing(cond, TST, kCcSet, rn, R0, so); } void Thumb2Assembler::teq(Register rn, const ShifterOperand& so, Condition cond) { CHECK_NE(rn, PC); // Reserve teq pc instruction for exception handler marker. - EmitDataProcessing(cond, TEQ, 1, rn, R0, so); + EmitDataProcessing(cond, TEQ, kCcSet, rn, R0, so); } void Thumb2Assembler::cmp(Register rn, const ShifterOperand& so, Condition cond) { - EmitDataProcessing(cond, CMP, 1, rn, R0, so); + EmitDataProcessing(cond, CMP, kCcSet, rn, R0, so); } void Thumb2Assembler::cmn(Register rn, const ShifterOperand& so, Condition cond) { - EmitDataProcessing(cond, CMN, 1, rn, R0, so); + EmitDataProcessing(cond, CMN, kCcSet, rn, R0, so); } -void Thumb2Assembler::orr(Register rd, Register rn, - const ShifterOperand& so, Condition cond) { - EmitDataProcessing(cond, ORR, 0, rn, rd, so); +void Thumb2Assembler::orr(Register rd, Register rn, const ShifterOperand& so, + Condition cond, SetCc set_cc) { + EmitDataProcessing(cond, ORR, set_cc, rn, rd, so); } -void Thumb2Assembler::orrs(Register rd, Register rn, - const ShifterOperand& so, Condition cond) { - EmitDataProcessing(cond, ORR, 1, rn, rd, so); -} - - -void Thumb2Assembler::mov(Register rd, const ShifterOperand& so, Condition cond) { - EmitDataProcessing(cond, MOV, 0, R0, rd, so); -} - - -void Thumb2Assembler::movs(Register rd, const ShifterOperand& so, Condition cond) { - EmitDataProcessing(cond, MOV, 1, R0, rd, so); +void Thumb2Assembler::mov(Register rd, const ShifterOperand& so, + Condition cond, SetCc set_cc) { + EmitDataProcessing(cond, MOV, set_cc, R0, rd, so); } void Thumb2Assembler::bic(Register rd, Register rn, const ShifterOperand& so, - Condition cond) { - EmitDataProcessing(cond, BIC, 0, rn, rd, so); + Condition cond, SetCc set_cc) { + EmitDataProcessing(cond, BIC, set_cc, rn, rd, so); } -void Thumb2Assembler::mvn(Register rd, const ShifterOperand& so, Condition cond) { - EmitDataProcessing(cond, MVN, 0, R0, rd, so); -} - - -void Thumb2Assembler::mvns(Register rd, const ShifterOperand& so, Condition cond) { - EmitDataProcessing(cond, MVN, 1, R0, rd, so); +void Thumb2Assembler::mvn(Register rd, const ShifterOperand& so, + Condition cond, SetCc set_cc) { + EmitDataProcessing(cond, MVN, set_cc, R0, rd, so); } @@ -1054,7 +1022,7 @@ void Thumb2Assembler::blx(Label* label) { void Thumb2Assembler::MarkExceptionHandler(Label* label) { - EmitDataProcessing(AL, TST, 1, PC, R0, ShifterOperand(0)); + EmitDataProcessing(AL, TST, kCcSet, PC, R0, ShifterOperand(0)); Label l; b(&l); EmitBranch(AL, label, false, false); @@ -1075,9 +1043,9 @@ void Thumb2Assembler::Emit16(int16_t value) { } -bool Thumb2Assembler::Is32BitDataProcessing(Condition cond ATTRIBUTE_UNUSED, +bool Thumb2Assembler::Is32BitDataProcessing(Condition cond, Opcode opcode, - bool set_cc, + SetCc set_cc, Register rn, Register rd, const ShifterOperand& so) { @@ -1086,7 +1054,7 @@ bool Thumb2Assembler::Is32BitDataProcessing(Condition cond ATTRIBUTE_UNUSED, } // Check special case for SP relative ADD and SUB immediate. - if ((opcode == ADD || opcode == SUB) && rn == SP && so.IsImmediate()) { + if ((opcode == ADD || opcode == SUB) && rn == SP && so.IsImmediate() && set_cc != kCcSet) { // If the immediate is in range, use 16 bit. if (rd == SP) { if (so.GetImmediate() < (1 << 9)) { // 9 bit immediate. @@ -1099,8 +1067,10 @@ bool Thumb2Assembler::Is32BitDataProcessing(Condition cond ATTRIBUTE_UNUSED, } } - bool can_contain_high_register = (opcode == MOV) - || ((opcode == ADD) && (rn == rd) && !set_cc); + bool can_contain_high_register = + (opcode == CMP) || + (opcode == MOV && set_cc != kCcSet) || + ((opcode == ADD) && (rn == rd) && set_cc != kCcSet); if (IsHighRegister(rd) || IsHighRegister(rn)) { if (!can_contain_high_register) { @@ -1146,39 +1116,80 @@ bool Thumb2Assembler::Is32BitDataProcessing(Condition cond ATTRIBUTE_UNUSED, } if (so.IsImmediate()) { - if (rn_is_valid && rn != rd) { - // The only thumb1 instruction with a register and an immediate are ADD and SUB. The - // immediate must be 3 bits. - if (opcode != ADD && opcode != SUB) { + if (opcode == RSB) { + DCHECK(rn_is_valid); + if (so.GetImmediate() != 0u) { return true; - } else { - // Check that the immediate is 3 bits for ADD and SUB. - if (so.GetImmediate() >= 8) { + } + } else if (rn_is_valid && rn != rd) { + // The only thumb1 instructions with a register and an immediate are ADD and SUB + // with a 3-bit immediate, and RSB with zero immediate. + if (opcode == ADD || opcode == SUB) { + if (!IsUint<3>(so.GetImmediate())) { return true; } + } else { + return true; } } else { // ADD, SUB, CMP and MOV may be thumb1 only if the immediate is 8 bits. if (!(opcode == ADD || opcode == SUB || opcode == MOV || opcode == CMP)) { return true; } else { - if (so.GetImmediate() > 255) { + if (!IsUint<8>(so.GetImmediate())) { return true; } } } - } - - // Check for register shift operand. - if (so.IsRegister() && so.IsShift()) { - if (opcode != MOV) { - return true; - } - // Check for MOV with an ROR. - if (so.GetShift() == ROR) { - if (so.GetImmediate() != 0) { + } else { + DCHECK(so.IsRegister()); + if (so.IsShift()) { + // Shift operand - check if it is a MOV convertible to a 16-bit shift instruction. + if (opcode != MOV) { return true; } + // Check for MOV with an ROR/RRX. There is no 16-bit ROR immediate and no 16-bit RRX. + if (so.GetShift() == ROR || so.GetShift() == RRX) { + return true; + } + // 16-bit shifts set condition codes if and only if outside IT block, + // i.e. if and only if cond == AL. + if ((cond == AL) ? set_cc == kCcKeep : set_cc == kCcSet) { + return true; + } + } else { + // Register operand without shift. + switch (opcode) { + case ADD: + // The 16-bit ADD that cannot contain high registers can set condition codes + // if and only if outside IT block, i.e. if and only if cond == AL. + if (!can_contain_high_register && + ((cond == AL) ? set_cc == kCcKeep : set_cc == kCcSet)) { + return true; + } + break; + case AND: + case BIC: + case EOR: + case ORR: + case MVN: + case ADC: + case SUB: + case SBC: + // These 16-bit opcodes set condition codes if and only if outside IT block, + // i.e. if and only if cond == AL. + if ((cond == AL) ? set_cc == kCcKeep : set_cc == kCcSet) { + return true; + } + break; + case RSB: + case RSC: + // No 16-bit RSB/RSC Rd, Rm, Rn. It would be equivalent to SUB/SBC Rd, Rn, Rm. + return true; + case CMP: + default: + break; + } } } @@ -1189,7 +1200,7 @@ bool Thumb2Assembler::Is32BitDataProcessing(Condition cond ATTRIBUTE_UNUSED, void Thumb2Assembler::Emit32BitDataProcessing(Condition cond ATTRIBUTE_UNUSED, Opcode opcode, - bool set_cc, + SetCc set_cc, Register rn, Register rd, const ShifterOperand& so) { @@ -1203,10 +1214,10 @@ void Thumb2Assembler::Emit32BitDataProcessing(Condition cond ATTRIBUTE_UNUSED, case ADC: thumb_opcode = 10U /* 0b1010 */; break; case SBC: thumb_opcode = 11U /* 0b1011 */; break; case RSC: break; - case TST: thumb_opcode = 0U /* 0b0000 */; set_cc = true; rd = PC; break; - case TEQ: thumb_opcode = 4U /* 0b0100 */; set_cc = true; rd = PC; break; - case CMP: thumb_opcode = 13U /* 0b1101 */; set_cc = true; rd = PC; break; - case CMN: thumb_opcode = 8U /* 0b1000 */; set_cc = true; rd = PC; break; + case TST: thumb_opcode = 0U /* 0b0000 */; DCHECK(set_cc == kCcSet); rd = PC; break; + case TEQ: thumb_opcode = 4U /* 0b0100 */; DCHECK(set_cc == kCcSet); rd = PC; break; + case CMP: thumb_opcode = 13U /* 0b1101 */; DCHECK(set_cc == kCcSet); rd = PC; break; + case CMN: thumb_opcode = 8U /* 0b1000 */; DCHECK(set_cc == kCcSet); rd = PC; break; case ORR: thumb_opcode = 2U /* 0b0010 */; break; case MOV: thumb_opcode = 2U /* 0b0010 */; rn = PC; break; case BIC: thumb_opcode = 1U /* 0b0001 */; break; @@ -1224,7 +1235,7 @@ void Thumb2Assembler::Emit32BitDataProcessing(Condition cond ATTRIBUTE_UNUSED, if (so.IsImmediate()) { // Check special cases. if ((opcode == SUB || opcode == ADD) && (so.GetImmediate() < (1u << 12))) { - if (!set_cc) { + if (set_cc != kCcSet) { if (opcode == SUB) { thumb_opcode = 5U; } else if (opcode == ADD) { @@ -1238,7 +1249,7 @@ void Thumb2Assembler::Emit32BitDataProcessing(Condition cond ATTRIBUTE_UNUSED, uint32_t imm8 = imm & 0xff; encoding = B31 | B30 | B29 | B28 | - (set_cc ? B20 : B25) | + (set_cc == kCcSet ? B20 : B25) | thumb_opcode << 21 | rn << 16 | rd << 8 | @@ -1254,7 +1265,7 @@ void Thumb2Assembler::Emit32BitDataProcessing(Condition cond ATTRIBUTE_UNUSED, } encoding = B31 | B30 | B29 | B28 | thumb_opcode << 21 | - (set_cc ? B20 : 0) | + (set_cc == kCcSet ? B20 : 0) | rn << 16 | rd << 8 | imm; @@ -1263,7 +1274,7 @@ void Thumb2Assembler::Emit32BitDataProcessing(Condition cond ATTRIBUTE_UNUSED, // Register (possibly shifted) encoding = B31 | B30 | B29 | B27 | B25 | thumb_opcode << 21 | - (set_cc ? B20 : 0) | + (set_cc == kCcSet ? B20 : 0) | rn << 16 | rd << 8 | so.encodingThumb(); @@ -1274,7 +1285,7 @@ void Thumb2Assembler::Emit32BitDataProcessing(Condition cond ATTRIBUTE_UNUSED, void Thumb2Assembler::Emit16BitDataProcessing(Condition cond, Opcode opcode, - bool set_cc, + SetCc set_cc, Register rn, Register rd, const ShifterOperand& so) { @@ -1304,19 +1315,25 @@ void Thumb2Assembler::Emit16BitDataProcessing(Condition cond, rn = so.GetRegister(); switch (so.GetShift()) { - case LSL: thumb_opcode = 0U /* 0b00 */; break; - case LSR: thumb_opcode = 1U /* 0b01 */; break; - case ASR: thumb_opcode = 2U /* 0b10 */; break; - case ROR: - // ROR doesn't allow immediates. - thumb_opcode = 7U /* 0b111 */; - dp_opcode = 1U /* 0b01 */; - opcode_shift = 6; - use_immediate = false; + case LSL: + DCHECK_LE(immediate, 31u); + thumb_opcode = 0U /* 0b00 */; + break; + case LSR: + DCHECK(1 <= immediate && immediate <= 32); + immediate &= 31; // 32 is encoded as 0. + thumb_opcode = 1U /* 0b01 */; + break; + case ASR: + DCHECK(1 <= immediate && immediate <= 32); + immediate &= 31; // 32 is encoded as 0. + thumb_opcode = 2U /* 0b10 */; break; - case RRX: break; + case ROR: // No 16-bit ROR immediate. + case RRX: // No 16-bit RRX. default: - break; + LOG(FATAL) << "Unexpected shift: " << so.GetShift(); + UNREACHABLE(); } } else { if (so.IsImmediate()) { @@ -1334,6 +1351,9 @@ void Thumb2Assembler::Emit16BitDataProcessing(Condition cond, case ADC: case SBC: case BIC: { + // Sets condition codes if and only if outside IT block, + // check that it complies with set_cc. + DCHECK((cond == AL) ? set_cc != kCcKeep : set_cc != kCcSet); if (rn == rd) { rn = so.GetRegister(); } else { @@ -1348,9 +1368,17 @@ void Thumb2Assembler::Emit16BitDataProcessing(Condition cond, rn = so.GetRegister(); break; } - case TST: - case TEQ: case MVN: { + // Sets condition codes if and only if outside IT block, + // check that it complies with set_cc. + DCHECK((cond == AL) ? set_cc != kCcKeep : set_cc != kCcSet); + CHECK_EQ(rn, 0); + rn = so.GetRegister(); + break; + } + case TST: + case TEQ: { + DCHECK(set_cc == kCcSet); CHECK_EQ(rn, 0); rn = so.GetRegister(); break; @@ -1371,6 +1399,7 @@ void Thumb2Assembler::Emit16BitDataProcessing(Condition cond, case TST: thumb_opcode = 8U /* 0b1000 */; CHECK(!use_immediate); break; case MVN: thumb_opcode = 15U /* 0b1111 */; CHECK(!use_immediate); break; case CMP: { + DCHECK(set_cc == kCcSet); if (use_immediate) { // T2 encoding. dp_opcode = 0; @@ -1378,6 +1407,13 @@ void Thumb2Assembler::Emit16BitDataProcessing(Condition cond, thumb_opcode = 5U /* 0b101 */; rd_shift = 8; rn_shift = 8; + } else if (IsHighRegister(rd) || IsHighRegister(rn)) { + // Special cmp for high registers. + dp_opcode = 1U /* 0b01 */; + opcode_shift = 7; + // Put the top bit of rd into the bottom bit of the opcode. + thumb_opcode = 10U /* 0b0001010 */ | static_cast<uint32_t>(rd) >> 3; + rd = static_cast<Register>(static_cast<uint32_t>(rd) & 7U /* 0b111 */); } else { thumb_opcode = 10U /* 0b1010 */; } @@ -1399,7 +1435,7 @@ void Thumb2Assembler::Emit16BitDataProcessing(Condition cond, rn_shift = 8; } else { rn = so.GetRegister(); - if (IsHighRegister(rn) || IsHighRegister(rd)) { + if (set_cc != kCcSet) { // Special mov for high registers. dp_opcode = 1U /* 0b01 */; opcode_shift = 7; @@ -1407,6 +1443,8 @@ void Thumb2Assembler::Emit16BitDataProcessing(Condition cond, thumb_opcode = 12U /* 0b0001100 */ | static_cast<uint32_t>(rd) >> 3; rd = static_cast<Register>(static_cast<uint32_t>(rd) & 7U /* 0b111 */); } else { + DCHECK(!IsHighRegister(rn)); + DCHECK(!IsHighRegister(rd)); thumb_opcode = 0; } } @@ -1436,9 +1474,9 @@ void Thumb2Assembler::Emit16BitDataProcessing(Condition cond, // ADD and SUB are complex enough to warrant their own emitter. -void Thumb2Assembler::Emit16BitAddSub(Condition cond ATTRIBUTE_UNUSED, +void Thumb2Assembler::Emit16BitAddSub(Condition cond, Opcode opcode, - bool set_cc, + SetCc set_cc, Register rn, Register rd, const ShifterOperand& so) { @@ -1449,7 +1487,7 @@ void Thumb2Assembler::Emit16BitAddSub(Condition cond ATTRIBUTE_UNUSED, uint8_t immediate_shift = 0; bool use_immediate = false; uint32_t immediate = 0; // Should be at most 9 bits but keep the full immediate for CHECKs. - uint8_t thumb_opcode;; + uint8_t thumb_opcode; if (so.IsImmediate()) { use_immediate = true; @@ -1460,7 +1498,7 @@ void Thumb2Assembler::Emit16BitAddSub(Condition cond ATTRIBUTE_UNUSED, case ADD: if (so.IsRegister()) { Register rm = so.GetRegister(); - if (rn == rd && !set_cc) { + if (rn == rd && set_cc != kCcSet) { // Can use T2 encoding (allows 4 bit registers) dp_opcode = 1U /* 0b01 */; opcode_shift = 10; @@ -1471,6 +1509,12 @@ void Thumb2Assembler::Emit16BitAddSub(Condition cond ATTRIBUTE_UNUSED, rd = static_cast<Register>(static_cast<uint32_t>(rd) & 7U /* 0b111 */); } else { // T1. + DCHECK(!IsHighRegister(rd)); + DCHECK(!IsHighRegister(rn)); + DCHECK(!IsHighRegister(rm)); + // Sets condition codes if and only if outside IT block, + // check that it complies with set_cc. + DCHECK((cond == AL) ? set_cc != kCcKeep : set_cc != kCcSet); opcode_shift = 9; thumb_opcode = 12U /* 0b01100 */; immediate = static_cast<uint32_t>(so.GetRegister()); @@ -1523,40 +1567,47 @@ void Thumb2Assembler::Emit16BitAddSub(Condition cond ATTRIBUTE_UNUSED, case SUB: if (so.IsRegister()) { - // T1. - opcode_shift = 9; - thumb_opcode = 13U /* 0b01101 */; - immediate = static_cast<uint32_t>(so.GetRegister()); - use_immediate = true; - immediate_shift = 6; - } else { - if (rd == SP && rn == SP) { - // SUB sp, sp, #imm - dp_opcode = 2U /* 0b10 */; - thumb_opcode = 0x61 /* 0b1100001 */; - opcode_shift = 7; - CHECK_LT(immediate, (1u << 9)); - CHECK_ALIGNED(immediate, 4); - - // Remove rd and rn from instruction by orring it with immed and clearing bits. - rn = R0; - rd = R0; - rd_shift = 0; - rn_shift = 0; - immediate >>= 2; - } else if (rn != rd) { - // Must use T1. - opcode_shift = 9; - thumb_opcode = 15U /* 0b01111 */; - immediate_shift = 6; - } else { - // T2 encoding. - opcode_shift = 11; - thumb_opcode = 7U /* 0b111 */; - rd_shift = 8; - rn_shift = 8; - } - } + // T1. + Register rm = so.GetRegister(); + DCHECK(!IsHighRegister(rd)); + DCHECK(!IsHighRegister(rn)); + DCHECK(!IsHighRegister(rm)); + // Sets condition codes if and only if outside IT block, + // check that it complies with set_cc. + DCHECK((cond == AL) ? set_cc != kCcKeep : set_cc != kCcSet); + opcode_shift = 9; + thumb_opcode = 13U /* 0b01101 */; + immediate = static_cast<uint32_t>(rm); + use_immediate = true; + immediate_shift = 6; + } else { + if (rd == SP && rn == SP) { + // SUB sp, sp, #imm + dp_opcode = 2U /* 0b10 */; + thumb_opcode = 0x61 /* 0b1100001 */; + opcode_shift = 7; + CHECK_LT(immediate, (1u << 9)); + CHECK_ALIGNED(immediate, 4); + + // Remove rd and rn from instruction by orring it with immed and clearing bits. + rn = R0; + rd = R0; + rd_shift = 0; + rn_shift = 0; + immediate >>= 2; + } else if (rn != rd) { + // Must use T1. + opcode_shift = 9; + thumb_opcode = 15U /* 0b01111 */; + immediate_shift = 6; + } else { + // T2 encoding. + opcode_shift = 11; + thumb_opcode = 7U /* 0b111 */; + rd_shift = 8; + rn_shift = 8; + } + } break; default: LOG(FATAL) << "This opcode is not an ADD or SUB: " << opcode; @@ -1575,7 +1626,7 @@ void Thumb2Assembler::Emit16BitAddSub(Condition cond ATTRIBUTE_UNUSED, void Thumb2Assembler::EmitDataProcessing(Condition cond, Opcode opcode, - bool set_cc, + SetCc set_cc, Register rn, Register rd, const ShifterOperand& so) { @@ -1589,9 +1640,15 @@ void Thumb2Assembler::EmitDataProcessing(Condition cond, } } -void Thumb2Assembler::EmitShift(Register rd, Register rm, Shift shift, uint8_t amount, bool setcc) { +void Thumb2Assembler::EmitShift(Register rd, + Register rm, + Shift shift, + uint8_t amount, + Condition cond, + SetCc set_cc) { CHECK_LT(amount, (1 << 5)); - if (IsHighRegister(rd) || IsHighRegister(rm) || shift == ROR || shift == RRX) { + if ((IsHighRegister(rd) || IsHighRegister(rm) || shift == ROR || shift == RRX) || + ((cond == AL) ? set_cc == kCcKeep : set_cc == kCcSet)) { uint16_t opcode = 0; switch (shift) { case LSL: opcode = 0U /* 0b00 */; break; @@ -1605,7 +1662,7 @@ void Thumb2Assembler::EmitShift(Register rd, Register rm, Shift shift, uint8_t a } // 32 bit. int32_t encoding = B31 | B30 | B29 | B27 | B25 | B22 | - 0xf << 16 | (setcc ? B20 : 0); + 0xf << 16 | (set_cc == kCcSet ? B20 : 0); uint32_t imm3 = amount >> 2; uint32_t imm2 = amount & 3U /* 0b11 */; encoding |= imm3 << 12 | imm2 << 6 | static_cast<int16_t>(rm) | @@ -1628,10 +1685,16 @@ void Thumb2Assembler::EmitShift(Register rd, Register rm, Shift shift, uint8_t a } } -void Thumb2Assembler::EmitShift(Register rd, Register rn, Shift shift, Register rm, bool setcc) { +void Thumb2Assembler::EmitShift(Register rd, + Register rn, + Shift shift, + Register rm, + Condition cond, + SetCc set_cc) { CHECK_NE(shift, RRX); bool must_be_32bit = false; - if (IsHighRegister(rd) || IsHighRegister(rm) || IsHighRegister(rn) || rd != rn) { + if (IsHighRegister(rd) || IsHighRegister(rm) || IsHighRegister(rn) || rd != rn || + ((cond == AL) ? set_cc == kCcKeep : set_cc == kCcSet)) { must_be_32bit = true; } @@ -1648,7 +1711,7 @@ void Thumb2Assembler::EmitShift(Register rd, Register rn, Shift shift, Register } // 32 bit. int32_t encoding = B31 | B30 | B29 | B28 | B27 | B25 | - 0xf << 12 | (setcc ? B20 : 0); + 0xf << 12 | (set_cc == kCcSet ? B20 : 0); encoding |= static_cast<int16_t>(rn) << 16 | static_cast<int16_t>(rm) | static_cast<int16_t>(rd) << 8 | opcode << 21; Emit32(encoding); @@ -1658,6 +1721,7 @@ void Thumb2Assembler::EmitShift(Register rd, Register rn, Shift shift, Register case LSL: opcode = 2U /* 0b0010 */; break; case LSR: opcode = 3U /* 0b0011 */; break; case ASR: opcode = 4U /* 0b0100 */; break; + case ROR: opcode = 7U /* 0b0111 */; break; default: LOG(FATAL) << "Unsupported thumb2 shift opcode"; UNREACHABLE(); @@ -2915,70 +2979,70 @@ void Thumb2Assembler::Bind(Label* label) { void Thumb2Assembler::Lsl(Register rd, Register rm, uint32_t shift_imm, - bool setcc, Condition cond) { + Condition cond, SetCc set_cc) { CHECK_LE(shift_imm, 31u); CheckCondition(cond); - EmitShift(rd, rm, LSL, shift_imm, setcc); + EmitShift(rd, rm, LSL, shift_imm, cond, set_cc); } void Thumb2Assembler::Lsr(Register rd, Register rm, uint32_t shift_imm, - bool setcc, Condition cond) { + Condition cond, SetCc set_cc) { CHECK(1u <= shift_imm && shift_imm <= 32u); if (shift_imm == 32) shift_imm = 0; // Comply to UAL syntax. CheckCondition(cond); - EmitShift(rd, rm, LSR, shift_imm, setcc); + EmitShift(rd, rm, LSR, shift_imm, cond, set_cc); } void Thumb2Assembler::Asr(Register rd, Register rm, uint32_t shift_imm, - bool setcc, Condition cond) { + Condition cond, SetCc set_cc) { CHECK(1u <= shift_imm && shift_imm <= 32u); if (shift_imm == 32) shift_imm = 0; // Comply to UAL syntax. CheckCondition(cond); - EmitShift(rd, rm, ASR, shift_imm, setcc); + EmitShift(rd, rm, ASR, shift_imm, cond, set_cc); } void Thumb2Assembler::Ror(Register rd, Register rm, uint32_t shift_imm, - bool setcc, Condition cond) { + Condition cond, SetCc set_cc) { CHECK(1u <= shift_imm && shift_imm <= 31u); CheckCondition(cond); - EmitShift(rd, rm, ROR, shift_imm, setcc); + EmitShift(rd, rm, ROR, shift_imm, cond, set_cc); } -void Thumb2Assembler::Rrx(Register rd, Register rm, bool setcc, Condition cond) { +void Thumb2Assembler::Rrx(Register rd, Register rm, Condition cond, SetCc set_cc) { CheckCondition(cond); - EmitShift(rd, rm, RRX, rm, setcc); + EmitShift(rd, rm, RRX, rm, cond, set_cc); } void Thumb2Assembler::Lsl(Register rd, Register rm, Register rn, - bool setcc, Condition cond) { + Condition cond, SetCc set_cc) { CheckCondition(cond); - EmitShift(rd, rm, LSL, rn, setcc); + EmitShift(rd, rm, LSL, rn, cond, set_cc); } void Thumb2Assembler::Lsr(Register rd, Register rm, Register rn, - bool setcc, Condition cond) { + Condition cond, SetCc set_cc) { CheckCondition(cond); - EmitShift(rd, rm, LSR, rn, setcc); + EmitShift(rd, rm, LSR, rn, cond, set_cc); } void Thumb2Assembler::Asr(Register rd, Register rm, Register rn, - bool setcc, Condition cond) { + Condition cond, SetCc set_cc) { CheckCondition(cond); - EmitShift(rd, rm, ASR, rn, setcc); + EmitShift(rd, rm, ASR, rn, cond, set_cc); } void Thumb2Assembler::Ror(Register rd, Register rm, Register rn, - bool setcc, Condition cond) { + Condition cond, SetCc set_cc) { CheckCondition(cond); - EmitShift(rd, rm, ROR, rn, setcc); + EmitShift(rd, rm, ROR, rn, cond, set_cc); } @@ -3173,24 +3237,24 @@ void Thumb2Assembler::AddConstantSetFlags(Register rd, Register rn, int32_t valu Condition cond) { ShifterOperand shifter_op; if (ShifterOperandCanHold(rd, rn, ADD, value, &shifter_op)) { - adds(rd, rn, shifter_op, cond); + add(rd, rn, shifter_op, cond, kCcSet); } else if (ShifterOperandCanHold(rd, rn, ADD, -value, &shifter_op)) { - subs(rd, rn, shifter_op, cond); + sub(rd, rn, shifter_op, cond, kCcSet); } else { CHECK(rn != IP); if (ShifterOperandCanHold(rd, rn, MVN, ~value, &shifter_op)) { mvn(IP, shifter_op, cond); - adds(rd, rn, ShifterOperand(IP), cond); + add(rd, rn, ShifterOperand(IP), cond, kCcSet); } else if (ShifterOperandCanHold(rd, rn, MVN, ~(-value), &shifter_op)) { mvn(IP, shifter_op, cond); - subs(rd, rn, ShifterOperand(IP), cond); + sub(rd, rn, ShifterOperand(IP), cond, kCcSet); } else { movw(IP, Low16Bits(value), cond); uint16_t value_high = High16Bits(value); if (value_high != 0) { movt(IP, value_high, cond); } - adds(rd, rn, ShifterOperand(IP), cond); + add(rd, rn, ShifterOperand(IP), cond, kCcSet); } } } @@ -3316,7 +3380,7 @@ void Thumb2Assembler::StoreToOffset(StoreOperandType type, } } LoadImmediate(tmp_reg, offset, cond); - add(tmp_reg, tmp_reg, ShifterOperand(base), cond); + add(tmp_reg, tmp_reg, ShifterOperand(base), AL); base = tmp_reg; offset = 0; } diff --git a/compiler/utils/arm/assembler_thumb2.h b/compiler/utils/arm/assembler_thumb2.h index 41eb5d36f2..c802c27ea6 100644 --- a/compiler/utils/arm/assembler_thumb2.h +++ b/compiler/utils/arm/assembler_thumb2.h @@ -63,25 +63,29 @@ class Thumb2Assembler FINAL : public ArmAssembler { void FinalizeCode() OVERRIDE; // Data-processing instructions. - void and_(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + virtual void and_(Register rd, Register rn, const ShifterOperand& so, + Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE; - void eor(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + virtual void eor(Register rd, Register rn, const ShifterOperand& so, + Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE; - void sub(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; - void subs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + virtual void sub(Register rd, Register rn, const ShifterOperand& so, + Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE; - void rsb(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; - void rsbs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + virtual void rsb(Register rd, Register rn, const ShifterOperand& so, + Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE; - void add(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + virtual void add(Register rd, Register rn, const ShifterOperand& so, + Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE; - void adds(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + virtual void adc(Register rd, Register rn, const ShifterOperand& so, + Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE; - void adc(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + virtual void sbc(Register rd, Register rn, const ShifterOperand& so, + Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE; - void sbc(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; - - void rsc(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + virtual void rsc(Register rd, Register rn, const ShifterOperand& so, + Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE; void tst(Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; @@ -91,16 +95,17 @@ class Thumb2Assembler FINAL : public ArmAssembler { void cmn(Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; - void orr(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; - void orrs(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + virtual void orr(Register rd, Register rn, const ShifterOperand& so, + Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE; - void mov(Register rd, const ShifterOperand& so, Condition cond = AL) OVERRIDE; - void movs(Register rd, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + virtual void mov(Register rd, const ShifterOperand& so, + Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE; - void bic(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + virtual void bic(Register rd, Register rn, const ShifterOperand& so, + Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE; - void mvn(Register rd, const ShifterOperand& so, Condition cond = AL) OVERRIDE; - void mvns(Register rd, const ShifterOperand& so, Condition cond = AL) OVERRIDE; + virtual void mvn(Register rd, const ShifterOperand& so, + Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE; // Miscellaneous data-processing instructions. void clz(Register rd, Register rm, Condition cond = AL) OVERRIDE; @@ -245,25 +250,25 @@ class Thumb2Assembler FINAL : public ArmAssembler { void blx(Register rm, Condition cond = AL) OVERRIDE; void bx(Register rm, Condition cond = AL) OVERRIDE; - void Lsl(Register rd, Register rm, uint32_t shift_imm, bool setcc = false, - Condition cond = AL) OVERRIDE; - void Lsr(Register rd, Register rm, uint32_t shift_imm, bool setcc = false, - Condition cond = AL) OVERRIDE; - void Asr(Register rd, Register rm, uint32_t shift_imm, bool setcc = false, - Condition cond = AL) OVERRIDE; - void Ror(Register rd, Register rm, uint32_t shift_imm, bool setcc = false, - Condition cond = AL) OVERRIDE; - void Rrx(Register rd, Register rm, bool setcc = false, - Condition cond = AL) OVERRIDE; - - void Lsl(Register rd, Register rm, Register rn, bool setcc = false, - Condition cond = AL) OVERRIDE; - void Lsr(Register rd, Register rm, Register rn, bool setcc = false, - Condition cond = AL) OVERRIDE; - void Asr(Register rd, Register rm, Register rn, bool setcc = false, - Condition cond = AL) OVERRIDE; - void Ror(Register rd, Register rm, Register rn, bool setcc = false, - Condition cond = AL) OVERRIDE; + virtual void Lsl(Register rd, Register rm, uint32_t shift_imm, + Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE; + virtual void Lsr(Register rd, Register rm, uint32_t shift_imm, + Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE; + virtual void Asr(Register rd, Register rm, uint32_t shift_imm, + Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE; + virtual void Ror(Register rd, Register rm, uint32_t shift_imm, + Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE; + virtual void Rrx(Register rd, Register rm, + Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE; + + virtual void Lsl(Register rd, Register rm, Register rn, + Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE; + virtual void Lsr(Register rd, Register rm, Register rn, + Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE; + virtual void Asr(Register rd, Register rm, Register rn, + Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE; + virtual void Ror(Register rd, Register rm, Register rn, + Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE; void Push(Register rd, Condition cond = AL) OVERRIDE; void Pop(Register rd, Condition cond = AL) OVERRIDE; @@ -600,7 +605,7 @@ class Thumb2Assembler FINAL : public ArmAssembler { // Emit a single 32 or 16 bit data processing instruction. void EmitDataProcessing(Condition cond, Opcode opcode, - bool set_cc, + SetCc set_cc, Register rn, Register rd, const ShifterOperand& so); @@ -609,7 +614,7 @@ class Thumb2Assembler FINAL : public ArmAssembler { // in 16 bits? bool Is32BitDataProcessing(Condition cond, Opcode opcode, - bool set_cc, + SetCc set_cc, Register rn, Register rd, const ShifterOperand& so); @@ -617,7 +622,7 @@ class Thumb2Assembler FINAL : public ArmAssembler { // Emit a 32 bit data processing instruction. void Emit32BitDataProcessing(Condition cond, Opcode opcode, - bool set_cc, + SetCc set_cc, Register rn, Register rd, const ShifterOperand& so); @@ -625,14 +630,14 @@ class Thumb2Assembler FINAL : public ArmAssembler { // Emit a 16 bit data processing instruction. void Emit16BitDataProcessing(Condition cond, Opcode opcode, - bool set_cc, + SetCc set_cc, Register rn, Register rd, const ShifterOperand& so); void Emit16BitAddSub(Condition cond, Opcode opcode, - bool set_cc, + SetCc set_cc, Register rn, Register rd, const ShifterOperand& so); @@ -694,8 +699,10 @@ class Thumb2Assembler FINAL : public ArmAssembler { static int DecodeBranchOffset(int32_t inst); int32_t EncodeTstOffset(int offset, int32_t inst); int DecodeTstOffset(int32_t inst); - void EmitShift(Register rd, Register rm, Shift shift, uint8_t amount, bool setcc = false); - void EmitShift(Register rd, Register rn, Shift shift, Register rm, bool setcc = false); + void EmitShift(Register rd, Register rm, Shift shift, uint8_t amount, + Condition cond = AL, SetCc set_cc = kCcDontCare); + void EmitShift(Register rd, Register rn, Shift shift, Register rm, + Condition cond = AL, SetCc set_cc = kCcDontCare); // Whether the assembler can relocate branches. If false, unresolved branches will be // emitted on 32bits. diff --git a/compiler/utils/assembler_thumb_test.cc b/compiler/utils/assembler_thumb_test.cc index cb01cea8ef..b2a354b63c 100644 --- a/compiler/utils/assembler_thumb_test.cc +++ b/compiler/utils/assembler_thumb_test.cc @@ -199,6 +199,7 @@ void EmitAndCheck(arm::Thumb2Assembler* assembler, const char* testname) { TEST(Thumb2AssemblerTest, SimpleMov) { arm::Thumb2Assembler assembler; + __ movs(R0, ShifterOperand(R1)); __ mov(R0, ShifterOperand(R1)); __ mov(R8, ShifterOperand(R9)); @@ -222,8 +223,8 @@ TEST(Thumb2AssemblerTest, SimpleMovAdd) { arm::Thumb2Assembler assembler; __ mov(R0, ShifterOperand(R1)); - __ add(R0, R1, ShifterOperand(R2)); - __ add(R0, R1, ShifterOperand()); + __ adds(R0, R1, ShifterOperand(R2)); + __ add(R0, R1, ShifterOperand(0)); EmitAndCheck(&assembler, "SimpleMovAdd"); } @@ -231,41 +232,132 @@ TEST(Thumb2AssemblerTest, SimpleMovAdd) { TEST(Thumb2AssemblerTest, DataProcessingRegister) { arm::Thumb2Assembler assembler; + // 32 bit variants using low registers. + __ mvn(R0, ShifterOperand(R1), AL, kCcKeep); + __ add(R0, R1, ShifterOperand(R2), AL, kCcKeep); + __ sub(R0, R1, ShifterOperand(R2), AL, kCcKeep); + __ and_(R0, R1, ShifterOperand(R2), AL, kCcKeep); + __ orr(R0, R1, ShifterOperand(R2), AL, kCcKeep); + __ eor(R0, R1, ShifterOperand(R2), AL, kCcKeep); + __ bic(R0, R1, ShifterOperand(R2), AL, kCcKeep); + __ adc(R0, R1, ShifterOperand(R2), AL, kCcKeep); + __ sbc(R0, R1, ShifterOperand(R2), AL, kCcKeep); + __ rsb(R0, R1, ShifterOperand(R2), AL, kCcKeep); + __ teq(R0, ShifterOperand(R1)); + + // 16 bit variants using low registers. + __ movs(R0, ShifterOperand(R1)); + __ mov(R0, ShifterOperand(R1), AL, kCcKeep); + __ mvns(R0, ShifterOperand(R1)); + __ add(R0, R0, ShifterOperand(R1), AL, kCcKeep); + __ adds(R0, R1, ShifterOperand(R2)); + __ subs(R0, R1, ShifterOperand(R2)); + __ adcs(R0, R0, ShifterOperand(R1)); + __ sbcs(R0, R0, ShifterOperand(R1)); + __ ands(R0, R0, ShifterOperand(R1)); + __ orrs(R0, R0, ShifterOperand(R1)); + __ eors(R0, R0, ShifterOperand(R1)); + __ bics(R0, R0, ShifterOperand(R1)); + __ tst(R0, ShifterOperand(R1)); + __ cmp(R0, ShifterOperand(R1)); + __ cmn(R0, ShifterOperand(R1)); + + // 16-bit variants using high registers. + __ mov(R1, ShifterOperand(R8), AL, kCcKeep); + __ mov(R9, ShifterOperand(R0), AL, kCcKeep); + __ mov(R8, ShifterOperand(R9), AL, kCcKeep); + __ add(R1, R1, ShifterOperand(R8), AL, kCcKeep); + __ add(R9, R9, ShifterOperand(R0), AL, kCcKeep); + __ add(R8, R8, ShifterOperand(R9), AL, kCcKeep); + __ cmp(R0, ShifterOperand(R9)); + __ cmp(R8, ShifterOperand(R1)); + __ cmp(R9, ShifterOperand(R8)); + + // The 16-bit RSBS Rd, Rn, #0, also known as NEGS Rd, Rn is specified using + // an immediate (0) but emitted without any, so we test it here. + __ rsbs(R0, R1, ShifterOperand(0)); + __ rsbs(R0, R0, ShifterOperand(0)); // Check Rd == Rn code path. + + // 32 bit variants using high registers that would be 16-bit if using low registers. + __ movs(R0, ShifterOperand(R8)); + __ mvns(R0, ShifterOperand(R8)); + __ add(R0, R1, ShifterOperand(R8), AL, kCcKeep); + __ adds(R0, R1, ShifterOperand(R8)); + __ subs(R0, R1, ShifterOperand(R8)); + __ adcs(R0, R0, ShifterOperand(R8)); + __ sbcs(R0, R0, ShifterOperand(R8)); + __ ands(R0, R0, ShifterOperand(R8)); + __ orrs(R0, R0, ShifterOperand(R8)); + __ eors(R0, R0, ShifterOperand(R8)); + __ bics(R0, R0, ShifterOperand(R8)); + __ tst(R0, ShifterOperand(R8)); + __ cmn(R0, ShifterOperand(R8)); + __ rsbs(R0, R8, ShifterOperand(0)); // Check that this is not emitted as 16-bit. + __ rsbs(R8, R8, ShifterOperand(0)); // Check that this is not emitted as 16-bit (Rd == Rn). + + // 32-bit variants of instructions that would be 16-bit outside IT block. + __ it(arm::EQ); + __ mvns(R0, ShifterOperand(R1), arm::EQ); + __ it(arm::EQ); + __ adds(R0, R1, ShifterOperand(R2), arm::EQ); + __ it(arm::EQ); + __ subs(R0, R1, ShifterOperand(R2), arm::EQ); + __ it(arm::EQ); + __ adcs(R0, R0, ShifterOperand(R1), arm::EQ); + __ it(arm::EQ); + __ sbcs(R0, R0, ShifterOperand(R1), arm::EQ); + __ it(arm::EQ); + __ ands(R0, R0, ShifterOperand(R1), arm::EQ); + __ it(arm::EQ); + __ orrs(R0, R0, ShifterOperand(R1), arm::EQ); + __ it(arm::EQ); + __ eors(R0, R0, ShifterOperand(R1), arm::EQ); + __ it(arm::EQ); + __ bics(R0, R0, ShifterOperand(R1), arm::EQ); + + // 16-bit variants of instructions that would be 32-bit outside IT block. + __ it(arm::EQ); + __ mvn(R0, ShifterOperand(R1), arm::EQ, kCcKeep); + __ it(arm::EQ); + __ add(R0, R1, ShifterOperand(R2), arm::EQ, kCcKeep); + __ it(arm::EQ); + __ sub(R0, R1, ShifterOperand(R2), arm::EQ, kCcKeep); + __ it(arm::EQ); + __ adc(R0, R0, ShifterOperand(R1), arm::EQ, kCcKeep); + __ it(arm::EQ); + __ sbc(R0, R0, ShifterOperand(R1), arm::EQ, kCcKeep); + __ it(arm::EQ); + __ and_(R0, R0, ShifterOperand(R1), arm::EQ, kCcKeep); + __ it(arm::EQ); + __ orr(R0, R0, ShifterOperand(R1), arm::EQ, kCcKeep); + __ it(arm::EQ); + __ eor(R0, R0, ShifterOperand(R1), arm::EQ, kCcKeep); + __ it(arm::EQ); + __ bic(R0, R0, ShifterOperand(R1), arm::EQ, kCcKeep); + + // 16 bit variants selected for the default kCcDontCare. __ mov(R0, ShifterOperand(R1)); __ mvn(R0, ShifterOperand(R1)); - - // 32 bit variants. + __ add(R0, R0, ShifterOperand(R1)); __ add(R0, R1, ShifterOperand(R2)); __ sub(R0, R1, ShifterOperand(R2)); - __ and_(R0, R1, ShifterOperand(R2)); - __ orr(R0, R1, ShifterOperand(R2)); - __ eor(R0, R1, ShifterOperand(R2)); - __ bic(R0, R1, ShifterOperand(R2)); - __ adc(R0, R1, ShifterOperand(R2)); - __ sbc(R0, R1, ShifterOperand(R2)); - __ rsb(R0, R1, ShifterOperand(R2)); - - // 16 bit variants. - __ add(R0, R1, ShifterOperand()); - __ sub(R0, R1, ShifterOperand()); + __ adc(R0, R0, ShifterOperand(R1)); + __ sbc(R0, R0, ShifterOperand(R1)); __ and_(R0, R0, ShifterOperand(R1)); __ orr(R0, R0, ShifterOperand(R1)); __ eor(R0, R0, ShifterOperand(R1)); __ bic(R0, R0, ShifterOperand(R1)); - __ adc(R0, R0, ShifterOperand(R1)); - __ sbc(R0, R0, ShifterOperand(R1)); - __ rsb(R0, R0, ShifterOperand(R1)); - - __ tst(R0, ShifterOperand(R1)); - __ teq(R0, ShifterOperand(R1)); - __ cmp(R0, ShifterOperand(R1)); - __ cmn(R0, ShifterOperand(R1)); - - __ movs(R0, ShifterOperand(R1)); - __ mvns(R0, ShifterOperand(R1)); + __ mov(R1, ShifterOperand(R8)); + __ mov(R9, ShifterOperand(R0)); + __ mov(R8, ShifterOperand(R9)); + __ add(R1, R1, ShifterOperand(R8)); + __ add(R9, R9, ShifterOperand(R0)); + __ add(R8, R8, ShifterOperand(R9)); + __ rsb(R0, R1, ShifterOperand(0)); + __ rsb(R0, R0, ShifterOperand(0)); - // 32 bit variants. - __ add(R12, R1, ShifterOperand(R0)); + // And an arbitrary 32-bit instruction using IP. + __ add(R12, R1, ShifterOperand(R0), AL, kCcKeep); EmitAndCheck(&assembler, "DataProcessingRegister"); } @@ -296,6 +388,9 @@ TEST(Thumb2AssemblerTest, DataProcessingImmediate) { __ movs(R0, ShifterOperand(0x55)); __ mvns(R0, ShifterOperand(0x55)); + __ adds(R0, R1, ShifterOperand(5)); + __ subs(R0, R1, ShifterOperand(5)); + EmitAndCheck(&assembler, "DataProcessingImmediate"); } @@ -340,18 +435,30 @@ TEST(Thumb2AssemblerTest, DataProcessingModifiedImmediates) { TEST(Thumb2AssemblerTest, DataProcessingShiftedRegister) { arm::Thumb2Assembler assembler; - __ mov(R3, ShifterOperand(R4, LSL, 4)); - __ mov(R3, ShifterOperand(R4, LSR, 5)); - __ mov(R3, ShifterOperand(R4, ASR, 6)); - __ mov(R3, ShifterOperand(R4, ROR, 7)); - __ mov(R3, ShifterOperand(R4, ROR)); + // 16-bit variants. + __ movs(R3, ShifterOperand(R4, LSL, 4)); + __ movs(R3, ShifterOperand(R4, LSR, 5)); + __ movs(R3, ShifterOperand(R4, ASR, 6)); - // 32 bit variants. - __ mov(R8, ShifterOperand(R4, LSL, 4)); - __ mov(R8, ShifterOperand(R4, LSR, 5)); - __ mov(R8, ShifterOperand(R4, ASR, 6)); - __ mov(R8, ShifterOperand(R4, ROR, 7)); - __ mov(R8, ShifterOperand(R4, RRX)); + // 32-bit ROR because ROR immediate doesn't have the same 16-bit version as other shifts. + __ movs(R3, ShifterOperand(R4, ROR, 7)); + + // 32-bit RRX because RRX has no 16-bit version. + __ movs(R3, ShifterOperand(R4, RRX)); + + // 32 bit variants (not setting condition codes). + __ mov(R3, ShifterOperand(R4, LSL, 4), AL, kCcKeep); + __ mov(R3, ShifterOperand(R4, LSR, 5), AL, kCcKeep); + __ mov(R3, ShifterOperand(R4, ASR, 6), AL, kCcKeep); + __ mov(R3, ShifterOperand(R4, ROR, 7), AL, kCcKeep); + __ mov(R3, ShifterOperand(R4, RRX), AL, kCcKeep); + + // 32 bit variants (high registers). + __ movs(R8, ShifterOperand(R4, LSL, 4)); + __ movs(R8, ShifterOperand(R4, LSR, 5)); + __ movs(R8, ShifterOperand(R4, ASR, 6)); + __ movs(R8, ShifterOperand(R4, ROR, 7)); + __ movs(R8, ShifterOperand(R4, RRX)); EmitAndCheck(&assembler, "DataProcessingShiftedRegister"); } @@ -1023,7 +1130,7 @@ TEST(Thumb2AssemblerTest, MixedBranch32) { TEST(Thumb2AssemblerTest, Shifts) { arm::Thumb2Assembler assembler; - // 16 bit + // 16 bit selected for CcDontCare. __ Lsl(R0, R1, 5); __ Lsr(R0, R1, 5); __ Asr(R0, R1, 5); @@ -1031,6 +1138,32 @@ TEST(Thumb2AssemblerTest, Shifts) { __ Lsl(R0, R0, R1); __ Lsr(R0, R0, R1); __ Asr(R0, R0, R1); + __ Ror(R0, R0, R1); + + // 16 bit with kCcSet. + __ Lsls(R0, R1, 5); + __ Lsrs(R0, R1, 5); + __ Asrs(R0, R1, 5); + + __ Lsls(R0, R0, R1); + __ Lsrs(R0, R0, R1); + __ Asrs(R0, R0, R1); + __ Rors(R0, R0, R1); + + // 32-bit with kCcKeep. + __ Lsl(R0, R1, 5, AL, kCcKeep); + __ Lsr(R0, R1, 5, AL, kCcKeep); + __ Asr(R0, R1, 5, AL, kCcKeep); + + __ Lsl(R0, R0, R1, AL, kCcKeep); + __ Lsr(R0, R0, R1, AL, kCcKeep); + __ Asr(R0, R0, R1, AL, kCcKeep); + __ Ror(R0, R0, R1, AL, kCcKeep); + + // 32-bit because ROR immediate doesn't have a 16-bit version like the other shifts. + __ Ror(R0, R1, 5); + __ Rors(R0, R1, 5); + __ Ror(R0, R1, 5, AL, kCcKeep); // 32 bit due to high registers. __ Lsl(R8, R1, 5); @@ -1052,21 +1185,21 @@ TEST(Thumb2AssemblerTest, Shifts) { // S bit (all 32 bit) // 32 bit due to high registers. - __ Lsl(R8, R1, 5, true); - __ Lsr(R0, R8, 5, true); - __ Asr(R8, R1, 5, true); - __ Ror(R0, R8, 5, true); + __ Lsls(R8, R1, 5); + __ Lsrs(R0, R8, 5); + __ Asrs(R8, R1, 5); + __ Rors(R0, R8, 5); // 32 bit due to different Rd and Rn. - __ Lsl(R0, R1, R2, true); - __ Lsr(R0, R1, R2, true); - __ Asr(R0, R1, R2, true); - __ Ror(R0, R1, R2, true); + __ Lsls(R0, R1, R2); + __ Lsrs(R0, R1, R2); + __ Asrs(R0, R1, R2); + __ Rors(R0, R1, R2); // 32 bit due to use of high registers. - __ Lsl(R8, R1, R2, true); - __ Lsr(R0, R8, R2, true); - __ Asr(R0, R1, R8, true); + __ Lsls(R8, R1, R2); + __ Lsrs(R0, R8, R2); + __ Asrs(R0, R1, R8); EmitAndCheck(&assembler, "Shifts"); } diff --git a/compiler/utils/assembler_thumb_test_expected.cc.inc b/compiler/utils/assembler_thumb_test_expected.cc.inc index 280ed779b3..82ad6429bf 100644 --- a/compiler/utils/assembler_thumb_test_expected.cc.inc +++ b/compiler/utils/assembler_thumb_test_expected.cc.inc @@ -1,8 +1,9 @@ const char* SimpleMovResults[] = { " 0: 0008 movs r0, r1\n", - " 2: 46c8 mov r8, r9\n", - " 4: 2001 movs r0, #1\n", - " 6: f04f 0809 mov.w r8, #9\n", + " 2: 4608 mov r0, r1\n", + " 4: 46c8 mov r8, r9\n", + " 6: 2001 movs r0, #1\n", + " 8: f04f 0809 mov.w r8, #9\n", nullptr }; const char* SimpleMov32Results[] = { @@ -11,39 +12,120 @@ const char* SimpleMov32Results[] = { nullptr }; const char* SimpleMovAddResults[] = { - " 0: 0008 movs r0, r1\n", + " 0: 4608 mov r0, r1\n", " 2: 1888 adds r0, r1, r2\n", " 4: 1c08 adds r0, r1, #0\n", nullptr }; const char* DataProcessingRegisterResults[] = { - " 0: 0008 movs r0, r1\n", - " 2: 43c8 mvns r0, r1\n", - " 4: 1888 adds r0, r1, r2\n", - " 6: 1a88 subs r0, r1, r2\n", - " 8: ea01 0002 and.w r0, r1, r2\n", - " c: ea41 0002 orr.w r0, r1, r2\n", - " 10: ea81 0002 eor.w r0, r1, r2\n", - " 14: ea21 0002 bic.w r0, r1, r2\n", - " 18: eb41 0002 adc.w r0, r1, r2\n", - " 1c: eb61 0002 sbc.w r0, r1, r2\n", - " 20: ebc1 0002 rsb r0, r1, r2\n", - " 24: 1c08 adds r0, r1, #0\n", - " 26: 1e08 subs r0, r1, #0\n", - " 28: 4008 ands r0, r1\n", - " 2a: 4308 orrs r0, r1\n", - " 2c: 4048 eors r0, r1\n", - " 2e: 4388 bics r0, r1\n", - " 30: 4148 adcs r0, r1\n", - " 32: 4188 sbcs r0, r1\n", - " 34: 4248 negs r0, r1\n", - " 36: 4208 tst r0, r1\n", - " 38: ea90 0f01 teq r0, r1\n", - " 3c: 4288 cmp r0, r1\n", - " 3e: 42c8 cmn r0, r1\n", - " 40: 0008 movs r0, r1\n", - " 42: 43c8 mvns r0, r1\n", - " 44: eb01 0c00 add.w ip, r1, r0\n", + " 0: ea6f 0001 mvn.w r0, r1\n", + " 4: eb01 0002 add.w r0, r1, r2\n", + " 8: eba1 0002 sub.w r0, r1, r2\n", + " c: ea01 0002 and.w r0, r1, r2\n", + " 10: ea41 0002 orr.w r0, r1, r2\n", + " 14: ea81 0002 eor.w r0, r1, r2\n", + " 18: ea21 0002 bic.w r0, r1, r2\n", + " 1c: eb41 0002 adc.w r0, r1, r2\n", + " 20: eb61 0002 sbc.w r0, r1, r2\n", + " 24: ebc1 0002 rsb r0, r1, r2\n", + " 28: ea90 0f01 teq r0, r1\n", + " 2c: 0008 movs r0, r1\n", + " 2e: 4608 mov r0, r1\n", + " 30: 43c8 mvns r0, r1\n", + " 32: 4408 add r0, r1\n", + " 34: 1888 adds r0, r1, r2\n", + " 36: 1a88 subs r0, r1, r2\n", + " 38: 4148 adcs r0, r1\n", + " 3a: 4188 sbcs r0, r1\n", + " 3c: 4008 ands r0, r1\n", + " 3e: 4308 orrs r0, r1\n", + " 40: 4048 eors r0, r1\n", + " 42: 4388 bics r0, r1\n", + " 44: 4208 tst r0, r1\n", + " 46: 4288 cmp r0, r1\n", + " 48: 42c8 cmn r0, r1\n", + " 4a: 4641 mov r1, r8\n", + " 4c: 4681 mov r9, r0\n", + " 4e: 46c8 mov r8, r9\n", + " 50: 4441 add r1, r8\n", + " 52: 4481 add r9, r0\n", + " 54: 44c8 add r8, r9\n", + " 56: 4548 cmp r0, r9\n", + " 58: 4588 cmp r8, r1\n", + " 5a: 45c1 cmp r9, r8\n", + " 5c: 4248 negs r0, r1\n", + " 5e: 4240 negs r0, r0\n", + " 60: ea5f 0008 movs.w r0, r8\n", + " 64: ea7f 0008 mvns.w r0, r8\n", + " 68: eb01 0008 add.w r0, r1, r8\n", + " 6c: eb11 0008 adds.w r0, r1, r8\n", + " 70: ebb1 0008 subs.w r0, r1, r8\n", + " 74: eb50 0008 adcs.w r0, r0, r8\n", + " 78: eb70 0008 sbcs.w r0, r0, r8\n", + " 7c: ea10 0008 ands.w r0, r0, r8\n", + " 80: ea50 0008 orrs.w r0, r0, r8\n", + " 84: ea90 0008 eors.w r0, r0, r8\n", + " 88: ea30 0008 bics.w r0, r0, r8\n", + " 8c: ea10 0f08 tst.w r0, r8\n", + " 90: eb10 0f08 cmn.w r0, r8\n", + " 94: f1d8 0000 rsbs r0, r8, #0\n", + " 98: f1d8 0800 rsbs r8, r8, #0\n", + " 9c: bf08 it eq\n", + " 9e: ea7f 0001 mvnseq.w r0, r1\n", + " a2: bf08 it eq\n", + " a4: eb11 0002 addseq.w r0, r1, r2\n", + " a8: bf08 it eq\n", + " aa: ebb1 0002 subseq.w r0, r1, r2\n", + " ae: bf08 it eq\n", + " b0: eb50 0001 adcseq.w r0, r0, r1\n", + " b4: bf08 it eq\n", + " b6: eb70 0001 sbcseq.w r0, r0, r1\n", + " ba: bf08 it eq\n", + " bc: ea10 0001 andseq.w r0, r0, r1\n", + " c0: bf08 it eq\n", + " c2: ea50 0001 orrseq.w r0, r0, r1\n", + " c6: bf08 it eq\n", + " c8: ea90 0001 eorseq.w r0, r0, r1\n", + " cc: bf08 it eq\n", + " ce: ea30 0001 bicseq.w r0, r0, r1\n", + " d2: bf08 it eq\n", + " d4: 43c8 mvneq r0, r1\n", + " d6: bf08 it eq\n", + " d8: 1888 addeq r0, r1, r2\n", + " da: bf08 it eq\n", + " dc: 1a88 subeq r0, r1, r2\n", + " de: bf08 it eq\n", + " e0: 4148 adceq r0, r1\n", + " e2: bf08 it eq\n", + " e4: 4188 sbceq r0, r1\n", + " e6: bf08 it eq\n", + " e8: 4008 andeq r0, r1\n", + " ea: bf08 it eq\n", + " ec: 4308 orreq r0, r1\n", + " ee: bf08 it eq\n", + " f0: 4048 eoreq r0, r1\n", + " f2: bf08 it eq\n", + " f4: 4388 biceq r0, r1\n", + " f6: 4608 mov r0, r1\n", + " f8: 43c8 mvns r0, r1\n", + " fa: 4408 add r0, r1\n", + " fc: 1888 adds r0, r1, r2\n", + " fe: 1a88 subs r0, r1, r2\n", + " 100: 4148 adcs r0, r1\n", + " 102: 4188 sbcs r0, r1\n", + " 104: 4008 ands r0, r1\n", + " 106: 4308 orrs r0, r1\n", + " 108: 4048 eors r0, r1\n", + " 10a: 4388 bics r0, r1\n", + " 10c: 4641 mov r1, r8\n", + " 10e: 4681 mov r9, r0\n", + " 110: 46c8 mov r8, r9\n", + " 112: 4441 add r1, r8\n", + " 114: 4481 add r9, r0\n", + " 116: 44c8 add r8, r9\n", + " 118: 4248 negs r0, r1\n", + " 11a: 4240 negs r0, r0\n", + " 11c: eb01 0c00 add.w ip, r1, r0\n", nullptr }; const char* DataProcessingImmediateResults[] = { @@ -66,6 +148,8 @@ const char* DataProcessingImmediateResults[] = { " 3a: 1f48 subs r0, r1, #5\n", " 3c: 2055 movs r0, #85 ; 0x55\n", " 3e: f07f 0055 mvns.w r0, #85 ; 0x55\n", + " 42: 1d48 adds r0, r1, #5\n", + " 44: 1f48 subs r0, r1, #5\n", nullptr }; const char* DataProcessingModifiedImmediateResults[] = { @@ -100,13 +184,18 @@ const char* DataProcessingShiftedRegisterResults[] = { " 0: 0123 lsls r3, r4, #4\n", " 2: 0963 lsrs r3, r4, #5\n", " 4: 11a3 asrs r3, r4, #6\n", - " 6: ea4f 13f4 mov.w r3, r4, ror #7\n", - " a: 41e3 rors r3, r4\n", - " c: ea4f 1804 mov.w r8, r4, lsl #4\n", - " 10: ea4f 1854 mov.w r8, r4, lsr #5\n", - " 14: ea4f 18a4 mov.w r8, r4, asr #6\n", - " 18: ea4f 18f4 mov.w r8, r4, ror #7\n", - " 1c: ea4f 0834 mov.w r8, r4, rrx\n", + " 6: ea5f 13f4 movs.w r3, r4, ror #7\n", + " a: ea5f 0334 movs.w r3, r4, rrx\n", + " e: ea4f 1304 mov.w r3, r4, lsl #4\n", + " 12: ea4f 1354 mov.w r3, r4, lsr #5\n", + " 16: ea4f 13a4 mov.w r3, r4, asr #6\n", + " 1a: ea4f 13f4 mov.w r3, r4, ror #7\n", + " 1e: ea4f 0334 mov.w r3, r4, rrx\n", + " 22: ea5f 1804 movs.w r8, r4, lsl #4\n", + " 26: ea5f 1854 movs.w r8, r4, lsr #5\n", + " 2a: ea5f 18a4 movs.w r8, r4, asr #6\n", + " 2e: ea5f 18f4 movs.w r8, r4, ror #7\n", + " 32: ea5f 0834 movs.w r8, r4, rrx\n", nullptr }; const char* BasicLoadResults[] = { @@ -1511,7 +1600,7 @@ const char* Max16BitBranchResults[] = { " 7fc: 23fa movs r3, #250 ; 0xfa\n", " 7fe: 23fc movs r3, #252 ; 0xfc\n", " 800: 23fe movs r3, #254 ; 0xfe\n", - " 802: 0011 movs r1, r2\n", + " 802: 4611 mov r1, r2\n", nullptr }; const char* Branch32Results[] = { @@ -2541,7 +2630,7 @@ const char* Branch32Results[] = { " 800: 23fc movs r3, #252 ; 0xfc\n", " 802: 23fe movs r3, #254 ; 0xfe\n", " 804: 2300 movs r3, #0\n", - " 806: 0011 movs r1, r2\n", + " 806: 4611 mov r1, r2\n", nullptr }; const char* CompareAndBranchMaxResults[] = { @@ -2610,7 +2699,7 @@ const char* CompareAndBranchMaxResults[] = { " 7c: 237a movs r3, #122 ; 0x7a\n", " 7e: 237c movs r3, #124 ; 0x7c\n", " 80: 237e movs r3, #126 ; 0x7e\n", - " 82: 0011 movs r1, r2\n", + " 82: 4611 mov r1, r2\n", nullptr }; const char* CompareAndBranchRelocation16Results[] = { @@ -2681,7 +2770,7 @@ const char* CompareAndBranchRelocation16Results[] = { " 80: 237c movs r3, #124 ; 0x7c\n", " 82: 237e movs r3, #126 ; 0x7e\n", " 84: 2380 movs r3, #128 ; 0x80\n", - " 86: 0011 movs r1, r2\n", + " 86: 4611 mov r1, r2\n", nullptr }; const char* CompareAndBranchRelocation32Results[] = { @@ -3712,7 +3801,7 @@ const char* CompareAndBranchRelocation32Results[] = { " 802: 23fc movs r3, #252 ; 0xfc\n", " 804: 23fe movs r3, #254 ; 0xfe\n", " 806: 2300 movs r3, #0\n", - " 808: 0011 movs r1, r2\n", + " 808: 4611 mov r1, r2\n", nullptr }; const char* MixedBranch32Results[] = { @@ -4743,7 +4832,7 @@ const char* MixedBranch32Results[] = { " 802: 23fe movs r3, #254 ; 0xfe\n", " 804: 2300 movs r3, #0\n", " 806: f7ff bbfd b.w 4 <MixedBranch32+0x4>\n", - " 80a: 0011 movs r1, r2\n", + " 80a: 4611 mov r1, r2\n", nullptr }; const char* ShiftsResults[] = { @@ -4753,28 +4842,46 @@ const char* ShiftsResults[] = { " 6: 4088 lsls r0, r1\n", " 8: 40c8 lsrs r0, r1\n", " a: 4108 asrs r0, r1\n", - " c: ea4f 1841 mov.w r8, r1, lsl #5\n", - " 10: ea4f 1058 mov.w r0, r8, lsr #5\n", - " 14: ea4f 1861 mov.w r8, r1, asr #5\n", - " 18: ea4f 1078 mov.w r0, r8, ror #5\n", - " 1c: fa01 f002 lsl.w r0, r1, r2\n", - " 20: fa21 f002 lsr.w r0, r1, r2\n", - " 24: fa41 f002 asr.w r0, r1, r2\n", - " 28: fa61 f002 ror.w r0, r1, r2\n", - " 2c: fa01 f802 lsl.w r8, r1, r2\n", - " 30: fa28 f002 lsr.w r0, r8, r2\n", - " 34: fa41 f008 asr.w r0, r1, r8\n", - " 38: ea5f 1841 movs.w r8, r1, lsl #5\n", - " 3c: ea5f 1058 movs.w r0, r8, lsr #5\n", - " 40: ea5f 1861 movs.w r8, r1, asr #5\n", - " 44: ea5f 1078 movs.w r0, r8, ror #5\n", - " 48: fa11 f002 lsls.w r0, r1, r2\n", - " 4c: fa31 f002 lsrs.w r0, r1, r2\n", - " 50: fa51 f002 asrs.w r0, r1, r2\n", - " 54: fa71 f002 rors.w r0, r1, r2\n", - " 58: fa11 f802 lsls.w r8, r1, r2\n", - " 5c: fa38 f002 lsrs.w r0, r8, r2\n", - " 60: fa51 f008 asrs.w r0, r1, r8\n", + " c: 41c8 rors r0, r1\n", + " e: 0148 lsls r0, r1, #5\n", + " 10: 0948 lsrs r0, r1, #5\n", + " 12: 1148 asrs r0, r1, #5\n", + " 14: 4088 lsls r0, r1\n", + " 16: 40c8 lsrs r0, r1\n", + " 18: 4108 asrs r0, r1\n", + " 1a: 41c8 rors r0, r1\n", + " 1c: ea4f 1041 mov.w r0, r1, lsl #5\n", + " 20: ea4f 1051 mov.w r0, r1, lsr #5\n", + " 24: ea4f 1061 mov.w r0, r1, asr #5\n", + " 28: fa00 f001 lsl.w r0, r0, r1\n", + " 2c: fa20 f001 lsr.w r0, r0, r1\n", + " 30: fa40 f001 asr.w r0, r0, r1\n", + " 34: fa60 f001 ror.w r0, r0, r1\n", + " 38: ea4f 1071 mov.w r0, r1, ror #5\n", + " 3c: ea5f 1071 movs.w r0, r1, ror #5\n", + " 40: ea4f 1071 mov.w r0, r1, ror #5\n", + " 44: ea4f 1841 mov.w r8, r1, lsl #5\n", + " 48: ea4f 1058 mov.w r0, r8, lsr #5\n", + " 4c: ea4f 1861 mov.w r8, r1, asr #5\n", + " 50: ea4f 1078 mov.w r0, r8, ror #5\n", + " 54: fa01 f002 lsl.w r0, r1, r2\n", + " 58: fa21 f002 lsr.w r0, r1, r2\n", + " 5c: fa41 f002 asr.w r0, r1, r2\n", + " 60: fa61 f002 ror.w r0, r1, r2\n", + " 64: fa01 f802 lsl.w r8, r1, r2\n", + " 68: fa28 f002 lsr.w r0, r8, r2\n", + " 6c: fa41 f008 asr.w r0, r1, r8\n", + " 70: ea5f 1841 movs.w r8, r1, lsl #5\n", + " 74: ea5f 1058 movs.w r0, r8, lsr #5\n", + " 78: ea5f 1861 movs.w r8, r1, asr #5\n", + " 7c: ea5f 1078 movs.w r0, r8, ror #5\n", + " 80: fa11 f002 lsls.w r0, r1, r2\n", + " 84: fa31 f002 lsrs.w r0, r1, r2\n", + " 88: fa51 f002 asrs.w r0, r1, r2\n", + " 8c: fa71 f002 rors.w r0, r1, r2\n", + " 90: fa11 f802 lsls.w r8, r1, r2\n", + " 94: fa38 f002 lsrs.w r0, r8, r2\n", + " 98: fa51 f008 asrs.w r0, r1, r8\n", nullptr }; const char* LoadStoreRegOffsetResults[] = { |