-
Notifications
You must be signed in to change notification settings - Fork 12.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
InstSimplify unconditionally executed trapping constant expression in phi fold #49839
Comments
This is still visible. I see srem and constant expressions in the IR, so some pass is likely hoisting an op without checking that it is safe to speculate. |
Still reproduces: https://godbolt.org/z/fx5j9zh49 According to GodBolt this started happening between 11.0 and 12.0: https://godbolt.org/z/hPrEb6a5E |
The culprit seems to be For the input, it sinks the
|
I think |
Thanks for tracking this down! |
Hm, I'm not so sure here. Intuitively I would say this transform is correct, because phi values are materialized on the incoming edge, not in the phi block. LangRef says:
I would say it's a backend bug if the backend materializes a trapping constant expression in the phi block. It should happen on the edge (possibly a split critical edge). But then alive2 says the transform is not valid, so possibly my understanding of the semantics is not correct. |
Thinking about this a bit more, I think this transform must be valid, otherwise doing RAUW with a constant folding result would be illegal, which would be very bad. I think the alive2 modelling isn't correct in this instance, because it places the constexpr evaluation in the wrong block. |
Yes that was my original thought as well, the incoming value should only execute when the edge is executed. |
I agree that as per langref the backend is at fault here. |
What if a phi BB's predecessor has multiple successors?
is this the same as:
or:
|
@nunoplopes The latter. If the edge is critical, it needs to be split. |
Thank you, makes sense! Let me try to implement that in Alive2.. |
I looked a bit closer into the original reproducer, and the problem here is in InstSimplify after all, just in a different place:
The phi with poison fold ends up executing the constant expression unconditionally, rather than only on one branch. |
It looks like the original C test still fails:
Compiler Explorer: https://godbolt.org/z/f5G5r16x5 |
According to alivecc, this is a bug in InstSimplify. Before: %vector.body:
%index = phi i32 [ 0, %vector.ph ], [ %index.next, %pred.srem.continue24 ]
%11 = phi i32 [ %3, %vector.ph ], [ %28, %pred.srem.continue24 ]
br i1 %7, label %pred.srem.if, label %pred.srem.continue
%pred.srem.continue:
%14 = phi <4 x i8> [ poison, %vector.body ], [ %13, %pred.srem.if ]
br i1 %8, label %pred.srem.if19, label %pred.srem.continue20
%pred.srem.if:
%__constexpr_5 = gep inbounds ptr @e, 8 x i64 0, 4 x i64 1
%__constexpr_4 = icmp eq ptr %__constexpr_5, @a
%__constexpr_3 = zext i1 %__constexpr_4 to i8
%12 = srem i8 1, %__constexpr_3
%13 = insertelement <4 x i8> poison, i8 %12, i64 0
br label %pred.srem.continue
%pred.srem.continue20:
%17 = phi <4 x i8> [ %14, %pred.srem.continue ], [ %16, %pred.srem.if19 ] After: %vector.body:
%index = phi i32 [ 0, %vector.ph ], [ %index.next, %pred.srem.continue24 ]
%4 = phi i32 [ %3, %vector.ph ], [ %14, %pred.srem.continue24 ]
%__constexpr_1 = gep inbounds ptr @e, 8 x i64 0, 4 x i64 1
%__constexpr_0 = icmp eq ptr %__constexpr_1, @a
br i1 %__constexpr_0, label %pred.srem.if, label %pred.srem.continue
%pred.srem.continue:
%__constexpr_3 = gep inbounds ptr @e, 8 x i64 0, 4 x i64 1
%__constexpr_2 = icmp eq ptr %__constexpr_3, @a
br i1 %__constexpr_2, label %pred.srem.if19, label %pred.srem.continue_%pred.srem.continue20
%pred.srem.continue_%pred.srem.continue20:
%__constexpr_34 = gep inbounds ptr @e, 8 x i64 0, 4 x i64 1
%__constexpr_33 = icmp eq ptr %__constexpr_34, @a
%__constexpr_32 = zext i1 %__constexpr_33 to i8 ; 0
%__constexpr_31 = srem i8 1, %__constexpr_32 ; UB
%__copy_1 = <4 x i8> { %__constexpr_31, poison, poison, poison }
br label %pred.srem.continue20
%pred.srem.continue20:
%5 = phi <4 x i8> [ %__copy_1, %pred.srem.continue_%pred.srem.continue20 ], [ %__copy_2, %pred.srem.if19 ] We may need c-smith + alivecc to minimize this thing (@regehr). |
The code looks good, I dunno where the bug might be: llvm-project/llvm/lib/Analysis/InstructionSimplify.cpp Lines 4847 to 4851 in b8c2781
|
Reduced test case: @e = external global [2 x i32]
@a = external global i32
define i8 @main() {
pred.srem.continue8:
br i1 false, label %pred.srem.if9, label %pred.srem.continue10
pred.srem.if9:
%sr = srem i8 1, zext (i1 icmp eq (ptr getelementptr inbounds ([2 x i32], ptr @e, i64 0, i64 1), ptr @a) to i8)
%v = insertelement <4 x i8> zeroinitializer, i8 %sr, i64 3
br label %pred.srem.continue10
pred.srem.continue10:
%phi = phi <4 x i8> [ poison, %pred.srem.continue8 ], [ %v, %pred.srem.if9 ]
%r = extractelement <4 x i8> %phi, i64 3
br label %middle.block
middle.block:
ret i8 %r
} InstSimplify changes: @@ -6,15 +6,11 @@
br i1 false, label %pred.srem.if9, label %pred.srem.continue10
pred.srem.if9:
- %sr = srem i8 1, zext (i1 icmp eq (ptr getelementptr inbounds ([2 x i32], ptr @e, i64 0, i64 1), ptr @a) to i8)
- %v = insertelement <4 x i8> zeroinitializer, i8 %sr, i64 3
br label %pred.srem.continue10
pred.srem.continue10:
- %phi = phi <4 x i8> [ poison, %pred.srem.continue8 ], [ %v, %pred.srem.if9 ]
- %r = extractelement <4 x i8> %phi, i64 3
br label %middle.block
middle.block:
- ret i8 %r
+ ret i8 srem (i8 1, i8 zext (i1 icmp eq (ptr getelementptr inbounds ([2 x i32], ptr @e, i64 0, i64 1), ptr @a) to i8))
} |
This is because I only checked for
Constant . In this case it's a trapping constant expression inside an aggregate constant.
|
Okay, this was a bit trickier than expected, because the ...however, testing the original C reproducer just now, it still fails, so there must be another issue somewhere. |
Perhaps #55999 is also related although it doesn't reproduce with 13.* and 14.*? |
@zhendongsu it's hard to tell without looking at the IR. You can use |
It's SimplifyCFG now: @e = external global [2 x i32]
@a = external global i32
define i32 @main(i1 %0) {
vector.body:
br i1 %0, label %pred.srem.if, label %pred.srem.continue
pred.srem.if:
br label %pred.srem.continue
pred.srem.continue:
%1 = phi <4 x i8> [ zeroinitializer, %vector.body ], [ <i8 srem (i8 1, i8 zext (i1 icmp eq (ptr getelementptr inbounds ([2 x i32], ptr @e, i64 0, i64 1), ptr @a) to i8)), i8 poison, i8 poison, i8 poison>, %pred.srem.if ]
ret i32 0
} gets transformed to: define i32 @main(i1 %0) {
vector.body:
%spec.select = select i1 %0, <4 x i8> <i8 srem (i8 1, i8 zext (i1 icmp eq (ptr getelementptr inbounds ([2 x i32], ptr @e, i64 0, i64 1), ptr @a) to i8)), i8 poison, i8 poison, i8 poison>, <4 x i8> zeroinitializer
ret i32 0
} |
Yeah, we have quite a few places with the same basic issue, they're checking canTrap() on ConstantExpr rather than Constant. |
Fixed some SimplifyCFG issues in 571c713, but the C reproducer is still broken. I still see an incorrect usage in SelectionDAGIsel, will check if fixing that helps. |
I fixed the SelectionDAG issue in b9a7dea, but it did not help. |
Thanks @nikic! There's still a problem in SimplifyCFG somehow: @e = external global [2 x i32]
@a = external global i32
define i32 @main(i1 %0) {
vector.body:
br i1 %0, label %pred.srem.if, label %pred.srem.continue
pred.srem.if:
br label %pred.srem.continue
pred.srem.continue:
%1 = phi <4 x i8> [ poison, %vector.body ], [ <i8 srem (i8 1, i8 zext (i1 icmp eq (ptr getelementptr inbounds ([2 x i32], ptr @e, i64 0, i64 1), ptr @a) to i8)), i8 poison, i8 poison, i8 poison>, %pred.srem.if ]
br label %pred.srem.continue6
pred.srem.continue6:
br i1 %0, label %pred.srem.if7, label %pred.srem.continue8
pred.srem.if7:
%2 = insertelement <4 x i8> zeroinitializer, i8 0, i64 0
br label %pred.srem.continue8
pred.srem.continue8:
%3 = phi <4 x i8> [ %1, %pred.srem.continue6 ], [ zeroinitializer, %pred.srem.if7 ]
ret i32 0
} |
I've put up an RFC to address the root cause: https://discourse.llvm.org/t/rfc-remove-most-constant-expressions/63179 |
@nikic fixed this already. |
…839) Folding this case would result in the constant expression being executed unconditionally, which may introduce a new trap. Fixes llvm/llvm-project#49839.
Unfortunately, it's not just constant expressions that can trap, we might also have a trapping constant expression nested inside a constant aggregate. Perform the check during phi folding on Constant rather than ConstantExpr, and extend the Constant::mayTrap() implementation to also recursive into ConstantAggregates, not just ConstantExprs. Fixes llvm/llvm-project#49839.
Extended Description
[585] % clangtk -v
clang version 13.0.0 (https://github.com/llvm/llvm-project.git 5dd86aa)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /local/suz-local/opfuzz/bin
Found candidate GCC installation: /usr/lib/gcc/i686-linux-gnu/8
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/6
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/6.5.0
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/7
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/7.5.0
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/8
Selected GCC installation: /usr/lib/gcc/x86_64-linux-gnu/7.5.0
Candidate multilib: .;@m64
Candidate multilib: 32;@m32
Candidate multilib: x32;@MX32
Selected multilib: .;@m64
[586] %
[586] % clangtk -O2 small.c; ./.aout
bash: ./.aout: No such file or directory
[587] %
[587] %
[587] % clangtk -v
clang version 13.0.0 (https://github.com/llvm/llvm-project.git 5dd86aa)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /local/suz-local/opfuzz/bin
Found candidate GCC installation: /usr/lib/gcc/i686-linux-gnu/8
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/6
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/6.5.0
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/7
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/7.5.0
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/8
Selected GCC installation: /usr/lib/gcc/x86_64-linux-gnu/7.5.0
Candidate multilib: .;@m64
Candidate multilib: 32;@m32
Candidate multilib: x32;@MX32
Selected multilib: .;@m64
clang-13: warning: argument unused during compilation: '-I /usr/local/include/csmith' [-Wunused-command-line-argument]
[588] %
[588] % clangtk -O2 small.c; ./a.out
[589] %
[589] % clangtk -O3 small.c
[590] % ./a.out
Floating point exception
[591] %
[591] % cat small.c
The text was updated successfully, but these errors were encountered: