[llvm] [SCEV] Restrict wrap flags when construction same AR for multiple phis. (PR #80430)

Florian Hahn via llvm-commits llvm-commits at lists.llvm.org
Fri Feb 2 06:27:03 PST 2024


https://github.com/fhahn updated https://github.com/llvm/llvm-project/pull/80430

>From 8add9c733e9ed36c3c14dc4e375746a6b34abdc0 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Fri, 2 Feb 2024 12:49:26 +0000
Subject: [PATCH 1/3] [SCEV] Add SCEV analysis tests with congruent IVs.

This patch adds a set of tests taken
from/llvm/test/Transforms/IndVarSimplify/iv-poison.ll with multiple
congruent IVs but different set of flags on the increments.
---
 .../Analysis/ScalarEvolution/iv-poison.ll     | 399 ++++++++++++++++++
 1 file changed, 399 insertions(+)
 create mode 100644 llvm/test/Analysis/ScalarEvolution/iv-poison.ll

diff --git a/llvm/test/Analysis/ScalarEvolution/iv-poison.ll b/llvm/test/Analysis/ScalarEvolution/iv-poison.ll
new file mode 100644
index 0000000000000..771a93f79cb11
--- /dev/null
+++ b/llvm/test/Analysis/ScalarEvolution/iv-poison.ll
@@ -0,0 +1,399 @@
+; NOTE: Assertions have been autogenerated by utils/update_analyze_test_checks.py UTC_ARGS: --version 4
+; RUN: opt "-passes=print<scalar-evolution>" -disable-output -S %s 2>&1 | FileCheck %s
+
+; PR59777
+define i2 @iv_nsw_poison(i2 %arg) {
+; CHECK-LABEL: 'iv_nsw_poison'
+; CHECK-NEXT:  Classifying expressions for: @iv_nsw_poison
+; CHECK-NEXT:    %.07 = phi i2 [ 1, %bb ], [ %i, %bb1 ]
+; CHECK-NEXT:    --> {1,+,1}<nuw><nsw><%bb1> U: [1,-2) S: [1,-2) Exits: <<Unknown>> LoopDispositions: { %bb1: Computable }
+; CHECK-NEXT:    %.0 = phi i2 [ 1, %bb ], [ %i2, %bb1 ]
+; CHECK-NEXT:    --> {1,+,1}<nuw><nsw><%bb1> U: [1,-2) S: [1,-2) Exits: <<Unknown>> LoopDispositions: { %bb1: Computable }
+; CHECK-NEXT:    %i = add nsw i2 %.07, 1
+; CHECK-NEXT:    --> {-2,+,1}<nuw><%bb1> U: [-2,0) S: [-2,0) Exits: <<Unknown>> LoopDispositions: { %bb1: Computable }
+; CHECK-NEXT:    %i2 = add i2 %.0, 1
+; CHECK-NEXT:    --> {-2,+,1}<nuw><%bb1> U: [-2,0) S: [-2,0) Exits: <<Unknown>> LoopDispositions: { %bb1: Computable }
+; CHECK-NEXT:  Determining loop execution counts for: @iv_nsw_poison
+; CHECK-NEXT:  Loop %bb1: Unpredictable backedge-taken count.
+; CHECK-NEXT:  Loop %bb1: Unpredictable constant max backedge-taken count.
+; CHECK-NEXT:  Loop %bb1: Unpredictable symbolic max backedge-taken count.
+; CHECK-NEXT:  Loop %bb1: Unpredictable predicated backedge-taken count.
+;
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb1, %bb
+  %.07 = phi i2 [ 1, %bb ], [ %i, %bb1 ]
+  %.0 = phi i2 [ 1, %bb ], [ %i2, %bb1 ]
+  %i = add nsw i2 %.07, 1
+  %i2 = add i2 %.0, 1
+  %.not.not = icmp ult i2 %.07, %arg
+  br i1 %.not.not, label %common.ret, label %bb1
+
+common.ret:                                       ; preds = %bb1
+  ret i2 %i2
+}
+
+define i4 @iv_nsw_poison2(i4 %0, i4 %end, i4 %start) {
+; CHECK-LABEL: 'iv_nsw_poison2'
+; CHECK-NEXT:  Classifying expressions for: @iv_nsw_poison2
+; CHECK-NEXT:    %iv.0 = phi i4 [ %start, %entry ], [ %iv.0.next, %loop ]
+; CHECK-NEXT:    --> {%start,+,1}<%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:    %iv.1 = phi i4 [ %start, %entry ], [ %iv.1.next, %loop ]
+; CHECK-NEXT:    --> {%start,+,1}<nsw><%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:    %iv.0.next = add i4 %iv.0, 1
+; CHECK-NEXT:    --> {(1 + %start),+,1}<nw><%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:    %iv.1.next = add nsw i4 %iv.1, 1
+; CHECK-NEXT:    --> {(1 + %start),+,1}<nw><%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:  Determining loop execution counts for: @iv_nsw_poison2
+; CHECK-NEXT:  Loop %loop: Unpredictable backedge-taken count.
+; CHECK-NEXT:  Loop %loop: Unpredictable constant max backedge-taken count.
+; CHECK-NEXT:  Loop %loop: Unpredictable symbolic max backedge-taken count.
+; CHECK-NEXT:  Loop %loop: Unpredictable predicated backedge-taken count.
+;
+entry:
+  br label %loop
+
+loop:
+  %iv.0 = phi i4 [ %start, %entry ], [ %iv.0.next, %loop ]
+  %iv.1 = phi i4 [ %start, %entry ], [ %iv.1.next, %loop ]
+  %iv.0.next = add i4 %iv.0, 1
+  %iv.1.next = add nsw i4 %iv.1, 1
+  %.not.not = icmp ult i4 %iv.0, %end
+  br i1 %.not.not, label %exit, label %loop
+
+exit:
+  ret i4 %iv.1.next
+}
+
+define i2 @iv_both_adds_nsw(i2 %arg) {
+; CHECK-LABEL: 'iv_both_adds_nsw'
+; CHECK-NEXT:  Classifying expressions for: @iv_both_adds_nsw
+; CHECK-NEXT:    %iv.0 = phi i2 [ 1, %bb ], [ %iv.0.next, %loop ]
+; CHECK-NEXT:    --> {1,+,1}<nuw><nsw><%loop> U: [1,-2) S: [1,-2) Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:    %iv.1 = phi i2 [ 1, %bb ], [ %iv.1.next, %loop ]
+; CHECK-NEXT:    --> {1,+,1}<nuw><nsw><%loop> U: [1,-2) S: [1,-2) Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:    %iv.0.next = add nsw i2 %iv.0, 1
+; CHECK-NEXT:    --> {-2,+,1}<nuw><%loop> U: [-2,0) S: [-2,0) Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:    %iv.1.next = add nsw i2 %iv.1, 1
+; CHECK-NEXT:    --> {-2,+,1}<nuw><%loop> U: [-2,0) S: [-2,0) Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:  Determining loop execution counts for: @iv_both_adds_nsw
+; CHECK-NEXT:  Loop %loop: Unpredictable backedge-taken count.
+; CHECK-NEXT:  Loop %loop: Unpredictable constant max backedge-taken count.
+; CHECK-NEXT:  Loop %loop: Unpredictable symbolic max backedge-taken count.
+; CHECK-NEXT:  Loop %loop: Unpredictable predicated backedge-taken count.
+;
+bb:
+  br label %loop
+
+loop:
+  %iv.0 = phi i2 [ 1, %bb ], [ %iv.0.next, %loop ]
+  %iv.1 = phi i2 [ 1, %bb ], [ %iv.1.next, %loop ]
+  %iv.0.next = add nsw i2 %iv.0, 1
+  %iv.1.next = add nsw i2 %iv.1, 1
+  %.not.not = icmp ult i2 %iv.0, %arg
+  br i1 %.not.not, label %exit, label %loop
+
+exit:
+  ret i2 %iv.1.next
+}
+
+define i4 @iv_both_adds_nsw_extra_use(i4 %arg) {
+; CHECK-LABEL: 'iv_both_adds_nsw_extra_use'
+; CHECK-NEXT:  Classifying expressions for: @iv_both_adds_nsw_extra_use
+; CHECK-NEXT:    %iv.0 = phi i4 [ 1, %bb ], [ %iv.0.next, %loop ]
+; CHECK-NEXT:    --> {1,+,1}<nuw><nsw><%loop> U: [1,-8) S: [1,-8) Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:    %iv.1 = phi i4 [ 1, %bb ], [ %iv.1.next, %loop ]
+; CHECK-NEXT:    --> {1,+,1}<nuw><nsw><%loop> U: [1,-8) S: [1,-8) Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:    %iv.0.next = add nsw i4 %iv.0, 1
+; CHECK-NEXT:    --> {2,+,1}<nuw><%loop> U: [2,0) S: [2,0) Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:    %iv.1.next = add nsw i4 %iv.1, 1
+; CHECK-NEXT:    --> {2,+,1}<nuw><%loop> U: [2,0) S: [2,0) Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:  Determining loop execution counts for: @iv_both_adds_nsw_extra_use
+; CHECK-NEXT:  Loop %loop: Unpredictable backedge-taken count.
+; CHECK-NEXT:  Loop %loop: Unpredictable constant max backedge-taken count.
+; CHECK-NEXT:  Loop %loop: Unpredictable symbolic max backedge-taken count.
+; CHECK-NEXT:  Loop %loop: Unpredictable predicated backedge-taken count.
+;
+bb:
+  br label %loop
+
+loop:
+  %iv.0 = phi i4 [ 1, %bb ], [ %iv.0.next, %loop ]
+  %iv.1 = phi i4 [ 1, %bb ], [ %iv.1.next, %loop ]
+  %iv.0.next = add nsw i4 %iv.0, 1
+  call void @use(i4 %iv.0.next)
+  %iv.1.next = add nsw i4 %iv.1, 1
+  call void @use(i4 %iv.1.next)
+  %.not.not = icmp ult i4 %iv.0, %arg
+  br i1 %.not.not, label %exit, label %loop
+
+exit:
+  ret i4 %iv.1.next
+}
+
+define i4 @iv_both_adds_nsw_extra_use_incs_reordered(i4 %arg) {
+; CHECK-LABEL: 'iv_both_adds_nsw_extra_use_incs_reordered'
+; CHECK-NEXT:  Classifying expressions for: @iv_both_adds_nsw_extra_use_incs_reordered
+; CHECK-NEXT:    %iv.0 = phi i4 [ 1, %bb ], [ %iv.0.next, %loop ]
+; CHECK-NEXT:    --> {1,+,1}<nuw><nsw><%loop> U: [1,-8) S: [1,-8) Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:    %iv.1 = phi i4 [ 1, %bb ], [ %iv.1.next, %loop ]
+; CHECK-NEXT:    --> {1,+,1}<nuw><nsw><%loop> U: [1,-8) S: [1,-8) Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:    %iv.1.next = add nsw i4 %iv.1, 1
+; CHECK-NEXT:    --> {2,+,1}<nuw><%loop> U: [2,0) S: [2,0) Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:    %iv.0.next = add nsw i4 %iv.0, 1
+; CHECK-NEXT:    --> {2,+,1}<nuw><%loop> U: [2,0) S: [2,0) Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:  Determining loop execution counts for: @iv_both_adds_nsw_extra_use_incs_reordered
+; CHECK-NEXT:  Loop %loop: Unpredictable backedge-taken count.
+; CHECK-NEXT:  Loop %loop: Unpredictable constant max backedge-taken count.
+; CHECK-NEXT:  Loop %loop: Unpredictable symbolic max backedge-taken count.
+; CHECK-NEXT:  Loop %loop: Unpredictable predicated backedge-taken count.
+;
+bb:
+  br label %loop
+
+loop:
+  %iv.0 = phi i4 [ 1, %bb ], [ %iv.0.next, %loop ]
+  %iv.1 = phi i4 [ 1, %bb ], [ %iv.1.next, %loop ]
+  %iv.1.next = add nsw i4 %iv.1, 1
+  call void @use(i4 %iv.1.next)
+  %iv.0.next = add nsw i4 %iv.0, 1
+  call void @use(i4 %iv.0.next)
+  %.not.not = icmp ult i4 %iv.0, %arg
+  br i1 %.not.not, label %exit, label %loop
+
+exit:
+  ret i4 %iv.1.next
+}
+
+define i4 @iv_nsw_poison_extra_use(i4 %0, i4 %end, i4 %start) {
+; CHECK-LABEL: 'iv_nsw_poison_extra_use'
+; CHECK-NEXT:  Classifying expressions for: @iv_nsw_poison_extra_use
+; CHECK-NEXT:    %iv.0 = phi i4 [ %start, %entry ], [ %iv.0.next, %loop ]
+; CHECK-NEXT:    --> {%start,+,1}<%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:    %iv.1 = phi i4 [ %start, %entry ], [ %iv.1.next, %loop ]
+; CHECK-NEXT:    --> {%start,+,1}<nsw><%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:    %iv.0.next = add i4 %iv.0, 1
+; CHECK-NEXT:    --> {(1 + %start),+,1}<nw><%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:    %iv.1.next = add nsw i4 %iv.1, 1
+; CHECK-NEXT:    --> {(1 + %start),+,1}<nw><%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:  Determining loop execution counts for: @iv_nsw_poison_extra_use
+; CHECK-NEXT:  Loop %loop: Unpredictable backedge-taken count.
+; CHECK-NEXT:  Loop %loop: Unpredictable constant max backedge-taken count.
+; CHECK-NEXT:  Loop %loop: Unpredictable symbolic max backedge-taken count.
+; CHECK-NEXT:  Loop %loop: Unpredictable predicated backedge-taken count.
+;
+entry:
+  br label %loop
+
+loop:
+  %iv.0 = phi i4 [ %start, %entry ], [ %iv.0.next, %loop ]
+  %iv.1 = phi i4 [ %start, %entry ], [ %iv.1.next, %loop ]
+  %iv.0.next = add i4 %iv.0, 1
+  call void @use(i4 %iv.0.next)
+  %iv.1.next = add nsw i4 %iv.1, 1
+  %.not.not = icmp ult i4 %iv.0, %end
+  br i1 %.not.not, label %exit, label %loop
+
+exit:
+  ret i4 %iv.1.next
+}
+
+declare void @use(i4)
+
+define i2 @iv_nuw_poison(i2 %arg, i2 %start) {
+; CHECK-LABEL: 'iv_nuw_poison'
+; CHECK-NEXT:  Classifying expressions for: @iv_nuw_poison
+; CHECK-NEXT:    %.07 = phi i2 [ %start, %bb ], [ %i, %bb1 ]
+; CHECK-NEXT:    --> {%start,+,1}<nuw><%bb1> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %bb1: Computable }
+; CHECK-NEXT:    %.0 = phi i2 [ %start, %bb ], [ %i2, %bb1 ]
+; CHECK-NEXT:    --> {%start,+,1}<nuw><%bb1> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %bb1: Computable }
+; CHECK-NEXT:    %i = add nuw i2 %.07, 1
+; CHECK-NEXT:    --> {(1 + %start),+,1}<nw><%bb1> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %bb1: Computable }
+; CHECK-NEXT:    %i2 = add i2 %.0, 1
+; CHECK-NEXT:    --> {(1 + %start),+,1}<nw><%bb1> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %bb1: Computable }
+; CHECK-NEXT:  Determining loop execution counts for: @iv_nuw_poison
+; CHECK-NEXT:  Loop %bb1: Unpredictable backedge-taken count.
+; CHECK-NEXT:  Loop %bb1: Unpredictable constant max backedge-taken count.
+; CHECK-NEXT:  Loop %bb1: Unpredictable symbolic max backedge-taken count.
+; CHECK-NEXT:  Loop %bb1: Unpredictable predicated backedge-taken count.
+;
+bb:
+  br label %bb1
+
+bb1:                                              ; preds = %bb1, %bb
+  %.07 = phi i2 [ %start, %bb ], [ %i, %bb1 ]
+  %.0 = phi i2 [ %start, %bb ], [ %i2, %bb1 ]
+  %i = add nuw i2 %.07, 1
+  %i2 = add i2 %.0, 1
+  %.not.not = icmp ult i2 %.07, %arg
+  br i1 %.not.not, label %common.ret, label %bb1
+
+common.ret:                                       ; preds = %bb1
+  ret i2 %i2
+}
+
+define i4 @iv_nuw_poison2(i4 %0, i4 %end, i4 %start) {
+; CHECK-LABEL: 'iv_nuw_poison2'
+; CHECK-NEXT:  Classifying expressions for: @iv_nuw_poison2
+; CHECK-NEXT:    %iv.0 = phi i4 [ %start, %entry ], [ %iv.0.next, %loop ]
+; CHECK-NEXT:    --> {%start,+,1}<%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:    %iv.1 = phi i4 [ %start, %entry ], [ %iv.1.next, %loop ]
+; CHECK-NEXT:    --> {%start,+,1}<nuw><%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:    %iv.0.next = add i4 %iv.0, 1
+; CHECK-NEXT:    --> {(1 + %start),+,1}<nw><%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:    %iv.1.next = add nuw i4 %iv.1, 1
+; CHECK-NEXT:    --> {(1 + %start),+,1}<nw><%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:  Determining loop execution counts for: @iv_nuw_poison2
+; CHECK-NEXT:  Loop %loop: Unpredictable backedge-taken count.
+; CHECK-NEXT:  Loop %loop: Unpredictable constant max backedge-taken count.
+; CHECK-NEXT:  Loop %loop: Unpredictable symbolic max backedge-taken count.
+; CHECK-NEXT:  Loop %loop: Unpredictable predicated backedge-taken count.
+;
+entry:
+  br label %loop
+
+loop:
+  %iv.0 = phi i4 [ %start, %entry ], [ %iv.0.next, %loop ]
+  %iv.1 = phi i4 [ %start, %entry ], [ %iv.1.next, %loop ]
+  %iv.0.next = add i4 %iv.0, 1
+  %iv.1.next = add nuw i4 %iv.1, 1
+  %.not.not = icmp ult i4 %iv.0, %end
+  br i1 %.not.not, label %exit, label %loop
+
+exit:
+  ret i4 %iv.1.next
+}
+
+define i2 @iv_both_adds_nuw(i2 %arg, i2 %start) {
+; CHECK-LABEL: 'iv_both_adds_nuw'
+; CHECK-NEXT:  Classifying expressions for: @iv_both_adds_nuw
+; CHECK-NEXT:    %iv.0 = phi i2 [ %start, %bb ], [ %iv.0.next, %loop ]
+; CHECK-NEXT:    --> {%start,+,1}<nuw><%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:    %iv.1 = phi i2 [ %start, %bb ], [ %iv.1.next, %loop ]
+; CHECK-NEXT:    --> {%start,+,1}<nuw><%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:    %iv.0.next = add nuw i2 %iv.0, 1
+; CHECK-NEXT:    --> {(1 + %start),+,1}<nw><%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:    %iv.1.next = add nuw i2 %iv.1, 1
+; CHECK-NEXT:    --> {(1 + %start),+,1}<nw><%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:  Determining loop execution counts for: @iv_both_adds_nuw
+; CHECK-NEXT:  Loop %loop: Unpredictable backedge-taken count.
+; CHECK-NEXT:  Loop %loop: Unpredictable constant max backedge-taken count.
+; CHECK-NEXT:  Loop %loop: Unpredictable symbolic max backedge-taken count.
+; CHECK-NEXT:  Loop %loop: Unpredictable predicated backedge-taken count.
+;
+bb:
+  br label %loop
+
+loop:
+  %iv.0 = phi i2 [ %start, %bb ], [ %iv.0.next, %loop ]
+  %iv.1 = phi i2 [ %start, %bb ], [ %iv.1.next, %loop ]
+  %iv.0.next = add nuw i2 %iv.0, 1
+  %iv.1.next = add nuw i2 %iv.1, 1
+  %.not.not = icmp ult i2 %iv.0, %arg
+  br i1 %.not.not, label %exit, label %loop
+
+exit:
+  ret i2 %iv.1.next
+}
+
+define i4 @iv_both_adds_nuw_extra_use(i4 %arg, i4 %start) {
+; CHECK-LABEL: 'iv_both_adds_nuw_extra_use'
+; CHECK-NEXT:  Classifying expressions for: @iv_both_adds_nuw_extra_use
+; CHECK-NEXT:    %iv.0 = phi i4 [ %start, %bb ], [ %iv.0.next, %loop ]
+; CHECK-NEXT:    --> {%start,+,1}<nuw><%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:    %iv.1 = phi i4 [ %start, %bb ], [ %iv.1.next, %loop ]
+; CHECK-NEXT:    --> {%start,+,1}<nuw><%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:    %iv.0.next = add nuw i4 %iv.0, 1
+; CHECK-NEXT:    --> {(1 + %start),+,1}<nw><%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:    %iv.1.next = add nuw i4 %iv.1, 1
+; CHECK-NEXT:    --> {(1 + %start),+,1}<nw><%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:  Determining loop execution counts for: @iv_both_adds_nuw_extra_use
+; CHECK-NEXT:  Loop %loop: Unpredictable backedge-taken count.
+; CHECK-NEXT:  Loop %loop: Unpredictable constant max backedge-taken count.
+; CHECK-NEXT:  Loop %loop: Unpredictable symbolic max backedge-taken count.
+; CHECK-NEXT:  Loop %loop: Unpredictable predicated backedge-taken count.
+;
+bb:
+  br label %loop
+
+loop:
+  %iv.0 = phi i4 [ %start, %bb ], [ %iv.0.next, %loop ]
+  %iv.1 = phi i4 [ %start, %bb ], [ %iv.1.next, %loop ]
+  %iv.0.next = add nuw i4 %iv.0, 1
+  call void @use(i4 %iv.0.next)
+  %iv.1.next = add nuw i4 %iv.1, 1
+  call void @use(i4 %iv.1.next)
+  %.not.not = icmp ult i4 %iv.0, %arg
+  br i1 %.not.not, label %exit, label %loop
+
+exit:
+  ret i4 %iv.1.next
+}
+
+define i4 @iv_both_adds_nuw_extra_use_incs_reordered(i4 %arg, i4 %start) {
+; CHECK-LABEL: 'iv_both_adds_nuw_extra_use_incs_reordered'
+; CHECK-NEXT:  Classifying expressions for: @iv_both_adds_nuw_extra_use_incs_reordered
+; CHECK-NEXT:    %iv.0 = phi i4 [ %start, %bb ], [ %iv.0.next, %loop ]
+; CHECK-NEXT:    --> {%start,+,1}<nuw><%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:    %iv.1 = phi i4 [ %start, %bb ], [ %iv.1.next, %loop ]
+; CHECK-NEXT:    --> {%start,+,1}<nuw><%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:    %iv.1.next = add nuw i4 %iv.1, 1
+; CHECK-NEXT:    --> {(1 + %start),+,1}<nw><%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:    %iv.0.next = add nuw i4 %iv.0, 1
+; CHECK-NEXT:    --> {(1 + %start),+,1}<nw><%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:  Determining loop execution counts for: @iv_both_adds_nuw_extra_use_incs_reordered
+; CHECK-NEXT:  Loop %loop: Unpredictable backedge-taken count.
+; CHECK-NEXT:  Loop %loop: Unpredictable constant max backedge-taken count.
+; CHECK-NEXT:  Loop %loop: Unpredictable symbolic max backedge-taken count.
+; CHECK-NEXT:  Loop %loop: Unpredictable predicated backedge-taken count.
+;
+bb:
+  br label %loop
+
+loop:
+  %iv.0 = phi i4 [ %start, %bb ], [ %iv.0.next, %loop ]
+  %iv.1 = phi i4 [ %start, %bb ], [ %iv.1.next, %loop ]
+  %iv.1.next = add nuw i4 %iv.1, 1
+  call void @use(i4 %iv.1.next)
+  %iv.0.next = add nuw i4 %iv.0, 1
+  call void @use(i4 %iv.0.next)
+  %.not.not = icmp ult i4 %iv.0, %arg
+  br i1 %.not.not, label %exit, label %loop
+
+exit:
+  ret i4 %iv.1.next
+}
+
+define i4 @iv_nuw_poison_extra_use(i4 %0, i4 %end, i4 %start) {
+; CHECK-LABEL: 'iv_nuw_poison_extra_use'
+; CHECK-NEXT:  Classifying expressions for: @iv_nuw_poison_extra_use
+; CHECK-NEXT:    %iv.0 = phi i4 [ %start, %entry ], [ %iv.0.next, %loop ]
+; CHECK-NEXT:    --> {%start,+,1}<%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:    %iv.1 = phi i4 [ %start, %entry ], [ %iv.1.next, %loop ]
+; CHECK-NEXT:    --> {%start,+,1}<nuw><%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:    %iv.0.next = add i4 %iv.0, 1
+; CHECK-NEXT:    --> {(1 + %start),+,1}<nw><%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:    %iv.1.next = add nuw i4 %iv.1, 1
+; CHECK-NEXT:    --> {(1 + %start),+,1}<nw><%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:  Determining loop execution counts for: @iv_nuw_poison_extra_use
+; CHECK-NEXT:  Loop %loop: Unpredictable backedge-taken count.
+; CHECK-NEXT:  Loop %loop: Unpredictable constant max backedge-taken count.
+; CHECK-NEXT:  Loop %loop: Unpredictable symbolic max backedge-taken count.
+; CHECK-NEXT:  Loop %loop: Unpredictable predicated backedge-taken count.
+;
+entry:
+  br label %loop
+
+loop:
+  %iv.0 = phi i4 [ %start, %entry ], [ %iv.0.next, %loop ]
+  %iv.1 = phi i4 [ %start, %entry ], [ %iv.1.next, %loop ]
+  %iv.0.next = add i4 %iv.0, 1
+  call void @use(i4 %iv.0.next)
+  %iv.1.next = add nuw i4 %iv.1, 1
+  %.not.not = icmp ult i4 %iv.0, %end
+  br i1 %.not.not, label %exit, label %loop
+
+exit:
+  ret i4 %iv.1.next
+}

