diff --git a/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp b/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp --- a/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp +++ b/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp @@ -70,6 +70,7 @@ bool expandLogic(unsigned Op, Block &MBB, BlockIt MBBI); bool expandLogicImm(unsigned Op, Block &MBB, BlockIt MBBI); bool isLogicImmOpRedundant(unsigned Op, unsigned ImmVal) const; + bool isLogicRegOpUndef(unsigned Op, unsigned ImmVal) const; template bool expandAtomic(Block &MBB, BlockIt MBBI, Func f); @@ -226,6 +227,18 @@ return false; } +bool AVRExpandPseudo::isLogicRegOpUndef(unsigned Op, unsigned ImmVal) const { + // ANDI Rd, 0x00 clears all input bits. + if (Op == AVR::ANDIRdK && ImmVal == 0x00) + return true; + + // ORI Rd, 0xff sets all input bits. + if (Op == AVR::ORIRdK && ImmVal == 0xff) + return true; + + return false; +} + bool AVRExpandPseudo::expandLogicImm(unsigned Op, Block &MBB, BlockIt MBBI) { MachineInstr &MI = *MBBI; Register DstLoReg, DstHiReg; @@ -247,6 +260,9 @@ // SREG is always implicitly dead MIBLO->getOperand(3).setIsDead(); + + if (isLogicRegOpUndef(Op, Lo8)) + MIBLO->getOperand(1).setIsUndef(true); } if (!isLogicImmOpRedundant(Op, Hi8)) { @@ -258,6 +274,9 @@ if (ImpIsDead) MIBHI->getOperand(3).setIsDead(); + + if (isLogicRegOpUndef(Op, Hi8)) + MIBHI->getOperand(1).setIsUndef(true); } MI.eraseFromParent(); diff --git a/llvm/lib/Target/AVR/AVRInstrInfo.cpp b/llvm/lib/Target/AVR/AVRInstrInfo.cpp --- a/llvm/lib/Target/AVR/AVRInstrInfo.cpp +++ b/llvm/lib/Target/AVR/AVRInstrInfo.cpp @@ -58,16 +58,21 @@ TRI.splitReg(DestReg, DestLo, DestHi); TRI.splitReg(SrcReg, SrcLo, SrcHi); + // Emit the copies. + // The original instruction was for a register pair, of which only one + // register might have been live. Add 'undef' to satisfy the machine + // verifier, when subreg liveness is enabled. + // TODO: Eliminate these unnecessary copies. if (DestLo == SrcHi) { BuildMI(MBB, MI, DL, get(AVR::MOVRdRr), DestHi) - .addReg(SrcHi, getKillRegState(KillSrc)); + .addReg(SrcHi, getKillRegState(KillSrc) | RegState::Undef); BuildMI(MBB, MI, DL, get(AVR::MOVRdRr), DestLo) - .addReg(SrcLo, getKillRegState(KillSrc)); + .addReg(SrcLo, getKillRegState(KillSrc) | RegState::Undef); } else { BuildMI(MBB, MI, DL, get(AVR::MOVRdRr), DestLo) - .addReg(SrcLo, getKillRegState(KillSrc)); + .addReg(SrcLo, getKillRegState(KillSrc) | RegState::Undef); BuildMI(MBB, MI, DL, get(AVR::MOVRdRr), DestHi) - .addReg(SrcHi, getKillRegState(KillSrc)); + .addReg(SrcHi, getKillRegState(KillSrc) | RegState::Undef); } } } else { diff --git a/llvm/lib/Target/AVR/AVRSubtarget.h b/llvm/lib/Target/AVR/AVRSubtarget.h --- a/llvm/lib/Target/AVR/AVRSubtarget.h +++ b/llvm/lib/Target/AVR/AVRSubtarget.h @@ -85,6 +85,8 @@ uint8_t getIORegisterOffset() const { return hasMemMappedGPR() ? 0x20 : 0x0; } + bool enableSubRegLiveness() const override { return true; } + /// Gets the ELF architecture for the e_flags field /// of an ELF object file. unsigned getELFArch() const { diff --git a/llvm/test/CodeGen/AVR/hardware-mul.ll b/llvm/test/CodeGen/AVR/hardware-mul.ll --- a/llvm/test/CodeGen/AVR/hardware-mul.ll +++ b/llvm/test/CodeGen/AVR/hardware-mul.ll @@ -18,19 +18,19 @@ ; CHECK-LABEL: mult16: ; CHECK: ; %bb.0: ; CHECK-NEXT: muls r22, r25 -; CHECK-NEXT: mov r20, r0 +; CHECK-NEXT: mov r25, r0 ; CHECK-NEXT: clr r1 ; CHECK-NEXT: mul r22, r24 -; CHECK-NEXT: mov r21, r0 +; CHECK-NEXT: mov r20, r0 ; CHECK-NEXT: mov r18, r1 ; CHECK-NEXT: clr r1 -; CHECK-NEXT: add r18, r20 +; CHECK-NEXT: add r18, r25 ; CHECK-NEXT: muls r23, r24 ; CHECK-NEXT: clr r1 ; CHECK-NEXT: add r18, r0 ; CHECK-NEXT: mov r19, r18 ; CHECK-NEXT: clr r18 -; CHECK-NEXT: mov r24, r21 +; CHECK-NEXT: mov r24, r20 ; CHECK-NEXT: clr r25 ; CHECK-NEXT: or r24, r18 ; CHECK-NEXT: or r25, r19 diff --git a/llvm/test/CodeGen/AVR/inline-asm/inline-asm3.ll b/llvm/test/CodeGen/AVR/inline-asm/inline-asm3.ll --- a/llvm/test/CodeGen/AVR/inline-asm/inline-asm3.ll +++ b/llvm/test/CodeGen/AVR/inline-asm/inline-asm3.ll @@ -227,14 +227,12 @@ ; CHECK-NEXT: mov r30, r22 ; CHECK-NEXT: mov r22, r24 ; CHECK-NEXT: mov r26, r22 -; CHECK-NEXT: mov r27, r23 ; CHECK-NEXT: ;APP ; CHECK-NEXT: mov r26, r26 ; CHECK-NEXT: add r26, r30 ; CHECK-NEXT: ;NO_APP -; CHECK-NEXT: mov r24, r26 -; CHECK-NEXT: ; kill: def $r22 killed $r22 killed $r23r22 ; CHECK-NEXT: mov r20, r30 +; CHECK-NEXT: mov r24, r26 ; CHECK-NEXT: rcall foo8 ; CHECK-NEXT: ret %3 = tail call i8 asm sideeffect "mov $0, $1\0Aadd $0, $2", "=e,e,e"(i8 %0, i8 %1) @@ -294,7 +292,6 @@ ; CHECK-NEXT: mov r24, r30 ; CHECK-NEXT: add r24, r26 ; CHECK-NEXT: ;NO_APP -; CHECK-NEXT: ; kill: def $r24 killed $r24 killed $r25r24 ; CHECK-NEXT: mov r22, r30 ; CHECK-NEXT: mov r20, r26 ; CHECK-NEXT: rcall foo8 @@ -345,9 +342,6 @@ ; CHECK-NEXT: ;NO_APP ; CHECK-NEXT: mov r24, r30 ; CHECK-NEXT: mov r25, r31 -; CHECK-NEXT: ; kill: def $r24 killed $r24 killed $r25r24 -; CHECK-NEXT: ; kill: def $r22 killed $r22 killed $r23r22 -; CHECK-NEXT: ; kill: def $r20 killed $r20 killed $r21r20 ; CHECK-NEXT: rcall foo8 ; CHECK-NEXT: pop r29 ; CHECK-NEXT: pop r28