1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s 3 4; This test checks that commutative instructions where the operands are 5; swapped are outlined as the same function. 6 7; It also checks that non-commutative instructions outlined as different 8; functions when the operands are swapped; 9 10; These are identical functions, except that in the flipped functions, 11; the operands in the adds are commuted. However, since add instructions 12; are commutative, we should still outline from all four as the same 13; instruction. 14 15define void @outline_from_add1() { 16; CHECK-LABEL: @outline_from_add1( 17; CHECK-NEXT: entry: 18; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 19; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4 20; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4 21; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[C]]) 22; CHECK-NEXT: ret void 23; 24entry: 25 %a = alloca i32, align 4 26 %b = alloca i32, align 4 27 %c = alloca i32, align 4 28 store i32 2, ptr %a, align 4 29 store i32 3, ptr %b, align 4 30 store i32 4, ptr %c, align 4 31 %al = load i32, ptr %a 32 %bl = load i32, ptr %b 33 %cl = load i32, ptr %c 34 %0 = add i32 %al, %bl 35 %1 = add i32 %al, %cl 36 %2 = add i32 %bl, %cl 37 ret void 38} 39 40define void @outline_from_add2() { 41; CHECK-LABEL: @outline_from_add2( 42; CHECK-NEXT: entry: 43; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 44; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4 45; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4 46; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[C]]) 47; CHECK-NEXT: ret void 48; 49entry: 50 %a = alloca i32, align 4 51 %b = alloca i32, align 4 52 %c = alloca i32, align 4 53 store i32 2, ptr %a, align 4 54 store i32 3, ptr %b, align 4 55 store i32 4, ptr %c, align 4 56 %al = load i32, ptr %a 57 %bl = load i32, ptr %b 58 %cl = load i32, ptr %c 59 %0 = add i32 %al, %bl 60 %1 = add i32 %al, %cl 61 %2 = add i32 %bl, %cl 62 ret void 63} 64 65define void @outline_from_flipped_add3() { 66; CHECK-LABEL: @outline_from_flipped_add3( 67; CHECK-NEXT: entry: 68; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 69; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4 70; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4 71; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[C]]) 72; CHECK-NEXT: ret void 73; 74entry: 75 %a = alloca i32, align 4 76 %b = alloca i32, align 4 77 %c = alloca i32, align 4 78 store i32 2, ptr %a, align 4 79 store i32 3, ptr %b, align 4 80 store i32 4, ptr %c, align 4 81 %al = load i32, ptr %a 82 %bl = load i32, ptr %b 83 %cl = load i32, ptr %c 84 %0 = add i32 %bl, %al 85 %1 = add i32 %cl, %al 86 %2 = add i32 %cl, %bl 87 ret void 88} 89 90define void @outline_from_flipped_add4() { 91; CHECK-LABEL: @outline_from_flipped_add4( 92; CHECK-NEXT: entry: 93; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 94; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4 95; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4 96; CHECK-NEXT: call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[C]]) 97; CHECK-NEXT: ret void 98; 99entry: 100 %a = alloca i32, align 4 101 %b = alloca i32, align 4 102 %c = alloca i32, align 4 103 store i32 2, ptr %a, align 4 104 store i32 3, ptr %b, align 4 105 store i32 4, ptr %c, align 4 106 %al = load i32, ptr %a 107 %bl = load i32, ptr %b 108 %cl = load i32, ptr %c 109 %0 = add i32 %bl, %al 110 %1 = add i32 %cl, %al 111 %2 = add i32 %cl, %bl 112 ret void 113} 114 115; These are identical functions, except that in the flipped functions, 116; the operands in the subtractions are commuted. Since subtraction 117; instructions are not commutative, we should outline the first two functions 118; differently than the second two functions. 119 120define void @outline_from_sub1() { 121; CHECK-LABEL: @outline_from_sub1( 122; CHECK-NEXT: entry: 123; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 124; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4 125; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4 126; CHECK-NEXT: call void @outlined_ir_func_2(ptr [[A]], ptr [[B]], ptr [[C]]) 127; CHECK-NEXT: ret void 128; 129entry: 130 %a = alloca i32, align 4 131 %b = alloca i32, align 4 132 %c = alloca i32, align 4 133 store i32 2, ptr %a, align 4 134 store i32 3, ptr %b, align 4 135 store i32 4, ptr %c, align 4 136 %al = load i32, ptr %a 137 %bl = load i32, ptr %b 138 %cl = load i32, ptr %c 139 %0 = sub i32 %al, %bl 140 %1 = sub i32 %al, %cl 141 %2 = sub i32 %bl, %cl 142 ret void 143} 144 145define void @outline_from_sub2() { 146; CHECK-LABEL: @outline_from_sub2( 147; CHECK-NEXT: entry: 148; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 149; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4 150; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4 151; CHECK-NEXT: call void @outlined_ir_func_2(ptr [[A]], ptr [[B]], ptr [[C]]) 152; CHECK-NEXT: ret void 153; 154entry: 155 %a = alloca i32, align 4 156 %b = alloca i32, align 4 157 %c = alloca i32, align 4 158 store i32 2, ptr %a, align 4 159 store i32 3, ptr %b, align 4 160 store i32 4, ptr %c, align 4 161 %al = load i32, ptr %a 162 %bl = load i32, ptr %b 163 %cl = load i32, ptr %c 164 %0 = sub i32 %al, %bl 165 %1 = sub i32 %al, %cl 166 %2 = sub i32 %bl, %cl 167 ret void 168} 169 170define void @dontoutline_from_flipped_sub3() { 171; CHECK-LABEL: @dontoutline_from_flipped_sub3( 172; CHECK-NEXT: entry: 173; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 174; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4 175; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4 176; CHECK-NEXT: call void @outlined_ir_func_1(ptr [[A]], ptr [[B]], ptr [[C]]) 177; CHECK-NEXT: ret void 178; 179entry: 180 %a = alloca i32, align 4 181 %b = alloca i32, align 4 182 %c = alloca i32, align 4 183 store i32 2, ptr %a, align 4 184 store i32 3, ptr %b, align 4 185 store i32 4, ptr %c, align 4 186 %al = load i32, ptr %a 187 %bl = load i32, ptr %b 188 %cl = load i32, ptr %c 189 %0 = sub i32 %bl, %al 190 %1 = sub i32 %cl, %al 191 %2 = sub i32 %cl, %bl 192 ret void 193} 194 195define void @dontoutline_from_flipped_sub4() { 196; CHECK-LABEL: @dontoutline_from_flipped_sub4( 197; CHECK-NEXT: entry: 198; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 199; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4 200; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4 201; CHECK-NEXT: call void @outlined_ir_func_1(ptr [[A]], ptr [[B]], ptr [[C]]) 202; CHECK-NEXT: ret void 203; 204entry: 205 %a = alloca i32, align 4 206 %b = alloca i32, align 4 207 %c = alloca i32, align 4 208 store i32 2, ptr %a, align 4 209 store i32 3, ptr %b, align 4 210 store i32 4, ptr %c, align 4 211 %al = load i32, ptr %a 212 %bl = load i32, ptr %b 213 %cl = load i32, ptr %c 214 %0 = sub i32 %bl, %al 215 %1 = sub i32 %cl, %al 216 %2 = sub i32 %cl, %bl 217 ret void 218} 219 220; CHECK: define internal void @outlined_ir_func_0(ptr [[ARG0:%.*]], ptr [[ARG1:%.*]], ptr [[ARG2:%.*]]) #0 { 221; CHECK: entry_to_outline: 222; CHECK-NEXT: store i32 2, ptr [[ARG0]], align 4 223; CHECK-NEXT: store i32 3, ptr [[ARG1]], align 4 224; CHECK-NEXT: store i32 4, ptr [[ARG2]], align 4 225; CHECK-NEXT: [[AL:%.*]] = load i32, ptr [[ARG0]], align 4 226; CHECK-NEXT: [[BL:%.*]] = load i32, ptr [[ARG1]], align 4 227; CHECK-NEXT: [[CL:%.*]] = load i32, ptr [[ARG2]], align 4 228; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[AL]], [[BL]] 229; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[AL]], [[CL]] 230; CHECK-NEXT: [[TMP2:%.*]] = add i32 [[BL]], [[CL]] 231 232; CHECK: define internal void @outlined_ir_func_1(ptr [[ARG0:%.*]], ptr [[ARG1:%.*]], ptr [[ARG2:%.*]]) #0 { 233; CHECK: entry_to_outline: 234; CHECK-NEXT: store i32 2, ptr [[ARG0]], align 4 235; CHECK-NEXT: store i32 3, ptr [[ARG1]], align 4 236; CHECK-NEXT: store i32 4, ptr [[ARG2]], align 4 237; CHECK-NEXT: [[AL:%.*]] = load i32, ptr [[ARG0]], align 4 238; CHECK-NEXT: [[BL:%.*]] = load i32, ptr [[ARG1]], align 4 239; CHECK-NEXT: [[CL:%.*]] = load i32, ptr [[ARG2]], align 4 240; CHECK-NEXT: [[TMP0:%.*]] = sub i32 [[BL]], [[AL]] 241; CHECK-NEXT: [[TMP1:%.*]] = sub i32 [[CL]], [[AL]] 242; CHECK-NEXT: [[TMP2:%.*]] = sub i32 [[CL]], [[BL]] 243 244; CHECK: define internal void @outlined_ir_func_2(ptr [[ARG0:%.*]], ptr [[ARG1:%.*]], ptr [[ARG2:%.*]]) #0 { 245; CHECK: entry_to_outline: 246; CHECK-NEXT: store i32 2, ptr [[ARG0]], align 4 247; CHECK-NEXT: store i32 3, ptr [[ARG1]], align 4 248; CHECK-NEXT: store i32 4, ptr [[ARG2]], align 4 249; CHECK-NEXT: [[AL:%.*]] = load i32, ptr [[ARG0]], align 4 250; CHECK-NEXT: [[BL:%.*]] = load i32, ptr [[ARG1]], align 4 251; CHECK-NEXT: [[CL:%.*]] = load i32, ptr [[ARG2]], align 4 252; CHECK-NEXT: [[TMP0:%.*]] = sub i32 [[AL]], [[BL]] 253; CHECK-NEXT: [[TMP1:%.*]] = sub i32 [[AL]], [[CL]] 254; CHECK-NEXT: [[TMP2:%.*]] = sub i32 [[BL]], [[CL]] 255