Index: lib/Target/ARM/ARMCodeEmitter.cpp =================================================================== --- lib/Target/ARM/ARMCodeEmitter.cpp +++ lib/Target/ARM/ARMCodeEmitter.cpp @@ -199,6 +199,8 @@ const { return 0; } unsigned getSOImmOpValue(const MachineInstr &MI, unsigned Op) const { return 0; } + unsigned getModifiedImmOpValue(const MachineInstr &MI, unsigned Op) + const { return 0; } unsigned getT2SOImmOpValue(const MachineInstr &MI, unsigned Op) const { return 0; } unsigned getSORegRegOpValue(const MachineInstr &MI, unsigned Op) Index: lib/Target/ARM/ARMInstrInfo.td =================================================================== --- lib/Target/ARM/ARMInstrInfo.td +++ lib/Target/ARM/ARMInstrInfo.td @@ -566,6 +566,37 @@ let DecoderMethod = "DecodeSOImmOperand"; } +// ARM modified immediate records an 8-bit immediate rotated by an even number +// of bits. There are modified variants so that (for example) "(add $LHS, -4)" +// can be spotted and converted into "(sub $LHS 4)". +class ModifiedImmAsmOperand : AsmOperandClass { + let Name = "ARMModifiedImm" # Modifier; + let RenderMethod = "addARMModifiedImm" # Modifier # "Operands"; + let ParserMethod = "parseARMModifiedImm"; +} + +class ModifiedImm : Operand { + let MIOperandInfo = (ops i32imm:$base, i32imm:$rot); + let EncoderMethod = "getModifiedImmOpValue"; + let ParserMatchClass = AsmOp; + let DecoderMethod = "DecodeARMModifiedImmOperand"; + let PrintMethod = "printARMModifiedImmOperand"; +} + +def mod_imm_asmoperand : ModifiedImmAsmOperand<"">; +def mod_imm : ModifiedImm, + ComplexPattern; + +// mod_imm_neg deals with add <-> sub conversions +def mod_imm_neg_asmoperand : ModifiedImmAsmOperand<"Neg">; +def mod_imm_neg : ModifiedImm, + ComplexPattern; + +// mod_imm_not deals with and <-> bic and mov <-> mvn conversions. +def mod_imm_not_asmoperand : ModifiedImmAsmOperand<"Not">; +def mod_imm_not : ModifiedImm, + ComplexPattern; + // Break so_imm's up into two pieces. This handles immediates with up to 16 // bits set in them. This uses so_imm2part to match and so_imm2part_[12] to // get the first/second pieces. @@ -663,18 +694,6 @@ let ParserMatchClass = Imm0_31AsmOperand; } -/// imm0_31even predicate - True if the 32-bit immediate is in the range [0,31] -/// and is even -def Imm0_31EvenAsmOperand : ImmAsmOperand { - let Name = "Imm0_31Even"; - let DiagnosticType = "ImmRange0_31Even"; -} -def imm0_31even : Operand, ImmLeaf= 0 && Imm < 32 && ((Imm % 2) == 0); -}]> { - let ParserMatchClass = Imm0_31EvenAsmOperand; -} - /// imm0_32 predicate - True if the 32-bit immediate is in the range [0,32]. def Imm0_32AsmOperand: ImmAsmOperand { let Name = "Imm0_32"; } def imm0_32 : Operand, ImmLeaf { // The register-immediate version is re-materializable. This is useful // in particular for taking the address of a local. - let isReMaterializable = 1 in { + let isReMaterializable = 1, isCodeGenOnly = 1 in { def ri : AsI1, @@ -1074,19 +1093,17 @@ let Inst{11-0} = imm; } } - let isAsmParserOnly = 1 in - def rii : AsI1 { + def rii : AsI1 { bits<4> Rd; bits<4> Rn; - bits<8> imm1; - bits<5> imm2; + bits<12> imm; + let Inst{25} = 1; let Inst{19-16} = Rn; let Inst{15-12} = Rd; - let Inst{11-8} = imm2{4-1}; - let Inst{7-0} = imm1; + let Inst{11-0} = imm; } def rr : AsI1 { // The register-immediate version is re-materializable. This is useful // in particular for taking the address of a local. - let isReMaterializable = 1 in { + let isReMaterializable = 1, isCodeGenOnly = 1 in { def ri : AsI1, @@ -1161,19 +1178,16 @@ let Inst{11-0} = imm; } } - let isAsmParserOnly = 1 in - def rii : AsI1 { + def rii : AsI1 { bits<4> Rd; bits<4> Rn; - bits<8> imm1; - bits<5> imm2; + bits<12> imm; let Inst{25} = 1; let Inst{19-16} = Rn; let Inst{15-12} = Rd; - let Inst{11-8} = imm2{4-1}; - let Inst{7-0} = imm1; + let Inst{11-0} = imm; } def rr : AsI1 opcod, string opc, InstrItinClass iii, InstrItinClass iir, InstrItinClass iis, PatFrag opnode, bit Commutable = 0> { + let isCodeGenOnly = 1 in def ri : AI1, @@ -1307,18 +1322,15 @@ let Unpredictable{15-12} = 0b1111; } - let isAsmParserOnly = 1 in - def rii : AI1 { + def rii : AI1 { bits<4> Rn; - bits<8> imm1; - bits<5> imm2; + bits<12> imm; let Inst{25} = 1; let Inst{20} = 1; let Inst{19-16} = Rn; let Inst{15-12} = 0b0000; - let Inst{11-8} = imm2{4-1}; - let Inst{7-0} = imm1; + let Inst{11-0} = imm; let Unpredictable{15-12} = 0b1111; } def rr : AI1, + def rii : AsI1, Requires<[IsARM]> { bits<4> Rd; bits<4> Rn; - bits<8> imm1; - bits<5> imm2; + bits<12> imm; let Inst{25} = 1; let Inst{15-12} = Rd; let Inst{19-16} = Rn; - let Inst{11-8} = imm2{4-1}; - let Inst{7-0} = imm1; + let Inst{11-0} = imm; } def rr : AsI1, + def rii : AsI1, Requires<[IsARM]> { bits<4> Rd; bits<4> Rn; - bits<8> imm1; - bits<5> imm2; + bits<12> imm; let Inst{25} = 1; let Inst{15-12} = Rd; let Inst{19-16} = Rn; - let Inst{11-8} = imm2{4-1}; - let Inst{7-0} = imm1; + let Inst{11-0} = imm; } def rr : AsI1, UnaryDP, Sched<[WriteALU]> { @@ -3107,18 +3118,15 @@ let Inst{11-0} = imm; } -let isAsmParserOnly = 1 in -def MOVii : AsI1<0b1101, (outs GPR:$Rd), (ins imm0_255:$imm1, imm0_31even:$imm2), - DPFrm, IIC_iMOVi, "mov", "\t$Rd, $imm1, $imm2", []>, UnaryDP, +def MOVii : AsI1<0b1101, (outs GPR:$Rd), (ins mod_imm:$imm), + DPFrm, IIC_iMOVi, "mov", "\t$Rd, $imm", []>, UnaryDP, Sched<[WriteALU]> { bits<4> Rd; - bits<8> imm1; - bits<5> imm2; + bits<12> imm; let Inst{25} = 1; let Inst{15-12} = Rd; let Inst{19-16} = 0b0000; - let Inst{11-8} = imm2{4-1}; - let Inst{7-0} = imm1; + let Inst{11-0} = imm; } let isReMaterializable = 1, isAsCheapAsAMove = 1, isMoveImm = 1 in @@ -3616,7 +3624,8 @@ let Inst{4} = 1; let Inst{3-0} = shift{3-0}; } -let isReMaterializable = 1, isAsCheapAsAMove = 1, isMoveImm = 1 in +let isReMaterializable = 1, isAsCheapAsAMove = 1, isCodeGenOnly = 1, + isMoveImm = 1 in def MVNi : AsI1<0b1111, (outs GPR:$Rd), (ins so_imm:$imm), DPFrm, IIC_iMVNi, "mvn", "\t$Rd, $imm", [(set GPR:$Rd, so_imm_not:$imm)]>,UnaryDP, Sched<[WriteALU]> { @@ -3628,17 +3637,14 @@ let Inst{11-0} = imm; } -let isAsmParserOnly = 1 in -def MVNii : AsI1<0b1111, (outs GPR:$Rd), (ins imm0_255:$imm1, imm0_31even:$imm2), - DPFrm, IIC_iMVNi, "mvn", "\t$Rd, $imm1, $imm2", []> { +def MVNii : AsI1<0b1111, (outs GPR:$Rd), (ins mod_imm:$imm), + DPFrm, IIC_iMVNi, "mvn", "\t$Rd, $imm", []> { bits<4> Rd; - bits<8> imm1; - bits<5> imm2; + bits<12> imm; let Inst{25} = 1; let Inst{19-16} = 0b0000; let Inst{15-12} = Rd; - let Inst{11-8} = imm2{4-1}; - let Inst{7-0} = imm1; + let Inst{11-0} = imm; } @@ -4160,21 +4166,20 @@ let Inst{11-0} = imm; let Unpredictable{15-12} = 0b1111; + + let isCodeGenOnly = 1; } -let isAsmParserOnly = 1 in -def CMNrii : AI1<0b1011, (outs), (ins GPR:$Rn, imm0_255:$imm1, imm0_31even:$imm2), - DPFrm, IIC_iCMPi, "cmn", "\t$Rn, $imm1, $imm2", []> { +def CMNrii : AI1<0b1011, (outs), (ins GPR:$Rn, mod_imm:$imm), + DPFrm, IIC_iCMPi, "cmn", "\t$Rn, $imm", []> { bits<4> Rn; - bits<8> imm1; - bits<5> imm2; + bits<12> imm; let Inst{25} = 1; let Inst{20} = 1; let Inst{19-16} = Rn; let Inst{15-12} = 0b0000; - let Inst{11-8} = imm2{4-1}; - let Inst{7-0} = imm1; + let Inst{11-0} = imm; let Unpredictable{15-12} = 0b1111; } @@ -5003,6 +5008,7 @@ let Inst{3-0} = Rn; } +let isCodeGenOnly = 1 in def MSRi : ABI<0b0011, (outs), (ins msr_mask:$mask, so_imm:$a), NoItinerary, "msr", "\t$mask, $a", []> { bits<5> mask; @@ -5015,21 +5021,18 @@ let Inst{11-0} = a; } -let isAsmParserOnly = 1 in -def MSRii : ABI<0b0011, (outs), - (ins msr_mask:$mask, imm0_255:$imm1, imm0_31even:$imm2), NoItinerary, - "msr", "\t$mask, $imm1, $imm2", []> { +def MSRii : ABI<0b0011, (outs), + (ins msr_mask:$mask, mod_imm:$imm), NoItinerary, + "msr", "\t$mask, $imm", []> { bits<5> mask; - bits<8> imm1; - bits<5> imm2; + bits<12> imm; let Inst{23} = 0; let Inst{22} = mask{4}; // R bit let Inst{21-20} = 0b10; let Inst{19-16} = mask{3-0}; let Inst{15-12} = 0b1111; - let Inst{11-8} = imm2{4-1}; - let Inst{7-0} = imm1; + let Inst{11-0} = imm; } @@ -5405,36 +5408,39 @@ // USAX == USUBADDX def : MnemonicAlias<"usubaddx", "usax">; -// "mov Rd, so_imm_not" can be handled via "mvn" in assembly, just like +// "mov Rd, mod_imm_not" can be handled via "mvn" in assembly, just like // for isel. def : ARMInstAlias<"mov${s}${p} $Rd, $imm", - (MVNi rGPR:$Rd, so_imm_not:$imm, pred:$p, cc_out:$s)>; + (MVNii rGPR:$Rd, mod_imm_not:$imm, pred:$p, cc_out:$s)>; def : ARMInstAlias<"mvn${s}${p} $Rd, $imm", - (MOVi rGPR:$Rd, so_imm_not:$imm, pred:$p, cc_out:$s)>; + (MOVii rGPR:$Rd, mod_imm_not:$imm, pred:$p, cc_out:$s)>; // Same for AND <--> BIC def : ARMInstAlias<"bic${s}${p} $Rd, $Rn, $imm", - (ANDri rGPR:$Rd, rGPR:$Rn, so_imm_not:$imm, - pred:$p, cc_out:$s)>; + (ANDrii rGPR:$Rd, rGPR:$Rn, mod_imm_not:$imm, + pred:$p, cc_out:$s)>; def : ARMInstAlias<"bic${s}${p} $Rdn, $imm", - (ANDri rGPR:$Rdn, rGPR:$Rdn, so_imm_not:$imm, - pred:$p, cc_out:$s)>; + (ANDrii rGPR:$Rdn, rGPR:$Rdn, mod_imm_not:$imm, + pred:$p, cc_out:$s)>; def : ARMInstAlias<"and${s}${p} $Rd, $Rn, $imm", - (BICri rGPR:$Rd, rGPR:$Rn, so_imm_not:$imm, - pred:$p, cc_out:$s)>; + (BICrii rGPR:$Rd, rGPR:$Rn, mod_imm_not:$imm, + pred:$p, cc_out:$s)>; def : ARMInstAlias<"and${s}${p} $Rdn, $imm", - (BICri rGPR:$Rdn, rGPR:$Rdn, so_imm_not:$imm, - pred:$p, cc_out:$s)>; + (BICrii rGPR:$Rdn, rGPR:$Rdn, mod_imm_not:$imm, + pred:$p, cc_out:$s)>; -// Likewise, "add Rd, so_imm_neg" -> sub +// Likewise, "add Rd, mod_imm_neg" -> sub def : ARMInstAlias<"add${s}${p} $Rd, $Rn, $imm", - (SUBri GPR:$Rd, GPR:$Rn, so_imm_neg:$imm, pred:$p, cc_out:$s)>; + (SUBrii GPR:$Rd, GPR:$Rn, mod_imm_neg:$imm, + pred:$p, cc_out:$s)>; def : ARMInstAlias<"add${s}${p} $Rd, $imm", - (SUBri GPR:$Rd, GPR:$Rd, so_imm_neg:$imm, pred:$p, cc_out:$s)>; -// Same for CMP <--> CMN via so_imm_neg + (SUBrii GPR:$Rd, GPR:$Rd, mod_imm_neg:$imm, + pred:$p, cc_out:$s)>; + +// Same for CMP <--> CMN via mod_imm_neg def : ARMInstAlias<"cmp${p} $Rd, $imm", - (CMNri rGPR:$Rd, so_imm_neg:$imm, pred:$p)>; + (CMNrii rGPR:$Rd, mod_imm_neg:$imm, pred:$p)>; def : ARMInstAlias<"cmn${p} $Rd, $imm", - (CMPri rGPR:$Rd, so_imm_neg:$imm, pred:$p)>; + (CMPrii rGPR:$Rd, mod_imm_neg:$imm, pred:$p)>; // The shifter forms of the MOV instruction are aliased to the ASR, LSL, // LSR, ROR, and RRX instructions. Index: lib/Target/ARM/AsmParser/ARMAsmParser.cpp =================================================================== --- lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -108,6 +108,7 @@ return Parser.Error(L, Msg, Ranges); } + int identifyRegister(StringRef Text); int tryParseRegister(); bool tryParseRegisterWithWriteBack(SmallVectorImpl &); int tryParseShiftRegister(SmallVectorImpl &); @@ -208,6 +209,8 @@ return parsePKHImm(O, "asr", 1, 32); } OperandMatchResultTy parseSetEndImm(SmallVectorImpl&); + OperandMatchResultTy parseARMModifiedImm( + SmallVectorImpl&); OperandMatchResultTy parseShifterImm(SmallVectorImpl&); OperandMatchResultTy parseRotImm(SmallVectorImpl&); OperandMatchResultTy parseBitfield(SmallVectorImpl&); @@ -311,6 +314,7 @@ k_VectorListAllLanes, k_VectorListIndexed, k_ShiftedRegister, + k_ARMModifiedImmediate, k_ShiftedImmediate, k_ShifterImmediate, k_RotateImmediate, @@ -417,6 +421,11 @@ unsigned ShiftImm; }; + struct ARMModifiedImmediateOp { + unsigned BaseImm; + unsigned Rot; + }; + struct RotImmOp { unsigned Imm; }; @@ -444,6 +453,7 @@ struct PostIdxRegOp PostIdxReg; struct ShifterImmOp ShifterImm; struct RegShiftedRegOp RegShiftedReg; + struct ARMModifiedImmediateOp ARMModifiedImmediateOp; struct RegShiftedImmOp RegShiftedImm; struct RotImmOp RotImm; struct BitfieldOp Bitfield; @@ -512,6 +522,9 @@ case k_ShiftedRegister: RegShiftedReg = o.RegShiftedReg; break; + case k_ARMModifiedImmediate: + ARMModifiedImmediateOp = o.ARMModifiedImmediateOp; + break; case k_ShiftedImmediate: RegShiftedImm = o.RegShiftedImm; break; @@ -918,6 +931,36 @@ if (isImm() && !isa(getImm())) return true; else return (isARMSOImm() || isARMSOImmNeg()); } + bool isARMModifiedImm() const { + if (isARMModifiedImmediate()) return true; + + // Otherwise it's a normal immediate that we have to range-check. + if (!isImm()) return false; + const MCConstantExpr *CE = dyn_cast(getImm()); + if (!CE) return false; + int64_t Value = CE->getValue(); + return ARM_AM::getSOImmVal(Value) != -1; + } + bool isARMModifiedImmNeg() const { + // This is for aliases converting between add/sub, don't allow an explicit + // "#imm1, #imm2". + if (!isImm()) return false; + const MCConstantExpr *CE = dyn_cast(getImm()); + if (!CE) return false; + int64_t Value = CE->getValue(); + return ARM_AM::getSOImmVal(Value) == -1 && + ARM_AM::getSOImmVal(-Value) != -1; + } + bool isARMModifiedImmNot() const { + // This is for aliases converting between and/bic, don't allow an explicit + // "#imm1, #imm2". + if (!isImm()) return false; + const MCConstantExpr *CE = dyn_cast(getImm()); + if (!CE) return false; + int64_t Value = CE->getValue(); + return ARM_AM::getSOImmVal(Value) == -1 && + ARM_AM::getSOImmVal(~Value) != -1; + } bool isARMSOImm() const { if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); @@ -986,6 +1029,7 @@ bool isRotImm() const { return Kind == k_RotateImmediate; } bool isBitfield() const { return Kind == k_BitfieldDescriptor; } bool isPostIdxRegShifted() const { return Kind == k_PostIndexRegister; } + bool isARMModifiedImmediate() const { return Kind == k_ARMModifiedImmediate; } bool isPostIdxReg() const { return Kind == k_PostIndexRegister && PostIdxReg.ShiftTy ==ARM_AM::no_shift; } @@ -1626,6 +1670,41 @@ addExpr(Inst, getImm()); } + void addARMModifiedImmOperands(MCInst &Inst, int64_t (*Op)(int64_t)) const { + uint32_t BaseImm, Rot; + if (isImm()) { + const MCConstantExpr *CE = cast(getImm()); + int Bits = ARM_AM::getSOImmVal(Op(CE->getValue())); + assert(Bits != -1 && "expected valid modified immediate"); + BaseImm = Bits & 0xff; + Rot = Bits >> 8; + } else { + assert(isARMModifiedImmediate() && "expected two-operand modified imm"); + BaseImm = ARMModifiedImmediateOp.BaseImm; + Rot = ARMModifiedImmediateOp.Rot; + } + Inst.addOperand(MCOperand::CreateImm(BaseImm)); + Inst.addOperand(MCOperand::CreateImm(Rot)); + } + + static int64_t identityOp(int64_t in) { return in; } + void addARMModifiedImmOperands(MCInst &Inst, unsigned N) const { + assert(N == 2 && "Invalid number of operands!"); + return addARMModifiedImmOperands(Inst, identityOp); + } + + static int64_t negOp(int64_t in) { return -in; } + void addARMModifiedImmNegOperands(MCInst &Inst, unsigned N) const { + assert(N == 2 && "Invalid number of operands!"); + return addARMModifiedImmOperands(Inst, negOp); + } + + static int64_t notOp(int64_t in) { return ~in; } + void addARMModifiedImmNotOperands(MCInst &Inst, unsigned N) const { + assert(N == 2 && "Invalid number of operands!"); + return addARMModifiedImmOperands(Inst, notOp); + } + void addFBits16Operands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); const MCConstantExpr *CE = dyn_cast(getImm()); @@ -2296,6 +2375,17 @@ return Op; } + static ARMOperand *CreateARMModifiedImmediate(unsigned BaseImm, + unsigned Rot, + SMLoc S, SMLoc E) { + ARMOperand *Op = new ARMOperand(k_ARMModifiedImmediate); + Op->ARMModifiedImmediateOp.BaseImm = BaseImm; + Op->ARMModifiedImmediateOp.Rot = Rot; + Op->StartLoc = S; + Op->EndLoc = E; + return Op; + } + static ARMOperand *CreateShiftedImmediate(ARM_AM::ShiftOpc ShTy, unsigned SrcReg, unsigned ShiftImm, @@ -2559,6 +2649,10 @@ << ARM_AM::getShiftOpcStr(RegShiftedReg.ShiftTy) << " " << RegShiftedReg.ShiftReg << ">"; break; + case k_ARMModifiedImmediate: + OS << "'; + break; case k_ShiftedImmediate: OS << "(lowerCase) .Case("r13", ARM::SP) @@ -2666,11 +2754,24 @@ // If no match, return failure. if (Entry == RegisterReqs.end()) return -1; - Parser.Lex(); // Eat identifier token. return Entry->getValue(); } - Parser.Lex(); // Eat identifier token. + return RegNum; +} + +/// Try to parse a register name. The token must be an Identifier when called, +/// and if it is a register name the token is eaten and the register number is +/// returned. Otherwise return -1. +/// +int ARMAsmParser::tryParseRegister() { + const AsmToken &Tok = Parser.getTok(); + if (Tok.isNot(AsmToken::Identifier)) return -1; + + int RegNum = identifyRegister(Tok.getString()); + + if (RegNum != -1) + Parser.Lex(); // Eat identifier token. return RegNum; } @@ -3799,6 +3900,77 @@ return MatchOperand_Success; } +ARMAsmParser::OperandMatchResultTy ARMAsmParser:: +parseARMModifiedImm(SmallVectorImpl &Operands) { + const AsmToken &Tok = Parser.getTok(); + SMLoc S = Parser.getTok().getLoc(), E; + + // An ARM modified immediate can't possibly match in thumb mode. + if (isThumb() || Tok.is(AsmToken::Colon)) + return MatchOperand_NoMatch; + + // We don't want to treat registers as normal expressions. For example we get + // called to deal with the second operand in "add r0, r0, #45" because "add + // r0, #45" is also valid syntax. + if (Tok.is(AsmToken::Identifier) && identifyRegister(Tok.getString())) + return MatchOperand_NoMatch; + + if (Tok.is(AsmToken::Hash)) + Parser.Lex(); + + const MCExpr *BaseImmExpr = 0; + if (getParser().parseExpression(BaseImmExpr, E)) { + // Error already emitted during parse. + return MatchOperand_ParseFail; + } + + const MCConstantExpr *BaseImmCE = dyn_cast(BaseImmExpr); + if (!BaseImmCE) { + Error(S, "value must be compile-time constant"); + return MatchOperand_ParseFail; + } + int64_t BaseImm = BaseImmCE->getValue(); + + if(Parser.getTok().isNot(AsmToken::Comma)) { + // Push the entire immediate as an operand, the range will be checked + // individually later. + Operands.push_back(ARMOperand::CreateImm(BaseImmCE, S, E)); + return MatchOperand_Success; + } + + Parser.Lex(); + + SMLoc SecondImmLoc = Parser.getTok().getLoc(); + if (Parser.getTok().is(AsmToken::Hash)) + Parser.Lex(); + + const MCExpr *RotExpr = 0; + if (getParser().parseExpression(RotExpr, E)) { + // Error already emitted during parse + return MatchOperand_ParseFail; + } + + const MCConstantExpr *RotCE = dyn_cast(RotExpr); + if (!RotCE) { + Error(SecondImmLoc, "value must be compile-time constant"); + return MatchOperand_ParseFail; + } + int64_t Rot = RotCE->getValue(); + + if (BaseImm < 0 || BaseImm > 255) { + Error(S, "modified-immediate base value must be integer in range [0,255]"); + return MatchOperand_ParseFail; + } else if (Rot % 2 != 0 || Rot < 0 || Rot > 30) { + Error(SecondImmLoc, "modified-immediate rotate operand must be " + "an even number in the range [0,30]"); + return MatchOperand_ParseFail; + } + + Operands.push_back(ARMOperand::CreateARMModifiedImmediate(BaseImm, Rot / 2, + S, E)); + return MatchOperand_Success; +} + /// parseShifterImm - Parse the shifter immediate operand for SSAT/USAT /// instructions. Legal values are: /// lsl #n 'n' in [0,31] @@ -5760,16 +5932,20 @@ const SmallVectorImpl &Operands) { switch (Inst.getOpcode()) { // Alias for alternate form of 'ADR Rd, #imm' instruction. - case ARM::ADDri: { + case ARM::ADDrii: { if (Inst.getOperand(1).getReg() != ARM::PC || - Inst.getOperand(5).getReg() != 0) + Inst.getOperand(6).getReg() != 0) return false; MCInst TmpInst; TmpInst.setOpcode(ARM::ADR); TmpInst.addOperand(Inst.getOperand(0)); - TmpInst.addOperand(Inst.getOperand(2)); - TmpInst.addOperand(Inst.getOperand(3)); + uint32_t Imm = Inst.getOperand(2).getImm(); + uint32_t Rot = Inst.getOperand(3).getImm() * 2; + uint32_t Amt = (Imm >> Rot) | (Imm << ((32 - Rot) & 0x1f)); + TmpInst.addOperand(MCOperand::CreateImm(Amt)); TmpInst.addOperand(Inst.getOperand(4)); + TmpInst.addOperand(Inst.getOperand(5)); + TmpInst.addOperand(Inst.getOperand(6)); Inst = TmpInst; return true; } @@ -7656,11 +7832,6 @@ if (ErrorLoc == SMLoc()) ErrorLoc = IDLoc; return Error(ErrorLoc, "immediate operand must be in the range [0,4]"); } - case Match_ImmRange0_31Even: { - SMLoc ErrorLoc = ((ARMOperand*)Operands[ErrorInfo])->getStartLoc(); - if (ErrorLoc == SMLoc()) ErrorLoc = IDLoc; - return Error(ErrorLoc, "immediate operand must an even number in the range [0,30]"); - } case Match_ImmRange0_15: { SMLoc ErrorLoc = ((ARMOperand*)Operands[ErrorInfo])->getStartLoc(); if (ErrorLoc == SMLoc()) ErrorLoc = IDLoc; Index: lib/Target/ARM/Disassembler/ARMDisassembler.cpp =================================================================== --- lib/Target/ARM/Disassembler/ARMDisassembler.cpp +++ lib/Target/ARM/Disassembler/ARMDisassembler.cpp @@ -189,7 +189,7 @@ uint64_t Address, const void *Decoder); static DecodeStatus DecodeCCOutOperand(MCInst &Inst, unsigned Val, uint64_t Address, const void *Decoder); -static DecodeStatus DecodeSOImmOperand(MCInst &Inst, unsigned Val, +static DecodeStatus DecodeARMModifiedImmOperand(MCInst &Inst, unsigned Val, uint64_t Address, const void *Decoder); static DecodeStatus DecodeRegListOperand(MCInst &Inst, unsigned Val, uint64_t Address, const void *Decoder); @@ -1100,12 +1100,10 @@ return MCDisassembler::Success; } -static DecodeStatus DecodeSOImmOperand(MCInst &Inst, unsigned Val, - uint64_t Address, const void *Decoder) { - uint32_t imm = Val & 0xFF; - uint32_t rot = (Val & 0xF00) >> 7; - uint32_t rot_imm = (imm >> rot) | (imm << ((32-rot) & 0x1F)); - Inst.addOperand(MCOperand::CreateImm(rot_imm)); +static DecodeStatus DecodeARMModifiedImmOperand(MCInst &Inst, unsigned Val, + uint64_t Address, const void *Decoder) { + Inst.addOperand(MCOperand::CreateImm(Val & 0xff)); + Inst.addOperand(MCOperand::CreateImm(Val >> 8)); return MCDisassembler::Success; } Index: lib/Target/ARM/InstPrinter/ARMInstPrinter.h =================================================================== --- lib/Target/ARM/InstPrinter/ARMInstPrinter.h +++ lib/Target/ARM/InstPrinter/ARMInstPrinter.h @@ -38,6 +38,8 @@ void printSORegRegOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O); void printSORegImmOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O); + void printARMModifiedImmOperand(const MCInst *MI, unsigned OpNum, + raw_ostream &O); void printAddrModeTBB(const MCInst *MI, unsigned OpNum, raw_ostream &O); void printAddrModeTBH(const MCInst *MI, unsigned OpNum, raw_ostream &O); Index: lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp =================================================================== --- lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp +++ lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp @@ -367,7 +367,18 @@ ARM_AM::getSORegOffset(MO2.getImm()), UseMarkup); } +void ARMInstPrinter::printARMModifiedImmOperand(const MCInst *MI, + unsigned OpNum, + raw_ostream &O) { + uint32_t Imm = MI->getOperand(OpNum).getImm(); + uint32_t Rot = MI->getOperand(OpNum + 1).getImm() * 2; + uint32_t RotImm = (Imm >> Rot) | (Imm << ((32-Rot) & 0x1F)); + if ((uint32_t)ARM_AM::getSOImmVal(RotImm) == (Imm | (Rot << 7))) + O << '#' << RotImm; + else + O << '#' << Imm << ", #" << Rot; +} //===--------------------------------------------------------------------===// // Addressing Mode #2 //===--------------------------------------------------------------------===// Index: lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp =================================================================== --- lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp +++ lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp @@ -252,6 +252,15 @@ return Binary; } + /// Return an encoded 12-bit shifted-immediate value. + unsigned getModifiedImmOpValue(const MCInst &MI, unsigned Op, + SmallVectorImpl &Fixups) const { + unsigned BaseImm = MI.getOperand(Op).getImm(); + unsigned RotateAmt = MI.getOperand(Op + 1).getImm(); + + return BaseImm | (RotateAmt << 8); + } + /// getT2SOImmOpValue - Return an encoded 12-bit shifted-immediate value. unsigned getT2SOImmOpValue(const MCInst &MI, unsigned Op, SmallVectorImpl &Fixups) const { Index: test/MC/ARM/basic-arm-instructions.s =================================================================== --- test/MC/ARM/basic-arm-instructions.s +++ test/MC/ARM/basic-arm-instructions.s @@ -242,7 +242,7 @@ @------------------------------------------------------------------------------ adds r9, r8, #33, #20 -@ CHECK: adds r9, r8, #33, #20 @ encoding: [0x21,0x9a,0x98,0xe2] +@ CHECK: adds r9, r8, #135168 @ encoding: [0x21,0x9a,0x98,0xe2] @------------------------------------------------------------------------------ @ AND @@ -287,7 +287,7 @@ @ CHECK: and r6, r7, r8, asr r2 @ encoding: [0x58,0x62,0x07,0xe0] @ CHECK: and r6, r7, r8, ror r2 @ encoding: [0x78,0x62,0x07,0xe0] @ CHECK: and r10, r1, r6, rrx @ encoding: [0x66,0xa0,0x01,0xe0] -@ CHECK: bic r2, r3, #-2147483648 @ encoding: [0x02,0x21,0xc3,0xe3] +@ CHECK: bic r2, r3, #2147483648 @ encoding: [0x02,0x21,0xc3,0xe3] @ CHECK: and r1, r1, #15 @ encoding: [0x0f,0x10,0x01,0xe2] @ CHECK: and r10, r10, r1 @ encoding: [0x01,0xa0,0x0a,0xe0] @@ -309,14 +309,16 @@ @ CHECK: and r3, r1, r2, asr #32 @ encoding: [0x42,0x30,0x01,0xe0] and r1, r9, #15, #14 -@ CHECK: and r1, r9, #15, #14 @ encoding: [0x0f,0x17,0x09,0xe2] + and r1, r9, #60, #16 +@ CHECK: and r1, r9, #3932160 @ encoding: [0x0f,0x17,0x09,0xe2] +@ CHECK: and r1, r9, #60, #16 @ encoding: [0x3c,0x18,0x09,0xe2] @------------------------------------------------------------------------------ @ ANDS @------------------------------------------------------------------------------ ands r6, r3, #127, #4 -@ CHECK: ands r6, r3, #127, #4 @ encoding: [0x7f,0x62,0x13,0xe2] +@ CHECK: ands r6, r3, #4026531847 @ encoding: [0x7f,0x62,0x13,0xe2] @------------------------------------------------------------------------------ @ ASR @@ -427,8 +429,8 @@ @ CHECK: bic r3, r1, r2, lsr #32 @ encoding: [0x22,0x30,0xc1,0xe1] @ CHECK: bic r3, r1, r2, asr #32 @ encoding: [0x42,0x30,0xc1,0xe1] - bic r0, r1, #90, #16 -@ CHECK: bic r0, r1, #90, #16 @ encoding: [0x5a,0x08,0xc1,0xe3] + bic r0, r1, #180, #16 +@ CHECK: bic r0, r1, #180, #16 @ encoding: [0xb4,0x08,0xc1,0xe3] @------------------------------------------------------------------------------ @ BICS @@ -555,7 +557,7 @@ @ CHECK: cmn r1, r6, rrx @ encoding: [0x66,0x00,0x71,0xe1] cmn lr, #175, #28 -@ CHECK: cmn lr, #175, #28 @ encoding: [0xaf,0x0e,0x7e,0xe3] +@ CHECK: cmn lr, #2800 @ encoding: [0xaf,0x0e,0x7e,0xe3] @------------------------------------------------------------------------------ @ CMP @@ -591,7 +593,7 @@ @ CHECK: cmp lr, #0 @ encoding: [0x00,0x00,0x5e,0xe3] cmp sp, #133, #18 -@ CHECK: cmp sp, #133, #18 @ encoding: [0x85,0x09,0x5d,0xe3] +@ CHECK: cmp sp, #2179072 @ encoding: [0x85,0x09,0x5d,0xe3] @------------------------------------------------------------------------------ @ CPS @@ -830,7 +832,7 @@ @------------------------------------------------------------------------------ eors r5, r5, #99, #30 -@ CHECK: eors r5, r5, #99, #30 @ encoding: [0x63,0x5f,0x35,0xe2] +@ CHECK: eors r5, r5, #396 @ encoding: [0x63,0x5f,0x35,0xe2] @------------------------------------------------------------------------------ @ ISB @@ -1121,7 +1123,7 @@ @------------------------------------------------------------------------------ movs r11, #99, #0 -@ CHECK: movs r11, #99, #0 @ encoding: [0x63,0xb0,0xb0,0xe3] +@ CHECK: movs r11, #99 @ encoding: [0x63,0xb0,0xb0,0xe3] @------------------------------------------------------------------------------ @ MOVT @@ -1240,7 +1242,7 @@ @ CHECK: msr CPSR_fsxc, r0 @ encoding: [0x00,0xf0,0x2f,0xe1] msr spsr_fc, #15, #16 -@ CHECK: msr SPSR_fc, #15, #16 @ encoding: [0x0f,0xf8,0x69,0xe3] +@ CHECK: msr SPSR_fc, #983040 @ encoding: [0x0f,0xf8,0x69,0xe3] @------------------------------------------------------------------------------ @ MUL @@ -1426,7 +1428,7 @@ @ CHECK: orr r3, r1, r2, asr #32 @ encoding: [0x42,0x30,0x81,0xe1] orr r9, pc, #233, #14 -@ CHECK: orr r9, pc, #233, #14 @ encoding: [0xe9,0x97,0x8f,0xe3] +@ CHECK: orr r9, pc, #61079552 @ encoding: [0xe9,0x97,0x8f,0xe3] @------------------------------------------------------------------------------ @ ORRS @@ -1693,14 +1695,14 @@ @ CHECK: rsb r4, r4, r5, rrx @ encoding: [0x65,0x40,0x64,0xe0] rsb r9, r3, #255, #2 -@ CHECK: rsb r9, r3, #255, #2 @ encoding: [0xff,0x91,0x63,0xe2] +@ CHECK: rsb r9, r3, #3221225535 @ encoding: [0xff,0x91,0x63,0xe2] @------------------------------------------------------------------------------ @ RSBS @------------------------------------------------------------------------------ rsbs r10, r11, #99, #28 -@ CHECK: rsbs r10, r11, #99, #28 @ encoding: [0x63,0xae,0x7b,0xe2] +@ CHECK: rsbs r10, r11, #1584 @ encoding: [0x63,0xae,0x7b,0xe2] @------------------------------------------------------------------------------ @ RSC @@ -1757,7 +1759,7 @@ @ CHECK: rsc r6, r6, r7, ror r9 @ encoding: [0x77,0x69,0xe6,0xe0] rsc r11, r4, #91, #24 -@ CHECK: rsc r11, r4, #91, #24 @ encoding: [0x5b,0xbc,0xe4,0xe2] +@ CHECK: rsc r11, r4, #23296 @ encoding: [0x5b,0xbc,0xe4,0xe2] @------------------------------------------------------------------------------ @ RSCS @@ -1867,7 +1869,7 @@ @ CHECK: sbc r6, r6, r7, ror r9 @ encoding: [0x77,0x69,0xc6,0xe0] sbc r0, r0, #33, #8 -@ CHECK: sbc r0, r0, #33, #8 @ encoding: [0x21,0x04,0xc0,0xe2] +@ CHECK: sbc r0, r0, #553648128 @ encoding: [0x21,0x04,0xc0,0xe2] @------------------------------------------------------------------------------ @ SBCS @@ -2538,14 +2540,14 @@ @ CHECK: sub r3, r1, r2, asr #32 @ encoding: [0x42,0x30,0x41,0xe0] sub r4, r11, #255, #0 -@ CHECK: sub r4, r11, #255, #0 @ encoding: [0xff,0x40,0x4b,0xe2] +@ CHECK: sub r4, r11, #255 @ encoding: [0xff,0x40,0x4b,0xe2] @------------------------------------------------------------------------------ @ SUBS @------------------------------------------------------------------------------ subs r0, r3, #63, #2 -@ CHECK: subs r0, r3, #63, #2 @ encoding: [0x3f,0x01,0x53,0xe2] +@ CHECK: subs r0, r3, #3221225487 @ encoding: [0x3f,0x01,0x53,0xe2] @------------------------------------------------------------------------------ @ SVC @@ -2693,7 +2695,7 @@ @ CHECK: teq r6, r7, ror r9 @ encoding: [0x77,0x09,0x36,0xe1] teq r11, #99, #30 -@ CHECK: teq r11, #99, #30 @ encoding: [0x63,0x0f,0x3b,0xe3] +@ CHECK: teq r11, #396 @ encoding: [0x63,0x0f,0x3b,0xe3] @------------------------------------------------------------------------------ @ TST @@ -2723,7 +2725,7 @@ @ CHECK: tst r6, r7, ror r9 @ encoding: [0x77,0x09,0x16,0xe1] tst r5, #113, #10 -@ CHECK: tst r5, #113, #10 @ encoding: [0x71,0x05,0x15,0xe3] +@ CHECK: tst r5, #473956352 @ encoding: [0x71,0x05,0x15,0xe3] @------------------------------------------------------------------------------ @ UADD16/UADD8 Index: test/MC/ARM/diagnostics.s =================================================================== --- test/MC/ARM/diagnostics.s +++ test/MC/ARM/diagnostics.s @@ -124,63 +124,63 @@ teq r11, #99, #31 tst r5, #113, #11 -@CHECK-ERRORS: error: immediate operand must an even number in the range [0,30] +@CHECK-ERRORS: error: modified-immediate rotate operand must be an even number in the range [0,30] @CHECK-ERRORS: adc r10, r0, #220, #23 -@CHECK-ERRORS: error: immediate operand must an even number in the range [0,30] +@CHECK-ERRORS: error: modified-immediate rotate operand must be an even number in the range [0,30] @CHECK-ERRORS: adcs r5, r11, #88, #44 -@CHECK-ERRORS: error: immediate operand must an even number in the range [0,30] +@CHECK-ERRORS: error: modified-immediate rotate operand must be an even number in the range [0,30] @CHECK-ERRORS: add r0, r12, #40, #-10 -@CHECK-ERRORS: error: immediate operand must an even number in the range [0,30] +@CHECK-ERRORS: error: modified-immediate rotate operand must be an even number in the range [0,30] @CHECK-ERRORS: adds r9, r8, #33, #21 -@CHECK-ERRORS: error: immediate operand must an even number in the range [0,30] +@CHECK-ERRORS: error: modified-immediate rotate operand must be an even number in the range [0,30] @CHECK-ERRORS: and r1, r9, #15, #15 -@CHECK-ERRORS: error: immediate operand must an even number in the range [0,30] +@CHECK-ERRORS: error: modified-immediate rotate operand must be an even number in the range [0,30] @CHECK-ERRORS: ands r6, r3, #127, #40 -@CHECK-ERRORS: error: immediate operand must an even number in the range [0,30] +@CHECK-ERRORS: error: modified-immediate rotate operand must be an even number in the range [0,30] @CHECK-ERRORS: bic r0, r1, #90, #126 -@CHECK-ERRORS: error: immediate operand must an even number in the range [0,30] +@CHECK-ERRORS: error: modified-immediate rotate operand must be an even number in the range [0,30] @CHECK-ERRORS: bics r5, r6, #240, #13 -@CHECK-ERRORS: error: immediate operand must an even number in the range [0,30] +@CHECK-ERRORS: error: modified-immediate rotate operand must be an even number in the range [0,30] @CHECK-ERRORS: cmn lr, #175, #29 -@CHECK-ERRORS: error: immediate operand must an even number in the range [0,30] +@CHECK-ERRORS: error: modified-immediate rotate operand must be an even number in the range [0,30] @CHECK-ERRORS: cmp sp, #133, #19 -@CHECK-ERRORS: error: immediate operand must an even number in the range [0,30] +@CHECK-ERRORS: error: modified-immediate rotate operand must be an even number in the range [0,30] @CHECK-ERRORS: eor r10, r7, #240, #32 -@CHECK-ERRORS: error: immediate operand must an even number in the range [0,30] +@CHECK-ERRORS: error: modified-immediate rotate operand must be an even number in the range [0,30] @CHECK-ERRORS: eors r5, r5, #99, #31 -@CHECK-ERRORS: error: immediate operand must an even number in the range [0,30] +@CHECK-ERRORS: error: modified-immediate rotate operand must be an even number in the range [0,30] @CHECK-ERRORS: mov r9, #240, #-30 -@CHECK-ERRORS: error: immediate operand must an even number in the range [0,30] +@CHECK-ERRORS: error: modified-immediate rotate operand must be an even number in the range [0,30] @CHECK-ERRORS: movs r11, #99, #1 -@CHECK-ERRORS: error: immediate operand must an even number in the range [0,30] +@CHECK-ERRORS: error: modified-immediate rotate operand must be an even number in the range [0,30] @CHECK-ERRORS: msr spsr_fc, #15, #17 -@CHECK-ERRORS: error: immediate operand must an even number in the range [0,30] +@CHECK-ERRORS: error: modified-immediate rotate operand must be an even number in the range [0,30] @CHECK-ERRORS: mvn r8, #120, #5 -@CHECK-ERRORS: error: immediate operand must an even number in the range [0,30] +@CHECK-ERRORS: error: modified-immediate rotate operand must be an even number in the range [0,30] @CHECK-ERRORS: mvns r2, #55, #32 -@CHECK-ERRORS: error: immediate operand must an even number in the range [0,30] +@CHECK-ERRORS: error: modified-immediate rotate operand must be an even number in the range [0,30] @CHECK-ERRORS: orr r9, pc, #233, #-1 -@CHECK-ERRORS: error: immediate operand must an even number in the range [0,30] +@CHECK-ERRORS: error: modified-immediate rotate operand must be an even number in the range [0,30] @CHECK-ERRORS: orrs r5, sp, #144, #33 -@CHECK-ERRORS: error: immediate operand must an even number in the range [0,30] +@CHECK-ERRORS: error: modified-immediate rotate operand must be an even number in the range [0,30] @CHECK-ERRORS: rsb r9, r3, #255, #3 -@CHECK-ERRORS: error: immediate operand must an even number in the range [0,30] +@CHECK-ERRORS: error: modified-immediate rotate operand must be an even number in the range [0,30] @CHECK-ERRORS: rsbs r10, r11, #99, #128 -@CHECK-ERRORS: error: immediate operand must an even number in the range [0,30] +@CHECK-ERRORS: error: modified-immediate rotate operand must be an even number in the range [0,30] @CHECK-ERRORS: rsc r11, r4, #91, #25 -@CHECK-ERRORS: error: immediate operand must an even number in the range [0,30] +@CHECK-ERRORS: error: modified-immediate rotate operand must be an even number in the range [0,30] @CHECK-ERRORS: rscs r5, r12, #172, #116 -@CHECK-ERRORS: error: immediate operand must an even number in the range [0,30] +@CHECK-ERRORS: error: modified-immediate rotate operand must be an even number in the range [0,30] @CHECK-ERRORS: sbc r0, r0, #33, #81 -@CHECK-ERRORS: error: immediate operand must an even number in the range [0,30] +@CHECK-ERRORS: error: modified-immediate rotate operand must be an even number in the range [0,30] @CHECK-ERRORS: sbcs r9, r2, #30, #29 -@CHECK-ERRORS: error: immediate operand must an even number in the range [0,30] +@CHECK-ERRORS: error: modified-immediate rotate operand must be an even number in the range [0,30] @CHECK-ERRORS: sub r4, r11, #255, #1 -@CHECK-ERRORS: error: immediate operand must an even number in the range [0,30] +@CHECK-ERRORS: error: modified-immediate rotate operand must be an even number in the range [0,30] @CHECK-ERRORS: subs r0, r3, #63, #3 -@CHECK-ERRORS: error: immediate operand must an even number in the range [0,30] +@CHECK-ERRORS: error: modified-immediate rotate operand must be an even number in the range [0,30] @CHECK-ERRORS: teq r11, #99, #31 -@CHECK-ERRORS: error: immediate operand must an even number in the range [0,30] +@CHECK-ERRORS: error: modified-immediate rotate operand must be an even number in the range [0,30] @CHECK-ERRORS: tst r5, #113, #11 @ Out of range 4 and 3 bit immediates on CDP[2] Index: test/MC/Disassembler/ARM/arm-tests.txt =================================================================== --- test/MC/Disassembler/ARM/arm-tests.txt +++ test/MC/Disassembler/ARM/arm-tests.txt @@ -1,6 +1,6 @@ # RUN: llvm-mc --disassemble %s -triple=armv7-apple-darwin9 -mcpu=cortex-a9-mp | FileCheck %s -# CHECK: addpl r4, pc, #318767104 +# CHECK: addpl r4, pc, #76, #10 0x4c 0x45 0x8f 0x52 # CHECK: b #0 @@ -362,3 +362,71 @@ # CHECK: ldmgt sp!, {r9} 0x00 0x02 0xbd 0xc8 + + +####################################################################### +# ARM modified immediate tests +####################################################################### + +[0x37,0x2f,0xf0,0xe3] +# CHECK: mvns r2, #55, #30 + +[0x00 0x90,0x98,0xe2] +# CHECK: adds r9, r8, #0{{$}} + +[0x08,0x21,0xc3,0xe3] +# CHECK: bic r2, r3, #8, #2 + +[0x00,0x17,0x09,0xe2] +# CHECK: and r1, r9, #0, #14 + +[0x3c,0x18,0x09,0xe2] +# CHECK: and r1, r9, #60, #16 + +[0x74,0x62,0x13,0xe2] +# CHECK: ands r6, r3, #116, #4 + +[0xb4,0x08,0xc1,0xe3] +# CHECK: bic r0, r1, #180, #16 + +[0xa0,0x0e,0x7e,0xe3] +# CHECK: cmn lr, #160, #28 + +[0x88,0x09,0x5d,0xe3] +# CHECK: cmp sp, #136, #18 + +[0x64,0x5f,0x35,0xe2] +# CHECK: eors r5, r5, #100, #30 + +[0x60,0xb0,0xb0,0xe3] +# CHECK: movs r11, #96{{$}} + +[0xf0,0xf8,0x69,0xe3] +# CHECK: msr SPSR_fc, #240, #16 + +[0xec,0x97,0x8f,0xe3] +# CHECK: orr r9, pc, #236, #14 + +[0xfc,0x91,0x63,0xe2] +# CHECK: rsb r9, r3, #252, #2 + +[0x64,0xae,0x7b,0xe2] +# CHECK: rsbs r10, r11, #100, #28 + +[0x5c,0xbc,0xe4,0xe2] +# CHECK: rsc r11, r4, #92, #24 + +[0x84,0x04,0xc0,0xe2] +# CHECK: sbc r0, r0, #132, #8 + +[0xf0,0x40,0x4b,0xe2] +# CHECK: sub r4, r11, #240{{$}} + +[0x3c,0x01,0x53,0xe2] +# CHECK: subs r0, r3, #60, #2 + +[0x64,0x0f,0x3b,0xe3] +# CHECK: teq r11, #100, #30 + +[0x78,0x05,0x15,0xe3] +# CHECK: tst r5, #120, #10