llvm/llvm/test/Transforms/GVNHoist/infinite-loop-indirect.ll

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
; RUN: opt -S -passes=gvn-hoist < %s | FileCheck %s

; Checking gvn-hoist in case of indirect branches.

%class.bar = type { ptr, ptr }
%class.base = type { ptr }

@bar = local_unnamed_addr global ptr null, align 8
@bar1 = local_unnamed_addr global ptr null, align 8

; Check that the bitcast is not hoisted because it is after an indirect call
define i32 @foo(ptr nocapture readonly %i) {
; CHECK-LABEL: define i32 @foo
; CHECK-SAME: (ptr nocapture readonly [[I:%.*]]) {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[AGG_TMP:%.*]] = alloca [[CLASS_BAR:%.*]], align 8
; CHECK-NEXT:    [[X:%.*]] = getelementptr inbounds [[CLASS_BAR]], ptr [[AGG_TMP]], i64 0, i32 1
; CHECK-NEXT:    [[Y:%.*]] = load ptr, ptr [[X]], align 8
; CHECK-NEXT:    [[TMP0:%.*]] = load i32, ptr [[I]], align 4
; CHECK-NEXT:    [[DOTOFF:%.*]] = add i32 [[TMP0]], -1
; CHECK-NEXT:    [[SWITCH:%.*]] = icmp ult i32 [[DOTOFF]], 2
; CHECK-NEXT:    br i1 [[SWITCH]], label [[L1_PREHEADER:%.*]], label [[SW_DEFAULT:%.*]]
; CHECK:       l1.preheader:
; CHECK-NEXT:    [[B1:%.*]] = bitcast ptr [[Y]] to ptr
; CHECK-NEXT:    br label [[L1:%.*]]
; CHECK:       l1:
; CHECK-NEXT:    [[TMP1:%.*]] = load ptr, ptr @bar, align 8
; CHECK-NEXT:    [[CALL:%.*]] = tail call i32 [[TMP1]]()
; CHECK-NEXT:    [[B2:%.*]] = bitcast ptr [[Y]] to ptr
; CHECK-NEXT:    br label [[L1]]
; CHECK:       sw.default:
; CHECK-NEXT:    [[TMP2:%.*]] = load ptr, ptr @bar1, align 8
; CHECK-NEXT:    [[CALL2:%.*]] = tail call i32 [[TMP2]]()
; CHECK-NEXT:    br label [[L1_PREHEADER]]
;
entry:
  %agg.tmp = alloca %class.bar, align 8
  %x= getelementptr inbounds %class.bar, ptr %agg.tmp, i64 0, i32 1
  %y = load ptr, ptr %x, align 8
  %0 = load i32, ptr %i, align 4
  %.off = add i32 %0, -1
  %switch = icmp ult i32 %.off, 2
  br i1 %switch, label %l1.preheader, label %sw.default

l1.preheader:                                     ; preds = %sw.default, %entry
  %b1 = bitcast ptr %y to ptr
  br label %l1

l1:                                               ; preds = %l1.preheader, %l1
  %1 = load ptr, ptr @bar, align 8
  %call = tail call i32 %1()
  %b2 = bitcast ptr %y to ptr
  br label %l1

sw.default:                                       ; preds = %entry
  %2 = load ptr, ptr @bar1, align 8
  %call2 = tail call i32 %2()
  br label %l1.preheader
}


