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 %s 2 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 4 6@gv2 = common global i32 0, align 4 7 8; Phi selects between ptr and gep with ptr as base and constant offset 9define void @test_phi_onegep_offset(ptr %ptr, i32 %value) { 10; CHECK-LABEL: @test_phi_onegep_offset 11; 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, 0 15 br i1 %cmp, label %if.then, label %if.end 16 17if.then: 18 %gep = getelementptr inbounds i32, ptr %ptr, i32 1 19 br label %if.end 20 21if.end: 22 %phi = phi ptr [ %ptr, %entry ], [ %gep, %if.then ] 23 store i32 %value, ptr %phi, align 4 24 ret void 25} 26 27; Phi selects between two geps with same base, different constant offsets 28define void @test_phi_twogep_offset(ptr %ptr, i32 %value) { 29; CHECK-LABEL: @test_phi_twogep_offset 30; 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, 0 34 br i1 %cmp, label %if.then, label %if.else 35 36if.then: 37 %gep1 = getelementptr inbounds i32, ptr %ptr, i32 1 38 br label %if.end 39 40if.else: 41 %gep2 = getelementptr inbounds i32, ptr %ptr, i32 2 42 br label %if.end 43 44if.end: 45 %phi = phi ptr [ %gep1, %if.then ], [ %gep2, %if.else ] 46 store i32 %value, ptr %phi, align 4 47 ret void 48} 49 50; Phi selects between ptr and gep with ptr as base and nonconstant offset 51define void @test_phi_onegep_nonconst_offset(ptr %ptr, i32 %value, i32 %off) { 52; CHECK-LABEL: @test_phi_onegep_nonconst_offset 53; 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, 0 57 br i1 %cmp, label %if.then, label %if.end 58 59if.then: 60 %gep = getelementptr inbounds i32, ptr %ptr, i32 %off 61 br label %if.end 62 63if.end: 64 %phi = phi ptr [ %ptr, %entry ], [ %gep, %if.then ] 65 store i32 %value, ptr %phi, align 4 66 ret void 67} 68 69; Phi selects between two geps with same base, different nonconstant offsets 70define void @test_phi_twogep_nonconst_offset(ptr %ptr, i32 %value, i32 %off1, i32 %off2) { 71; CHECK-LABEL: @test_phi_twogep_nonconst_offset 72; 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, 0 76 br i1 %cmp, label %if.then, label %if.else 77 78if.then: 79 %gep1 = getelementptr inbounds i32, ptr %ptr, i32 %off1 80 br label %if.end 81 82if.else: 83 %gep2 = getelementptr inbounds i32, ptr %ptr, i32 %off2 84 br label %if.end 85 86if.end: 87 %phi = phi ptr [ %gep1, %if.then ], [ %gep2, %if.else ] 88 store i32 %value, ptr %phi, align 4 89 ret void 90} 91 92; Phi selects between two geps with different base, same constant offset 93define void @test_phi_twogep_base(ptr %ptr1, ptr %ptr2, i32 %value) { 94; CHECK-LABEL: @test_phi_twogep_base 95; 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, 0 99 br i1 %cmp, label %if.then, label %if.else 100 101if.then: 102 %gep1 = getelementptr inbounds i32, ptr %ptr1, i32 1 103 br label %if.end 104 105if.else: 106 %gep2 = getelementptr inbounds i32, ptr %ptr2, i32 1 107 br label %if.end 108 109if.end: 110 %phi = phi ptr [ %gep1, %if.then ], [ %gep2, %if.else ] 111 store i32 %value, ptr %phi, align 4 112 ret void 113} 114 115; Phi selects between two geps with different base global variables, same constant offset 116define void @test_phi_twogep_base_gv(i32 %value) { 117; CHECK-LABEL: @test_phi_twogep_base_gv 118; 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, 0 122 br i1 %cmp, label %if.then, label %if.else 123 124if.then: 125 %gep1 = getelementptr inbounds i32, ptr @gv1, i32 1 126 br label %if.end 127 128if.else: 129 %gep2 = getelementptr inbounds i32, ptr @gv2, i32 1 130 br label %if.end 131 132if.end: 133 %phi = phi ptr [ %gep1, %if.then ], [ %gep2, %if.else ] 134 store i32 %value, ptr %phi, align 4 135 ret void 136} 137 138; Phi selects between ptr and gep with ptr as base and constant offset 139define void @test_select_onegep_offset(ptr %ptr, i32 %value) { 140; CHECK-LABEL: @test_select_onegep_offset 141; CHECK-NOT: select i1 %cmp, ptr %ptr, ptr %gep 142; CHECK: select i1 %cmp, i32 0, i32 4 143entry: 144 %cmp = icmp sgt i32 %value, 0 145 %gep = getelementptr inbounds i32, ptr %ptr, i32 1 146 %select = select i1 %cmp, ptr %ptr, ptr %gep 147 store i32 %value, ptr %select, align 4 148 ret void 149} 150 151; Select between two geps with same base, different constant offsets 152define void @test_select_twogep_offset(ptr %ptr, i32 %value) { 153; CHECK-LABEL: @test_select_twogep_offset 154; CHECK-NOT: select i1 %cmp, ptr %gep1, ptr %gep2 155; CHECK: select i1 %cmp, i32 4, i32 8 156entry: 157 %cmp = icmp sgt i32 %value, 0 158 %gep1 = getelementptr inbounds i32, ptr %ptr, i32 1 159 %gep2 = getelementptr inbounds i32, ptr %ptr, i32 2 160 %select = select i1 %cmp, ptr %gep1, ptr %gep2 161 store i32 %value, ptr %select, align 4 162 ret void 163} 164 165; Select between ptr and gep with ptr as base and nonconstant offset 166define void @test_select_onegep_nonconst_offset(ptr %ptr, i32 %value, i32 %off) { 167; CHECK-LABEL: @test_select_onegep_nonconst_offset 168; CHECK-NOT: select i1 %cmp, ptr %ptr, ptr %gep 169; CHECK: select i1 %cmp, i32 0, i32 %off 170entry: 171 %cmp = icmp sgt i32 %value, 0 172 %gep = getelementptr inbounds i32, ptr %ptr, i32 %off 173 %select = select i1 %cmp, ptr %ptr, ptr %gep 174 store i32 %value, ptr %select, align 4 175 ret void 176} 177 178; Select between two geps with same base, different nonconstant offsets 179define void @test_select_twogep_nonconst_offset(ptr %ptr, i32 %value, i32 %off1, i32 %off2) { 180; CHECK-LABEL: @test_select_twogep_nonconst_offset 181; CHECK-NOT: select i1 %cmp, ptr %gep1, ptr %gep2 182; CHECK: select i1 %cmp, i32 %off1, i32 %off2 183entry: 184 %cmp = icmp sgt i32 %value, 0 185 %gep1 = getelementptr inbounds i32, ptr %ptr, i32 %off1 186 %gep2 = getelementptr inbounds i32, ptr %ptr, i32 %off2 187 %select = select i1 %cmp, ptr %gep1, ptr %gep2 188 store i32 %value, ptr %select, align 4 189 ret void 190} 191 192; Select between two geps with different base, same constant offset 193define void @test_select_twogep_base(ptr %ptr1, ptr %ptr2, i32 %value) { 194; CHECK-LABEL: @test_select_twogep_base 195; CHECK-NOT: select i1 %cmp, ptr %gep1, ptr %gep2 196; CHECK: select i1 %cmp, ptr %ptr1, ptr %ptr2 197entry: 198 %cmp = icmp sgt i32 %value, 0 199 %gep1 = getelementptr inbounds i32, ptr %ptr1, i32 1 200 %gep2 = getelementptr inbounds i32, ptr %ptr2, i32 1 201 %select = select i1 %cmp, ptr %gep1, ptr %gep2 202 store i32 %value, ptr %select, align 4 203 ret void 204} 205 206; Select between two geps with different base global variables, same constant offset 207define void @test_select_twogep_base_gv(i32 %value) { 208; CHECK-LABEL: @test_select_twogep_base_gv 209; CHECK-NOT: select i1 %cmp, ptr %gep1, ptr %gep2 210; CHECK: select i1 %cmp, ptr @gv1, ptr @gv2 211entry: 212 %cmp = icmp sgt i32 %value, 0 213 %gep1 = getelementptr inbounds i32, ptr @gv1, i32 1 214 %gep2 = getelementptr inbounds i32, ptr @gv2, i32 1 215 %select = select i1 %cmp, ptr %gep1, ptr %gep2 216 store i32 %value, ptr %select, align 4 217 ret void 218} 219 220; If the phi is in a different block to where the gep will be, the phi goes where 221; the original phi was not where the gep is. 222; CHECK-LABEL: @test_phi_different_block 223; CHECK-LABEL: if1.end 224; 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, 0 229 br i1 %cmp1, label %if1.then, label %if1.end 230 231if1.then: 232 %gep = getelementptr inbounds i32, ptr %ptr, i32 1 233 br label %if1.end 234 235if1.end: 236 %phi = phi ptr [ %ptr, %entry ], [ %gep, %if1.then ] 237 %cmp2 = icmp sgt i32 %value2, 0 238 br i1 %cmp2, label %if2.then, label %if2.end 239 240if2.then: 241 store i32 %value1, ptr %ptr, align 4 242 br label %if2.end 243 244if2.end: 245 store i32 %value2, ptr %phi, align 4 246 ret void 247} 248 249; A phi with three incoming values should be optimised 250; CHECK-LABEL: @test_phi_threegep 251; 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, 0 256 br i1 %cmp1, label %if.then, label %if.else 257 258if.then: 259 %gep1 = getelementptr inbounds i32, ptr %ptr, i32 1 260 br label %if.end 261 262if.else: 263 %cmp2 = icmp sgt i32 %value2, 0 264 br i1 %cmp2, label %if.else.then, label %if.else.else 265 266if.else.then: 267 %gep2 = getelementptr inbounds i32, ptr %ptr, i32 2 268 br label %if.end 269 270if.else.else: 271 %gep3 = getelementptr inbounds i32, ptr %ptr, i32 3 272 br label %if.end 273 274if.end: 275 %phi = phi ptr [ %gep1, %if.then ], [ %gep2, %if.else.then ], [ %gep3, %if.else.else ] 276 store i32 %value1, ptr %phi, align 4 277 ret void 278} 279 280; A phi with two incoming values but three geps due to nesting should be 281; optimised 282; CHECK-LABEL: @test_phi_threegep_nested 283; 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, 0 288 br i1 %cmp1, label %if.then, label %if.else 289 290if.then: 291 %gep1 = getelementptr inbounds i32, ptr %ptr, i32 1 292 br label %if.end 293 294if.else: 295 %cmp2 = icmp sgt i32 %value2, 0 296 br i1 %cmp2, label %if.else.then, label %if.else.else 297 298if.else.then: 299 %gep2 = getelementptr inbounds i32, ptr %ptr, i32 2 300 br label %if.else.end 301 302if.else.else: 303 %gep3 = getelementptr inbounds i32, ptr %ptr, i32 3 304 br label %if.else.end 305 306if.else.end: 307 %gep4 = phi ptr [ %gep2, %if.else.then ], [ %gep3, %if.else.else ] 308 store i32 %value2, ptr %ptr, align 4 309 br label %if.end 310 311if.end: 312 %phi = phi ptr [ %gep1, %if.then ], [ %gep4, %if.else.end ] 313 store i32 %value1, ptr %phi, align 4 314 ret void 315} 316 317; A nested select is expected to be optimised 318; CHECK-LABEL: @test_nested_select 319; CHECK: %[[SELECT:[a-z0-9_]+]] = select i1 %cmp2, i32 4, i32 8 320; 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 1 324 %gep2 = getelementptr inbounds i32, ptr %ptr, i32 2 325 %cmp1 = icmp sgt i32 %value1, 0 326 %cmp2 = icmp sgt i32 %value2, 0 327 %select1 = select i1 %cmp2, ptr %gep1, ptr %gep2 328 %select2 = select i1 %cmp1, ptr %gep1, ptr %select1 329 store i32 %value1, ptr %select2, align 4 330 ret void 331} 332 333; Scaling the offset by a different amount is expected not to be optimised 334; CHECK-LABEL: @test_select_different_scale 335; CHECK: select i1 %cmp, ptr %gep1, ptr %gep2 336define void @test_select_different_scale(ptr %ptr, i32 %value, i32 %off) { 337entry: 338 %cmp = icmp sgt i32 %value, 0 339 %gep1 = getelementptr inbounds i32, ptr %ptr, i32 %off 340 %gep2 = getelementptr inbounds i16, ptr %ptr, i32 %off 341 %select = select i1 %cmp, ptr %gep1, ptr %gep2 342 store i32 %value, ptr %select, align 4 343 ret void 344} 345 346; A select between two values is already the best we can do 347; CHECK-LABEL: @test_select_trivial 348; CHECK: select i1 %cmp, ptr %ptr1, ptr %ptr2 349define void @test_select_trivial(ptr %ptr1, ptr %ptr2, i32 %value) { 350entey: 351 %cmp = icmp sgt i32 %value, 0 352 %select = select i1 %cmp, ptr %ptr1, ptr %ptr2 353 store i32 %value, ptr %select, align 4 354 ret void 355} 356 357; A select between two global variables is already the best we can do 358; CHECK-LABEL: @test_select_trivial_gv 359; CHECK: select i1 %cmp, ptr @gv1, ptr @gv2 360define void @test_select_trivial_gv(i32 %value) { 361entey: 362 %cmp = icmp sgt i32 %value, 0 363 %select = select i1 %cmp, ptr @gv1, ptr @gv2 364 store i32 %value, ptr %select, align 4 365 ret void 366} 367 368; Same for a select between a value and global variable 369; CHECK-LABEL: @test_select_trivial_ptr_gv 370; CHECK: select i1 %cmp, ptr %ptr, ptr @gv2 371define void @test_select_trivial_ptr_gv(ptr %ptr, i32 %value) { 372entry: 373 %cmp = icmp sgt i32 %value, 0 374 %select = select i1 %cmp, ptr %ptr, ptr @gv2 375 store i32 %value, ptr %select, align 4 376 ret void 377} 378 379; Same for a select between a global variable and null, though the test needs to 380; be a little more complicated to avoid dereferencing a potential null pointer 381; CHECK-LABEL: @test_select_trivial_gv_null 382; CHECK: select i1 %cmp.i, ptr @gv1, ptr null 383define void @test_select_trivial_gv_null(){ 384entry: 385 %gv1_val = load i32, ptr @gv1, align 4 386 %cmp.i = icmp eq i32 %gv1_val, 0 387 %spec.select.i = select i1 %cmp.i, ptr @gv1, ptr null 388 br i1 %cmp.i, label %if.then, label %if.end 389 390if.then: 391 %val = load i32, ptr %spec.select.i, align 4 392 %inc = add nsw i32 %val, 1 393 store i32 %inc, ptr %spec.select.i, align 4 394 br label %if.end 395 396if.end: 397 ret void 398} 399 400; Same for a select between a value and null 401; CHECK-LABEL: @test_select_trivial_ptr_null 402; CHECK: select i1 %cmp.i, ptr %ptr, ptr null 403define void @test_select_trivial_ptr_null(ptr %ptr){ 404entry: 405 %gv1_val = load i32, ptr %ptr, align 4 406 %cmp.i = icmp eq i32 %gv1_val, 0 407 %spec.select.i = select i1 %cmp.i, ptr %ptr, ptr null 408 br i1 %cmp.i, label %if.then, label %if.end 409 410if.then: 411 %val = load i32, ptr %spec.select.i, align 4 412 %inc = add nsw i32 %val, 1 413 store i32 %inc, ptr %spec.select.i, align 4 414 br label %if.end 415 416if.end: 417 ret void 418} 419