[llvm] [Extractor] Use function return for the one and only output (PR #191824)
Shimin Cui via llvm-commits
llvm-commits at lists.llvm.org
Thu Apr 16 08:04:33 PDT 2026
https://github.com/scui-ibm updated https://github.com/llvm/llvm-project/pull/191824
>From 8bab39ea3ac9e6633a82c7655a13780cb5e360bf Mon Sep 17 00:00:00 2001
From: Shimin Cui <scui at ca.ibm.com>
Date: Mon, 13 Apr 2026 14:11:58 +0000
Subject: [PATCH 1/5] [Extractor] Use function return for the one and only
output
---
.../llvm/Transforms/Utils/CodeExtractor.h | 18 ++-
llvm/lib/Transforms/IPO/BlockExtractor.cpp | 5 +-
llvm/lib/Transforms/IPO/IROutliner.cpp | 4 +-
llvm/lib/Transforms/Utils/CodeExtractor.cpp | 37 ++++--
.../CodeExtractor/PartialInlineAnd.ll | 2 +-
.../CodeExtractor/PartialInlineAttributes.ll | 8 +-
.../CodeExtractor/PartialInlineDebug.ll | 8 +-
.../PartialInlineInvokeProducesOutVal.ll | 11 +-
.../CodeExtractor/PartialInlineOrAnd.ll | 2 +-
.../PartialInlineVarArgsDebug.ll | 4 +-
.../HotColdSplit/apply-penalty-for-outputs.ll | 6 +-
.../HotColdSplit/duplicate-phi-preds-crash.ll | 4 +-
.../phi-with-distinct-outlined-values.ll | 5 +-
.../HotColdSplit/split-phis-in-exit-blocks.ll | 8 +-
.../HotColdSplit/succ-block-with-self-edge.ll | 8 +-
.../Transforms/Utils/CodeExtractorTest.cpp | 108 +++++++++++++++---
16 files changed, 171 insertions(+), 67 deletions(-)
diff --git a/llvm/include/llvm/Transforms/Utils/CodeExtractor.h b/llvm/include/llvm/Transforms/Utils/CodeExtractor.h
index e117a33d3435f..b86e0a00d9c80 100644
--- a/llvm/include/llvm/Transforms/Utils/CodeExtractor.h
+++ b/llvm/include/llvm/Transforms/Utils/CodeExtractor.h
@@ -132,6 +132,13 @@ class LLVM_ABI CodeExtractor {
// space.
bool ArgsInZeroAddressSpace;
+ // If true, the outlined function always return void even when there is only
+ // one output.
+ bool VoidReturnWithSingleOutput;
+
+ // If set, the return value of the outline function.
+ Value *FuncRetVal = nullptr;
+
public:
/// Create a code extractor for a sequence of blocks.
///
@@ -147,13 +154,16 @@ class LLVM_ABI CodeExtractor {
/// which case it will be placed in the entry block of the function from which
/// the code is being extracted. If ArgsInZeroAddressSpace param is set to
/// true, then the aggregate param pointer of the outlined function is
- /// declared in zero address space.
+ /// declared in zero address space. If VoidReturnWithSingleOutput is set to
+ /// true, then the return type of the outlined function is set void even if
+ /// there is only one output.
CodeExtractor(ArrayRef<BasicBlock *> BBs, DominatorTree *DT = nullptr,
bool AggregateArgs = false, BlockFrequencyInfo *BFI = nullptr,
BranchProbabilityInfo *BPI = nullptr,
AssumptionCache *AC = nullptr, bool AllowVarArgs = false,
bool AllowAlloca = false, BasicBlock *AllocationBlock = nullptr,
- std::string Suffix = "", bool ArgsInZeroAddressSpace = false);
+ std::string Suffix = "", bool ArgsInZeroAddressSpace = false,
+ bool VoidReturnWithSingleOutput = false);
/// Perform the extraction, returning the new function.
///
@@ -201,7 +211,7 @@ class LLVM_ABI CodeExtractor {
/// on the cost however.
void findInputsOutputs(ValueSet &Inputs, ValueSet &Outputs,
const ValueSet &Allocas,
- bool CollectGlobalInputs = false) const;
+ bool CollectGlobalInputs = false);
/// Check if life time marker nodes can be hoisted/sunk into the outline
/// region.
@@ -300,7 +310,7 @@ class LLVM_ABI CodeExtractor {
/// into the original function's control flow.
void
insertReplacerCall(Function *oldFunction, BasicBlock *header,
- BasicBlock *codeReplacer, const ValueSet &outputs,
+ CallInst *ReplacerCall, const ValueSet &outputs,
ArrayRef<Value *> Reloads,
const DenseMap<BasicBlock *, BlockFrequency> &ExitWeights);
};
diff --git a/llvm/lib/Transforms/IPO/BlockExtractor.cpp b/llvm/lib/Transforms/IPO/BlockExtractor.cpp
index 23991afc511a0..52a20227da633 100644
--- a/llvm/lib/Transforms/IPO/BlockExtractor.cpp
+++ b/llvm/lib/Transforms/IPO/BlockExtractor.cpp
@@ -168,7 +168,10 @@ bool BlockExtractor::runOnModule(Module &M) {
Changed = true;
}
CodeExtractorAnalysisCache CEAC(*BBs[0]->getParent());
- Function *F = CodeExtractor(BlocksToExtractVec).extractCodeRegion(CEAC);
+ Function *F =
+ CodeExtractor(BlocksToExtractVec, nullptr, false, nullptr, nullptr,
+ nullptr, false, false, nullptr, "", false, true)
+ .extractCodeRegion(CEAC);
if (F)
LLVM_DEBUG(dbgs() << "Extracted group '" << (*BBs.begin())->getName()
<< "' in: " << F->getName() << '\n');
diff --git a/llvm/lib/Transforms/IPO/IROutliner.cpp b/llvm/lib/Transforms/IPO/IROutliner.cpp
index 41c036496487c..08a77993423af 100644
--- a/llvm/lib/Transforms/IPO/IROutliner.cpp
+++ b/llvm/lib/Transforms/IPO/IROutliner.cpp
@@ -2789,7 +2789,7 @@ unsigned IROutliner::doOutline(Module &M) {
OS->Candidate->getBasicBlocks(BlocksInRegion, BE);
OS->CE = new (ExtractorAllocator.Allocate())
CodeExtractor(BE, nullptr, false, nullptr, nullptr, nullptr, false,
- false, nullptr, "outlined");
+ false, nullptr, "outlined", false, true);
findAddInputsOutputs(M, *OS, NotSame);
if (!OS->IgnoreRegion)
OutlinedRegions.push_back(OS);
@@ -2900,7 +2900,7 @@ unsigned IROutliner::doOutline(Module &M) {
OS->Candidate->getBasicBlocks(BlocksInRegion, BE);
OS->CE = new (ExtractorAllocator.Allocate())
CodeExtractor(BE, nullptr, false, nullptr, nullptr, nullptr, false,
- false, nullptr, "outlined");
+ false, nullptr, "outlined", false, true);
bool FunctionOutlined = extractSection(*OS);
if (FunctionOutlined) {
unsigned StartIdx = OS->Candidate->getStartIdx();
diff --git a/llvm/lib/Transforms/Utils/CodeExtractor.cpp b/llvm/lib/Transforms/Utils/CodeExtractor.cpp
index 8faf64a60997c..28db49daf2efa 100644
--- a/llvm/lib/Transforms/Utils/CodeExtractor.cpp
+++ b/llvm/lib/Transforms/Utils/CodeExtractor.cpp
@@ -264,12 +264,14 @@ CodeExtractor::CodeExtractor(ArrayRef<BasicBlock *> BBs, DominatorTree *DT,
BranchProbabilityInfo *BPI, AssumptionCache *AC,
bool AllowVarArgs, bool AllowAlloca,
BasicBlock *AllocationBlock, std::string Suffix,
- bool ArgsInZeroAddressSpace)
+ bool ArgsInZeroAddressSpace,
+ bool VoidReturnWithSingleOutput)
: DT(DT), AggregateArgs(AggregateArgs || AggregateArgsOpt), BFI(BFI),
BPI(BPI), AC(AC), AllocationBlock(AllocationBlock),
AllowVarArgs(AllowVarArgs),
Blocks(buildExtractionBlockSet(BBs, DT, AllowVarArgs, AllowAlloca)),
- Suffix(Suffix), ArgsInZeroAddressSpace(ArgsInZeroAddressSpace) {}
+ Suffix(Suffix), ArgsInZeroAddressSpace(ArgsInZeroAddressSpace),
+ VoidReturnWithSingleOutput(VoidReturnWithSingleOutput) {}
/// definedInRegion - Return true if the specified value is defined in the
/// extracted region.
@@ -662,7 +664,7 @@ bool CodeExtractor::isEligible() const {
void CodeExtractor::findInputsOutputs(ValueSet &Inputs, ValueSet &Outputs,
const ValueSet &SinkCands,
- bool CollectGlobalInputs) const {
+ bool CollectGlobalInputs) {
for (BasicBlock *BB : Blocks) {
// If a used value is defined outside the region, it's an input. If an
// instruction is used outside the region, it's an output.
@@ -682,6 +684,12 @@ void CodeExtractor::findInputsOutputs(ValueSet &Inputs, ValueSet &Outputs,
}
}
}
+
+ if (!VoidReturnWithSingleOutput && !AggregateArgs && Outputs.size() == 1 &&
+ getCommonExitBlock(Blocks)) {
+ FuncRetVal = Outputs[0];
+ Outputs.clear();
+ }
}
/// severSplitPHINodesOfEntry - If a PHI node has multiple inputs from outside
@@ -877,7 +885,7 @@ Function *CodeExtractor::constructFunctionDeclaration(
M->getContext(), ArgsInZeroAddressSpace ? 0 : DL.getAllocaAddrSpace()));
}
- Type *RetTy = getSwitchType();
+ Type *RetTy = FuncRetVal ? FuncRetVal->getType() : getSwitchType();
LLVM_DEBUG({
dbgs() << "Function type: " << *RetTy << " f(";
for (Type *i : ParamTy)
@@ -1519,8 +1527,8 @@ CodeExtractor::extractCodeRegion(const CodeExtractorAnalysisCache &CEAC,
inputs, outputs, StructValues, newFunction, StructTy, oldFunction, ReplIP,
EntryFreq, LifetimesStart.getArrayRef(), Reloads);
- insertReplacerCall(oldFunction, header, TheCall->getParent(), outputs,
- Reloads, ExitWeights);
+ insertReplacerCall(oldFunction, header, TheCall, outputs, Reloads,
+ ExitWeights);
fixupDebugInfoPostExtraction(*oldFunction, *newFunction, *TheCall, inputs,
NewValues);
@@ -1699,14 +1707,17 @@ void CodeExtractor::emitFunctionBody(
ExitBlockMap[OldTarget] = NewTarget;
Value *brVal = nullptr;
- Type *RetTy = getSwitchType();
+ Type *RetTy = FuncRetVal ? FuncRetVal->getType() : getSwitchType();
assert(ExtractedFuncRetVals.size() < 0xffff &&
"too many exit blocks for switch");
switch (ExtractedFuncRetVals.size()) {
case 0:
- case 1:
// No value needed.
break;
+ case 1:
+ if (FuncRetVal)
+ brVal = FuncRetVal;
+ break;
case 2: // Conditional branch, return a bool
brVal = ConstantInt::get(RetTy, !SuccNum);
break;
@@ -2019,13 +2030,14 @@ CallInst *CodeExtractor::emitReplacerCall(
}
void CodeExtractor::insertReplacerCall(
- Function *oldFunction, BasicBlock *header, BasicBlock *codeReplacer,
+ Function *oldFunction, BasicBlock *header, CallInst *ReplacerCall,
const ValueSet &outputs, ArrayRef<Value *> Reloads,
const DenseMap<BasicBlock *, BlockFrequency> &ExitWeights) {
// Rewrite branches to basic blocks outside of the loop to new dummy blocks
// within the new function. This must be done before we lose track of which
// blocks were originally in the code region.
+ BasicBlock *codeReplacer = ReplacerCall->getParent();
std::vector<User *> Users(header->user_begin(), header->user_end());
for (auto &U : Users)
// The BasicBlock which contains the branch is not in the region
@@ -2067,6 +2079,13 @@ void CodeExtractor::insertReplacerCall(
}
}
+ if (FuncRetVal)
+ for (User *U : FuncRetVal->users()) {
+ Instruction *inst = cast<Instruction>(U);
+ if (inst->getParent()->getParent() == oldFunction)
+ inst->replaceUsesOfWith(FuncRetVal, ReplacerCall);
+ }
+
// Update the branch weights for the exit block.
if (BFI && ExtractedFuncRetVals.size() > 1)
calculateNewCallTerminatorWeights(codeReplacer, ExitWeights, BPI);
diff --git a/llvm/test/Transforms/CodeExtractor/PartialInlineAnd.ll b/llvm/test/Transforms/CodeExtractor/PartialInlineAnd.ll
index 438a598324635..4b3db2a48e572 100644
--- a/llvm/test/Transforms/CodeExtractor/PartialInlineAnd.ll
+++ b/llvm/test/Transforms/CodeExtractor/PartialInlineAnd.ll
@@ -43,7 +43,7 @@ bb:
; LIMIT-LABEL: @dummy_caller
; LIMIT: br i1
; LIMIT-NOT: br
-; LIMIT: call void @bar.1.
+; LIMIT: call i32 @bar.1.
%tmp = tail call i32 @bar(i32 %arg)
ret i32 %tmp
}
diff --git a/llvm/test/Transforms/CodeExtractor/PartialInlineAttributes.ll b/llvm/test/Transforms/CodeExtractor/PartialInlineAttributes.ll
index b085e34d52648..1246c5de6834f 100644
--- a/llvm/test/Transforms/CodeExtractor/PartialInlineAttributes.ll
+++ b/llvm/test/Transforms/CodeExtractor/PartialInlineAttributes.ll
@@ -55,9 +55,9 @@ if.end:
ret i32 %add
}
; CHECK-LABEL: @caller
-; CHECK: call void @callee_most.2.if.then(i32 %v
+; CHECK: call i32 @callee_most.2.if.then(i32 %v
; CHECK: call i32 @callee_noinline(i32 %v)
-; CHECK: call void @callee_writeonly.1.if.then(i32 %v
+; CHECK: call i32 @callee_writeonly.1.if.then(i32 %v
define i32 @caller(i32 %v) ssp {
entry:
%c1 = call i32 @callee_most(i32 %v)
@@ -66,8 +66,8 @@ entry:
ret i32 %c3
}
-; CHECK: define internal void @callee_writeonly.1.if.then(i32 %v, ptr %sub.out) [[FN_ATTRS0:#[0-9]+]]
-; CHECK: define internal void @callee_most.2.if.then(i32 %v, ptr %sub.out) [[FN_ATTRS:#[0-9]+]]
+; CHECK: define internal i32 @callee_writeonly.1.if.then(i32 %v) [[FN_ATTRS0:#[0-9]+]]
+; CHECK: define internal i32 @callee_most.2.if.then(i32 %v) [[FN_ATTRS:#[0-9]+]]
; attributes to preserve
attributes #0 = {
diff --git a/llvm/test/Transforms/CodeExtractor/PartialInlineDebug.ll b/llvm/test/Transforms/CodeExtractor/PartialInlineDebug.ll
index ab01bbf20de71..af01ea1421cf5 100644
--- a/llvm/test/Transforms/CodeExtractor/PartialInlineDebug.ll
+++ b/llvm/test/Transforms/CodeExtractor/PartialInlineDebug.ll
@@ -24,7 +24,7 @@ if.end: ; preds = %if.then, %entry
; CHECK-LABEL: @caller
; CHECK: codeRepl.i:
; CHECK-NOT: br label
-; CHECK: call void @callee.2.if.then(i32 %v, ptr %mul.loc.i), !dbg ![[DBG2:[0-9]+]]
+; CHECK: call i32 @callee.2.if.then(i32 %v), !dbg ![[DBG2:[0-9]+]]
define i32 @caller(i32 %v) !dbg !8 {
entry:
%call = call i32 @callee(i32 %v), !dbg !14
@@ -55,17 +55,17 @@ if.end:
; CHECK-LABEL: @caller2
; CHECK: codeRepl.i:
; CHECK-NOT: br label
-; CHECK: call void @callee2.1.if.then(i32 %v, ptr %sub.loc.i), !dbg ![[DBG4:[0-9]+]]
+; CHECK: call i32 @callee2.1.if.then(i32 %v), !dbg ![[DBG4:[0-9]+]]
define i32 @caller2(i32 %v) !dbg !21 {
entry:
%call = call i32 @callee2(i32 %v), !dbg !22
ret i32 %call
}
-; CHECK-LABEL: define internal void @callee2.1.if.then
+; CHECK-LABEL: define internal i32 @callee2.1.if.then
; CHECK: br label %if.then, !dbg ![[DBG5:[0-9]+]]
-; CHECK-LABEL: define internal void @callee.2.if.then
+; CHECK-LABEL: define internal i32 @callee.2.if.then
; CHECK: br label %if.then, !dbg ![[DBG6:[0-9]+]]
; CHECK: ![[DBG1]] = !DILocation(line: 10, column: 7,
diff --git a/llvm/test/Transforms/CodeExtractor/PartialInlineInvokeProducesOutVal.ll b/llvm/test/Transforms/CodeExtractor/PartialInlineInvokeProducesOutVal.ll
index 5e0ce20645265..d598174544c5b 100644
--- a/llvm/test/Transforms/CodeExtractor/PartialInlineInvokeProducesOutVal.ll
+++ b/llvm/test/Transforms/CodeExtractor/PartialInlineInvokeProducesOutVal.ll
@@ -24,25 +24,22 @@ bb5: ; preds = %bb4, %bb1, %bb
; CHECK-LABEL: @dummy_caller
; CHECK-LABEL: bb:
-; CHECK-NEXT: [[CALL26LOC:%.*]] = alloca ptr
; CHECK-LABEL: codeRepl.i:
-; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[CALL26LOC]])
-; CHECK-NEXT: call void @bar.1.bb1(ptr [[CALL26LOC]])
-; CHECK-NEXT: %call26.reload.i = load ptr, ptr [[CALL26LOC]]
-; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[CALL26LOC]])
+; CHECK-NEXT: call ptr @bar.1.bb1()
define ptr @dummy_caller(i32 %arg) {
bb:
%tmp = tail call ptr @bar(i32 %arg)
ret ptr %tmp
}
-; CHECK-LABEL: define internal void @bar.1.bb1
+; CHECK-LABEL: define internal ptr @bar.1.bb1
; CHECK-LABEL: bb1:
; CHECK-NEXT: %call26 = invoke ptr @invoke_callee()
; CHECK-NEXT: to label %cont unwind label %lpad
; CHECK-LABEL: cont:
-; CHECK-NEXT: store ptr %call26, ptr %call26.out
; CHECK-NEXT: br label %bb5.exitStub
+; CHECK-LABEL: bb5.exitStub:
+; CHECK-NEXT: ret ptr %call26
; Function Attrs: nobuiltin
declare dso_local noalias nonnull ptr @invoke_callee() local_unnamed_addr #1
diff --git a/llvm/test/Transforms/CodeExtractor/PartialInlineOrAnd.ll b/llvm/test/Transforms/CodeExtractor/PartialInlineOrAnd.ll
index 2b357a893419c..6a74c345267d1 100644
--- a/llvm/test/Transforms/CodeExtractor/PartialInlineOrAnd.ll
+++ b/llvm/test/Transforms/CodeExtractor/PartialInlineOrAnd.ll
@@ -54,7 +54,7 @@ bb:
; LIMIT3: br i1
; LIMIT3: br i1
; LIMIT3-NOT: br i1
-; LIMIT3: call void @bar.1.
+; LIMIT3: call i32 @bar.1.
; LIMIT2-LABEL: @dummy_caller
; LIMIT2-NOT: br i1
; LIMIT2: call i32 @bar(
diff --git a/llvm/test/Transforms/CodeExtractor/PartialInlineVarArgsDebug.ll b/llvm/test/Transforms/CodeExtractor/PartialInlineVarArgsDebug.ll
index d0f9e01f950a2..c68729ea231b9 100644
--- a/llvm/test/Transforms/CodeExtractor/PartialInlineVarArgsDebug.ll
+++ b/llvm/test/Transforms/CodeExtractor/PartialInlineVarArgsDebug.ll
@@ -20,14 +20,14 @@ if.end: ; preds = %if.then, %entry
; CHECK-LABEL: @caller
; CHECK: codeRepl.i:
; CHECK-NOT: br label
-; CHECK: call void (i32, ptr, ...) @callee.1.if.then(i32 %v, ptr %mul.loc.i, i32 99), !dbg ![[DBG2:[0-9]+]]
+; CHECK: call i32 (i32, ...) @callee.1.if.then(i32 %v, i32 99), !dbg ![[DBG2:[0-9]+]]
define i32 @caller(i32 %v) !dbg !8 {
entry:
%call = call i32 (i32, ...) @callee(i32 %v, i32 99), !dbg !14
ret i32 %call, !dbg !15
}
-; CHECK-LABEL: define internal void @callee.1.if.then
+; CHECK-LABEL: define internal i32 @callee.1.if.then
; CHECK: br label %if.then, !dbg ![[DBG3:[0-9]+]]
; CHECK: ![[DBG1]] = !DILocation(line: 10, column: 7,
diff --git a/llvm/test/Transforms/HotColdSplit/apply-penalty-for-outputs.ll b/llvm/test/Transforms/HotColdSplit/apply-penalty-for-outputs.ll
index 96d73088e7874..d4cfccf2bff15 100644
--- a/llvm/test/Transforms/HotColdSplit/apply-penalty-for-outputs.ll
+++ b/llvm/test/Transforms/HotColdSplit/apply-penalty-for-outputs.ll
@@ -11,9 +11,9 @@ entry:
cold:
; CHECK: Applying penalty for splitting: 2
- ; CHECK-NEXT: Applying penalty for: 1 params
- ; CHECK-NEXT: Applying penalty for: 1 outputs/split phis
- ; CHECK-NEXT: penalty = 7
+ ; CHECK-NEXT: Applying penalty for: 0 params
+ ; CHECK-NEXT: Applying penalty for: 0 outputs/split phis
+ ; CHECK-NEXT: penalty = 2
%local = load i32, ptr @g
call void @sink()
br label %exit
diff --git a/llvm/test/Transforms/HotColdSplit/duplicate-phi-preds-crash.ll b/llvm/test/Transforms/HotColdSplit/duplicate-phi-preds-crash.ll
index ec772ce181a12..de6d60c825a40 100644
--- a/llvm/test/Transforms/HotColdSplit/duplicate-phi-preds-crash.ll
+++ b/llvm/test/Transforms/HotColdSplit/duplicate-phi-preds-crash.ll
@@ -15,9 +15,9 @@ declare void @sink() cold
; CHECK: call {{.*}}@sideeffect(
; CHECK: call {{.*}}@realloc(
; CHECK-LABEL: codeRepl:
-; CHECK: call {{.*}}@realloc2.cold.1(i64 %size, ptr %ptr, ptr %retval.0.ce.loc)
+; CHECK: %2 = call {{.*}}@realloc2.cold.1(i64 %size, ptr %ptr)
; CHECK-LABEL: cleanup:
-; CHECK-NEXT: phi ptr [ null, %if.then ], [ %call, %if.end ], [ %retval.0.ce.reload, %codeRepl ]
+; CHECK-NEXT: phi ptr [ null, %if.then ], [ %call, %if.end ], [ %2, %codeRepl ]
define ptr @realloc2(ptr %ptr, i64 %size) {
entry:
%0 = add i64 %size, -1
diff --git a/llvm/test/Transforms/HotColdSplit/phi-with-distinct-outlined-values.ll b/llvm/test/Transforms/HotColdSplit/phi-with-distinct-outlined-values.ll
index 7c07cd35a527c..d353adef057af 100644
--- a/llvm/test/Transforms/HotColdSplit/phi-with-distinct-outlined-values.ll
+++ b/llvm/test/Transforms/HotColdSplit/phi-with-distinct-outlined-values.ll
@@ -4,12 +4,13 @@ target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.14.0"
; CHECK-LABEL: define {{.*}}@foo(
-; CHECK: phi i32 [ 0, %entry ], [ %p.ce.reload, %codeRepl ]
+; CHECK: %0 = call {{.*}}@foo.cold.1(i1 %arg)
+; CHECK: phi i32 [ 0, %entry ], [ %0, %codeRepl ]
; CHECK-LABEL: define {{.*}}@foo.cold.1(
; CHECK: call {{.*}}@sink
; CHECK: %p.ce = phi i32 [ 1, %coldbb ], [ 3, %coldbb2 ]
-; CHECK-NEXT: store i32 %p.ce, ptr %p.ce.out
+; CHECK: ret i32 %p.ce
define void @foo(i32 %cond, i1 %arg) {
entry:
diff --git a/llvm/test/Transforms/HotColdSplit/split-phis-in-exit-blocks.ll b/llvm/test/Transforms/HotColdSplit/split-phis-in-exit-blocks.ll
index 915b3393a53b4..8caea59090803 100644
--- a/llvm/test/Transforms/HotColdSplit/split-phis-in-exit-blocks.ll
+++ b/llvm/test/Transforms/HotColdSplit/split-phis-in-exit-blocks.ll
@@ -5,21 +5,17 @@ target triple = "x86_64-apple-macosx10.14.0"
; CHECK-LABEL: define {{.*}}@pluto(
; CHECK-NEXT: bb:
-; CHECK-NEXT: %tmp8.ce.loc = alloca i1
; CHECK-NEXT: switch i8 undef, label %codeRepl [
; CHECK-NEXT: i8 0, label %bb7
; CHECK-NEXT: i8 1, label %bb7
; CHECK-NEXT: ]
;
; CHECK: codeRepl:
-; CHECK-NEXT: lifetime.start
-; CHECK-NEXT: call void @pluto.cold.1(ptr %tmp8.ce.loc)
-; CHECK-NEXT: %tmp8.ce.reload = load i1, ptr %tmp8.ce.loc
-; CHECK-NEXT: lifetime.end
+; CHECK-NEXT: %0 = call i1 @pluto.cold.1()
; CHECK-NEXT: br label %bb7
;
; CHECK: bb7:
-; CHECK: %tmp8 = phi i1 [ true, %bb ], [ true, %bb ], [ %tmp8.ce.reload, %codeRepl ]
+; CHECK: %tmp8 = phi i1 [ true, %bb ], [ true, %bb ], [ %0, %codeRepl ]
; CHECK: ret void
; CHECK-LABEL: define {{.*}}@pluto.cold.1(
diff --git a/llvm/test/Transforms/HotColdSplit/succ-block-with-self-edge.ll b/llvm/test/Transforms/HotColdSplit/succ-block-with-self-edge.ll
index 59efa3d54e249..e528cb7f7965d 100644
--- a/llvm/test/Transforms/HotColdSplit/succ-block-with-self-edge.ll
+++ b/llvm/test/Transforms/HotColdSplit/succ-block-with-self-edge.ll
@@ -4,9 +4,9 @@ target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.14.0"
; CHECK-LABEL: define {{.*}}@exit_block_with_same_incoming_vals
-; CHECK: call {{.*}}@exit_block_with_same_incoming_vals.cold.1(
+; CHECK: %0 = call {{.*}}@exit_block_with_same_incoming_vals.cold.1(
; CHECK-NOT: br i1 %arg
-; CHECK: phi i32 [ 0, %entry ], [ %p.ce.reload, %codeRepl ]
+; CHECK: phi i32 [ 0, %entry ], [ %0, %codeRepl ]
define void @exit_block_with_same_incoming_vals(i32 %cond, i1 %arg) {
entry:
%tobool = icmp eq i32 %cond, 0
@@ -27,9 +27,9 @@ if.end:
}
; CHECK-LABEL: define {{.*}}@exit_block_with_distinct_incoming_vals
-; CHECK: call {{.*}}@exit_block_with_distinct_incoming_vals.cold.1(
+; CHECK: %0 = call {{.*}}@exit_block_with_distinct_incoming_vals.cold.1(
; CHECK-NOT: br i1 %arg
-; CHECK: phi i32 [ 0, %entry ], [ %p.ce.reload, %codeRepl ]
+; CHECK: phi i32 [ 0, %entry ], [ %0, %codeRepl ]
define void @exit_block_with_distinct_incoming_vals(i32 %cond, i1 %arg) {
entry:
%tobool = icmp eq i32 %cond, 0
diff --git a/llvm/unittests/Transforms/Utils/CodeExtractorTest.cpp b/llvm/unittests/Transforms/Utils/CodeExtractorTest.cpp
index 90f06204ec9b3..1e4b530a901d4 100644
--- a/llvm/unittests/Transforms/Utils/CodeExtractorTest.cpp
+++ b/llvm/unittests/Transforms/Utils/CodeExtractorTest.cpp
@@ -69,7 +69,8 @@ TEST(CodeExtractor, ExitStub) {
getBlockByName(Func, "body1"),
getBlockByName(Func, "body2") };
- CodeExtractor CE(Candidates);
+ CodeExtractor CE(Candidates, nullptr, false, nullptr, nullptr, nullptr, false,
+ false, nullptr, "", false, true);
EXPECT_TRUE(CE.isEligible());
CodeExtractorAnalysisCache CEAC(*Func);
@@ -117,7 +118,8 @@ TEST(CodeExtractor, InputOutputMonitoring) {
getBlockByName(Func, "body1"),
getBlockByName(Func, "body2")};
- CodeExtractor CE(Candidates);
+ CodeExtractor CE(Candidates, nullptr, false, nullptr, nullptr, nullptr, false,
+ false, nullptr, "", false, true);
EXPECT_TRUE(CE.isEligible());
CodeExtractorAnalysisCache CEAC(*Func);
@@ -145,6 +147,70 @@ TEST(CodeExtractor, InputOutputMonitoring) {
EXPECT_FALSE(verifyFunction(*Func));
}
+TEST(CodeExtractor, InputOutputReturnMonitoring) {
+ LLVMContext Ctx;
+ SMDiagnostic Err;
+ std::unique_ptr<Module> M(parseAssemblyString(R"invalid(
+ define i32 @foo(i32 %x, i32 %y, i32 %z) {
+ header:
+ %0 = icmp ugt i32 %x, %y
+ br i1 %0, label %body1, label %body2
+
+ body1:
+ %1 = add i32 %z, 2
+ br label %notExtracted
+
+ body2:
+ %2 = mul i32 %z, 7
+ br label %notExtracted
+
+ notExtracted:
+ %3 = phi i32 [ %1, %body1 ], [ %2, %body2 ]
+ %4 = add i32 %3, %x
+ ret i32 %4
+ }
+ )invalid",
+ Err, Ctx));
+
+ Function *Func = M->getFunction("foo");
+ SmallVector<BasicBlock *, 3> Candidates{getBlockByName(Func, "header"),
+ getBlockByName(Func, "body1"),
+ getBlockByName(Func, "body2")};
+
+ CodeExtractor CE(Candidates, nullptr, false, nullptr, nullptr, nullptr, false,
+ false, nullptr, "", false, false);
+ EXPECT_TRUE(CE.isEligible());
+
+ CodeExtractorAnalysisCache CEAC(*Func);
+ SetVector<Value *> Inputs, Outputs;
+ Function *Outlined = CE.extractCodeRegion(CEAC, Inputs, Outputs);
+ EXPECT_TRUE(Outlined);
+
+ EXPECT_EQ(Inputs.size(), 3u);
+ EXPECT_EQ(Inputs[0], Func->getArg(2));
+ EXPECT_EQ(Inputs[1], Func->getArg(0));
+ EXPECT_EQ(Inputs[2], Func->getArg(1));
+ EXPECT_EQ(Outputs.size(), 0u);
+ BasicBlock *Exit = getBlockByName(Func, "notExtracted");
+ BasicBlock *ExitSplit = getBlockByName(Outlined, "notExtracted.split");
+ // Ensure that PHI in exit block has only one incoming value (from code
+ // replacer block).
+ EXPECT_TRUE(Exit && cast<PHINode>(Exit->front()).getNumIncomingValues() == 1);
+ // Ensure that there is a PHI in outlined function with 2 incoming values.
+ EXPECT_TRUE(ExitSplit &&
+ cast<PHINode>(ExitSplit->front()).getNumIncomingValues() == 2);
+
+ BasicBlock *ExitStub = getBlockByName(Outlined, "notExtracted.exitStub");
+ Instruction *ExitTerm = ExitStub->getTerminator();
+ ReturnInst *ExitReturn = dyn_cast<ReturnInst>(ExitTerm);
+ EXPECT_TRUE(ExitReturn);
+ Value *RetVal = ExitReturn->getReturnValue();
+ EXPECT_TRUE(ExitReturn);
+
+ EXPECT_FALSE(verifyFunction(*Outlined));
+ EXPECT_FALSE(verifyFunction(*Func));
+}
+
TEST(CodeExtractor, ExitBlockOrderingPhis) {
LLVMContext Ctx;
SMDiagnostic Err;
@@ -177,7 +243,8 @@ TEST(CodeExtractor, ExitBlockOrderingPhis) {
getBlockByName(Func, "test1"),
getBlockByName(Func, "test") };
- CodeExtractor CE(Candidates);
+ CodeExtractor CE(Candidates, nullptr, false, nullptr, nullptr, nullptr, false,
+ false, nullptr, "", false, true);
EXPECT_TRUE(CE.isEligible());
CodeExtractorAnalysisCache CEAC(*Func);
@@ -234,7 +301,8 @@ TEST(CodeExtractor, ExitBlockOrdering) {
getBlockByName(Func, "test1"),
getBlockByName(Func, "test") };
- CodeExtractor CE(Candidates);
+ CodeExtractor CE(Candidates, nullptr, false, nullptr, nullptr, nullptr, false,
+ false, nullptr, "", false, true);
EXPECT_TRUE(CE.isEligible());
CodeExtractorAnalysisCache CEAC(*Func);
@@ -293,7 +361,8 @@ TEST(CodeExtractor, ExitPHIOnePredFromRegion) {
getBlockByName(Func, "extracted2")
};
- CodeExtractor CE(ExtractedBlocks);
+ CodeExtractor CE(ExtractedBlocks, nullptr, false, nullptr, nullptr, nullptr,
+ false, false, nullptr, "", false, true);
EXPECT_TRUE(CE.isEligible());
CodeExtractorAnalysisCache CEAC(*Func);
@@ -353,7 +422,7 @@ TEST(CodeExtractor, StoreOutputInvokeResultAfterEHPad) {
}
)invalid", Err, Ctx));
- if (!M) {
+ if (!M) {
Err.print("unit", errs());
exit(1);
}
@@ -368,7 +437,8 @@ TEST(CodeExtractor, StoreOutputInvokeResultAfterEHPad) {
getBlockByName(Func, "lpad2")
};
- CodeExtractor CE(ExtractedBlocks);
+ CodeExtractor CE(ExtractedBlocks, nullptr, false, nullptr, nullptr, nullptr,
+ false, false, nullptr, "", false, true);
EXPECT_TRUE(CE.isEligible());
CodeExtractorAnalysisCache CEAC(*Func);
@@ -403,7 +473,8 @@ TEST(CodeExtractor, StoreOutputInvokeResultInExitStub) {
SmallVector<BasicBlock *, 1> Blocks{ getBlockByName(Func, "entry"),
getBlockByName(Func, "lpad") };
- CodeExtractor CE(Blocks);
+ CodeExtractor CE(Blocks, nullptr, false, nullptr, nullptr, nullptr, false,
+ false, nullptr, "", false, true);
EXPECT_TRUE(CE.isEligible());
CodeExtractorAnalysisCache CEAC(*Func);
@@ -455,7 +526,8 @@ TEST(CodeExtractor, ExtractAndInvalidateAssumptionCache) {
Function *Func = M->getFunction("test");
SmallVector<BasicBlock *, 1> Blocks{ getBlockByName(Func, "if.else") };
AssumptionCache AC(*Func);
- CodeExtractor CE(Blocks, nullptr, false, nullptr, nullptr, &AC);
+ CodeExtractor CE(Blocks, nullptr, false, nullptr, nullptr, &AC, false, false,
+ nullptr, "", false, true);
EXPECT_TRUE(CE.isEligible());
CodeExtractorAnalysisCache CEAC(*Func);
@@ -499,7 +571,8 @@ TEST(CodeExtractor, RemoveBitcastUsesFromOuterLifetimeMarkers) {
Function *Func = M->getFunction("foo");
SmallVector<BasicBlock *, 1> Blocks{getBlockByName(Func, "extract")};
- CodeExtractor CE(Blocks);
+ CodeExtractor CE(Blocks, nullptr, false, nullptr, nullptr, nullptr, false,
+ false, nullptr, "", false, true);
EXPECT_TRUE(CE.isEligible());
CodeExtractorAnalysisCache CEAC(*Func);
@@ -554,7 +627,8 @@ TEST(CodeExtractor, PartialAggregateArgs) {
// Create the CodeExtractor with arguments aggregation enabled.
CodeExtractor CE(Blocks, /* DominatorTree */ nullptr,
- /* AggregateArgs */ true);
+ /* AggregateArgs */ true, nullptr, nullptr, nullptr, false,
+ false, nullptr, "", false, true);
EXPECT_TRUE(CE.isEligible());
CodeExtractorAnalysisCache CEAC(*Func);
@@ -602,7 +676,7 @@ TEST(CodeExtractor, AllocaBlock) {
BasicBlock *AllocaBlock = getBlockByName(Func, "allocas");
CodeExtractor CE(Candidates, nullptr, true, nullptr, nullptr, nullptr, false,
- false, AllocaBlock);
+ false, AllocaBlock, "", false, true);
CE.excludeArgFromAggregate(Func->getArg(0));
CE.excludeArgFromAggregate(getInstByName(Func, "w"));
EXPECT_TRUE(CE.isEligible());
@@ -656,7 +730,8 @@ TEST(CodeExtractor, PartialAggregateArgs2) {
// Create the CodeExtractor with arguments aggregation enabled.
CodeExtractor CE(Blocks, /* DominatorTree */ nullptr,
- /* AggregateArgs */ true);
+ /* AggregateArgs */ true, nullptr, nullptr, nullptr, false,
+ false, nullptr, "", false, true);
EXPECT_TRUE(CE.isEligible());
CodeExtractorAnalysisCache CEAC(*Func);
@@ -713,7 +788,8 @@ TEST(CodeExtractor, OpenMPAggregateArgs) {
/* AllowAlloca */ true,
/* AllocaBlock*/ &Func->getEntryBlock(),
/* Suffix */ ".outlined",
- /* ArgsInZeroAddressSpace */ true);
+ /* ArgsInZeroAddressSpace */ true,
+ /* VoidReturnWithSingleOutput */ true);
EXPECT_TRUE(CE.isEligible());
@@ -779,7 +855,9 @@ TEST(CodeExtractor, ArgsDebugInfo) {
SmallVector<BasicBlock *, 1> Blocks{getBlockByName(Func, "extract")};
auto TestExtracted = [&](bool AggregateArgs) {
- CodeExtractor CE(Blocks, /* DominatorTree */ nullptr, AggregateArgs);
+ CodeExtractor CE(Blocks, /* DominatorTree */ nullptr, AggregateArgs,
+ nullptr, nullptr, nullptr, false, false, nullptr, "",
+ false, true);
EXPECT_TRUE(CE.isEligible());
CodeExtractorAnalysisCache CEAC(*Func);
SetVector<Value *> Inputs, Outputs, SinkingCands, HoistingCands;
>From 26fd87978411a51b84bd4541940d0466fd7bfdbf Mon Sep 17 00:00:00 2001
From: Shimin Cui <scui at ca.ibm.com>
Date: Mon, 13 Apr 2026 15:27:17 +0000
Subject: [PATCH 2/5] Fix build errors
---
llvm/unittests/Transforms/Utils/CodeExtractorTest.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/unittests/Transforms/Utils/CodeExtractorTest.cpp b/llvm/unittests/Transforms/Utils/CodeExtractorTest.cpp
index 1e4b530a901d4..d1c4bb5cb6c6c 100644
--- a/llvm/unittests/Transforms/Utils/CodeExtractorTest.cpp
+++ b/llvm/unittests/Transforms/Utils/CodeExtractorTest.cpp
@@ -205,7 +205,7 @@ TEST(CodeExtractor, InputOutputReturnMonitoring) {
ReturnInst *ExitReturn = dyn_cast<ReturnInst>(ExitTerm);
EXPECT_TRUE(ExitReturn);
Value *RetVal = ExitReturn->getReturnValue();
- EXPECT_TRUE(ExitReturn);
+ EXPECT_TRUE(RetVal);
EXPECT_FALSE(verifyFunction(*Outlined));
EXPECT_FALSE(verifyFunction(*Func));
>From e623ced0efb6dd2b803d8f731a204eb75c720884 Mon Sep 17 00:00:00 2001
From: Shimin Cui <scui at ca.ibm.com>
Date: Tue, 14 Apr 2026 17:15:49 +0000
Subject: [PATCH 3/5] Set VoidReturnWithSingleOutput default true
---
.../llvm/Transforms/Utils/CodeExtractor.h | 2 +-
llvm/lib/Transforms/IPO/BlockExtractor.cpp | 5 +--
llvm/lib/Transforms/IPO/HotColdSplitting.cpp | 2 +-
llvm/lib/Transforms/IPO/IROutliner.cpp | 4 +-
llvm/lib/Transforms/IPO/PartialInlining.cpp | 4 +-
.../Transforms/Utils/CodeExtractorTest.cpp | 42 +++++++------------
6 files changed, 21 insertions(+), 38 deletions(-)
diff --git a/llvm/include/llvm/Transforms/Utils/CodeExtractor.h b/llvm/include/llvm/Transforms/Utils/CodeExtractor.h
index b86e0a00d9c80..66c9491182b16 100644
--- a/llvm/include/llvm/Transforms/Utils/CodeExtractor.h
+++ b/llvm/include/llvm/Transforms/Utils/CodeExtractor.h
@@ -163,7 +163,7 @@ class LLVM_ABI CodeExtractor {
AssumptionCache *AC = nullptr, bool AllowVarArgs = false,
bool AllowAlloca = false, BasicBlock *AllocationBlock = nullptr,
std::string Suffix = "", bool ArgsInZeroAddressSpace = false,
- bool VoidReturnWithSingleOutput = false);
+ bool VoidReturnWithSingleOutput = true);
/// Perform the extraction, returning the new function.
///
diff --git a/llvm/lib/Transforms/IPO/BlockExtractor.cpp b/llvm/lib/Transforms/IPO/BlockExtractor.cpp
index 52a20227da633..23991afc511a0 100644
--- a/llvm/lib/Transforms/IPO/BlockExtractor.cpp
+++ b/llvm/lib/Transforms/IPO/BlockExtractor.cpp
@@ -168,10 +168,7 @@ bool BlockExtractor::runOnModule(Module &M) {
Changed = true;
}
CodeExtractorAnalysisCache CEAC(*BBs[0]->getParent());
- Function *F =
- CodeExtractor(BlocksToExtractVec, nullptr, false, nullptr, nullptr,
- nullptr, false, false, nullptr, "", false, true)
- .extractCodeRegion(CEAC);
+ Function *F = CodeExtractor(BlocksToExtractVec).extractCodeRegion(CEAC);
if (F)
LLVM_DEBUG(dbgs() << "Extracted group '" << (*BBs.begin())->getName()
<< "' in: " << F->getName() << '\n');
diff --git a/llvm/lib/Transforms/IPO/HotColdSplitting.cpp b/llvm/lib/Transforms/IPO/HotColdSplitting.cpp
index 85668cfe3ede0..ca7148f0e7b8e 100644
--- a/llvm/lib/Transforms/IPO/HotColdSplitting.cpp
+++ b/llvm/lib/Transforms/IPO/HotColdSplitting.cpp
@@ -721,7 +721,7 @@ bool HotColdSplitting::outlineColdRegions(Function &F, bool HasProfileSummary) {
SubRegion, &*DT, /* AggregateArgs */ false, /* BFI */ nullptr,
/* BPI */ nullptr, AC, /* AllowVarArgs */ false,
/* AllowAlloca */ false, /* AllocaBlock */ nullptr,
- /* Suffix */ "cold." + std::to_string(OutlinedFunctionID));
+ /* Suffix */ "cold." + std::to_string(OutlinedFunctionID), false, false);
if (CE.isEligible() && isSplittingBeneficial(CE, SubRegion, TTI) &&
// If this outlining region intersects with another, drop the new
diff --git a/llvm/lib/Transforms/IPO/IROutliner.cpp b/llvm/lib/Transforms/IPO/IROutliner.cpp
index 08a77993423af..41c036496487c 100644
--- a/llvm/lib/Transforms/IPO/IROutliner.cpp
+++ b/llvm/lib/Transforms/IPO/IROutliner.cpp
@@ -2789,7 +2789,7 @@ unsigned IROutliner::doOutline(Module &M) {
OS->Candidate->getBasicBlocks(BlocksInRegion, BE);
OS->CE = new (ExtractorAllocator.Allocate())
CodeExtractor(BE, nullptr, false, nullptr, nullptr, nullptr, false,
- false, nullptr, "outlined", false, true);
+ false, nullptr, "outlined");
findAddInputsOutputs(M, *OS, NotSame);
if (!OS->IgnoreRegion)
OutlinedRegions.push_back(OS);
@@ -2900,7 +2900,7 @@ unsigned IROutliner::doOutline(Module &M) {
OS->Candidate->getBasicBlocks(BlocksInRegion, BE);
OS->CE = new (ExtractorAllocator.Allocate())
CodeExtractor(BE, nullptr, false, nullptr, nullptr, nullptr, false,
- false, nullptr, "outlined", false, true);
+ false, nullptr, "outlined");
bool FunctionOutlined = extractSection(*OS);
if (FunctionOutlined) {
unsigned StartIdx = OS->Candidate->getStartIdx();
diff --git a/llvm/lib/Transforms/IPO/PartialInlining.cpp b/llvm/lib/Transforms/IPO/PartialInlining.cpp
index 0b5c5d17abf81..e41726fb54d63 100644
--- a/llvm/lib/Transforms/IPO/PartialInlining.cpp
+++ b/llvm/lib/Transforms/IPO/PartialInlining.cpp
@@ -1104,7 +1104,7 @@ bool PartialInlinerImpl::FunctionCloner::doMultiRegionFunctionOutlining() {
CodeExtractor CE(RegionInfo.Region, &DT, /*AggregateArgs*/ false,
ClonedFuncBFI.get(), &BPI,
LookupAC(*RegionInfo.EntryBlock->getParent()),
- /* AllowVarargs */ false);
+ /* AllowVarargs */ false, false, nullptr, "", false, false);
CE.findInputsOutputs(Inputs, Outputs, Sinks);
@@ -1185,7 +1185,7 @@ PartialInlinerImpl::FunctionCloner::doSingleRegionFunctionOutlining() {
Function *OutlinedFunc =
CodeExtractor(ToExtract, &DT, /*AggregateArgs*/ false,
ClonedFuncBFI.get(), &BPI, LookupAC(*ClonedFunc),
- /* AllowVarargs */ true)
+ /* AllowVarargs */ true, false, nullptr, "", false, false)
.extractCodeRegion(CEAC);
if (OutlinedFunc) {
diff --git a/llvm/unittests/Transforms/Utils/CodeExtractorTest.cpp b/llvm/unittests/Transforms/Utils/CodeExtractorTest.cpp
index d1c4bb5cb6c6c..0b39a308de566 100644
--- a/llvm/unittests/Transforms/Utils/CodeExtractorTest.cpp
+++ b/llvm/unittests/Transforms/Utils/CodeExtractorTest.cpp
@@ -69,8 +69,7 @@ TEST(CodeExtractor, ExitStub) {
getBlockByName(Func, "body1"),
getBlockByName(Func, "body2") };
- CodeExtractor CE(Candidates, nullptr, false, nullptr, nullptr, nullptr, false,
- false, nullptr, "", false, true);
+ CodeExtractor CE(Candidates);
EXPECT_TRUE(CE.isEligible());
CodeExtractorAnalysisCache CEAC(*Func);
@@ -118,8 +117,7 @@ TEST(CodeExtractor, InputOutputMonitoring) {
getBlockByName(Func, "body1"),
getBlockByName(Func, "body2")};
- CodeExtractor CE(Candidates, nullptr, false, nullptr, nullptr, nullptr, false,
- false, nullptr, "", false, true);
+ CodeExtractor CE(Candidates);
EXPECT_TRUE(CE.isEligible());
CodeExtractorAnalysisCache CEAC(*Func);
@@ -243,8 +241,7 @@ TEST(CodeExtractor, ExitBlockOrderingPhis) {
getBlockByName(Func, "test1"),
getBlockByName(Func, "test") };
- CodeExtractor CE(Candidates, nullptr, false, nullptr, nullptr, nullptr, false,
- false, nullptr, "", false, true);
+ CodeExtractor CE(Candidates);
EXPECT_TRUE(CE.isEligible());
CodeExtractorAnalysisCache CEAC(*Func);
@@ -301,8 +298,7 @@ TEST(CodeExtractor, ExitBlockOrdering) {
getBlockByName(Func, "test1"),
getBlockByName(Func, "test") };
- CodeExtractor CE(Candidates, nullptr, false, nullptr, nullptr, nullptr, false,
- false, nullptr, "", false, true);
+ CodeExtractor CE(Candidates);
EXPECT_TRUE(CE.isEligible());
CodeExtractorAnalysisCache CEAC(*Func);
@@ -361,8 +357,7 @@ TEST(CodeExtractor, ExitPHIOnePredFromRegion) {
getBlockByName(Func, "extracted2")
};
- CodeExtractor CE(ExtractedBlocks, nullptr, false, nullptr, nullptr, nullptr,
- false, false, nullptr, "", false, true);
+ CodeExtractor CE(ExtractedBlocks);
EXPECT_TRUE(CE.isEligible());
CodeExtractorAnalysisCache CEAC(*Func);
@@ -437,8 +432,7 @@ TEST(CodeExtractor, StoreOutputInvokeResultAfterEHPad) {
getBlockByName(Func, "lpad2")
};
- CodeExtractor CE(ExtractedBlocks, nullptr, false, nullptr, nullptr, nullptr,
- false, false, nullptr, "", false, true);
+ CodeExtractor CE(ExtractedBlocks);
EXPECT_TRUE(CE.isEligible());
CodeExtractorAnalysisCache CEAC(*Func);
@@ -473,8 +467,7 @@ TEST(CodeExtractor, StoreOutputInvokeResultInExitStub) {
SmallVector<BasicBlock *, 1> Blocks{ getBlockByName(Func, "entry"),
getBlockByName(Func, "lpad") };
- CodeExtractor CE(Blocks, nullptr, false, nullptr, nullptr, nullptr, false,
- false, nullptr, "", false, true);
+ CodeExtractor CE(Blocks);
EXPECT_TRUE(CE.isEligible());
CodeExtractorAnalysisCache CEAC(*Func);
@@ -526,8 +519,7 @@ TEST(CodeExtractor, ExtractAndInvalidateAssumptionCache) {
Function *Func = M->getFunction("test");
SmallVector<BasicBlock *, 1> Blocks{ getBlockByName(Func, "if.else") };
AssumptionCache AC(*Func);
- CodeExtractor CE(Blocks, nullptr, false, nullptr, nullptr, &AC, false, false,
- nullptr, "", false, true);
+ CodeExtractor CE(Blocks, nullptr, false, nullptr, nullptr, &AC);
EXPECT_TRUE(CE.isEligible());
CodeExtractorAnalysisCache CEAC(*Func);
@@ -571,8 +563,7 @@ TEST(CodeExtractor, RemoveBitcastUsesFromOuterLifetimeMarkers) {
Function *Func = M->getFunction("foo");
SmallVector<BasicBlock *, 1> Blocks{getBlockByName(Func, "extract")};
- CodeExtractor CE(Blocks, nullptr, false, nullptr, nullptr, nullptr, false,
- false, nullptr, "", false, true);
+ CodeExtractor CE(Blocks);
EXPECT_TRUE(CE.isEligible());
CodeExtractorAnalysisCache CEAC(*Func);
@@ -627,8 +618,7 @@ TEST(CodeExtractor, PartialAggregateArgs) {
// Create the CodeExtractor with arguments aggregation enabled.
CodeExtractor CE(Blocks, /* DominatorTree */ nullptr,
- /* AggregateArgs */ true, nullptr, nullptr, nullptr, false,
- false, nullptr, "", false, true);
+ /* AggregateArgs */ true);
EXPECT_TRUE(CE.isEligible());
CodeExtractorAnalysisCache CEAC(*Func);
@@ -676,7 +666,7 @@ TEST(CodeExtractor, AllocaBlock) {
BasicBlock *AllocaBlock = getBlockByName(Func, "allocas");
CodeExtractor CE(Candidates, nullptr, true, nullptr, nullptr, nullptr, false,
- false, AllocaBlock, "", false, true);
+ false, AllocaBlock);
CE.excludeArgFromAggregate(Func->getArg(0));
CE.excludeArgFromAggregate(getInstByName(Func, "w"));
EXPECT_TRUE(CE.isEligible());
@@ -730,8 +720,7 @@ TEST(CodeExtractor, PartialAggregateArgs2) {
// Create the CodeExtractor with arguments aggregation enabled.
CodeExtractor CE(Blocks, /* DominatorTree */ nullptr,
- /* AggregateArgs */ true, nullptr, nullptr, nullptr, false,
- false, nullptr, "", false, true);
+ /* AggregateArgs */ true);
EXPECT_TRUE(CE.isEligible());
CodeExtractorAnalysisCache CEAC(*Func);
@@ -788,8 +777,7 @@ TEST(CodeExtractor, OpenMPAggregateArgs) {
/* AllowAlloca */ true,
/* AllocaBlock*/ &Func->getEntryBlock(),
/* Suffix */ ".outlined",
- /* ArgsInZeroAddressSpace */ true,
- /* VoidReturnWithSingleOutput */ true);
+ /* ArgsInZeroAddressSpace */ true);
EXPECT_TRUE(CE.isEligible());
@@ -855,9 +843,7 @@ TEST(CodeExtractor, ArgsDebugInfo) {
SmallVector<BasicBlock *, 1> Blocks{getBlockByName(Func, "extract")};
auto TestExtracted = [&](bool AggregateArgs) {
- CodeExtractor CE(Blocks, /* DominatorTree */ nullptr, AggregateArgs,
- nullptr, nullptr, nullptr, false, false, nullptr, "",
- false, true);
+ CodeExtractor CE(Blocks, /* DominatorTree */ nullptr, AggregateArgs);
EXPECT_TRUE(CE.isEligible());
CodeExtractorAnalysisCache CEAC(*Func);
SetVector<Value *> Inputs, Outputs, SinkingCands, HoistingCands;
>From 8268a1d6b231c3c9e336eff78a19e63d510dbe83 Mon Sep 17 00:00:00 2001
From: Shimin Cui <scui at ca.ibm.com>
Date: Tue, 14 Apr 2026 17:31:10 +0000
Subject: [PATCH 4/5] clang format change
---
llvm/lib/Transforms/IPO/HotColdSplitting.cpp | 3 ++-
llvm/lib/Transforms/IPO/PartialInlining.cpp | 8 ++++----
2 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/llvm/lib/Transforms/IPO/HotColdSplitting.cpp b/llvm/lib/Transforms/IPO/HotColdSplitting.cpp
index ca7148f0e7b8e..741a4d84a496e 100644
--- a/llvm/lib/Transforms/IPO/HotColdSplitting.cpp
+++ b/llvm/lib/Transforms/IPO/HotColdSplitting.cpp
@@ -721,7 +721,8 @@ bool HotColdSplitting::outlineColdRegions(Function &F, bool HasProfileSummary) {
SubRegion, &*DT, /* AggregateArgs */ false, /* BFI */ nullptr,
/* BPI */ nullptr, AC, /* AllowVarArgs */ false,
/* AllowAlloca */ false, /* AllocaBlock */ nullptr,
- /* Suffix */ "cold." + std::to_string(OutlinedFunctionID), false, false);
+ /* Suffix */ "cold." + std::to_string(OutlinedFunctionID), false,
+ false);
if (CE.isEligible() && isSplittingBeneficial(CE, SubRegion, TTI) &&
// If this outlining region intersects with another, drop the new
diff --git a/llvm/lib/Transforms/IPO/PartialInlining.cpp b/llvm/lib/Transforms/IPO/PartialInlining.cpp
index e41726fb54d63..ea2380b1c4d0e 100644
--- a/llvm/lib/Transforms/IPO/PartialInlining.cpp
+++ b/llvm/lib/Transforms/IPO/PartialInlining.cpp
@@ -1101,10 +1101,10 @@ bool PartialInlinerImpl::FunctionCloner::doMultiRegionFunctionOutlining() {
InstructionCost CurrentOutlinedRegionCost =
ComputeRegionCost(RegionInfo.Region);
- CodeExtractor CE(RegionInfo.Region, &DT, /*AggregateArgs*/ false,
- ClonedFuncBFI.get(), &BPI,
- LookupAC(*RegionInfo.EntryBlock->getParent()),
- /* AllowVarargs */ false, false, nullptr, "", false, false);
+ CodeExtractor CE(
+ RegionInfo.Region, &DT, /*AggregateArgs*/ false, ClonedFuncBFI.get(),
+ &BPI, LookupAC(*RegionInfo.EntryBlock->getParent()),
+ /* AllowVarargs */ false, false, nullptr, "", false, false);
CE.findInputsOutputs(Inputs, Outputs, Sinks);
>From ab07404ae145691fe25848cbb7208be8efb68ed0 Mon Sep 17 00:00:00 2001
From: Shimin Cui <scui at ca.ibm.com>
Date: Thu, 16 Apr 2026 15:03:41 +0000
Subject: [PATCH 5/5] Add comments on the arguments
---
llvm/lib/Transforms/IPO/HotColdSplitting.cpp | 5 +++--
llvm/lib/Transforms/IPO/PartialInlining.cpp | 16 +++++++++++-----
.../Transforms/Utils/CodeExtractorTest.cpp | 8 ++++++--
3 files changed, 20 insertions(+), 9 deletions(-)
diff --git a/llvm/lib/Transforms/IPO/HotColdSplitting.cpp b/llvm/lib/Transforms/IPO/HotColdSplitting.cpp
index 741a4d84a496e..b3e9796ca6789 100644
--- a/llvm/lib/Transforms/IPO/HotColdSplitting.cpp
+++ b/llvm/lib/Transforms/IPO/HotColdSplitting.cpp
@@ -721,8 +721,9 @@ bool HotColdSplitting::outlineColdRegions(Function &F, bool HasProfileSummary) {
SubRegion, &*DT, /* AggregateArgs */ false, /* BFI */ nullptr,
/* BPI */ nullptr, AC, /* AllowVarArgs */ false,
/* AllowAlloca */ false, /* AllocaBlock */ nullptr,
- /* Suffix */ "cold." + std::to_string(OutlinedFunctionID), false,
- false);
+ /* Suffix */ "cold." + std::to_string(OutlinedFunctionID),
+ /* ArgsInZeroAddressSpace */ false,
+ /* VoidReturnWithSingleOutput */ false);
if (CE.isEligible() && isSplittingBeneficial(CE, SubRegion, TTI) &&
// If this outlining region intersects with another, drop the new
diff --git a/llvm/lib/Transforms/IPO/PartialInlining.cpp b/llvm/lib/Transforms/IPO/PartialInlining.cpp
index ea2380b1c4d0e..8b4b2b5c70844 100644
--- a/llvm/lib/Transforms/IPO/PartialInlining.cpp
+++ b/llvm/lib/Transforms/IPO/PartialInlining.cpp
@@ -1101,10 +1101,13 @@ bool PartialInlinerImpl::FunctionCloner::doMultiRegionFunctionOutlining() {
InstructionCost CurrentOutlinedRegionCost =
ComputeRegionCost(RegionInfo.Region);
- CodeExtractor CE(
- RegionInfo.Region, &DT, /*AggregateArgs*/ false, ClonedFuncBFI.get(),
- &BPI, LookupAC(*RegionInfo.EntryBlock->getParent()),
- /* AllowVarargs */ false, false, nullptr, "", false, false);
+ CodeExtractor CE(RegionInfo.Region, &DT, /*AggregateArgs*/ false,
+ ClonedFuncBFI.get(), &BPI,
+ LookupAC(*RegionInfo.EntryBlock->getParent()),
+ /* AllowVarargs */ false, /* AllowAlloca */ false,
+ /* AllocaBlock */ nullptr, /* Suffix */ "",
+ /* ArgsInZeroAddressSpace */ false,
+ /* VoidReturnWithSingleOutput */ false);
CE.findInputsOutputs(Inputs, Outputs, Sinks);
@@ -1185,7 +1188,10 @@ PartialInlinerImpl::FunctionCloner::doSingleRegionFunctionOutlining() {
Function *OutlinedFunc =
CodeExtractor(ToExtract, &DT, /*AggregateArgs*/ false,
ClonedFuncBFI.get(), &BPI, LookupAC(*ClonedFunc),
- /* AllowVarargs */ true, false, nullptr, "", false, false)
+ /* AllowVarargs */ true, /* AllowAlloca */ false,
+ /* AllocaBlock */ nullptr, /* Suffix */ "",
+ /* ArgsInZeroAddressSpace */ false,
+ /* VoidReturnWithSingleOutput */ false)
.extractCodeRegion(CEAC);
if (OutlinedFunc) {
diff --git a/llvm/unittests/Transforms/Utils/CodeExtractorTest.cpp b/llvm/unittests/Transforms/Utils/CodeExtractorTest.cpp
index 0b39a308de566..269d427d382b6 100644
--- a/llvm/unittests/Transforms/Utils/CodeExtractorTest.cpp
+++ b/llvm/unittests/Transforms/Utils/CodeExtractorTest.cpp
@@ -175,8 +175,12 @@ TEST(CodeExtractor, InputOutputReturnMonitoring) {
getBlockByName(Func, "body1"),
getBlockByName(Func, "body2")};
- CodeExtractor CE(Candidates, nullptr, false, nullptr, nullptr, nullptr, false,
- false, nullptr, "", false, false);
+ CodeExtractor CE(Candidates, /* DT */ nullptr, /* AggregateArgs */ false,
+ /* BFI */ nullptr, /* BPI */ nullptr, /* AC */ nullptr,
+ /* AllowVarargs */ false, /* AllowAlloca */ false,
+ /* AllocaBlock */ nullptr, /* Suffix */ "",
+ /* ArgsInZeroAddressSpace */ false,
+ /* VoidReturnWithSingleOutput */ false);
EXPECT_TRUE(CE.isEligible());
CodeExtractorAnalysisCache CEAC(*Func);
More information about the llvm-commits
mailing list