Index: llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp =================================================================== --- llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp +++ llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp @@ -89,17 +89,22 @@ bool expandAtomicArithmeticOp(unsigned MemOpcode, unsigned ArithOpcode, Block &MBB, BlockIt MBBI); - /// Specific shift implementation. + /// Specific shift implementation for int8. bool expandLSLB7Rd(Block &MBB, BlockIt MBBI); bool expandLSRB7Rd(Block &MBB, BlockIt MBBI); bool expandASRB7Rd(Block &MBB, BlockIt MBBI); + + /// Specific shift implementation for int16. bool expandLSLW4Rd(Block &MBB, BlockIt MBBI); bool expandLSRW4Rd(Block &MBB, BlockIt MBBI); + bool expandASRW7Rd(Block &MBB, BlockIt MBBI); bool expandLSLW8Rd(Block &MBB, BlockIt MBBI); bool expandLSRW8Rd(Block &MBB, BlockIt MBBI); bool expandASRW8Rd(Block &MBB, BlockIt MBBI); bool expandLSLW12Rd(Block &MBB, BlockIt MBBI); bool expandLSRW12Rd(Block &MBB, BlockIt MBBI); + bool expandASRW14Rd(Block &MBB, BlockIt MBBI); + bool expandASRW15Rd(Block &MBB, BlockIt MBBI); /// Scavenges a free GPR8 register for use. Register scavengeGPR8(MachineInstr &MI); @@ -1843,6 +1848,56 @@ return true; } +bool AVRExpandPseudo::expandASRW7Rd(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(3).isDead(); + TRI->splitReg(DstReg, DstLoReg, DstHiReg); + + // lsl r24 + // mov r24,r25 + // rol r24 + // sbc r25,r25 + + // lsl r24 <=> add r24, r24 + buildMI(MBB, MBBI, AVR::ADDRdRr) + .addReg(DstLoReg, RegState::Define, getDeadRegState(DstIsDead)) + .addReg(DstLoReg, getKillRegState(DstIsKill)) + .addReg(DstLoReg, getKillRegState(DstIsKill)) + ->getOperand(3) + .setIsUndef(true); + + // mov r24, r25 + buildMI(MBB, MBBI, AVR::MOVRdRr) + .addReg(DstLoReg, RegState::Define, getDeadRegState(DstIsDead)) + .addReg(DstHiReg, getKillRegState(DstIsKill)); + + // rol r24 <=> adc r24, r24 + buildMI(MBB, MBBI, AVR::ADCRdRr) + .addReg(DstLoReg, RegState::Define, getDeadRegState(DstIsDead)) + .addReg(DstLoReg, getKillRegState(DstIsKill)) + .addReg(DstLoReg, getKillRegState(DstIsKill)); + + // sbc r25, r25 + auto MISBC = + buildMI(MBB, MBBI, AVR::SBCRdRr) + .addReg(DstHiReg, RegState::Define, getDeadRegState(DstIsDead)) + .addReg(DstHiReg, getKillRegState(DstIsKill)) + .addReg(DstHiReg, getKillRegState(DstIsKill)); + + if (ImpIsDead) + MISBC->getOperand(3).setIsDead(); + + // SREG is always implicitly killed + MISBC->getOperand(4).setIsKill(); + + MI.eraseFromParent(); + return true; +} + bool AVRExpandPseudo::expandASRW8Rd(Block &MBB, BlockIt MBBI) { MachineInstr &MI = *MBBI; Register DstLoReg, DstHiReg; @@ -1872,6 +1927,107 @@ if (ImpIsDead) MIBHI->getOperand(3).setIsDead(); + // SREG is always implicitly killed + MIBHI->getOperand(4).setIsKill(); + + MI.eraseFromParent(); + return true; +} + +bool AVRExpandPseudo::expandASRW14Rd(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(3).isDead(); + TRI->splitReg(DstReg, DstLoReg, DstHiReg); + + // lsl r25 + // sbc r24, r24 + // lsl r25 + // mov r25, r24 + // rol r24 + + // lsl r25 <=> add r25, r25 + buildMI(MBB, MBBI, AVR::ADDRdRr) + .addReg(DstHiReg, RegState::Define, getDeadRegState(DstIsDead)) + .addReg(DstHiReg, getKillRegState(DstIsKill)) + .addReg(DstHiReg, getKillRegState(DstIsKill)) + ->getOperand(3) + .setIsUndef(true); + + // sbc r24, r24 + buildMI(MBB, MBBI, AVR::SBCRdRr) + .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead)) + .addReg(DstLoReg, getKillRegState(DstIsKill)) + .addReg(DstLoReg, getKillRegState(DstIsKill)); + + // lsl r25 <=> add r25, r25 + buildMI(MBB, MBBI, AVR::ADDRdRr) + .addReg(DstHiReg, RegState::Define, getDeadRegState(DstIsDead)) + .addReg(DstHiReg, getKillRegState(DstIsKill)) + .addReg(DstHiReg, getKillRegState(DstIsKill)); + + // mov r25, r24 + buildMI(MBB, MBBI, AVR::MOVRdRr) + .addReg(DstHiReg, RegState::Define, getDeadRegState(DstIsDead)) + .addReg(DstLoReg, getKillRegState(DstIsKill)); + + // rol r24 <=> adc r24, r24 + auto MIROL = + buildMI(MBB, MBBI, AVR::ADCRdRr) + .addReg(DstLoReg, RegState::Define, getDeadRegState(DstIsDead)) + .addReg(DstLoReg, getKillRegState(DstIsKill)) + .addReg(DstLoReg, getKillRegState(DstIsKill)); + + if (ImpIsDead) + MIROL->getOperand(3).setIsDead(); + + // SREG is always implicitly killed + MIROL->getOperand(4).setIsKill(); + + MI.eraseFromParent(); + return false; +} + +bool AVRExpandPseudo::expandASRW15Rd(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(3).isDead(); + TRI->splitReg(DstReg, DstLoReg, DstHiReg); + + // lsl r25 + // sbc r25, r25 + // mov r24, r25 + + // lsl r25 <=> add r25, r25 + buildMI(MBB, MBBI, AVR::ADDRdRr) + .addReg(DstHiReg, RegState::Define, getDeadRegState(DstIsDead)) + .addReg(DstHiReg, getKillRegState(DstIsKill)) + .addReg(DstHiReg, getKillRegState(DstIsKill)) + ->getOperand(3) + .setIsUndef(true); + + // sbc r25, r25 + auto MISBC = + buildMI(MBB, MBBI, AVR::SBCRdRr) + .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead)) + .addReg(DstHiReg, getKillRegState(DstIsKill)) + .addReg(DstHiReg, getKillRegState(DstIsKill)); + if (ImpIsDead) + MISBC->getOperand(3).setIsDead(); + // SREG is always implicitly killed + MISBC->getOperand(4).setIsKill(); + + // mov r24, r25 + buildMI(MBB, MBBI, AVR::MOVRdRr) + .addReg(DstLoReg, RegState::Define, getDeadRegState(DstIsDead)) + .addReg(DstHiReg, getKillRegState(DstIsKill)); + MI.eraseFromParent(); return true; } @@ -1881,8 +2037,14 @@ MachineInstr &MI = *MBBI; unsigned Imm = MI.getOperand(2).getImm(); switch (Imm) { + case 7: + return expandASRW7Rd(MBB, MBBI); case 8: return expandASRW8Rd(MBB, MBBI); + case 14: + return expandASRW14Rd(MBB, MBBI); + case 15: + return expandASRW15Rd(MBB, MBBI); default: llvm_unreachable("unimplemented asrwn"); return false; Index: llvm/lib/Target/AVR/AVRISelLowering.cpp =================================================================== --- llvm/lib/Target/AVR/AVRISelLowering.cpp +++ llvm/lib/Target/AVR/AVRISelLowering.cpp @@ -366,6 +366,27 @@ ShiftAmount = 0; } } else if (VT.getSizeInBits() == 16) { + if (Op.getOpcode() == ISD::SRA) + // Special optimization for int16 arithmetic right shift. + switch (ShiftAmount) { + case 15: + Victim = DAG.getNode(AVRISD::ASRWN, dl, VT, Victim, + DAG.getConstant(15, dl, VT)); + ShiftAmount = 0; + break; + case 14: + Victim = DAG.getNode(AVRISD::ASRWN, dl, VT, Victim, + DAG.getConstant(14, dl, VT)); + ShiftAmount = 0; + break; + case 7: + Victim = DAG.getNode(AVRISD::ASRWN, dl, VT, Victim, + DAG.getConstant(7, dl, VT)); + ShiftAmount = 0; + break; + default: + break; + } if (4 <= ShiftAmount && ShiftAmount < 8) switch (Op.getOpcode()) { case ISD::SHL: Index: llvm/test/CodeGen/AVR/shift.ll =================================================================== --- llvm/test/CodeGen/AVR/shift.ll +++ llvm/test/CodeGen/AVR/shift.ll @@ -291,6 +291,17 @@ ret i16 %result } +define i16 @asr_i16_7(i16 %a) { +; CHECK-LABEL: asr_i16_7 +; CHECK: lsl r24 +; CHECK-NEXT: mov r24, r25 +; CHECK-NEXT: rol r24 +; CHECK-NEXT: sbc r25, r25 +; CHECK-NEXT: ret + %result = ashr i16 %a, 7 + ret i16 %result +} + define i16 @asr_i16_9(i16 %a) { ; CHECK-LABEL: asr_i16_9 ; CHECK: mov r24, r25 @@ -315,3 +326,25 @@ %result = ashr i16 %a, 12 ret i16 %result } + +define i16 @asr_i16_14(i16 %a) { +; CHECK-LABEL: asr_i16_14 +; CHECK: lsl r25 +; CHECK-NEXT: sbc r24, r24 +; CHECK-NEXT: lsl r25 +; CHECK-NEXT: mov r25, r24 +; CHECK-NEXT: rol r24 +; CHECK-NEXT: ret + %result = ashr i16 %a, 14 + ret i16 %result +} + +define i16 @asr_i16_15(i16 %a) { +; CHECK-LABEL: asr_i16_15 +; CHECK: lsl r25 +; CHECK-NEXT: sbc r25, r25 +; CHECK-NEXT: mov r24, r25 +; CHECK-NEXT: ret + %result = ashr i16 %a, 15 + ret i16 %result +}