Closed
Description
I tried the following IR:
define internal ptr @bar(ptr %arg, i1 %arg1) {
bb:
br i1 %arg1, label %bb4, label %bb2
bb2:
%i = load ptr, ptr %arg, align 8
%i3 = getelementptr inbounds i8, ptr %i, i64 1
store ptr %i3, ptr %arg, align 8
br label %bb4
bb4:
%i5 = phi ptr [ %i, %bb2 ], [ null, %bb ]
ret ptr %i5
}
define i32 @foo(ptr %arg, i1 %arg1) {
bb:
%i = call ptr @bar(ptr %arg, i1 %arg1)
%i2 = icmp ne ptr %i, null
call void @llvm.assume(i1 %i2)
%i3 = load i32, ptr %i, align 4
ret i32 %i3
}
declare void @llvm.assume(i1)
We can eliminate the branch, but it doesn't. To my surprise, re-executing the output once simplifycfg eliminates this branch: https://llvm.godbolt.org/z/85zKbMdxe.
I've noticed that the user order is different after inlining and reading the text IR. See: #98799 (comment).
The passingValueIsAlwaysUndefined
only considers the first user:
llvm-project/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
Lines 7567 to 7577 in 92f4001
Of course there are many ways to solve this problem, for example:
- Handle all users
- Choose an instruction that
passingValueIsAlwaysUndefined
can handle (I'd go with this one first.) - Support
assume(%p == null)
But my biggest concern here is whether the user order needs to be consistent. I don't like it when an optimization happens randomly.