1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt -S -passes='sroa<preserve-cfg>' < %s | FileCheck %s --check-prefixes=CHECK,CHECK-PRESERVE-CFG 3; RUN: opt -S -passes='sroa<modify-cfg>' < %s | FileCheck %s --check-prefixes=CHECK,CHECK-MODIFY-CFG 4 5%pair = type { i32, i32 } 6 7define i32 @test_sroa_select_gep(i1 %cond) { 8; CHECK-LABEL: @test_sroa_select_gep( 9; CHECK-NEXT: bb: 10; CHECK-NEXT: [[LOAD_SROA_SPECULATED:%.*]] = select i1 [[COND:%.*]], i32 1, i32 2 11; CHECK-NEXT: ret i32 [[LOAD_SROA_SPECULATED]] 12; 13bb: 14 %a = alloca %pair, align 4 15 %b = alloca %pair, align 4 16 %gep_a = getelementptr inbounds %pair, ptr %a, i32 0, i32 1 17 %gep_b = getelementptr inbounds %pair, ptr %b, i32 0, i32 1 18 store i32 1, ptr %gep_a, align 4 19 store i32 2, ptr %gep_b, align 4 20 %select = select i1 %cond, ptr %a, ptr %b 21 %gep = getelementptr inbounds %pair, ptr %select, i32 0, i32 1 22 %load = load i32, ptr %gep, align 4 23 ret i32 %load 24} 25 26define i32 @test_sroa_select_gep_non_inbound(i1 %cond) { 27; CHECK-LABEL: @test_sroa_select_gep_non_inbound( 28; CHECK-NEXT: bb: 29; CHECK-NEXT: [[LOAD_SROA_SPECULATED:%.*]] = select i1 [[COND:%.*]], i32 1, i32 2 30; CHECK-NEXT: ret i32 [[LOAD_SROA_SPECULATED]] 31; 32bb: 33 %a = alloca %pair, align 4 34 %b = alloca %pair, align 4 35 %gep_a = getelementptr %pair, ptr %a, i32 0, i32 1 36 %gep_b = getelementptr %pair, ptr %b, i32 0, i32 1 37 store i32 1, ptr %gep_a, align 4 38 store i32 2, ptr %gep_b, align 4 39 %select = select i1 %cond, ptr %a, ptr %b 40 %gep = getelementptr %pair, ptr %select, i32 0, i32 1 41 %load = load i32, ptr %gep, align 4 42 ret i32 %load 43} 44 45define i32 @test_sroa_select_gep_volatile_load(i1 %cond) { 46; CHECK-LABEL: @test_sroa_select_gep_volatile_load( 47; CHECK-NEXT: bb: 48; CHECK-NEXT: [[A_SROA_0:%.*]] = alloca i32, align 4 49; CHECK-NEXT: [[A_SROA_2:%.*]] = alloca i32, align 4 50; CHECK-NEXT: [[B_SROA_0:%.*]] = alloca i32, align 4 51; CHECK-NEXT: [[B_SROA_2:%.*]] = alloca i32, align 4 52; CHECK-NEXT: store i32 11, ptr [[A_SROA_0]], align 4 53; CHECK-NEXT: store i32 12, ptr [[B_SROA_0]], align 4 54; CHECK-NEXT: store i32 21, ptr [[A_SROA_2]], align 4 55; CHECK-NEXT: store i32 22, ptr [[B_SROA_2]], align 4 56; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND:%.*]], ptr [[A_SROA_0]], ptr [[B_SROA_0]] 57; CHECK-NEXT: [[LOAD1:%.*]] = load volatile i32, ptr [[SELECT]], align 4 58; CHECK-NEXT: [[SELECT_SROA_SEL:%.*]] = select i1 [[COND]], ptr [[A_SROA_2]], ptr [[B_SROA_2]] 59; CHECK-NEXT: [[LOAD2:%.*]] = load volatile i32, ptr [[SELECT_SROA_SEL]], align 4 60; CHECK-NEXT: [[ADD:%.*]] = add i32 [[LOAD1]], [[LOAD2]] 61; CHECK-NEXT: ret i32 [[ADD]] 62; 63bb: 64 %a = alloca %pair, align 4 65 %b = alloca %pair, align 4 66 store i32 11, ptr %a, align 4 67 store i32 12, ptr %b, align 4 68 %gep_a1 = getelementptr inbounds %pair, ptr %a, i32 0, i32 1 69 %gep_b1 = getelementptr inbounds %pair, ptr %b, i32 0, i32 1 70 store i32 21, ptr %gep_a1, align 4 71 store i32 22, ptr %gep_b1, align 4 72 %select = select i1 %cond, ptr %a, ptr %b 73 %load1 = load volatile i32, ptr %select, align 4 74 %gep2 = getelementptr inbounds %pair, ptr %select, i32 0, i32 1 75 %load2 = load volatile i32, ptr %gep2, align 4 76 %add = add i32 %load1, %load2 77 ret i32 %add 78} 79 80define i32 @test_sroa_select_gep_poison(i1 %cond) { 81; CHECK-PRESERVE-CFG-LABEL: @test_sroa_select_gep_poison( 82; CHECK-PRESERVE-CFG-NEXT: bb: 83; CHECK-PRESERVE-CFG-NEXT: [[A_SROA_0:%.*]] = alloca i32, align 4 84; CHECK-PRESERVE-CFG-NEXT: [[SELECT_SROA_SEL:%.*]] = select i1 [[COND:%.*]], ptr [[A_SROA_0]], ptr poison 85; CHECK-PRESERVE-CFG-NEXT: [[LOAD:%.*]] = load i32, ptr [[SELECT_SROA_SEL]], align 4 86; CHECK-PRESERVE-CFG-NEXT: ret i32 [[LOAD]] 87; 88; CHECK-MODIFY-CFG-LABEL: @test_sroa_select_gep_poison( 89; CHECK-MODIFY-CFG-NEXT: bb: 90; CHECK-MODIFY-CFG-NEXT: br i1 [[COND:%.*]], label [[BB_CONT:%.*]], label [[BB_ELSE:%.*]] 91; CHECK-MODIFY-CFG: bb.else: 92; CHECK-MODIFY-CFG-NEXT: [[LOAD_ELSE_VAL:%.*]] = load i32, ptr poison, align 4 93; CHECK-MODIFY-CFG-NEXT: br label [[BB_CONT]] 94; CHECK-MODIFY-CFG: bb.cont: 95; CHECK-MODIFY-CFG-NEXT: [[LOAD:%.*]] = phi i32 [ undef, [[BB:%.*]] ], [ [[LOAD_ELSE_VAL]], [[BB_ELSE]] ] 96; CHECK-MODIFY-CFG-NEXT: ret i32 [[LOAD]] 97; 98bb: 99 %a = alloca %pair, align 4 100 %select = select i1 %cond, ptr %a, ptr poison 101 %gep = getelementptr inbounds %pair, ptr %select, i32 0, i32 1 102 %load = load i32, ptr %gep, align 4 103 ret i32 %load 104} 105 106define i32 @test_sroa_gep_select_gep(i1 %cond) { 107; CHECK-LABEL: @test_sroa_gep_select_gep( 108; CHECK-NEXT: bb: 109; CHECK-NEXT: [[A_SROA_0:%.*]] = alloca i32, align 4 110; CHECK-NEXT: [[B_SROA_0:%.*]] = alloca i32, align 4 111; CHECK-NEXT: store i32 1, ptr [[A_SROA_0]], align 4 112; CHECK-NEXT: store i32 2, ptr [[B_SROA_0]], align 4 113; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND:%.*]], ptr [[A_SROA_0]], ptr [[B_SROA_0]] 114; CHECK-NEXT: [[SELECT2:%.*]] = select i1 [[COND]], ptr [[SELECT]], ptr [[A_SROA_0]] 115; CHECK-NEXT: [[LOAD:%.*]] = load i32, ptr [[SELECT2]], align 4 116; CHECK-NEXT: ret i32 [[LOAD]] 117; 118bb: 119 %a = alloca %pair, align 4 120 %b = alloca %pair, align 4 121 %gep_a = getelementptr inbounds %pair, ptr %a, i32 0, i32 1 122 %gep_b = getelementptr inbounds %pair, ptr %b, i32 0, i32 1 123 store i32 1, ptr %gep_a, align 4 124 store i32 2, ptr %gep_b, align 4 125 %select = select i1 %cond, ptr %gep_a, ptr %gep_b 126 %select2 = select i1 %cond, ptr %select, ptr %gep_a 127 %load = load i32, ptr %select2, align 4 128 ret i32 %load 129} 130 131define i32 @test_sroa_gep_select_gep_nonconst_idx(i1 %cond, i32 %idx) { 132; CHECK-LABEL: @test_sroa_gep_select_gep_nonconst_idx( 133; CHECK-NEXT: bb: 134; CHECK-NEXT: [[A:%.*]] = alloca [[PAIR:%.*]], align 4 135; CHECK-NEXT: [[B:%.*]] = alloca [[PAIR]], align 4 136; CHECK-NEXT: [[GEP_A:%.*]] = getelementptr inbounds [[PAIR]], ptr [[A]], i32 0, i32 1 137; CHECK-NEXT: [[GEP_B:%.*]] = getelementptr inbounds [[PAIR]], ptr [[B]], i32 0, i32 1 138; CHECK-NEXT: store i32 1, ptr [[GEP_A]], align 4 139; CHECK-NEXT: store i32 2, ptr [[GEP_B]], align 4 140; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND:%.*]], ptr [[A]], ptr [[B]] 141; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds [[PAIR]], ptr [[SELECT]], i32 [[IDX:%.*]], i32 1 142; CHECK-NEXT: [[LOAD:%.*]] = load i32, ptr [[GEP]], align 4 143; CHECK-NEXT: ret i32 [[LOAD]] 144; 145bb: 146 %a = alloca %pair, align 4 147 %b = alloca %pair, align 4 148 %gep_a = getelementptr inbounds %pair, ptr %a, i32 0, i32 1 149 %gep_b = getelementptr inbounds %pair, ptr %b, i32 0, i32 1 150 store i32 1, ptr %gep_a, align 4 151 store i32 2, ptr %gep_b, align 4 152 %select = select i1 %cond, ptr %a, ptr %b 153 %gep = getelementptr inbounds %pair, ptr %select, i32 %idx, i32 1 154 %load = load i32, ptr %gep, align 4 155 ret i32 %load 156} 157 158; Test gep of index select unfolding on an alloca that is splittable, but not 159; promotable. The allocas here will be optimized away by subsequent passes. 160define i32 @test_select_idx_memcpy(i1 %c, ptr %p) { 161; CHECK-LABEL: @test_select_idx_memcpy( 162; CHECK-NEXT: [[ALLOCA_SROA_0:%.*]] = alloca [4 x i8], align 8 163; CHECK-NEXT: [[ALLOCA_SROA_2:%.*]] = alloca [20 x i8], align 4 164; CHECK-NEXT: [[ALLOCA_SROA_22:%.*]] = alloca [4 x i8], align 8 165; CHECK-NEXT: [[ALLOCA_SROA_3:%.*]] = alloca [132 x i8], align 4 166; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[ALLOCA_SROA_0]], ptr align 1 [[P:%.*]], i64 4, i1 false) 167; CHECK-NEXT: [[ALLOCA_SROA_2_0_P_SROA_IDX:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 4 168; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[ALLOCA_SROA_2]], ptr align 1 [[ALLOCA_SROA_2_0_P_SROA_IDX]], i64 20, i1 false) 169; CHECK-NEXT: [[ALLOCA_SROA_22_0_P_SROA_IDX:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 24 170; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[ALLOCA_SROA_22]], ptr align 1 [[ALLOCA_SROA_22_0_P_SROA_IDX]], i64 4, i1 false) 171; CHECK-NEXT: [[ALLOCA_SROA_3_0_P_SROA_IDX:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 28 172; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[ALLOCA_SROA_3]], ptr align 1 [[ALLOCA_SROA_3_0_P_SROA_IDX]], i64 132, i1 false) 173; CHECK-NEXT: [[IDX:%.*]] = select i1 [[C:%.*]], i64 24, i64 0 174; CHECK-NEXT: [[IDX_SROA_SEL:%.*]] = select i1 [[C]], ptr [[ALLOCA_SROA_22]], ptr [[ALLOCA_SROA_0]] 175; CHECK-NEXT: [[RES:%.*]] = load i32, ptr [[IDX_SROA_SEL]], align 4 176; CHECK-NEXT: ret i32 [[RES]] 177; 178 %alloca = alloca [20 x i64], align 8 179 call void @llvm.memcpy.p0.p0.i64(ptr %alloca, ptr %p, i64 160, i1 false) 180 %idx = select i1 %c, i64 24, i64 0 181 %gep = getelementptr inbounds i8, ptr %alloca, i64 %idx 182 %res = load i32, ptr %gep, align 4 183 ret i32 %res 184} 185 186; Test gep of index select unfolding on an alloca that is splittable and 187; promotable. 188define i32 @test_select_idx_mem2reg(i1 %c) { 189; CHECK-LABEL: @test_select_idx_mem2reg( 190; CHECK-NEXT: [[IDX:%.*]] = select i1 [[C:%.*]], i64 24, i64 0 191; CHECK-NEXT: [[RES_SROA_SPECULATED:%.*]] = select i1 [[C]], i32 2, i32 1 192; CHECK-NEXT: ret i32 [[RES_SROA_SPECULATED]] 193; 194 %alloca = alloca [20 x i64], align 8 195 store i32 1, ptr %alloca 196 %gep1 = getelementptr inbounds i8, ptr %alloca, i64 24 197 store i32 2, ptr %gep1 198 %idx = select i1 %c, i64 24, i64 0 199 %gep2 = getelementptr inbounds i8, ptr %alloca, i64 %idx 200 %res = load i32, ptr %gep2, align 4 201 ret i32 %res 202} 203 204; Test gep of index select unfolding on an alloca that escaped, and as such 205; is not splittable or promotable. 206; FIXME: Ideally, no transform would take place in this case. 207define i32 @test_select_idx_escaped(i1 %c, ptr %p) { 208; CHECK-LABEL: @test_select_idx_escaped( 209; CHECK-NEXT: [[ALLOCA:%.*]] = alloca [20 x i64], align 8 210; CHECK-NEXT: store ptr [[ALLOCA]], ptr [[P:%.*]], align 8 211; CHECK-NEXT: store i32 1, ptr [[ALLOCA]], align 4 212; CHECK-NEXT: [[GEP1:%.*]] = getelementptr inbounds i8, ptr [[ALLOCA]], i64 24 213; CHECK-NEXT: store i32 2, ptr [[GEP1]], align 4 214; CHECK-NEXT: [[IDX:%.*]] = select i1 [[C:%.*]], i64 24, i64 0 215; CHECK-NEXT: [[DOTSROA_GEP:%.*]] = getelementptr inbounds i8, ptr [[ALLOCA]], i64 24 216; CHECK-NEXT: [[DOTSROA_GEP1:%.*]] = getelementptr inbounds i8, ptr [[ALLOCA]], i64 0 217; CHECK-NEXT: [[IDX_SROA_SEL:%.*]] = select i1 [[C]], ptr [[DOTSROA_GEP]], ptr [[DOTSROA_GEP1]] 218; CHECK-NEXT: [[RES:%.*]] = load i32, ptr [[IDX_SROA_SEL]], align 4 219; CHECK-NEXT: ret i32 [[RES]] 220; 221 %alloca = alloca [20 x i64], align 8 222 store ptr %alloca, ptr %p 223 store i32 1, ptr %alloca 224 %gep1 = getelementptr inbounds i8, ptr %alloca, i64 24 225 store i32 2, ptr %gep1 226 %idx = select i1 %c, i64 24, i64 0 227 %gep2 = getelementptr inbounds i8, ptr %alloca, i64 %idx 228 %res = load i32, ptr %gep2, align 4 229 ret i32 %res 230} 231 232; FIXME: Should we allow recursive select unfolding if all the leaves are 233; constants? 234define i32 @test_select_idx_nested(i1 %c, i1 %c2) { 235; CHECK-LABEL: @test_select_idx_nested( 236; CHECK-NEXT: [[ALLOCA:%.*]] = alloca [20 x i64], align 8 237; CHECK-NEXT: store i32 1, ptr [[ALLOCA]], align 4 238; CHECK-NEXT: [[GEP1:%.*]] = getelementptr inbounds i8, ptr [[ALLOCA]], i64 8 239; CHECK-NEXT: store i32 2, ptr [[GEP1]], align 4 240; CHECK-NEXT: [[GEP2:%.*]] = getelementptr inbounds i8, ptr [[ALLOCA]], i64 24 241; CHECK-NEXT: store i32 3, ptr [[GEP2]], align 4 242; CHECK-NEXT: [[IDX1:%.*]] = select i1 [[C:%.*]], i64 24, i64 0 243; CHECK-NEXT: [[IDX2:%.*]] = select i1 [[C2:%.*]], i64 [[IDX1]], i64 8 244; CHECK-NEXT: [[GEP3:%.*]] = getelementptr inbounds i8, ptr [[ALLOCA]], i64 [[IDX2]] 245; CHECK-NEXT: [[RES:%.*]] = load i32, ptr [[GEP3]], align 4 246; CHECK-NEXT: ret i32 [[RES]] 247; 248 %alloca = alloca [20 x i64], align 8 249 store i32 1, ptr %alloca 250 %gep1 = getelementptr inbounds i8, ptr %alloca, i64 8 251 store i32 2, ptr %gep1 252 %gep2 = getelementptr inbounds i8, ptr %alloca, i64 24 253 store i32 3, ptr %gep2 254 %idx1 = select i1 %c, i64 24, i64 0 255 %idx2 = select i1 %c2, i64 %idx1, i64 8 256 %gep3 = getelementptr inbounds i8, ptr %alloca, i64 %idx2 257 %res = load i32, ptr %gep3, align 4 258 ret i32 %res 259} 260 261; The following cases involve non-constant indices and should not be 262; transformed. 263 264define i32 @test_select_idx_not_constant1(i1 %c, ptr %p, i64 %arg) { 265; CHECK-LABEL: @test_select_idx_not_constant1( 266; CHECK-NEXT: [[ALLOCA:%.*]] = alloca [20 x i64], align 8 267; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr [[ALLOCA]], ptr [[P:%.*]], i64 160, i1 false) 268; CHECK-NEXT: [[IDX:%.*]] = select i1 [[C:%.*]], i64 24, i64 [[ARG:%.*]] 269; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr [[ALLOCA]], i64 [[IDX]] 270; CHECK-NEXT: [[RES:%.*]] = load i32, ptr [[GEP]], align 4 271; CHECK-NEXT: ret i32 [[RES]] 272; 273 %alloca = alloca [20 x i64], align 8 274 call void @llvm.memcpy.p0.p0.i64(ptr %alloca, ptr %p, i64 160, i1 false) 275 %idx = select i1 %c, i64 24, i64 %arg 276 %gep = getelementptr inbounds i8, ptr %alloca, i64 %idx 277 %res = load i32, ptr %gep, align 4 278 ret i32 %res 279} 280 281define i32 @test_select_idx_not_constant2(i1 %c, ptr %p, i64 %arg) { 282; CHECK-LABEL: @test_select_idx_not_constant2( 283; CHECK-NEXT: [[ALLOCA:%.*]] = alloca [20 x i64], align 8 284; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr [[ALLOCA]], ptr [[P:%.*]], i64 160, i1 false) 285; CHECK-NEXT: [[IDX:%.*]] = select i1 [[C:%.*]], i64 [[ARG:%.*]], i64 0 286; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr [[ALLOCA]], i64 [[IDX]] 287; CHECK-NEXT: [[RES:%.*]] = load i32, ptr [[GEP]], align 4 288; CHECK-NEXT: ret i32 [[RES]] 289; 290 %alloca = alloca [20 x i64], align 8 291 call void @llvm.memcpy.p0.p0.i64(ptr %alloca, ptr %p, i64 160, i1 false) 292 %idx = select i1 %c, i64 %arg, i64 0 293 %gep = getelementptr inbounds i8, ptr %alloca, i64 %idx 294 %res = load i32, ptr %gep, align 4 295 ret i32 %res 296} 297 298define i32 @test_select_idx_not_constant3(i1 %c, ptr %p, i64 %arg) { 299; CHECK-LABEL: @test_select_idx_not_constant3( 300; CHECK-NEXT: [[ALLOCA:%.*]] = alloca [20 x i64], align 8 301; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr [[ALLOCA]], ptr [[P:%.*]], i64 160, i1 false) 302; CHECK-NEXT: [[IDX:%.*]] = select i1 [[C:%.*]], i64 24, i64 0 303; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds [1 x i8], ptr [[ALLOCA]], i64 [[IDX]], i64 [[ARG:%.*]] 304; CHECK-NEXT: [[RES:%.*]] = load i32, ptr [[GEP]], align 4 305; CHECK-NEXT: ret i32 [[RES]] 306; 307 %alloca = alloca [20 x i64], align 8 308 call void @llvm.memcpy.p0.p0.i64(ptr %alloca, ptr %p, i64 160, i1 false) 309 %idx = select i1 %c, i64 24, i64 0 310 %gep = getelementptr inbounds [1 x i8], ptr %alloca, i64 %idx, i64 %arg 311 %res = load i32, ptr %gep, align 4 312 ret i32 %res 313} 314