419 lines · plain
1; RUN: opt -S -passes='require<profile-summary>,function(codegenprepare)' -mtriple=thumbv7m -disable-complex-addr-modes=false -addr-sink-new-select=true -addr-sink-new-phis=true < %s | FileCheck %s2 3target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"4 5@gv1 = common global i32 0, align 46@gv2 = common global i32 0, align 47 8; Phi selects between ptr and gep with ptr as base and constant offset9define void @test_phi_onegep_offset(ptr %ptr, i32 %value) {10; CHECK-LABEL: @test_phi_onegep_offset11; CHECK-NOT: phi ptr [ %ptr, %entry ], [ %gep, %if.then ]12; CHECK: phi i32 [ 4, %if.then ], [ 0, %entry ]13entry:14 %cmp = icmp sgt i32 %value, 015 br i1 %cmp, label %if.then, label %if.end16 17if.then:18 %gep = getelementptr inbounds i32, ptr %ptr, i32 119 br label %if.end20 21if.end:22 %phi = phi ptr [ %ptr, %entry ], [ %gep, %if.then ]23 store i32 %value, ptr %phi, align 424 ret void25}26 27; Phi selects between two geps with same base, different constant offsets28define void @test_phi_twogep_offset(ptr %ptr, i32 %value) {29; CHECK-LABEL: @test_phi_twogep_offset30; CHECK-NOT: phi ptr [ %gep1, %if.then ], [ %gep2, %if.else ]31; CHECK: phi i32 [ 8, %if.else ], [ 4, %if.then ]32entry:33 %cmp = icmp sgt i32 %value, 034 br i1 %cmp, label %if.then, label %if.else35 36if.then:37 %gep1 = getelementptr inbounds i32, ptr %ptr, i32 138 br label %if.end39 40if.else:41 %gep2 = getelementptr inbounds i32, ptr %ptr, i32 242 br label %if.end43 44if.end:45 %phi = phi ptr [ %gep1, %if.then ], [ %gep2, %if.else ]46 store i32 %value, ptr %phi, align 447 ret void48}49 50; Phi selects between ptr and gep with ptr as base and nonconstant offset51define void @test_phi_onegep_nonconst_offset(ptr %ptr, i32 %value, i32 %off) {52; CHECK-LABEL: @test_phi_onegep_nonconst_offset53; CHECK-NOT: phi ptr [ %ptr, %entry ], [ %gep, %if.then ]54; CHECK: phi i32 [ %off, %if.then ], [ 0, %entry ]55entry:56 %cmp = icmp sgt i32 %value, 057 br i1 %cmp, label %if.then, label %if.end58 59if.then:60 %gep = getelementptr inbounds i32, ptr %ptr, i32 %off61 br label %if.end62 63if.end:64 %phi = phi ptr [ %ptr, %entry ], [ %gep, %if.then ]65 store i32 %value, ptr %phi, align 466 ret void67}68 69; Phi selects between two geps with same base, different nonconstant offsets70define void @test_phi_twogep_nonconst_offset(ptr %ptr, i32 %value, i32 %off1, i32 %off2) {71; CHECK-LABEL: @test_phi_twogep_nonconst_offset72; CHECK-NOT: phi ptr [ %gep1, %if.then ], [ %gep2, %if.else ]73; CHECK: phi i32 [ %off2, %if.else ], [ %off1, %if.then ]74entry:75 %cmp = icmp sgt i32 %value, 076 br i1 %cmp, label %if.then, label %if.else77 78if.then:79 %gep1 = getelementptr inbounds i32, ptr %ptr, i32 %off180 br label %if.end81 82if.else:83 %gep2 = getelementptr inbounds i32, ptr %ptr, i32 %off284 br label %if.end85 86if.end:87 %phi = phi ptr [ %gep1, %if.then ], [ %gep2, %if.else ]88 store i32 %value, ptr %phi, align 489 ret void90}91 92; Phi selects between two geps with different base, same constant offset93define void @test_phi_twogep_base(ptr %ptr1, ptr %ptr2, i32 %value) {94; CHECK-LABEL: @test_phi_twogep_base95; CHECK-NOT: phi ptr [ %gep1, %if.then ], [ %gep2, %if.else ]96; CHECK: phi ptr [ %ptr2, %if.else ], [ %ptr1, %if.then ]97entry:98 %cmp = icmp sgt i32 %value, 099 br i1 %cmp, label %if.then, label %if.else100 101if.then:102 %gep1 = getelementptr inbounds i32, ptr %ptr1, i32 1103 br label %if.end104 105if.else:106 %gep2 = getelementptr inbounds i32, ptr %ptr2, i32 1107 br label %if.end108 109if.end:110 %phi = phi ptr [ %gep1, %if.then ], [ %gep2, %if.else ]111 store i32 %value, ptr %phi, align 4112 ret void113}114 115; Phi selects between two geps with different base global variables, same constant offset116define void @test_phi_twogep_base_gv(i32 %value) {117; CHECK-LABEL: @test_phi_twogep_base_gv118; CHECK-NOT: phi ptr [ %gep1, %if.then ], [ %gep2, %if.else ]119; CHECK: phi ptr [ @gv2, %if.else ], [ @gv1, %if.then ]120entry:121 %cmp = icmp sgt i32 %value, 0122 br i1 %cmp, label %if.then, label %if.else123 124if.then:125 %gep1 = getelementptr inbounds i32, ptr @gv1, i32 1126 br label %if.end127 128if.else:129 %gep2 = getelementptr inbounds i32, ptr @gv2, i32 1130 br label %if.end131 132if.end:133 %phi = phi ptr [ %gep1, %if.then ], [ %gep2, %if.else ]134 store i32 %value, ptr %phi, align 4135 ret void136}137 138; Phi selects between ptr and gep with ptr as base and constant offset139define void @test_select_onegep_offset(ptr %ptr, i32 %value) {140; CHECK-LABEL: @test_select_onegep_offset141; CHECK-NOT: select i1 %cmp, ptr %ptr, ptr %gep142; CHECK: select i1 %cmp, i32 0, i32 4143entry:144 %cmp = icmp sgt i32 %value, 0145 %gep = getelementptr inbounds i32, ptr %ptr, i32 1146 %select = select i1 %cmp, ptr %ptr, ptr %gep147 store i32 %value, ptr %select, align 4148 ret void149}150 151; Select between two geps with same base, different constant offsets152define void @test_select_twogep_offset(ptr %ptr, i32 %value) {153; CHECK-LABEL: @test_select_twogep_offset154; CHECK-NOT: select i1 %cmp, ptr %gep1, ptr %gep2155; CHECK: select i1 %cmp, i32 4, i32 8156entry:157 %cmp = icmp sgt i32 %value, 0158 %gep1 = getelementptr inbounds i32, ptr %ptr, i32 1159 %gep2 = getelementptr inbounds i32, ptr %ptr, i32 2160 %select = select i1 %cmp, ptr %gep1, ptr %gep2161 store i32 %value, ptr %select, align 4162 ret void163}164 165; Select between ptr and gep with ptr as base and nonconstant offset166define void @test_select_onegep_nonconst_offset(ptr %ptr, i32 %value, i32 %off) {167; CHECK-LABEL: @test_select_onegep_nonconst_offset168; CHECK-NOT: select i1 %cmp, ptr %ptr, ptr %gep169; CHECK: select i1 %cmp, i32 0, i32 %off170entry:171 %cmp = icmp sgt i32 %value, 0172 %gep = getelementptr inbounds i32, ptr %ptr, i32 %off173 %select = select i1 %cmp, ptr %ptr, ptr %gep174 store i32 %value, ptr %select, align 4175 ret void176}177 178; Select between two geps with same base, different nonconstant offsets179define void @test_select_twogep_nonconst_offset(ptr %ptr, i32 %value, i32 %off1, i32 %off2) {180; CHECK-LABEL: @test_select_twogep_nonconst_offset181; CHECK-NOT: select i1 %cmp, ptr %gep1, ptr %gep2182; CHECK: select i1 %cmp, i32 %off1, i32 %off2183entry:184 %cmp = icmp sgt i32 %value, 0185 %gep1 = getelementptr inbounds i32, ptr %ptr, i32 %off1186 %gep2 = getelementptr inbounds i32, ptr %ptr, i32 %off2187 %select = select i1 %cmp, ptr %gep1, ptr %gep2188 store i32 %value, ptr %select, align 4189 ret void190}191 192; Select between two geps with different base, same constant offset193define void @test_select_twogep_base(ptr %ptr1, ptr %ptr2, i32 %value) {194; CHECK-LABEL: @test_select_twogep_base195; CHECK-NOT: select i1 %cmp, ptr %gep1, ptr %gep2196; CHECK: select i1 %cmp, ptr %ptr1, ptr %ptr2197entry:198 %cmp = icmp sgt i32 %value, 0199 %gep1 = getelementptr inbounds i32, ptr %ptr1, i32 1200 %gep2 = getelementptr inbounds i32, ptr %ptr2, i32 1201 %select = select i1 %cmp, ptr %gep1, ptr %gep2202 store i32 %value, ptr %select, align 4203 ret void204}205 206; Select between two geps with different base global variables, same constant offset207define void @test_select_twogep_base_gv(i32 %value) {208; CHECK-LABEL: @test_select_twogep_base_gv209; CHECK-NOT: select i1 %cmp, ptr %gep1, ptr %gep2210; CHECK: select i1 %cmp, ptr @gv1, ptr @gv2211entry:212 %cmp = icmp sgt i32 %value, 0213 %gep1 = getelementptr inbounds i32, ptr @gv1, i32 1214 %gep2 = getelementptr inbounds i32, ptr @gv2, i32 1215 %select = select i1 %cmp, ptr %gep1, ptr %gep2216 store i32 %value, ptr %select, align 4217 ret void218}219 220; If the phi is in a different block to where the gep will be, the phi goes where221; the original phi was not where the gep is.222; CHECK-LABEL: @test_phi_different_block223; CHECK-LABEL: if1.end224; CHECK-NOT: phi ptr [ %ptr, %entry ], [ %gep, %if1.then ]225; CHECK: phi i32 [ 4, %if1.then ], [ 0, %entry ]226define void @test_phi_different_block(ptr %ptr, i32 %value1, i32 %value2) {227entry:228 %cmp1 = icmp sgt i32 %value1, 0229 br i1 %cmp1, label %if1.then, label %if1.end230 231if1.then:232 %gep = getelementptr inbounds i32, ptr %ptr, i32 1233 br label %if1.end234 235if1.end:236 %phi = phi ptr [ %ptr, %entry ], [ %gep, %if1.then ]237 %cmp2 = icmp sgt i32 %value2, 0238 br i1 %cmp2, label %if2.then, label %if2.end239 240if2.then:241 store i32 %value1, ptr %ptr, align 4242 br label %if2.end243 244if2.end:245 store i32 %value2, ptr %phi, align 4246 ret void247}248 249; A phi with three incoming values should be optimised250; CHECK-LABEL: @test_phi_threegep251; CHECK-NOT: phi ptr [ %gep1, %if.then ], [ %gep2, %if.else.then ], [ %gep3, %if.else.else ]252; CHECK: phi i32 [ 12, %if.else.else ], [ 8, %if.else.then ], [ 4, %if.then ]253define void @test_phi_threegep(ptr %ptr, i32 %value1, i32 %value2) {254entry:255 %cmp1 = icmp sgt i32 %value1, 0256 br i1 %cmp1, label %if.then, label %if.else257 258if.then:259 %gep1 = getelementptr inbounds i32, ptr %ptr, i32 1260 br label %if.end261 262if.else:263 %cmp2 = icmp sgt i32 %value2, 0264 br i1 %cmp2, label %if.else.then, label %if.else.else265 266if.else.then:267 %gep2 = getelementptr inbounds i32, ptr %ptr, i32 2268 br label %if.end269 270if.else.else:271 %gep3 = getelementptr inbounds i32, ptr %ptr, i32 3272 br label %if.end273 274if.end:275 %phi = phi ptr [ %gep1, %if.then ], [ %gep2, %if.else.then ], [ %gep3, %if.else.else ]276 store i32 %value1, ptr %phi, align 4277 ret void278}279 280; A phi with two incoming values but three geps due to nesting should be281; optimised282; CHECK-LABEL: @test_phi_threegep_nested283; CHECK: %[[PHI:[a-z0-9_]+]] = phi i32 [ 12, %if.else.else ], [ 8, %if.else.then ]284; CHECK: phi i32 [ %[[PHI]], %if.else.end ], [ 4, %if.then ]285define void @test_phi_threegep_nested(ptr %ptr, i32 %value1, i32 %value2) {286entry:287 %cmp1 = icmp sgt i32 %value1, 0288 br i1 %cmp1, label %if.then, label %if.else289 290if.then:291 %gep1 = getelementptr inbounds i32, ptr %ptr, i32 1292 br label %if.end293 294if.else:295 %cmp2 = icmp sgt i32 %value2, 0296 br i1 %cmp2, label %if.else.then, label %if.else.else297 298if.else.then:299 %gep2 = getelementptr inbounds i32, ptr %ptr, i32 2300 br label %if.else.end301 302if.else.else:303 %gep3 = getelementptr inbounds i32, ptr %ptr, i32 3304 br label %if.else.end305 306if.else.end:307 %gep4 = phi ptr [ %gep2, %if.else.then ], [ %gep3, %if.else.else ]308 store i32 %value2, ptr %ptr, align 4309 br label %if.end310 311if.end:312 %phi = phi ptr [ %gep1, %if.then ], [ %gep4, %if.else.end ]313 store i32 %value1, ptr %phi, align 4314 ret void315}316 317; A nested select is expected to be optimised318; CHECK-LABEL: @test_nested_select319; CHECK: %[[SELECT:[a-z0-9_]+]] = select i1 %cmp2, i32 4, i32 8320; CHECK: select i1 %cmp1, i32 4, i32 %[[SELECT]]321define void @test_nested_select(ptr %ptr, i32 %value1, i32 %value2) {322entry:323 %gep1 = getelementptr inbounds i32, ptr %ptr, i32 1324 %gep2 = getelementptr inbounds i32, ptr %ptr, i32 2325 %cmp1 = icmp sgt i32 %value1, 0326 %cmp2 = icmp sgt i32 %value2, 0327 %select1 = select i1 %cmp2, ptr %gep1, ptr %gep2328 %select2 = select i1 %cmp1, ptr %gep1, ptr %select1329 store i32 %value1, ptr %select2, align 4330 ret void331}332 333; Scaling the offset by a different amount is expected not to be optimised334; CHECK-LABEL: @test_select_different_scale335; CHECK: select i1 %cmp, ptr %gep1, ptr %gep2336define void @test_select_different_scale(ptr %ptr, i32 %value, i32 %off) {337entry:338 %cmp = icmp sgt i32 %value, 0339 %gep1 = getelementptr inbounds i32, ptr %ptr, i32 %off340 %gep2 = getelementptr inbounds i16, ptr %ptr, i32 %off341 %select = select i1 %cmp, ptr %gep1, ptr %gep2342 store i32 %value, ptr %select, align 4343 ret void344}345 346; A select between two values is already the best we can do347; CHECK-LABEL: @test_select_trivial348; CHECK: select i1 %cmp, ptr %ptr1, ptr %ptr2349define void @test_select_trivial(ptr %ptr1, ptr %ptr2, i32 %value) {350entey:351 %cmp = icmp sgt i32 %value, 0352 %select = select i1 %cmp, ptr %ptr1, ptr %ptr2353 store i32 %value, ptr %select, align 4354 ret void355}356 357; A select between two global variables is already the best we can do358; CHECK-LABEL: @test_select_trivial_gv359; CHECK: select i1 %cmp, ptr @gv1, ptr @gv2360define void @test_select_trivial_gv(i32 %value) {361entey:362 %cmp = icmp sgt i32 %value, 0363 %select = select i1 %cmp, ptr @gv1, ptr @gv2364 store i32 %value, ptr %select, align 4365 ret void366}367 368; Same for a select between a value and global variable369; CHECK-LABEL: @test_select_trivial_ptr_gv370; CHECK: select i1 %cmp, ptr %ptr, ptr @gv2371define void @test_select_trivial_ptr_gv(ptr %ptr, i32 %value) {372entry:373 %cmp = icmp sgt i32 %value, 0374 %select = select i1 %cmp, ptr %ptr, ptr @gv2375 store i32 %value, ptr %select, align 4376 ret void377}378 379; Same for a select between a global variable and null, though the test needs to380; be a little more complicated to avoid dereferencing a potential null pointer381; CHECK-LABEL: @test_select_trivial_gv_null382; CHECK: select i1 %cmp.i, ptr @gv1, ptr null383define void @test_select_trivial_gv_null(){384entry:385 %gv1_val = load i32, ptr @gv1, align 4386 %cmp.i = icmp eq i32 %gv1_val, 0387 %spec.select.i = select i1 %cmp.i, ptr @gv1, ptr null388 br i1 %cmp.i, label %if.then, label %if.end389 390if.then:391 %val = load i32, ptr %spec.select.i, align 4392 %inc = add nsw i32 %val, 1393 store i32 %inc, ptr %spec.select.i, align 4394 br label %if.end395 396if.end:397 ret void398}399 400; Same for a select between a value and null401; CHECK-LABEL: @test_select_trivial_ptr_null402; CHECK: select i1 %cmp.i, ptr %ptr, ptr null403define void @test_select_trivial_ptr_null(ptr %ptr){404entry:405 %gv1_val = load i32, ptr %ptr, align 4406 %cmp.i = icmp eq i32 %gv1_val, 0407 %spec.select.i = select i1 %cmp.i, ptr %ptr, ptr null408 br i1 %cmp.i, label %if.then, label %if.end409 410if.then:411 %val = load i32, ptr %spec.select.i, align 4412 %inc = add nsw i32 %val, 1413 store i32 %inc, ptr %spec.select.i, align 4414 br label %if.end415 416if.end:417 ret void418}419