>From cad0558e0a4f1870df1ab7ac870fb4cff081d7d0 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Fri, 2 Feb 2024 12:52:38 +0000
Subject: [PATCH 2/3] [SCEV] Restrict wrap flags when construction same AR for
 multiple phis.

When constructing AddRecs from multiple equivalent phi nodes modulo
increment wrap flags, the resulting AddRec has the union of all
increment wrap flags as no-wrap flags.

This seems incorrect: uses of this AddRec are more poisonous in contexts
where an original phi node didn't have an increment with wrap flags.

This patch tries to ensures that the wrap flags for the constructed
AddRecs are valid for all phis that get mapped to an AddRec. To do so,
first check if there's already an existing AddRec. In that case, the
available wrap-flags are an upper bound on the wrap-flags; additional
wrap flags may make existing uses more poisonous.

If the AddRec can never be poison, it should still be safe to use the
full IR flags from IR.

Note the change in @iv_hoist_nuw_poison_extra_use fixes a mis-compile
found by Alive2.
---
 llvm/include/llvm/Analysis/ScalarEvolution.h  | 11 +++-
 .../Analysis/ScalarEvolutionExpressions.h     |  4 ++
 llvm/lib/Analysis/ScalarEvolution.cpp         | 54 ++++++++++++++++---
 .../Analysis/ScalarEvolution/iv-poison.ll     | 32 +++++------
 .../Transforms/IndVarSimplify/iv-poison.ll    |  2 +-
 .../X86/expander-crashes.ll                   |  2 +-
 6 files changed, 78 insertions(+), 27 deletions(-)

