forked from OSchip/llvm-project
[AVR] Implement non-constant bit rotations
This lets us do bit rotations of variable amount. llvm-svn: 301794
This commit is contained in:
parent
4064dc76c5
commit
59e7fe3da8
|
@ -79,6 +79,11 @@ AVRTargetLowering::AVRTargetLowering(AVRTargetMachine &tm)
|
|||
setOperationAction(ISD::SRA_PARTS, MVT::i16, Expand);
|
||||
setOperationAction(ISD::SRL_PARTS, MVT::i16, Expand);
|
||||
|
||||
setOperationAction(ISD::ROTL, MVT::i8, Custom);
|
||||
setOperationAction(ISD::ROTL, MVT::i16, Custom);
|
||||
setOperationAction(ISD::ROTR, MVT::i8, Custom);
|
||||
setOperationAction(ISD::ROTR, MVT::i16, Custom);
|
||||
|
||||
setOperationAction(ISD::BR_CC, MVT::i8, Custom);
|
||||
setOperationAction(ISD::BR_CC, MVT::i16, Custom);
|
||||
setOperationAction(ISD::BR_CC, MVT::i32, Custom);
|
||||
|
@ -273,6 +278,12 @@ SDValue AVRTargetLowering::LowerShifts(SDValue Op, SelectionDAG &DAG) const {
|
|||
case ISD::SRL:
|
||||
return DAG.getNode(AVRISD::LSRLOOP, dl, VT, N->getOperand(0),
|
||||
N->getOperand(1));
|
||||
case ISD::ROTL:
|
||||
return DAG.getNode(AVRISD::ROLLOOP, dl, VT, N->getOperand(0),
|
||||
N->getOperand(1));
|
||||
case ISD::ROTR:
|
||||
return DAG.getNode(AVRISD::RORLOOP, dl, VT, N->getOperand(0),
|
||||
N->getOperand(1));
|
||||
case ISD::SRA:
|
||||
return DAG.getNode(AVRISD::ASRLOOP, dl, VT, N->getOperand(0),
|
||||
N->getOperand(1));
|
||||
|
@ -1440,6 +1451,22 @@ MachineBasicBlock *AVRTargetLowering::insertShift(MachineInstr &MI,
|
|||
Opc = AVR::LSRWRd;
|
||||
RC = &AVR::DREGSRegClass;
|
||||
break;
|
||||
case AVR::Rol8:
|
||||
Opc = AVR::ROLRd;
|
||||
RC = &AVR::GPR8RegClass;
|
||||
break;
|
||||
case AVR::Rol16:
|
||||
Opc = AVR::ROLWRd;
|
||||
RC = &AVR::DREGSRegClass;
|
||||
break;
|
||||
case AVR::Ror8:
|
||||
Opc = AVR::RORRd;
|
||||
RC = &AVR::GPR8RegClass;
|
||||
break;
|
||||
case AVR::Ror16:
|
||||
Opc = AVR::RORWRd;
|
||||
RC = &AVR::DREGSRegClass;
|
||||
break;
|
||||
}
|
||||
|
||||
const BasicBlock *LLVM_BB = BB->getBasicBlock();
|
||||
|
@ -1552,6 +1579,10 @@ AVRTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
|
|||
case AVR::Lsl16:
|
||||
case AVR::Lsr8:
|
||||
case AVR::Lsr16:
|
||||
case AVR::Rol8:
|
||||
case AVR::Rol16:
|
||||
case AVR::Ror8:
|
||||
case AVR::Ror16:
|
||||
case AVR::Asr8:
|
||||
case AVR::Asr16:
|
||||
return insertShift(MI, MBB);
|
||||
|
|
|
@ -43,6 +43,8 @@ enum NodeType {
|
|||
ROL, ///< Bit rotate left.
|
||||
LSLLOOP, ///< A loop of single logical shift left instructions.
|
||||
LSRLOOP, ///< A loop of single logical shift right instructions.
|
||||
ROLLOOP, ///< A loop of single left bit rotate instructions.
|
||||
RORLOOP, ///< A loop of single right bit rotate instructions.
|
||||
ASRLOOP, ///< A loop of single arithmetic shift right instructions.
|
||||
/// AVR conditional branches. Operand 0 is the chain operand, operand 1
|
||||
/// is the block to branch if condition is true, operand 2 is the
|
||||
|
|
|
@ -64,6 +64,8 @@ def AVRasr : SDNode<"AVRISD::ASR", SDTIntUnaryOp>;
|
|||
// Pseudo shift nodes for non-constant shift amounts.
|
||||
def AVRlslLoop : SDNode<"AVRISD::LSLLOOP", SDTIntShiftOp>;
|
||||
def AVRlsrLoop : SDNode<"AVRISD::LSRLOOP", SDTIntShiftOp>;
|
||||
def AVRrolLoop : SDNode<"AVRISD::ROLLOOP", SDTIntShiftOp>;
|
||||
def AVRrorLoop : SDNode<"AVRISD::RORLOOP", SDTIntShiftOp>;
|
||||
def AVRasrLoop : SDNode<"AVRISD::ASRLOOP", SDTIntShiftOp>;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -1932,7 +1934,6 @@ def Lsr8 : ShiftPseudo<
|
|||
[(set i8:$dst, (AVRlsrLoop i8:$src, i8:$cnt))]
|
||||
>;
|
||||
|
||||
|
||||
def Lsr16 : ShiftPseudo<
|
||||
(outs DREGS:$dst),
|
||||
(ins DREGS:$src, GPR8:$cnt),
|
||||
|
@ -1940,6 +1941,34 @@ def Lsr16 : ShiftPseudo<
|
|||
[(set i16:$dst, (AVRlsrLoop i16:$src, i8:$cnt))]
|
||||
>;
|
||||
|
||||
def Rol8 : ShiftPseudo<
|
||||
(outs GPR8:$dst),
|
||||
(ins GPR8:$src, GPR8:$cnt),
|
||||
"# Rol8 PSEUDO",
|
||||
[(set i8:$dst, (AVRrolLoop i8:$src, i8:$cnt))]
|
||||
>;
|
||||
|
||||
def Rol16 : ShiftPseudo<
|
||||
(outs DREGS:$dst),
|
||||
(ins DREGS:$src, GPR8:$cnt),
|
||||
"# Rol16 PSEUDO",
|
||||
[(set i16:$dst, (AVRrolLoop i16:$src, i8:$cnt))]
|
||||
>;
|
||||
|
||||
def Ror8 : ShiftPseudo<
|
||||
(outs GPR8:$dst),
|
||||
(ins GPR8:$src, GPR8:$cnt),
|
||||
"# Ror8 PSEUDO",
|
||||
[(set i8:$dst, (AVRrorLoop i8:$src, i8:$cnt))]
|
||||
>;
|
||||
|
||||
def Ror16 : ShiftPseudo<
|
||||
(outs DREGS:$dst),
|
||||
(ins DREGS:$src, GPR8:$cnt),
|
||||
"# Ror16 PSEUDO",
|
||||
[(set i16:$dst, (AVRrorLoop i16:$src, i8:$cnt))]
|
||||
>;
|
||||
|
||||
def Asr8 : ShiftPseudo<
|
||||
(outs GPR8:$dst),
|
||||
(ins GPR8:$src, GPR8:$cnt),
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
; RUN: llc < %s -march=avr | FileCheck %s
|
||||
|
||||
; Bit rotation tests.
|
||||
|
||||
; CHECK-LABEL: rol8:
|
||||
define i8 @rol8(i8 %val, i8 %amt) {
|
||||
; CHECK: andi r22, 7
|
||||
|
||||
; CHECK-NEXT: cp r22, r0
|
||||
; CHECK-NEXT: breq LBB0_2
|
||||
|
||||
; CHECK-NEXT: LBB0_1:
|
||||
; CHECK-NEXT: rol r24
|
||||
; CHECK-NEXT: subi r22, 1
|
||||
; CHECK-NEXT: brne LBB0_1
|
||||
|
||||
; CHECK-NEXT:LBB0_2:
|
||||
; CHECK-NEXT: ret
|
||||
%mod = urem i8 %amt, 8
|
||||
|
||||
%inv = sub i8 8, %mod
|
||||
%parta = shl i8 %val, %mod
|
||||
%partb = lshr i8 %val, %inv
|
||||
|
||||
%rotl = or i8 %parta, %partb
|
||||
|
||||
ret i8 %rotl
|
||||
}
|
||||
|
||||
|
||||
; CHECK-LABEL: ror8:
|
||||
define i8 @ror8(i8 %val, i8 %amt) {
|
||||
; CHECK: andi r22, 7
|
||||
|
||||
; CHECK-NEXT: cp r22, r0
|
||||
; CHECK-NEXT: breq LBB1_2
|
||||
|
||||
; CHECK-NEXT: LBB1_1:
|
||||
; CHECK-NEXT: ror r24
|
||||
; CHECK-NEXT: subi r22, 1
|
||||
; CHECK-NEXT: brne LBB1_1
|
||||
|
||||
; CHECK-NEXT:LBB1_2:
|
||||
; CHECK-NEXT: ret
|
||||
%mod = urem i8 %amt, 8
|
||||
|
||||
%inv = sub i8 8, %mod
|
||||
%parta = lshr i8 %val, %mod
|
||||
%partb = shl i8 %val, %inv
|
||||
|
||||
%rotr = or i8 %parta, %partb
|
||||
|
||||
ret i8 %rotr
|
||||
}
|
||||
|
Loading…
Reference in New Issue