Index: llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp =================================================================== --- llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp +++ llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp @@ -1531,6 +1531,30 @@ return true; } +template <> +bool AVRExpandPseudo::expand(Block &MBB, BlockIt MBBI) { + MachineInstr &MI = *MBBI; + Register DstLoReg, DstHiReg; + Register DstReg = MI.getOperand(0).getReg(); + bool DstIsDead = MI.getOperand(0).isDead(); + bool DstIsKill = MI.getOperand(1).isKill(); + bool ImpIsDead = MI.getOperand(2).isDead(); + TRI->splitReg(DstReg, DstLoReg, DstHiReg); + + // Only left shift high byte. + auto MIBHI = + buildMI(MBB, MBBI, AVR::ADDRdRr) + .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead)) + .addReg(DstHiReg) + .addReg(DstHiReg, getKillRegState(DstIsKill)); + + if (ImpIsDead) + MIBHI->getOperand(3).setIsDead(); + + MI.eraseFromParent(); + return true; +} + template <> bool AVRExpandPseudo::expand(Block &MBB, BlockIt MBBI) { MachineInstr &MI = *MBBI; @@ -1691,6 +1715,29 @@ return true; } +template <> +bool AVRExpandPseudo::expand(Block &MBB, BlockIt MBBI) { + MachineInstr &MI = *MBBI; + Register DstLoReg, DstHiReg; + Register DstReg = MI.getOperand(0).getReg(); + bool DstIsDead = MI.getOperand(0).isDead(); + bool DstIsKill = MI.getOperand(1).isKill(); + bool ImpIsDead = MI.getOperand(2).isDead(); + TRI->splitReg(DstReg, DstLoReg, DstHiReg); + + // Only logical right shift lower byte. + auto MIBLO = + buildMI(MBB, MBBI, AVR::LSRRd) + .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead)) + .addReg(DstLoReg, getKillRegState(DstIsKill)); + + if (ImpIsDead) + MIBLO->getOperand(2).setIsDead(); + + MI.eraseFromParent(); + return true; +} + template <> bool AVRExpandPseudo::expand(Block &MBB, BlockIt MBBI) { llvm_unreachable("RORW unimplemented"); @@ -1767,6 +1814,29 @@ return true; } +template <> +bool AVRExpandPseudo::expand(Block &MBB, BlockIt MBBI) { + MachineInstr &MI = *MBBI; + Register DstLoReg, DstHiReg; + Register DstReg = MI.getOperand(0).getReg(); + bool DstIsDead = MI.getOperand(0).isDead(); + bool DstIsKill = MI.getOperand(1).isKill(); + bool ImpIsDead = MI.getOperand(2).isDead(); + TRI->splitReg(DstReg, DstLoReg, DstHiReg); + + // Only arithmetic right shift lower byte. + auto MIBLO = + buildMI(MBB, MBBI, AVR::ASRRd) + .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead)) + .addReg(DstLoReg, getKillRegState(DstIsKill)); + + if (ImpIsDead) + MIBLO->getOperand(2).setIsDead(); + + MI.eraseFromParent(); + return true; +} + template <> bool AVRExpandPseudo::expand(Block &MBB, BlockIt MBBI) { MachineInstr &MI = *MBBI; @@ -2090,19 +2160,22 @@ EXPAND(AVR::RORBRd); EXPAND(AVR::LSLWRd); EXPAND(AVR::LSLW4Rd); + EXPAND(AVR::LSLB7Rd); EXPAND(AVR::LSLW8Rd); EXPAND(AVR::LSLW12Rd); + EXPAND(AVR::LSLWHIRd); EXPAND(AVR::LSRWRd); EXPAND(AVR::LSRW4Rd); + EXPAND(AVR::LSRB7Rd); EXPAND(AVR::LSRW8Rd); EXPAND(AVR::LSRW12Rd); + EXPAND(AVR::LSRWLORd); EXPAND(AVR::RORWRd); EXPAND(AVR::ROLWRd); EXPAND(AVR::ASRWRd); - EXPAND(AVR::ASRW8Rd); - EXPAND(AVR::LSLB7Rd); - EXPAND(AVR::LSRB7Rd); EXPAND(AVR::ASRB7Rd); + EXPAND(AVR::ASRW8Rd); + EXPAND(AVR::ASRWLORd); EXPAND(AVR::SEXT); EXPAND(AVR::ZEXT); EXPAND(AVR::SPREAD); Index: llvm/lib/Target/AVR/AVRISelLowering.h =================================================================== --- llvm/lib/Target/AVR/AVRISelLowering.h +++ llvm/lib/Target/AVR/AVRISelLowering.h @@ -37,17 +37,20 @@ WRAPPER, LSL, ///< Logical shift left. LSL4, ///< Logical shift left 4 bits. + LSL7, ///< Logical shift left 7 bits. LSL8, ///< Logical shift left 8 bits. LSL12, ///< Logical shift left 12 bits. + LSLHI, ///< Logical shift left higher byte only. LSR, ///< Logical shift right. LSR4, ///< Logical shift right 4 bits. + LSR7, ///< Logical shift right 7 bits. LSR8, ///< Logical shift right 8 bits. LSR12, ///< Logical shift right 12 bits. + LSRLO, ///< Logical shift right lower byte only. ASR, ///< Arithmetic shift right. - ASR8, ///< Arithmetic shift right 8 bits. - LSL7, ///< Logical shift left 7 bits. - LSR7, ///< Logical shift right 7 bits. ASR7, ///< Arithmetic shift right 7 bits. + ASR8, ///< Arithmetic shift right 8 bits. + ASRLO, ///< Arithmetic shift right lower byte only. ROR, ///< Bit rotate right. ROL, ///< Bit rotate left. LSLLOOP, ///< A loop of single logical shift left instructions. Index: llvm/lib/Target/AVR/AVRISelLowering.cpp =================================================================== --- llvm/lib/Target/AVR/AVRISelLowering.cpp +++ llvm/lib/Target/AVR/AVRISelLowering.cpp @@ -269,8 +269,6 @@ } SDValue AVRTargetLowering::LowerShifts(SDValue Op, SelectionDAG &DAG) const { - //:TODO: this function has to be completely rewritten to produce optimal - // code, for now it's producing very long but correct code. unsigned Opc8; const SDNode *N = Op.getNode(); EVT VT = Op.getValueType(); @@ -380,14 +378,20 @@ switch (Op.getOpcode()) { case ISD::SHL: Victim = DAG.getNode(AVRISD::LSL8, dl, VT, Victim); + // Only left shift the higher byte. + Opc8 = AVRISD::LSLHI; ShiftAmount -= 8; break; case ISD::SRL: Victim = DAG.getNode(AVRISD::LSR8, dl, VT, Victim); + // Only logical right shift the lower byte. + Opc8 = AVRISD::LSRLO; ShiftAmount -= 8; break; case ISD::SRA: Victim = DAG.getNode(AVRISD::ASR8, dl, VT, Victim); + // Only arithmetic right shift the lower byte. + Opc8 = AVRISD::ASRLO; ShiftAmount -= 8; break; default: @@ -397,10 +401,14 @@ switch (Op.getOpcode()) { case ISD::SHL: Victim = DAG.getNode(AVRISD::LSL12, dl, VT, Victim); + // Only left shift the higher byte. + Opc8 = AVRISD::LSLHI; ShiftAmount -= 12; break; case ISD::SRL: Victim = DAG.getNode(AVRISD::LSR12, dl, VT, Victim); + // Only logical right shift the lower byte. + Opc8 = AVRISD::LSRLO; ShiftAmount -= 12; break; default: Index: llvm/lib/Target/AVR/AVRInstrInfo.td =================================================================== --- llvm/lib/Target/AVR/AVRInstrInfo.td +++ llvm/lib/Target/AVR/AVRInstrInfo.td @@ -69,6 +69,9 @@ def AVRlsl7 : SDNode<"AVRISD::LSL7", SDTIntUnaryOp>; def AVRlsr7 : SDNode<"AVRISD::LSR7", SDTIntUnaryOp>; def AVRasr7 : SDNode<"AVRISD::ASR7", SDTIntUnaryOp>; +def AVRlslhi : SDNode<"AVRISD::LSLHI", SDTIntUnaryOp>; +def AVRlsrlo : SDNode<"AVRISD::LSRLO", SDTIntUnaryOp>; +def AVRasrlo : SDNode<"AVRISD::ASRLO", SDTIntUnaryOp>; // Pseudo shift nodes for non-constant shift amounts. def AVRlslLoop : SDNode<"AVRISD::LSLLOOP", SDTIntShiftOp>; @@ -1692,9 +1695,14 @@ [(set i16:$rd, (AVRlsl8 i16:$src)), (implicit SREG)]>; def LSLW12Rd : Pseudo<(outs DREGS:$rd), - (ins DREGS:$src), - "lslw12\t$rd", - [(set i16:$rd, (AVRlsl12 i16:$src)), (implicit SREG)]>; + (ins DREGS:$src), + "lslw12\t$rd", + [(set i16:$rd, (AVRlsl12 i16:$src)), (implicit SREG)]>; + + def LSLWHIRd : Pseudo<(outs DREGS:$rd), + (ins DREGS:$src), + "lslwhi\t$rd", + [(set i16:$rd, (AVRlslhi i16:$src)), (implicit SREG)]>; def LSRRd : FRd<0b1001, 0b0100110, @@ -1724,9 +1732,14 @@ [(set i16:$rd, (AVRlsr8 i16:$src)), (implicit SREG)]>; def LSRW12Rd : Pseudo<(outs DREGS:$rd), - (ins DREGS:$src), - "lsrw12\t$rd", - [(set i16:$rd, (AVRlsr12 i16:$src)), (implicit SREG)]>; + (ins DREGS:$src), + "lsrw12\t$rd", + [(set i16:$rd, (AVRlsr12 i16:$src)), (implicit SREG)]>; + + def LSRWLORd : Pseudo<(outs DREGS:$rd), + (ins DREGS:$src), + "lsrwlo\t$rd", + [(set i16:$rd, (AVRlsrlo i16:$src)), (implicit SREG)]>; def ASRRd : FRd<0b1001, 0b0100101, @@ -1750,6 +1763,11 @@ "asrw8\t$rd", [(set i16:$rd, (AVRasr8 i16:$src)), (implicit SREG)]>; + def ASRWLORd : Pseudo<(outs DREGS:$rd), + (ins DREGS:$src), + "asrwlo\t$rd", + [(set i16:$rd, (AVRasrlo i16:$src)), (implicit SREG)]>; + // Bit rotate operations. let Uses = [SREG] in { Index: llvm/test/CodeGen/AVR/shift.ll =================================================================== --- llvm/test/CodeGen/AVR/shift.ll +++ llvm/test/CodeGen/AVR/shift.ll @@ -1,16 +1,19 @@ -; RUN: llc < %s -march=avr | FileCheck %s +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc < %s -mtriple=avr | FileCheck %s ; Optimize for speed. ; CHECK-LABEL: shift_i8_i8_speed define i8 @shift_i8_i8_speed(i8 %a, i8 %b) { - ; CHECK: dec r22 - ; CHECK-NEXT: brmi .LBB0_2 - ; CHECK-NEXT: .LBB0_1: - ; CHECK-NEXT: lsl r24 - ; CHECK-NEXT: dec r22 - ; CHECK-NEXT: brpl .LBB0_1 - ; CHECK-NEXT: .LBB0_2: - ; CHECK-NEXT: ret +; CHECK-LABEL: shift_i8_i8_speed: +; CHECK: ; %bb.0: +; CHECK-NEXT: dec r22 +; CHECK-NEXT: brmi .LBB0_2 +; CHECK-NEXT: .LBB0_1: ; =>This Inner Loop Header: Depth=1 +; CHECK-NEXT: lsl r24 +; CHECK-NEXT: dec r22 +; CHECK-NEXT: brpl .LBB0_1 +; CHECK-NEXT: .LBB0_2: +; CHECK-NEXT: ret %result = shl i8 %a, %b ret i8 %result } @@ -18,253 +21,296 @@ ; Optimize for size (producing slightly smaller code). ; CHECK-LABEL: shift_i8_i8_size define i8 @shift_i8_i8_size(i8 %a, i8 %b) optsize { - ; CHECK: .LBB1_1: - ; CHECK-NEXT: dec r22 - ; CHECK-NEXT: brmi .LBB1_3 - ; CHECK: lsl r24 - ; CHECK-NEXT: rjmp .LBB1_1 - ; CHECK-NEXT: .LBB1_3: - ; CHECK-NEXT: ret +; CHECK-LABEL: shift_i8_i8_size: +; CHECK: ; %bb.0: +; CHECK-NEXT: .LBB1_1: ; =>This Inner Loop Header: Depth=1 +; CHECK-NEXT: dec r22 +; CHECK-NEXT: brmi .LBB1_3 +; CHECK-NEXT: ; %bb.2: ; in Loop: Header=BB1_1 Depth=1 +; CHECK-NEXT: lsl r24 +; CHECK-NEXT: rjmp .LBB1_1 +; CHECK-NEXT: .LBB1_3: +; CHECK-NEXT: ret %result = shl i8 %a, %b ret i8 %result } ; CHECK-LABEL: shift_i16_i16 define i16 @shift_i16_i16(i16 %a, i16 %b) { - ; CHECK: dec r22 - ; CHECK-NEXT: brmi .LBB2_2 - ; CHECK-NEXT: .LBB2_1: - ; CHECK-NEXT: lsl r24 - ; CHECK-NEXT: rol r25 - ; CHECK-NEXT: dec r22 - ; CHECK-NEXT: brpl .LBB2_1 - ; CHECK-NEXT: .LBB2_2: - ; CHECK-NEXT: ret +; CHECK-LABEL: shift_i16_i16: +; CHECK: ; %bb.0: +; CHECK-NEXT: dec r22 +; CHECK-NEXT: brmi .LBB2_2 +; CHECK-NEXT: .LBB2_1: ; =>This Inner Loop Header: Depth=1 +; CHECK-NEXT: lsl r24 +; CHECK-NEXT: rol r25 +; CHECK-NEXT: dec r22 +; CHECK-NEXT: brpl .LBB2_1 +; CHECK-NEXT: .LBB2_2: +; CHECK-NEXT: ret %result = shl i16 %a, %b ret i16 %result } ; CHECK-LABEL: shift_i64_i64 define i64 @shift_i64_i64(i64 %a, i64 %b) { - ; CHECK: call __ashldi3 +; CHECK-LABEL: shift_i64_i64: +; CHECK: ; %bb.0: +; CHECK-NEXT: push r16 +; CHECK-NEXT: mov r16, r10 +; CHECK-NEXT: call __ashldi3 +; CHECK-NEXT: pop r16 +; CHECK-NEXT: ret %result = shl i64 %a, %b ret i64 %result } define i8 @lsl_i8_1(i8 %a) { ; CHECK-LABEL: lsl_i8_1: -; CHECK: lsl r24 +; CHECK: ; %bb.0: +; CHECK-NEXT: lsl r24 +; CHECK-NEXT: ret %res = shl i8 %a, 1 ret i8 %res } define i8 @lsl_i8_2(i8 %a) { ; CHECK-LABEL: lsl_i8_2: -; CHECK: lsl r24 -; CHECK-NEXT: lsl r24 +; CHECK: ; %bb.0: +; CHECK-NEXT: lsl r24 +; CHECK-NEXT: lsl r24 +; CHECK-NEXT: ret %res = shl i8 %a, 2 ret i8 %res } define i8 @lsl_i8_3(i8 %a) { ; CHECK-LABEL: lsl_i8_3: -; CHECK: lsl r24 -; CHECK-NEXT: lsl r24 -; CHECK-NEXT: lsl r24 +; CHECK: ; %bb.0: +; CHECK-NEXT: lsl r24 +; CHECK-NEXT: lsl r24 +; CHECK-NEXT: lsl r24 +; CHECK-NEXT: ret %res = shl i8 %a, 3 ret i8 %res } define i8 @lsl_i8_4(i8 %a) { ; CHECK-LABEL: lsl_i8_4: -; CHECK: swap r24 -; CHECK-NEXT: andi r24, -16 +; CHECK: ; %bb.0: +; CHECK-NEXT: swap r24 +; CHECK-NEXT: andi r24, -16 +; CHECK-NEXT: ret %res = shl i8 %a, 4 ret i8 %res } define i8 @lsl_i8_5(i8 %a) { ; CHECK-LABEL: lsl_i8_5: -; CHECK: swap r24 -; CHECK-NEXT: andi r24, -16 -; CHECK-NEXT: lsl r24 +; CHECK: ; %bb.0: +; CHECK-NEXT: swap r24 +; CHECK-NEXT: andi r24, -16 +; CHECK-NEXT: lsl r24 +; CHECK-NEXT: ret %res = shl i8 %a, 5 ret i8 %res } define i8 @lsl_i8_6(i8 %a) { ; CHECK-LABEL: lsl_i8_6: -; CHECK: swap r24 -; CHECK-NEXT: andi r24, -16 -; CHECK-NEXT: lsl r24 -; CHECK-NEXT: lsl r24 +; CHECK: ; %bb.0: +; CHECK-NEXT: swap r24 +; CHECK-NEXT: andi r24, -16 +; CHECK-NEXT: lsl r24 +; CHECK-NEXT: lsl r24 +; CHECK-NEXT: ret %res = shl i8 %a, 6 ret i8 %res } define i8 @lsr_i8_1(i8 %a) { ; CHECK-LABEL: lsr_i8_1: -; CHECK: lsr r24 +; CHECK: ; %bb.0: +; CHECK-NEXT: lsr r24 +; CHECK-NEXT: ret %res = lshr i8 %a, 1 ret i8 %res } define i8 @lsr_i8_2(i8 %a) { ; CHECK-LABEL: lsr_i8_2: -; CHECK: lsr r24 -; CHECK-NEXT: lsr r24 +; CHECK: ; %bb.0: +; CHECK-NEXT: lsr r24 +; CHECK-NEXT: lsr r24 +; CHECK-NEXT: ret %res = lshr i8 %a, 2 ret i8 %res } define i8 @lsr_i8_3(i8 %a) { ; CHECK-LABEL: lsr_i8_3: -; CHECK: lsr r24 -; CHECK-NEXT: lsr r24 -; CHECK-NEXT: lsr r24 +; CHECK: ; %bb.0: +; CHECK-NEXT: lsr r24 +; CHECK-NEXT: lsr r24 +; CHECK-NEXT: lsr r24 +; CHECK-NEXT: ret %res = lshr i8 %a, 3 ret i8 %res } define i8 @lsr_i8_4(i8 %a) { ; CHECK-LABEL: lsr_i8_4: -; CHECK: swap r24 -; CHECK-NEXT: andi r24, 15 +; CHECK: ; %bb.0: +; CHECK-NEXT: swap r24 +; CHECK-NEXT: andi r24, 15 +; CHECK-NEXT: ret %res = lshr i8 %a, 4 ret i8 %res } define i8 @lsr_i8_5(i8 %a) { ; CHECK-LABEL: lsr_i8_5: -; CHECK: swap r24 -; CHECK-NEXT: andi r24, 15 -; CHECK-NEXT: lsr r24 +; CHECK: ; %bb.0: +; CHECK-NEXT: swap r24 +; CHECK-NEXT: andi r24, 15 +; CHECK-NEXT: lsr r24 +; CHECK-NEXT: ret %res = lshr i8 %a, 5 ret i8 %res } define i8 @lsr_i8_6(i8 %a) { ; CHECK-LABEL: lsr_i8_6: -; CHECK: swap r24 -; CHECK-NEXT: andi r24, 15 -; CHECK-NEXT: lsr r24 -; CHECK-NEXT: lsr r24 +; CHECK: ; %bb.0: +; CHECK-NEXT: swap r24 +; CHECK-NEXT: andi r24, 15 +; CHECK-NEXT: lsr r24 +; CHECK-NEXT: lsr r24 +; CHECK-NEXT: ret %res = lshr i8 %a, 6 ret i8 %res } define i8 @lsl_i8_7(i8 %a) { -; CHECK-LABEL: lsl_i8_7 -; CHECK: ror r24 -; CHECK-NEXT: clr r24 -; CHECK-NEXT: ror r24 +; CHECK-LABEL: lsl_i8_7: +; CHECK: ; %bb.0: +; CHECK-NEXT: ror r24 +; CHECK-NEXT: clr r24 +; CHECK-NEXT: ror r24 +; CHECK-NEXT: ret %result = shl i8 %a, 7 ret i8 %result } define i8 @lsr_i8_7(i8 %a) { -; CHECK-LABEL: lsr_i8_7 -; CHECK: rol r24 -; CHECK-NEXT: clr r24 -; CHECK-NEXT: rol r24 +; CHECK-LABEL: lsr_i8_7: +; CHECK: ; %bb.0: +; CHECK-NEXT: rol r24 +; CHECK-NEXT: clr r24 +; CHECK-NEXT: rol r24 +; CHECK-NEXT: ret %result = lshr i8 %a, 7 ret i8 %result } define i8 @asr_i8_7(i8 %a) { -; CHECK-LABEL: asr_i8_7 -; CHECK: lsl r24 -; CHECK-NEXT: sbc r24, r24 +; CHECK-LABEL: asr_i8_7: +; CHECK: ; %bb.0: +; CHECK-NEXT: lsl r24 +; CHECK-NEXT: sbc r24, r24 +; CHECK-NEXT: ret %result = ashr i8 %a, 7 ret i8 %result } define i16 @lsl_i16_5(i16 %a) { -; CHECK-LABEL: lsl_i16_5 -; CHECK: swap r25 -; CHECK-NEXT: swap r24 -; CHECK-NEXT: andi r25, 240 -; CHECK-NEXT: eor r25, r24 -; CHECK-NEXT: andi r24, 240 -; CHECK-NEXT: eor r25, r24 -; CHECK-NEXT: lsl r24 -; CHECK-NEXT: rol r25 -; CHECK-NEXT: ret +; CHECK-LABEL: lsl_i16_5: +; CHECK: ; %bb.0: +; CHECK-NEXT: swap r25 +; CHECK-NEXT: swap r24 +; CHECK-NEXT: andi r25, 240 +; CHECK-NEXT: eor r25, r24 +; CHECK-NEXT: andi r24, 240 +; CHECK-NEXT: eor r25, r24 +; CHECK-NEXT: lsl r24 +; CHECK-NEXT: rol r25 +; CHECK-NEXT: ret %result = shl i16 %a, 5 ret i16 %result } define i16 @lsl_i16_9(i16 %a) { -; CHECK-LABEL: lsl_i16_9 -; CHECK: mov r25, r24 -; CHECK-NEXT: clr r24 -; CHECK-NEXT: lsl r24 -; CHECK-NEXT: rol r25 -; CHECK-NEXT: ret +; CHECK-LABEL: lsl_i16_9: +; CHECK: ; %bb.0: +; CHECK-NEXT: mov r25, r24 +; CHECK-NEXT: clr r24 +; CHECK-NEXT: lsl r25 +; CHECK-NEXT: ret %result = shl i16 %a, 9 ret i16 %result } define i16 @lsl_i16_13(i16 %a) { -; CHECK-LABEL: lsl_i16_13 -; CHECK: mov r25, r24 -; CHECK-NEXT: swap r25 -; CHECK-NEXT: andi r25, 240 -; CHECK-NEXT: clr r24 -; CHECK-NEXT: lsl r24 -; CHECK-NEXT: rol r25 -; CHECK-NEXT: ret +; CHECK-LABEL: lsl_i16_13: +; CHECK: ; %bb.0: +; CHECK-NEXT: mov r25, r24 +; CHECK-NEXT: swap r25 +; CHECK-NEXT: andi r25, 240 +; CHECK-NEXT: clr r24 +; CHECK-NEXT: lsl r25 +; CHECK-NEXT: ret %result = shl i16 %a, 13 ret i16 %result } define i16 @lsr_i16_5(i16 %a) { -; CHECK-LABEL: lsr_i16_5 -; CHECK: swap r25 -; CHECK-NEXT: swap r24 -; CHECK-NEXT: andi r24, 15 -; CHECK-NEXT: eor r24, r25 -; CHECK-NEXT: andi r25, 15 -; CHECK-NEXT: eor r24, r25 -; CHECK-NEXT: lsr r25 -; CHECK-NEXT: ror r24 -; CHECK-NEXT: ret +; CHECK-LABEL: lsr_i16_5: +; CHECK: ; %bb.0: +; CHECK-NEXT: swap r25 +; CHECK-NEXT: swap r24 +; CHECK-NEXT: andi r24, 15 +; CHECK-NEXT: eor r24, r25 +; CHECK-NEXT: andi r25, 15 +; CHECK-NEXT: eor r24, r25 +; CHECK-NEXT: lsr r25 +; CHECK-NEXT: ror r24 +; CHECK-NEXT: ret %result = lshr i16 %a, 5 ret i16 %result } define i16 @lsr_i16_9(i16 %a) { -; CHECK-LABEL: lsr_i16_9 -; CHECK: mov r24, r25 -; CHECK-NEXT: clr r25 -; CHECK-NEXT: lsr r25 -; CHECK-NEXT: ror r24 -; CHECK-NEXT: ret +; CHECK-LABEL: lsr_i16_9: +; CHECK: ; %bb.0: +; CHECK-NEXT: mov r24, r25 +; CHECK-NEXT: clr r25 +; CHECK-NEXT: lsr r24 +; CHECK-NEXT: ret %result = lshr i16 %a, 9 ret i16 %result } define i16 @lsr_i16_13(i16 %a) { -; CHECK-LABEL: lsr_i16_13 -; CHECK: mov r24, r25 -; CHECK-NEXT: swap r24 -; CHECK-NEXT: andi r24, 15 -; CHECK-NEXT: clr r25 -; CHECK-NEXT: lsr r25 -; CHECK-NEXT: ror r24 -; CHECK-NEXT: ret +; CHECK-LABEL: lsr_i16_13: +; CHECK: ; %bb.0: +; CHECK-NEXT: mov r24, r25 +; CHECK-NEXT: swap r24 +; CHECK-NEXT: andi r24, 15 +; CHECK-NEXT: clr r25 +; CHECK-NEXT: lsr r24 +; CHECK-NEXT: ret %result = lshr i16 %a, 13 ret i16 %result } define i16 @asr_i16_9(i16 %a) { -; CHECK-LABEL: asr_i16_9 -; CHECK: mov r24, r25 -; CHECK-NEXT: lsl r25 -; CHECK-NEXT: sbc r25, r25 -; CHECK-NEXT: asr r25 -; CHECK-NEXT: ror r24 -; CHECK-NEXT: ret +; CHECK-LABEL: asr_i16_9: +; CHECK: ; %bb.0: +; CHECK-NEXT: mov r24, r25 +; CHECK-NEXT: lsl r25 +; CHECK-NEXT: sbc r25, r25 +; CHECK-NEXT: asr r24 +; CHECK-NEXT: ret %result = ashr i16 %a, 9 ret i16 %result }