[llvm-branch-commits] [llvm] [GVN] Simple GVN-based hoisting of scalars: precommit tests (NFC) (PR #210336)
Momchil Velikov via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Thu Jul 23 06:00:56 PDT 2026
https://github.com/momchil-velikov updated https://github.com/llvm/llvm-project/pull/210336
>From 91253eee35f08c690449c367ba4aeef9526322bb Mon Sep 17 00:00:00 2001
From: Momchil Velikov <momchil.velikov at arm.com>
Date: Fri, 10 Jul 2026 13:54:09 +0100
Subject: [PATCH] [GVN] Simple GVN-based hoisting of scalars: precommit tests
---
.../Transforms/GVN/simple-gvn-hoist-limits.ll | 155 +++++++
.../GVN/simple-gvn-hoist-scalars.ll | 382 ++++++++++++++++++
2 files changed, 537 insertions(+)
create mode 100644 llvm/test/Transforms/GVN/simple-gvn-hoist-limits.ll
create mode 100644 llvm/test/Transforms/GVN/simple-gvn-hoist-scalars.ll
diff --git a/llvm/test/Transforms/GVN/simple-gvn-hoist-limits.ll b/llvm/test/Transforms/GVN/simple-gvn-hoist-limits.ll
new file mode 100644
index 0000000000000..0c0789e6e4144
--- /dev/null
+++ b/llvm/test/Transforms/GVN/simple-gvn-hoist-limits.ll
@@ -0,0 +1,155 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S --passes=gvn --gvn-max-num-insns=3 %s -o - | FileCheck %s --check-prefix=MAX-DEPTH3
+; RUN: opt -S --passes=gvn --gvn-max-num-insns=4 %s -o - | FileCheck %s --check-prefix=MAX-DEPTH4
+; RUN: opt -S --passes=gvn --gvn-max-num-insns=5 %s -o - | FileCheck %s --check-prefix=MAX-DEPTH5
+
+; Check effect of limiting the how deep in a block we look for
+; instructions to hoist; At max depth 3 we shouldn't hoist
+; anything to the `entry` block, at max depth 4 we should hoist
+; the first `add` and at max depth 5 the second `add`.
+
+; In any case we shouldn't hoist the `and` and the `icmp`, in order
+; to not separate them from the `br`
+
+define i32 @f(i1 %c, i32 %a, i32 %b, i32 %d) {
+; MAX-DEPTH3-LABEL: @f(
+; MAX-DEPTH3-NEXT: entry:
+; MAX-DEPTH3-NEXT: br i1 [[C:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+; MAX-DEPTH3: if.then:
+; MAX-DEPTH3-NEXT: [[R0:%.*]] = add i32 [[B:%.*]], 1
+; MAX-DEPTH3-NEXT: [[AND0:%.*]] = and i32 [[A:%.*]], 1
+; MAX-DEPTH3-NEXT: [[TOBOOL_AND0:%.*]] = icmp eq i32 [[AND0]], 0
+; MAX-DEPTH3-NEXT: [[D0:%.*]] = add i32 [[D:%.*]], 1
+; MAX-DEPTH3-NEXT: [[S0:%.*]] = add i32 [[D0]], [[B]]
+; MAX-DEPTH3-NEXT: br i1 [[TOBOOL_AND0]], label [[IF_THEN1:%.*]], label [[IF_ELSE1:%.*]]
+; MAX-DEPTH3: if.then1:
+; MAX-DEPTH3-NEXT: [[OR0:%.*]] = or i32 [[R0]], 1
+; MAX-DEPTH3-NEXT: br label [[EXIT:%.*]]
+; MAX-DEPTH3: if.else1:
+; MAX-DEPTH3-NEXT: [[OR1:%.*]] = or i32 [[R0]], 2
+; MAX-DEPTH3-NEXT: br label [[EXIT]]
+; MAX-DEPTH3: if.else:
+; MAX-DEPTH3-NEXT: [[R1:%.*]] = add i32 [[B]], 2
+; MAX-DEPTH3-NEXT: [[AND1:%.*]] = and i32 [[A]], 1
+; MAX-DEPTH3-NEXT: [[TOBOOL_AND1:%.*]] = icmp eq i32 [[AND1]], 0
+; MAX-DEPTH3-NEXT: [[D1:%.*]] = add i32 [[D]], 1
+; MAX-DEPTH3-NEXT: [[S1:%.*]] = add i32 [[D1]], [[B]]
+; MAX-DEPTH3-NEXT: br i1 [[TOBOOL_AND1]], label [[IF_THEN2:%.*]], label [[IF_ELSE2:%.*]]
+; MAX-DEPTH3: if.then2:
+; MAX-DEPTH3-NEXT: [[OR2:%.*]] = or i32 [[R1]], 4
+; MAX-DEPTH3-NEXT: br label [[EXIT]]
+; MAX-DEPTH3: if.else2:
+; MAX-DEPTH3-NEXT: [[OR3:%.*]] = or i32 [[R1]], 8
+; MAX-DEPTH3-NEXT: br label [[EXIT]]
+; MAX-DEPTH3: exit:
+; MAX-DEPTH3-NEXT: [[OR:%.*]] = phi i32 [ [[OR0]], [[IF_THEN1]] ], [ [[OR1]], [[IF_ELSE1]] ], [ [[OR2]], [[IF_THEN2]] ], [ [[OR3]], [[IF_ELSE2]] ]
+; MAX-DEPTH3-NEXT: [[S:%.*]] = phi i32 [ [[S0]], [[IF_THEN1]] ], [ [[S0]], [[IF_ELSE1]] ], [ [[S1]], [[IF_THEN2]] ], [ [[S1]], [[IF_ELSE2]] ]
+; MAX-DEPTH3-NEXT: [[R:%.*]] = add i32 [[OR]], [[S]]
+; MAX-DEPTH3-NEXT: ret i32 [[R]]
+;
+; MAX-DEPTH4-LABEL: @f(
+; MAX-DEPTH4-NEXT: entry:
+; MAX-DEPTH4-NEXT: br i1 [[C:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+; MAX-DEPTH4: if.then:
+; MAX-DEPTH4-NEXT: [[R0:%.*]] = add i32 [[B:%.*]], 1
+; MAX-DEPTH4-NEXT: [[AND0:%.*]] = and i32 [[A:%.*]], 1
+; MAX-DEPTH4-NEXT: [[TOBOOL_AND0:%.*]] = icmp eq i32 [[AND0]], 0
+; MAX-DEPTH4-NEXT: [[D0:%.*]] = add i32 [[D:%.*]], 1
+; MAX-DEPTH4-NEXT: [[S0:%.*]] = add i32 [[D0]], [[B]]
+; MAX-DEPTH4-NEXT: br i1 [[TOBOOL_AND0]], label [[IF_THEN1:%.*]], label [[IF_ELSE1:%.*]]
+; MAX-DEPTH4: if.then1:
+; MAX-DEPTH4-NEXT: [[OR0:%.*]] = or i32 [[R0]], 1
+; MAX-DEPTH4-NEXT: br label [[EXIT:%.*]]
+; MAX-DEPTH4: if.else1:
+; MAX-DEPTH4-NEXT: [[OR1:%.*]] = or i32 [[R0]], 2
+; MAX-DEPTH4-NEXT: br label [[EXIT]]
+; MAX-DEPTH4: if.else:
+; MAX-DEPTH4-NEXT: [[R1:%.*]] = add i32 [[B]], 2
+; MAX-DEPTH4-NEXT: [[AND1:%.*]] = and i32 [[A]], 1
+; MAX-DEPTH4-NEXT: [[TOBOOL_AND1:%.*]] = icmp eq i32 [[AND1]], 0
+; MAX-DEPTH4-NEXT: [[D1:%.*]] = add i32 [[D]], 1
+; MAX-DEPTH4-NEXT: [[S1:%.*]] = add i32 [[D1]], [[B]]
+; MAX-DEPTH4-NEXT: br i1 [[TOBOOL_AND1]], label [[IF_THEN2:%.*]], label [[IF_ELSE2:%.*]]
+; MAX-DEPTH4: if.then2:
+; MAX-DEPTH4-NEXT: [[OR2:%.*]] = or i32 [[R1]], 4
+; MAX-DEPTH4-NEXT: br label [[EXIT]]
+; MAX-DEPTH4: if.else2:
+; MAX-DEPTH4-NEXT: [[OR3:%.*]] = or i32 [[R1]], 8
+; MAX-DEPTH4-NEXT: br label [[EXIT]]
+; MAX-DEPTH4: exit:
+; MAX-DEPTH4-NEXT: [[OR:%.*]] = phi i32 [ [[OR0]], [[IF_THEN1]] ], [ [[OR1]], [[IF_ELSE1]] ], [ [[OR2]], [[IF_THEN2]] ], [ [[OR3]], [[IF_ELSE2]] ]
+; MAX-DEPTH4-NEXT: [[S:%.*]] = phi i32 [ [[S0]], [[IF_THEN1]] ], [ [[S0]], [[IF_ELSE1]] ], [ [[S1]], [[IF_THEN2]] ], [ [[S1]], [[IF_ELSE2]] ]
+; MAX-DEPTH4-NEXT: [[R:%.*]] = add i32 [[OR]], [[S]]
+; MAX-DEPTH4-NEXT: ret i32 [[R]]
+;
+; MAX-DEPTH5-LABEL: @f(
+; MAX-DEPTH5-NEXT: entry:
+; MAX-DEPTH5-NEXT: br i1 [[C:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+; MAX-DEPTH5: if.then:
+; MAX-DEPTH5-NEXT: [[R0:%.*]] = add i32 [[B:%.*]], 1
+; MAX-DEPTH5-NEXT: [[AND0:%.*]] = and i32 [[A:%.*]], 1
+; MAX-DEPTH5-NEXT: [[TOBOOL_AND0:%.*]] = icmp eq i32 [[AND0]], 0
+; MAX-DEPTH5-NEXT: [[D0:%.*]] = add i32 [[D:%.*]], 1
+; MAX-DEPTH5-NEXT: [[S0:%.*]] = add i32 [[D0]], [[B]]
+; MAX-DEPTH5-NEXT: br i1 [[TOBOOL_AND0]], label [[IF_THEN1:%.*]], label [[IF_ELSE1:%.*]]
+; MAX-DEPTH5: if.then1:
+; MAX-DEPTH5-NEXT: [[OR0:%.*]] = or i32 [[R0]], 1
+; MAX-DEPTH5-NEXT: br label [[EXIT:%.*]]
+; MAX-DEPTH5: if.else1:
+; MAX-DEPTH5-NEXT: [[OR1:%.*]] = or i32 [[R0]], 2
+; MAX-DEPTH5-NEXT: br label [[EXIT]]
+; MAX-DEPTH5: if.else:
+; MAX-DEPTH5-NEXT: [[R1:%.*]] = add i32 [[B]], 2
+; MAX-DEPTH5-NEXT: [[AND1:%.*]] = and i32 [[A]], 1
+; MAX-DEPTH5-NEXT: [[TOBOOL_AND1:%.*]] = icmp eq i32 [[AND1]], 0
+; MAX-DEPTH5-NEXT: [[D1:%.*]] = add i32 [[D]], 1
+; MAX-DEPTH5-NEXT: [[S1:%.*]] = add i32 [[D1]], [[B]]
+; MAX-DEPTH5-NEXT: br i1 [[TOBOOL_AND1]], label [[IF_THEN2:%.*]], label [[IF_ELSE2:%.*]]
+; MAX-DEPTH5: if.then2:
+; MAX-DEPTH5-NEXT: [[OR2:%.*]] = or i32 [[R1]], 4
+; MAX-DEPTH5-NEXT: br label [[EXIT]]
+; MAX-DEPTH5: if.else2:
+; MAX-DEPTH5-NEXT: [[OR3:%.*]] = or i32 [[R1]], 8
+; MAX-DEPTH5-NEXT: br label [[EXIT]]
+; MAX-DEPTH5: exit:
+; MAX-DEPTH5-NEXT: [[OR:%.*]] = phi i32 [ [[OR0]], [[IF_THEN1]] ], [ [[OR1]], [[IF_ELSE1]] ], [ [[OR2]], [[IF_THEN2]] ], [ [[OR3]], [[IF_ELSE2]] ]
+; MAX-DEPTH5-NEXT: [[S:%.*]] = phi i32 [ [[S0]], [[IF_THEN1]] ], [ [[S0]], [[IF_ELSE1]] ], [ [[S1]], [[IF_THEN2]] ], [ [[S1]], [[IF_ELSE2]] ]
+; MAX-DEPTH5-NEXT: [[R:%.*]] = add i32 [[OR]], [[S]]
+; MAX-DEPTH5-NEXT: ret i32 [[R]]
+;
+entry:
+ br i1 %c, label %if.then, label %if.else
+
+if.then:
+ %r0 = add i32 %b, 1
+ %and0 = and i32 %a, 1
+ %tobool.and0 = icmp eq i32 %and0, 0
+ %d0 = add i32 %d, 1
+ %s0 = add i32 %d0, %b
+ br i1 %tobool.and0, label %if.then1, label %if.else1
+if.then1:
+ %or0 = or i32 %r0, 1
+ br label %exit
+if.else1:
+ %or1 = or i32 %r0, 2
+ br label %exit
+
+if.else:
+ %r1 = add i32 %b, 2
+ %and1 = and i32 %a, 1
+ %tobool.and1 = icmp eq i32 %and1, 0
+ %d1 = add i32 %d, 1
+ %s1 = add i32 %d1, %b
+ br i1 %tobool.and1, label %if.then2, label %if.else2
+if.then2:
+ %or2 = or i32 %r1, 4
+ br label %exit
+if.else2:
+ %or3 = or i32 %r1, 8
+ br label %exit
+exit:
+ %or = phi i32 [%or0, %if.then1], [%or1, %if.else1], [%or2, %if.then2], [%or3, %if.else2]
+ %s = phi i32 [%s0, %if.then1], [%s0, %if.else1], [%s1, %if.then2], [%s1, %if.else2]
+ %r = add i32 %or, %s
+ ret i32 %r
+}
diff --git a/llvm/test/Transforms/GVN/simple-gvn-hoist-scalars.ll b/llvm/test/Transforms/GVN/simple-gvn-hoist-scalars.ll
new file mode 100644
index 0000000000000..e774f64d4a4e5
--- /dev/null
+++ b/llvm/test/Transforms/GVN/simple-gvn-hoist-scalars.ll
@@ -0,0 +1,382 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt --passes=gvn -S %s | FileCheck %s
+; RUN: opt --passes="gvn<memoryssa>" -S %s | FileCheck %s
+
+target triple = "aarch64-unknown-linux"
+
+define dso_local i32 @everything_hoisted(i1 %cc, i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @everything_hoisted(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: br i1 [[CC:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+; CHECK: if.then:
+; CHECK-NEXT: [[TMP0:%.*]] = call i32 @barrier(i32 [[A:%.*]])
+; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[TMP0]], [[B:%.*]]
+; CHECK-NEXT: [[TMP2:%.*]] = sdiv i32 [[TMP1]], [[C:%.*]]
+; CHECK-NEXT: br label [[IF_END:%.*]]
+; CHECK: if.else:
+; CHECK-NEXT: [[TMP3:%.*]] = call i32 @barrier(i32 [[A]])
+; CHECK-NEXT: [[TMP4:%.*]] = add i32 [[TMP3]], [[B]]
+; CHECK-NEXT: [[TMP5:%.*]] = sdiv i32 [[TMP4]], [[C]]
+; CHECK-NEXT: br label [[IF_END]]
+; CHECK: if.end:
+; CHECK-NEXT: [[R:%.*]] = phi i32 [ [[TMP2]], [[IF_THEN]] ], [ [[TMP5]], [[IF_ELSE]] ]
+; CHECK-NEXT: ret i32 [[R]]
+;
+entry:
+ br i1 %cc, label %if.then, label %if.else
+
+if.then:
+ %0 = call i32 @barrier(i32 %a)
+ %1 = add i32 %0, %b
+ %2 = sdiv i32 %1, %c
+ br label %if.end
+
+if.else:
+ %3 = call i32 @barrier(i32 %a)
+ %4 = add i32 %3, %b
+ %5 = sdiv i32 %4, %c
+ br label %if.end
+
+if.end:
+ %r = phi i32 [%2, %if.then], [%5, %if.else]
+ ret i32 %r
+}
+
+; speculation barrier on the short(collect) side
+define dso_local i32 @spec_barrier_short_side(i1 %cc, i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @spec_barrier_short_side(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: br i1 [[CC:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+; CHECK: if.then:
+; CHECK-NEXT: [[TMP2:%.*]] = call i32 @barrier(i32 [[A:%.*]])
+; CHECK-NEXT: [[TMP0:%.*]] = add nsw i32 [[A]], [[B:%.*]]
+; CHECK-NEXT: [[TMP1:%.*]] = sdiv i32 [[C:%.*]], [[TMP0]]
+; CHECK-NEXT: br label [[IF_END:%.*]]
+; CHECK: if.else:
+; CHECK-NEXT: [[TMP6:%.*]] = add nsw i32 [[A]], [[B]]
+; CHECK-NEXT: [[TMP3:%.*]] = sdiv i32 [[C]], [[TMP6]]
+; CHECK-NEXT: [[TMP5:%.*]] = add i32 [[TMP3]], 1
+; CHECK-NEXT: [[TMP4:%.*]] = add i32 [[TMP5]], 2
+; CHECK-NEXT: br label [[IF_END]]
+; CHECK: if.end:
+; CHECK-NEXT: [[R:%.*]] = phi i32 [ [[TMP1]], [[IF_THEN]] ], [ [[TMP4]], [[IF_ELSE]] ]
+; CHECK-NEXT: ret i32 [[R]]
+;
+entry:
+ br i1 %cc, label %if.then, label %if.else
+
+if.then:
+ %0 = call i32 @barrier(i32 %a)
+ %1 = add nsw i32 %a, %b
+ %2 = sdiv i32 %c, %1
+ br label %if.end
+
+if.else:
+ %3 = add nsw i32 %a, %b
+ %4 = sdiv i32 %c, %3
+ %5 = add i32 %4, 1
+ %6 = add i32 %5, 2
+ br label %if.end
+
+if.end:
+ %r = phi i32 [%2, %if.then], [%6, %if.else]
+ ret i32 %r
+}
+
+; speculation barrier on the long(match) side
+define dso_local i32 @spec_barrier_long_side(i1 %cc, i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @spec_barrier_long_side(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: br i1 [[CC:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+; CHECK: if.then:
+; CHECK-NEXT: [[TMP0:%.*]] = add nsw i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT: [[TMP1:%.*]] = sdiv i32 [[C:%.*]], [[TMP0]]
+; CHECK-NEXT: br label [[IF_END:%.*]]
+; CHECK: if.else:
+; CHECK-NEXT: [[TMP2:%.*]] = call i32 @barrier(i32 [[A]])
+; CHECK-NEXT: [[TMP6:%.*]] = add nsw i32 [[A]], [[B]]
+; CHECK-NEXT: [[TMP3:%.*]] = sdiv i32 [[C]], [[TMP6]]
+; CHECK-NEXT: [[TMP5:%.*]] = add i32 [[TMP3]], 1
+; CHECK-NEXT: [[TMP4:%.*]] = add i32 [[TMP5]], 2
+; CHECK-NEXT: br label [[IF_END]]
+; CHECK: if.end:
+; CHECK-NEXT: [[R:%.*]] = phi i32 [ [[TMP1]], [[IF_THEN]] ], [ [[TMP4]], [[IF_ELSE]] ]
+; CHECK-NEXT: ret i32 [[R]]
+;
+entry:
+ br i1 %cc, label %if.then, label %if.else
+
+if.then:
+ %0 = add nsw i32 %a, %b
+ %1 = sdiv i32 %c, %0
+ br label %if.end
+
+if.else:
+ %2 = call i32 @barrier(i32 %a)
+ %3 = add nsw i32 %a, %b
+ %4 = sdiv i32 %c, %3
+ %5 = add i32 %4, 1
+ %6 = add i32 %5, 2
+ br label %if.end
+
+if.end:
+ %r = phi i32 [%1, %if.then], [%6, %if.else]
+ ret i32 %r
+}
+
+define dso_local i32 @no_reorder_across_volatile(i1 %cc, i32 %a, i32 %b, i32 %c, ptr %p) {
+; CHECK-LABEL: @no_reorder_across_volatile(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: br i1 [[CC:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+; CHECK: if.then:
+; CHECK-NEXT: [[TMP0:%.*]] = add nsw i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT: [[TMP1:%.*]] = sdiv i32 [[C:%.*]], [[TMP0]]
+; CHECK-NEXT: br label [[IF_END:%.*]]
+; CHECK: if.else:
+; CHECK-NEXT: store volatile i32 0, ptr [[P:%.*]], align 4
+; CHECK-NEXT: [[TMP3:%.*]] = add nsw i32 [[A]], [[B]]
+; CHECK-NEXT: [[TMP2:%.*]] = sdiv i32 [[C]], [[TMP3]]
+; CHECK-NEXT: br label [[IF_END]]
+; CHECK: if.end:
+; CHECK-NEXT: [[R:%.*]] = phi i32 [ [[TMP1]], [[IF_THEN]] ], [ [[TMP2]], [[IF_ELSE]] ]
+; CHECK-NEXT: ret i32 [[R]]
+;
+entry:
+ br i1 %cc, label %if.then, label %if.else
+
+if.then:
+ %0 = add nsw i32 %a, %b
+ %1 = sdiv i32 %c, %0
+ br label %if.end
+
+if.else:
+ store volatile i32 0, ptr %p
+ %2 = add nsw i32 %a, %b
+ %3 = sdiv i32 %c, %2
+ br label %if.end
+
+if.end:
+ %r = phi i32 [%1, %if.then], [%3, %if.else]
+ ret i32 %r
+}
+
+define dso_local i32 @no_barrier_call(i1 %cc, i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @no_barrier_call(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: br i1 [[CC:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+; CHECK: if.then:
+; CHECK-NEXT: call void @will_return()
+; CHECK-NEXT: [[TMP0:%.*]] = sdiv i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT: [[TMP1:%.*]] = add nsw i32 [[C:%.*]], [[TMP0]]
+; CHECK-NEXT: br label [[IF_END:%.*]]
+; CHECK: if.else:
+; CHECK-NEXT: call void @will_return()
+; CHECK-NEXT: [[TMP2:%.*]] = sdiv i32 [[A]], [[B]]
+; CHECK-NEXT: [[TMP3:%.*]] = add nsw i32 [[C]], [[TMP2]]
+; CHECK-NEXT: br label [[IF_END]]
+; CHECK: if.end:
+; CHECK-NEXT: [[R:%.*]] = phi i32 [ [[TMP1]], [[IF_THEN]] ], [ [[TMP3]], [[IF_ELSE]] ]
+; CHECK-NEXT: ret i32 [[R]]
+;
+entry:
+ br i1 %cc, label %if.then, label %if.else
+
+if.then:
+ call void @will_return()
+ %0 = sdiv i32 %a, %b
+ %1 = add nsw i32 %c, %0
+ br label %if.end
+
+if.else:
+ call void @will_return()
+ %2 = sdiv i32 %a, %b
+ %3 = add nsw i32 %c, %2
+ br label %if.end
+
+if.end:
+ %r = phi i32 [%1, %if.then], [%3, %if.else]
+ ret i32 %r
+}
+
+define dso_local i32 @no_reorder_atomic(i1 %cc, i32 %a, i32 %b, i32 %c, ptr %p) {
+; CHECK-LABEL: @no_reorder_atomic(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: br i1 [[CC:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+; CHECK: if.then:
+; CHECK-NEXT: [[TMP0:%.*]] = load atomic volatile i32, ptr [[P:%.*]] acquire, align 4
+; CHECK-NEXT: [[TMP1:%.*]] = sdiv i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT: [[TMP2:%.*]] = add nsw i32 [[C:%.*]], [[TMP1]]
+; CHECK-NEXT: [[TMP3:%.*]] = mul nsw i32 [[TMP0]], [[TMP2]]
+; CHECK-NEXT: br label [[IF_END:%.*]]
+; CHECK: if.else:
+; CHECK-NEXT: [[TMP4:%.*]] = load atomic volatile i32, ptr [[P]] acquire, align 4
+; CHECK-NEXT: [[TMP5:%.*]] = sdiv i32 [[A]], [[B]]
+; CHECK-NEXT: [[TMP6:%.*]] = add nsw i32 [[C]], [[TMP5]]
+; CHECK-NEXT: [[TMP7:%.*]] = mul nsw i32 [[TMP4]], [[TMP6]]
+; CHECK-NEXT: br label [[IF_END]]
+; CHECK: if.end:
+; CHECK-NEXT: [[R:%.*]] = phi i32 [ [[TMP3]], [[IF_THEN]] ], [ [[TMP7]], [[IF_ELSE]] ]
+; CHECK-NEXT: ret i32 [[R]]
+;
+entry:
+ br i1 %cc, label %if.then, label %if.else
+
+if.then:
+ %0 = load atomic volatile i32, ptr %p acquire, align 4
+ %1 = sdiv i32 %a, %b
+ %2 = add nsw i32 %c, %1
+ %3 = mul nsw i32 %0, %2
+ br label %if.end
+
+if.else:
+ %4 = load atomic volatile i32, ptr %p acquire, align 4
+ %5 = sdiv i32 %a, %b
+ %6 = add nsw i32 %c, %5
+ %7 = mul nsw i32 %4, %6
+ br label %if.end
+
+if.end:
+ %r = phi i32 [%3, %if.then], [%7, %if.else]
+ ret i32 %r
+}
+
+define dso_local i32 @multiple_use(i1 %cc, i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @multiple_use(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: br i1 [[CC:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+; CHECK: if.then:
+; CHECK-NEXT: [[TMP0:%.*]] = add nsw i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT: [[TMP1:%.*]] = mul nsw i32 [[TMP0]], [[C:%.*]]
+; CHECK-NEXT: [[TMP2:%.*]] = add nsw i32 [[TMP0]], [[TMP1]]
+; CHECK-NEXT: br label [[IF_END:%.*]]
+; CHECK: if.else:
+; CHECK-NEXT: [[TMP3:%.*]] = add nsw i32 [[A]], [[B]]
+; CHECK-NEXT: [[TMP4:%.*]] = mul nsw i32 [[TMP3]], [[C]]
+; CHECK-NEXT: [[TMP5:%.*]] = add nsw i32 [[TMP3]], [[TMP4]]
+; CHECK-NEXT: br label [[IF_END]]
+; CHECK: if.end:
+; CHECK-NEXT: [[R:%.*]] = phi i32 [ [[TMP2]], [[IF_THEN]] ], [ [[TMP5]], [[IF_ELSE]] ]
+; CHECK-NEXT: ret i32 [[R]]
+;
+entry:
+ br i1 %cc, label %if.then, label %if.else
+
+if.then:
+ %0 = add nsw i32 %a, %b
+ %1 = mul nsw i32 %0, %c
+ %2 = add nsw i32 %0, %1
+ br label %if.end
+
+if.else:
+ %3 = add nsw i32 %a, %b
+ %4 = mul nsw i32 %3, %c
+ %5 = add nsw i32 %3, %4
+ br label %if.end
+
+if.end:
+ %r = phi i32 [%2, %if.then], [%5, %if.else]
+ ret i32 %r
+}
+
+; Different operand order in commutative operations
+define dso_local i32 @commutative_ops(i1 %cc, i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @commutative_ops(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: br i1 [[CC:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+; CHECK: if.then:
+; CHECK-NEXT: [[TMP0:%.*]] = add nsw i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT: [[TMP1:%.*]] = add nsw i32 [[TMP0]], [[C:%.*]]
+; CHECK-NEXT: [[TMP2:%.*]] = sdiv i32 [[TMP0]], [[TMP1]]
+; CHECK-NEXT: br label [[IF_END:%.*]]
+; CHECK: if.else:
+; CHECK-NEXT: [[TMP3:%.*]] = add nsw i32 [[A]], [[B]]
+; CHECK-NEXT: [[TMP4:%.*]] = add nsw i32 [[C]], [[TMP3]]
+; CHECK-NEXT: [[TMP5:%.*]] = sdiv i32 [[TMP3]], [[TMP4]]
+; CHECK-NEXT: br label [[IF_END]]
+; CHECK: if.end:
+; CHECK-NEXT: [[R:%.*]] = phi i32 [ [[TMP2]], [[IF_THEN]] ], [ [[TMP5]], [[IF_ELSE]] ]
+; CHECK-NEXT: ret i32 [[R]]
+;
+entry:
+ br i1 %cc, label %if.then, label %if.else
+
+if.then:
+ %0 = add nsw i32 %a, %b
+ %1 = add nsw i32 %0, %c
+ %2 = sdiv i32 %0, %1
+ br label %if.end
+
+if.else:
+ %3 = add nsw i32 %a, %b
+ %4 = add nsw i32 %c, %3
+ %5 = sdiv i32 %3, %4
+ br label %if.end
+
+if.end:
+ %r = phi i32 [%2, %if.then], [%5, %if.else]
+ ret i32 %r
+}
+
+define dso_local i32 @no_hoist_mem(i1 %cc, ptr %p) {
+; CHECK-LABEL: @no_hoist_mem(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: br i1 [[CC:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+; CHECK: if.then:
+; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[P:%.*]], align 4
+; CHECK-NEXT: [[TMP1:%.*]] = add nsw i32 [[TMP0]], 1
+; CHECK-NEXT: br label [[IF_END:%.*]]
+; CHECK: if.else:
+; CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[P]], align 4
+; CHECK-NEXT: [[TMP3:%.*]] = add nsw i32 [[TMP2]], 1
+; CHECK-NEXT: br label [[IF_END]]
+; CHECK: if.end:
+; CHECK-NEXT: [[R:%.*]] = phi i32 [ [[TMP1]], [[IF_THEN]] ], [ [[TMP3]], [[IF_ELSE]] ]
+; CHECK-NEXT: ret i32 [[R]]
+;
+entry:
+ br i1 %cc, label %if.then, label %if.else
+
+if.then:
+ %0 = load i32, ptr %p
+ %1 = add nsw i32 %0, 1
+ br label %if.end
+
+if.else:
+ %2 = load i32, ptr %p
+ %3 = add nsw i32 %2, 1
+ br label %if.end
+
+if.end:
+ %r = phi i32 [%1, %if.then], [%3, %if.else]
+ ret i32 %r
+}
+
+define dso_local i32 @no_hoist_musttail(i1 %cc, i32 %x, ptr %p) {
+; CHECK-LABEL: @no_hoist_musttail(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[V:%.*]] = load i32, ptr [[P:%.*]], align 4
+; CHECK-NEXT: [[W:%.*]] = add i32 [[V]], [[X:%.*]]
+; CHECK-NEXT: br i1 [[CC:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+; CHECK: if.then:
+; CHECK-NEXT: [[TMP0:%.*]] = musttail call i32 @will_return(i1 true, i32 [[W]], ptr [[P]])
+; CHECK-NEXT: ret i32 [[TMP0]]
+; CHECK: if.else:
+; CHECK-NEXT: [[TMP1:%.*]] = musttail call i32 @will_return(i1 false, i32 [[W]], ptr [[P]])
+; CHECK-NEXT: ret i32 [[TMP1]]
+;
+entry:
+ %v = load i32, ptr %p
+ %w = add i32 %v, %x
+ br i1 %cc, label %if.then, label %if.else
+
+if.then:
+ %0 = musttail call i32 @will_return(i1 %cc, i32 %w, ptr %p)
+ ret i32 %0
+
+if.else:
+ %1 = musttail call i32 @will_return(i1 %cc, i32 %w, ptr %p)
+ ret i32 %1
+}
+
+declare i32 @barrier(i32) memory(none)
+declare void @will_return() nounwind willreturn
More information about the llvm-branch-commits
mailing list