llvm/llvm/test/Transforms/SCCP/resolvedundefsin-tracked-fn.ll

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature
; RUN: opt -passes=ipsccp -S %s | FileCheck %s

%t1 = type opaque

@e = common global i32 0, align 4

; Test that we a skip unknown values depending on a unknown tracked call, until the call gets resolved. The @test1 and @test2 variants are very similar, they just check 2 different kinds of users (icmp and zext)

define i32 @test1_m(i32 %h) {
; CHECK-LABEL: define {{[^@]+}}@test1_m
; CHECK-SAME: (i32 [[H:%.*]]) {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[CONV:%.*]] = trunc i32 [[H]] to i8
; CHECK-NEXT:    [[CALL:%.*]] = call i32 @test1_k(i8 [[CONV]], i32 0)
; CHECK-NEXT:    [[CONV1:%.*]] = sext i32 [[H]] to i64
; CHECK-NEXT:    [[TMP0:%.*]] = inttoptr i64 [[CONV1]] to ptr
; CHECK-NEXT:    [[CALL2:%.*]] = call i1 @test1_g(ptr [[TMP0]], i32 1)
; CHECK-NEXT:    ret i32 undef
;
entry:
  %conv = trunc i32 %h to i8
  %call = call i32 @test1_k(i8 %conv, i32 0)
  %conv1 = sext i32 %h to i64
  %0 = inttoptr i64 %conv1 to ptr
  %call2 = call i1 @test1_g(ptr %0, i32 1)
  ret i32 undef

; uselistorder directives
  uselistorder i32 %h, { 1, 0 }
}

declare void @use.1(i1)

define internal i32 @test1_k(i8 %h, i32 %i) {
; CHECK-LABEL: define {{[^@]+}}@test1_k
; CHECK-SAME: (i8 [[H:%.*]], i32 [[I:%.*]]) {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[TMP0:%.*]] = load i32, ptr @e, align 4
; CHECK-NEXT:    [[CONV:%.*]] = sext i32 [[TMP0]] to i64
; CHECK-NEXT:    [[TMP1:%.*]] = inttoptr i64 [[CONV]] to ptr
; CHECK-NEXT:    [[CALL:%.*]] = call i1 @test1_g(ptr [[TMP1]], i32 0)
; CHECK-NEXT:    call void @use.1(i1 false)
; CHECK-NEXT:    ret i32 undef
;
entry:
  %0 = load i32, ptr @e, align 4
  %conv = sext i32 %0 to i64
  %1 = inttoptr i64 %conv to ptr
  %call = call i1 @test1_g(ptr %1, i32 %i)
  %frombool.1 = zext i1 %call to i8
  %tobool.1 = trunc i8 %frombool.1 to i1
  call void @use.1(i1 %tobool.1)
  ret i32 undef
}

define internal i1 @test1_g(ptr %h, i32 %i) #0 {
; CHECK-LABEL: define {{[^@]+}}@test1_g
; CHECK-SAME: (ptr [[H:%.*]], i32 [[I:%.*]]) {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp ne i32 [[I]], 0
; CHECK-NEXT:    br i1 [[TOBOOL]], label [[LAND_RHS:%.*]], label [[LAND_END:%.*]]
; CHECK:       land.rhs:
; CHECK-NEXT:    [[CALL:%.*]] = call i32 (...) @test1_j()
; CHECK-NEXT:    [[TOBOOL1:%.*]] = icmp ne i32 [[CALL]], 0
; CHECK-NEXT:    br label [[LAND_END]]
; CHECK:       land.end:
; CHECK-NEXT:    [[TMP0:%.*]] = phi i1 [ false, [[ENTRY:%.*]] ], [ [[TOBOOL1]], [[LAND_RHS]] ]
; CHECK-NEXT:    ret i1 poison
;
entry:
  %tobool = icmp ne i32 %i, 0
  br i1 %tobool, label %land.rhs, label %land.end

land.rhs:                                         ; preds = %entry
  %call = call i32 (...) @test1_j()
  %tobool1 = icmp ne i32 %call, 0
  br label %land.end

land.end:                                         ; preds = %land.rhs, %entry
  %0 = phi i1 [ false, %entry ], [ %tobool1, %land.rhs ]
  ret i1 false
}

