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,27 @@ // 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()) { + if (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/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,21 +331,23 @@ 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 to the common predecessor block. define i32 @no_domination(i1 %cmp, i32 %a, i32 %b) { ; CHECK-LABEL: @no_domination( ; CHECK-NEXT: entry: +; CHECK-NEXT: [[A_FROZEN:%.*]] = freeze i32 [[A:%.*]] +; CHECK-NEXT: [[B_FROZEN:%.*]] = freeze i32 [[B:%.*]] +; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[A_FROZEN]], [[B_FROZEN]] ; 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: [[TMP0:%.*]] = mul i32 [[DIV]], [[B_FROZEN]] +; CHECK-NEXT: [[REM_DECOMPOSED:%.*]] = sub i32 [[A_FROZEN]], [[TMP0]] ; CHECK-NEXT: br label [[END]] ; CHECK: end: -; CHECK-NEXT: [[RET:%.*]] = phi i32 [ [[DIV]], [[IF]] ], [ [[REM]], [[ELSE]] ] +; CHECK-NEXT: [[RET:%.*]] = phi i32 [ [[DIV]], [[IF]] ], [ [[REM_DECOMPOSED]], [[ELSE]] ] ; CHECK-NEXT: ret i32 [[RET]] ; entry: 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]] ]