1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --include-generated-funcs 2; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s 3 4; Here we have multiple exits, but the different sources, different outputs are 5; needed, this checks that they are handled by separate switch statements. 6 7define void @outline_outputs1() #0 { 8entry: 9 %output = alloca i32, align 4 10 %result = alloca i32, align 4 11 %output2 = alloca i32, align 4 12 %result2 = alloca i32, align 4 13 %a = alloca i32, align 4 14 %b = alloca i32, align 4 15 br label %block_2 16block_1: 17 %a2 = alloca i32, align 4 18 %b2 = alloca i32, align 4 19 br label %block_2 20block_2: 21 %a2val = load i32, ptr %a 22 %b2val = load i32, ptr %b 23 %add2 = add i32 2, %a2val 24 %mul2 = mul i32 2, %b2val 25 br label %block_5 26block_3: 27 %aval = load i32, ptr %a 28 %bval = load i32, ptr %b 29 %add = add i32 2, %aval 30 %mul = mul i32 2, %bval 31 br label %block_4 32block_4: 33 store i32 %add, ptr %output, align 4 34 store i32 %mul, ptr %result, align 4 35 br label %block_6 36block_5: 37 store i32 %add2, ptr %output, align 4 38 store i32 %mul2, ptr %result, align 4 39 br label %block_7 40block_6: 41 %div = udiv i32 %aval, %bval 42 ret void 43block_7: 44 %sub = sub i32 %a2val, %b2val 45 ret void 46} 47 48define void @outline_outputs2() #0 { 49entry: 50 %output = alloca i32, align 4 51 %result = alloca i32, align 4 52 %output2 = alloca i32, align 4 53 %result2 = alloca i32, align 4 54 %a = alloca i32, align 4 55 %b = alloca i32, align 4 56 br label %block_2 57block_1: 58 %a2 = alloca i32, align 4 59 %b2 = alloca i32, align 4 60 br label %block_2 61block_2: 62 %a2val = load i32, ptr %a 63 %b2val = load i32, ptr %b 64 %add2 = add i32 2, %a2val 65 %mul2 = mul i32 2, %b2val 66 br label %block_5 67block_3: 68 %aval = load i32, ptr %a 69 %bval = load i32, ptr %b 70 %add = add i32 2, %aval 71 %mul = mul i32 2, %bval 72 br label %block_4 73block_4: 74 store i32 %add, ptr %output, align 4 75 store i32 %mul, ptr %result, align 4 76 br label %block_7 77block_5: 78 store i32 %add2, ptr %output, align 4 79 store i32 %mul2, ptr %result, align 4 80 br label %block_6 81block_6: 82 %diff = sub i32 %a2val, %b2val 83 ret void 84block_7: 85 %quot = udiv i32 %add, %mul 86 ret void 87} 88; CHECK-LABEL: @outline_outputs1( 89; CHECK-NEXT: entry: 90; CHECK-NEXT: [[BVAL_LOC:%.*]] = alloca i32, align 4 91; CHECK-NEXT: [[AVAL_LOC:%.*]] = alloca i32, align 4 92; CHECK-NEXT: [[B2VAL_LOC:%.*]] = alloca i32, align 4 93; CHECK-NEXT: [[A2VAL_LOC:%.*]] = alloca i32, align 4 94; CHECK-NEXT: [[OUTPUT:%.*]] = alloca i32, align 4 95; CHECK-NEXT: [[RESULT:%.*]] = alloca i32, align 4 96; CHECK-NEXT: [[OUTPUT2:%.*]] = alloca i32, align 4 97; CHECK-NEXT: [[RESULT2:%.*]] = alloca i32, align 4 98; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 99; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4 100; CHECK-NEXT: br label [[BLOCK_2:%.*]] 101; CHECK: block_1: 102; CHECK-NEXT: [[A2:%.*]] = alloca i32, align 4 103; CHECK-NEXT: [[B2:%.*]] = alloca i32, align 4 104; CHECK-NEXT: br label [[BLOCK_2]] 105; CHECK: block_2: 106; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 -1, ptr [[A2VAL_LOC]]) 107; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 -1, ptr [[B2VAL_LOC]]) 108; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 -1, ptr [[AVAL_LOC]]) 109; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 -1, ptr [[BVAL_LOC]]) 110; CHECK-NEXT: [[TMP0:%.*]] = call i1 @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[OUTPUT]], ptr [[RESULT]], ptr [[A2VAL_LOC]], ptr [[B2VAL_LOC]], ptr [[AVAL_LOC]], ptr [[BVAL_LOC]], i32 0) 111; CHECK-NEXT: [[A2VAL_RELOAD:%.*]] = load i32, ptr [[A2VAL_LOC]], align 4 112; CHECK-NEXT: [[B2VAL_RELOAD:%.*]] = load i32, ptr [[B2VAL_LOC]], align 4 113; CHECK-NEXT: [[AVAL_RELOAD:%.*]] = load i32, ptr [[AVAL_LOC]], align 4 114; CHECK-NEXT: [[BVAL_RELOAD:%.*]] = load i32, ptr [[BVAL_LOC]], align 4 115; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 -1, ptr [[A2VAL_LOC]]) 116; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 -1, ptr [[B2VAL_LOC]]) 117; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 -1, ptr [[AVAL_LOC]]) 118; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 -1, ptr [[BVAL_LOC]]) 119; CHECK-NEXT: br i1 [[TMP0]], label [[BLOCK_6:%.*]], label [[BLOCK_7:%.*]] 120; CHECK: block_6: 121; CHECK-NEXT: [[DIV:%.*]] = udiv i32 [[AVAL_RELOAD]], [[BVAL_RELOAD]] 122; CHECK-NEXT: ret void 123; CHECK: block_7: 124; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[A2VAL_RELOAD]], [[B2VAL_RELOAD]] 125; CHECK-NEXT: ret void 126; 127; 128; CHECK-LABEL: @outline_outputs2( 129; CHECK-NEXT: entry: 130; CHECK-NEXT: [[MUL_LOC:%.*]] = alloca i32, align 4 131; CHECK-NEXT: [[ADD_LOC:%.*]] = alloca i32, align 4 132; CHECK-NEXT: [[B2VAL_LOC:%.*]] = alloca i32, align 4 133; CHECK-NEXT: [[A2VAL_LOC:%.*]] = alloca i32, align 4 134; CHECK-NEXT: [[OUTPUT:%.*]] = alloca i32, align 4 135; CHECK-NEXT: [[RESULT:%.*]] = alloca i32, align 4 136; CHECK-NEXT: [[OUTPUT2:%.*]] = alloca i32, align 4 137; CHECK-NEXT: [[RESULT2:%.*]] = alloca i32, align 4 138; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 139; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4 140; CHECK-NEXT: br label [[BLOCK_2:%.*]] 141; CHECK: block_1: 142; CHECK-NEXT: [[A2:%.*]] = alloca i32, align 4 143; CHECK-NEXT: [[B2:%.*]] = alloca i32, align 4 144; CHECK-NEXT: br label [[BLOCK_2]] 145; CHECK: block_2: 146; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 -1, ptr [[A2VAL_LOC]]) 147; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 -1, ptr [[B2VAL_LOC]]) 148; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 -1, ptr [[ADD_LOC]]) 149; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 -1, ptr [[MUL_LOC]]) 150; CHECK-NEXT: [[TMP0:%.*]] = call i1 @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[OUTPUT]], ptr [[RESULT]], ptr [[A2VAL_LOC]], ptr [[B2VAL_LOC]], ptr [[ADD_LOC]], ptr [[MUL_LOC]], i32 1) 151; CHECK-NEXT: [[A2VAL_RELOAD:%.*]] = load i32, ptr [[A2VAL_LOC]], align 4 152; CHECK-NEXT: [[B2VAL_RELOAD:%.*]] = load i32, ptr [[B2VAL_LOC]], align 4 153; CHECK-NEXT: [[ADD_RELOAD:%.*]] = load i32, ptr [[ADD_LOC]], align 4 154; CHECK-NEXT: [[MUL_RELOAD:%.*]] = load i32, ptr [[MUL_LOC]], align 4 155; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 -1, ptr [[A2VAL_LOC]]) 156; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 -1, ptr [[B2VAL_LOC]]) 157; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 -1, ptr [[ADD_LOC]]) 158; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 -1, ptr [[MUL_LOC]]) 159; CHECK-NEXT: br i1 [[TMP0]], label [[BLOCK_7:%.*]], label [[BLOCK_6:%.*]] 160; CHECK: block_6: 161; CHECK-NEXT: [[DIFF:%.*]] = sub i32 [[A2VAL_RELOAD]], [[B2VAL_RELOAD]] 162; CHECK-NEXT: ret void 163; CHECK: block_7: 164; CHECK-NEXT: [[QUOT:%.*]] = udiv i32 [[ADD_RELOAD]], [[MUL_RELOAD]] 165; CHECK-NEXT: ret void 166; 167; 168; CHECK: define internal i1 @outlined_ir_func_0( 169; CHECK-NEXT: newFuncRoot: 170; CHECK-NEXT: br label [[BLOCK_2_TO_OUTLINE:%.*]] 171; CHECK: block_2_to_outline: 172; CHECK-NEXT: [[A2VAL:%.*]] = load i32, ptr [[TMP0:%.*]], align 4 173; CHECK-NEXT: [[B2VAL:%.*]] = load i32, ptr [[TMP1:%.*]], align 4 174; CHECK-NEXT: [[ADD2:%.*]] = add i32 2, [[A2VAL]] 175; CHECK-NEXT: [[MUL2:%.*]] = mul i32 2, [[B2VAL]] 176; CHECK-NEXT: br label [[BLOCK_5:%.*]] 177; CHECK: block_3: 178; CHECK-NEXT: [[AVAL:%.*]] = load i32, ptr [[TMP0]], align 4 179; CHECK-NEXT: [[BVAL:%.*]] = load i32, ptr [[TMP1]], align 4 180; CHECK-NEXT: [[ADD:%.*]] = add i32 2, [[AVAL]] 181; CHECK-NEXT: [[MUL:%.*]] = mul i32 2, [[BVAL]] 182; CHECK-NEXT: br label [[BLOCK_4:%.*]] 183; CHECK: block_4: 184; CHECK-NEXT: store i32 [[ADD]], ptr [[TMP2:%.*]], align 4 185; CHECK-NEXT: store i32 [[MUL]], ptr [[TMP3:%.*]], align 4 186; CHECK-NEXT: br label [[BLOCK_6_EXITSTUB:%.*]] 187; CHECK: block_5: 188; CHECK-NEXT: store i32 [[ADD2]], ptr [[TMP2]], align 4 189; CHECK-NEXT: store i32 [[MUL2]], ptr [[TMP3]], align 4 190; CHECK-NEXT: br label [[BLOCK_7_EXITSTUB:%.*]] 191; CHECK: block_6.exitStub: 192; CHECK-NEXT: switch i32 [[TMP8:%.*]], label [[FINAL_BLOCK_1:%.*]] [ 193; CHECK-NEXT: i32 0, label [[OUTPUT_BLOCK_0_1:%.*]] 194; CHECK-NEXT: i32 1, label [[OUTPUT_BLOCK_1_1:%.*]] 195; CHECK-NEXT: ] 196; CHECK: block_7.exitStub: 197; CHECK-NEXT: switch i32 [[TMP8]], label [[FINAL_BLOCK_0:%.*]] [ 198; CHECK-NEXT: i32 0, label [[OUTPUT_BLOCK_0_0:%.*]] 199; CHECK-NEXT: i32 1, label [[OUTPUT_BLOCK_1_0:%.*]] 200; CHECK-NEXT: ] 201; CHECK: output_block_0_0: 202; CHECK-NEXT: store i32 [[A2VAL]], ptr [[TMP4:%.*]], align 4 203; CHECK-NEXT: store i32 [[B2VAL]], ptr [[TMP5:%.*]], align 4 204; CHECK-NEXT: br label [[FINAL_BLOCK_0]] 205; CHECK: output_block_0_1: 206; CHECK-NEXT: store i32 [[AVAL]], ptr [[TMP6:%.*]], align 4 207; CHECK-NEXT: store i32 [[BVAL]], ptr [[TMP7:%.*]], align 4 208; CHECK-NEXT: br label [[FINAL_BLOCK_1]] 209; CHECK: output_block_1_0: 210; CHECK-NEXT: store i32 [[A2VAL]], ptr [[TMP4]], align 4 211; CHECK-NEXT: store i32 [[B2VAL]], ptr [[TMP5]], align 4 212; CHECK-NEXT: br label [[FINAL_BLOCK_0]] 213; CHECK: output_block_1_1: 214; CHECK-NEXT: store i32 [[ADD]], ptr [[TMP6]], align 4 215; CHECK-NEXT: store i32 [[MUL]], ptr [[TMP7]], align 4 216; CHECK-NEXT: br label [[FINAL_BLOCK_1]] 217; CHECK: final_block_0: 218; CHECK-NEXT: ret i1 false 219; CHECK: final_block_1: 220; CHECK-NEXT: ret i1 true 221; 222