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 <typename Func> bool expandAtomic(Block &MBB, BlockIt MBBI, Func f);
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;
// SREG is always implicitly dead
MIBLO->getOperand(3).setIsDead();
+
+ if (isLogicRegOpUndef(Op, Lo8))
+ MIBLO->getOperand(1).setIsUndef(true);
}
if (!isLogicImmOpRedundant(Op, Hi8)) {
if (ImpIsDead)
MIBHI->getOperand(3).setIsDead();
+
+ if (isLogicRegOpUndef(Op, Hi8))
+ MIBHI->getOperand(1).setIsUndef(true);
}
MI.eraseFromParent();
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 {
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 {
; 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
; 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)
; 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
; 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