[LoopStrengthReduce] Don't trim formula that uses a subset of required registers

Consider this use from the new testcase:

  LSR Use: Kind=ICmpZero, Offsets={0}, widest fixup type: i32
    reg({1000,+,-1}<nw><%for.body>)
    -3003 + reg({3,+,3}<nw><%for.body>)
    -1001 + reg({1,+,1}<nuw><nsw><%for.body>)
    -1000 + reg({0,+,1}<nw><%for.body>)
    -3000 + reg({0,+,3}<nuw><%for.body>)
    reg({-1000,+,1}<nw><%for.body>)
    reg({-3000,+,3}<nsw><%for.body>)

This is the last use we consider for a solution in SolveRecurse, so CurRegs is
a large set.  (CurRegs is the set of registers that are needed by the
previously visited uses in the in-progress solution.)

ReqRegs is {
  {3,+,3}<nw><%for.body>,
  {1,+,1}<nuw><nsw><%for.body>
}

This is the intersection of the regs used by any of the formulas for the
current use and CurRegs.

Now, the code requires a formula to contain *all* these regs (the comment is
simply wrong), otherwise the formula is immediately disqualified.  Obviously,
no formula for this use contains two regs so they will all get disqualified.

The fix modifies the check to allow the formula in this case.  The idea is
that neither of these formulae is introducing any new registers which is the
point of this early pruning as far as I understand.

In terms of set arithmetic, we now allow formulas whose used regs are a subset
of the required regs not just the other way around.

There are few more loops in the test-suite that are now successfully LSRed.  I
have benchmarked those and found very minimal change.

Fixes <rdar://problem/13965777>

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@207271 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Adam Nemet 2014-04-25 21:02:21 +00:00
parent d9dc95709e
commit d761cc1dfa
3 changed files with 49 additions and 10 deletions

View File

@ -256,7 +256,7 @@ struct Formula {
void InitialMatch(const SCEV *S, Loop *L, ScalarEvolution &SE);
unsigned getNumRegs() const;
size_t getNumRegs() const;
Type *getType() const;
void DeleteBaseReg(const SCEV *&S);
@ -351,7 +351,7 @@ void Formula::InitialMatch(const SCEV *S, Loop *L, ScalarEvolution &SE) {
/// getNumRegs - Return the total number of register operands used by this
/// formula. This does not include register uses implied by non-constant
/// addrec strides.
unsigned Formula::getNumRegs() const {
size_t Formula::getNumRegs() const {
return !!ScaledReg + BaseRegs.size();
}
@ -4132,19 +4132,22 @@ void LSRInstance::SolveRecurse(SmallVectorImpl<const Formula *> &Solution,
E = LU.Formulae.end(); I != E; ++I) {
const Formula &F = *I;
// Ignore formulae which do not use any of the required registers.
bool SatisfiedReqReg = true;
// Ignore formulae which may not be ideal in terms of register reuse of
// ReqRegs. The formula should use all required registers before
// introducing new ones.
int NumReqRegsToFind = std::min(F.getNumRegs(), ReqRegs.size());
for (SmallSetVector<const SCEV *, 4>::const_iterator J = ReqRegs.begin(),
JE = ReqRegs.end(); J != JE; ++J) {
const SCEV *Reg = *J;
if ((!F.ScaledReg || F.ScaledReg != Reg) &&
std::find(F.BaseRegs.begin(), F.BaseRegs.end(), Reg) ==
if ((F.ScaledReg && F.ScaledReg == Reg) ||
std::find(F.BaseRegs.begin(), F.BaseRegs.end(), Reg) !=
F.BaseRegs.end()) {
SatisfiedReqReg = false;
--NumReqRegsToFind;
if (NumReqRegsToFind == 0)
break;
}
}
if (!SatisfiedReqReg) {
if (NumReqRegsToFind != 0) {
// If none of the formulae satisfied the required registers, then we could
// clear ReqRegs and try again. Currently, we simply give up in this case.
continue;

View File

@ -1,4 +1,4 @@
config.suffixes = ['.ll']
config.suffixes = ['.ll' '.c']
targets = set(config.root.targets_to_build.split())
if not 'ARM64' in targets:

View File

@ -0,0 +1,36 @@
// RUN: clang %s -O3 -target arm64-apple-ios -o - -S -mllvm -debug-only=loop-reduce 2>&1| FileCheck %s
// REQUIRES: asserts
// LSR used to fail here due to a bug in the ReqRegs test. To complicate
// things, this could only be reproduced with clang because the uses would
// come out in different order when invoked through llc.
// CHECK: The chosen solution requires
// CHECK-NOT: No Satisfactory Solution
typedef unsigned long iter_t;
void use_int(int result);
struct _state {
int N;
int M;
int K;
double* data;
};
void
do_integer_add(iter_t iterations, void* cookie)
{
struct _state *pState = (struct _state*)cookie;
register int i;
register int a = pState->N + 57;
while (iterations-- > 0) {
for (i = 1; i < 1001; ++i) {
a=a+a+i; a=a+a+i; a=a+a+i; a=a+a+i;
a=a+a+i; a=a+a+i; a=a+a+i; a=a+a+i;
a=a+a+i; a=a+a+i;
}
}
use_int(a);
}