diff --git a/llvm/lib/Target/MSP430/MSP430ISelLowering.h b/llvm/lib/Target/MSP430/MSP430ISelLowering.h --- a/llvm/lib/Target/MSP430/MSP430ISelLowering.h +++ b/llvm/lib/Target/MSP430/MSP430ISelLowering.h @@ -20,54 +20,63 @@ namespace llvm { namespace MSP430ISD { - enum NodeType : unsigned { - FIRST_NUMBER = ISD::BUILTIN_OP_END, + enum NodeType : unsigned { + FIRST_NUMBER = ISD::BUILTIN_OP_END, - /// Return with a flag operand. Operand 0 is the chain operand. - RET_FLAG, + /// Return with a flag operand. Operand 0 is the chain operand. + RET_FLAG, - /// Same as RET_FLAG, but used for returning from ISRs. - RETI_FLAG, + /// Same as RET_FLAG, but used for returning from ISRs. + RETI_FLAG, - /// Y = R{R,L}A X, rotate right (left) arithmetically - RRA, RLA, + /// Y = R{R,L}A X, rotate right (left) arithmetically + RRA, + RLA, - /// Y = RRC X, rotate right via carry - RRC, + /// Y = RRC X, rotate right via carry + RRC, - /// Rotate right via carry, carry gets cleared beforehand by clrc - RRCL, + /// Rotate right via carry, carry gets cleared beforehand by clrc + RRCL, - /// CALL - These operations represent an abstract call - /// instruction, which includes a bunch of information. - CALL, + /// CALL - These operations represent an abstract call + /// instruction, which includes a bunch of information. + CALL, - /// Wrapper - A wrapper node for TargetConstantPool, TargetExternalSymbol, - /// and TargetGlobalAddress. - Wrapper, + /// Wrapper - A wrapper node for TargetConstantPool, TargetExternalSymbol, + /// and TargetGlobalAddress. + Wrapper, - /// CMP - Compare instruction. - CMP, + /// CMP - Compare instruction. + CMP, - /// SetCC - Operand 0 is condition code, and operand 1 is the flag - /// operand produced by a CMP instruction. - SETCC, + /// SetCC - Operand 0 is condition code, and operand 1 is the flag + /// operand produced by a CMP instruction. + SETCC, - /// MSP430 conditional branches. Operand 0 is the chain operand, operand 1 - /// is the block to branch if condition is true, operand 2 is the - /// condition code, and operand 3 is the flag operand produced by a CMP - /// instruction. - BR_CC, + /// MSP430 conditional branches. Operand 0 is the chain operand, operand 1 + /// is the block to branch if condition is true, operand 2 is the + /// condition code, and operand 3 is the flag operand produced by a CMP + /// instruction. + BR_CC, - /// SELECT_CC - Operand 0 and operand 1 are selection variable, operand 3 - /// is condition code and operand 4 is flag operand. - SELECT_CC, + /// SELECT_CC - Operand 0 and operand 1 are selection variable, operand 3 + /// is condition code and operand 4 is flag operand. + SELECT_CC, - /// DADD - Decimal addition with carry - /// TODO Nothing generates a node of this type yet. - DADD, - }; - } + /// DADD - Decimal addition with carry + /// TODO Nothing generates a node of this type yet. + DADD, + + /// Extended versions of the shift instructions, supported by the 430X CPU. + RRAM, + RRUM, + RLAM, + RRAX, + RLAX, + RRUX + }; + } // namespace MSP430ISD class MSP430Subtarget; class MSP430TargetLowering : public TargetLowering { diff --git a/llvm/lib/Target/MSP430/MSP430ISelLowering.cpp b/llvm/lib/Target/MSP430/MSP430ISelLowering.cpp --- a/llvm/lib/Target/MSP430/MSP430ISelLowering.cpp +++ b/llvm/lib/Target/MSP430/MSP430ISelLowering.cpp @@ -360,7 +360,8 @@ // Define non profitable transforms into shifts bool MSP430TargetLowering::shouldAvoidTransformToShift(EVT VT, unsigned Amount) const { - return !(Amount == 8 || Amount == 9 || Amount<=2); + return !(Subtarget->hasMSP430X() || Amount == 8 || Amount == 9 || + Amount <= 2); } // Implemented to verify test case assertions in @@ -953,59 +954,183 @@ return Chain; } -SDValue MSP430TargetLowering::LowerShifts(SDValue Op, - SelectionDAG &DAG) const { +/// Efficiently lower a shift count of 8 by swapping bytes of the value to be +/// shifted, instead of using shift instructions. +static SDValue shiftBy8(SDValue Op, SelectionDAG &DAG) { unsigned Opc = Op.getOpcode(); - SDNode* N = Op.getNode(); EVT VT = Op.getValueType(); - SDLoc dl(N); + SDLoc Dl(Op); + SDValue Victim = Op.getOperand(0); - // Expand non-constant shifts to loops: - if (!isa(N->getOperand(1))) - return Op; - - uint64_t ShiftAmount = cast(N->getOperand(1))->getZExtValue(); + switch (Opc) { + default: + llvm_unreachable("Unknown shift"); + case ISD::SHL: + // foo << (8 + N) => swpb(zext(foo)) << N + Victim = DAG.getZeroExtendInReg(Victim, Dl, MVT::i8); + Victim = DAG.getNode(ISD::BSWAP, Dl, VT, Victim); + break; + case ISD::SRA: + case ISD::SRL: + // foo >> (8 + N) => sxt(swpb(foo)) >> N + Victim = DAG.getNode(ISD::BSWAP, Dl, VT, Victim); + Victim = (Opc == ISD::SRA) ? DAG.getNode(ISD::SIGN_EXTEND_INREG, Dl, VT, + Victim, DAG.getValueType(MVT::i8)) + : DAG.getZeroExtendInReg(Victim, Dl, MVT::i8); + break; + } + return Victim; +} - // Expand the stuff into sequence of shifts. - SDValue Victim = N->getOperand(0); +/// Lower shifts of byte or word-sized operands, using the 430 instructions RRC, +/// RLA and RRA. +static SDValue lowerShiftToRxx(SDValue Op, SelectionDAG &DAG) { + unsigned Opc = Op.getOpcode(); + EVT VT = Op.getValueType(); + SDLoc Dl(Op); + SDValue Victim = Op.getOperand(0); + assert(isa(Op.getOperand(1))); + int ShiftAmount = cast(Op.getOperand(1))->getZExtValue(); if (ShiftAmount >= 8) { - assert(VT == MVT::i16 && "Can not shift i8 by 8 and more"); - switch(Opc) { - default: - llvm_unreachable("Unknown shift"); - case ISD::SHL: - // foo << (8 + N) => swpb(zext(foo)) << N - Victim = DAG.getZeroExtendInReg(Victim, dl, MVT::i8); - Victim = DAG.getNode(ISD::BSWAP, dl, VT, Victim); - break; - case ISD::SRA: - case ISD::SRL: - // foo >> (8 + N) => sxt(swpb(foo)) >> N - Victim = DAG.getNode(ISD::BSWAP, dl, VT, Victim); - Victim = (Opc == ISD::SRA) - ? DAG.getNode(ISD::SIGN_EXTEND_INREG, dl, VT, Victim, - DAG.getValueType(MVT::i8)) - : DAG.getZeroExtendInReg(Victim, dl, MVT::i8); - break; - } + Victim = shiftBy8(Op, DAG); + // For SRL, the top byte is now 0, so we can go straight to emitting RRA. + // CLRC, RRC is not required. ShiftAmount -= 8; - } - - if (Opc == ISD::SRL && ShiftAmount) { + } else if (Opc == ISD::SRL) { // Emit a special goodness here: // srl A, 1 => clrc; rrc A - Victim = DAG.getNode(MSP430ISD::RRCL, dl, VT, Victim); + Victim = DAG.getNode(MSP430ISD::RRCL, Dl, VT, Victim); ShiftAmount -= 1; } while (ShiftAmount--) Victim = DAG.getNode((Opc == ISD::SHL ? MSP430ISD::RLA : MSP430ISD::RRA), - dl, VT, Victim); + Dl, VT, Victim); + return Victim; +} + +/// Lower shifts of byte or word-sized operands, using the 430X extended +/// instructions RLAX, RRUX and RRAX. +static SDValue lowerShiftToRxxX(SDValue Op, SelectionDAG &DAG) { + EVT VT = Op.getValueType(); + SDLoc Dl(Op); + SDValue Victim = Op.getOperand(0); + assert(isa(Op.getOperand(1))); + int ShiftAmount = cast(Op.getOperand(1))->getZExtValue(); + + if (ShiftAmount == 8) + return shiftBy8(Op, DAG); + + switch (Op.getOpcode()) { + case ISD::SHL: + return DAG.getNode(MSP430ISD::RLAX, Dl, VT, Victim, + DAG.getConstant(ShiftAmount, Dl, MVT::i8)); + case ISD::SRA: + return DAG.getNode(MSP430ISD::RRAX, Dl, VT, Victim, + DAG.getConstant(ShiftAmount, Dl, MVT::i8)); + case ISD::SRL: + return DAG.getNode(MSP430ISD::RRUX, Dl, VT, Victim, + DAG.getConstant(ShiftAmount, Dl, MVT::i8)); + default: + llvm_unreachable("unhandled shift instruction"); + } +} + +/// Lower shifts of word-sized operands, using the 430X extended +/// format exception instructions RLAM, RRUM and RRAM. +static SDValue lowerShiftToRxxM(SDValue Op, SelectionDAG &DAG) { + assert(Op.getValueSizeInBits() == 16 && + "can only lower shifts to RxxM for word-sized ops"); + EVT VT = Op.getValueType(); + SDLoc Dl(Op); + SDValue Victim = Op.getOperand(0); + assert(isa(Op.getOperand(1))); + int ShiftAmount = cast(Op.getOperand(1))->getZExtValue(); + + if (ShiftAmount > 8) { + Victim = shiftBy8(Op, DAG); + ShiftAmount -= 8; + } + + while (ShiftAmount > 0) { + int CurrentShiftAmount = ShiftAmount; + if (CurrentShiftAmount > 4) + CurrentShiftAmount = 4; + switch (Op.getOpcode()) { + case ISD::SHL: + Victim = DAG.getNode(MSP430ISD::RLAM, Dl, VT, Victim, + DAG.getConstant(CurrentShiftAmount, Dl, MVT::i8)); + break; + case ISD::SRA: + Victim = DAG.getNode(MSP430ISD::RRAM, Dl, VT, Victim, + DAG.getConstant(CurrentShiftAmount, Dl, MVT::i8)); + break; + case ISD::SRL: + Victim = DAG.getNode(MSP430ISD::RRUM, Dl, VT, Victim, + DAG.getConstant(CurrentShiftAmount, Dl, MVT::i8)); + break; + default: + llvm_unreachable("unhandled shift instruction"); + break; + } + ShiftAmount -= CurrentShiftAmount; + } return Victim; } +SDValue MSP430TargetLowering::LowerShifts(SDValue Op, SelectionDAG &DAG) const { + + // Expand non-constant shifts to loops. + // + // TODO: For the MSP430X CPU, if the non-constant shift amount is in a + // register, we can use the RPT flag in the extension word to shift by the + // amount stored in the register, without using loops. + if (!isa(Op.getOperand(1))) + return Op; + + // Let the middle-end handle shifts of 32-bit/64-bit operands. + TypeSize OpSize = Op.getValueSizeInBits(); + if (OpSize > 16) + return Op; + + if (!Subtarget->hasMSP430X()) + return lowerShiftToRxx(Op, DAG); + + int ShiftAmount = cast(Op.getOperand(1))->getZExtValue(); + if (ShiftAmount == 1) { + // SRL -> RRC requires a CLRC first, for a total of 2 words. We can do it in + // 1 word with RRUM. + // + // TODO: If op0 is not a register, it would be more efficient to use an Rxx + // shift. + if (OpSize == 16 && Op.getOpcode() == ISD::SRL) + return lowerShiftToRxxM(Op, DAG); + return lowerShiftToRxx(Op, DAG); + } + if (ShiftAmount == 8) + return shiftBy8(Op, DAG); + if (OpSize == 8) { + // RxxM shifts can't handle byte-sized operands. + return lowerShiftToRxxX(Op, DAG); + } + + // Even though RxxM can only shift by <= 4, for shift counts < 8 it's cheaper + // to chain the RxxM shifts than to use the RxxX shifts with rpt. This saves + // one cycle and uses the same number of words. + // + // Only when not optimizing for size, use shiftBy8 followed by an RxxM chain + // to shift by > 8. Compared to using an RxxX insn, this saves 7 cycles but + // adds 2 words. + if (Op.getValueSizeInBits() == 16 && + (ShiftAmount < 8 || !DAG.getMachineFunction().getFunction().hasOptSize())) + return lowerShiftToRxxM(Op, DAG); + + assert(OpSize == 16 && ShiftAmount > 8); + return lowerShiftToRxxX(Op, DAG); +} + SDValue MSP430TargetLowering::LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const { const GlobalValue *GV = cast(Op)->getGlobal(); @@ -1366,20 +1491,46 @@ const char *MSP430TargetLowering::getTargetNodeName(unsigned Opcode) const { switch ((MSP430ISD::NodeType)Opcode) { - case MSP430ISD::FIRST_NUMBER: break; - case MSP430ISD::RET_FLAG: return "MSP430ISD::RET_FLAG"; - case MSP430ISD::RETI_FLAG: return "MSP430ISD::RETI_FLAG"; - case MSP430ISD::RRA: return "MSP430ISD::RRA"; - case MSP430ISD::RLA: return "MSP430ISD::RLA"; - case MSP430ISD::RRC: return "MSP430ISD::RRC"; - case MSP430ISD::RRCL: return "MSP430ISD::RRCL"; - case MSP430ISD::CALL: return "MSP430ISD::CALL"; - case MSP430ISD::Wrapper: return "MSP430ISD::Wrapper"; - case MSP430ISD::BR_CC: return "MSP430ISD::BR_CC"; - case MSP430ISD::CMP: return "MSP430ISD::CMP"; - case MSP430ISD::SETCC: return "MSP430ISD::SETCC"; - case MSP430ISD::SELECT_CC: return "MSP430ISD::SELECT_CC"; - case MSP430ISD::DADD: return "MSP430ISD::DADD"; + case MSP430ISD::FIRST_NUMBER: + break; + case MSP430ISD::RET_FLAG: + return "MSP430ISD::RET_FLAG"; + case MSP430ISD::RETI_FLAG: + return "MSP430ISD::RETI_FLAG"; + case MSP430ISD::RRA: + return "MSP430ISD::RRA"; + case MSP430ISD::RLA: + return "MSP430ISD::RLA"; + case MSP430ISD::RRC: + return "MSP430ISD::RRC"; + case MSP430ISD::RRCL: + return "MSP430ISD::RRCL"; + case MSP430ISD::CALL: + return "MSP430ISD::CALL"; + case MSP430ISD::Wrapper: + return "MSP430ISD::Wrapper"; + case MSP430ISD::BR_CC: + return "MSP430ISD::BR_CC"; + case MSP430ISD::CMP: + return "MSP430ISD::CMP"; + case MSP430ISD::SETCC: + return "MSP430ISD::SETCC"; + case MSP430ISD::SELECT_CC: + return "MSP430ISD::SELECT_CC"; + case MSP430ISD::DADD: + return "MSP430ISD::DADD"; + case MSP430ISD::RRAM: + return "MSP430ISD::RRAM"; + case MSP430ISD::RRUM: + return "MSP430ISD::RRUM"; + case MSP430ISD::RLAM: + return "MSP430ISD::RLAM"; + case MSP430ISD::RRAX: + return "MSP430ISD::RRAX"; + case MSP430ISD::RLAX: + return "MSP430ISD::RLAX"; + case MSP430ISD::RRUX: + return "MSP430ISD::RRUX"; } return nullptr; } diff --git a/llvm/lib/Target/MSP430/MSP430InstrInfoExtended.td b/llvm/lib/Target/MSP430/MSP430InstrInfoExtended.td --- a/llvm/lib/Target/MSP430/MSP430InstrInfoExtended.td +++ b/llvm/lib/Target/MSP430/MSP430InstrInfoExtended.td @@ -18,6 +18,16 @@ // required in the small memory model, and have increased size/cycle count // compared to their 430 versions. +def MSP430rram : SDNode<"MSP430ISD::RRAM", SDTIntShiftOp>; +def MSP430rrum : SDNode<"MSP430ISD::RRUM", SDTIntShiftOp>; +def MSP430rlam : SDNode<"MSP430ISD::RLAM", SDTIntShiftOp>; + +def MSP430rrax : SDNode<"MSP430ISD::RRAX", SDTIntShiftOp>; +def MSP430rlax : SDNode<"MSP430ISD::RLAX", SDTIntShiftOp>; +def MSP430rrux : SDNode<"MSP430ISD::RRUX", SDTIntShiftOp>; + +// Differentiate between rpt2 and rpt4 to catch shift counts in IIExtExcRot +// instructions that are too large. def Rpt2ImmAsmOperand : AsmOperandClass { let Name = "Rpt2Imm"; let RenderMethod = "addImmOperands"; @@ -47,43 +57,53 @@ // let Predicates = [HasMSP430X] in { let Constraints = "$rs = $rd", Defs = [SR] in { - multiclass IIExtExcRot OpCode> { + multiclass IIExtExcRot OpCode, SDNode OpNode> { def _16 : IIExtExcRotForm16; + !strconcat(Mnemonic, "\t$cnt, $rd"), + [(set GR16:$rd, (OpNode GR16:$rs, (i8 rpt2imm:$cnt))), + (implicit SR)]>; } - defm RRAM : IIExtExcRot<"rram", 0b01>; - defm RRUM : IIExtExcRot<"rrum", 0b11>; - defm RLAM : IIExtExcRot<"rlam", 0b10>; + defm RRAM : IIExtExcRot<"rram", 0b01, MSP430rram>; + defm RRUM : IIExtExcRot<"rrum", 0b11, MSP430rrum>; + defm RLAM : IIExtExcRot<"rlam", 0b10, MSP430rlam>; - multiclass IIExtRot OpCode, bit ZC> { + multiclass IIExtRot OpCode, bit ZC, SDNode OpNode> { let RptCountFlag = 1 in { def _8 : II8rExtended; + !strconcat(Mnemonic, ".b\t$rd"), + [(set GR8:$rd, (OpNode GR8:$rs, (i8 rpt4imm:$cnt))), + (implicit SR)]>; def _16 : II16rExtended; + !strconcat(Mnemonic, "\t$rd"), + [(set GR16:$rd, (OpNode GR16:$rs, (i8 rpt4imm:$cnt))), + (implicit SR)]>; } } - defm RRAX : IIExtRot<"rrax", 0b010, 0>; + defm RRAX : IIExtRot<"rrax", 0b010, 0, MSP430rrax>; // RRUX is encoded as RRCX with the ZC flag set. - defm RRUX : IIExtRot<"rrux", 0b000, 1>; + defm RRUX : IIExtRot<"rrux", 0b000, 1, MSP430rrux>; - multiclass IExtRot OpCode> { + multiclass IExtRot OpCode, SDNode OpNode> { let RptCountFlag = 1 in { def _8 : I8rExtended; + !strconcat(Mnemonic, ".b\t$rd"), + [(set GR8:$rd, (OpNode GR8:$rs, (i8 rpt4imm:$cnt))), + (implicit SR)]>; def _16 : I16rExtended; + !strconcat(Mnemonic, "\t$rd"), + [(set GR16:$rd, (OpNode GR16:$rs, (i8 rpt4imm:$cnt))), + (implicit SR)]>; } } // RLAX is encoded as ADDX. - defm RLAX : IExtRot<"rlax", 0b0101>; + defm RLAX : IExtRot<"rlax", 0b0101, MSP430rlax>; } // Defs = [SR], Constraints = "$rs = $rd" diff --git a/llvm/test/CodeGen/MSP430/shift-amount-threshold.ll b/llvm/test/CodeGen/MSP430/shift-amount-threshold.ll --- a/llvm/test/CodeGen/MSP430/shift-amount-threshold.ll +++ b/llvm/test/CodeGen/MSP430/shift-amount-threshold.ll @@ -199,8 +199,7 @@ ; CHECK: ; %bb.0: ; %entry ; CHECK-NEXT: swpb r12 ; CHECK-NEXT: mov.b r12, r12 -; CHECK-NEXT: clrc -; CHECK-NEXT: rrc r12 +; CHECK-NEXT: rra r12 ; CHECK-NEXT: and #64, r12 ; CHECK-NEXT: ret entry: diff --git a/llvm/test/CodeGen/MSP430/shifts-430x-byte.ll b/llvm/test/CodeGen/MSP430/shifts-430x-byte.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/MSP430/shifts-430x-byte.ll @@ -0,0 +1,178 @@ +; Tests for constant shifts of 8-bit register operands, for the 430X CPU. +; +; RUN: llc -mcpu=msp430x < %s | FileCheck %s +target datalayout = "e-p:16:8:8-i8:8:8-i8:8:8-i32:8:8-n8:16" +target triple = "msp430-elf" + +;; Tests for logical right shifts. +define i8 @lshr1(i8 %value) { +; CHECK-LABEL: lshr1: +; CHECK: clrc +; CHECK-NEXT: rrc.b r12 + %result = lshr i8 %value, 1 + ret i8 %result +} + +define i8 @lshr2(i8 %value) { +; CHECK-LABEL: lshr2: +; CHECK: rpt #2 { rrux.b r12 + %result = lshr i8 %value, 2 + ret i8 %result +} + +define i8 @lshr3(i8 %value) { +; CHECK-LABEL: lshr3: +; CHECK: rpt #3 { rrux.b r12 + %result = lshr i8 %value, 3 + ret i8 %result +} + +define i8 @lshr4(i8 %value) { +; CHECK-LABEL: lshr4: +; CHECK: rpt #4 { rrux.b r12 + %result = lshr i8 %value, 4 + ret i8 %result +} + +define i8 @lshr5(i8 %value) { +; CHECK-LABEL: lshr5: +; CHECK: rpt #5 { rrux.b r12 + %result = lshr i8 %value, 5 + ret i8 %result +} + +define i8 @lshr6(i8 %value) { +; CHECK-LABEL: lshr6: +; CHECK: rpt #6 { rrux.b r12 + %result = lshr i8 %value, 6 + ret i8 %result +} + +define i8 @lshr7(i8 %value) { +; CHECK-LABEL: lshr7: +; CHECK: rpt #7 { rrux.b r12 + %result = lshr i8 %value, 7 + ret i8 %result +} + +define i8 @lshr8(i8 %value) { +; CHECK-LABEL: lshr8: +; CHECK-NOT: rrum +; CHECK-NOT: rrux + %result = lshr i8 %value, 8 + ret i8 %result +} + +;; Tests for arithmetic right shifts. +define i8 @ashr1(i8 %value) { +; CHECK-LABEL: ashr1: +; CHECK: rra.b r12 + %result = ashr i8 %value, 1 + ret i8 %result +} + +define i8 @ashr2(i8 %value) { +; CHECK-LABEL: ashr2: +; CHECK: rpt #2 { rrax.b r12 + %result = ashr i8 %value, 2 + ret i8 %result +} + +define i8 @ashr3(i8 %value) { +; CHECK-LABEL: ashr3: +; CHECK: rpt #3 { rrax.b r12 + %result = ashr i8 %value, 3 + ret i8 %result +} + +define i8 @ashr4(i8 %value) { +; CHECK-LABEL: ashr4: +; CHECK: rpt #4 { rrax.b r12 + %result = ashr i8 %value, 4 + ret i8 %result +} + +define i8 @ashr5(i8 %value) { +; CHECK-LABEL: ashr5: +; CHECK: rpt #5 { rrax.b r12 + %result = ashr i8 %value, 5 + ret i8 %result +} + +define i8 @ashr6(i8 %value) { +; CHECK-LABEL: ashr6: +; CHECK: rpt #6 { rrax.b r12 + %result = ashr i8 %value, 6 + ret i8 %result +} + +define i8 @ashr7(i8 %value) { +; CHECK-LABEL: ashr7: +; CHECK: rpt #7 { rrax.b r12 + %result = ashr i8 %value, 7 + ret i8 %result +} + +define i8 @ashr8(i8 %value) { +; CHECK-LABEL: ashr8: +; CHECK-NOT: rra + %result = ashr i8 %value, 8 + ret i8 %result +} + +;; Tests for logical left shifts. +define i8 @shl1(i8 %value) { +; CHECK-LABEL: shl1: +; CHECK: add.b r12, r12 + %result = shl i8 %value, 1 + ret i8 %result +} + +define i8 @shl2(i8 %value) { +; CHECK-LABEL: shl2: +; CHECK: rpt #2 { rlax.b r12 + %result = shl i8 %value, 2 + ret i8 %result +} + +define i8 @shl3(i8 %value) { +; CHECK-LABEL: shl3: +; CHECK: rpt #3 { rlax.b r12 + %result = shl i8 %value, 3 + ret i8 %result +} + +define i8 @shl4(i8 %value) { +; CHECK-LABEL: shl4: +; CHECK: rpt #4 { rlax.b r12 + %result = shl i8 %value, 4 + ret i8 %result +} + +define i8 @shl5(i8 %value) { +; CHECK-LABEL: shl5: +; CHECK: rpt #5 { rlax.b r12 + %result = shl i8 %value, 5 + ret i8 %result +} + +define i8 @shl6(i8 %value) { +; CHECK-LABEL: shl6: +; CHECK: rpt #6 { rlax.b r12 + %result = shl i8 %value, 6 + ret i8 %result +} + +define i8 @shl7(i8 %value) { +; CHECK-LABEL: shl7: +; CHECK: rpt #7 { rlax.b r12 + %result = shl i8 %value, 7 + ret i8 %result +} + +define i8 @shl8(i8 %value) { +; CHECK-LABEL: shl8: +; CHECK-NOT: rla + %result = shl i8 %value, 8 + ret i8 %result +} diff --git a/llvm/test/CodeGen/MSP430/shifts-430x-word.ll b/llvm/test/CodeGen/MSP430/shifts-430x-word.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/MSP430/shifts-430x-word.ll @@ -0,0 +1,766 @@ +; Tests for constant shifts of 16-bit register operands, for the 430X CPU. +; +; RUN: llc -mcpu=msp430x < %s | FileCheck %s +target datalayout = "e-p:16:8:8-i8:8:8-i16:8:8-i32:8:8-n8:16" +target triple = "msp430-elf" + +;; Tests for logical right shifts. +define i16 @lshr1(i16 %value) { +; CHECK-LABEL: lshr1: +; CHECK: rrum #1, r12 + %result = lshr i16 %value, 1 + ret i16 %result +} + +define i16 @lshr2(i16 %value) { +; CHECK-LABEL: lshr2: +; CHECK: rrum #2, r12 + %result = lshr i16 %value, 2 + ret i16 %result +} + +define i16 @lshr3(i16 %value) { +; CHECK-LABEL: lshr3: +; CHECK: rrum #3, r12 + %result = lshr i16 %value, 3 + ret i16 %result +} + +define i16 @lshr4(i16 %value) { +; CHECK-LABEL: lshr4: +; CHECK: rrum #4, r12 + %result = lshr i16 %value, 4 + ret i16 %result +} + +define i16 @lshr5(i16 %value) { +; CHECK-LABEL: lshr5: +; CHECK: rrum #4, r12 +; CHECK-NEXT: rrum #1, r12 + %result = lshr i16 %value, 5 + ret i16 %result +} + +define i16 @lshr6(i16 %value) { +; CHECK-LABEL: lshr6: +; CHECK: rrum #4, r12 +; CHECK-NEXT: rrum #2, r12 + %result = lshr i16 %value, 6 + ret i16 %result +} + +define i16 @lshr7(i16 %value) { +; CHECK-LABEL: lshr7: +; CHECK: rrum #4, r12 +; CHECK-NEXT: rrum #3, r12 + %result = lshr i16 %value, 7 + ret i16 %result +} + +define i16 @lshr8(i16 %value) { +; CHECK-LABEL: lshr8: +; CHECK: swpb r12 +; CHECK-NEXT: mov.b r12, r12 + %result = lshr i16 %value, 8 + ret i16 %result +} + +define i16 @lshr9(i16 %value) { +; CHECK-LABEL: lshr9: +; CHECK: swpb r12 +; CHECK-NEXT: mov.b r12, r12 +; CHECK-NEXT: rrum #1, r12 + %result = lshr i16 %value, 9 + ret i16 %result +} + +define i16 @lshr10(i16 %value) { +; CHECK-LABEL: lshr10: +; CHECK: swpb r12 +; CHECK-NEXT: mov.b r12, r12 +; CHECK-NEXT: rrum #2, r12 + %result = lshr i16 %value, 10 + ret i16 %result +} + +define i16 @lshr11(i16 %value) { +; CHECK-LABEL: lshr11: +; CHECK: swpb r12 +; CHECK-NEXT: mov.b r12, r12 +; CHECK-NEXT: rrum #3, r12 + %result = lshr i16 %value, 11 + ret i16 %result +} + +define i16 @lshr12(i16 %value) { +; CHECK-LABEL: lshr12: +; CHECK: swpb r12 +; CHECK-NEXT: mov.b r12, r12 +; CHECK-NEXT: rrum #4, r12 + %result = lshr i16 %value, 12 + ret i16 %result +} + +define i16 @lshr13(i16 %value) { +; CHECK-LABEL: lshr13: +; CHECK: swpb r12 +; CHECK-NEXT: mov.b r12, r12 +; CHECK-NEXT: rrum #4, r12 +; CHECK-NEXT: rrum #1, r12 + %result = lshr i16 %value, 13 + ret i16 %result +} + +define i16 @lshr14(i16 %value) { +; CHECK-LABEL: lshr14: +; CHECK: swpb r12 +; CHECK-NEXT: mov.b r12, r12 +; CHECK-NEXT: rrum #4, r12 +; CHECK-NEXT: rrum #2, r12 + %result = lshr i16 %value, 14 + ret i16 %result +} + +define i16 @lshr15(i16 %value) { +; CHECK-LABEL: lshr15: +; CHECK: swpb r12 +; CHECK-NEXT: mov.b r12, r12 +; CHECK-NEXT: rrum #4, r12 +; CHECK-NEXT: rrum #3, r12 + %result = lshr i16 %value, 15 + ret i16 %result +} + +define i16 @lshr16(i16 %value) { +; CHECK-LABEL: lshr16: +; CHECK-NOT: rrum +; CHECK-NOT: rrux + %result = lshr i16 %value, 16 + ret i16 %result +} + +;; Tests for arithmetic right shifts. +define i16 @ashr1(i16 %value) { +; CHECK-LABEL: ashr1: +; CHECK: rra r12 + %result = ashr i16 %value, 1 + ret i16 %result +} + +define i16 @ashr2(i16 %value) { +; CHECK-LABEL: ashr2: +; CHECK: rram #2, r12 + %result = ashr i16 %value, 2 + ret i16 %result +} + +define i16 @ashr3(i16 %value) { +; CHECK-LABEL: ashr3: +; CHECK: rram #3, r12 + %result = ashr i16 %value, 3 + ret i16 %result +} + +define i16 @ashr4(i16 %value) { +; CHECK-LABEL: ashr4: +; CHECK: rram #4, r12 + %result = ashr i16 %value, 4 + ret i16 %result +} + +define i16 @ashr5(i16 %value) { +; CHECK-LABEL: ashr5: +; CHECK: rram #4, r12 +; CHECK-NEXT: rram #1, r12 + %result = ashr i16 %value, 5 + ret i16 %result +} + +define i16 @ashr6(i16 %value) { +; CHECK-LABEL: ashr6: +; CHECK: rram #4, r12 +; CHECK-NEXT: rram #2, r12 + %result = ashr i16 %value, 6 + ret i16 %result +} + +define i16 @ashr7(i16 %value) { +; CHECK-LABEL: ashr7: +; CHECK: rram #4, r12 +; CHECK-NEXT: rram #3, r12 + %result = ashr i16 %value, 7 + ret i16 %result +} + +define i16 @ashr8(i16 %value) { +; CHECK-LABEL: ashr8: +; CHECK: swpb r12 +; CHECK-NEXT: sxt r12 + %result = ashr i16 %value, 8 + ret i16 %result +} + +define i16 @ashr9(i16 %value) { +; CHECK-LABEL: ashr9: +; CHECK: swpb r12 +; CHECK-NEXT: sxt r12 +; CHECK-NEXT: rram #1, r12 + %result = ashr i16 %value, 9 + ret i16 %result +} + +define i16 @ashr10(i16 %value) { +; CHECK-LABEL: ashr10: +; CHECK: swpb r12 +; CHECK-NEXT: sxt r12 +; CHECK-NEXT: rram #2, r12 + %result = ashr i16 %value, 10 + ret i16 %result +} + +define i16 @ashr11(i16 %value) { +; CHECK-LABEL: ashr11: +; CHECK: swpb r12 +; CHECK-NEXT: sxt r12 +; CHECK-NEXT: rram #3, r12 + %result = ashr i16 %value, 11 + ret i16 %result +} + +define i16 @ashr12(i16 %value) { +; CHECK-LABEL: ashr12: +; CHECK: swpb r12 +; CHECK-NEXT: sxt r12 +; CHECK-NEXT: rram #4, r12 + %result = ashr i16 %value, 12 + ret i16 %result +} + +define i16 @ashr13(i16 %value) { +; CHECK-LABEL: ashr13: +; CHECK: swpb r12 +; CHECK-NEXT: sxt r12 +; CHECK-NEXT: rram #4, r12 +; CHECK-NEXT: rram #1, r12 + %result = ashr i16 %value, 13 + ret i16 %result +} + +define i16 @ashr14(i16 %value) { +; CHECK-LABEL: ashr14: +; CHECK: swpb r12 +; CHECK-NEXT: sxt r12 +; CHECK-NEXT: rram #4, r12 +; CHECK-NEXT: rram #2, r12 + %result = ashr i16 %value, 14 + ret i16 %result +} + +define i16 @ashr15(i16 %value) { +; CHECK-LABEL: ashr15: +; CHECK: swpb r12 +; CHECK-NEXT: sxt r12 +; CHECK-NEXT: rram #4, r12 +; CHECK-NEXT: rram #3, r12 + %result = ashr i16 %value, 15 + ret i16 %result +} + +define i16 @ashr16(i16 %value) { +; CHECK-LABEL: ashr16: +; CHECK-NOT: rram +; CHECK-NOT: rrax + %result = ashr i16 %value, 16 + ret i16 %result +} + +;; Tests for logical left shifts. +define i16 @shl1(i16 %value) { +; CHECK-LABEL: shl1: +; CHECK: add r12, r12 + %result = shl i16 %value, 1 + ret i16 %result +} + +define i16 @shl2(i16 %value) { +; CHECK-LABEL: shl2: +; CHECK: rlam #2, r12 + %result = shl i16 %value, 2 + ret i16 %result +} + +define i16 @shl3(i16 %value) { +; CHECK-LABEL: shl3: +; CHECK: rlam #3, r12 + %result = shl i16 %value, 3 + ret i16 %result +} + +define i16 @shl4(i16 %value) { +; CHECK-LABEL: shl4: +; CHECK: rlam #4, r12 + %result = shl i16 %value, 4 + ret i16 %result +} + +define i16 @shl5(i16 %value) { +; CHECK-LABEL: shl5: +; CHECK: rlam #4, r12 +; CHECK-NEXT: rlam #1, r12 + %result = shl i16 %value, 5 + ret i16 %result +} + +define i16 @shl6(i16 %value) { +; CHECK-LABEL: shl6: +; CHECK: rlam #4, r12 +; CHECK-NEXT: rlam #2, r12 + %result = shl i16 %value, 6 + ret i16 %result +} + +define i16 @shl7(i16 %value) { +; CHECK-LABEL: shl7: +; CHECK: rlam #4, r12 +; CHECK-NEXT: rlam #3, r12 + %result = shl i16 %value, 7 + ret i16 %result +} + +define i16 @shl8(i16 %value) { +; CHECK-LABEL: shl8: +; CHECK: mov.b r12, r12 +; CHECK-NEXT: swpb r12 + %result = shl i16 %value, 8 + ret i16 %result +} + +define i16 @shl9(i16 %value) { +; CHECK-LABEL: shl9: +; CHECK: mov.b r12, r12 +; CHECK-NEXT: swpb r12 +; CHECK-NEXT: rlam #1, r12 + %result = shl i16 %value, 9 + ret i16 %result +} + +define i16 @shl10(i16 %value) { +; CHECK-LABEL: shl10: +; CHECK: mov.b r12, r12 +; CHECK-NEXT: swpb r12 +; CHECK-NEXT: rlam #2, r12 + %result = shl i16 %value, 10 + ret i16 %result +} + +define i16 @shl11(i16 %value) { +; CHECK-LABEL: shl11: +; CHECK: mov.b r12, r12 +; CHECK-NEXT: swpb r12 +; CHECK-NEXT: rlam #3, r12 + %result = shl i16 %value, 11 + ret i16 %result +} + +define i16 @shl12(i16 %value) { +; CHECK-LABEL: shl12: +; CHECK: mov.b r12, r12 +; CHECK-NEXT: swpb r12 +; CHECK-NEXT: rlam #4, r12 + %result = shl i16 %value, 12 + ret i16 %result +} + +define i16 @shl13(i16 %value) { +; CHECK-LABEL: shl13: +; CHECK: mov.b r12, r12 +; CHECK-NEXT: swpb r12 +; CHECK-NEXT: rlam #4, r12 +; CHECK-NEXT: rlam #1, r12 + %result = shl i16 %value, 13 + ret i16 %result +} + +define i16 @shl14(i16 %value) { +; CHECK-LABEL: shl14: +; CHECK: mov.b r12, r12 +; CHECK-NEXT: swpb r12 +; CHECK-NEXT: rlam #4, r12 +; CHECK-NEXT: rlam #2, r12 + %result = shl i16 %value, 14 + ret i16 %result +} + +define i16 @shl15(i16 %value) { +; CHECK-LABEL: shl15: +; CHECK: mov.b r12, r12 +; CHECK-NEXT: swpb r12 +; CHECK-NEXT: rlam #4, r12 +; CHECK-NEXT: rlam #3, r12 + %result = shl i16 %value, 15 + ret i16 %result +} + +define i16 @shl16(i16 %value) { +; CHECK-LABEL: shl16: +; CHECK-NOT: rlam +; CHECK-NOT: rlax + %result = shl i16 %value, 16 + ret i16 %result +} + +;; Begin tests for shifts, when optimizing for size. +;;-------------------------------------------------- +;; Tests for logical right shifts, when optimizing for size. +define i16 @lshr1_s(i16 %value) optsize { +; CHECK-LABEL: lshr1_s: +; CHECK: rrum #1, r12 + %result = lshr i16 %value, 1 + ret i16 %result +} + +define i16 @lshr2_s(i16 %value) optsize { +; CHECK-LABEL: lshr2_s: +; CHECK: rrum #2, r12 + %result = lshr i16 %value, 2 + ret i16 %result +} + +define i16 @lshr3_s(i16 %value) optsize { +; CHECK-LABEL: lshr3_s: +; CHECK: rrum #3, r12 + %result = lshr i16 %value, 3 + ret i16 %result +} + +define i16 @lshr4_s(i16 %value) optsize { +; CHECK-LABEL: lshr4_s: +; CHECK: rrum #4, r12 + %result = lshr i16 %value, 4 + ret i16 %result +} + +define i16 @lshr5_s(i16 %value) optsize { +; CHECK-LABEL: lshr5_s: +; CHECK: rrum #4, r12 +; CHECK-NEXT: rrum #1, r12 + %result = lshr i16 %value, 5 + ret i16 %result +} + +define i16 @lshr6_s(i16 %value) optsize { +; CHECK-LABEL: lshr6_s: +; CHECK: rrum #4, r12 +; CHECK-NEXT: rrum #2, r12 + %result = lshr i16 %value, 6 + ret i16 %result +} + +define i16 @lshr7_s(i16 %value) optsize { +; CHECK-LABEL: lshr7_s: +; CHECK: rrum #4, r12 +; CHECK-NEXT: rrum #3, r12 + %result = lshr i16 %value, 7 + ret i16 %result +} + +define i16 @lshr8_s(i16 %value) optsize { +; CHECK-LABEL: lshr8_s: +; CHECK: swpb r12 +; CHECK-NEXT: mov.b r12, r12 + %result = lshr i16 %value, 8 + ret i16 %result +} + +define i16 @lshr9_s(i16 %value) optsize { +; CHECK-LABEL: lshr9_s: +; CHECK: rpt #9 { rrux r12 + %result = lshr i16 %value, 9 + ret i16 %result +} + +define i16 @lshr10_s(i16 %value) optsize { +; CHECK-LABEL: lshr10_s: +; CHECK: rpt #10 { rrux r12 + %result = lshr i16 %value, 10 + ret i16 %result +} + +define i16 @lshr11_s(i16 %value) optsize { +; CHECK-LABEL: lshr11_s: +; CHECK: rpt #11 { rrux r12 + %result = lshr i16 %value, 11 + ret i16 %result +} + +define i16 @lshr12_s(i16 %value) optsize { +; CHECK-LABEL: lshr12_s: +; CHECK: rpt #12 { rrux r12 + %result = lshr i16 %value, 12 + ret i16 %result +} + +define i16 @lshr13_s(i16 %value) optsize { +; CHECK-LABEL: lshr13_s: +; CHECK: rpt #13 { rrux r12 + %result = lshr i16 %value, 13 + ret i16 %result +} + +define i16 @lshr14_s(i16 %value) optsize { +; CHECK-LABEL: lshr14_s: +; CHECK: rpt #14 { rrux r12 + %result = lshr i16 %value, 14 + ret i16 %result +} + +define i16 @lshr15_s(i16 %value) optsize { +; CHECK-LABEL: lshr15_s: +; CHECK: rpt #15 { rrux r12 + %result = lshr i16 %value, 15 + ret i16 %result +} + +define i16 @lshr16_s(i16 %value) optsize { +; CHECK-LABEL: lshr16_s: +; CHECK-NOT: rrum +; CHECK-NOT: rrux + %result = lshr i16 %value, 16 + ret i16 %result +} + +;; Tests for arithmetic right shifts, when optimizing for size. +define i16 @ashr1_s(i16 %value) optsize { +; CHECK-LABEL: ashr1_s: +; CHECK: rra r12 + %result = ashr i16 %value, 1 + ret i16 %result +} + +define i16 @ashr2_s(i16 %value) optsize { +; CHECK-LABEL: ashr2_s: +; CHECK: rram #2, r12 + %result = ashr i16 %value, 2 + ret i16 %result +} + +define i16 @ashr3_s(i16 %value) optsize { +; CHECK-LABEL: ashr3_s: +; CHECK: rram #3, r12 + %result = ashr i16 %value, 3 + ret i16 %result +} + +define i16 @ashr4_s(i16 %value) optsize { +; CHECK-LABEL: ashr4_s: +; CHECK: rram #4, r12 + %result = ashr i16 %value, 4 + ret i16 %result +} + +define i16 @ashr5_s(i16 %value) optsize { +; CHECK-LABEL: ashr5_s: +; CHECK: rram #4, r12 +; CHECK-NEXT: rram #1, r12 + %result = ashr i16 %value, 5 + ret i16 %result +} + +define i16 @ashr6_s(i16 %value) optsize { +; CHECK-LABEL: ashr6_s: +; CHECK: rram #4, r12 +; CHECK-NEXT: rram #2, r12 + %result = ashr i16 %value, 6 + ret i16 %result +} + +define i16 @ashr7_s(i16 %value) optsize { +; CHECK-LABEL: ashr7_s: +; CHECK: rram #4, r12 +; CHECK-NEXT: rram #3, r12 + %result = ashr i16 %value, 7 + ret i16 %result +} + +define i16 @ashr8_s(i16 %value) optsize { +; CHECK-LABEL: ashr8_s: +; CHECK: swpb r12 +; CHECK-NEXT: sxt r12 + %result = ashr i16 %value, 8 + ret i16 %result +} + +define i16 @ashr9_s(i16 %value) optsize { +; CHECK-LABEL: ashr9_s: +; CHECK: rpt #9 { rrax r12 + %result = ashr i16 %value, 9 + ret i16 %result +} + +define i16 @ashr10_s(i16 %value) optsize { +; CHECK-LABEL: ashr10_s: +; CHECK: rpt #10 { rrax r12 + %result = ashr i16 %value, 10 + ret i16 %result +} + +define i16 @ashr11_s(i16 %value) optsize { +; CHECK-LABEL: ashr11_s: +; CHECK: rpt #11 { rrax r12 + %result = ashr i16 %value, 11 + ret i16 %result +} + +define i16 @ashr12_s(i16 %value) optsize { +; CHECK-LABEL: ashr12_s: +; CHECK: rpt #12 { rrax r12 + %result = ashr i16 %value, 12 + ret i16 %result +} + +define i16 @ashr13_s(i16 %value) optsize { +; CHECK-LABEL: ashr13_s: +; CHECK: rpt #13 { rrax r12 + %result = ashr i16 %value, 13 + ret i16 %result +} + +define i16 @ashr14_s(i16 %value) optsize { +; CHECK-LABEL: ashr14_s: +; CHECK: rpt #14 { rrax r12 + %result = ashr i16 %value, 14 + ret i16 %result +} + +define i16 @ashr15_s(i16 %value) optsize { +; CHECK-LABEL: ashr15_s: +; CHECK: rpt #15 { rrax r12 + %result = ashr i16 %value, 15 + ret i16 %result +} + +define i16 @ashr16_s(i16 %value) optsize { +; CHECK-LABEL: ashr16_s: +; CHECK-NOT: rram +; CHECK-NOT: rrax + %result = ashr i16 %value, 16 + ret i16 %result +} + +;; Tests for logical left shifts, when optimizing for size. +define i16 @shl1_s(i16 %value) optsize { +; CHECK-LABEL: shl1_s: +; CHECK: add r12, r12 + %result = shl i16 %value, 1 + ret i16 %result +} + +define i16 @shl2_s(i16 %value) optsize { +; CHECK-LABEL: shl2_s: +; CHECK: rlam #2, r12 + %result = shl i16 %value, 2 + ret i16 %result +} + +define i16 @shl3_s(i16 %value) optsize { +; CHECK-LABEL: shl3_s: +; CHECK: rlam #3, r12 + %result = shl i16 %value, 3 + ret i16 %result +} + +define i16 @shl4_s(i16 %value) optsize { +; CHECK-LABEL: shl4_s: +; CHECK: rlam #4, r12 + %result = shl i16 %value, 4 + ret i16 %result +} + +define i16 @shl5_s(i16 %value) optsize { +; CHECK-LABEL: shl5_s: +; CHECK: rlam #4, r12 +; CHECK-NEXT: rlam #1, r12 + %result = shl i16 %value, 5 + ret i16 %result +} + +define i16 @shl6_s(i16 %value) optsize { +; CHECK-LABEL: shl6_s: +; CHECK: rlam #4, r12 +; CHECK-NEXT: rlam #2, r12 + %result = shl i16 %value, 6 + ret i16 %result +} + +define i16 @shl7_s(i16 %value) optsize { +; CHECK-LABEL: shl7_s: +; CHECK: rlam #4, r12 +; CHECK-NEXT: rlam #3, r12 + %result = shl i16 %value, 7 + ret i16 %result +} + +define i16 @shl8_s(i16 %value) optsize { +; CHECK-LABEL: shl8_s: +; CHECK: mov.b r12, r12 +; CHECK-NEXT: swpb r12 + %result = shl i16 %value, 8 + ret i16 %result +} + +define i16 @shl9_s(i16 %value) optsize { +; CHECK-LABEL: shl9_s: +; CHECK: rpt #9 { rlax r12 + %result = shl i16 %value, 9 + ret i16 %result +} + +define i16 @shl10_s(i16 %value) optsize { +; CHECK-LABEL: shl10_s: +; CHECK: rpt #10 { rlax r12 + %result = shl i16 %value, 10 + ret i16 %result +} + +define i16 @shl11_s(i16 %value) optsize { +; CHECK-LABEL: shl11_s: +; CHECK: rpt #11 { rlax r12 + %result = shl i16 %value, 11 + ret i16 %result +} + +define i16 @shl12_s(i16 %value) optsize { +; CHECK-LABEL: shl12_s: +; CHECK: rpt #12 { rlax r12 + %result = shl i16 %value, 12 + ret i16 %result +} + +define i16 @shl13_s(i16 %value) optsize { +; CHECK-LABEL: shl13_s: +; CHECK: rpt #13 { rlax r12 + %result = shl i16 %value, 13 + ret i16 %result +} + +define i16 @shl14_s(i16 %value) optsize { +; CHECK-LABEL: shl14_s: +; CHECK: rpt #14 { rlax r12 + %result = shl i16 %value, 14 + ret i16 %result +} + +define i16 @shl15_s(i16 %value) optsize { +; CHECK-LABEL: shl15_s: +; CHECK: rpt #15 { rlax r12 + %result = shl i16 %value, 15 + ret i16 %result +} + +define i16 @shl16_s(i16 %value) optsize { +; CHECK-LABEL: shl16_s: +; CHECK-NOT: rlam +; CHECK-NOT: rlax + %result = shl i16 %value, 16 + ret i16 %result +} diff --git a/llvm/test/CodeGen/MSP430/shifts.ll b/llvm/test/CodeGen/MSP430/shifts.ll --- a/llvm/test/CodeGen/MSP430/shifts.ll +++ b/llvm/test/CodeGen/MSP430/shifts.ll @@ -68,8 +68,7 @@ ; CHECK-LABEL: lshr10_i16: ; CHECK: swpb r12 ; CHECK-NEXT: mov.b r12, r12 -; CHECK-NEXT: clrc -; CHECK-NEXT: rrc r12 +; CHECK-NEXT: rra r12 ; CHECK-NEXT: rra r12 %shr = lshr i16 %a, 10 ret i16 %shr