-
Notifications
You must be signed in to change notification settings - Fork 12k
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
[IndVars][SCEVExpander] Incorrect reuse of disjoint or instructions #79861
Comments
It seems to go wrong sometime before git hash bc82cfb, |
I think the idiosyncrasy here stems from IndVarSimplifyPass / SCEV. In for.body2.i: ; preds = %for.body2.i, %entry
%0 = phi i32 [ 2, %entry ], [ %dec.i, %for.body2.i ]
%1 = and i32 %0, 65535
%tobool.not.i.i = icmp eq i32 %1, 0
%add21.i = add nsw i32 %0, 2
%add.i = or disjoint i32 %0, 2
%idxprom8.idxprom822.v.i = select i1 %tobool.not.i.i, i32 %add.i, i32 %add21.i
%idxprom8.idxprom822.i = sext i32 %idxprom8.idxprom822.v.i to i64
; memory accesses omitted
%dec.i = add nsw i32 %0, -1
%tobool.not.i = icmp eq i32 %dec.i, 0
br i1 %tobool.not.i, label %k.exit, label %for.body2.i Conversely, in for.body2.i: ; preds = %for.body2.i, %entry
%0 = phi i32 [ 2, %entry ], [ %dec.i, %for.body2.i ]
%1 = and i32 %0, 65535
%tobool.not.i.i = icmp eq i32 %1, 0
%add.i = or disjoint i32 %0, 2
%add21.i = add nsw i32 %0, 2
%idxprom822.sink33.v.i = select i1 %tobool.not.i.i, i32 %add.i, i32 %add21.i
%idxprom822.sink33.i = sext i32 %idxprom822.sink33.v.i to i64
; memory accesses omitted
%dec.i = add nsw i32 %0, -1
%tobool.not.i = icmp eq i32 %dec.i, 0
br i1 %tobool.not.i, label %k.exit, label %for.body2.i InstCombine arranges the for.body2.i: ; preds = %for.body2.i, %entry
%indvars.iv = phi i64 [ %indvars.iv.next, %for.body2.i ], [ 2, %entry ]
%0 = add nuw nsw i64 %indvars.iv, 2
%arrayidx923.i = getelementptr inbounds [2 x [5 x i32]], ptr @b, i64 0, i64 0, i64 %0
%arrayidx923.1.i = getelementptr inbounds [2 x [5 x i32]], ptr @b, i64 0, i64 1, i64 %0
for.body2.i: ; preds = %for.body2.i, %entry
%indvars.iv = phi i64 [ %indvars.iv.next, %for.body2.i ], [ 2, %entry ]
%0 = or disjoint i64 %indvars.iv, 2
%arrayidx923.i = getelementptr inbounds [2 x [5 x i32]], ptr @b, i64 0, i64 0, i64 %0
%arrayidx923.1.i = getelementptr inbounds [2 x [5 x i32]], ptr @b, i64 0, i64 1, i64 %0 I can take a look, maybe @nikic might confirm this though (Alive2 says source functions are UB: https://alive2.llvm.org/ce/z/vK-zUe). |
@antoniofrighetto Just from your description, I suspect this may be related to SCEVExpander value reuse. SCEV will add a mapping from |
I suspect releases are on a different branch to the mainstream, but the date With my previous comment, that gives me a git range, so I will have a look at half-way, |
Date 2023-11-13 seems good, trying 2023-12-13, commit 2c5fe14. |
2023-12-13 tested bad, so trying 2023-11-29 commit 771e9cd |
Date 2023-11-29 looks good, so trying date 2023-12-06 commit 546a9ce. |
Reduced test case: declare void @use(i64)
define void @test() {
entry:
br label %loop
loop:
%iv = phi i64 [ 2, %entry ], [ %iv.dec, %loop ]
%iv.zero = icmp eq i64 %iv, 0
%or = or disjoint i64 %iv, 1
%add = add nsw i64 %iv, 1
%sel = select i1 %iv.zero, i64 %or, i64 %add
call void @use(i64 %sel)
%iv.dec = add nsw i64 %iv, -1
%exit.cond = icmp eq i64 %iv.dec, 0
br i1 %exit.cond, label %exit, label %loop
exit:
ret void
} |
Okay, the guess about SCEVExpander wasn't right (though I suspect there may still be an issue there). This particular problem is introduced by It replaces an instruction with an instruction operand if they have the same SCEV -- but this may not be poison-safe. Here's another variant that doesn't use the new define void @test2(i64 %n) {
entry:
br label %loop
loop:
%iv = phi i64 [ 0, %entry ], [ %iv.inc, %loop ]
%add1 = add nuw nsw i64 %iv, 123
%add2 = add i64 %iv, 123
%sel = select i1 false, i64 %add1, i64 %add2
call void @use(i64 %sel)
%iv.inc = add i64 %iv, 1
%exit.cond = icmp eq i64 %iv.inc, %n
br i1 %exit.cond, label %exit, label %loop
exit:
ret void
} This will pick the add instruction with the nowrap flags, which may not be correct. |
Here's a variant that demonstrates the SCEVExpander issue: target datalayout = "n64"
declare void @use(i64)
define void @test3(i64 %n) {
entry:
%or = or disjoint i64 %n, 1
br label %loop
loop:
%iv = phi i64 [ 0, %entry ], [ %iv.inc, %loop ]
%iv.inc = add i64 %iv, 1
%add = add i64 %iv, %or
call void @use(i64 %add)
%cmp = icmp ult i64 %iv, %n
br i1 %cmp, label %loop, label %exit
exit:
ret void
} This will rewrite the condition to compare with |
I've put up #80281 for the SCEVExpander part of this. I think the IndVars side fix will involve reusing the same legality analysis SCEVExpander performs, so it's good to fix that first. |
SCEV treats "or disjoint" the same as "add nsw nuw". However, when expanding, we cannot generally replace an add SCEV node with an "or disjoint" instruction. Just dropping the poison flag is insufficient in this case, we would have to actually convert the or into an add. This is a partial fix for llvm#79861.
SCEV treats "or disjoint" the same as "add nsw nuw". However, when expanding, we cannot generally replace an add SCEV node with an "or disjoint" instruction. Just dropping the poison flag is insufficient in this case, we would have to actually convert the or into an add. This is a partial fix for #79861.
IndVars may replace an instruction with one of its operands, if they have the same SCEV expression. However, such a replacement may be more poisonous. First, check whether the operand being poison implies that the instruction is also poison, in which case the replacement is always safe. If this fails, check whether SCEV can determine that reusing the instruction is safe, using the same check as SCEVExpander. Fixes llvm#79861.
IndVars may replace an instruction with one of its operands, if they have the same SCEV expression. However, such a replacement may be more poisonous. First, check whether the operand being poison implies that the instruction is also poison, in which case the replacement is always safe. If this fails, check whether SCEV can determine that reusing the instruction is safe, using the same check as SCEVExpander. Fixes #79861.
SCEV treats "or disjoint" the same as "add nsw nuw". However, when expanding, we cannot generally replace an add SCEV node with an "or disjoint" instruction. Just dropping the poison flag is insufficient in this case, we would have to actually convert the or into an add. This is a partial fix for llvm#79861.
) IndVars may replace an instruction with one of its operands, if they have the same SCEV expression. However, such a replacement may be more poisonous. First, check whether the operand being poison implies that the instruction is also poison, in which case the replacement is always safe. If this fails, check whether SCEV can determine that reusing the instruction is safe, using the same check as SCEVExpander. Fixes llvm#79861.
(cherry picked from commit c105848)
SCEV treats "or disjoint" the same as "add nsw nuw". However, when expanding, we cannot generally replace an add SCEV node with an "or disjoint" instruction. Just dropping the poison flag is insufficient in this case, we would have to actually convert the or into an add. This is a partial fix for llvm#79861. (cherry picked from commit 5b8e1a6)
) IndVars may replace an instruction with one of its operands, if they have the same SCEV expression. However, such a replacement may be more poisonous. First, check whether the operand being poison implies that the instruction is also poison, in which case the replacement is always safe. If this fails, check whether SCEV can determine that reusing the instruction is safe, using the same check as SCEVExpander. Fixes llvm#79861. (cherry picked from commit 7d2b6f0)
/pull-request #80832 |
(cherry picked from commit c105848)
SCEV treats "or disjoint" the same as "add nsw nuw". However, when expanding, we cannot generally replace an add SCEV node with an "or disjoint" instruction. Just dropping the poison flag is insufficient in this case, we would have to actually convert the or into an add. This is a partial fix for llvm#79861. (cherry picked from commit 5b8e1a6)
) IndVars may replace an instruction with one of its operands, if they have the same SCEV expression. However, such a replacement may be more poisonous. First, check whether the operand being poison implies that the instruction is also poison, in which case the replacement is always safe. If this fails, check whether SCEV can determine that reusing the instruction is safe, using the same check as SCEVExpander. Fixes llvm#79861. (cherry picked from commit 7d2b6f0)
(cherry picked from commit c105848)
SCEV treats "or disjoint" the same as "add nsw nuw". However, when expanding, we cannot generally replace an add SCEV node with an "or disjoint" instruction. Just dropping the poison flag is insufficient in this case, we would have to actually convert the or into an add. This is a partial fix for llvm#79861. (cherry picked from commit 5b8e1a6)
) IndVars may replace an instruction with one of its operands, if they have the same SCEV expression. However, such a replacement may be more poisonous. First, check whether the operand being poison implies that the instruction is also poison, in which case the replacement is always safe. If this fails, check whether SCEV can determine that reusing the instruction is safe, using the same check as SCEVExpander. Fixes llvm#79861. (cherry picked from commit 7d2b6f0)
It appears to be a recent regression as it doesn't reproduce with 17.0.1.
Compiler Explorer: https://godbolt.org/z/W5WEb7Eev
The text was updated successfully, but these errors were encountered: