[llvm] [IPO] Added attributor for identifying invariant loads (PR #141800)
Krzysztof Drewniak via llvm-commits
llvm-commits at lists.llvm.org
Wed May 28 10:43:46 PDT 2025
================
@@ -0,0 +1,220 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt -passes=attributor %s -S | FileCheck %s
+
+ at G = global i32 zeroinitializer, align 4
+
+declare ptr @get_ptr()
+declare noalias ptr @get_noalias_ptr()
+
+define i32 @test_plain(ptr %ptr) {
+; CHECK-LABEL: define i32 @test_plain(
+; CHECK-SAME: ptr nofree noundef nonnull readonly align 4 captures(none) dereferenceable(4) [[PTR:%.*]]) #[[ATTR0:[0-9]+]] {
+; CHECK-NEXT: [[VAL:%.*]] = load i32, ptr [[PTR]], align 4
+; CHECK-NEXT: ret i32 [[VAL]]
+;
+ %val = load i32, ptr %ptr, align 4
+ ret i32 %val
+}
+
+define i32 @test_noalias_ptr(ptr noalias %ptr) {
+; CHECK-LABEL: define i32 @test_noalias_ptr(
+; CHECK-SAME: ptr noalias nofree noundef nonnull readonly align 4 captures(none) dereferenceable(4) [[PTR:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[VAL:%.*]] = load i32, ptr [[PTR]], align 4, !invariant.load [[META0:![0-9]+]]
----------------
krzysz00 wrote:
Do we know if this is true in general? My understanding is that `!invariant.load` means that the value doesn't change at any program point where the pointer is dereferencable, while `readonly noalias` only guarantees a lack of modification during the execution of the function.
That is, is this safe with respect to inlining?
Consider
```llvm
define i1 @check(ptr noalias readonly nonnull noundef align 4 dereferencable(4) %ptr) {
%v = load i32, ptr %p ; This can be !invariant.load by current analysis
%r = cmpi eq i32 %v, 0
ret i1 %r
}
define i1 @foo(ptr %p, i32 %x) {
store i32 %x, ptr %p
%v = call i1 @check(ptr %p)
ret i1 %v
}
```
As far as I'm aware, if you inline `@check` into `@foo`, the `!invariant.load` can safely be hoisted above the `store` (or the `store` becomes UB and is eliminatable, or so on), thus defeating the purpose of `@foo`.
I think this analysis needs some information (which, I suspect, is triple-specific) about objects that have a program-wide lifetime (kernel arguments on GPUs, arguments to main(), etc.)
https://github.com/llvm/llvm-project/pull/141800
More information about the llvm-commits
mailing list