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 different sources, and only one has an 5; output set. We check to make sure that we do not generated extra output 6; blocks or entries in the switch statement. 7 8define void @outline_outputs1() #0 { 9entry: 10 %output = alloca i32, align 4 11 %result = alloca i32, align 4 12 %output2 = alloca i32, align 4 13 %result2 = alloca i32, align 4 14 %a = alloca i32, align 4 15 %b = alloca i32, align 4 16 br label %block_2 17block_1: 18 %a2 = alloca i32, align 4 19 %b2 = alloca i32, align 4 20 br label %block_2 21block_2: 22 %a2val = load i32, ptr %a 23 %b2val = load i32, ptr %b 24 %add2 = add i32 2, %a2val 25 %mul2 = mul i32 2, %b2val 26 br label %block_5 27block_3: 28 %aval = load i32, ptr %a 29 %bval = load i32, ptr %b 30 %add = add i32 2, %aval 31 %mul = mul i32 2, %bval 32 br label %block_4 33block_4: 34 store i32 %add, ptr %output, align 4 35 store i32 %mul, ptr %result, align 4 36 br label %block_6 37block_5: 38 store i32 %add2, ptr %output, align 4 39 store i32 %mul2, ptr %result, align 4 40 br label %block_7 41block_6: 42 ret void 43block_7: 44 ret void 45} 46 47define void @outline_outputs2() #0 { 48entry: 49 %output = alloca i32, align 4 50 %result = alloca i32, align 4 51 %output2 = alloca i32, align 4 52 %result2 = alloca i32, align 4 53 %a = alloca i32, align 4 54 %b = alloca i32, align 4 55 br label %block_2 56block_1: 57 %a2 = alloca i32, align 4 58 %b2 = alloca i32, align 4 59 br label %block_2 60block_2: 61 %a2val = load i32, ptr %a 62 %b2val = load i32, ptr %b 63 %add2 = add i32 2, %a2val 64 %mul2 = mul i32 2, %b2val 65 br label %block_5 66block_3: 67 %aval = load i32, ptr %a 68 %bval = load i32, ptr %b 69 %add = add i32 2, %aval 70 %mul = mul i32 2, %bval 71 br label %block_4 72block_4: 73 store i32 %add, ptr %output, align 4 74 store i32 %mul, ptr %result, align 4 75 br label %block_7 76block_5: 77 store i32 %add2, ptr %output, align 4 78 store i32 %mul2, ptr %result, align 4 79 br label %block_6 80block_6: 81 %diff = sub i32 %a2val, %b2val 82 ret void 83block_7: 84 %quot = udiv i32 %add, %mul 85 ret void 86} 87; CHECK-LABEL: @outline_outputs1( 88; CHECK-NEXT: entry: 89; CHECK-NEXT: [[OUTPUT:%.*]] = alloca i32, align 4 90; CHECK-NEXT: [[RESULT:%.*]] = alloca i32, align 4 91; CHECK-NEXT: [[OUTPUT2:%.*]] = alloca i32, align 4 92; CHECK-NEXT: [[RESULT2:%.*]] = alloca i32, align 4 93; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 94; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4 95; CHECK-NEXT: br label [[BLOCK_2:%.*]] 96; CHECK: block_1: 97; CHECK-NEXT: [[A2:%.*]] = alloca i32, align 4 98; CHECK-NEXT: [[B2:%.*]] = alloca i32, align 4 99; CHECK-NEXT: br label [[BLOCK_2]] 100; CHECK: block_2: 101; CHECK-NEXT: [[TMP0:%.*]] = call i1 @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[OUTPUT]], ptr [[RESULT]], ptr null, ptr null, ptr null, ptr null, i32 -1) 102; CHECK-NEXT: br i1 [[TMP0]], label [[BLOCK_6:%.*]], label [[BLOCK_7:%.*]] 103; CHECK: block_6: 104; CHECK-NEXT: ret void 105; CHECK: block_7: 106; CHECK-NEXT: ret void 107; 108; 109; CHECK-LABEL: @outline_outputs2( 110; CHECK-NEXT: entry: 111; CHECK-NEXT: [[MUL_LOC:%.*]] = alloca i32, align 4 112; CHECK-NEXT: [[ADD_LOC:%.*]] = alloca i32, align 4 113; CHECK-NEXT: [[B2VAL_LOC:%.*]] = alloca i32, align 4 114; CHECK-NEXT: [[A2VAL_LOC:%.*]] = alloca i32, align 4 115; CHECK-NEXT: [[OUTPUT:%.*]] = alloca i32, align 4 116; CHECK-NEXT: [[RESULT:%.*]] = alloca i32, align 4 117; CHECK-NEXT: [[OUTPUT2:%.*]] = alloca i32, align 4 118; CHECK-NEXT: [[RESULT2:%.*]] = alloca i32, align 4 119; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 120; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4 121; CHECK-NEXT: br label [[BLOCK_2:%.*]] 122; CHECK: block_1: 123; CHECK-NEXT: [[A2:%.*]] = alloca i32, align 4 124; CHECK-NEXT: [[B2:%.*]] = alloca i32, align 4 125; CHECK-NEXT: br label [[BLOCK_2]] 126; CHECK: block_2: 127; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 -1, ptr [[A2VAL_LOC]]) 128; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 -1, ptr [[B2VAL_LOC]]) 129; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 -1, ptr [[ADD_LOC]]) 130; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 -1, ptr [[MUL_LOC]]) 131; 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 0) 132; CHECK-NEXT: [[A2VAL_RELOAD:%.*]] = load i32, ptr [[A2VAL_LOC]], align 4 133; CHECK-NEXT: [[B2VAL_RELOAD:%.*]] = load i32, ptr [[B2VAL_LOC]], align 4 134; CHECK-NEXT: [[ADD_RELOAD:%.*]] = load i32, ptr [[ADD_LOC]], align 4 135; CHECK-NEXT: [[MUL_RELOAD:%.*]] = load i32, ptr [[MUL_LOC]], align 4 136; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 -1, ptr [[A2VAL_LOC]]) 137; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 -1, ptr [[B2VAL_LOC]]) 138; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 -1, ptr [[ADD_LOC]]) 139; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 -1, ptr [[MUL_LOC]]) 140; CHECK-NEXT: br i1 [[TMP0]], label [[BLOCK_7:%.*]], label [[BLOCK_6:%.*]] 141; CHECK: block_6: 142; CHECK-NEXT: [[DIFF:%.*]] = sub i32 [[A2VAL_RELOAD]], [[B2VAL_RELOAD]] 143; CHECK-NEXT: ret void 144; CHECK: block_7: 145; CHECK-NEXT: [[QUOT:%.*]] = udiv i32 [[ADD_RELOAD]], [[MUL_RELOAD]] 146; CHECK-NEXT: ret void 147; 148; 149; CHECK: define internal i1 @outlined_ir_func_0( 150; CHECK-NEXT: newFuncRoot: 151; CHECK-NEXT: br label [[BLOCK_2_TO_OUTLINE:%.*]] 152; CHECK: block_2_to_outline: 153; CHECK-NEXT: [[A2VAL:%.*]] = load i32, ptr [[TMP0:%.*]], align 4 154; CHECK-NEXT: [[B2VAL:%.*]] = load i32, ptr [[TMP1:%.*]], align 4 155; CHECK-NEXT: [[ADD2:%.*]] = add i32 2, [[A2VAL]] 156; CHECK-NEXT: [[MUL2:%.*]] = mul i32 2, [[B2VAL]] 157; CHECK-NEXT: br label [[BLOCK_5:%.*]] 158; CHECK: block_3: 159; CHECK-NEXT: [[AVAL:%.*]] = load i32, ptr [[TMP0]], align 4 160; CHECK-NEXT: [[BVAL:%.*]] = load i32, ptr [[TMP1]], align 4 161; CHECK-NEXT: [[ADD:%.*]] = add i32 2, [[AVAL]] 162; CHECK-NEXT: [[MUL:%.*]] = mul i32 2, [[BVAL]] 163; CHECK-NEXT: br label [[BLOCK_4:%.*]] 164; CHECK: block_4: 165; CHECK-NEXT: store i32 [[ADD]], ptr [[TMP2:%.*]], align 4 166; CHECK-NEXT: store i32 [[MUL]], ptr [[TMP3:%.*]], align 4 167; CHECK-NEXT: br label [[BLOCK_6_EXITSTUB:%.*]] 168; CHECK: block_5: 169; CHECK-NEXT: store i32 [[ADD2]], ptr [[TMP2]], align 4 170; CHECK-NEXT: store i32 [[MUL2]], ptr [[TMP3]], align 4 171; CHECK-NEXT: br label [[BLOCK_7_EXITSTUB:%.*]] 172; CHECK: block_6.exitStub: 173; CHECK-NEXT: switch i32 [[TMP8:%.*]], label [[FINAL_BLOCK_1:%.*]] [ 174; CHECK-NEXT: i32 0, label [[OUTPUT_BLOCK_1_1:%.*]] 175; CHECK-NEXT: ] 176; CHECK: block_7.exitStub: 177; CHECK-NEXT: switch i32 [[TMP8]], label [[FINAL_BLOCK_0:%.*]] [ 178; CHECK-NEXT: i32 0, label [[OUTPUT_BLOCK_1_0:%.*]] 179; CHECK-NEXT: ] 180; CHECK: output_block_1_0: 181; CHECK-NEXT: store i32 [[A2VAL]], ptr [[TMP4:%.*]], align 4 182; CHECK-NEXT: store i32 [[B2VAL]], ptr [[TMP5:%.*]], align 4 183; CHECK-NEXT: br label [[FINAL_BLOCK_0]] 184; CHECK: output_block_1_1: 185; CHECK-NEXT: store i32 [[ADD]], ptr [[TMP6:%.*]], align 4 186; CHECK-NEXT: store i32 [[MUL]], ptr [[TMP7:%.*]], align 4 187; CHECK-NEXT: br label [[FINAL_BLOCK_1]] 188; CHECK: final_block_0: 189; CHECK-NEXT: ret i1 false 190; CHECK: final_block_1: 191; CHECK-NEXT: ret i1 true 192; 193