[AVR] Optimize int16 shift operation for shift amount greater than 8

Skip operation on the lower byte in int16 logical left shift when
shift amount is greater than 8.

Skip operation on the higher byte in int16 logical & arithmetic
right shift when shift amount is greater than 8.

Reviewed By: aykevl

Differential Revision: https://reviews.llvm.org/D115594
This commit is contained in:
Ben Shi 2022-01-04 11:14:30 +00:00
parent 5c57e6aa57
commit 99e7bf46c9
5 changed files with 124 additions and 10 deletions

View File

@ -1412,6 +1412,30 @@ bool AVRExpandPseudo::expand<AVR::LSLWRd>(Block &MBB, BlockIt MBBI) {
return true;
}
template <>
bool AVRExpandPseudo::expand<AVR::LSLWHiRd>(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);
// add hireg, hireg <==> lsl hireg
auto MILSL =
buildMI(MBB, MBBI, AVR::ADDRdRr)
.addReg(DstHiReg, RegState::Define, getDeadRegState(DstIsDead))
.addReg(DstHiReg, getKillRegState(DstIsKill))
.addReg(DstHiReg, getKillRegState(DstIsKill));
if (ImpIsDead)
MILSL->getOperand(3).setIsDead();
MI.eraseFromParent();
return true;
}
bool AVRExpandPseudo::expandLSLW4Rd(Block &MBB, BlockIt MBBI) {
MachineInstr &MI = *MBBI;
Register DstLoReg, DstHiReg;
@ -1587,6 +1611,29 @@ bool AVRExpandPseudo::expand<AVR::LSRWRd>(Block &MBB, BlockIt MBBI) {
return true;
}
template <>
bool AVRExpandPseudo::expand<AVR::LSRWLoRd>(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);
// lsr loreg
auto MILSR =
buildMI(MBB, MBBI, AVR::LSRRd)
.addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
.addReg(DstLoReg, getKillRegState(DstIsKill));
if (ImpIsDead)
MILSR->getOperand(2).setIsDead();
MI.eraseFromParent();
return true;
}
bool AVRExpandPseudo::expandLSRW4Rd(Block &MBB, BlockIt MBBI) {
MachineInstr &MI = *MBBI;
Register DstLoReg, DstHiReg;
@ -1774,6 +1821,29 @@ bool AVRExpandPseudo::expand<AVR::ASRWRd>(Block &MBB, BlockIt MBBI) {
return true;
}
template <>
bool AVRExpandPseudo::expand<AVR::ASRWLoRd>(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);
// asr loreg
auto MIASR =
buildMI(MBB, MBBI, AVR::ASRRd)
.addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
.addReg(DstLoReg, getKillRegState(DstIsKill));
if (ImpIsDead)
MIASR->getOperand(2).setIsDead();
MI.eraseFromParent();
return true;
}
bool AVRExpandPseudo::expandASRW8Rd(Block &MBB, BlockIt MBBI) {
MachineInstr &MI = *MBBI;
Register DstLoReg, DstHiReg;
@ -2230,6 +2300,9 @@ bool AVRExpandPseudo::expandMI(Block &MBB, BlockIt MBBI) {
EXPAND(AVR::RORWRd);
EXPAND(AVR::ROLWRd);
EXPAND(AVR::ASRWRd);
EXPAND(AVR::LSLWHiRd);
EXPAND(AVR::LSRWLoRd);
EXPAND(AVR::ASRWLoRd);
EXPAND(AVR::LSLWNRd);
EXPAND(AVR::LSRWNRd);
EXPAND(AVR::ASRWNRd);

View File

@ -392,16 +392,22 @@ SDValue AVRTargetLowering::LowerShifts(SDValue Op, SelectionDAG &DAG) const {
Victim = DAG.getNode(AVRISD::LSLWN, dl, VT, Victim,
DAG.getConstant(8, dl, VT));
ShiftAmount -= 8;
// Only operate on the higher byte for remaining shift bits.
Opc8 = AVRISD::LSLHI;
break;
case ISD::SRL:
Victim = DAG.getNode(AVRISD::LSRWN, dl, VT, Victim,
DAG.getConstant(8, dl, VT));
ShiftAmount -= 8;
// Only operate on the lower byte for remaining shift bits.
Opc8 = AVRISD::LSRLO;
break;
case ISD::SRA:
Victim = DAG.getNode(AVRISD::ASRWN, dl, VT, Victim,
DAG.getConstant(8, dl, VT));
ShiftAmount -= 8;
// Only operate on the lower byte for remaining shift bits.
Opc8 = AVRISD::ASRLO;
break;
default:
break;
@ -412,11 +418,22 @@ SDValue AVRTargetLowering::LowerShifts(SDValue Op, SelectionDAG &DAG) const {
Victim = DAG.getNode(AVRISD::LSLWN, dl, VT, Victim,
DAG.getConstant(12, dl, VT));
ShiftAmount -= 12;
// Only operate on the higher byte for remaining shift bits.
Opc8 = AVRISD::LSLHI;
break;
case ISD::SRL:
Victim = DAG.getNode(AVRISD::LSRWN, dl, VT, Victim,
DAG.getConstant(12, dl, VT));
ShiftAmount -= 12;
// Only operate on the lower byte for remaining shift bits.
Opc8 = AVRISD::LSRLO;
break;
case ISD::SRA:
Victim = DAG.getNode(AVRISD::ASRWN, dl, VT, Victim,
DAG.getConstant(8, dl, VT));
ShiftAmount -= 8;
// Only operate on the lower byte for remaining shift bits.
Opc8 = AVRISD::ASRLO;
break;
default:
break;

View File

@ -38,12 +38,15 @@ enum NodeType {
LSL, ///< Logical shift left.
LSLBN, ///< Byte logical shift left N bits.
LSLWN, ///< Word logical shift left N bits.
LSLHI, ///< Higher 8-bit of word logical shift left.
LSR, ///< Logical shift right.
LSRBN, ///< Byte logical shift right N bits.
LSRWN, ///< Word logical shift right N bits.
LSRLO, ///< Lower 8-bit of word logical shift right.
ASR, ///< Arithmetic shift right.
ASRBN, ///< Byte arithmetic shift right N bits.
ASRWN, ///< Word arithmetic shift right N bits.
ASRLO, ///< Lower 8-bit of word arithmetic shift right.
ROR, ///< Bit rotate right.
ROL, ///< Bit rotate left.
LSLLOOP, ///< A loop of single logical shift left instructions.

View File

@ -60,6 +60,9 @@ def AVRlsr : SDNode<"AVRISD::LSR", SDTIntUnaryOp>;
def AVRrol : SDNode<"AVRISD::ROL", SDTIntUnaryOp>;
def AVRror : SDNode<"AVRISD::ROR", SDTIntUnaryOp>;
def AVRasr : SDNode<"AVRISD::ASR", SDTIntUnaryOp>;
def AVRlslhi : SDNode<"AVRISD::LSLHI", SDTIntUnaryOp>;
def AVRlsrlo : SDNode<"AVRISD::LSRLO", SDTIntUnaryOp>;
def AVRasrlo : SDNode<"AVRISD::ASRLO", SDTIntUnaryOp>;
def AVRlslbn : SDNode<"AVRISD::LSLBN", SDTIntBinOp>;
def AVRlsrbn : SDNode<"AVRISD::LSRBN", SDTIntBinOp>;
def AVRasrbn : SDNode<"AVRISD::ASRBN", SDTIntBinOp>;
@ -1848,6 +1851,9 @@ let Constraints = "$src = $rd", Defs = [SREG] in {
: $src)),
(implicit SREG)]>;
def LSLWHiRd : Pseudo<(outs DREGS:$rd), (ins DREGS:$src), "lslwhi\t$rd",
[(set i16:$rd, (AVRlslhi i16:$src)), (implicit SREG)]>;
def LSLWNRd : Pseudo<(outs DLDREGS
: $rd),
(ins DREGS
@ -1895,6 +1901,9 @@ let Constraints = "$src = $rd", Defs = [SREG] in {
: $src)),
(implicit SREG)]>;
def LSRWLoRd : Pseudo<(outs DREGS:$rd), (ins DREGS:$src), "lsrwlo\t$rd",
[(set i16:$rd, (AVRlsrlo i16:$src)), (implicit SREG)]>;
def LSRWNRd : Pseudo<(outs DLDREGS
: $rd),
(ins DREGS
@ -1968,6 +1977,9 @@ let Constraints = "$src = $rd", Defs = [SREG] in {
: $src)),
(implicit SREG)]>;
def ASRWLoRd : Pseudo<(outs DREGS:$rd), (ins DREGS:$src), "asrwlo\t$rd",
[(set i16:$rd, (AVRasrlo i16:$src)), (implicit SREG)]>;
def ROLBRd : Pseudo<(outs GPR8
: $rd),
(ins GPR8

View File

@ -227,8 +227,7 @@ 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: lsl r25
; CHECK-NEXT: ret
%result = shl i16 %a, 9
ret i16 %result
@ -240,8 +239,7 @@ define i16 @lsl_i16_13(i16 %a) {
; CHECK-NEXT: swap r25
; CHECK-NEXT: andi r25, 240
; CHECK-NEXT: clr r24
; CHECK-NEXT: lsl r24
; CHECK-NEXT: rol r25
; CHECK-NEXT: lsl r25
; CHECK-NEXT: ret
%result = shl i16 %a, 13
ret i16 %result
@ -285,8 +283,7 @@ 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: lsr r24
; CHECK-NEXT: ret
%result = lshr i16 %a, 9
ret i16 %result
@ -298,8 +295,7 @@ define i16 @lsr_i16_13(i16 %a) {
; CHECK-NEXT: swap r24
; CHECK-NEXT: andi r24, 15
; CHECK-NEXT: clr r25
; CHECK-NEXT: lsr r25
; CHECK-NEXT: ror r24
; CHECK-NEXT: lsr r24
; CHECK-NEXT: ret
%result = lshr i16 %a, 13
ret i16 %result
@ -310,9 +306,22 @@ define i16 @asr_i16_9(i16 %a) {
; CHECK: mov r24, r25
; CHECK-NEXT: lsl r25
; CHECK-NEXT: sbc r25, r25
; CHECK-NEXT: asr r25
; CHECK-NEXT: ror r24
; CHECK-NEXT: asr r24
; CHECK-NEXT: ret
%result = ashr i16 %a, 9
ret i16 %result
}
define i16 @asr_i16_12(i16 %a) {
; CHECK-LABEL: asr_i16_12
; CHECK: mov r24, r25
; CHECK-NEXT: lsl r25
; CHECK-NEXT: sbc r25, r25
; CHECK-NEXT: asr r24
; CHECK-NEXT: asr r24
; CHECK-NEXT: asr r24
; CHECK-NEXT: asr r24
; CHECK-NEXT: ret
%result = ashr i16 %a, 12
ret i16 %result
}