[llvm] [AggressiveInstCombine] Preserve Profile Info for [0, 1] Memset Guard (PR #223728)
Aiden Grossman via llvm-commits
llvm-commits at lists.llvm.org
Tue Sep 15 07:54:20 PDT 2026
https://github.com/boomanaiden154 created https://github.com/llvm/llvm-project/pull/223728
This showed up as a profcheck failure from #213240. If the memset has profile information, we can use that to synthesize appropriate branch weights.
>From b10a1d0313028a304f072a62dfbd237b46bfe8a7 Mon Sep 17 00:00:00 2001
From: Aiden Grossman <aidengrossman at google.com>
Date: Tue, 15 Sep 2026 14:44:59 +0000
Subject: [PATCH] [AggressiveInstCombine] Preserve Profile Info for [0,1]
Memset Guard
This showed up as a profcheck failure from #213240. If the memset has
profile information, we can use that to synthesize appropriate branch
weights.
---
.../AggressiveInstCombine.cpp | 27 +++++++
.../AggressiveInstCombine/memset.ll | 75 ++++++++++++++++++-
2 files changed, 99 insertions(+), 3 deletions(-)
diff --git a/llvm/lib/Transforms/AggressiveInstCombine/AggressiveInstCombine.cpp b/llvm/lib/Transforms/AggressiveInstCombine/AggressiveInstCombine.cpp
index 5e4f715d05a3d..20809ef3e4cfa 100644
--- a/llvm/lib/Transforms/AggressiveInstCombine/AggressiveInstCombine.cpp
+++ b/llvm/lib/Transforms/AggressiveInstCombine/AggressiveInstCombine.cpp
@@ -33,6 +33,7 @@
#include "llvm/IR/MDBuilder.h"
#include "llvm/IR/PatternMatch.h"
#include "llvm/IR/ProfDataUtils.h"
+#include "llvm/ProfileData/InstrProf.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
@@ -2476,6 +2477,26 @@ static bool foldMemSetZeroOrOneLength(Instruction &I, const DataLayout &DL,
if (!KnownLen.getMaxValue().isOne())
return false;
+ uint64_t TotalCount;
+ SmallVector<InstrProfValueData> MemsetVPMetadata = getValueProfDataFromInst(
+ I, InstrProfValueKind::IPVK_MemOPSize, 2, TotalCount);
+ std::optional<uint64_t> ZeroCount = std::nullopt;
+ std::optional<uint64_t> OneCount = std::nullopt;
+ for (const auto [MemOpSize, SizeFrequency] : MemsetVPMetadata) {
+ if (MemOpSize == 0)
+ ZeroCount = SizeFrequency;
+ else if (MemOpSize == 1)
+ OneCount = SizeFrequency;
+ }
+ // If we only have one value in the profile, we assume that the other is zero.
+ if (MemsetVPMetadata.size() == 1) {
+ if (ZeroCount.has_value())
+ OneCount = 0;
+ else if (OneCount.has_value())
+ ZeroCount = 0;
+ }
+
+ BasicBlock *HeadBlock = MI->getIterator()->getParent();
DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Lazy);
IRBuilder<> B(MI);
Value *IsNonZero = B.CreateIsNotNull(MI->getLength(), "memset.notzero");
@@ -2483,6 +2504,12 @@ static bool foldMemSetZeroOrOneLength(Instruction &I, const DataLayout &DL,
IsNonZero, MI->getIterator(), /*Unreachable=*/false,
/*BranchWeights=*/nullptr, &DTU);
+ Instruction &IsNonZeroBranch = *HeadBlock->getTerminator();
+ if (OneCount.has_value() && ZeroCount.has_value())
+ setFittedBranchWeights(IsNonZeroBranch, {*OneCount, *ZeroCount}, false);
+ else
+ setExplicitlyUnknownBranchWeightsIfProfiled(IsNonZeroBranch, DEBUG_TYPE);
+
IRBuilder<> StoreBuilder(ThenTerm);
StoreInst *Store = StoreBuilder.CreateAlignedStore(
MI->getValue(), MI->getDest(), MI->getDestAlign(), MI->isVolatile());
diff --git a/llvm/test/Transforms/AggressiveInstCombine/memset.ll b/llvm/test/Transforms/AggressiveInstCombine/memset.ll
index a5c1096c36dc0..df70907ab2285 100644
--- a/llvm/test/Transforms/AggressiveInstCombine/memset.ll
+++ b/llvm/test/Transforms/AggressiveInstCombine/memset.ll
@@ -4,13 +4,13 @@
declare void @llvm.memset.p0.i64(ptr, i8, i64, i1)
declare void @llvm.assume(i1)
-define void @range_0_1(ptr %dst, i8 %value, i64 %n) {
+define void @range_0_1(ptr %dst, i8 %value, i64 %n) !prof !0 {
; CHECK-LABEL: define void @range_0_1(
-; CHECK-SAME: ptr [[DST:%.*]], i8 [[VALUE:%.*]], i64 [[N:%.*]]) {
+; CHECK-SAME: ptr [[DST:%.*]], i8 [[VALUE:%.*]], i64 [[N:%.*]]) !prof [[PROF0:![0-9]+]] {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: [[LEN:%.*]] = and i64 [[N]], 1
; CHECK-NEXT: [[MEMSET_NOTZERO:%.*]] = icmp ne i64 [[LEN]], 0
-; CHECK-NEXT: br i1 [[MEMSET_NOTZERO]], label %[[DO_MEMSET:.*]], label %[[END:.*]]
+; CHECK-NEXT: br i1 [[MEMSET_NOTZERO]], label %[[DO_MEMSET:.*]], label %[[END:.*]], !prof [[PROF1:![0-9]+]]
; CHECK: [[DO_MEMSET]]:
; CHECK-NEXT: store i8 [[VALUE]], ptr [[DST]], align 1
; CHECK-NEXT: br label %[[END]]
@@ -23,6 +23,63 @@ entry:
ret void
}
+define void @range_0_1_value_profile(ptr %dst, i8 %value, i64 %n) !prof !0 {
+; CHECK-LABEL: define void @range_0_1_value_profile(
+; CHECK-SAME: ptr [[DST:%.*]], i8 [[VALUE:%.*]], i64 [[N:%.*]]) !prof [[PROF0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[LEN:%.*]] = and i64 [[N]], 1
+; CHECK-NEXT: [[MEMSET_NOTZERO:%.*]] = icmp ne i64 [[LEN]], 0
+; CHECK-NEXT: br i1 [[MEMSET_NOTZERO]], label %[[BB0:.*]], label %[[BB1:.*]], !prof [[PROF2:![0-9]+]]
+; CHECK: [[BB0]]:
+; CHECK-NEXT: store i8 [[VALUE]], ptr [[DST]], align 1
+; CHECK-NEXT: br label %[[BB1]]
+; CHECK: [[BB1]]:
+; CHECK-NEXT: ret void
+;
+entry:
+ %len = and i64 %n, 1
+ call void @llvm.memset.p0.i64(ptr align 1 %dst, i8 %value, i64 %len, i1 false), !prof !1
+ ret void
+}
+
+define void @range_0_1_value_profile_one_value(ptr %dst, i8 %value, i64 %n) !prof !0 {
+; CHECK-LABEL: define void @range_0_1_value_profile_one_value(
+; CHECK-SAME: ptr [[DST:%.*]], i8 [[VALUE:%.*]], i64 [[N:%.*]]) !prof [[PROF0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[LEN:%.*]] = and i64 [[N]], 1
+; CHECK-NEXT: [[MEMSET_NOTZERO:%.*]] = icmp ne i64 [[LEN]], 0
+; CHECK-NEXT: br i1 [[MEMSET_NOTZERO]], label %[[BB0:.*]], label %[[BB1:.*]], !prof [[PROF3:![0-9]+]]
+; CHECK: [[BB0]]:
+; CHECK-NEXT: store i8 [[VALUE]], ptr [[DST]], align 1
+; CHECK-NEXT: br label %[[BB1]]
+; CHECK: [[BB1]]:
+; CHECK-NEXT: ret void
+;
+entry:
+ %len = and i64 %n, 1
+ call void @llvm.memset.p0.i64(ptr align 1 %dst, i8 %value, i64 %len, i1 false), !prof !2
+ ret void
+}
+
+define void @range_0_1_value_profile_invalid_values(ptr %dst, i8 %value, i64 %n) !prof !0 {
+; CHECK-LABEL: define void @range_0_1_value_profile_invalid_values(
+; CHECK-SAME: ptr [[DST:%.*]], i8 [[VALUE:%.*]], i64 [[N:%.*]]) !prof [[PROF0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[LEN:%.*]] = and i64 [[N]], 1
+; CHECK-NEXT: [[MEMSET_NOTZERO:%.*]] = icmp ne i64 [[LEN]], 0
+; CHECK-NEXT: br i1 [[MEMSET_NOTZERO]], label %[[BB0:.*]], label %[[BB1:.*]], !prof [[PROF1]]
+; CHECK: [[BB0]]:
+; CHECK-NEXT: store i8 [[VALUE]], ptr [[DST]], align 1
+; CHECK-NEXT: br label %[[BB1]]
+; CHECK: [[BB1]]:
+; CHECK-NEXT: ret void
+;
+entry:
+ %len = and i64 %n, 1
+ call void @llvm.memset.p0.i64(ptr align 1 %dst, i8 %value, i64 %len, i1 false), !prof !3
+ ret void
+}
+
define void @range_0_1_zext(ptr %dst, i8 %value, i32 %n) {
; CHECK-LABEL: define void @range_0_1_zext(
; CHECK-SAME: ptr [[DST:%.*]], i8 [[VALUE:%.*]], i32 [[N:%.*]]) {
@@ -109,3 +166,15 @@ entry:
call void @llvm.memset.p0.i64(ptr align 1 %dst, i8 %value, i64 %n, i1 false)
ret void
}
+
+!0 = !{!"function_entry_count", i32 10}
+!1 = !{!"VP", i32 1, i64 5, i64 0, i64 2, i64 1, i64 3}
+!2 = !{!"VP", i32 1, i64 5, i64 1, i64 5}
+!3 = !{!"VP", i32 1, i64 5, i64 2, i64 4, i64 3, i64 1}
+
+;.
+; CHECK: [[PROF0]] = !{!"function_entry_count", i32 10}
+; CHECK: [[PROF1]] = !{!"unknown", !"aggressive-instcombine"}
+; CHECK: [[PROF2]] = !{!"branch_weights", i32 3, i32 2}
+; CHECK: [[PROF3]] = !{!"branch_weights", i32 5, i32 0}
+;.
More information about the llvm-commits
mailing list