diff --git a/llvm/lib/Transforms/Scalar/DivRemPairs.cpp b/llvm/lib/Transforms/Scalar/DivRemPairs.cpp --- a/llvm/lib/Transforms/Scalar/DivRemPairs.cpp +++ b/llvm/lib/Transforms/Scalar/DivRemPairs.cpp @@ -267,10 +267,28 @@ // DivBB will always reach the Div/Rem, we can hoist Div to PredBB. If // we have a DivRem operation we can also hoist Rem. Otherwise we'll leave // Rem where it is and rewrite it to mul/sub. - // FIXME: We could handle more hoisting cases. - if (RemBB->getSingleSuccessor() == DivBB) + if (RemBB->getSingleSuccessor() == DivBB) { PredBB = RemBB->getUniquePredecessor(); + // Look for something like this + // PredBB + // / \ + // Div Rem + // + // If the Rem and Din blocks share a unique predecessor, and and all paths + // from PredBB go to either RemBB or DivBB, and execution of RemBB and + // DivBB will always reach the Div/Rem, we can hoist Div to PredBB. If + // we have a DivRem operation we can also hoist Rem. Otherwise we'll leave + // Rem where it is and rewrite it to mul/sub. + } else if (BasicBlock* RemPredBB = RemBB->getUniquePredecessor()) { + // This hoist is only profitable when the target has a DivRem op. + if (HasDivRemOp && RemPredBB == DivBB->getUniquePredecessor()) { + PredBB = RemPredBB; + } + } + // FIXME: We could handle more hoisting cases. + + if (PredBB && IsSafeToHoist(RemInst, RemBB) && IsSafeToHoist(DivInst, DivBB) && all_of(successors(PredBB), diff --git a/llvm/test/Transforms/DivRemPairs/MSP430/div-rem-pairs.ll b/llvm/test/Transforms/DivRemPairs/MSP430/div-rem-pairs.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/DivRemPairs/MSP430/div-rem-pairs.ll @@ -0,0 +1,35 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -passes=div-rem-pairs -S -mtriple=msp430-unknown-unknown | FileCheck %s + +; Do not hoist to the common predecessor block since we don't +; have a div-rem operation. + +define i32 @no_domination(i1 %cmp, i32 %a, i32 %b) { +; CHECK-LABEL: @no_domination( +; CHECK-NEXT: entry: +; CHECK-NEXT: br i1 [[CMP:%.*]], label [[IF:%.*]], label [[ELSE:%.*]] +; CHECK: if: +; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: br label [[END:%.*]] +; CHECK: else: +; CHECK-NEXT: [[REM:%.*]] = srem i32 [[A]], [[B]] +; CHECK-NEXT: br label [[END]] +; CHECK: end: +; CHECK-NEXT: [[RET:%.*]] = phi i32 [ [[DIV]], [[IF]] ], [ [[REM]], [[ELSE]] ] +; CHECK-NEXT: ret i32 [[RET]] +; +entry: + br i1 %cmp, label %if, label %else + +if: + %div = sdiv i32 %a, %b + br label %end + +else: + %rem = srem i32 %a, %b + br label %end + +end: + %ret = phi i32 [ %div, %if ], [ %rem, %else ] + ret i32 %ret +} diff --git a/llvm/test/Transforms/DivRemPairs/Mips/div-rem-pairs.ll b/llvm/test/Transforms/DivRemPairs/Mips/div-rem-pairs.ll --- a/llvm/test/Transforms/DivRemPairs/Mips/div-rem-pairs.ll +++ b/llvm/test/Transforms/DivRemPairs/Mips/div-rem-pairs.ll @@ -317,18 +317,17 @@ ret i128 %ret } -; We don't hoist if one op does not dominate the other, -; but we could hoist both ops to the common predecessor block? +; Hoist both ops to the common predecessor block. define i32 @no_domination(i1 %cmp, i32 %a, i32 %b) { ; CHECK-LABEL: @no_domination( ; CHECK-NEXT: entry: +; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[REM:%.*]] = srem i32 [[A]], [[B]] ; CHECK-NEXT: br i1 [[CMP:%.*]], label [[IF:%.*]], label [[ELSE:%.*]] ; CHECK: if: -; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[A:%.*]], [[B:%.*]] ; CHECK-NEXT: br label [[END:%.*]] ; CHECK: else: -; CHECK-NEXT: [[REM:%.*]] = srem i32 [[A]], [[B]] ; CHECK-NEXT: br label [[END]] ; CHECK: end: ; CHECK-NEXT: [[RET:%.*]] = phi i32 [ [[DIV]], [[IF]] ], [ [[REM]], [[ELSE]] ] diff --git a/llvm/test/Transforms/DivRemPairs/PowerPC/div-rem-pairs.ll b/llvm/test/Transforms/DivRemPairs/PowerPC/div-rem-pairs.ll --- a/llvm/test/Transforms/DivRemPairs/PowerPC/div-rem-pairs.ll +++ b/llvm/test/Transforms/DivRemPairs/PowerPC/div-rem-pairs.ll @@ -331,8 +331,8 @@ ret i128 %ret } -; We don't hoist if one op does not dominate the other, -; but we could hoist both ops to the common predecessor block? +; Do not hoist to the common predecessor block since we don't +; have a div-rem operation. define i32 @no_domination(i1 %cmp, i32 %a, i32 %b) { ; CHECK-LABEL: @no_domination( diff --git a/llvm/test/Transforms/DivRemPairs/RISCV/div-rem-pairs.ll b/llvm/test/Transforms/DivRemPairs/RISCV/div-rem-pairs.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/DivRemPairs/RISCV/div-rem-pairs.ll @@ -0,0 +1,35 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -passes=div-rem-pairs -S -mtriple=riscv64-unknown-unknown | FileCheck %s + +; Do not hoist to the common predecessor block since we don't +; have a div-rem operation. + +define i32 @no_domination(i1 %cmp, i32 %a, i32 %b) { +; CHECK-LABEL: @no_domination( +; CHECK-NEXT: entry: +; CHECK-NEXT: br i1 [[CMP:%.*]], label [[IF:%.*]], label [[ELSE:%.*]] +; CHECK: if: +; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: br label [[END:%.*]] +; CHECK: else: +; CHECK-NEXT: [[REM:%.*]] = srem i32 [[A]], [[B]] +; CHECK-NEXT: br label [[END]] +; CHECK: end: +; CHECK-NEXT: [[RET:%.*]] = phi i32 [ [[DIV]], [[IF]] ], [ [[REM]], [[ELSE]] ] +; CHECK-NEXT: ret i32 [[RET]] +; +entry: + br i1 %cmp, label %if, label %else + +if: + %div = sdiv i32 %a, %b + br label %end + +else: + %rem = srem i32 %a, %b + br label %end + +end: + %ret = phi i32 [ %div, %if ], [ %rem, %else ] + ret i32 %ret +} diff --git a/llvm/test/Transforms/DivRemPairs/X86/div-expanded-rem-pair.ll b/llvm/test/Transforms/DivRemPairs/X86/div-expanded-rem-pair.ll --- a/llvm/test/Transforms/DivRemPairs/X86/div-expanded-rem-pair.ll +++ b/llvm/test/Transforms/DivRemPairs/X86/div-expanded-rem-pair.ll @@ -174,14 +174,14 @@ define i32 @can_have_divrem_in_mutually_nondominating_bbs(i1 %cmp, i32 %a, i32 %b) { ; CHECK-LABEL: @can_have_divrem_in_mutually_nondominating_bbs( ; CHECK-NEXT: entry: +; CHECK-NEXT: [[T3:%.*]] = udiv i32 [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[T2_RECOMPOSED:%.*]] = urem i32 [[A]], [[B]] ; CHECK-NEXT: br i1 [[CMP:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] ; CHECK: if.then: -; CHECK-NEXT: [[T0:%.*]] = udiv i32 [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[T0:%.*]] = udiv i32 [[A]], [[B]] ; CHECK-NEXT: [[T1:%.*]] = mul nuw i32 [[T0]], [[B]] -; CHECK-NEXT: [[T2_RECOMPOSED:%.*]] = urem i32 [[A]], [[B]] ; CHECK-NEXT: br label [[END:%.*]] ; CHECK: if.else: -; CHECK-NEXT: [[T3:%.*]] = udiv i32 [[A]], [[B]] ; CHECK-NEXT: br label [[END]] ; CHECK: end: ; CHECK-NEXT: [[RET:%.*]] = phi i32 [ [[T2_RECOMPOSED]], [[IF_THEN]] ], [ [[T3]], [[IF_ELSE]] ] diff --git a/llvm/test/Transforms/DivRemPairs/X86/div-rem-pairs.ll b/llvm/test/Transforms/DivRemPairs/X86/div-rem-pairs.ll --- a/llvm/test/Transforms/DivRemPairs/X86/div-rem-pairs.ll +++ b/llvm/test/Transforms/DivRemPairs/X86/div-rem-pairs.ll @@ -308,18 +308,17 @@ ret i128 %ret } -; We don't hoist if one op does not dominate the other, -; but we could hoist both ops to the common predecessor block? +; Hoist both ops to the common predecessor block. define i32 @no_domination(i1 %cmp, i32 %a, i32 %b) { ; CHECK-LABEL: @no_domination( ; CHECK-NEXT: entry: +; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[REM:%.*]] = srem i32 [[A]], [[B]] ; CHECK-NEXT: br i1 [[CMP:%.*]], label [[IF:%.*]], label [[ELSE:%.*]] ; CHECK: if: -; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[A:%.*]], [[B:%.*]] ; CHECK-NEXT: br label [[END:%.*]] ; CHECK: else: -; CHECK-NEXT: [[REM:%.*]] = srem i32 [[A]], [[B]] ; CHECK-NEXT: br label [[END]] ; CHECK: end: ; CHECK-NEXT: [[RET:%.*]] = phi i32 [ [[DIV]], [[IF]] ], [ [[REM]], [[ELSE]] ]