; Any instruction inside an infinite loop will not be hoisted because
; there is no path to exit of the function.
define i32 @foo1(ptr nocapture readonly %i) {
; CHECK-LABEL: define i32 @foo1
; CHECK-SAME: (ptr nocapture readonly [[I:%.*]]) {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[AGG_TMP:%.*]] = alloca [[CLASS_BAR:%.*]], align 8
; CHECK-NEXT:    [[X:%.*]] = getelementptr inbounds [[CLASS_BAR]], ptr [[AGG_TMP]], i64 0, i32 1
; CHECK-NEXT:    [[Y:%.*]] = load ptr, ptr [[X]], align 8
; CHECK-NEXT:    [[TMP0:%.*]] = load i32, ptr [[I]], align 4
; CHECK-NEXT:    [[DOTOFF:%.*]] = add i32 [[TMP0]], -1
; CHECK-NEXT:    [[SWITCH:%.*]] = icmp ult i32 [[DOTOFF]], 2
; CHECK-NEXT:    br i1 [[SWITCH]], label [[L1_PREHEADER:%.*]], label [[SW_DEFAULT:%.*]]
; CHECK:       l1.preheader:
; CHECK-NEXT:    [[B1:%.*]] = bitcast ptr [[Y]] to ptr
; CHECK-NEXT:    [[Y1:%.*]] = load ptr, ptr [[X]], align 8
; CHECK-NEXT:    br label [[L1:%.*]]
; CHECK:       l1:
; CHECK-NEXT:    [[B2:%.*]] = bitcast ptr [[Y]] to ptr
; CHECK-NEXT:    [[TMP1:%.*]] = load ptr, ptr @bar, align 8
; CHECK-NEXT:    [[Y2:%.*]] = load ptr, ptr [[X]], align 8
; CHECK-NEXT:    [[CALL:%.*]] = tail call i32 [[TMP1]]()
; CHECK-NEXT:    br label [[L1]]
; CHECK:       sw.default:
; CHECK-NEXT:    [[TMP2:%.*]] = load ptr, ptr @bar1, align 8
; CHECK-NEXT:    [[CALL2:%.*]] = tail call i32 [[TMP2]]()
; CHECK-NEXT:    br label [[L1_PREHEADER]]
;
entry:
  %agg.tmp = alloca %class.bar, align 8
  %x= getelementptr inbounds %class.bar, ptr %agg.tmp, i64 0, i32 1
  %y = load ptr, ptr %x, align 8
  %0 = load i32, ptr %i, align 4
  %.off = add i32 %0, -1
  %switch = icmp ult i32 %.off, 2
  br i1 %switch, label %l1.preheader, label %sw.default

l1.preheader:                                     ; preds = %sw.default, %entry
  %b1 = bitcast ptr %y to ptr
  %y1 = load ptr, ptr %x, align 8
  br label %l1

l1:                                               ; preds = %l1.preheader, %l1
  %b2 = bitcast ptr %y to ptr
  %1 = load ptr, ptr @bar, align 8
  %y2 = load ptr, ptr %x, align 8
  %call = tail call i32 %1()
  br label %l1

sw.default:                                       ; preds = %entry
  %2 = load ptr, ptr @bar1, align 8
  %call2 = tail call i32 %2()
  br label %l1.preheader
}

; Check that bitcast is hoisted even when one of them is partially redundant.
define i32 @test13(ptr %P, ptr %Ptr, ptr nocapture readonly %i) {
; CHECK-LABEL: define i32 @test13
; CHECK-SAME: (ptr [[P:%.*]], ptr [[PTR:%.*]], ptr nocapture readonly [[I:%.*]]) {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[AGG_TMP:%.*]] = alloca [[CLASS_BAR:%.*]], align 8
; CHECK-NEXT:    [[X:%.*]] = getelementptr inbounds [[CLASS_BAR]], ptr [[AGG_TMP]], i64 0, i32 1
; CHECK-NEXT:    [[Y:%.*]] = load ptr, ptr [[X]], align 8
; CHECK-NEXT:    [[B2:%.*]] = bitcast ptr [[Y]] to ptr
; CHECK-NEXT:    indirectbr ptr [[PTR]], [label [[BRBLOCK:%.*]], label %B2]
; CHECK:       B2:
; CHECK-NEXT:    store i32 4, ptr [[P]], align 4
; CHECK-NEXT:    br label [[BRBLOCK]]
; CHECK:       BrBlock:
; CHECK-NEXT:    [[L:%.*]] = load i32, ptr [[P]], align 4
; CHECK-NEXT:    [[C:%.*]] = icmp eq i32 [[L]], 42
; CHECK-NEXT:    br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
; CHECK:       T:
; CHECK-NEXT:    ret i32 123
; CHECK:       F:
; CHECK-NEXT:    ret i32 1422
;
entry:
  %agg.tmp = alloca %class.bar, align 8
  %x= getelementptr inbounds %class.bar, ptr %agg.tmp, i64 0, i32 1
  %y = load ptr, ptr %x, align 8
  indirectbr ptr %Ptr, [label %BrBlock, label %B2]

B2:
  %b1 = bitcast ptr %y to ptr
  store i32 4, ptr %P
  br label %BrBlock

BrBlock:
  %b2 = bitcast ptr %y to ptr
  %L = load i32, ptr %P
  %C = icmp eq i32 %L, 42
  br i1 %C, label %T, label %F

T:
  ret i32 123
F:
  ret i32 1422
}

; Check that the bitcast is not hoisted because anticipability
; cannot be guaranteed here as one of the indirect branch targets
; do not have the bitcast instruction.
define i32 @test14(ptr %P, ptr %Ptr, ptr nocapture readonly %i) {
; CHECK-LABEL: define i32 @test14
; CHECK-SAME: (ptr [[P:%.*]], ptr [[PTR:%.*]], ptr nocapture readonly [[I:%.*]]) {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[AGG_TMP:%.*]] = alloca [[CLASS_BAR:%.*]], align 8
; CHECK-NEXT:    [[X:%.*]] = getelementptr inbounds [[CLASS_BAR]], ptr [[AGG_TMP]], i64 0, i32 1
; CHECK-NEXT:    [[Y:%.*]] = load ptr, ptr [[X]], align 8
; CHECK-NEXT:    indirectbr ptr [[PTR]], [label [[BRBLOCK:%.*]], label [[B2:%.*]], label %T]
; CHECK:       B2:
; CHECK-NEXT:    [[B1:%.*]] = bitcast ptr [[Y]] to ptr
; CHECK-NEXT:    store i32 4, ptr [[P]], align 4
; CHECK-NEXT:    br label [[BRBLOCK]]
; CHECK:       BrBlock:
; CHECK-NEXT:    [[B2:%.*]] = bitcast ptr [[Y]] to ptr
; CHECK-NEXT:    [[L:%.*]] = load i32, ptr [[P]], align 4
; CHECK-NEXT:    [[C:%.*]] = icmp eq i32 [[L]], 42
; CHECK-NEXT:    br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
; CHECK:       T:
; CHECK-NEXT:    [[PI:%.*]] = load i32, ptr [[I]], align 4
; CHECK-NEXT:    ret i32 [[PI]]
; CHECK:       F:
; CHECK-NEXT:    [[PL:%.*]] = load i32, ptr [[P]], align 4
; CHECK-NEXT:    ret i32 [[PL]]
;
entry:
  %agg.tmp = alloca %class.bar, align 8
  %x= getelementptr inbounds %class.bar, ptr %agg.tmp, i64 0, i32 1
  %y = load ptr, ptr %x, align 8
  indirectbr ptr %Ptr, [label %BrBlock, label %B2, label %T]

B2:
  %b1 = bitcast ptr %y to ptr
  store i32 4, ptr %P
  br label %BrBlock

BrBlock:
  %b2 = bitcast ptr %y to ptr
  %L = load i32, ptr %P
  %C = icmp eq i32 %L, 42
  br i1 %C, label %T, label %F

T:
  %pi = load i32, ptr %i, align 4
  ret i32 %pi
F:
  %pl = load i32, ptr %P
  ret i32 %pl
}


; Check that the bitcast is not hoisted because of a cycle
; due to indirect branches
define i32 @test16(ptr %P, ptr %Ptr, ptr nocapture readonly %i) {
; CHECK-LABEL: define i32 @test16
; CHECK-SAME: (ptr [[P:%.*]], ptr [[PTR:%.*]], ptr nocapture readonly [[I:%.*]]) {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[AGG_TMP:%.*]] = alloca [[CLASS_BAR:%.*]], align 8
; CHECK-NEXT:    [[X:%.*]] = getelementptr inbounds [[CLASS_BAR]], ptr [[AGG_TMP]], i64 0, i32 1
; CHECK-NEXT:    [[Y:%.*]] = load ptr, ptr [[X]], align 8
; CHECK-NEXT:    indirectbr ptr [[PTR]], [label [[BRBLOCK:%.*]], label %B2]
; CHECK:       B2:
; CHECK-NEXT:    [[B1:%.*]] = bitcast ptr [[Y]] to ptr
; CHECK-NEXT:    [[TMP0:%.*]] = load i32, ptr [[I]], align 4
; CHECK-NEXT:    store i32 [[TMP0]], ptr [[P]], align 4
; CHECK-NEXT:    br label [[BRBLOCK]]
; CHECK:       BrBlock:
; CHECK-NEXT:    [[B2:%.*]] = bitcast ptr [[Y]] to ptr
; CHECK-NEXT:    [[L:%.*]] = load i32, ptr [[P]], align 4
; CHECK-NEXT:    [[C:%.*]] = icmp eq i32 [[L]], 42
; CHECK-NEXT:    br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
; CHECK:       T:
; CHECK-NEXT:    indirectbr ptr [[P]], [label [[BRBLOCK]], label %B2]
; CHECK:       F:
; CHECK-NEXT:    indirectbr ptr [[PTR]], [label [[BRBLOCK]], label %B2]
;
entry:
  %agg.tmp = alloca %class.bar, align 8
  %x= getelementptr inbounds %class.bar, ptr %agg.tmp, i64 0, i32 1
  %y = load ptr, ptr %x, align 8
  indirectbr ptr %Ptr, [label %BrBlock, label %B2]

B2:
  %b1 = bitcast ptr %y to ptr
  %0 = load i32, ptr %i, align 4
  store i32 %0, ptr %P
  br label %BrBlock

BrBlock:
  %b2 = bitcast ptr %y to ptr
  %L = load i32, ptr %P
  %C = icmp eq i32 %L, 42
  br i1 %C, label %T, label %F

T:
  indirectbr ptr %P, [label %BrBlock, label %B2]

F:
  indirectbr ptr %Ptr, [label %BrBlock, label %B2]
}


