1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt < %s -passes=aggressive-instcombine -S | FileCheck %s 3 4; https://bugs.llvm.org/show_bug.cgi?id=34924 5 6define i32 @rotl(i32 %a, i32 %b) { 7; CHECK-LABEL: @rotl( 8; CHECK-NEXT: entry: 9; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[B:%.*]], 0 10; CHECK-NEXT: br i1 [[CMP]], label [[END:%.*]], label [[ROTBB:%.*]] 11; CHECK: rotbb: 12; CHECK-NEXT: br label [[END]] 13; CHECK: end: 14; CHECK-NEXT: [[TMP0:%.*]] = call i32 @llvm.fshl.i32(i32 [[A:%.*]], i32 [[A]], i32 [[B]]) 15; CHECK-NEXT: ret i32 [[TMP0]] 16; 17entry: 18 %cmp = icmp eq i32 %b, 0 19 br i1 %cmp, label %end, label %rotbb 20 21rotbb: 22 %sub = sub i32 32, %b 23 %shr = lshr i32 %a, %sub 24 %shl = shl i32 %a, %b 25 %or = or i32 %shr, %shl 26 br label %end 27 28end: 29 %cond = phi i32 [ %or, %rotbb ], [ %a, %entry ] 30 ret i32 %cond 31} 32 33define i32 @rotl_commute_phi(i32 %a, i32 %b) { 34; CHECK-LABEL: @rotl_commute_phi( 35; CHECK-NEXT: entry: 36; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[B:%.*]], 0 37; CHECK-NEXT: br i1 [[CMP]], label [[END:%.*]], label [[ROTBB:%.*]] 38; CHECK: rotbb: 39; CHECK-NEXT: br label [[END]] 40; CHECK: end: 41; CHECK-NEXT: [[TMP0:%.*]] = call i32 @llvm.fshl.i32(i32 [[A:%.*]], i32 [[A]], i32 [[B]]) 42; CHECK-NEXT: ret i32 [[TMP0]] 43; 44entry: 45 %cmp = icmp eq i32 %b, 0 46 br i1 %cmp, label %end, label %rotbb 47 48rotbb: 49 %sub = sub i32 32, %b 50 %shr = lshr i32 %a, %sub 51 %shl = shl i32 %a, %b 52 %or = or i32 %shr, %shl 53 br label %end 54 55end: 56 %cond = phi i32 [ %a, %entry ], [ %or, %rotbb ] 57 ret i32 %cond 58} 59 60define i32 @rotl_commute_or(i32 %a, i32 %b) { 61; CHECK-LABEL: @rotl_commute_or( 62; CHECK-NEXT: entry: 63; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[B:%.*]], 0 64; CHECK-NEXT: br i1 [[CMP]], label [[END:%.*]], label [[ROTBB:%.*]] 65; CHECK: rotbb: 66; CHECK-NEXT: br label [[END]] 67; CHECK: end: 68; CHECK-NEXT: [[TMP0:%.*]] = call i32 @llvm.fshl.i32(i32 [[A:%.*]], i32 [[A]], i32 [[B]]) 69; CHECK-NEXT: ret i32 [[TMP0]] 70; 71entry: 72 %cmp = icmp eq i32 %b, 0 73 br i1 %cmp, label %end, label %rotbb 74 75rotbb: 76 %sub = sub i32 32, %b 77 %shr = lshr i32 %a, %sub 78 %shl = shl i32 %a, %b 79 %or = or i32 %shl, %shr 80 br label %end 81 82end: 83 %cond = phi i32 [ %a, %entry ], [ %or, %rotbb ] 84 ret i32 %cond 85} 86 87; Verify that the intrinsic is inserted into a valid position. 88 89define i32 @rotl_insert_valid_location(i32 %a, i32 %b) { 90; CHECK-LABEL: @rotl_insert_valid_location( 91; CHECK-NEXT: entry: 92; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[B:%.*]], 0 93; CHECK-NEXT: br i1 [[CMP]], label [[END:%.*]], label [[ROTBB:%.*]] 94; CHECK: rotbb: 95; CHECK-NEXT: br label [[END]] 96; CHECK: end: 97; CHECK-NEXT: [[OTHER:%.*]] = phi i32 [ 1, [[ROTBB]] ], [ 2, [[ENTRY:%.*]] ] 98; CHECK-NEXT: [[TMP0:%.*]] = call i32 @llvm.fshl.i32(i32 [[A:%.*]], i32 [[A]], i32 [[B]]) 99; CHECK-NEXT: [[RES:%.*]] = or i32 [[TMP0]], [[OTHER]] 100; CHECK-NEXT: ret i32 [[RES]] 101; 102entry: 103 %cmp = icmp eq i32 %b, 0 104 br i1 %cmp, label %end, label %rotbb 105 106rotbb: 107 %sub = sub i32 32, %b 108 %shr = lshr i32 %a, %sub 109 %shl = shl i32 %a, %b 110 %or = or i32 %shr, %shl 111 br label %end 112 113end: 114 %cond = phi i32 [ %or, %rotbb ], [ %a, %entry ] 115 %other = phi i32 [ 1, %rotbb ], [ 2, %entry ] 116 %res = or i32 %cond, %other 117 ret i32 %res 118} 119 120define i32 @rotr(i32 %a, i32 %b) { 121; CHECK-LABEL: @rotr( 122; CHECK-NEXT: entry: 123; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[B:%.*]], 0 124; CHECK-NEXT: br i1 [[CMP]], label [[END:%.*]], label [[ROTBB:%.*]] 125; CHECK: rotbb: 126; CHECK-NEXT: br label [[END]] 127; CHECK: end: 128; CHECK-NEXT: [[TMP0:%.*]] = call i32 @llvm.fshr.i32(i32 [[A:%.*]], i32 [[A]], i32 [[B]]) 129; CHECK-NEXT: ret i32 [[TMP0]] 130; 131entry: 132 %cmp = icmp eq i32 %b, 0 133 br i1 %cmp, label %end, label %rotbb 134 135rotbb: 136 %sub = sub i32 32, %b 137 %shl = shl i32 %a, %sub 138 %shr = lshr i32 %a, %b 139 %or = or i32 %shr, %shl 140 br label %end 141 142end: 143 %cond = phi i32 [ %or, %rotbb ], [ %a, %entry ] 144 ret i32 %cond 145} 146 147define i32 @rotr_commute_phi(i32 %a, i32 %b) { 148; CHECK-LABEL: @rotr_commute_phi( 149; CHECK-NEXT: entry: 150; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[B:%.*]], 0 151; CHECK-NEXT: br i1 [[CMP]], label [[END:%.*]], label [[ROTBB:%.*]] 152; CHECK: rotbb: 153; CHECK-NEXT: br label [[END]] 154; CHECK: end: 155; CHECK-NEXT: [[TMP0:%.*]] = call i32 @llvm.fshr.i32(i32 [[A:%.*]], i32 [[A]], i32 [[B]]) 156; CHECK-NEXT: ret i32 [[TMP0]] 157; 158entry: 159 %cmp = icmp eq i32 %b, 0 160 br i1 %cmp, label %end, label %rotbb 161 162rotbb: 163 %sub = sub i32 32, %b 164 %shl = shl i32 %a, %sub 165 %shr = lshr i32 %a, %b 166 %or = or i32 %shr, %shl 167 br label %end 168 169end: 170 %cond = phi i32 [ %a, %entry ], [ %or, %rotbb ] 171 ret i32 %cond 172} 173 174define i32 @rotr_commute_or(i32 %a, i32 %b) { 175; CHECK-LABEL: @rotr_commute_or( 176; CHECK-NEXT: entry: 177; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[B:%.*]], 0 178; CHECK-NEXT: br i1 [[CMP]], label [[END:%.*]], label [[ROTBB:%.*]] 179; CHECK: rotbb: 180; CHECK-NEXT: br label [[END]] 181; CHECK: end: 182; CHECK-NEXT: [[TMP0:%.*]] = call i32 @llvm.fshr.i32(i32 [[A:%.*]], i32 [[A]], i32 [[B]]) 183; CHECK-NEXT: ret i32 [[TMP0]] 184; 185entry: 186 %cmp = icmp eq i32 %b, 0 187 br i1 %cmp, label %end, label %rotbb 188 189rotbb: 190 %sub = sub i32 32, %b 191 %shl = shl i32 %a, %sub 192 %shr = lshr i32 %a, %b 193 %or = or i32 %shl, %shr 194 br label %end 195 196end: 197 %cond = phi i32 [ %a, %entry ], [ %or, %rotbb ] 198 ret i32 %cond 199} 200 201; Negative test - non-power-of-2 might require urem expansion in the backend. 202 203define i12 @could_be_rotr_weird_type(i12 %a, i12 %b) { 204; CHECK-LABEL: @could_be_rotr_weird_type( 205; CHECK-NEXT: entry: 206; CHECK-NEXT: [[CMP:%.*]] = icmp eq i12 [[B:%.*]], 0 207; CHECK-NEXT: br i1 [[CMP]], label [[END:%.*]], label [[ROTBB:%.*]] 208; CHECK: rotbb: 209; CHECK-NEXT: [[SUB:%.*]] = sub i12 12, [[B]] 210; CHECK-NEXT: [[SHL:%.*]] = shl i12 [[A:%.*]], [[SUB]] 211; CHECK-NEXT: [[SHR:%.*]] = lshr i12 [[A]], [[B]] 212; CHECK-NEXT: [[OR:%.*]] = or i12 [[SHL]], [[SHR]] 213; CHECK-NEXT: br label [[END]] 214; CHECK: end: 215; CHECK-NEXT: [[COND:%.*]] = phi i12 [ [[A]], [[ENTRY:%.*]] ], [ [[OR]], [[ROTBB]] ] 216; CHECK-NEXT: ret i12 [[COND]] 217; 218entry: 219 %cmp = icmp eq i12 %b, 0 220 br i1 %cmp, label %end, label %rotbb 221 222rotbb: 223 %sub = sub i12 12, %b 224 %shl = shl i12 %a, %sub 225 %shr = lshr i12 %a, %b 226 %or = or i12 %shl, %shr 227 br label %end 228 229end: 230 %cond = phi i12 [ %a, %entry ], [ %or, %rotbb ] 231 ret i12 %cond 232} 233 234; Negative test - wrong phi ops. 235 236define i32 @not_rotr_1(i32 %a, i32 %b) { 237; CHECK-LABEL: @not_rotr_1( 238; CHECK-NEXT: entry: 239; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[B:%.*]], 0 240; CHECK-NEXT: br i1 [[CMP]], label [[END:%.*]], label [[ROTBB:%.*]] 241; CHECK: rotbb: 242; CHECK-NEXT: [[SUB:%.*]] = sub i32 32, [[B]] 243; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[A:%.*]], [[SUB]] 244; CHECK-NEXT: [[SHR:%.*]] = lshr i32 [[A]], [[B]] 245; CHECK-NEXT: [[OR:%.*]] = or i32 [[SHL]], [[SHR]] 246; CHECK-NEXT: br label [[END]] 247; CHECK: end: 248; CHECK-NEXT: [[COND:%.*]] = phi i32 [ [[B]], [[ENTRY:%.*]] ], [ [[OR]], [[ROTBB]] ] 249; CHECK-NEXT: ret i32 [[COND]] 250; 251entry: 252 %cmp = icmp eq i32 %b, 0 253 br i1 %cmp, label %end, label %rotbb 254 255rotbb: 256 %sub = sub i32 32, %b 257 %shl = shl i32 %a, %sub 258 %shr = lshr i32 %a, %b 259 %or = or i32 %shl, %shr 260 br label %end 261 262end: 263 %cond = phi i32 [ %b, %entry ], [ %or, %rotbb ] 264 ret i32 %cond 265} 266 267; Negative test - too many phi ops. 268 269define i32 @not_rotr_2(i32 %a, i32 %b, i32 %c) { 270; CHECK-LABEL: @not_rotr_2( 271; CHECK-NEXT: entry: 272; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[B:%.*]], 0 273; CHECK-NEXT: br i1 [[CMP]], label [[END:%.*]], label [[ROTBB:%.*]] 274; CHECK: rotbb: 275; CHECK-NEXT: [[SUB:%.*]] = sub i32 32, [[B]] 276; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[A:%.*]], [[SUB]] 277; CHECK-NEXT: [[SHR:%.*]] = lshr i32 [[A]], [[B]] 278; CHECK-NEXT: [[OR:%.*]] = or i32 [[SHL]], [[SHR]] 279; CHECK-NEXT: [[CMP42:%.*]] = icmp ugt i32 [[OR]], 42 280; CHECK-NEXT: br i1 [[CMP42]], label [[END]], label [[BOGUS:%.*]] 281; CHECK: bogus: 282; CHECK-NEXT: br label [[END]] 283; CHECK: end: 284; CHECK-NEXT: [[COND:%.*]] = phi i32 [ [[A]], [[ENTRY:%.*]] ], [ [[OR]], [[ROTBB]] ], [ [[C:%.*]], [[BOGUS]] ] 285; CHECK-NEXT: ret i32 [[COND]] 286; 287entry: 288 %cmp = icmp eq i32 %b, 0 289 br i1 %cmp, label %end, label %rotbb 290 291rotbb: 292 %sub = sub i32 32, %b 293 %shl = shl i32 %a, %sub 294 %shr = lshr i32 %a, %b 295 %or = or i32 %shl, %shr 296 %cmp42 = icmp ugt i32 %or, 42 297 br i1 %cmp42, label %end, label %bogus 298 299bogus: 300 br label %end 301 302end: 303 %cond = phi i32 [ %a, %entry ], [ %or, %rotbb ], [ %c, %bogus ] 304 ret i32 %cond 305} 306 307; Negative test - wrong cmp (but this should match?). 308 309define i32 @not_rotr_3(i32 %a, i32 %b) { 310; CHECK-LABEL: @not_rotr_3( 311; CHECK-NEXT: entry: 312; CHECK-NEXT: [[CMP:%.*]] = icmp sle i32 [[B:%.*]], 0 313; CHECK-NEXT: br i1 [[CMP]], label [[END:%.*]], label [[ROTBB:%.*]] 314; CHECK: rotbb: 315; CHECK-NEXT: [[SUB:%.*]] = sub i32 32, [[B]] 316; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[A:%.*]], [[SUB]] 317; CHECK-NEXT: [[SHR:%.*]] = lshr i32 [[A]], [[B]] 318; CHECK-NEXT: [[OR:%.*]] = or i32 [[SHL]], [[SHR]] 319; CHECK-NEXT: br label [[END]] 320; CHECK: end: 321; CHECK-NEXT: [[COND:%.*]] = phi i32 [ [[A]], [[ENTRY:%.*]] ], [ [[OR]], [[ROTBB]] ] 322; CHECK-NEXT: ret i32 [[COND]] 323; 324entry: 325 %cmp = icmp sle i32 %b, 0 326 br i1 %cmp, label %end, label %rotbb 327 328rotbb: 329 %sub = sub i32 32, %b 330 %shl = shl i32 %a, %sub 331 %shr = lshr i32 %a, %b 332 %or = or i32 %shl, %shr 333 br label %end 334 335end: 336 %cond = phi i32 [ %a, %entry ], [ %or, %rotbb ] 337 ret i32 %cond 338} 339 340; Negative test - wrong shift. 341 342define i32 @not_rotr_4(i32 %a, i32 %b) { 343; CHECK-LABEL: @not_rotr_4( 344; CHECK-NEXT: entry: 345; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[B:%.*]], 0 346; CHECK-NEXT: br i1 [[CMP]], label [[END:%.*]], label [[ROTBB:%.*]] 347; CHECK: rotbb: 348; CHECK-NEXT: [[SUB:%.*]] = sub i32 32, [[B]] 349; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[A:%.*]], [[SUB]] 350; CHECK-NEXT: [[SHR:%.*]] = ashr i32 [[A]], [[B]] 351; CHECK-NEXT: [[OR:%.*]] = or i32 [[SHL]], [[SHR]] 352; CHECK-NEXT: br label [[END]] 353; CHECK: end: 354; CHECK-NEXT: [[COND:%.*]] = phi i32 [ [[A]], [[ENTRY:%.*]] ], [ [[OR]], [[ROTBB]] ] 355; CHECK-NEXT: ret i32 [[COND]] 356; 357entry: 358 %cmp = icmp eq i32 %b, 0 359 br i1 %cmp, label %end, label %rotbb 360 361rotbb: 362 %sub = sub i32 32, %b 363 %shl = shl i32 %a, %sub 364 %shr = ashr i32 %a, %b 365 %or = or i32 %shl, %shr 366 br label %end 367 368end: 369 %cond = phi i32 [ %a, %entry ], [ %or, %rotbb ] 370 ret i32 %cond 371} 372 373; Negative test - wrong shift for rotate (but can be folded to a generic funnel shift). 374 375define i32 @not_rotr_5(i32 %a, i32 %b) { 376; CHECK-LABEL: @not_rotr_5( 377; CHECK-NEXT: entry: 378; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[B:%.*]], 0 379; CHECK-NEXT: br i1 [[CMP]], label [[END:%.*]], label [[ROTBB:%.*]] 380; CHECK: rotbb: 381; CHECK-NEXT: br label [[END]] 382; CHECK: end: 383; CHECK-NEXT: [[TMP0:%.*]] = call i32 @llvm.fshr.i32(i32 [[B]], i32 [[A:%.*]], i32 [[B]]) 384; CHECK-NEXT: ret i32 [[TMP0]] 385; 386entry: 387 %cmp = icmp eq i32 %b, 0 388 br i1 %cmp, label %end, label %rotbb 389 390rotbb: 391 %sub = sub i32 32, %b 392 %shl = shl i32 %b, %sub 393 %shr = lshr i32 %a, %b 394 %or = or i32 %shl, %shr 395 br label %end 396 397end: 398 %cond = phi i32 [ %a, %entry ], [ %or, %rotbb ] 399 ret i32 %cond 400} 401 402; Negative test - wrong sub. 403 404define i32 @not_rotr_6(i32 %a, i32 %b) { 405; CHECK-LABEL: @not_rotr_6( 406; CHECK-NEXT: entry: 407; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[B:%.*]], 0 408; CHECK-NEXT: br i1 [[CMP]], label [[END:%.*]], label [[ROTBB:%.*]] 409; CHECK: rotbb: 410; CHECK-NEXT: [[SUB:%.*]] = sub i32 8, [[B]] 411; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[A:%.*]], [[SUB]] 412; CHECK-NEXT: [[SHR:%.*]] = lshr i32 [[A]], [[B]] 413; CHECK-NEXT: [[OR:%.*]] = or i32 [[SHL]], [[SHR]] 414; CHECK-NEXT: br label [[END]] 415; CHECK: end: 416; CHECK-NEXT: [[COND:%.*]] = phi i32 [ [[A]], [[ENTRY:%.*]] ], [ [[OR]], [[ROTBB]] ] 417; CHECK-NEXT: ret i32 [[COND]] 418; 419entry: 420 %cmp = icmp eq i32 %b, 0 421 br i1 %cmp, label %end, label %rotbb 422 423rotbb: 424 %sub = sub i32 8, %b 425 %shl = shl i32 %a, %sub 426 %shr = lshr i32 %a, %b 427 %or = or i32 %shl, %shr 428 br label %end 429 430end: 431 %cond = phi i32 [ %a, %entry ], [ %or, %rotbb ] 432 ret i32 %cond 433} 434 435; Negative test - extra use. Technically, we could transform this 436; because it doesn't increase the instruction count, but we're 437; being cautious not to cause a potential perf pessimization for 438; targets that do not have a rotate instruction. 439 440define i32 @could_be_rotr(i32 %a, i32 %b, ptr %p) { 441; CHECK-LABEL: @could_be_rotr( 442; CHECK-NEXT: entry: 443; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[B:%.*]], 0 444; CHECK-NEXT: br i1 [[CMP]], label [[END:%.*]], label [[ROTBB:%.*]] 445; CHECK: rotbb: 446; CHECK-NEXT: [[SUB:%.*]] = sub i32 32, [[B]] 447; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[A:%.*]], [[SUB]] 448; CHECK-NEXT: [[SHR:%.*]] = lshr i32 [[A]], [[B]] 449; CHECK-NEXT: [[OR:%.*]] = or i32 [[SHL]], [[SHR]] 450; CHECK-NEXT: store i32 [[OR]], ptr [[P:%.*]], align 4 451; CHECK-NEXT: br label [[END]] 452; CHECK: end: 453; CHECK-NEXT: [[COND:%.*]] = phi i32 [ [[A]], [[ENTRY:%.*]] ], [ [[OR]], [[ROTBB]] ] 454; CHECK-NEXT: ret i32 [[COND]] 455; 456entry: 457 %cmp = icmp eq i32 %b, 0 458 br i1 %cmp, label %end, label %rotbb 459 460rotbb: 461 %sub = sub i32 32, %b 462 %shl = shl i32 %a, %sub 463 %shr = lshr i32 %a, %b 464 %or = or i32 %shl, %shr 465 store i32 %or, ptr %p 466 br label %end 467 468end: 469 %cond = phi i32 [ %a, %entry ], [ %or, %rotbb ] 470 ret i32 %cond 471} 472 473