declare i32 @test1_j(...)

define i32 @test2_m(i32 %h) #0 {
; CHECK-LABEL: define {{[^@]+}}@test2_m
; CHECK-SAME: (i32 [[H:%.*]]) {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[CONV:%.*]] = trunc i32 [[H]] to i8
; CHECK-NEXT:    [[CALL:%.*]] = call i32 @test2_k(i8 [[CONV]], i32 0)
; CHECK-NEXT:    [[CONV1:%.*]] = sext i32 [[H]] to i64
; CHECK-NEXT:    [[TMP0:%.*]] = inttoptr i64 [[CONV1]] to ptr
; CHECK-NEXT:    [[CALL2:%.*]] = call i1 @test2_g(ptr [[TMP0]], i32 1)
; CHECK-NEXT:    ret i32 undef
;
entry:
  %conv = trunc i32 %h to i8
  %call = call i32 @test2_k(i8 %conv, i32 0)
  %conv1 = sext i32 %h to i64
  %0 = inttoptr i64 %conv1 to ptr
  %call2 = call i1 @test2_g(ptr %0, i32 1)
  ret i32 undef

; uselistorder directives
  uselistorder i32 %h, { 1, 0 }
}

; TODO: We could do better for the return value of call i1 @test3_g, if we
;       resolve the unknown values there first.
define internal i32 @test2_k(i8 %h, i32 %i) {
; CHECK-LABEL: define {{[^@]+}}@test2_k
; CHECK-SAME: (i8 [[H:%.*]], i32 [[I:%.*]]) {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[TMP0:%.*]] = load i32, ptr @e, align 4
; CHECK-NEXT:    [[CONV:%.*]] = sext i32 [[TMP0]] to i64
; CHECK-NEXT:    [[TMP1:%.*]] = inttoptr i64 [[CONV]] to ptr
; CHECK-NEXT:    [[CALL:%.*]] = call i1 @test3_g(ptr [[TMP1]], i32 0)
; CHECK-NEXT:    call void @use.1(i1 false)
; CHECK-NEXT:    ret i32 undef
;
entry:
  %0 = load i32, ptr @e, align 4
  %conv = sext i32 %0 to i64
  %1 = inttoptr i64 %conv to ptr
  %call = call i1 @test3_g(ptr %1, i32 %i)
  %frombool = icmp slt i1 %call, 1
  %add = add i1 %frombool, %frombool
  call void @use.1(i1 %frombool)
  ret i32 undef

}