@_ZTIi = external constant ptr

; Check that an instruction is not hoisted out of landing pad (%lpad4)
; Also within a landing pad no redundancies are removed by gvn-hoist,
; however an instruction may be hoisted into a landing pad if
; landing pad has direct branches (e.g., %lpad to %catch1, %catch)
; This CFG has a cycle (%lpad -> %catch1 -> %lpad4 -> %lpad)

define i32 @foo2(ptr nocapture readonly %i) local_unnamed_addr personality ptr @__gxx_personality_v0 {
; CHECK-LABEL: define i32 @foo2
; CHECK-SAME: (ptr nocapture readonly [[I:%.*]]) local_unnamed_addr personality ptr @__gxx_personality_v0 {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[TMP0:%.*]] = load i32, ptr [[I]], align 4
; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[TMP0]], 0
; CHECK-NEXT:    br i1 [[CMP]], label [[TRY_CONT:%.*]], label [[IF_THEN:%.*]]
; CHECK:       if.then:
; CHECK-NEXT:    [[EXCEPTION:%.*]] = tail call ptr @__cxa_allocate_exception(i64 4) #[[ATTR1:[0-9]+]]
; CHECK-NEXT:    [[TMP1:%.*]] = bitcast ptr [[EXCEPTION]] to ptr
; CHECK-NEXT:    store i32 [[TMP0]], ptr [[TMP1]], align 16
; CHECK-NEXT:    invoke void @__cxa_throw(ptr [[EXCEPTION]], ptr @_ZTIi, ptr null) #[[ATTR2:[0-9]+]]
; CHECK-NEXT:    to label [[UNREACHABLE:%.*]] unwind label [[LPAD:%.*]]
; CHECK:       lpad:
; CHECK-NEXT:    [[TMP2:%.*]] = landingpad { ptr, i32 }
; CHECK-NEXT:    catch ptr @_ZTIi
; CHECK-NEXT:    catch ptr null
; CHECK-NEXT:    [[BC1:%.*]] = add i32 [[TMP0]], 10
; CHECK-NEXT:    [[TMP3:%.*]] = extractvalue { ptr, i32 } [[TMP2]], 0
; CHECK-NEXT:    [[TMP4:%.*]] = extractvalue { ptr, i32 } [[TMP2]], 1
; CHECK-NEXT:    [[TMP5:%.*]] = tail call i32 @llvm.eh.typeid.for.p0(ptr @_ZTIi) #[[ATTR1]]
; CHECK-NEXT:    [[MATCHES:%.*]] = icmp eq i32 [[TMP4]], [[TMP5]]
; CHECK-NEXT:    [[BC7:%.*]] = add i32 [[TMP0]], 10
; CHECK-NEXT:    [[TMP6:%.*]] = tail call ptr @__cxa_begin_catch(ptr [[TMP3]]) #[[ATTR1]]
; CHECK-NEXT:    [[BC4:%.*]] = add i32 [[TMP0]], 10
; CHECK-NEXT:    br i1 [[MATCHES]], label [[CATCH1:%.*]], label [[CATCH:%.*]]
; CHECK:       catch1:
; CHECK-NEXT:    invoke void @__cxa_rethrow() #[[ATTR2]]
; CHECK-NEXT:    to label [[UNREACHABLE]] unwind label [[LPAD4:%.*]]
; CHECK:       catch:
; CHECK-NEXT:    [[TMP7:%.*]] = load i32, ptr [[I]], align 4
; CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 [[TMP7]], 1
; CHECK-NEXT:    tail call void @__cxa_end_catch()
; CHECK-NEXT:    br label [[TRY_CONT]]
; CHECK:       lpad4:
; CHECK-NEXT:    [[TMP8:%.*]] = landingpad { ptr, i32 }
; CHECK-NEXT:    cleanup
; CHECK-NEXT:    [[BC5:%.*]] = add i32 [[TMP0]], 10
; CHECK-NEXT:    tail call void @__cxa_end_catch() #[[ATTR1]]
; CHECK-NEXT:    invoke void @__cxa_throw(ptr [[EXCEPTION]], ptr @_ZTIi, ptr null) #[[ATTR2]]
; CHECK-NEXT:    to label [[UNREACHABLE]] unwind label [[LPAD]]
; CHECK:       try.cont:
; CHECK-NEXT:    [[K_0:%.*]] = phi i32 [ [[ADD]], [[CATCH]] ], [ 0, [[ENTRY:%.*]] ]
; CHECK-NEXT:    [[BC6:%.*]] = add i32 [[TMP0]], 10
; CHECK-NEXT:    ret i32 [[K_0]]
; CHECK:       unreachable:
; CHECK-NEXT:    [[BC2:%.*]] = add i32 [[TMP0]], 10
; CHECK-NEXT:    ret i32 [[BC2]]
;
entry:
  %0 = load i32, ptr %i, align 4
  %cmp = icmp eq i32 %0, 0
  br i1 %cmp, label %try.cont, label %if.then

