llvm/llvm/test/Transforms/SimpleLoopUnswitch/memssa-readnone-access.ll

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
; RUN: opt -S -passes="loop-mssa(loop-instsimplify,simple-loop-unswitch<nontrivial>)" < %s | FileCheck %s

@vtable = constant ptr @foo

declare void @foo() memory(none)
declare void @bar()

; The call becomes known readnone after simplification, but still have a
; MemoryAccess. Make sure this does not lead to an assertion failure.
define void @test(i1 %c) {
; CHECK-LABEL: define void @test(
; CHECK-SAME: i1 [[C:%.*]]) {
; CHECK-NEXT:    [[C_FR:%.*]] = freeze i1 [[C]]
; CHECK-NEXT:    br i1 [[C_FR]], label [[DOTSPLIT_US:%.*]], label [[DOTSPLIT:%.*]]
; CHECK:       .split.us:
; CHECK-NEXT:    br label [[LOOP_US:%.*]]
; CHECK:       loop.us:
; CHECK-NEXT:    call void @foo()
; CHECK-NEXT:    br label [[EXIT_SPLIT_US:%.*]]
; CHECK:       exit.split.us:
; CHECK-NEXT:    br label [[EXIT:%.*]]
; CHECK:       .split:
; CHECK-NEXT:    br label [[LOOP:%.*]]
; CHECK:       loop:
; CHECK-NEXT:    call void @foo()
; CHECK-NEXT:    br label [[LOOP]]
; CHECK:       exit:
; CHECK-NEXT:    ret void
;
  br label %loop

loop:
  %fn = load ptr, ptr @vtable, align 8
  call void %fn()
  br i1 %c, label %exit, label %loop

exit:
  ret void
}

; Variant with another access after the call.
define void @test2(i1 %c, ptr %p) {
; CHECK-LABEL: define void @test2(
; CHECK-SAME: i1 [[C:%.*]], ptr [[P:%.*]]) {
; CHECK-NEXT:    [[C_FR:%.*]] = freeze i1 [[C]]
; CHECK-NEXT:    br i1 [[C_FR]], label [[DOTSPLIT_US:%.*]], label [[DOTSPLIT:%.*]]
; CHECK:       .split.us:
; CHECK-NEXT:    br label [[LOOP_US:%.*]]
; CHECK:       loop.us:
; CHECK-NEXT:    call void @foo()
; CHECK-NEXT:    call void @bar()
; CHECK-NEXT:    br label [[EXIT_SPLIT_US:%.*]]
; CHECK:       exit.split.us:
; CHECK-NEXT:    br label [[EXIT:%.*]]
; CHECK:       .split:
; CHECK-NEXT:    br label [[LOOP:%.*]]
; CHECK:       loop:
; CHECK-NEXT:    call void @foo()
; CHECK-NEXT:    call void @bar()
; CHECK-NEXT:    br label [[LOOP]]
; CHECK:       exit:
; CHECK-NEXT:    ret void
;
  br label %loop

loop:
  %fn = load ptr, ptr @vtable, align 8
  call void %fn()
  call void @bar()
  br i1 %c, label %exit, label %loop

exit:
  ret void
}

; Variant with another access after the call and no access before the call.
define void @test3(i1 %c, ptr %p) {
; CHECK-LABEL: define void @test3(
; CHECK-SAME: i1 [[C:%.*]], ptr [[P:%.*]]) {
; CHECK-NEXT:    [[C_FR:%.*]] = freeze i1 [[C]]
; CHECK-NEXT:    br i1 [[C_FR]], label [[DOTSPLIT_US:%.*]], label [[DOTSPLIT:%.*]]
; CHECK:       .split.us:
; CHECK-NEXT:    br label [[LOOP_US:%.*]]
; CHECK:       loop.us:
; CHECK-NEXT:    br label [[SPLIT_US:%.*]]
; CHECK:       split.us:
; CHECK-NEXT:    call void @foo()
; CHECK-NEXT:    call void @bar()
; CHECK-NEXT:    br label [[EXIT_SPLIT_US:%.*]]
; CHECK:       exit.split.us:
; CHECK-NEXT:    br label [[EXIT:%.*]]
; CHECK:       .split:
; CHECK-NEXT:    br label [[LOOP:%.*]]
; CHECK:       loop:
; CHECK-NEXT:    br label [[SPLIT:%.*]]
; CHECK:       split:
; CHECK-NEXT:    call void @foo()
; CHECK-NEXT:    call void @bar()
; CHECK-NEXT:    br label [[LOOP]]
; CHECK:       exit:
; CHECK-NEXT:    ret void
;
  br label %loop

loop:
  %fn = load ptr, ptr @vtable, align 8
  br label %split

split:
  call void %fn()
  call void @bar()
  br i1 %c, label %exit, label %loop

exit:
  ret void
}

; Variants of the above test with swapped branch destinations.

define void @test1_swapped(i1 %c) {
; CHECK-LABEL: define void @test1_swapped(
; CHECK-SAME: i1 [[C:%.*]]) {
; CHECK-NEXT:  start:
; CHECK-NEXT:    [[C_FR:%.*]] = freeze i1 [[C]]
; CHECK-NEXT:    br i1 [[C_FR]], label [[START_SPLIT_US:%.*]], label [[START_SPLIT:%.*]]
; CHECK:       start.split.us:
; CHECK-NEXT:    br label [[LOOP_US:%.*]]
; CHECK:       loop.us:
; CHECK-NEXT:    call void @foo()
; CHECK-NEXT:    br label [[LOOP_US]]
; CHECK:       start.split:
; CHECK-NEXT:    br label [[LOOP:%.*]]
; CHECK:       loop:
; CHECK-NEXT:    call void @foo()
; CHECK-NEXT:    br label [[EXIT:%.*]]
; CHECK:       exit:
; CHECK-NEXT:    ret void
;
start:
  br label %loop

loop:
  %fn = load ptr, ptr @vtable, align 8
  call void %fn()
  br i1 %c, label %loop, label %exit

exit:
  ret void
}

define void @test2_swapped(i1 %c, ptr %p) {
; CHECK-LABEL: define void @test2_swapped(
; CHECK-SAME: i1 [[C:%.*]], ptr [[P:%.*]]) {
; CHECK-NEXT:    [[C_FR:%.*]] = freeze i1 [[C]]
; CHECK-NEXT:    br i1 [[C_FR]], label [[DOTSPLIT_US:%.*]], label [[DOTSPLIT:%.*]]
; CHECK:       .split.us:
; CHECK-NEXT:    br label [[LOOP_US:%.*]]
; CHECK:       loop.us:
; CHECK-NEXT:    call void @foo()
; CHECK-NEXT:    call void @bar()
; CHECK-NEXT:    br label [[LOOP_US]]
; CHECK:       .split:
; CHECK-NEXT:    br label [[LOOP:%.*]]
; CHECK:       loop:
; CHECK-NEXT:    call void @foo()
; CHECK-NEXT:    call void @bar()
; CHECK-NEXT:    br label [[EXIT:%.*]]
; CHECK:       exit:
; CHECK-NEXT:    ret void
;
  br label %loop

loop:
  %fn = load ptr, ptr @vtable, align 8
  call void %fn()
  call void @bar()
  br i1 %c, label %loop, label %exit

exit:
  ret void
}

define void @test3_swapped(i1 %c, ptr %p) {
; CHECK-LABEL: define void @test3_swapped(
; CHECK-SAME: i1 [[C:%.*]], ptr [[P:%.*]]) {
; CHECK-NEXT:    [[C_FR:%.*]] = freeze i1 [[C]]
; CHECK-NEXT:    br i1 [[C_FR]], label [[DOTSPLIT_US:%.*]], label [[DOTSPLIT:%.*]]
; CHECK:       .split.us:
; CHECK-NEXT:    br label [[LOOP_US:%.*]]
; CHECK:       loop.us:
; CHECK-NEXT:    br label [[SPLIT_US:%.*]]
; CHECK:       split.us:
; CHECK-NEXT:    call void @foo()
; CHECK-NEXT:    call void @bar()
; CHECK-NEXT:    br label [[LOOP_US]]
; CHECK:       .split:
; CHECK-NEXT:    br label [[LOOP:%.*]]
; CHECK:       loop:
; CHECK-NEXT:    br label [[SPLIT:%.*]]
; CHECK:       split:
; CHECK-NEXT:    call void @foo()
; CHECK-NEXT:    call void @bar()
; CHECK-NEXT:    br label [[EXIT:%.*]]
; CHECK:       exit:
; CHECK-NEXT:    ret void
;
  br label %loop

loop:
  %fn = load ptr, ptr @vtable, align 8
  br label %split

split:
  call void %fn()
  call void @bar()
  br i1 %c, label %loop, label %exit

exit:
  ret void
}