diff --git a/llvm/include/llvm/CodeGen/MachineOutliner.h b/llvm/include/llvm/CodeGen/MachineOutliner.h --- a/llvm/include/llvm/CodeGen/MachineOutliner.h +++ b/llvm/include/llvm/CodeGen/MachineOutliner.h @@ -146,9 +146,15 @@ LRU.addLiveOuts(*MBB); // Compute liveness from the end of the block up to the beginning of the - // outlining candidate. + // outlining candidate. On some targets (such as ARM) If-conversion might + // have introduced predicated terminators when merging blocks, in such cases + // block's liveouts needs to be added again. std::for_each(MBB->rbegin(), (MachineBasicBlock::reverse_iterator)front(), - [this](MachineInstr &MI) { LRU.stepBackward(MI); }); + [this](MachineInstr &MI) { + if (MI.isTerminator()) + LRU.addLiveOuts(*MBB); + LRU.stepBackward(MI); + }); // Walk over the sequence itself and figure out which registers were used // in the sequence. diff --git a/llvm/test/CodeGen/ARM/machine-outliner-liveness.ll b/llvm/test/CodeGen/ARM/machine-outliner-liveness.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/ARM/machine-outliner-liveness.ll @@ -0,0 +1,150 @@ +; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py +; RUN: llc -enable-machine-outliner -verify-machineinstrs -mtriple=armv8-- \ +; RUN: --stop-after=machine-outliner < %s | FileCheck %s + +target triple = "armv8-unknown-linux-gnueabihf" + +%"mtype" = type { i32, i8*, i32 } + +; Function Attrs: nounwind +declare i32 @foo(i8*, i32) local_unnamed_addr #0 + +; Function Attrs: noreturn nounwind +declare void @bar() local_unnamed_addr #1 + +; Function Attrs: nounwind +define %"mtype"* @f1(%"mtype"* readonly returned %this) unnamed_addr #0 align 2 { + ; CHECK-LABEL: name: f1 + ; CHECK: bb.0.entry: + ; CHECK: liveins: $r0, $r4, $lr + ; CHECK: BL @OUTLINED_FUNCTION_0 + ; CHECK: Bcc %bb.2, 0 /* CC::eq */, killed $cpsr + ; CHECK: bb.1.if.then: + ; CHECK: liveins: $r0, $r4 + ; CHECK: BL @OUTLINED_FUNCTION_2 + ; CHECK: bb.2.if.end: + ; CHECK: liveins: $r4 + ; CHECK: TAILJMPd @OUTLINED_FUNCTION_1 +entry: + %Mapping = getelementptr inbounds %"mtype", %"mtype"* %this, i32 0, i32 1 + %0 = load i8*, i8** %Mapping, align 4 + %tobool = icmp eq i8* %0, null + br i1 %tobool, label %if.end, label %if.then + +if.then: ; preds = %entry + %Size = getelementptr inbounds %"mtype", %"mtype"* %this, i32 0, i32 0 + %1 = load i32, i32* %Size, align 4 + %call = tail call i32 @foo(i8* nonnull %0, i32 %1) #25 + br label %if.end + +if.end: ; preds = %entry, %if.then + ret %"mtype"* %this +} + +; Function Attrs: nounwind +define %"mtype"* @f2(%"mtype"* readonly returned %this) unnamed_addr #0 align 2 { + ; CHECK-LABEL: name: f2 + ; CHECK: bb.0.entry: + ; CHECK: liveins: $r0, $r4, $lr + ; CHECK: BL @OUTLINED_FUNCTION_0 + ; CHECK: Bcc %bb.2, 0 /* CC::eq */, killed $cpsr + ; CHECK: bb.1.if.then: + ; CHECK: liveins: $r0, $r4 + ; CHECK: BL @OUTLINED_FUNCTION_2 + ; CHECK: bb.2.if.end: + ; CHECK: liveins: $r4 + ; CHECK: TAILJMPd @OUTLINED_FUNCTION_1 +entry: + %Mapping = getelementptr inbounds %"mtype", %"mtype"* %this, i32 0, i32 1 + %0 = load i8*, i8** %Mapping, align 4 + %tobool = icmp eq i8* %0, null + br i1 %tobool, label %if.end, label %if.then + +if.then: ; preds = %entry + %Size = getelementptr inbounds %"mtype", %"mtype"* %this, i32 0, i32 0 + %1 = load i32, i32* %Size, align 4 + %call = tail call i32 @foo(i8* nonnull %0, i32 %1) #25 + br label %if.end + +if.end: ; preds = %entry, %if.then + ret %"mtype"* %this +} + +; Function Attrs: nounwind +define %"mtype"* @f3(%"mtype"* readonly returned %this) unnamed_addr #0 align 2 { + ; CHECK-LABEL: name: f3 + ; CHECK: bb.0.entry: + ; CHECK: liveins: $r0, $r4, $lr + ; CHECK: BL @OUTLINED_FUNCTION_0 + ; CHECK: Bcc %bb.2, 0 /* CC::eq */, killed $cpsr + ; CHECK: bb.1.if.then: + ; CHECK: liveins: $r0, $r4 + ; CHECK: BL @OUTLINED_FUNCTION_2 + ; CHECK: bb.2.if.end: + ; CHECK: liveins: $r4 + ; CHECK: TAILJMPd @OUTLINED_FUNCTION_1 +entry: + %Mapping = getelementptr inbounds %"mtype", %"mtype"* %this, i32 0, i32 1 + %0 = load i8*, i8** %Mapping, align 4 + %tobool = icmp eq i8* %0, null + br i1 %tobool, label %if.end, label %if.then + +if.then: ; preds = %entry + %Size = getelementptr inbounds %"mtype", %"mtype"* %this, i32 0, i32 0 + %1 = load i32, i32* %Size, align 4 + %call = tail call i32 @foo(i8* nonnull %0, i32 %1) #25 + br label %if.end + +if.end: ; preds = %entry, %if.then + ret %"mtype"* %this +} + +; Function Attrs: nounwind +define i8* @f4(%"mtype"* nocapture readonly %this) local_unnamed_addr #0 align 2 { + ; CHECK-LABEL: name: f4 + ; CHECK: bb.0.entry: + ; CHECK: liveins: $r0 + ; CHECK: renamable $r0 = LDRi12 killed renamable $r0, 4, 14 /* CC::al */, $noreg + ; CHECK: CMPri renamable $r0, 0, 14 /* CC::al */, $noreg, implicit-def $cpsr + ; CHECK: BX_RET 1 /* CC::ne */, killed $cpsr, implicit killed $r0 + ; CHECK: BL @bar, csr_aapcs, implicit-def dead $lr, implicit $sp, implicit-def $sp +entry: + %Mapping = getelementptr inbounds %"mtype", %"mtype"* %this, i32 0, i32 1 + %0 = load i8*, i8** %Mapping, align 4 + %tobool = icmp eq i8* %0, null + br i1 %tobool, label %cond.false, label %cond.end + +cond.false: ; preds = %entry + tail call void @bar() + unreachable + +cond.end: ; preds = %entry + ret i8* %0 +} + +; Function Attrs: nounwind +define i8* @f5(%"mtype"* nocapture readonly %this) local_unnamed_addr #0 align 2 { + ; CHECK-LABEL: name: f5 + ; CHECK: bb.0.entry: + ; CHECK: liveins: $r0 + ; CHECK: renamable $r0 = LDRi12 killed renamable $r0, 4, 14 /* CC::al */, $noreg + ; CHECK: CMPri renamable $r0, 0, 14 /* CC::al */, $noreg, implicit-def $cpsr + ; CHECK: BX_RET 1 /* CC::ne */, killed $cpsr, implicit killed $r0 + ; CHECK: BL @bar, csr_aapcs, implicit-def dead $lr, implicit $sp, implicit-def $sp +entry: + %Mapping = getelementptr inbounds %"mtype", %"mtype"* %this, i32 0, i32 1 + %0 = load i8*, i8** %Mapping, align 4 + %tobool = icmp eq i8* %0, null + br i1 %tobool, label %cond.false, label %cond.end + +cond.false: ; preds = %entry + tail call void @bar() + unreachable + +cond.end: ; preds = %entry + ret i8* %0 +} + +attributes #0 = { nounwind "target-cpu"="generic" "target-features"="+armv8-a,-thumb-mode" } +attributes #1 = { noreturn nounwind "target-cpu"="generic" "target-features"="+armv8-a,-thumb-mode" } +attributes #2 = { noreturn nounwind }