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