mirror of
https://github.com/RPCSX/llvm.git
synced 2024-11-24 20:29:53 +00:00
This converts a signed remainder instruction to unsigned remainder, which
enables the code size optimisation to fold a rem and div into a single aeabi_uidivmod call. This was not happening before because sdiv was converted but srem not, and instructions with different signedness are not combined. Differential Revision: http://reviews.llvm.org/D22214 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@275403 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
2bb340ccad
commit
4fab1d4f07
@ -37,6 +37,7 @@ STATISTIC(NumCmps, "Number of comparisons propagated");
|
||||
STATISTIC(NumReturns, "Number of return values propagated");
|
||||
STATISTIC(NumDeadCases, "Number of switch cases removed");
|
||||
STATISTIC(NumSDivs, "Number of sdiv converted to udiv");
|
||||
STATISTIC(NumSRems, "Number of srem converted to urem");
|
||||
|
||||
namespace {
|
||||
class CorrelatedValuePropagation : public FunctionPass {
|
||||
@ -325,32 +326,51 @@ static bool processCallSite(CallSite CS, LazyValueInfo *LVI) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Helper function to rewrite srem and sdiv. As a policy choice, we choose not
|
||||
// to waste compile time on anything where the operands are local defs. While
|
||||
// LVI can sometimes reason about such cases, it's not its primary purpose.
|
||||
static bool hasLocalDefs(BinaryOperator *SDI) {
|
||||
for (Value *O : SDI->operands()) {
|
||||
auto *I = dyn_cast<Instruction>(O);
|
||||
if (I && I->getParent() == SDI->getParent())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool hasPositiveOperands(BinaryOperator *SDI, LazyValueInfo *LVI) {
|
||||
Constant *Zero = ConstantInt::get(SDI->getType(), 0);
|
||||
for (Value *O : SDI->operands()) {
|
||||
auto Result = LVI->getPredicateAt(ICmpInst::ICMP_SGE, O, Zero, SDI);
|
||||
if (Result != LazyValueInfo::True)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool processSRem(BinaryOperator *SDI, LazyValueInfo *LVI) {
|
||||
if (SDI->getType()->isVectorTy() || hasLocalDefs(SDI) ||
|
||||
!hasPositiveOperands(SDI, LVI))
|
||||
return false;
|
||||
|
||||
++NumSRems;
|
||||
auto *BO = BinaryOperator::CreateURem(SDI->getOperand(0), SDI->getOperand(1),
|
||||
SDI->getName(), SDI);
|
||||
SDI->replaceAllUsesWith(BO);
|
||||
SDI->eraseFromParent();
|
||||
return true;
|
||||
}
|
||||
|
||||
/// See if LazyValueInfo's ability to exploit edge conditions or range
|
||||
/// information is sufficient to prove the both operands of this SDiv are
|
||||
/// positive. If this is the case, replace the SDiv with a UDiv. Even for local
|
||||
/// conditions, this can sometimes prove conditions instcombine can't by
|
||||
/// exploiting range information.
|
||||
static bool processSDiv(BinaryOperator *SDI, LazyValueInfo *LVI) {
|
||||
if (SDI->getType()->isVectorTy())
|
||||
if (SDI->getType()->isVectorTy() || hasLocalDefs(SDI) ||
|
||||
!hasPositiveOperands(SDI, LVI))
|
||||
return false;
|
||||
|
||||
for (Value *O : SDI->operands()) {
|
||||
// As a policy choice, we choose not to waste compile time on anything where
|
||||
// the operands are local defs. While LVI can sometimes reason about such
|
||||
// cases, it's not its primary purpose.
|
||||
auto *I = dyn_cast<Instruction>(O);
|
||||
if (I && I->getParent() == SDI->getParent())
|
||||
return false;
|
||||
}
|
||||
|
||||
Constant *Zero = ConstantInt::get(SDI->getType(), 0);
|
||||
for (Value *O : SDI->operands()) {
|
||||
LazyValueInfo::Tristate Result =
|
||||
LVI->getPredicateAt(ICmpInst::ICMP_SGE, O, Zero, SDI);
|
||||
if (Result != LazyValueInfo::True)
|
||||
return false;
|
||||
}
|
||||
|
||||
++NumSDivs;
|
||||
auto *BO = BinaryOperator::CreateUDiv(SDI->getOperand(0), SDI->getOperand(1),
|
||||
SDI->getName(), SDI);
|
||||
@ -410,6 +430,9 @@ static bool runImpl(Function &F, LazyValueInfo *LVI) {
|
||||
case Instruction::Invoke:
|
||||
BBChanged |= processCallSite(CallSite(II), LVI);
|
||||
break;
|
||||
case Instruction::SRem:
|
||||
BBChanged |= processSRem(cast<BinaryOperator>(II), LVI);
|
||||
break;
|
||||
case Instruction::SDiv:
|
||||
BBChanged |= processSDiv(cast<BinaryOperator>(II), LVI);
|
||||
break;
|
||||
|
21
test/Transforms/CorrelatedValuePropagation/srem.ll
Normal file
21
test/Transforms/CorrelatedValuePropagation/srem.ll
Normal file
@ -0,0 +1,21 @@
|
||||
; RUN: opt < %s -correlated-propagation -S | FileCheck %s
|
||||
|
||||
target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"
|
||||
target triple = "thumbv7m-arm-none-eabi"
|
||||
|
||||
define void @h(i32* nocapture %p, i32 %x) local_unnamed_addr #0 {
|
||||
entry:
|
||||
; CHECK-LABEL: @h(
|
||||
; CHECK: urem
|
||||
|
||||
%cmp = icmp sgt i32 %x, 0
|
||||
br i1 %cmp, label %if.then, label %if.end
|
||||
|
||||
if.then:
|
||||
%rem2 = srem i32 %x, 10
|
||||
store i32 %rem2, i32* %p, align 4
|
||||
br label %if.end
|
||||
|
||||
if.end:
|
||||
ret void
|
||||
}
|
Loading…
Reference in New Issue
Block a user