Index: lib/Target/ARM/ARMISelLowering.cpp =================================================================== --- lib/Target/ARM/ARMISelLowering.cpp +++ lib/Target/ARM/ARMISelLowering.cpp @@ -8857,6 +8857,29 @@ } } +// Returns true if CPSR is used/live before another definition. +static bool isCPSRLiveBeforeDefinition(const MachineBasicBlock &BB, + const TargetRegisterInfo *TRI) { + // Scan forward through BB for a use/def of CPSR. + MachineBasicBlock::const_iterator miI = BB.begin(); + for (MachineBasicBlock::const_iterator miE = BB.end(); miI != miE; ++miI) { + const MachineInstr &mi = *miI; + if (mi.readsRegister(ARM::CPSR)) + return true; + if (mi.definesRegister(ARM::CPSR)) + break; // Should have kill-flag - update below. + } + + // If we hit the end of the block, check whether CPSR is live into a + // successor. + if (miI == BB.end()) + return any_of(BB.successors(), [](const MachineBasicBlock *Succ) { + return Succ->isLiveIn(ARM::CPSR); + }); + + return false; +} + MachineBasicBlock * ARMTargetLowering::EmitStructByval(MachineInstr &MI, MachineBasicBlock *BB) const { @@ -8978,6 +9001,13 @@ std::next(MachineBasicBlock::iterator(MI)), BB->end()); exitMBB->transferSuccessorsAndUpdatePHIs(BB); + // Check whether CPSR is live past the pseudo instruction. + const TargetRegisterInfo *TRI = Subtarget->getRegisterInfo(); + if (isCPSRLiveBeforeDefinition(*exitMBB, TRI)) { + loopMBB->addLiveIn(ARM::CPSR); + exitMBB->addLiveIn(ARM::CPSR); + } + // Load an immediate to varEnd. unsigned varEnd = MRI.createVirtualRegister(TRC); if (Subtarget->useMovt(*MF)) { @@ -9206,42 +9236,6 @@ return ContBB; } -// The CPSR operand of SelectItr might be missing a kill marker -// because there were multiple uses of CPSR, and ISel didn't know -// which to mark. Figure out whether SelectItr should have had a -// kill marker, and set it if it should. Returns the correct kill -// marker value. -static bool checkAndUpdateCPSRKill(MachineBasicBlock::iterator SelectItr, - MachineBasicBlock* BB, - const TargetRegisterInfo* TRI) { - // Scan forward through BB for a use/def of CPSR. - MachineBasicBlock::iterator miI(std::next(SelectItr)); - for (MachineBasicBlock::iterator miE = BB->end(); miI != miE; ++miI) { - const MachineInstr& mi = *miI; - if (mi.readsRegister(ARM::CPSR)) - return false; - if (mi.definesRegister(ARM::CPSR)) - break; // Should have kill-flag - update below. - } - - // If we hit the end of the block, check whether CPSR is live into a - // successor. - if (miI == BB->end()) { - for (MachineBasicBlock::succ_iterator sItr = BB->succ_begin(), - sEnd = BB->succ_end(); - sItr != sEnd; ++sItr) { - MachineBasicBlock* succ = *sItr; - if (succ->isLiveIn(ARM::CPSR)) - return false; - } - } - - // We found a def, or hit the end of the basic block and CPSR wasn't live - // out. SelectMI should have a kill flag on CPSR. - SelectItr->addRegisterKilled(ARM::CPSR, TRI); - return true; -} - MachineBasicBlock * ARMTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI, MachineBasicBlock *BB) const { @@ -9343,17 +9337,25 @@ // Check whether CPSR is live past the tMOVCCr_pseudo. const TargetRegisterInfo *TRI = Subtarget->getRegisterInfo(); - if (!MI.killsRegister(ARM::CPSR) && - !checkAndUpdateCPSRKill(MI, thisMBB, TRI)) { - copy0MBB->addLiveIn(ARM::CPSR); - sinkMBB->addLiveIn(ARM::CPSR); - } // Transfer the remainder of BB and its successor edges to sinkMBB. sinkMBB->splice(sinkMBB->begin(), BB, std::next(MachineBasicBlock::iterator(MI)), BB->end()); sinkMBB->transferSuccessorsAndUpdatePHIs(BB); + if (!MI.killsRegister(ARM::CPSR)) { + // The CPSR operand of MI might be missing a kill marker + // because there were multiple uses of CPSR, and ISel didn't know + // which to mark. Figure out whether MI should have had a + // kill marker, and set it if it should. + if (isCPSRLiveBeforeDefinition(*sinkMBB, TRI)) { + copy0MBB->addLiveIn(ARM::CPSR); + sinkMBB->addLiveIn(ARM::CPSR); + } else + // MI is the last use of CPSR, we can kill it. + MI.addRegisterKilled(ARM::CPSR, TRI); + } + BB->addSuccessor(copy0MBB); BB->addSuccessor(sinkMBB); Index: test/CodeGen/ARM/expand-isel-pseudos-liveins.mir =================================================================== --- /dev/null +++ test/CodeGen/ARM/expand-isel-pseudos-liveins.mir @@ -0,0 +1,134 @@ +# Check liveins are properly set when new MBBs are created in +# expand-isel-pseudos. + +# RUN: llc -mtriple=arm-unknown- -run-pass=expand-isel-pseudos %s -o - | FileCheck %s +--- | + + define i32 @test_copy_struct_byval(i32 %x) { + entry: + unreachable + } + + define { i32, i32 } @test_slt_not(i32 %c, i32 %d, i64 %a, i64 %b) { + entry: + %cmp = icmp slt i64 %a, %b + %not = xor i1 %cmp, true + %r1 = zext i1 %cmp to i32 + %r2 = zext i1 %not to i32 + %z = insertvalue { i32, i32 } undef, i32 %r1, 0 + %z2 = insertvalue { i32, i32 } %z, i32 %r2, 1 + ret { i32, i32 } %z2 + } +... +--- +# CHECK-LABEL: name: test_copy_struct_byval +# CHECK-LABEL: bb.2.entry: +# CHECK-NEXT: liveins: $cpsr +name: test_copy_struct_byval +alignment: 2 +tracksRegLiveness: true +registers: + - { id: 0, class: gpr, preferred-register: '' } + - { id: 1, class: gpr, preferred-register: '' } + - { id: 2, class: gpr, preferred-register: '' } + - { id: 3, class: gpr, preferred-register: '' } + - { id: 4, class: gpr, preferred-register: '' } + - { id: 5, class: gpr, preferred-register: '' } + - { id: 6, class: gpr, preferred-register: '' } + - { id: 7, class: gpr, preferred-register: '' } + - { id: 8, class: gpr, preferred-register: '' } + - { id: 9, class: gpr, preferred-register: '' } + - { id: 10, class: gpr, preferred-register: '' } + - { id: 11, class: gpr, preferred-register: '' } + - { id: 12, class: gpr, preferred-register: '' } +liveins: + - { reg: '$r0', virtual-reg: '%0' } + - { reg: '$r1', virtual-reg: '%1' } +body: | + bb.0.entry: + liveins: $r0, $r1 + + %1:gpr = COPY $r1 + %0:gpr = COPY $r0 + %2:gpr = LDRi12 %0, 0, 14, $noreg :: (load 4) + %3:gpr = LDRi12 %0, 4, 14, $noreg :: (load 4) + ADJCALLSTACKDOWN 136, 0, 14, $noreg, implicit-def dead $sp, implicit $sp + %4:gpr = ADDri %1, 16, 14, $noreg, $noreg + %5:gpr = LDRi12 %1, 0, 14, $noreg :: (load 4) + %6:gpr = LDRi12 %1, 4, 14, $noreg :: (load 4) + %7:gpr = LDRi12 %1, 8, 14, $noreg :: (load 4) + %8:gpr = LDRi12 %1, 12, 14, $noreg :: (load 4) + %9:gpr = COPY $sp + COPY_STRUCT_BYVAL_I32 %9, killed %4, 56, 8 + %10:gpr = SUBri %2, 1, 14, $noreg, def $cpsr + STRi12 killed %10, %9, 128, 14, $noreg :: (store 4 into stack + 128) + %11:gpr = ADDri %9, 56, 14, $noreg, $noreg + COPY_STRUCT_BYVAL_I32 killed %11, %1, 72, 8 + %12:gpr = SUBri killed %2, 1, 14, $noreg, $cpsr + STRi12 killed %12, %9, 132, 14, $noreg :: (store 4 into stack + 132) + $r0 = COPY %5 + $r1 = COPY %6 + $r2 = COPY %7 + $r3 = COPY %8 + ADJCALLSTACKUP 136, 0, 14, $noreg, implicit-def dead $sp, implicit $sp + BX_RET 14, $noreg + +... +--- +# CHECK-LABEL: name: test_slt_not +# CHECK-LABEL: bb.1.entry: +# CHECK-NEXT: successors: +# CHECK-NEXT: liveins: $cpsr +# CHECK-LABEL: bb.2.entry: +# CHECK-NEXT: successors: +# CHECK-NEXT: liveins: $cpsr +name: test_slt_not +alignment: 1 +tracksRegLiveness: true +hasWinCFI: false +registers: + - { id: 0, class: tgpr, preferred-register: '' } + - { id: 1, class: tgpr, preferred-register: '' } + - { id: 2, class: tgpr, preferred-register: '' } + - { id: 3, class: tgpr, preferred-register: '' } + - { id: 4, class: tgpr, preferred-register: '' } + - { id: 5, class: tgpr, preferred-register: '' } + - { id: 6, class: tgpr, preferred-register: '' } + - { id: 7, class: tgpr, preferred-register: '' } + - { id: 8, class: tgpr, preferred-register: '' } + - { id: 9, class: tgpr, preferred-register: '' } + - { id: 10, class: tgpr, preferred-register: '' } + - { id: 11, class: tgpr, preferred-register: '' } +liveins: + - { reg: '$r2', virtual-reg: '%2' } + - { reg: '$r3', virtual-reg: '%3' } +frameInfo: +fixedStack: + - { id: 0, type: default, offset: 4, size: 4, alignment: 4, stack-id: 0, + isImmutable: true, isAliased: false, callee-saved-register: '', callee-saved-restored: true, + debug-info-variable: '', debug-info-expression: '', debug-info-location: '' } + - { id: 1, type: default, offset: 0, size: 4, alignment: 8, stack-id: 0, + isImmutable: true, isAliased: false, callee-saved-register: '', callee-saved-restored: true, + debug-info-variable: '', debug-info-expression: '', debug-info-location: '' } +stack: [] +constants: [] +body: | + bb.0.entry: + liveins: $r2, $r3 + + %3:tgpr = COPY $r3 + %2:tgpr = COPY $r2 + %4:tgpr, dead $cpsr = tMOVi8 1, 14, $noreg + %5:tgpr, dead $cpsr = tMOVi8 0, 14, $noreg + %6:tgpr = tLDRspi %fixed-stack.0, 0, 14, $noreg :: (load 4 from %fixed-stack.0) + %7:tgpr = tLDRspi %fixed-stack.1, 0, 14, $noreg :: (load 4 from %fixed-stack.1, align 8) + %8:tgpr, $cpsr = tSUBrr %2, killed %7, 14, $noreg + %9:tgpr, $cpsr = tSBC %3, %6, 14, $noreg, implicit $cpsr + %10:tgpr = tMOVCCr_pseudo %5, %4, 11, $cpsr + %11:tgpr = tMOVCCr_pseudo %5, %4, 10, $cpsr + $r0 = COPY %10 + $r1 = COPY %11 + %12:tgpr, $cpsr = tSBC %3, killed %6, 14, $noreg, implicit $cpsr + STRi12 killed %12, %2, 132, 14, $noreg :: (store 4 into stack + 132) + tBX_RET 14, $noreg, implicit $r0, implicit $r1 +...