Skip to content

Commit 10e7671

Browse files
authored
Reland "[InstCombine] Fold (sub nuw X, (Y << nuw Z)) >>u exact Z --> (X >>u exact Z) sub nuw Y" (#93571)
This is the same fold as ((X << nuw Z) sub nuw Y) >>u exact Z --> X sub nuw (Y >>u exact Z), but with the sub operands swapped. Alive2 Proof: https://alive2.llvm.org/ce/z/pT-RxG
1 parent f367eaa commit 10e7671

File tree

2 files changed

+124
-0
lines changed

2 files changed

+124
-0
lines changed

llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1275,6 +1275,17 @@ Instruction *InstCombinerImpl::visitLShr(BinaryOperator &I) {
12751275
return NewSub;
12761276
}
12771277

1278+
// (sub nuw X, (Y << nuw Z)) >>u exact Z --> (X >>u exact Z) sub nuw Y
1279+
if (I.isExact() &&
1280+
match(Op0, m_OneUse(m_NUWSub(m_Value(X),
1281+
m_NUWShl(m_Value(Y), m_Specific(Op1)))))) {
1282+
Value *NewLshr = Builder.CreateLShr(X, Op1, "", /*isExact=*/true);
1283+
auto *NewSub = BinaryOperator::CreateNUWSub(NewLshr, Y);
1284+
NewSub->setHasNoSignedWrap(
1285+
cast<OverflowingBinaryOperator>(Op0)->hasNoSignedWrap());
1286+
return NewSub;
1287+
}
1288+
12781289
auto isSuitableBinOpcode = [](Instruction::BinaryOps BinOpcode) {
12791290
switch (BinOpcode) {
12801291
default:

llvm/test/Transforms/InstCombine/lshr.ll

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -464,6 +464,119 @@ define i32 @shl_sub_lshr(i32 %x, i32 %c, i32 %y) {
464464
ret i32 %lshr
465465
}
466466

467+
define i32 @shl_sub_lshr_reverse(i32 %x, i32 %c, i32 %y) {
468+
; CHECK-LABEL: @shl_sub_lshr_reverse(
469+
; CHECK-NEXT: [[TMP1:%.*]] = lshr exact i32 [[Y:%.*]], [[C:%.*]]
470+
; CHECK-NEXT: [[LSHR:%.*]] = sub nuw nsw i32 [[TMP1]], [[X:%.*]]
471+
; CHECK-NEXT: ret i32 [[LSHR]]
472+
;
473+
%shl = shl nuw i32 %x, %c
474+
%sub = sub nuw nsw i32 %y, %shl
475+
%lshr = lshr exact i32 %sub, %c
476+
ret i32 %lshr
477+
}
478+
479+
define i32 @shl_sub_lshr_reverse_no_nsw(i32 %x, i32 %c, i32 %y) {
480+
; CHECK-LABEL: @shl_sub_lshr_reverse_no_nsw(
481+
; CHECK-NEXT: [[TMP1:%.*]] = lshr exact i32 [[Y:%.*]], [[C:%.*]]
482+
; CHECK-NEXT: [[LSHR:%.*]] = sub nuw i32 [[TMP1]], [[X:%.*]]
483+
; CHECK-NEXT: ret i32 [[LSHR]]
484+
;
485+
%shl = shl nuw i32 %x, %c
486+
%sub = sub nuw i32 %y, %shl
487+
%lshr = lshr exact i32 %sub, %c
488+
ret i32 %lshr
489+
}
490+
491+
define i32 @shl_sub_lshr_reverse_nsw_on_op1(i32 %x, i32 %c, i32 %y) {
492+
; CHECK-LABEL: @shl_sub_lshr_reverse_nsw_on_op1(
493+
; CHECK-NEXT: [[TMP1:%.*]] = lshr exact i32 [[Y:%.*]], [[C:%.*]]
494+
; CHECK-NEXT: [[LSHR:%.*]] = sub nuw i32 [[TMP1]], [[X:%.*]]
495+
; CHECK-NEXT: ret i32 [[LSHR]]
496+
;
497+
%shl = shl nuw nsw i32 %x, %c
498+
%sub = sub nuw i32 %y, %shl
499+
%lshr = lshr exact i32 %sub, %c
500+
ret i32 %lshr
501+
}
502+
503+
; Negative test
504+
505+
define i32 @shl_sub_lshr_reverse_no_exact(i32 %x, i32 %c, i32 %y) {
506+
; CHECK-LABEL: @shl_sub_lshr_reverse_no_exact(
507+
; CHECK-NEXT: [[SHL:%.*]] = shl nuw i32 [[X:%.*]], [[C:%.*]]
508+
; CHECK-NEXT: [[SUB:%.*]] = sub nuw nsw i32 [[Y:%.*]], [[SHL]]
509+
; CHECK-NEXT: [[LSHR:%.*]] = lshr i32 [[SUB]], [[C]]
510+
; CHECK-NEXT: ret i32 [[LSHR]]
511+
;
512+
%shl = shl nuw i32 %x, %c
513+
%sub = sub nuw nsw i32 %y, %shl
514+
%lshr = lshr i32 %sub, %c
515+
ret i32 %lshr
516+
}
517+
518+
; Negative test
519+
520+
define i32 @shl_sub_lshr_reverse_multiuse(i32 %x, i32 %c, i32 %y) {
521+
; CHECK-LABEL: @shl_sub_lshr_reverse_multiuse(
522+
; CHECK-NEXT: [[SHL:%.*]] = shl nuw i32 [[X:%.*]], [[C:%.*]]
523+
; CHECK-NEXT: [[SUB:%.*]] = sub nuw i32 [[Y:%.*]], [[SHL]]
524+
; CHECK-NEXT: call void @use(i32 [[SUB]])
525+
; CHECK-NEXT: [[LSHR:%.*]] = lshr exact i32 [[SUB]], [[C]]
526+
; CHECK-NEXT: ret i32 [[LSHR]]
527+
;
528+
%shl = shl nuw i32 %x, %c
529+
%sub = sub nuw i32 %y, %shl
530+
call void @use(i32 %sub)
531+
%lshr = lshr exact i32 %sub, %c
532+
ret i32 %lshr
533+
}
534+
535+
define i32 @shl_sub_lshr_reverse_multiuse2(i32 %x, i32 %c, i32 %y) {
536+
; CHECK-LABEL: @shl_sub_lshr_reverse_multiuse2(
537+
; CHECK-NEXT: [[SHL:%.*]] = shl nuw i32 [[X:%.*]], [[C:%.*]]
538+
; CHECK-NEXT: call void @use(i32 [[SHL]])
539+
; CHECK-NEXT: [[TMP1:%.*]] = lshr exact i32 [[Y:%.*]], [[C]]
540+
; CHECK-NEXT: [[LSHR:%.*]] = sub nuw i32 [[TMP1]], [[X]]
541+
; CHECK-NEXT: ret i32 [[LSHR]]
542+
;
543+
%shl = shl nuw i32 %x, %c
544+
call void @use(i32 %shl)
545+
%sub = sub nuw i32 %y, %shl
546+
%lshr = lshr exact i32 %sub, %c
547+
ret i32 %lshr
548+
}
549+
550+
; Negative test
551+
552+
define i32 @shl_sub_lshr_reverse_no_nuw(i32 %x, i32 %c, i32 %y) {
553+
; CHECK-LABEL: @shl_sub_lshr_reverse_no_nuw(
554+
; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[X:%.*]], [[C:%.*]]
555+
; CHECK-NEXT: [[SUB:%.*]] = sub nuw i32 [[Y:%.*]], [[SHL]]
556+
; CHECK-NEXT: [[LSHR:%.*]] = lshr exact i32 [[SUB]], [[C]]
557+
; CHECK-NEXT: ret i32 [[LSHR]]
558+
;
559+
%shl = shl i32 %x, %c
560+
%sub = sub nuw i32 %y, %shl
561+
%lshr = lshr exact i32 %sub, %c
562+
ret i32 %lshr
563+
}
564+
565+
; Negative test
566+
567+
define i32 @shl_sub_lshr_reverse_no_nsw_2(i32 %x, i32 %c, i32 %y) {
568+
; CHECK-LABEL: @shl_sub_lshr_reverse_no_nsw_2(
569+
; CHECK-NEXT: [[SHL:%.*]] = shl nuw nsw i32 [[X:%.*]], [[C:%.*]]
570+
; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[Y:%.*]], [[SHL]]
571+
; CHECK-NEXT: [[LSHR:%.*]] = lshr exact i32 [[SUB]], [[C]]
572+
; CHECK-NEXT: ret i32 [[LSHR]]
573+
;
574+
%shl = shl nuw nsw i32 %x, %c
575+
%sub = sub i32 %y, %shl
576+
%lshr = lshr exact i32 %sub, %c
577+
ret i32 %lshr
578+
}
579+
467580
define i32 @shl_or_lshr(i32 %x, i32 %c, i32 %y) {
468581
; CHECK-LABEL: @shl_or_lshr(
469582
; CHECK-NEXT: [[TMP1:%.*]] = lshr i32 [[Y:%.*]], [[C:%.*]]

0 commit comments

Comments
 (0)