Index: lib/CodeGen/BranchFolding.cpp =================================================================== --- lib/CodeGen/BranchFolding.cpp +++ lib/CodeGen/BranchFolding.cpp @@ -865,7 +865,7 @@ // Merge MMOs from memory operations in the common block. if (MBBICommon->mayLoad() || MBBICommon->mayStore()) MBBICommon->cloneMergedMemRefs(*MBB->getParent(), {&*MBBICommon, &*MBBI}); - // Drop undef flags if they aren't present in all merged instructions. + // Drop undef/kill flags if they aren't present in all merged instructions. for (unsigned I = 0, E = MBBICommon->getNumOperands(); I != E; ++I) { MachineOperand &MO = MBBICommon->getOperand(I); if (MO.isReg() && MO.isUndef()) { @@ -873,6 +873,21 @@ if (!OtherMO.isUndef()) MO.setIsUndef(false); } + if (MO.isReg() && MO.isKill()) { + const MachineOperand &OtherMO = MBBI->getOperand(I); + // An exception to the clearing of the kill flag is if we merge + // something like: + // undef $r0 + // $r0 = + // and + // killed $r0 + // $r0 = + // Here we should keep the kill flag even if it's only set in one of the + // merged paths since it's undef in the other. So the only real value + // in $r0 that actually reaches will indeed be killed there. + if (!OtherMO.isKill() && !OtherMO.isUndef()) + MO.setIsKill(false); + } } ++MBBI; Index: test/CodeGen/Hexagon/branchfolder-clear-kill.mir =================================================================== --- /dev/null +++ test/CodeGen/Hexagon/branchfolder-clear-kill.mir @@ -0,0 +1,47 @@ +# RUN: llc -march=hexagon -run-pass branch-folder %s -o - -verify-machineinstrs | FileCheck %s + +# When the branchfolder merges common tails, it needs to clear both undef and +# killed flags if they differ between the merged blocks. + +# In the below example, if the killed flag is not cleared we will be left with +# A2_nop 0, killed $r0 +# A2_nop 0, $r0 +# and then the verifier will complain about use of an undefined physical +# register. + +--- +# CHECK-LABEL: name: func0 +# CHECK-LABEL: bb.0: +# CHECK: liveins: $r0, $r31 +# CHECK: A2_nop implicit $r0 +# CHECK: A2_nop implicit $r0 +# CHECK: PS_jmpret + +name: func0 +tracksRegLiveness: true + +body: | + bb.0: + liveins: $r0, $r31 + successors: %bb.1, %bb.2 + J2_jumpt undef $p0, %bb.2, implicit-def $pc + J2_jump %bb.1, implicit-def $pc + + bb.1: + liveins: $r0, $r31 + successors: %bb.3 + A2_nop implicit $r0 + A2_nop implicit killed $r0 + J2_jump %bb.3, implicit-def $pc + + bb.2: + liveins: $r0, $r31 + successors: %bb.3 + A2_nop implicit killed $r0 + A2_nop implicit undef $r0 + J2_jump %bb.3, implicit-def $pc + + bb.3: + liveins: $r31 + PS_jmpret killed $r31, implicit-def $pc +...