define internal i1 @test2_g(ptr %h, i32 %i) {
; CHECK-LABEL: define {{[^@]+}}@test2_g
; CHECK-SAME: (ptr [[H:%.*]], i32 [[I:%.*]]) {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    br label [[LAND_RHS:%.*]]
; CHECK:       land.rhs:
; CHECK-NEXT:    [[CALL:%.*]] = call i32 (...) @test2_j()
; CHECK-NEXT:    [[TOBOOL1:%.*]] = icmp ne i32 [[CALL]], 0
; CHECK-NEXT:    br label [[LAND_END:%.*]]
; CHECK:       land.end:
; CHECK-NEXT:    ret i1 poison
;
entry:
  %tobool = icmp ne i32 %i, 0
  br i1 %tobool, label %land.rhs, label %land.end

land.rhs:                                         ; preds = %entry
  %call = call i32 (...) @test2_j()
  %tobool1 = icmp ne i32 %call, 0
  br label %land.end

land.end:                                         ; preds = %land.rhs, %entry
  %0 = phi i1 [ false, %entry ], [ %tobool1, %land.rhs ]
  ret i1 false
}

declare i32 @test2_j(...)



; Same as test_2*, but with a PHI node depending on a tracked  call result.
define i32 @test3_m(i32 %h) #0 {
; CHECK-LABEL: define {{[^@]+}}@test3_m
; CHECK-SAME: (i32 [[H:%.*]]) {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[CONV:%.*]] = trunc i32 [[H]] to i8
; CHECK-NEXT:    [[CALL:%.*]] = call i32 @test3_k(i8 [[CONV]], i32 0)
; CHECK-NEXT:    [[CONV1:%.*]] = sext i32 [[H]] to i64
; CHECK-NEXT:    [[TMP0:%.*]] = inttoptr i64 [[CONV1]] to ptr
; CHECK-NEXT:    [[CALL2:%.*]] = call i1 @test3_g(ptr [[TMP0]], i32 1)
; CHECK-NEXT:    ret i32 undef
;
entry:
  %conv = trunc i32 %h to i8
  %call = call i32 @test3_k(i8 %conv, i32 0)
  %conv1 = sext i32 %h to i64
  %0 = inttoptr i64 %conv1 to ptr
  %call2 = call i1 @test3_g(ptr %0, i32 1)
  ret i32 undef

; uselistorder directives
  uselistorder i32 %h, { 1, 0 }
}

define internal i32 @test3_k(i8 %h, i32 %i) {
; CHECK-LABEL: define {{[^@]+}}@test3_k
; CHECK-SAME: (i8 [[H:%.*]], i32 [[I:%.*]]) {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[TMP0:%.*]] = load i32, ptr @e, align 4
; CHECK-NEXT:    [[CONV:%.*]] = sext i32 [[TMP0]] to i64
; CHECK-NEXT:    [[TMP1:%.*]] = inttoptr i64 [[CONV]] to ptr
; CHECK-NEXT:    br label [[LOOP:%.*]]
; CHECK:       loop:
; CHECK-NEXT:    [[CALL:%.*]] = call i1 @test3_g(ptr [[TMP1]], i32 0)
; CHECK-NEXT:    call void @use.1(i1 false)
; CHECK-NEXT:    br label [[EXIT:%.*]]
; CHECK:       exit:
; CHECK-NEXT:    ret i32 undef
;
entry:
  %0 = load i32, ptr @e, align 4
  %conv = sext i32 %0 to i64
  %1 = inttoptr i64 %conv to ptr
  br label %loop

loop:
  %phi = phi i1 [ undef, %entry], [ %call, %loop ]
  %call = call i1 @test3_g(ptr %1, i32 %i)
  %frombool = icmp slt i1 %call, 1
  %add = add i1 %frombool, %frombool
  call void @use.1(i1 %frombool)
  br i1 %call, label %loop, label %exit

exit:
  ret i32 undef
}

define internal i1 @test3_g(ptr %h, i32 %i) {
; CHECK-LABEL: define {{[^@]+}}@test3_g
; CHECK-SAME: (ptr [[H:%.*]], i32 [[I:%.*]]) {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp ne i32 [[I]], 0
; CHECK-NEXT:    br i1 [[TOBOOL]], label [[LAND_RHS:%.*]], label [[LAND_END:%.*]]
; CHECK:       land.rhs:
; CHECK-NEXT:    [[CALL:%.*]] = call i32 (...) @test3_j()
; CHECK-NEXT:    [[TOBOOL1:%.*]] = icmp ne i32 [[CALL]], 0
; CHECK-NEXT:    br label [[LAND_END]]
; CHECK:       land.end:
; CHECK-NEXT:    [[TMP0:%.*]] = phi i1 [ false, [[ENTRY:%.*]] ], [ [[TOBOOL1]], [[LAND_RHS]] ]
; CHECK-NEXT:    ret i1 poison
;
entry:
  %tobool = icmp ne i32 %i, 0
  br i1 %tobool, label %land.rhs, label %land.end

land.rhs:                                         ; preds = %entry
  %call = call i32 (...) @test3_j()
  %tobool1 = icmp ne i32 %call, 0
  br label %land.end

land.end:                                         ; preds = %land.rhs, %entry
  %0 = phi i1 [ false, %entry ], [ %tobool1, %land.rhs ]
  ret i1 false
}

declare i32 @test3_j(...)


; TODO: We can eliminate the bitcast, if we resolve the unknown argument of
;       @test4_b first.

declare void @use.16(ptr)
declare void @use.8(ptr)

define void @test4_a() {
; CHECK-LABEL: define {{[^@]+}}@test4_a() {
; CHECK-NEXT:  bb:
; CHECK-NEXT:    [[TMP:%.*]] = call ptr @test4_c(ptr null)
; CHECK-NEXT:    call void @test4_b(ptr null)
; CHECK-NEXT:    ret void
;
bb:
  %tmp = call ptr @test4_c(ptr null)
  call void @test4_b(ptr %tmp)
  ret void
}

define internal void @test4_b(ptr %arg) {
; CHECK-LABEL: define {{[^@]+}}@test4_b
; CHECK-SAME: (ptr [[ARG:%.*]]) {
; CHECK-NEXT:  bb:
; CHECK-NEXT:    [[SEL:%.*]] = select i1 false, ptr null, ptr null
; CHECK-NEXT:    call void @use.16(ptr null)
; CHECK-NEXT:    call void @use.8(ptr [[SEL]])
; CHECK-NEXT:    ret void
;
bb:
  %sel = select i1 false, ptr %arg, ptr %arg
  call void @use.16(ptr %arg)
  call void @use.8(ptr %sel)
  ret void
}

define internal ptr @test4_c(ptr %arg) {
; CHECK-LABEL: define {{[^@]+}}@test4_c
; CHECK-SAME: (ptr [[ARG:%.*]]) {
; CHECK-NEXT:  bb1:
; CHECK-NEXT:    [[TMP:%.*]] = and i1 undef, undef
; CHECK-NEXT:    br i1 [[TMP]], label [[BB3:%.*]], label [[BB2:%.*]]
; CHECK:       bb2:
; CHECK-NEXT:    unreachable
; CHECK:       bb3:
; CHECK-NEXT:    ret ptr poison
;
bb1:                                              ; preds = %bb
  %tmp = and i1 undef, undef
  br i1 %tmp, label %bb3, label %bb2

bb2:                                              ; preds = %bb1
  unreachable

bb3:                                              ; preds = %bb1
  ret ptr null
}

; TODO: Same as test4, but with a select instead of a bitcast.

define void @test5_a() {
; CHECK-LABEL: define {{[^@]+}}@test5_a() {
; CHECK-NEXT:  bb:
; CHECK-NEXT:    [[TMP:%.*]] = call ptr @test5_c(ptr null)
; CHECK-NEXT:    call void @test5_b(ptr null)
; CHECK-NEXT:    ret void
;
bb:
  %tmp = call ptr @test5_c(ptr null)
  call void @test5_b(ptr %tmp)
  ret void
}

define internal void @test5_b(ptr %arg) {
; CHECK-LABEL: define {{[^@]+}}@test5_b
; CHECK-SAME: (ptr [[ARG:%.*]]) {
; CHECK-NEXT:  bb:
; CHECK-NEXT:    [[SEL:%.*]] = select i1 false, ptr null, ptr null
; CHECK-NEXT:    call void @use.8(ptr [[SEL]])
; CHECK-NEXT:    ret void
;
bb:
  %sel = select i1 false, ptr %arg, ptr %arg
  call void @use.8(ptr %sel)
  ret void
}

define internal ptr @test5_c(ptr %arg) {
; CHECK-LABEL: define {{[^@]+}}@test5_c
; CHECK-SAME: (ptr [[ARG:%.*]]) {
; CHECK-NEXT:  bb1:
; CHECK-NEXT:    [[TMP:%.*]] = and i1 undef, undef
; CHECK-NEXT:    br i1 [[TMP]], label [[BB3:%.*]], label [[BB2:%.*]]
; CHECK:       bb2:
; CHECK-NEXT:    unreachable
; CHECK:       bb3:
; CHECK-NEXT:    ret ptr poison
;
bb1:                                              ; preds = %bb
  %tmp = and i1 undef, undef
  br i1 %tmp, label %bb3, label %bb2

bb2:                                              ; preds = %bb1
  unreachable

bb3:                                              ; preds = %bb1
  ret ptr null
}



@contextsize = external dso_local local_unnamed_addr global i32, align 4
@pcount = internal local_unnamed_addr global i32 0, align 4
@maxposslen = external dso_local local_unnamed_addr global i32, align 4

define void @test3() {
; CHECK-LABEL: define {{[^@]+}}@test3() {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    br label [[IF_END16:%.*]]
; CHECK:       if.end16:
; CHECK-NEXT:    [[TMP0:%.*]] = load i32, ptr @contextsize, align 4
; CHECK-NEXT:    [[SUB18:%.*]] = sub i32 undef, [[TMP0]]
; CHECK-NEXT:    [[SUB19:%.*]] = sub i32 [[SUB18]], undef
; CHECK-NEXT:    [[TMP1:%.*]] = load i32, ptr @maxposslen, align 4
; CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 [[TMP1]], 8
; CHECK-NEXT:    [[DIV:%.*]] = sdiv i32 undef, [[ADD]]
; CHECK-NEXT:    [[TMP2:%.*]] = load i32, ptr @pcount, align 4
; CHECK-NEXT:    [[MUL:%.*]] = mul nsw i32 [[DIV]], [[SUB19]]
; CHECK-NEXT:    [[CMP20:%.*]] = icmp sgt i32 [[TMP2]], [[MUL]]
; CHECK-NEXT:    br i1 [[CMP20]], label [[IF_THEN22:%.*]], label [[IF_END24:%.*]]
; CHECK:       if.then22:
; CHECK-NEXT:    store i32 [[MUL]], ptr @pcount, align 4
; CHECK-NEXT:    ret void
; CHECK:       if.end24:
; CHECK-NEXT:    [[CMP25474:%.*]] = icmp sgt i32 [[TMP2]], 0
; CHECK-NEXT:    br i1 [[CMP25474]], label [[FOR_BODY:%.*]], label [[FOR_END:%.*]]
; CHECK:       for.body:
; CHECK-NEXT:    ret void
; CHECK:       for.end:
; CHECK-NEXT:    ret void
;
entry:
  br label %if.end16

if.end16:                                         ; preds = %entry
  %0 = load i32, ptr @contextsize, align 4
  %sub18 = sub i32 undef, %0
  %sub19 = sub i32 %sub18, undef
  %1 = load i32, ptr @maxposslen, align 4
  %add = add nsw i32 %1, 8
  %div = sdiv i32 undef, %add
  %2 = load i32, ptr @pcount, align 4
  %mul = mul nsw i32 %div, %sub19
  %cmp20 = icmp sgt i32 %2, %mul
  br i1 %cmp20, label %if.then22, label %if.end24

if.then22:                                        ; preds = %if.end16
  store i32 %mul, ptr @pcount, align 4
  ret void

if.end24:                                         ; preds = %if.end16
  %cmp25474 = icmp sgt i32 %2, 0
  br i1 %cmp25474, label %for.body, label %for.end

for.body:                                         ; preds = %if.end24
  %3 = trunc i64 0 to i32
  %div30 = sdiv i32 %3, %sub19
  ret void

for.end:                                          ; preds = %if.end24
  ret void
}