Index: llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp =================================================================== --- llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp +++ llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp @@ -415,6 +415,47 @@ 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); + + // Do NEG on the upper byte. + auto MIBHI = + buildMI(MBB, MBBI, AVR::NEGRd) + .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead)) + .addReg(DstHiReg, getKillRegState(DstIsKill)); + // SREG is always implicitly dead + MIBHI->getOperand(2).setIsDead(); + + // Do NEG on the lower byte. + auto MIBLO = + buildMI(MBB, MBBI, AVR::NEGRd) + .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead)) + .addReg(DstLoReg, getKillRegState(DstIsKill)); + // SREG is always implicitly dead + MIBLO->getOperand(2).setIsDead(); + + // Do an extra SBCI. + auto MISBCI = + buildMI(MBB, MBBI, AVR::SBCIRdK) + .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead)) + .addReg(DstHiReg, getKillRegState(DstIsKill)) + .addImm(0); + if (ImpIsDead) + MISBCI->getOperand(3).setIsDead(); + // SREG is always implicitly killed + MISBCI->getOperand(4).setIsKill(); + + MI.eraseFromParent(); + return true; +} + template <> bool AVRExpandPseudo::expand(Block &MBB, BlockIt MBBI) { MachineInstr &MI = *MBBI; @@ -1616,6 +1657,7 @@ EXPAND(AVR::ORIWRdK); EXPAND(AVR::EORWRdRr); EXPAND(AVR::COMWRd); + EXPAND(AVR::NEGWRd); EXPAND(AVR::CPWRdRr); EXPAND(AVR::CPCWRdRr); EXPAND(AVR::LDIWRdK); Index: llvm/lib/Target/AVR/AVRInstrInfo.td =================================================================== --- llvm/lib/Target/AVR/AVRInstrInfo.td +++ llvm/lib/Target/AVR/AVRInstrInfo.td @@ -732,13 +732,23 @@ "comw\t$rd", [(set i16:$rd, (not i16:$src)), (implicit SREG)]>; - //:TODO: optimize NEG for wider types def NEGRd : FRd<0b1001, 0b0100001, (outs GPR8:$rd), (ins GPR8:$src), "neg\t$rd", [(set i8:$rd, (ineg i8:$src)), (implicit SREG)]>; + + // NEGW Rd+1:Rd + // + // Expands to: + // neg Rd + // clr Rtmp + // sbc Rtmp, Rd+1 + def NEGWRd : Pseudo<(outs DREGS:$rd), + (ins DREGS:$src), + "negw\t$rd", + [(set i16:$rd, (ineg i16:$src)), (implicit SREG)]>; } // TST Rd Index: llvm/test/CodeGen/AVR/pseudo/NEGWRd.mir =================================================================== --- /dev/null +++ llvm/test/CodeGen/AVR/pseudo/NEGWRd.mir @@ -0,0 +1,25 @@ +# RUN: llc -O0 -run-pass=avr-expand-pseudo %s -o - | FileCheck %s + +# This test checks the expansion of the 16-bit NEG pseudo instruction. + +--- | + target triple = "avr--" + define void @test_negwrd() { + entry: + ret void + } +... + +--- +name: test_negwrd +body: | + bb.0.entry: + + ; CHECK-LABEL: test_negwrd + + ; CHECK: $r15 = NEGRd $r15, implicit-def dead $sreg + ; CHECK-NEXT: $r14 = NEGRd $r14, implicit-def dead $sreg + ; CHECK-NEXT: $r15 = SBCIRdK $r15, 0, implicit-def $sreg, implicit killed $sreg + + $r15r14 = NEGWRd $r15r14, implicit-def $sreg +...