| Issue |
172295
|
| Summary |
[ConstantFolding] Constant folding during inline can leak users
|
| Labels |
new issue
|
| Assignees |
|
| Reporter |
Keenuts
|
Hi,
I discovered this while implementing push constant support for HLSL.
It seems when running the AlwaysInline pass, the ConstantFolding logic leaks users on global variables.
This can be observed by adding the following code in the `AlwaysInlinerImpl` code before and after the whole process
```cpp
for (auto &G : M.globals())
for (auto U : G.users())
U->dump();
```
And running the following test case:
```llvm
; RUN: opt -passes=always-inline %s -o - -S | FileCheck %s
target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-n8:16:32:64-G10"
target triple = "spirv1.6-unknown-vulkan1.3-compute"
%struct.layout = type <{ i32, float, target("spirv.Padding", 8), <3 x float>, target("spirv.Padding", 4), %struct.inner }>
%struct.inner = type <{ float }>
@PushConstants = external hidden global %struct.layout, align 1
define internal spir_func void @_Z4mainv() convergent alwaysinline {
entry:
%0 = call token @llvm.experimental.convergence.entry()
%1 = load float, ptr getelementptr inbounds nuw (%struct.layout, ptr @PushConstants, i32 0, i32 1), align 4
ret void
}
define void @main() convergent "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" {
entry:
%0 = call token @llvm.experimental.convergence.entry()
call spir_func void @_Z4mainv() [ "convergencectrl"(token %0) ]
ret void
}
declare token @llvm.experimental.convergence.entry() #0
attributes #0 = { convergent nocallback nofree nosync nounwind willreturn memory(none) }
```
Running this will show a single user before the pass begins:
```
ptr getelementptr inbounds nuw (%struct.layout, ptr @PushConstants, i32 0, i32 1)
```
But 3 users once the pass is done:
```
ptr getelementptr inbounds nuw (i8, ptr @PushConstants, i64 4)
ptr getelementptr inbounds nuw (%struct.layout, ptr @PushConstants, i64 0, i32 1)
ptr getelementptr inbounds nuw (%struct.layout, ptr @PushConstants, i32 0, i32 1)
```
The issue is: the first user does not exists in the resulting module:
```llvm
struct.layout = type <{ i32, float, target("spirv.Padding", 8), <3 x float>, target("spirv.Padding", 4), %struct.inner }>
%struct.inner = type <{ float }>
@PushConstants = external hidden global %struct.layout, align 1
; Function Attrs: convergent
define void @main() #0 {
entry:
%0 = call token @llvm.experimental.convergence.entry()
%1 = load float, ptr getelementptr inbounds nuw (%struct.layout, ptr @PushConstants, i32 0, i32 1), align 4
ret void
}
```
It seems when trying to ConstantFold a load, the GEP operand is first folded (causing the `GEP i64 4` to show up). Then, the load folding fails because the load source doesn't match some conditions, so folding returns nullptr and aborts. Issue is the created GEP still remains in the list of users.
This causes issues down the line as later passes, when inspecting the global variable users, will see those invalid users.
_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs