1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --include-generated-funcs --version 5 2; RUN: opt -passes="ipsccp<func-spec>,deadargelim" -funcspec-for-literal-constant=false -force-specialization -S < %s | FileCheck %s 3; RUN: opt -passes="ipsccp<func-spec>,deadargelim" -funcspec-for-literal-constant=false -funcspec-max-iters=1 -force-specialization -S < %s | FileCheck %s --check-prefix=ONE-ITER 4; RUN: opt -passes="ipsccp<func-spec>,deadargelim" -funcspec-for-literal-constant=false -funcspec-max-iters=0 -force-specialization -S < %s | FileCheck %s --check-prefix=DISABLED 5 6 7define internal i32 @func(ptr %0, i32 %1, ptr nocapture %2) { 8 %4 = alloca i32, align 4 9 store i32 %1, ptr %4, align 4 10 %5 = load i32, ptr %4, align 4 11 %6 = icmp slt i32 %5, 1 12 br i1 %6, label %14, label %7 13 147: ; preds = %3 15 %8 = load i32, ptr %4, align 4 16 %9 = sext i32 %8 to i64 17 %10 = getelementptr inbounds i32, ptr %0, i64 %9 18 call void %2(ptr %10) 19 %11 = load i32, ptr %4, align 4 20 %12 = add nsw i32 %11, -1 21 %13 = call i32 @func(ptr %0, i32 %12, ptr %2) 22 br label %14 23 2414: ; preds = %3, %7 25 ret i32 0 26} 27 28define internal void @increment(ptr nocapture %0) { 29 %2 = load i32, ptr %0, align 4 30 %3 = add nsw i32 %2, 1 31 store i32 %3, ptr %0, align 4 32 ret void 33} 34 35define internal void @decrement(ptr nocapture %0) { 36 %2 = load i32, ptr %0, align 4 37 %3 = add nsw i32 %2, -1 38 store i32 %3, ptr %0, align 4 39 ret void 40} 41 42define i32 @main(ptr %0, i32 %1) { 43 %3 = call i32 @func(ptr %0, i32 %1, ptr nonnull @increment) 44 %4 = call i32 @func(ptr %0, i32 %3, ptr nonnull @decrement) 45 ret i32 %4 46} 47 48; CHECK-LABEL: define internal void @increment( 49; CHECK-SAME: ptr captures(none) [[TMP0:%.*]]) { 50; CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[TMP0]], align 4 51; CHECK-NEXT: [[TMP3:%.*]] = add nsw i32 [[TMP2]], 1 52; CHECK-NEXT: store i32 [[TMP3]], ptr [[TMP0]], align 4 53; CHECK-NEXT: ret void 54; 55; 56; CHECK-LABEL: define internal void @decrement( 57; CHECK-SAME: ptr captures(none) [[TMP0:%.*]]) { 58; CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[TMP0]], align 4 59; CHECK-NEXT: [[TMP3:%.*]] = add nsw i32 [[TMP2]], -1 60; CHECK-NEXT: store i32 [[TMP3]], ptr [[TMP0]], align 4 61; CHECK-NEXT: ret void 62; 63; 64; CHECK-LABEL: define i32 @main( 65; CHECK-SAME: ptr [[TMP0:%.*]], i32 [[TMP1:%.*]]) { 66; CHECK-NEXT: call void @func.specialized.2(ptr [[TMP0]], i32 [[TMP1]]) 67; CHECK-NEXT: call void @func.specialized.1(ptr [[TMP0]], i32 0) 68; CHECK-NEXT: ret i32 0 69; 70; 71; CHECK-LABEL: define internal void @func.specialized.1( 72; CHECK-SAME: ptr [[TMP0:%.*]], i32 [[TMP1:%.*]]) { 73; CHECK-NEXT: [[TMP2:%.*]] = alloca i32, align 4 74; CHECK-NEXT: store i32 [[TMP1]], ptr [[TMP2]], align 4 75; CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[TMP2]], align 4 76; CHECK-NEXT: [[TMP4:%.*]] = icmp slt i32 [[TMP3]], 1 77; CHECK-NEXT: br i1 [[TMP4]], label %[[BB12:.*]], label %[[BB6:.*]] 78; CHECK: [[BB6]]: 79; CHECK-NEXT: [[TMP6:%.*]] = load i32, ptr [[TMP2]], align 4 80; CHECK-NEXT: [[TMP7:%.*]] = sext i32 [[TMP6]] to i64 81; CHECK-NEXT: [[TMP8:%.*]] = getelementptr inbounds i32, ptr [[TMP0]], i64 [[TMP7]] 82; CHECK-NEXT: call void @decrement(ptr [[TMP8]]) 83; CHECK-NEXT: [[TMP9:%.*]] = load i32, ptr [[TMP2]], align 4 84; CHECK-NEXT: [[TMP10:%.*]] = add nsw i32 [[TMP9]], -1 85; CHECK-NEXT: call void @func.specialized.1(ptr [[TMP0]], i32 [[TMP10]]) 86; CHECK-NEXT: br label %[[BB12]] 87; CHECK: [[BB12]]: 88; CHECK-NEXT: ret void 89; 90; 91; CHECK-LABEL: define internal void @func.specialized.2( 92; CHECK-SAME: ptr [[TMP0:%.*]], i32 [[TMP1:%.*]]) { 93; CHECK-NEXT: [[TMP3:%.*]] = alloca i32, align 4 94; CHECK-NEXT: store i32 [[TMP1]], ptr [[TMP3]], align 4 95; CHECK-NEXT: [[TMP4:%.*]] = load i32, ptr [[TMP3]], align 4 96; CHECK-NEXT: [[TMP5:%.*]] = icmp slt i32 [[TMP4]], 1 97; CHECK-NEXT: br i1 [[TMP5]], label %[[BB12:.*]], label %[[BB6:.*]] 98; CHECK: [[BB6]]: 99; CHECK-NEXT: [[TMP7:%.*]] = load i32, ptr [[TMP3]], align 4 100; CHECK-NEXT: [[TMP8:%.*]] = sext i32 [[TMP7]] to i64 101; CHECK-NEXT: [[TMP9:%.*]] = getelementptr inbounds i32, ptr [[TMP0]], i64 [[TMP8]] 102; CHECK-NEXT: call void @increment(ptr [[TMP9]]) 103; CHECK-NEXT: [[TMP10:%.*]] = load i32, ptr [[TMP3]], align 4 104; CHECK-NEXT: [[TMP11:%.*]] = add nsw i32 [[TMP10]], -1 105; CHECK-NEXT: call void @func.specialized.2(ptr [[TMP0]], i32 [[TMP11]]) 106; CHECK-NEXT: br label %[[BB12]] 107; CHECK: [[BB12]]: 108; CHECK-NEXT: ret void 109; 110; 111; ONE-ITER-LABEL: define internal void @increment( 112; ONE-ITER-SAME: ptr captures(none) [[TMP0:%.*]]) { 113; ONE-ITER-NEXT: [[TMP2:%.*]] = load i32, ptr [[TMP0]], align 4 114; ONE-ITER-NEXT: [[TMP3:%.*]] = add nsw i32 [[TMP2]], 1 115; ONE-ITER-NEXT: store i32 [[TMP3]], ptr [[TMP0]], align 4 116; ONE-ITER-NEXT: ret void 117; 118; 119; ONE-ITER-LABEL: define internal void @decrement( 120; ONE-ITER-SAME: ptr captures(none) [[TMP0:%.*]]) { 121; ONE-ITER-NEXT: [[TMP2:%.*]] = load i32, ptr [[TMP0]], align 4 122; ONE-ITER-NEXT: [[TMP3:%.*]] = add nsw i32 [[TMP2]], -1 123; ONE-ITER-NEXT: store i32 [[TMP3]], ptr [[TMP0]], align 4 124; ONE-ITER-NEXT: ret void 125; 126; 127; ONE-ITER-LABEL: define i32 @main( 128; ONE-ITER-SAME: ptr [[TMP0:%.*]], i32 [[TMP1:%.*]]) { 129; ONE-ITER-NEXT: call void @func.specialized.2(ptr [[TMP0]], i32 [[TMP1]]) 130; ONE-ITER-NEXT: call void @func.specialized.1(ptr [[TMP0]], i32 0) 131; ONE-ITER-NEXT: ret i32 0 132; 133; 134; ONE-ITER-LABEL: define internal void @func.specialized.1( 135; ONE-ITER-SAME: ptr [[TMP0:%.*]], i32 [[TMP1:%.*]]) { 136; ONE-ITER-NEXT: [[TMP2:%.*]] = alloca i32, align 4 137; ONE-ITER-NEXT: store i32 [[TMP1]], ptr [[TMP2]], align 4 138; ONE-ITER-NEXT: [[TMP3:%.*]] = load i32, ptr [[TMP2]], align 4 139; ONE-ITER-NEXT: [[TMP4:%.*]] = icmp slt i32 [[TMP3]], 1 140; ONE-ITER-NEXT: br i1 [[TMP4]], label %[[BB12:.*]], label %[[BB6:.*]] 141; ONE-ITER: [[BB6]]: 142; ONE-ITER-NEXT: [[TMP6:%.*]] = load i32, ptr [[TMP2]], align 4 143; ONE-ITER-NEXT: [[TMP7:%.*]] = sext i32 [[TMP6]] to i64 144; ONE-ITER-NEXT: [[TMP8:%.*]] = getelementptr inbounds i32, ptr [[TMP0]], i64 [[TMP7]] 145; ONE-ITER-NEXT: call void @decrement(ptr [[TMP8]]) 146; ONE-ITER-NEXT: [[TMP9:%.*]] = load i32, ptr [[TMP2]], align 4 147; ONE-ITER-NEXT: [[TMP10:%.*]] = add nsw i32 [[TMP9]], -1 148; ONE-ITER-NEXT: call void @func.specialized.1(ptr [[TMP0]], i32 [[TMP10]]) 149; ONE-ITER-NEXT: br label %[[BB12]] 150; ONE-ITER: [[BB12]]: 151; ONE-ITER-NEXT: ret void 152; 153; 154; ONE-ITER-LABEL: define internal void @func.specialized.2( 155; ONE-ITER-SAME: ptr [[TMP0:%.*]], i32 [[TMP1:%.*]]) { 156; ONE-ITER-NEXT: [[TMP3:%.*]] = alloca i32, align 4 157; ONE-ITER-NEXT: store i32 [[TMP1]], ptr [[TMP3]], align 4 158; ONE-ITER-NEXT: [[TMP4:%.*]] = load i32, ptr [[TMP3]], align 4 159; ONE-ITER-NEXT: [[TMP5:%.*]] = icmp slt i32 [[TMP4]], 1 160; ONE-ITER-NEXT: br i1 [[TMP5]], label %[[BB12:.*]], label %[[BB6:.*]] 161; ONE-ITER: [[BB6]]: 162; ONE-ITER-NEXT: [[TMP7:%.*]] = load i32, ptr [[TMP3]], align 4 163; ONE-ITER-NEXT: [[TMP8:%.*]] = sext i32 [[TMP7]] to i64 164; ONE-ITER-NEXT: [[TMP9:%.*]] = getelementptr inbounds i32, ptr [[TMP0]], i64 [[TMP8]] 165; ONE-ITER-NEXT: call void @increment(ptr [[TMP9]]) 166; ONE-ITER-NEXT: [[TMP10:%.*]] = load i32, ptr [[TMP3]], align 4 167; ONE-ITER-NEXT: [[TMP11:%.*]] = add nsw i32 [[TMP10]], -1 168; ONE-ITER-NEXT: call void @func.specialized.2(ptr [[TMP0]], i32 [[TMP11]]) 169; ONE-ITER-NEXT: br label %[[BB12]] 170; ONE-ITER: [[BB12]]: 171; ONE-ITER-NEXT: ret void 172; 173; 174; DISABLED-LABEL: define internal void @func( 175; DISABLED-SAME: ptr [[TMP0:%.*]], i32 [[TMP1:%.*]], ptr captures(none) [[TMP2:%.*]]) { 176; DISABLED-NEXT: [[TMP4:%.*]] = alloca i32, align 4 177; DISABLED-NEXT: store i32 [[TMP1]], ptr [[TMP4]], align 4 178; DISABLED-NEXT: [[TMP5:%.*]] = load i32, ptr [[TMP4]], align 4 179; DISABLED-NEXT: [[TMP6:%.*]] = icmp slt i32 [[TMP5]], 1 180; DISABLED-NEXT: br i1 [[TMP6]], label %[[BB13:.*]], label %[[BB7:.*]] 181; DISABLED: [[BB7]]: 182; DISABLED-NEXT: [[TMP8:%.*]] = load i32, ptr [[TMP4]], align 4 183; DISABLED-NEXT: [[TMP9:%.*]] = sext i32 [[TMP8]] to i64 184; DISABLED-NEXT: [[TMP10:%.*]] = getelementptr inbounds i32, ptr [[TMP0]], i64 [[TMP9]] 185; DISABLED-NEXT: call void [[TMP2]](ptr [[TMP10]]) 186; DISABLED-NEXT: [[TMP11:%.*]] = load i32, ptr [[TMP4]], align 4 187; DISABLED-NEXT: [[TMP12:%.*]] = add nsw i32 [[TMP11]], -1 188; DISABLED-NEXT: call void @func(ptr [[TMP0]], i32 [[TMP12]], ptr [[TMP2]]) 189; DISABLED-NEXT: br label %[[BB13]] 190; DISABLED: [[BB13]]: 191; DISABLED-NEXT: ret void 192; 193; 194; DISABLED-LABEL: define internal void @increment( 195; DISABLED-SAME: ptr captures(none) [[TMP0:%.*]]) { 196; DISABLED-NEXT: [[TMP2:%.*]] = load i32, ptr [[TMP0]], align 4 197; DISABLED-NEXT: [[TMP3:%.*]] = add nsw i32 [[TMP2]], 1 198; DISABLED-NEXT: store i32 [[TMP3]], ptr [[TMP0]], align 4 199; DISABLED-NEXT: ret void 200; 201; 202; DISABLED-LABEL: define internal void @decrement( 203; DISABLED-SAME: ptr captures(none) [[TMP0:%.*]]) { 204; DISABLED-NEXT: [[TMP2:%.*]] = load i32, ptr [[TMP0]], align 4 205; DISABLED-NEXT: [[TMP3:%.*]] = add nsw i32 [[TMP2]], -1 206; DISABLED-NEXT: store i32 [[TMP3]], ptr [[TMP0]], align 4 207; DISABLED-NEXT: ret void 208; 209; 210; DISABLED-LABEL: define i32 @main( 211; DISABLED-SAME: ptr [[TMP0:%.*]], i32 [[TMP1:%.*]]) { 212; DISABLED-NEXT: call void @func(ptr [[TMP0]], i32 [[TMP1]], ptr nonnull @increment) 213; DISABLED-NEXT: call void @func(ptr [[TMP0]], i32 0, ptr nonnull @decrement) 214; DISABLED-NEXT: ret i32 0 215; 216