diff --git a/llvm/include/llvm/Analysis/ScalarEvolution.h b/llvm/include/llvm/Analysis/ScalarEvolution.h
index af3ad822e0b0d..2cad21b8b2a4f 100644
--- a/llvm/include/llvm/Analysis/ScalarEvolution.h
+++ b/llvm/include/llvm/Analysis/ScalarEvolution.h
@@ -563,6 +563,11 @@ class ScalarEvolution {
   /// Return an existing SCEV for V if there is one, otherwise return nullptr.
   const SCEV *getExistingSCEV(Value *V);
 
+  /// Return the AddRec for \p Ops and \p L if there is one, otherwise return
+  /// nullptr.
+  const SCEVAddRecExpr *getExistingAddRecExpr(ArrayRef<const SCEV *> Ops,
+                                              const Loop *L);
+
   const SCEV *getConstant(ConstantInt *V);
   const SCEV *getConstant(const APInt &Val);
   const SCEV *getConstant(Type *Ty, uint64_t V, bool isSigned = false);
@@ -2124,8 +2129,10 @@ class ScalarEvolution {
   /// This is like \c isSCEVExprNeverPoison but it specifically works for
   /// instructions that will get mapped to SCEV add recurrences.  Return true
   /// if \p I will never generate poison under the assumption that \p I is an
-  /// add recurrence on the loop \p L.
-  bool isAddRecNeverPoison(const Instruction *I, const Loop *L);
+  /// add recurrence on the loop \p L. Don't call \c isSCEVExprNeverPoison if \p
+  /// CheckSCEVScope is false.
+  bool isAddRecNeverPoison(const Instruction *I, const Loop *L,
+                           bool CheckSCEVScope = true);
 
   /// Similar to createAddRecFromPHI, but with the additional flexibility of
   /// suggesting runtime overflow checks in case casts are encountered.
diff --git a/llvm/include/llvm/Analysis/ScalarEvolutionExpressions.h b/llvm/include/llvm/Analysis/ScalarEvolutionExpressions.h
index fd884f2a2f55b..fcfcb1c5af879 100644
--- a/llvm/include/llvm/Analysis/ScalarEvolutionExpressions.h
+++ b/llvm/include/llvm/Analysis/ScalarEvolutionExpressions.h
@@ -392,6 +392,10 @@ class SCEVAddRecExpr : public SCEVNAryExpr {
     SubclassData |= Flags;
   }
 
+  /// Set the flags for the recurrence to \p Flags. This overwrites any existing
+  /// flags.
+  void forceSetNoWrapFlags(NoWrapFlags Flags) { SubclassData = Flags; }
+
   /// Return the value of this chain of recurrences at the specified
   /// iteration number.
   const SCEV *evaluateAtIteration(const SCEV *It, ScalarEvolution &SE) const;
diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index 2acb45837c480..e87770e064f8a 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -4520,6 +4520,18 @@ const SCEV *ScalarEvolution::getExistingSCEV(Value *V) {
   return nullptr;
 }
 
+const SCEVAddRecExpr *
+ScalarEvolution::getExistingAddRecExpr(ArrayRef<const SCEV *> Ops,
+                                       const Loop *L) {
+  FoldingSetNodeID ID;
+  ID.AddInteger(scAddRecExpr);
+  for (const SCEV *Op : Ops)
+    ID.AddPointer(Op);
+  ID.AddPointer(L);
+  void *IP = nullptr;
+  return static_cast<SCEVAddRecExpr *>(UniqueSCEVs.FindNodeOrInsertPos(ID, IP));
+}
+
 /// Return a SCEV corresponding to -V = -1*V
 const SCEV *ScalarEvolution::getNegativeSCEV(const SCEV *V,
                                              SCEV::NoWrapFlags Flags) {
@@ -5703,19 +5715,46 @@ const SCEV *ScalarEvolution::createSimpleAffineAddRec(PHINode *PN,
     return nullptr;
 
   SCEV::NoWrapFlags Flags = SCEV::FlagAnyWrap;
-  if (BO->IsNUW)
+  if (BO->IsNUW) {
     Flags = setFlags(Flags, SCEV::FlagNUW);
-  if (BO->IsNSW)
+    Flags = setFlags(Flags, SCEV::FlagNW);
+  }
+  if (BO->IsNSW) {
     Flags = setFlags(Flags, SCEV::FlagNSW);
+    Flags = setFlags(Flags, SCEV::FlagNW);
+  }
 
   const SCEV *StartVal = getSCEV(StartValueV);
+  SCEV::NoWrapFlags MinFlags = Flags;
+  auto *ExistingAR = getExistingAddRecExpr({StartVal, Accum}, L);
+  // If there's already an AddRec, use its flags to compute the minimal valid
+  // flags that hold for the users of the existing AddRec and the users of the
+  // current phi we are constructing an AddRec for.
+  if (ExistingAR)
+    MinFlags = maskFlags(ExistingAR->getNoWrapFlags(), Flags);
+
   const SCEV *PHISCEV = getAddRecExpr(StartVal, Accum, L, Flags);
   insertValueToMap(PN, PHISCEV);
 
+  // Check if the AddRec can never be poison, but avoid constructing new SCEVs
+  // for PN's operands, as this would instantiate the SCEV for the increment
+  // earlier.
+  bool NeverPoison = isAddRecNeverPoison(PN, L, false);
+  // If the AddRec is never poison, it is safe the use the flags from the IR
+  // unconditionally. But if it may be poison,  force the AddRec's flags to the
+  // minimum valid set for both the existing AddRec and the current context.
+  if (!NeverPoison && ExistingAR) {
+    const_cast<SCEVAddRecExpr *>(ExistingAR)->forceSetNoWrapFlags(MinFlags);
+    UnsignedRanges.erase(ExistingAR);
+    SignedRanges.erase(ExistingAR);
+    ConstantMultipleCache.erase(ExistingAR);
+  }
+
   if (auto *AR = dyn_cast<SCEVAddRecExpr>(PHISCEV)) {
-    setNoWrapFlags(const_cast<SCEVAddRecExpr *>(AR),
-                   (SCEV::NoWrapFlags)(AR->getNoWrapFlags() |
-                                       proveNoWrapViaConstantRanges(AR)));
+    SCEV::NoWrapFlags FlagsViaConstantRanges = proveNoWrapViaConstantRanges(AR);
+    setNoWrapFlags(
+        const_cast<SCEVAddRecExpr *>(AR),
+        (SCEV::NoWrapFlags)(AR->getNoWrapFlags() | FlagsViaConstantRanges));
   }
 
   // We can add Flags to the post-inc expression only if we
@@ -7269,9 +7308,10 @@ bool ScalarEvolution::isSCEVExprNeverPoison(const Instruction *I) {
   return isGuaranteedToTransferExecutionTo(DefI, I);
 }
 
-bool ScalarEvolution::isAddRecNeverPoison(const Instruction *I, const Loop *L) {
+bool ScalarEvolution::isAddRecNeverPoison(const Instruction *I, const Loop *L,
+                                          bool CheckSCEVScope) {
   // If we know that \c I can never be poison period, then that's enough.
-  if (isSCEVExprNeverPoison(I))
+  if (CheckSCEVScope && isSCEVExprNeverPoison(I))
     return true;
 
   // If the loop only has one exit, then we know that, if the loop is entered,
diff --git a/llvm/test/Analysis/ScalarEvolution/iv-poison.ll b/llvm/test/Analysis/ScalarEvolution/iv-poison.ll
index 771a93f79cb11..03fa233930cdf 100644
--- a/llvm/test/Analysis/ScalarEvolution/iv-poison.ll
+++ b/llvm/test/Analysis/ScalarEvolution/iv-poison.ll
@@ -8,7 +8,7 @@ define i2 @iv_nsw_poison(i2 %arg) {
 ; CHECK-NEXT:    %.07 = phi i2 [ 1, %bb ], [ %i, %bb1 ]
 ; CHECK-NEXT:    --> {1,+,1}<nuw><nsw><%bb1> U: [1,-2) S: [1,-2) Exits: <<Unknown>> LoopDispositions: { %bb1: Computable }
 ; CHECK-NEXT:    %.0 = phi i2 [ 1, %bb ], [ %i2, %bb1 ]
-; CHECK-NEXT:    --> {1,+,1}<nuw><nsw><%bb1> U: [1,-2) S: [1,-2) Exits: <<Unknown>> LoopDispositions: { %bb1: Computable }
+; CHECK-NEXT:    --> {1,+,1}<%bb1> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %bb1: Computable }
 ; CHECK-NEXT:    %i = add nsw i2 %.07, 1
 ; CHECK-NEXT:    --> {-2,+,1}<nuw><%bb1> U: [-2,0) S: [-2,0) Exits: <<Unknown>> LoopDispositions: { %bb1: Computable }
 ; CHECK-NEXT:    %i2 = add i2 %.0, 1
@@ -40,11 +40,11 @@ define i4 @iv_nsw_poison2(i4 %0, i4 %end, i4 %start) {
 ; CHECK-NEXT:    %iv.0 = phi i4 [ %start, %entry ], [ %iv.0.next, %loop ]
 ; CHECK-NEXT:    --> {%start,+,1}<%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
 ; CHECK-NEXT:    %iv.1 = phi i4 [ %start, %entry ], [ %iv.1.next, %loop ]
-; CHECK-NEXT:    --> {%start,+,1}<nsw><%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:    --> {%start,+,1}<%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
 ; CHECK-NEXT:    %iv.0.next = add i4 %iv.0, 1
-; CHECK-NEXT:    --> {(1 + %start),+,1}<nw><%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:    --> {(1 + %start),+,1}<%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
 ; CHECK-NEXT:    %iv.1.next = add nsw i4 %iv.1, 1
-; CHECK-NEXT:    --> {(1 + %start),+,1}<nw><%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:    --> {(1 + %start),+,1}<%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
 ; CHECK-NEXT:  Determining loop execution counts for: @iv_nsw_poison2
 ; CHECK-NEXT:  Loop %loop: Unpredictable backedge-taken count.
 ; CHECK-NEXT:  Loop %loop: Unpredictable constant max backedge-taken count.
@@ -172,11 +172,11 @@ define i4 @iv_nsw_poison_extra_use(i4 %0, i4 %end, i4 %start) {
 ; CHECK-NEXT:    %iv.0 = phi i4 [ %start, %entry ], [ %iv.0.next, %loop ]
 ; CHECK-NEXT:    --> {%start,+,1}<%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
 ; CHECK-NEXT:    %iv.1 = phi i4 [ %start, %entry ], [ %iv.1.next, %loop ]
-; CHECK-NEXT:    --> {%start,+,1}<nsw><%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:    --> {%start,+,1}<%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
 ; CHECK-NEXT:    %iv.0.next = add i4 %iv.0, 1
-; CHECK-NEXT:    --> {(1 + %start),+,1}<nw><%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:    --> {(1 + %start),+,1}<%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
 ; CHECK-NEXT:    %iv.1.next = add nsw i4 %iv.1, 1
-; CHECK-NEXT:    --> {(1 + %start),+,1}<nw><%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:    --> {(1 + %start),+,1}<%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
 ; CHECK-NEXT:  Determining loop execution counts for: @iv_nsw_poison_extra_use
 ; CHECK-NEXT:  Loop %loop: Unpredictable backedge-taken count.
 ; CHECK-NEXT:  Loop %loop: Unpredictable constant max backedge-taken count.
@@ -207,11 +207,11 @@ define i2 @iv_nuw_poison(i2 %arg, i2 %start) {
 ; CHECK-NEXT:    %.07 = phi i2 [ %start, %bb ], [ %i, %bb1 ]
 ; CHECK-NEXT:    --> {%start,+,1}<nuw><%bb1> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %bb1: Computable }
 ; CHECK-NEXT:    %.0 = phi i2 [ %start, %bb ], [ %i2, %bb1 ]
-; CHECK-NEXT:    --> {%start,+,1}<nuw><%bb1> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %bb1: Computable }
+; CHECK-NEXT:    --> {%start,+,1}<%bb1> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %bb1: Computable }
 ; CHECK-NEXT:    %i = add nuw i2 %.07, 1
-; CHECK-NEXT:    --> {(1 + %start),+,1}<nw><%bb1> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %bb1: Computable }
+; CHECK-NEXT:    --> {(1 + %start),+,1}<%bb1> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %bb1: Computable }
 ; CHECK-NEXT:    %i2 = add i2 %.0, 1
-; CHECK-NEXT:    --> {(1 + %start),+,1}<nw><%bb1> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %bb1: Computable }
+; CHECK-NEXT:    --> {(1 + %start),+,1}<%bb1> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %bb1: Computable }
 ; CHECK-NEXT:  Determining loop execution counts for: @iv_nuw_poison
 ; CHECK-NEXT:  Loop %bb1: Unpredictable backedge-taken count.
 ; CHECK-NEXT:  Loop %bb1: Unpredictable constant max backedge-taken count.
@@ -239,11 +239,11 @@ define i4 @iv_nuw_poison2(i4 %0, i4 %end, i4 %start) {
 ; CHECK-NEXT:    %iv.0 = phi i4 [ %start, %entry ], [ %iv.0.next, %loop ]
 ; CHECK-NEXT:    --> {%start,+,1}<%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
 ; CHECK-NEXT:    %iv.1 = phi i4 [ %start, %entry ], [ %iv.1.next, %loop ]
-; CHECK-NEXT:    --> {%start,+,1}<nuw><%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:    --> {%start,+,1}<%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
 ; CHECK-NEXT:    %iv.0.next = add i4 %iv.0, 1
-; CHECK-NEXT:    --> {(1 + %start),+,1}<nw><%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:    --> {(1 + %start),+,1}<%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
 ; CHECK-NEXT:    %iv.1.next = add nuw i4 %iv.1, 1
-; CHECK-NEXT:    --> {(1 + %start),+,1}<nw><%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:    --> {(1 + %start),+,1}<%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
 ; CHECK-NEXT:  Determining loop execution counts for: @iv_nuw_poison2
 ; CHECK-NEXT:  Loop %loop: Unpredictable backedge-taken count.
 ; CHECK-NEXT:  Loop %loop: Unpredictable constant max backedge-taken count.
@@ -371,11 +371,11 @@ define i4 @iv_nuw_poison_extra_use(i4 %0, i4 %end, i4 %start) {
 ; CHECK-NEXT:    %iv.0 = phi i4 [ %start, %entry ], [ %iv.0.next, %loop ]
 ; CHECK-NEXT:    --> {%start,+,1}<%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
 ; CHECK-NEXT:    %iv.1 = phi i4 [ %start, %entry ], [ %iv.1.next, %loop ]
-; CHECK-NEXT:    --> {%start,+,1}<nuw><%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:    --> {%start,+,1}<%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
 ; CHECK-NEXT:    %iv.0.next = add i4 %iv.0, 1
-; CHECK-NEXT:    --> {(1 + %start),+,1}<nw><%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:    --> {(1 + %start),+,1}<%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
 ; CHECK-NEXT:    %iv.1.next = add nuw i4 %iv.1, 1
-; CHECK-NEXT:    --> {(1 + %start),+,1}<nw><%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:    --> {(1 + %start),+,1}<%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
 ; CHECK-NEXT:  Determining loop execution counts for: @iv_nuw_poison_extra_use
 ; CHECK-NEXT:  Loop %loop: Unpredictable backedge-taken count.
 ; CHECK-NEXT:  Loop %loop: Unpredictable constant max backedge-taken count.
diff --git a/llvm/test/Transforms/IndVarSimplify/iv-poison.ll b/llvm/test/Transforms/IndVarSimplify/iv-poison.ll
index 383599f614357..9acffea5669d7 100644
--- a/llvm/test/Transforms/IndVarSimplify/iv-poison.ll
+++ b/llvm/test/Transforms/IndVarSimplify/iv-poison.ll
@@ -338,7 +338,7 @@ define i4 @iv_hoist_nuw_poison_extra_use(i4 %0, i4 %end, i4 %start) {
 ; CHECK-NEXT:    [[IV_0:%.*]] = phi i4 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_0_NEXT:%.*]], [[LOOP]] ]
 ; CHECK-NEXT:    [[IV_0_NEXT]] = add i4 [[IV_0]], 1
 ; CHECK-NEXT:    call void @use(i4 [[IV_0_NEXT]])
-; CHECK-NEXT:    [[DOTNOT_NOT:%.*]] = icmp ult i4 [[START]], [[END:%.*]]
+; CHECK-NEXT:    [[DOTNOT_NOT:%.*]] = icmp ult i4 [[IV_0]], [[END:%.*]]
 ; CHECK-NEXT:    br i1 [[DOTNOT_NOT]], label [[EXIT:%.*]], label [[LOOP]]
 ; CHECK:       exit:
 ; CHECK-NEXT:    [[IV_1_NEXT_LCSSA:%.*]] = phi i4 [ [[IV_0_NEXT]], [[LOOP]] ]
diff --git a/llvm/test/Transforms/LoopStrengthReduce/X86/expander-crashes.ll b/llvm/test/Transforms/LoopStrengthReduce/X86/expander-crashes.ll
index 29c03b88c5fb1..9b6d7041aa8c2 100644
--- a/llvm/test/Transforms/LoopStrengthReduce/X86/expander-crashes.ll
+++ b/llvm/test/Transforms/LoopStrengthReduce/X86/expander-crashes.ll
@@ -17,7 +17,7 @@ define i64 @blam(ptr %start, ptr %end, ptr %ptr.2) {
 ; CHECK-NEXT:    [[LSR_IV4:%.*]] = phi i64 [ [[LSR_IV_NEXT5:%.*]], [[LOOP_1_HEADER]] ], [ [[START1]], [[ENTRY:%.*]] ]
 ; CHECK-NEXT:    [[IV:%.*]] = phi ptr [ [[IV_NEXT:%.*]], [[LOOP_1_HEADER]] ], [ [[START]], [[ENTRY]] ]
 ; CHECK-NEXT:    [[IV_NEXT]] = getelementptr inbounds [[STRUCT_HOGE:%.*]], ptr [[IV]], i64 1
-; CHECK-NEXT:    [[LSR_IV_NEXT5]] = add nuw i64 [[LSR_IV4]], 16
+; CHECK-NEXT:    [[LSR_IV_NEXT5]] = add i64 [[LSR_IV4]], 16
 ; CHECK-NEXT:    [[EC:%.*]] = icmp eq ptr [[IV_NEXT]], [[END:%.*]]
 ; CHECK-NEXT:    br i1 [[EC]], label [[LOOP_2_PH:%.*]], label [[LOOP_1_HEADER]]
 ; CHECK:       loop.2.ph:

>From 35652640034d20be2a3b7dde9c54e656280491e6 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Fri, 2 Feb 2024 14:26:11 +0000
Subject: [PATCH 3/3] !fixup invalidate expressions based on PHISCEV.

---
 llvm/lib/Analysis/ScalarEvolution.cpp         |  8 +++----
 .../Analysis/ScalarEvolution/iv-poison.ll     |  4 ++--
 .../IndVarSimplify/AArch64/widen-loop-comp.ll | 24 +++++++++----------
 3 files changed, 18 insertions(+), 18 deletions(-)

diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index e87770e064f8a..660d555875da6 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -5734,7 +5734,6 @@ const SCEV *ScalarEvolution::createSimpleAffineAddRec(PHINode *PN,
     MinFlags = maskFlags(ExistingAR->getNoWrapFlags(), Flags);
 
   const SCEV *PHISCEV = getAddRecExpr(StartVal, Accum, L, Flags);
-  insertValueToMap(PN, PHISCEV);
 
   // Check if the AddRec can never be poison, but avoid constructing new SCEVs
   // for PN's operands, as this would instantiate the SCEV for the increment
@@ -5744,12 +5743,13 @@ const SCEV *ScalarEvolution::createSimpleAffineAddRec(PHINode *PN,
   // unconditionally. But if it may be poison,  force the AddRec's flags to the
   // minimum valid set for both the existing AddRec and the current context.
   if (!NeverPoison && ExistingAR) {
+    forgetMemoizedResults(PHISCEV);
+    PHISCEV = getAddRecExpr(StartVal, Accum, L, MinFlags);
     const_cast<SCEVAddRecExpr *>(ExistingAR)->forceSetNoWrapFlags(MinFlags);
-    UnsignedRanges.erase(ExistingAR);
-    SignedRanges.erase(ExistingAR);
-    ConstantMultipleCache.erase(ExistingAR);
   }
 
+  insertValueToMap(PN, PHISCEV);
+
   if (auto *AR = dyn_cast<SCEVAddRecExpr>(PHISCEV)) {
     SCEV::NoWrapFlags FlagsViaConstantRanges = proveNoWrapViaConstantRanges(AR);
     setNoWrapFlags(
diff --git a/llvm/test/Analysis/ScalarEvolution/iv-poison.ll b/llvm/test/Analysis/ScalarEvolution/iv-poison.ll
index 03fa233930cdf..e4da99e16a20a 100644
--- a/llvm/test/Analysis/ScalarEvolution/iv-poison.ll
+++ b/llvm/test/Analysis/ScalarEvolution/iv-poison.ll
@@ -209,9 +209,9 @@ define i2 @iv_nuw_poison(i2 %arg, i2 %start) {
 ; CHECK-NEXT:    %.0 = phi i2 [ %start, %bb ], [ %i2, %bb1 ]
 ; CHECK-NEXT:    --> {%start,+,1}<%bb1> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %bb1: Computable }
 ; CHECK-NEXT:    %i = add nuw i2 %.07, 1
-; CHECK-NEXT:    --> {(1 + %start),+,1}<%bb1> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %bb1: Computable }
+; CHECK-NEXT:    --> {(1 + %start),+,1}<nw><%bb1> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %bb1: Computable }
 ; CHECK-NEXT:    %i2 = add i2 %.0, 1
-; CHECK-NEXT:    --> {(1 + %start),+,1}<%bb1> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %bb1: Computable }
+; CHECK-NEXT:    --> {(1 + %start),+,1}<nw><%bb1> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %bb1: Computable }
 ; CHECK-NEXT:  Determining loop execution counts for: @iv_nuw_poison
 ; CHECK-NEXT:  Loop %bb1: Unpredictable backedge-taken count.
 ; CHECK-NEXT:  Loop %bb1: Unpredictable constant max backedge-taken count.
diff --git a/llvm/test/Transforms/IndVarSimplify/AArch64/widen-loop-comp.ll b/llvm/test/Transforms/IndVarSimplify/AArch64/widen-loop-comp.ll
index 6f659a88da2e2..0a2199b6efef4 100644
--- a/llvm/test/Transforms/IndVarSimplify/AArch64/widen-loop-comp.ll
+++ b/llvm/test/Transforms/IndVarSimplify/AArch64/widen-loop-comp.ll
@@ -928,27 +928,27 @@ define i32 @test16_unsigned_pos2(i32 %start, ptr %p, ptr %q, i32 %x) {
 ; CHECK:       loop:
 ; CHECK-NEXT:    [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], [[BACKEDGE:%.*]] ], [ [[TMP0]], [[ENTRY:%.*]] ]
 ; CHECK-NEXT:    [[COND:%.*]] = icmp eq i64 [[INDVARS_IV]], 0
-; CHECK-NEXT:    [[TMP1:%.*]] = add nsw i64 [[INDVARS_IV]], -1
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc i64 [[INDVARS_IV]] to i32
+; CHECK-NEXT:    [[FOO:%.*]] = add i32 [[TMP1]], -1
 ; CHECK-NEXT:    br i1 [[COND]], label [[EXIT:%.*]], label [[GUARDED:%.*]]
 ; CHECK:       guarded:
-; CHECK-NEXT:    [[TMP2:%.*]] = zext i32 [[X:%.*]] to i64
-; CHECK-NEXT:    [[ICMP_USER_WIDE:%.*]] = icmp ne i64 [[TMP1]], [[TMP2]]
-; CHECK-NEXT:    br i1 [[ICMP_USER_WIDE]], label [[BACKEDGE]], label [[SIDE_EXIT:%.*]]
+; CHECK-NEXT:    [[ICMP_USER:%.*]] = icmp ne i32 [[FOO]], [[X:%.*]]
+; CHECK-NEXT:    br i1 [[ICMP_USER]], label [[BACKEDGE]], label [[SIDE_EXIT:%.*]]
 ; CHECK:       backedge:
-; CHECK-NEXT:    [[STORE_ADDR:%.*]] = getelementptr i32, ptr [[P:%.*]], i64 [[TMP1]]
+; CHECK-NEXT:    [[INDEX:%.*]] = zext i32 [[FOO]] to i64
+; CHECK-NEXT:    [[STORE_ADDR:%.*]] = getelementptr i32, ptr [[P:%.*]], i64 [[INDEX]]
 ; CHECK-NEXT:    store i32 1, ptr [[STORE_ADDR]], align 4
-; CHECK-NEXT:    [[STOP:%.*]] = load i32, ptr [[Q:%.*]], align 4
+; CHECK-NEXT:    [[LOAD_ADDR:%.*]] = getelementptr i32, ptr [[Q:%.*]], i64 [[INDEX]]
+; CHECK-NEXT:    [[STOP:%.*]] = load i32, ptr [[Q]], align 4
 ; CHECK-NEXT:    [[LOOP_COND:%.*]] = icmp eq i32 [[STOP]], 0
 ; CHECK-NEXT:    [[INDVARS_IV_NEXT]] = add nsw i64 [[INDVARS_IV]], -1
 ; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[LOOP]], label [[FAILURE:%.*]]
 ; CHECK:       exit:
-; CHECK-NEXT:    [[TMP3:%.*]] = trunc i64 -1 to i32
-; CHECK-NEXT:    call void @use(i32 [[TMP3]])
-; CHECK-NEXT:    ret i32 [[TMP3]]
+; CHECK-NEXT:    call void @use(i32 -1)
+; CHECK-NEXT:    ret i32 -1
 ; CHECK:       failure:
-; CHECK-NEXT:    [[FOO_LCSSA2_WIDE:%.*]] = phi i64 [ [[TMP1]], [[BACKEDGE]] ]
-; CHECK-NEXT:    [[TMP4:%.*]] = trunc i64 [[FOO_LCSSA2_WIDE]] to i32
-; CHECK-NEXT:    call void @use(i32 [[TMP4]])
+; CHECK-NEXT:    [[FOO_LCSSA2:%.*]] = phi i32 [ [[FOO]], [[BACKEDGE]] ]
+; CHECK-NEXT:    call void @use(i32 [[FOO_LCSSA2]])
 ; CHECK-NEXT:    unreachable
 ; CHECK:       side_exit:
 ; CHECK-NEXT:    ret i32 0



More information about the llvm-commits mailing list