diff --git a/llvm/lib/Transforms/IPO/IROutliner.cpp b/llvm/lib/Transforms/IPO/IROutliner.cpp index 142ce10449f319..c355048df449bd 100644 --- a/llvm/lib/Transforms/IPO/IROutliner.cpp +++ b/llvm/lib/Transforms/IPO/IROutliner.cpp @@ -691,8 +691,6 @@ static void moveFunctionData(Function &Old, Function &New, for (Instruction *I : DebugInsts) I->eraseFromParent(); } - - assert(NewEnds.size() > 0 && "No return instruction for new function?"); } /// Find the the constants that will need to be lifted into arguments diff --git a/llvm/test/Transforms/IROutliner/outlining-no-return-functions.ll b/llvm/test/Transforms/IROutliner/outlining-no-return-functions.ll new file mode 100644 index 00000000000000..1a7af015c0f81e --- /dev/null +++ b/llvm/test/Transforms/IROutliner/outlining-no-return-functions.ll @@ -0,0 +1,55 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --include-generated-funcs +; RUN: opt -S -verify -iroutliner -ir-outlining-no-cost < %s | FileCheck %s + +; Make sure that we outline safely from functions with no return instructions. + +; The code extractor will insert return instructions in the outer function +; due to assumptions about the contents of the outlined region. + +define void @f1() { +bb: + br label %bb1 +bb1: + br label %bb1 +} + +define void @f2() { +bb: + br label %bb1 +bb1: + br label %bb1 +} + +define void @f3() { +bb: + br label %bb1 +bb1: + br label %bb1 +} +; CHECK-LABEL: @f1( +; CHECK-NEXT: bb: +; CHECK-NEXT: br label [[BB1:%.*]] +; CHECK: bb1: +; CHECK-NEXT: br label [[BB1]] +; +; +; CHECK-LABEL: @f2( +; CHECK-NEXT: bb: +; CHECK-NEXT: call void @outlined_ir_func_0() +; CHECK-NEXT: ret void +; +; +; CHECK-LABEL: @f3( +; CHECK-NEXT: bb: +; CHECK-NEXT: call void @outlined_ir_func_0() +; CHECK-NEXT: ret void +; +; +; CHECK-LABEL: define internal void @outlined_ir_func_0( +; CHECK-NEXT: newFuncRoot: +; CHECK-NEXT: br label [[BB_TO_OUTLINE:%.*]] +; CHECK: bb_to_outline: +; CHECK-NEXT: br label [[BB1:%.*]] +; CHECK: bb1: +; CHECK-NEXT: br label [[BB1]] +;