1; RUN: opt -S -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(i32* %ptr, i32 %value) { 10; CHECK-LABEL: @test_phi_onegep_offset 11; CHECK-NOT: phi i32* [ %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, i32* %ptr, i32 1 19 br label %if.end 20 21if.end: 22 %phi = phi i32* [ %ptr, %entry ], [ %gep, %if.then ] 23 store i32 %value, i32* %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(i32* %ptr, i32 %value) { 29; CHECK-LABEL: @test_phi_twogep_offset 30; CHECK-NOT: phi i32* [ %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, i32* %ptr, i32 1 38 br label %if.end 39 40if.else: 41 %gep2 = getelementptr inbounds i32, i32* %ptr, i32 2 42 br label %if.end 43 44if.end: 45 %phi = phi i32* [ %gep1, %if.then ], [ %gep2, %if.else ] 46 store i32 %value, i32* %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(i32* %ptr, i32 %value, i32 %off) { 52; CHECK-LABEL: @test_phi_onegep_nonconst_offset 53; CHECK-NOT: phi i32* [ %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, i32* %ptr, i32 %off 61 br label %if.end 62 63if.end: 64 %phi = phi i32* [ %ptr, %entry ], [ %gep, %if.then ] 65 store i32 %value, i32* %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(i32* %ptr, i32 %value, i32 %off1, i32 %off2) { 71; CHECK-LABEL: @test_phi_twogep_nonconst_offset 72; CHECK-NOT: phi i32* [ %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, i32* %ptr, i32 %off1 80 br label %if.end 81 82if.else: 83 %gep2 = getelementptr inbounds i32, i32* %ptr, i32 %off2 84 br label %if.end 85 86if.end: 87 %phi = phi i32* [ %gep1, %if.then ], [ %gep2, %if.else ] 88 store i32 %value, i32* %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(i32* %ptr1, i32* %ptr2, i32 %value) { 94; CHECK-LABEL: @test_phi_twogep_base 95; CHECK-NOT: phi i32* [ %gep1, %if.then ], [ %gep2, %if.else ] 96; CHECK: phi i32* [ %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, i32* %ptr1, i32 1 103 br label %if.end 104 105if.else: 106 %gep2 = getelementptr inbounds i32, i32* %ptr2, i32 1 107 br label %if.end 108 109if.end: 110 %phi = phi i32* [ %gep1, %if.then ], [ %gep2, %if.else ] 111 store i32 %value, i32* %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 i32* [ %gep1, %if.then ], [ %gep2, %if.else ] 119; CHECK: phi i32* [ @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, i32* @gv1, i32 1 126 br label %if.end 127 128if.else: 129 %gep2 = getelementptr inbounds i32, i32* @gv2, i32 1 130 br label %if.end 131 132if.end: 133 %phi = phi i32* [ %gep1, %if.then ], [ %gep2, %if.else ] 134 store i32 %value, i32* %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(i32* %ptr, i32 %value) { 140; CHECK-LABEL: @test_select_onegep_offset 141; CHECK-NOT: select i1 %cmp, i32* %ptr, i32* %gep 142; CHECK: select i1 %cmp, i32 0, i32 4 143entry: 144 %cmp = icmp sgt i32 %value, 0 145 %gep = getelementptr inbounds i32, i32* %ptr, i32 1 146 %select = select i1 %cmp, i32* %ptr, i32* %gep 147 store i32 %value, i32* %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(i32* %ptr, i32 %value) { 153; CHECK-LABEL: @test_select_twogep_offset 154; CHECK-NOT: select i1 %cmp, i32* %gep1, i32* %gep2 155; CHECK: select i1 %cmp, i32 4, i32 8 156entry: 157 %cmp = icmp sgt i32 %value, 0 158 %gep1 = getelementptr inbounds i32, i32* %ptr, i32 1 159 %gep2 = getelementptr inbounds i32, i32* %ptr, i32 2 160 %select = select i1 %cmp, i32* %gep1, i32* %gep2 161 store i32 %value, i32* %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(i32* %ptr, i32 %value, i32 %off) { 167; CHECK-LABEL: @test_select_onegep_nonconst_offset 168; CHECK-NOT: select i1 %cmp, i32* %ptr, i32* %gep 169; CHECK: select i1 %cmp, i32 0, i32 %off 170entry: 171 %cmp = icmp sgt i32 %value, 0 172 %gep = getelementptr inbounds i32, i32* %ptr, i32 %off 173 %select = select i1 %cmp, i32* %ptr, i32* %gep 174 store i32 %value, i32* %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(i32* %ptr, i32 %value, i32 %off1, i32 %off2) { 180; CHECK-LABEL: @test_select_twogep_nonconst_offset 181; CHECK-NOT: select i1 %cmp, i32* %gep1, i32* %gep2 182; CHECK: select i1 %cmp, i32 %off1, i32 %off2 183entry: 184 %cmp = icmp sgt i32 %value, 0 185 %gep1 = getelementptr inbounds i32, i32* %ptr, i32 %off1 186 %gep2 = getelementptr inbounds i32, i32* %ptr, i32 %off2 187 %select = select i1 %cmp, i32* %gep1, i32* %gep2 188 store i32 %value, i32* %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(i32* %ptr1, i32* %ptr2, i32 %value) { 194; CHECK-LABEL: @test_select_twogep_base 195; CHECK-NOT: select i1 %cmp, i32* %gep1, i32* %gep2 196; CHECK: select i1 %cmp, i32* %ptr1, i32* %ptr2 197entry: 198 %cmp = icmp sgt i32 %value, 0 199 %gep1 = getelementptr inbounds i32, i32* %ptr1, i32 1 200 %gep2 = getelementptr inbounds i32, i32* %ptr2, i32 1 201 %select = select i1 %cmp, i32* %gep1, i32* %gep2 202 store i32 %value, i32* %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, i32* %gep1, i32* %gep2 210; CHECK: select i1 %cmp, i32* @gv1, i32* @gv2 211entry: 212 %cmp = icmp sgt i32 %value, 0 213 %gep1 = getelementptr inbounds i32, i32* @gv1, i32 1 214 %gep2 = getelementptr inbounds i32, i32* @gv2, i32 1 215 %select = select i1 %cmp, i32* %gep1, i32* %gep2 216 store i32 %value, i32* %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 i32* [ %ptr, %entry ], [ %gep, %if1.then ] 225; CHECK: phi i32 [ 4, %if1.then ], [ 0, %entry ] 226define void @test_phi_different_block(i32* %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, i32* %ptr, i32 1 233 br label %if1.end 234 235if1.end: 236 %phi = phi i32* [ %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, i32* %ptr, align 4 242 br label %if2.end 243 244if2.end: 245 store i32 %value2, i32* %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 i32* [ %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(i32* %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, i32* %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, i32* %ptr, i32 2 268 br label %if.end 269 270if.else.else: 271 %gep3 = getelementptr inbounds i32, i32* %ptr, i32 3 272 br label %if.end 273 274if.end: 275 %phi = phi i32* [ %gep1, %if.then ], [ %gep2, %if.else.then ], [ %gep3, %if.else.else ] 276 store i32 %value1, i32* %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(i32* %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, i32* %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, i32* %ptr, i32 2 300 br label %if.else.end 301 302if.else.else: 303 %gep3 = getelementptr inbounds i32, i32* %ptr, i32 3 304 br label %if.else.end 305 306if.else.end: 307 %gep4 = phi i32* [ %gep2, %if.else.then ], [ %gep3, %if.else.else ] 308 store i32 %value2, i32* %ptr, align 4 309 br label %if.end 310 311if.end: 312 %phi = phi i32* [ %gep1, %if.then ], [ %gep4, %if.else.end ] 313 store i32 %value1, i32* %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(i32* %ptr, i32 %value1, i32 %value2) { 322entry: 323 %gep1 = getelementptr inbounds i32, i32* %ptr, i32 1 324 %gep2 = getelementptr inbounds i32, i32* %ptr, i32 2 325 %cmp1 = icmp sgt i32 %value1, 0 326 %cmp2 = icmp sgt i32 %value2, 0 327 %select1 = select i1 %cmp2, i32* %gep1, i32* %gep2 328 %select2 = select i1 %cmp1, i32* %gep1, i32* %select1 329 store i32 %value1, i32* %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, i32* %gep1, i32* %castgep 336define void @test_select_different_scale(i32* %ptr, i32 %value, i32 %off) { 337entry: 338 %cmp = icmp sgt i32 %value, 0 339 %castptr = bitcast i32* %ptr to i16* 340 %gep1 = getelementptr inbounds i32, i32* %ptr, i32 %off 341 %gep2 = getelementptr inbounds i16, i16* %castptr, i32 %off 342 %castgep = bitcast i16* %gep2 to i32* 343 %select = select i1 %cmp, i32* %gep1, i32* %castgep 344 store i32 %value, i32* %select, align 4 345 ret void 346} 347 348; A select between two values is already the best we can do 349; CHECK-LABEL: @test_select_trivial 350; CHECK: select i1 %cmp, i32* %ptr1, i32* %ptr2 351define void @test_select_trivial(i32* %ptr1, i32* %ptr2, i32 %value) { 352entey: 353 %cmp = icmp sgt i32 %value, 0 354 %select = select i1 %cmp, i32* %ptr1, i32* %ptr2 355 store i32 %value, i32* %select, align 4 356 ret void 357} 358 359; A select between two global variables is already the best we can do 360; CHECK-LABEL: @test_select_trivial_gv 361; CHECK: select i1 %cmp, i32* @gv1, i32* @gv2 362define void @test_select_trivial_gv(i32 %value) { 363entey: 364 %cmp = icmp sgt i32 %value, 0 365 %select = select i1 %cmp, i32* @gv1, i32* @gv2 366 store i32 %value, i32* %select, align 4 367 ret void 368} 369 370; Same for a select between a value and global variable 371; CHECK-LABEL: @test_select_trivial_ptr_gv 372; CHECK: select i1 %cmp, i32* %ptr, i32* @gv2 373define void @test_select_trivial_ptr_gv(i32* %ptr, i32 %value) { 374entry: 375 %cmp = icmp sgt i32 %value, 0 376 %select = select i1 %cmp, i32* %ptr, i32* @gv2 377 store i32 %value, i32* %select, align 4 378 ret void 379} 380 381; Same for a select between a global variable and null, though the test needs to 382; be a little more complicated to avoid dereferencing a potential null pointer 383; CHECK-LABEL: @test_select_trivial_gv_null 384; CHECK: select i1 %cmp.i, i32* @gv1, i32* null 385define void @test_select_trivial_gv_null(){ 386entry: 387 %gv1_val = load i32, i32* @gv1, align 4 388 %cmp.i = icmp eq i32 %gv1_val, 0 389 %spec.select.i = select i1 %cmp.i, i32* @gv1, i32* null 390 br i1 %cmp.i, label %if.then, label %if.end 391 392if.then: 393 %val = load i32, i32* %spec.select.i, align 4 394 %inc = add nsw i32 %val, 1 395 store i32 %inc, i32* %spec.select.i, align 4 396 br label %if.end 397 398if.end: 399 ret void 400} 401 402; Same for a select between a value and null 403; CHECK-LABEL: @test_select_trivial_ptr_null 404; CHECK: select i1 %cmp.i, i32* %ptr, i32* null 405define void @test_select_trivial_ptr_null(i32* %ptr){ 406entry: 407 %gv1_val = load i32, i32* %ptr, align 4 408 %cmp.i = icmp eq i32 %gv1_val, 0 409 %spec.select.i = select i1 %cmp.i, i32* %ptr, i32* null 410 br i1 %cmp.i, label %if.then, label %if.end 411 412if.then: 413 %val = load i32, i32* %spec.select.i, align 4 414 %inc = add nsw i32 %val, 1 415 store i32 %inc, i32* %spec.select.i, align 4 416 br label %if.end 417 418if.end: 419 ret void 420} 421