[llvm] 58d9781 - [PGO][ICP] Prevent indirect call promotion to functions with incompatible target features (#192142)
via llvm-commits
llvm-commits at lists.llvm.org
Mon May 4 22:03:13 PDT 2026
Author: Han Shen
Date: 2026-05-04T22:03:09-07:00
New Revision: 58d9781e8433878444d7b7873e75f7e2c2fd8f50
URL: https://github.com/llvm/llvm-project/commit/58d9781e8433878444d7b7873e75f7e2c2fd8f50
DIFF: https://github.com/llvm/llvm-project/commit/58d9781e8433878444d7b7873e75f7e2c2fd8f50.diff
LOG: [PGO][ICP] Prevent indirect call promotion to functions with incompatible target features (#192142)
Profile-driven indirect call promotion was promoting indirect calls to
functions requiring advanced CPU features (e.g., AVX512) even when the
caller function did not support those features. When these promoted
calls were subsequently inlined, it could lead to invalid IR and
backend crashes during instruction selection because the target CPU
could not handle the advanced instructions.
This patch addresses the issue by adding a target feature
compatibility check to `llvm::isLegalToPromote` in
`CallPromotionUtils.cpp`. If the callee requires target features
(prefixed with `+`) that are not present in the caller's target
features, the promotion is skipped. By centralizing this check in
`isLegalToPromote`, we protect all passes relying on this utility
(such as `SampleProfileLoader` and `IndirectCallPromotion`) from
promoting to incompatible targets. This also prevents incorrect
inlining of `always_inline` functions that would otherwise be promoted
via indirect calls and then inlined.
Fixes #192126
Pull Request: https://github.com/llvm/llvm-project/pull/192142
Added:
llvm/test/Transforms/SampleProfile/icp_target_feature.ll
Modified:
llvm/lib/Transforms/Utils/CallPromotionUtils.cpp
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/Utils/CallPromotionUtils.cpp b/llvm/lib/Transforms/Utils/CallPromotionUtils.cpp
index f0f9add09bf82..1bfeea3b711f9 100644
--- a/llvm/lib/Transforms/Utils/CallPromotionUtils.cpp
+++ b/llvm/lib/Transforms/Utils/CallPromotionUtils.cpp
@@ -477,6 +477,27 @@ bool llvm::isLegalToPromote(const CallBase &CB, Function *Callee,
}
}
+ // Check target feature compatibility. This is also needed to avoid incorrect
+ // inlining if the callee has the always_inline attribute. An always_inline
+ // function can be incorrectly inlined via two paths: either it is directly
+ // called and inlined, or it is indirectly called, promoted, and then inlined.
+ // The check here only prevents the latter case.
+ auto CalleeFeatures =
+ Callee->getFnAttribute("target-features").getValueAsString();
+ auto CallerFeatures =
+ CB.getCaller()->getFnAttribute("target-features").getValueAsString();
+ SmallVector<StringRef, 8> CalleeFeats;
+ CalleeFeatures.split(CalleeFeats, ',');
+ for (auto Feat : CalleeFeats) {
+ if (Feat.starts_with("+")) {
+ if (!CallerFeatures.contains(Feat)) {
+ if (FailureReason)
+ *FailureReason = "Incompatible target features";
+ return false;
+ }
+ }
+ }
+
return true;
}
diff --git a/llvm/test/Transforms/SampleProfile/icp_target_feature.ll b/llvm/test/Transforms/SampleProfile/icp_target_feature.ll
new file mode 100644
index 0000000000000..1210a97e98b09
--- /dev/null
+++ b/llvm/test/Transforms/SampleProfile/icp_target_feature.ll
@@ -0,0 +1,61 @@
+; This test verifies that indirect call promotion (ICP) under sample profiling
+; correctly checks target feature compatibility. Specifically, a callee with
+; target features incompatible with the caller's features (e.g., "_Z3moov" requiring
+; "+avx512f" while caller "_Z3goov" does not support it) should not be promoted,
+; while a compatible callee (e.g., "_Z3hoov") should be promoted successfully.
+; Note that under Sample PGO, the promotion candidates (e.g., _Z3hoov and _Z3moov)
+; are retrieved directly from the sample profile file (Inputs/norepeated-icp-2.prof)
+; at the corresponding line offset (1) rather than using value profile !prof metadata.
+; RUN: opt < %s -passes=sample-profile -sample-profile-file=%S/Inputs/norepeated-icp-2.prof -S | FileCheck %s
+
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+ at p = dso_local global ptr null, align 8
+
+; Function Attrs: uwtable mustprogress
+define dso_local void @_Z3moov() #0 !dbg !7 {
+entry:
+ ret void
+}
+
+; Function Attrs: uwtable mustprogress
+define dso_local void @_Z3hoov() #1 !dbg !11 {
+entry:
+ store ptr @_Z3moov, ptr @p, align 8
+ ret void
+}
+
+; Function Attrs: uwtable mustprogress
+define dso_local void @_Z3goov() #1 !dbg !24 {
+entry:
+ %t0 = load ptr, ptr @p, align 8
+ ; Here, _Z3moov requires "+avx512f" (attributes #0) which the caller lacks (attributes #1).
+ ; Therefore, _Z3moov is not promoted.
+ ; CHECK-NOT: icmp eq ptr %t0, @_Z3moov
+ ; On the other hand, _Z3hoov has compatible target features and is promoted successfully.
+ ; CHECK: icmp eq ptr %t0, @_Z3hoov
+ ; CHECK-NOT: icmp eq ptr %t0, @_Z3moov
+ call void %t0(), !dbg !26
+ ret void
+}
+
+attributes #0 = { uwtable mustprogress "use-sample-profile" "target-features"="+avx512f" }
+attributes #1 = { uwtable mustprogress "use-sample-profile" }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4, !5}
+!llvm.ident = !{!6}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang", isOptimized: true, runtimeVersion: 0, emissionKind: LineTablesOnly, enums: !2, splitDebugInlining: false, debugInfoForProfiling: true, nameTableKind: None)
+!1 = !DIFile(filename: "1.cc", directory: "")
+!2 = !{}
+!3 = !{i32 7, !"Dwarf Version", i32 4}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{i32 1, !"wchar_size", i32 4}
+!6 = !{!"clang"}
+!7 = distinct !DISubprogram(name: "moo", linkageName: "_Z3moov", scope: !1, file: !1, line: 1, type: !8, scopeLine: 1, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !2)
+!8 = !DISubroutineType(types: !2)
+!11 = distinct !DISubprogram(name: "hoo", linkageName: "_Z3hoov", scope: !1, file: !1, line: 9, type: !8, scopeLine: 9, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !2)
+!24 = distinct !DISubprogram(name: "goo", linkageName: "_Z3goov", scope: !1, file: !1, line: 15, type: !8, scopeLine: 15, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !2)
+!26 = !DILocation(line: 16, column: 3, scope: !24)
More information about the llvm-commits
mailing list