Index: llvm/test/Transforms/GVN/simple-gvnhoist-scalars.ll
===================================================================
--- /dev/null
+++ llvm/test/Transforms/GVN/simple-gvnhoist-scalars.ll
@@ -0,0 +1,319 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt --passes=gvn -S %s | FileCheck %s
+
+target triple = "aarch64-unknown-linux"
+
+; everything hoisted
+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:%.*]] = add nsw i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = sdiv i32 [[C:%.*]], [[TMP0]]
+; CHECK-NEXT:    br label [[IF_END:%.*]]
+; CHECK:       if.else:
+; CHECK-NEXT:    [[TMP2:%.*]] = add nsw i32 [[A]], [[B]]
+; CHECK-NEXT:    [[TMP3:%.*]] = sdiv 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:
+  %0 = add nsw i32 %a, %b
+  %1 = sdiv i32 %c, %0
+  br label %if.end
+
+if.else:
+  %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
+}
+
+; speculation barrier
+define dso_local i32 @spec_barrier0(i1 %cc, i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @spec_barrier0(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br i1 [[CC:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+; CHECK:       if.then:
+; CHECK-NEXT:    call void @h()
+; 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:    call void @h()
+; CHECK-NEXT:    [[TMP2:%.*]] = add nsw i32 [[A]], [[B]]
+; CHECK-NEXT:    [[TMP3:%.*]] = sdiv 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 @h()
+  %0 = add nsw i32 %a, %b
+  %1 = sdiv i32 %c, %0
+  br label %if.end
+
+if.else:
+  call void @h()
+  %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
+}
+
+; speculation barrier
+define dso_local i32 @spec_barrier1(i1 %cc, i32 %a, i32 %b, i32 %c, i32* %p) {
+; CHECK-LABEL: @spec_barrier1(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br i1 [[CC:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+; CHECK:       if.then:
+; CHECK-NEXT:    store volatile i32 0, i32* [[P:%.*]], align 4
+; 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, i32* [[P]], align 4
+; CHECK-NEXT:    [[TMP2:%.*]] = add nsw i32 [[A]], [[B]]
+; CHECK-NEXT:    [[TMP3:%.*]] = sdiv 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:
+  store volatile i32 0, i32* %p
+  %0 = add nsw i32 %a, %b
+  %1 = sdiv i32 %c, %0
+  br label %if.end
+
+if.else:
+  store volatile i32 0, i32* %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
+}
+
+; speculation barrier
+define dso_local i32 @spec_barrier2(i1 %cc, i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @spec_barrier2(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br i1 [[CC:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+; CHECK:       if.then:
+; CHECK-NEXT:    call void @h()
+; 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 @h()
+; 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 @h()
+  %0 = sdiv i32 %a, %b
+  %1 = add nsw i32 %c, %0
+  br label %if.end
+
+if.else:
+  call void @h()
+  %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
+}
+
+; no speculation barrier
+define dso_local i32 @no_spec_barrier0(i1 %cc, i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @no_spec_barrier0(
+; 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
+}
+
+; no speculation barrier
+define dso_local i32 @no_spec_barrier1(i1 %cc, i32 %a, i32 %b, i32 %c, i32* %p) {
+; CHECK-LABEL: @no_spec_barrier1(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br i1 [[CC:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+; CHECK:       if.then:
+; CHECK-NEXT:    [[TMP0:%.*]] = load atomic volatile i32, i32* [[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, i32* [[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, i32* %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, i32* %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
+}
+
+; multiple uses of a hoisted instruction
+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
+}
+
+declare void @h()
+declare void @will_return() nounwind willreturn