[llvm] [LoopIdiom] Don't convert `memset.inline` into `memset` (PR #227650)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Sep 30 03:35:06 PDT 2026
=?utf-8?q?Ömer_Sinan_Ağacan?= <omer at osa1.net>
Message-ID:
In-Reply-To: <llvm.org/llvm/llvm-project/pull/227650 at github.com>
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms
Author: Ömer Sinan Ağacan (osa1)
<details>
<summary>Changes</summary>
Also remove an old and invalid FIXME and reword comments to clarify why we don't turn inline intrinsics into non-inline versions.
---
Full diff: https://github.com/llvm/llvm-project/pull/227650.diff
2 Files Affected:
- (modified) llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp (+19-8)
- (added) llvm/test/Transforms/LoopIdiom/memset-inline-intrinsic.ll (+31)
``````````diff
diff --git a/llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp b/llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp
index bbb0bd370899e..5605b4a55a315 100644
--- a/llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp
@@ -837,8 +837,10 @@ bool LoopIdiomRecognize::processLoopMemCpy(MemCpyInst *MCI,
if (MCI->isVolatile() || !isa<ConstantInt>(MCI->getLength()))
return false;
- // If we're not allowed to hack on memcpy, we fail.
- if ((!HasMemcpy && !MCI->isForceInlined()) || DisableLIRP::Memcpy)
+ // If we're not allowed to hack on memcpy, we fail. We don't mess with the
+ // inlined version as generating a larger inline mempcy could affect code
+ // size.
+ if (!HasMemcpy || MCI->isForceInlined() || DisableLIRP::Memcpy)
return false;
Value *Dest = MCI->getDest();
@@ -900,8 +902,9 @@ bool LoopIdiomRecognize::processLoopMemSet(MemSetInst *MSI,
if (MSI->isVolatile())
return false;
- // If we're not allowed to hack on memset, we fail.
- if (!HasMemset || DisableLIRP::Memset)
+ // If we're not allowed to hack on memset, we fail. We don't mess with the
+ // inlined version as generating a larger memset could affect code size.
+ if (!HasMemset || MSI->isForceInlined() || DisableLIRP::Memset)
return false;
Value *Pointer = MSI->getDest();
@@ -1096,6 +1099,10 @@ bool LoopIdiomRecognize::processLoopStridedStore(
Value *StoredVal, Instruction *TheStore,
SmallPtrSetImpl<Instruction *> &Stores, const SCEVAddRecExpr *Ev,
const SCEV *BECount, bool IsNegStride, bool IsLoopMemset) {
+ // The same check as in `processLoopStoreOfLoopLoad`, see the comments there.
+ if (auto *MSI = dyn_cast<MemSetInst>(TheStore); MSI && MSI->isForceInlined())
+ return false;
+
Module *M = TheStore->getModule();
// The trip count of the loop and the base pointer of the addrec SCEV is
@@ -1352,10 +1359,14 @@ bool LoopIdiomRecognize::processLoopStoreOfLoopLoad(
MaybeAlign StoreAlign, MaybeAlign LoadAlign, Instruction *TheStore,
Instruction *TheLoad, const SCEVAddRecExpr *StoreEv,
const SCEVAddRecExpr *LoadEv, const SCEV *BECount) {
-
- // FIXME: until llvm.memcpy.inline supports dynamic sizes, we need to
- // conservatively bail here, since otherwise we may have to transform
- // llvm.memcpy.inline into llvm.memcpy which is illegal.
+ // Avoid converting `llvm.memcpy.inline` into `llvm.memcpy`, as the inline
+ // intrinsic is guaranteed to not make a libcall.
+ //
+ // We could generate `llvm.memcpy.inline` when the store instruction is the
+ // inline version, but that can potentially generate more code. For now, do
+ // the conservative thing and bail.
+ //
+ // The same check for `llvm.memset.inline` is in `processLoopStridedStore`.
if (auto *MCI = dyn_cast<MemCpyInst>(TheStore); MCI && MCI->isForceInlined())
return false;
diff --git a/llvm/test/Transforms/LoopIdiom/memset-inline-intrinsic.ll b/llvm/test/Transforms/LoopIdiom/memset-inline-intrinsic.ll
new file mode 100644
index 0000000000000..d2fe3f5d3073d
--- /dev/null
+++ b/llvm/test/Transforms/LoopIdiom/memset-inline-intrinsic.ll
@@ -0,0 +1,31 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -passes=loop-idiom < %s -S | FileCheck %s
+
+define void @f(ptr %a, i64 %n) {
+; CHECK-LABEL: @f(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: br label [[LOOP:%.*]]
+; CHECK: loop:
+; CHECK-NEXT: [[I:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[LOOP]] ]
+; CHECK-NEXT: [[P:%.*]] = getelementptr inbounds [16 x i8], ptr [[A:%.*]], i64 [[I]]
+; CHECK-NEXT: call void @llvm.memset.inline.p0.i64(ptr [[P]], i8 0, i64 16, i1 false)
+; CHECK-NEXT: [[INC]] = add nuw nsw i64 [[I]], 1
+; CHECK-NEXT: [[C:%.*]] = icmp ult i64 [[INC]], [[N:%.*]]
+; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]
+; CHECK: exit:
+; CHECK-NEXT: ret void
+;
+entry:
+ br label %loop
+
+loop:
+ %i = phi i64 [ 0, %entry ], [ %inc, %loop ]
+ %p = getelementptr inbounds [16 x i8], ptr %a, i64 %i
+ call void @llvm.memset.inline.p0.i64(ptr %p, i8 0, i64 16, i1 false)
+ %inc = add nuw nsw i64 %i, 1
+ %c = icmp ult i64 %inc, %n
+ br i1 %c, label %loop, label %exit
+
+exit:
+ ret void
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/227650
More information about the llvm-commits
mailing list