[llvm] ab33f1e - [IROutliner] Add TTI Hook for Propagating Attributes (#153985)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Feb 10 19:49:21 PST 2026
Author: Sam Elliott
Date: 2026-02-10T19:49:16-08:00
New Revision: ab33f1e427f7757a180e77ebeb67faded5b5b3d3
URL: https://github.com/llvm/llvm-project/commit/ab33f1e427f7757a180e77ebeb67faded5b5b3d3
DIFF: https://github.com/llvm/llvm-project/commit/ab33f1e427f7757a180e77ebeb67faded5b5b3d3.diff
LOG: [IROutliner] Add TTI Hook for Propagating Attributes (#153985)
On RISC-V, the interrupt attribute relates only to the prolog and epilog
of the attributed function (and has specific restrictions on the
function's signature). It does not change how that function calls other
functions, and when outlining, the outlined function must not have this
attribute.
This adds a target-independent hook to TTI so targets can choose which
attributes to propagate (by default all are propagated).
Fixes #149969
Added:
llvm/test/Transforms/IROutliner/outlining-compatible-and-never-transfer-riscv.ll
Modified:
llvm/include/llvm/Analysis/TargetTransformInfo.h
llvm/include/llvm/Analysis/TargetTransformInfoImpl.h
llvm/include/llvm/Transforms/IPO/IROutliner.h
llvm/lib/Analysis/TargetTransformInfo.cpp
llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp
llvm/lib/Target/RISCV/RISCVTargetTransformInfo.h
llvm/lib/Transforms/IPO/IROutliner.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/Analysis/TargetTransformInfo.h b/llvm/include/llvm/Analysis/TargetTransformInfo.h
index a013122df5f06..b06ee091827f7 100644
--- a/llvm/include/llvm/Analysis/TargetTransformInfo.h
+++ b/llvm/include/llvm/Analysis/TargetTransformInfo.h
@@ -1842,6 +1842,12 @@ class TargetTransformInfo {
const CallBase &Call,
unsigned DefaultCallPenalty) const;
+ /// \returns true if `Caller`'s `Attr` should be added to the new function
+ /// created by outlining part of `Caller`.
+ LLVM_ABI bool
+ shouldCopyAttributeWhenOutliningFrom(const Function *Caller,
+ const Attribute &Attr) const;
+
/// \returns True if the caller and callee agree on how \p Types will be
/// passed to or returned from the callee.
/// to the callee.
diff --git a/llvm/include/llvm/Analysis/TargetTransformInfoImpl.h b/llvm/include/llvm/Analysis/TargetTransformInfoImpl.h
index 6d27cabf404f8..5ef18fecabd99 100644
--- a/llvm/include/llvm/Analysis/TargetTransformInfoImpl.h
+++ b/llvm/include/llvm/Analysis/TargetTransformInfoImpl.h
@@ -1065,6 +1065,13 @@ class TargetTransformInfoImplBase {
return DefaultCallPenalty;
}
+ virtual bool
+ shouldCopyAttributeWhenOutliningFrom(const Function *Caller,
+ const Attribute &Attr) const {
+ // Copy attributes by default
+ return true;
+ }
+
virtual bool areTypesABICompatible(const Function *Caller,
const Function *Callee,
ArrayRef<Type *> Types) const {
diff --git a/llvm/include/llvm/Transforms/IPO/IROutliner.h b/llvm/include/llvm/Transforms/IPO/IROutliner.h
index e8275b2d20ade..3ddb1b096ad42 100644
--- a/llvm/include/llvm/Transforms/IPO/IROutliner.h
+++ b/llvm/include/llvm/Transforms/IPO/IROutliner.h
@@ -312,6 +312,22 @@ class IROutliner {
std::vector<Function *> &FuncsToRemove,
unsigned &OutlinedFunctionNum);
+ /// Fill the new function that will serve as the replacement function for all
+ /// of the extracted regions of a certain structure from the first region in
+ /// the list of regions. Replace this first region's extracted function with
+ /// the new overall function.
+ ///
+ /// \param [in] M - The module we are outlining from.
+ /// \param [in] CurrentGroup - The group of regions to be outlined.
+ /// \param [in,out] OutputStoreBBs - The output blocks for each
diff erent
+ /// set of stores needed for the
diff erent functions.
+ /// \param [in,out] FuncsToRemove - Extracted functions to erase from module
+ /// once outlining is complete.
+ void fillOverallFunction(
+ Module &M, OutlinableGroup &CurrentGroup,
+ std::vector<DenseMap<Value *, BasicBlock *>> &OutputStoreBBs,
+ std::vector<Function *> &FuncsToRemove);
+
/// If true, enables us to outline from functions that have LinkOnceFromODR
/// linkages.
bool OutlineFromLinkODRs = false;
diff --git a/llvm/lib/Analysis/TargetTransformInfo.cpp b/llvm/lib/Analysis/TargetTransformInfo.cpp
index 19785204ed2b3..504fa9b448ec0 100644
--- a/llvm/lib/Analysis/TargetTransformInfo.cpp
+++ b/llvm/lib/Analysis/TargetTransformInfo.cpp
@@ -1369,6 +1369,10 @@ TargetTransformInfo::getInlineCallPenalty(const Function *F,
return TTIImpl->getInlineCallPenalty(F, Call, DefaultCallPenalty);
}
+bool TargetTransformInfo::shouldCopyAttributeWhenOutliningFrom(
+ const Function *Caller, const Attribute &Attr) const {
+ return TTIImpl->shouldCopyAttributeWhenOutliningFrom(Caller, Attr);
+}
bool TargetTransformInfo::areTypesABICompatible(const Function *Caller,
const Function *Callee,
ArrayRef<Type *> Types) const {
diff --git a/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp b/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp
index 2fb9795ff87c8..a40d77dd734c8 100644
--- a/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp
+++ b/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp
@@ -3546,3 +3546,15 @@ bool RISCVTTIImpl::shouldTreatInstructionLikeSelect(
}
return BaseT::shouldTreatInstructionLikeSelect(I);
}
+
+bool RISCVTTIImpl::shouldCopyAttributeWhenOutliningFrom(
+ const Function *Caller, const Attribute &Attr) const {
+ // "interrupt" controls the prolog/epilog of interrupt handlers (and includes
+ // restrictions on their signatures). We can outline from the bodies of these
+ // handlers, but when we do we need to make sure we don't mark the outlined
+ // function as an interrupt handler too.
+ if (Attr.isStringAttribute() && Attr.getKindAsString() == "interrupt")
+ return false;
+
+ return BaseT::shouldCopyAttributeWhenOutliningFrom(Caller, Attr);
+}
diff --git a/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.h b/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.h
index faa87b4fc48dd..cee41b1422b85 100644
--- a/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.h
+++ b/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.h
@@ -507,6 +507,10 @@ class RISCVTTIImpl final : public BasicTTIImplBase<RISCVTTIImpl> {
}
bool shouldTreatInstructionLikeSelect(const Instruction *I) const override;
+
+ bool
+ shouldCopyAttributeWhenOutliningFrom(const Function *Caller,
+ const Attribute &Attr) const override;
};
} // end namespace llvm
diff --git a/llvm/lib/Transforms/IPO/IROutliner.cpp b/llvm/lib/Transforms/IPO/IROutliner.cpp
index 6e1ca9c4cd2d6..250957684dff9 100644
--- a/llvm/lib/Transforms/IPO/IROutliner.cpp
+++ b/llvm/lib/Transforms/IPO/IROutliner.cpp
@@ -2203,26 +2203,14 @@ void createSwitchStatement(
}
}
-/// Fill the new function that will serve as the replacement function for all of
-/// the extracted regions of a certain structure from the first region in the
-/// list of regions. Replace this first region's extracted function with the
-/// new overall function.
-///
-/// \param [in] M - The module we are outlining from.
-/// \param [in] CurrentGroup - The group of regions to be outlined.
-/// \param [in,out] OutputStoreBBs - The output blocks for each
diff erent
-/// set of stores needed for the
diff erent functions.
-/// \param [in,out] FuncsToRemove - Extracted functions to erase from module
-/// once outlining is complete.
-/// \param [in] OutputMappings - Extracted functions to erase from module
-/// once outlining is complete.
-static void fillOverallFunction(
+void IROutliner::fillOverallFunction(
Module &M, OutlinableGroup &CurrentGroup,
std::vector<DenseMap<Value *, BasicBlock *>> &OutputStoreBBs,
- std::vector<Function *> &FuncsToRemove,
- const DenseMap<Value *, Value *> &OutputMappings) {
+ std::vector<Function *> &FuncsToRemove) {
OutlinableRegion *CurrentOS = CurrentGroup.Regions[0];
+ TargetTransformInfo &TTI = getTTI(*CurrentOS->StartBB->getParent());
+
// Move first extracted function's instructions into new function.
LLVM_DEBUG(dbgs() << "Move instructions from "
<< *CurrentOS->ExtractedFunction << " to instruction "
@@ -2231,8 +2219,14 @@ static void fillOverallFunction(
*CurrentGroup.OutlinedFunction, CurrentGroup.EndBBs);
// Transfer the attributes from the function to the new function.
- for (Attribute A : CurrentOS->ExtractedFunction->getAttributes().getFnAttrs())
+ for (Attribute A :
+ CurrentOS->ExtractedFunction->getAttributes().getFnAttrs()) {
+ if (!TTI.shouldCopyAttributeWhenOutliningFrom(CurrentOS->ExtractedFunction,
+ A))
+ continue;
+
CurrentGroup.OutlinedFunction->addFnAttr(A);
+ }
// Create a new set of output blocks for the first extracted function.
DenseMap<Value *, BasicBlock *> NewBBs;
@@ -2274,8 +2268,7 @@ void IROutliner::deduplicateExtractedSections(
OutlinableRegion *CurrentOS;
- fillOverallFunction(M, CurrentGroup, OutputStoreBBs, FuncsToRemove,
- OutputMappings);
+ fillOverallFunction(M, CurrentGroup, OutputStoreBBs, FuncsToRemove);
for (unsigned Idx = 1; Idx < CurrentGroup.Regions.size(); Idx++) {
CurrentOS = CurrentGroup.Regions[Idx];
diff --git a/llvm/test/Transforms/IROutliner/outlining-compatible-and-never-transfer-riscv.ll b/llvm/test/Transforms/IROutliner/outlining-compatible-and-never-transfer-riscv.ll
new file mode 100644
index 0000000000000..d2751e12f355e
--- /dev/null
+++ b/llvm/test/Transforms/IROutliner/outlining-compatible-and-never-transfer-riscv.ll
@@ -0,0 +1,298 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-globals --include-generated-funcs
+; RUN: opt -mtriple=riscv32 -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
+
+; REQUIRES: riscv-registered-target
+
+; This has two compatible regions based on function attributes. We have attributes
+; that should never be transferred to the outlined functions:
+; - `interrupt`=*
+
+; On RISC-V, the `interrupt` attribute only applies to the prolog and epilog of
+; the annotated function, and not any functions it calls. If this attribute is
+; preserved, there will be codegen errors because of restrictions on the
+; signatures of `interrupt` attributes.
+
+define void @outline_attrs1() #0 {
+entry:
+ %a = alloca i32, align 4
+ %b = alloca i32, align 4
+ %c = alloca i32, align 4
+ store i32 2, ptr %a, align 4
+ store i32 3, ptr %b, align 4
+ store i32 4, ptr %c, align 4
+ %al = load i32, ptr %a
+ %bl = load i32, ptr %b
+ %cl = load i32, ptr %c
+ ret void
+}
+
+define void @outline_attrs2() #1 {
+entry:
+ %a = alloca i32, align 4
+ %b = alloca i32, align 4
+ %c = alloca i32, align 4
+ store i32 2, ptr %a, align 4
+ store i32 3, ptr %b, align 4
+ store i32 4, ptr %c, align 4
+ %al = load i32, ptr %a
+ %bl = load i32, ptr %b
+ %cl = load i32, ptr %c
+ ret void
+}
+
+define void @outline_attrs3() {
+entry:
+ %a = alloca i32, align 4
+ %b = alloca i32, align 4
+ %c = alloca i32, align 4
+ store i32 2, ptr %a, align 4
+ store i32 3, ptr %b, align 4
+ store i32 4, ptr %c, align 4
+ %al = load i32, ptr %a
+ %bl = load i32, ptr %b
+ %cl = load i32, ptr %c
+ ret void
+}
+
+define void @outline_outputs1() #0 {
+entry:
+ %output = alloca i32, align 4
+ %result = alloca i32, align 4
+ %output2 = alloca i32, align 4
+ %result2 = alloca i32, align 4
+ %a = alloca i32, align 4
+ %b = alloca i32, align 4
+ br label %block_2
+block_1:
+ %a2 = alloca i32, align 4
+ %b2 = alloca i32, align 4
+ br label %block_2
+block_2:
+ %a2val = load i32, ptr %a
+ %b2val = load i32, ptr %b
+ %add2 = add i32 2, %a2val
+ %mul2 = mul i32 2, %b2val
+ br label %block_5
+block_3:
+ %aval = load i32, ptr %a
+ %bval = load i32, ptr %b
+ %add = add i32 2, %aval
+ %mul = mul i32 2, %bval
+ br label %block_4
+block_4:
+ store i32 %add, ptr %output, align 4
+ store i32 %mul, ptr %result, align 4
+ br label %block_6
+block_5:
+ store i32 %add2, ptr %output, align 4
+ store i32 %mul2, ptr %result, align 4
+ br label %block_7
+block_6:
+ ret void
+block_7:
+ ret void
+}
+
+define void @outline_outputs2() #1 {
+entry:
+ %output = alloca i32, align 4
+ %result = alloca i32, align 4
+ %output2 = alloca i32, align 4
+ %result2 = alloca i32, align 4
+ %a = alloca i32, align 4
+ %b = alloca i32, align 4
+ br label %block_2
+block_1:
+ %a2 = alloca i32, align 4
+ %b2 = alloca i32, align 4
+ br label %block_2
+block_2:
+ %a2val = load i32, ptr %a
+ %b2val = load i32, ptr %b
+ %add2 = add i32 2, %a2val
+ %mul2 = mul i32 2, %b2val
+ br label %block_5
+block_3:
+ %aval = load i32, ptr %a
+ %bval = load i32, ptr %b
+ %add = add i32 2, %aval
+ %mul = mul i32 2, %bval
+ br label %block_4
+block_4:
+ store i32 %add, ptr %output, align 4
+ store i32 %mul, ptr %result, align 4
+ br label %block_7
+block_5:
+ store i32 %add2, ptr %output, align 4
+ store i32 %mul2, ptr %result, align 4
+ br label %block_6
+block_6:
+ %
diff = sub i32 %a2val, %b2val
+ ret void
+block_7:
+ %quot = udiv i32 %add, %mul
+ ret void
+}
+
+attributes #0 = { "interrupt"="machine" optsize }
+attributes #1 = { "interrupt"="qci-nest" optsize }
+; CHECK-LABEL: define {{[^@]+}}@outline_attrs1
+; CHECK-SAME: () #[[ATTR0:[0-9]+]] {
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
+; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
+; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
+; CHECK-NEXT: call void @outlined_ir_func_1(ptr [[A]], ptr [[B]], ptr [[C]])
+; CHECK-NEXT: ret void
+;
+;
+; CHECK-LABEL: define {{[^@]+}}@outline_attrs2
+; CHECK-SAME: () #[[ATTR1:[0-9]+]] {
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
+; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
+; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
+; CHECK-NEXT: call void @outlined_ir_func_1(ptr [[A]], ptr [[B]], ptr [[C]])
+; CHECK-NEXT: ret void
+;
+;
+; CHECK-LABEL: define {{[^@]+}}@outline_attrs3() {
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
+; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
+; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
+; CHECK-NEXT: call void @outlined_ir_func_1(ptr [[A]], ptr [[B]], ptr [[C]])
+; CHECK-NEXT: ret void
+;
+;
+; CHECK-LABEL: define {{[^@]+}}@outline_outputs1
+; CHECK-SAME: () #[[ATTR0]] {
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[OUTPUT:%.*]] = alloca i32, align 4
+; CHECK-NEXT: [[RESULT:%.*]] = alloca i32, align 4
+; CHECK-NEXT: [[OUTPUT2:%.*]] = alloca i32, align 4
+; CHECK-NEXT: [[RESULT2:%.*]] = alloca i32, align 4
+; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
+; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
+; CHECK-NEXT: br label [[BLOCK_2:%.*]]
+; CHECK: block_1:
+; CHECK-NEXT: [[A2:%.*]] = alloca i32, align 4
+; CHECK-NEXT: [[B2:%.*]] = alloca i32, align 4
+; CHECK-NEXT: br label [[BLOCK_2]]
+; CHECK: block_2:
+; CHECK-NEXT: [[TMP0:%.*]] = call i1 @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[OUTPUT]], ptr [[RESULT]], ptr null, ptr null, ptr null, ptr null, i32 -1)
+; CHECK-NEXT: br i1 [[TMP0]], label [[BLOCK_6:%.*]], label [[BLOCK_7:%.*]]
+; CHECK: block_6:
+; CHECK-NEXT: ret void
+; CHECK: block_7:
+; CHECK-NEXT: ret void
+;
+;
+; CHECK-LABEL: define {{[^@]+}}@outline_outputs2
+; CHECK-SAME: () #[[ATTR1]] {
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[MUL_LOC:%.*]] = alloca i32, align 4
+; CHECK-NEXT: [[ADD_LOC:%.*]] = alloca i32, align 4
+; CHECK-NEXT: [[B2VAL_LOC:%.*]] = alloca i32, align 4
+; CHECK-NEXT: [[A2VAL_LOC:%.*]] = alloca i32, align 4
+; CHECK-NEXT: [[OUTPUT:%.*]] = alloca i32, align 4
+; CHECK-NEXT: [[RESULT:%.*]] = alloca i32, align 4
+; CHECK-NEXT: [[OUTPUT2:%.*]] = alloca i32, align 4
+; CHECK-NEXT: [[RESULT2:%.*]] = alloca i32, align 4
+; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
+; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
+; CHECK-NEXT: br label [[BLOCK_2:%.*]]
+; CHECK: block_1:
+; CHECK-NEXT: [[A2:%.*]] = alloca i32, align 4
+; CHECK-NEXT: [[B2:%.*]] = alloca i32, align 4
+; CHECK-NEXT: br label [[BLOCK_2]]
+; CHECK: block_2:
+; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[A2VAL_LOC]])
+; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[B2VAL_LOC]])
+; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[ADD_LOC]])
+; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[MUL_LOC]])
+; CHECK-NEXT: [[TMP0:%.*]] = call i1 @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[OUTPUT]], ptr [[RESULT]], ptr [[A2VAL_LOC]], ptr [[B2VAL_LOC]], ptr [[ADD_LOC]], ptr [[MUL_LOC]], i32 0)
+; CHECK-NEXT: [[A2VAL_RELOAD:%.*]] = load i32, ptr [[A2VAL_LOC]], align 4
+; CHECK-NEXT: [[B2VAL_RELOAD:%.*]] = load i32, ptr [[B2VAL_LOC]], align 4
+; CHECK-NEXT: [[ADD_RELOAD:%.*]] = load i32, ptr [[ADD_LOC]], align 4
+; CHECK-NEXT: [[MUL_RELOAD:%.*]] = load i32, ptr [[MUL_LOC]], align 4
+; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[A2VAL_LOC]])
+; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[B2VAL_LOC]])
+; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[ADD_LOC]])
+; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[MUL_LOC]])
+; CHECK-NEXT: br i1 [[TMP0]], label [[BLOCK_7:%.*]], label [[BLOCK_6:%.*]]
+; CHECK: block_6:
+; CHECK-NEXT: [[DIFF:%.*]] = sub i32 [[A2VAL_RELOAD]], [[B2VAL_RELOAD]]
+; CHECK-NEXT: ret void
+; CHECK: block_7:
+; CHECK-NEXT: [[QUOT:%.*]] = udiv i32 [[ADD_RELOAD]], [[MUL_RELOAD]]
+; CHECK-NEXT: ret void
+;
+;
+; CHECK-LABEL: define {{[^@]+}}@outlined_ir_func_0
+; CHECK-SAME: (ptr [[TMP0:%.*]], ptr [[TMP1:%.*]], ptr [[TMP2:%.*]], ptr [[TMP3:%.*]], ptr [[TMP4:%.*]], ptr [[TMP5:%.*]], ptr [[TMP6:%.*]], ptr [[TMP7:%.*]], i32 [[TMP8:%.*]]) #[[ATTR3:[0-9]+]] {
+; CHECK-NEXT: newFuncRoot:
+; CHECK-NEXT: br label [[BLOCK_2_TO_OUTLINE:%.*]]
+; CHECK: block_2_to_outline:
+; CHECK-NEXT: [[A2VAL:%.*]] = load i32, ptr [[TMP0]], align 4
+; CHECK-NEXT: [[B2VAL:%.*]] = load i32, ptr [[TMP1]], align 4
+; CHECK-NEXT: [[ADD2:%.*]] = add i32 2, [[A2VAL]]
+; CHECK-NEXT: [[MUL2:%.*]] = mul i32 2, [[B2VAL]]
+; CHECK-NEXT: br label [[BLOCK_5:%.*]]
+; CHECK: block_3:
+; CHECK-NEXT: [[AVAL:%.*]] = load i32, ptr [[TMP0]], align 4
+; CHECK-NEXT: [[BVAL:%.*]] = load i32, ptr [[TMP1]], align 4
+; CHECK-NEXT: [[ADD:%.*]] = add i32 2, [[AVAL]]
+; CHECK-NEXT: [[MUL:%.*]] = mul i32 2, [[BVAL]]
+; CHECK-NEXT: br label [[BLOCK_4:%.*]]
+; CHECK: block_4:
+; CHECK-NEXT: store i32 [[ADD]], ptr [[TMP2]], align 4
+; CHECK-NEXT: store i32 [[MUL]], ptr [[TMP3]], align 4
+; CHECK-NEXT: br label [[BLOCK_6_EXITSTUB:%.*]]
+; CHECK: block_5:
+; CHECK-NEXT: store i32 [[ADD2]], ptr [[TMP2]], align 4
+; CHECK-NEXT: store i32 [[MUL2]], ptr [[TMP3]], align 4
+; CHECK-NEXT: br label [[BLOCK_7_EXITSTUB:%.*]]
+; CHECK: block_6.exitStub:
+; CHECK-NEXT: switch i32 [[TMP8]], label [[FINAL_BLOCK_1:%.*]] [
+; CHECK-NEXT: i32 0, label [[OUTPUT_BLOCK_1_1:%.*]]
+; CHECK-NEXT: ]
+; CHECK: block_7.exitStub:
+; CHECK-NEXT: switch i32 [[TMP8]], label [[FINAL_BLOCK_0:%.*]] [
+; CHECK-NEXT: i32 0, label [[OUTPUT_BLOCK_1_0:%.*]]
+; CHECK-NEXT: ]
+; CHECK: output_block_1_0:
+; CHECK-NEXT: store i32 [[A2VAL]], ptr [[TMP4]], align 4
+; CHECK-NEXT: store i32 [[B2VAL]], ptr [[TMP5]], align 4
+; CHECK-NEXT: br label [[FINAL_BLOCK_0]]
+; CHECK: output_block_1_1:
+; CHECK-NEXT: store i32 [[ADD]], ptr [[TMP6]], align 4
+; CHECK-NEXT: store i32 [[MUL]], ptr [[TMP7]], align 4
+; CHECK-NEXT: br label [[FINAL_BLOCK_1]]
+; CHECK: final_block_0:
+; CHECK-NEXT: ret i1 false
+; CHECK: final_block_1:
+; CHECK-NEXT: ret i1 true
+;
+;
+; CHECK-LABEL: define {{[^@]+}}@outlined_ir_func_1
+; CHECK-SAME: (ptr [[TMP0:%.*]], ptr [[TMP1:%.*]], ptr [[TMP2:%.*]]) #[[ATTR3]] {
+; CHECK-NEXT: newFuncRoot:
+; CHECK-NEXT: br label [[ENTRY_TO_OUTLINE:%.*]]
+; CHECK: entry_to_outline:
+; CHECK-NEXT: store i32 2, ptr [[TMP0]], align 4
+; CHECK-NEXT: store i32 3, ptr [[TMP1]], align 4
+; CHECK-NEXT: store i32 4, ptr [[TMP2]], align 4
+; CHECK-NEXT: [[AL:%.*]] = load i32, ptr [[TMP0]], align 4
+; CHECK-NEXT: [[BL:%.*]] = load i32, ptr [[TMP1]], align 4
+; CHECK-NEXT: [[CL:%.*]] = load i32, ptr [[TMP2]], align 4
+; CHECK-NEXT: br label [[ENTRY_AFTER_OUTLINE_EXITSTUB:%.*]]
+; CHECK: entry_after_outline.exitStub:
+; CHECK-NEXT: ret void
+;
+;.
+; CHECK: attributes #[[ATTR0]] = { optsize "interrupt"="machine" }
+; CHECK: attributes #[[ATTR1]] = { optsize "interrupt"="qci-nest" }
+; CHECK: attributes #[[ATTR2:[0-9]+]] = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
+; CHECK: attributes #[[ATTR3]] = { minsize optsize }
+;.
More information about the llvm-commits
mailing list