From 99e7bf46c9e34644a8c0033684798dcafc790200 Mon Sep 17 00:00:00 2001 From: Ben Shi Date: Tue, 4 Jan 2022 11:14:30 +0000 Subject: [PATCH] [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 --- llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp | 73 ++++++++++++++++++++ llvm/lib/Target/AVR/AVRISelLowering.cpp | 17 +++++ llvm/lib/Target/AVR/AVRISelLowering.h | 3 + llvm/lib/Target/AVR/AVRInstrInfo.td | 12 ++++ llvm/test/CodeGen/AVR/shift.ll | 29 +++++--- 5 files changed, 124 insertions(+), 10 deletions(-) diff --git a/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp b/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp index 3c93da8e2039..7d101f6cfb14 100644 --- a/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp +++ b/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp @@ -1412,6 +1412,30 @@ bool AVRExpandPseudo::expand(Block &MBB, BlockIt MBBI) { 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); + + // 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(Block &MBB, BlockIt MBBI) { 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); + + // 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(Block &MBB, BlockIt MBBI) { 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); + + // 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); diff --git a/llvm/lib/Target/AVR/AVRISelLowering.cpp b/llvm/lib/Target/AVR/AVRISelLowering.cpp index f3e74e843695..f7f560ff5db3 100644 --- a/llvm/lib/Target/AVR/AVRISelLowering.cpp +++ b/llvm/lib/Target/AVR/AVRISelLowering.cpp @@ -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; diff --git a/llvm/lib/Target/AVR/AVRISelLowering.h b/llvm/lib/Target/AVR/AVRISelLowering.h index 3ae036b66bcb..223a47372ef7 100644 --- a/llvm/lib/Target/AVR/AVRISelLowering.h +++ b/llvm/lib/Target/AVR/AVRISelLowering.h @@ -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. diff --git a/llvm/lib/Target/AVR/AVRInstrInfo.td b/llvm/lib/Target/AVR/AVRInstrInfo.td index c7f423292da0..c695cde04590 100644 --- a/llvm/lib/Target/AVR/AVRInstrInfo.td +++ b/llvm/lib/Target/AVR/AVRInstrInfo.td @@ -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 diff --git a/llvm/test/CodeGen/AVR/shift.ll b/llvm/test/CodeGen/AVR/shift.ll index 90e1b25bd762..beba537cd104 100644 --- a/llvm/test/CodeGen/AVR/shift.ll +++ b/llvm/test/CodeGen/AVR/shift.ll @@ -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 +}