diff --git a/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp b/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp --- a/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp +++ b/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp @@ -1488,10 +1488,12 @@ // multiple registers, but when we actually need to rotate stuff, we have // to explicitly add the carry bit. + const AVRSubtarget &STI = MBB.getParent()->getSubtarget(); + MachineInstr &MI = *MBBI; unsigned OpShift, OpCarry; Register DstReg = MI.getOperand(0).getReg(); - Register ZeroReg = MI.getOperand(2).getReg(); + Register ZeroReg = STI.getZeroRegister(); bool DstIsDead = MI.getOperand(0).isDead(); bool DstIsKill = MI.getOperand(1).isKill(); OpShift = AVR::ADDRdRr; diff --git a/llvm/lib/Target/AVR/AVRISelLowering.cpp b/llvm/lib/Target/AVR/AVRISelLowering.cpp --- a/llvm/lib/Target/AVR/AVRISelLowering.cpp +++ b/llvm/lib/Target/AVR/AVRISelLowering.cpp @@ -1755,7 +1755,6 @@ unsigned Opc; const TargetRegisterClass *RC; bool HasRepeatedOperand = false; - bool HasZeroOperand = false; MachineFunction *F = BB->getParent(); MachineRegisterInfo &RI = F->getRegInfo(); const TargetInstrInfo &TII = *Subtarget.getInstrInfo(); @@ -1792,7 +1791,6 @@ case AVR::Rol8: Opc = AVR::ROLBRd; RC = &AVR::GPR8RegClass; - HasZeroOperand = true; break; case AVR::Rol16: Opc = AVR::ROLWRd; @@ -1854,8 +1852,6 @@ auto ShiftMI = BuildMI(LoopBB, dl, TII.get(Opc), ShiftReg2).addReg(ShiftReg); if (HasRepeatedOperand) ShiftMI.addReg(ShiftReg); - if (HasZeroOperand) - ShiftMI.addReg(Subtarget.getZeroRegister()); // CheckBB: // ShiftReg = phi [%SrcReg, BB], [%ShiftReg2, LoopBB] diff --git a/llvm/lib/Target/AVR/AVRInstrInfo.td b/llvm/lib/Target/AVR/AVRInstrInfo.td --- a/llvm/lib/Target/AVR/AVRInstrInfo.td +++ b/llvm/lib/Target/AVR/AVRInstrInfo.td @@ -2029,12 +2029,15 @@ def ASRWLoRd : Pseudo<(outs DREGS:$rd), (ins DREGS:$src), "asrwlo\t$rd", [(set i16:$rd, (AVRasrlo i16:$src)), (implicit SREG)]>; - let hasSideEffects=0 in def ROLBRd : Pseudo<(outs GPR8 : $rd), - (ins GPR8:$src, GPR8:$zero), + (ins GPR8 + : $src), "rolb\t$rd", - []>; + [(set i8 + : $rd, (AVRrol i8 + : $src)), + (implicit SREG)]>; def RORBRd : Pseudo<(outs GPR8 : $rd), diff --git a/llvm/test/CodeGen/AVR/pseudo/ROLBrd.mir b/llvm/test/CodeGen/AVR/pseudo/ROLBrd.mir --- a/llvm/test/CodeGen/AVR/pseudo/ROLBrd.mir +++ b/llvm/test/CodeGen/AVR/pseudo/ROLBrd.mir @@ -20,10 +20,5 @@ ; CHECK: $r14 = ADDRdRr killed $r14, killed $r14, implicit-def $sreg ; CHECK-NEXT: $r14 = ADCRdRr $r14, $r1, implicit-def dead $sreg, implicit killed $sreg - $r14 = ROLBRd $r14, $r1, implicit-def $sreg - - ; avrtiny variant - ; CHECK: $r14 = ADDRdRr killed $r14, killed $r14, implicit-def $sreg - ; CHECK-NEXT: $r14 = ADCRdRr $r14, $r17, implicit-def dead $sreg, implicit killed $sreg - $r14 = ROLBRd $r14, $r17, implicit-def $sreg + $r14 = ROLBRd $r14, implicit-def $sreg ... diff --git a/llvm/test/CodeGen/AVR/rotate.ll b/llvm/test/CodeGen/AVR/rotate.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/AVR/rotate.ll @@ -0,0 +1,230 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 2 +; RUN: llc < %s -mtriple=avr | FileCheck %s + +define i8 @rotl8_1(i8 %x) { +; CHECK-LABEL: rotl8_1: +; CHECK: ; %bb.0: ; %start +; CHECK-NEXT: lsl r24 +; CHECK-NEXT: adc r24, r1 +; CHECK-NEXT: ret +start: + %0 = call i8 @llvm.fshl.i8(i8 %x, i8 %x, i8 1) + ret i8 %0 +} + +define i8 @rotl8_3(i8 %x) { +; CHECK-LABEL: rotl8_3: +; CHECK: ; %bb.0: ; %start +; CHECK-NEXT: lsl r24 +; CHECK-NEXT: adc r24, r1 +; CHECK-NEXT: lsl r24 +; CHECK-NEXT: adc r24, r1 +; CHECK-NEXT: lsl r24 +; CHECK-NEXT: adc r24, r1 +; CHECK-NEXT: ret +start: + %0 = call i8 @llvm.fshl.i8(i8 %x, i8 %x, i8 3) + ret i8 %0 +} + +define i8 @rotl8_dyn(i8 %x, i8 %y) { +; CHECK-LABEL: rotl8_dyn: +; CHECK: ; %bb.0: ; %start +; CHECK-NEXT: andi r22, 7 +; CHECK-NEXT: dec r22 +; CHECK-NEXT: brmi .LBB2_2 +; CHECK-NEXT: .LBB2_1: ; %start +; CHECK-NEXT: ; =>This Inner Loop Header: Depth=1 +; CHECK-NEXT: lsl r24 +; CHECK-NEXT: adc r24, r1 +; CHECK-NEXT: dec r22 +; CHECK-NEXT: brpl .LBB2_1 +; CHECK-NEXT: .LBB2_2: ; %start +; CHECK-NEXT: ret +start: + %0 = call i8 @llvm.fshl.i8(i8 %x, i8 %x, i8 %y) + ret i8 %0 +} + +define i8 @rotr8_1(i8 %x) { +; CHECK-LABEL: rotr8_1: +; CHECK: ; %bb.0: ; %start +; CHECK-NEXT: bst r24, 0 +; CHECK-NEXT: ror r24 +; CHECK-NEXT: bld r24, 7 +; CHECK-NEXT: ret +start: + %0 = call i8 @llvm.fshr.i8(i8 %x, i8 %x, i8 1) + ret i8 %0 +} + +define i8 @rotr8_3(i8 %x) { +; CHECK-LABEL: rotr8_3: +; CHECK: ; %bb.0: ; %start +; CHECK-NEXT: bst r24, 0 +; CHECK-NEXT: ror r24 +; CHECK-NEXT: bld r24, 7 +; CHECK-NEXT: bst r24, 0 +; CHECK-NEXT: ror r24 +; CHECK-NEXT: bld r24, 7 +; CHECK-NEXT: bst r24, 0 +; CHECK-NEXT: ror r24 +; CHECK-NEXT: bld r24, 7 +; CHECK-NEXT: ret +start: + %0 = call i8 @llvm.fshr.i8(i8 %x, i8 %x, i8 3) + ret i8 %0 +} + +define i8 @rotr8_dyn(i8 %x, i8 %y) { +; CHECK-LABEL: rotr8_dyn: +; CHECK: ; %bb.0: ; %start +; CHECK-NEXT: andi r22, 7 +; CHECK-NEXT: dec r22 +; CHECK-NEXT: brmi .LBB5_2 +; CHECK-NEXT: .LBB5_1: ; %start +; CHECK-NEXT: ; =>This Inner Loop Header: Depth=1 +; CHECK-NEXT: bst r24, 0 +; CHECK-NEXT: ror r24 +; CHECK-NEXT: bld r24, 7 +; CHECK-NEXT: dec r22 +; CHECK-NEXT: brpl .LBB5_1 +; CHECK-NEXT: .LBB5_2: ; %start +; CHECK-NEXT: ret +start: + %0 = call i8 @llvm.fshr.i8(i8 %x, i8 %x, i8 %y) + ret i8 %0 +} + +define i16 @rotl16(i16 %x) { +; CHECK-LABEL: rotl16: +; CHECK: ; %bb.0: ; %start +; CHECK-NEXT: mov r18, r24 +; CHECK-NEXT: mov r19, r25 +; CHECK-NEXT: lsl r18 +; CHECK-NEXT: rol r19 +; CHECK-NEXT: lsl r18 +; CHECK-NEXT: rol r19 +; CHECK-NEXT: mov r24, r25 +; CHECK-NEXT: swap r24 +; CHECK-NEXT: andi r24, 15 +; CHECK-NEXT: clr r25 +; CHECK-NEXT: lsr r24 +; CHECK-NEXT: lsr r24 +; CHECK-NEXT: or r24, r18 +; CHECK-NEXT: or r25, r19 +; CHECK-NEXT: ret +start: + %0 = call i16 @llvm.fshl.i16(i16 %x, i16 %x, i16 2) + ret i16 %0 +} + +define i16 @rotr16(i16 %x) { +; CHECK-LABEL: rotr16: +; CHECK: ; %bb.0: ; %start +; CHECK-NEXT: mov r18, r24 +; CHECK-NEXT: mov r19, r25 +; CHECK-NEXT: lsr r19 +; CHECK-NEXT: ror r18 +; CHECK-NEXT: lsr r19 +; CHECK-NEXT: ror r18 +; CHECK-NEXT: mov r25, r24 +; CHECK-NEXT: swap r25 +; CHECK-NEXT: andi r25, 240 +; CHECK-NEXT: clr r24 +; CHECK-NEXT: lsl r25 +; CHECK-NEXT: lsl r25 +; CHECK-NEXT: or r24, r18 +; CHECK-NEXT: or r25, r19 +; CHECK-NEXT: ret +start: + %0 = call i16 @llvm.fshr.i16(i16 %x, i16 %x, i16 2) + ret i16 %0 +} + +define i32 @rotl32(i32 %x) { +; CHECK-LABEL: rotl32: +; CHECK: ; %bb.0: ; %start +; CHECK-NEXT: mov r20, r22 +; CHECK-NEXT: mov r21, r23 +; CHECK-NEXT: lsl r20 +; CHECK-NEXT: rol r21 +; CHECK-NEXT: lsl r20 +; CHECK-NEXT: rol r21 +; CHECK-NEXT: mov r18, r24 +; CHECK-NEXT: mov r19, r25 +; CHECK-NEXT: mov r18, r19 +; CHECK-NEXT: swap r18 +; CHECK-NEXT: andi r18, 15 +; CHECK-NEXT: clr r19 +; CHECK-NEXT: lsr r18 +; CHECK-NEXT: lsr r18 +; CHECK-NEXT: or r18, r20 +; CHECK-NEXT: or r19, r21 +; CHECK-NEXT: lsl r24 +; CHECK-NEXT: rol r25 +; CHECK-NEXT: lsl r24 +; CHECK-NEXT: rol r25 +; CHECK-NEXT: mov r22, r23 +; CHECK-NEXT: swap r22 +; CHECK-NEXT: andi r22, 15 +; CHECK-NEXT: clr r23 +; CHECK-NEXT: lsr r22 +; CHECK-NEXT: lsr r22 +; CHECK-NEXT: or r24, r22 +; CHECK-NEXT: or r25, r23 +; CHECK-NEXT: mov r22, r18 +; CHECK-NEXT: mov r23, r19 +; CHECK-NEXT: ret +start: + %0 = call i32 @llvm.fshl.i32(i32 %x, i32 %x, i32 2) + ret i32 %0 +} + +define i32 @rotr32(i32 %x) { +; CHECK-LABEL: rotr32: +; CHECK: ; %bb.0: ; %start +; CHECK-NEXT: mov r20, r22 +; CHECK-NEXT: mov r21, r23 +; CHECK-NEXT: lsr r21 +; CHECK-NEXT: ror r20 +; CHECK-NEXT: lsr r21 +; CHECK-NEXT: ror r20 +; CHECK-NEXT: mov r18, r24 +; CHECK-NEXT: mov r19, r25 +; CHECK-NEXT: mov r19, r18 +; CHECK-NEXT: swap r19 +; CHECK-NEXT: andi r19, 240 +; CHECK-NEXT: clr r18 +; CHECK-NEXT: lsl r19 +; CHECK-NEXT: lsl r19 +; CHECK-NEXT: or r18, r20 +; CHECK-NEXT: or r19, r21 +; CHECK-NEXT: lsr r25 +; CHECK-NEXT: ror r24 +; CHECK-NEXT: lsr r25 +; CHECK-NEXT: ror r24 +; CHECK-NEXT: mov r23, r22 +; CHECK-NEXT: swap r23 +; CHECK-NEXT: andi r23, 240 +; CHECK-NEXT: clr r22 +; CHECK-NEXT: lsl r23 +; CHECK-NEXT: lsl r23 +; CHECK-NEXT: or r24, r22 +; CHECK-NEXT: or r25, r23 +; CHECK-NEXT: mov r22, r18 +; CHECK-NEXT: mov r23, r19 +; CHECK-NEXT: ret +start: + %0 = call i32 @llvm.fshr.i32(i32 %x, i32 %x, i32 2) + ret i32 %0 +} + +declare i8 @llvm.fshl.i8(i8, i8, i8) +declare i8 @llvm.fshr.i8(i8, i8, i8) + +declare i16 @llvm.fshl.i16(i16, i16, i16) +declare i16 @llvm.fshr.i16(i16, i16, i16) + +declare i32 @llvm.fshl.i32(i32, i32, i32) +declare i32 @llvm.fshr.i32(i32, i32, i32)