if.then:
  %exception = tail call ptr @__cxa_allocate_exception(i64 4) #2
  %1 = bitcast ptr %exception to ptr
  store i32 %0, ptr %1, align 16
  invoke void @__cxa_throw(ptr %exception, ptr @_ZTIi, ptr null) #3
  to label %unreachable unwind label %lpad

lpad:
  %2 = landingpad { ptr, i32 }
  catch ptr @_ZTIi
  catch ptr null
  %bc1 = add i32 %0, 10
  %3 = extractvalue { ptr, i32 } %2, 0
  %4 = extractvalue { ptr, i32 } %2, 1
  %5 = tail call i32 @llvm.eh.typeid.for.p0(ptr @_ZTIi) #2
  %matches = icmp eq i32 %4, %5
  %bc7 = add i32 %0, 10
  %6 = tail call ptr @__cxa_begin_catch(ptr %3) #2
  br i1 %matches, label %catch1, label %catch

catch1:
  %bc3 = add i32 %0, 10
  invoke void @__cxa_rethrow() #3
  to label %unreachable unwind label %lpad4

catch:
  %bc4 = add i32 %0, 10
  %7 = load i32, ptr %i, align 4
  %add = add nsw i32 %7, 1
  tail call void @__cxa_end_catch()
  br label %try.cont

lpad4:
  %8 = landingpad { ptr, i32 }
  cleanup
  %bc5 = add i32 %0, 10
  tail call void @__cxa_end_catch() #2
  invoke void @__cxa_throw(ptr %exception, ptr @_ZTIi, ptr null) #3
  to label %unreachable unwind label %lpad

try.cont:
  %k.0 = phi i32 [ %add, %catch ], [ 0, %entry ]
  %bc6 = add i32 %0, 10
  ret i32 %k.0

unreachable:
  %bc2 = add i32 %0, 10
  ret i32 %bc2
}

declare ptr @__cxa_allocate_exception(i64) local_unnamed_addr

declare void @__cxa_throw(ptr, ptr, ptr) local_unnamed_addr

declare i32 @__gxx_personality_v0(...)

; Function Attrs: nounwind readnone
declare i32 @llvm.eh.typeid.for.p0(ptr) #1

declare ptr @__cxa_begin_catch(ptr) local_unnamed_addr

declare void @__cxa_end_catch() local_unnamed_addr

declare void @__cxa_rethrow() local_unnamed_addr

attributes #1 = { nounwind readnone }
attributes #2 = { nounwind }
attributes #3 = { noreturn }