Currently, codegen may spent some time in SDISel passes even if an entire

function is successfully handled by fast-isel. That's because function
arguments are *always* handled by SDISel. Introduce FastLowerArguments to
allow each target to provide hook to handle formal argument lowering.

As a proof-of-concept, add ARMFastIsel::FastLowerArguments to handle
functions with 4 or fewer scalar integer (i8, i16, or i32) arguments. It
completely eliminates the need for SDISel for trivial functions.

rdar://13163905


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@174855 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Evan Cheng 2013-02-11 01:27:15 +00:00
parent 5f352cc6e4
commit 092e5e7566
4 changed files with 124 additions and 8 deletions

View File

@ -90,6 +90,11 @@ public:
/// getCurDebugLoc() - Return current debug location information.
DebugLoc getCurDebugLoc() const { return DL; }
/// LowerArguments - Do "fast" instruction selection for function arguments
/// and append machine instructions to the current block. Return true if
/// it is successful.
bool LowerArguments();
/// SelectInstruction - Do "fast" instruction selection for the given
/// LLVM IR instruction, and append generated machine instructions to
@ -160,6 +165,11 @@ protected:
///
virtual bool
TargetSelectInstruction(const Instruction *I) = 0;
/// FastLowerArguments - This method is called by target-independent code to
/// do target specific argument lowering. It returns true if it was
/// successful.
virtual bool FastLowerArguments();
/// FastEmit_r - This method is called by target-independent code
/// to request that an instruction with the given type and opcode

View File

@ -87,6 +87,27 @@ void FastISel::startNewBlock() {
LastLocalValue = EmitStartPt;
}
bool FastISel::LowerArguments() {
if (!FuncInfo.CanLowerReturn)
// Fallback to SDISel argument lowering code to deal with sret pointer
// parameter.
return false;
if (!FastLowerArguments())
return false;
// Enter non-dead arguments into ValueMap for uses in non-entry BBs.
for (Function::const_arg_iterator I = FuncInfo.Fn->arg_begin(),
E = FuncInfo.Fn->arg_end(); I != E; ++I) {
if (!I->use_empty()) {
DenseMap<const Value *, unsigned>::iterator VI = LocalValueMap.find(I);
assert(VI != LocalValueMap.end() && "Missed an argument?");
FuncInfo.ValueMap[I] = VI->second;
}
}
return true;
}
void FastISel::flushLocalValueMap() {
LocalValueMap.clear();
LastLocalValue = EmitStartPt;
@ -836,7 +857,8 @@ FastISel::SelectInstruction(const Instruction *I) {
void
FastISel::FastEmitBranch(MachineBasicBlock *MSucc, DebugLoc DL) {
if (FuncInfo.MBB->getBasicBlock()->size() > 1 && FuncInfo.MBB->isLayoutSuccessor(MSucc)) {
if (FuncInfo.MBB->getBasicBlock()->size() > 1 &&
FuncInfo.MBB->isLayoutSuccessor(MSucc)) {
// For more accurate line information if this is the only instruction
// in the block then emit it, otherwise we have the unconditional
// fall-through case, which needs no instructions.
@ -1067,6 +1089,10 @@ FastISel::FastISel(FunctionLoweringInfo &funcInfo,
FastISel::~FastISel() {}
bool FastISel::FastLowerArguments() {
return false;
}
unsigned FastISel::FastEmit_(MVT, MVT,
unsigned) {
return 0;

View File

@ -1032,10 +1032,6 @@ void SelectionDAGISel::SelectAllBasicBlocks(const Function &Fn) {
if (FuncInfo->MBB->isLandingPad())
PrepareEHLandingPad();
// Lower any arguments needed in this block if this is the entry block.
if (LLVMBB == &Fn.getEntryBlock())
LowerArguments(LLVMBB);
// Before doing SelectionDAG ISel, see if FastISel has been requested.
if (FastIS) {
FastIS->startNewBlock();
@ -1043,9 +1039,15 @@ void SelectionDAGISel::SelectAllBasicBlocks(const Function &Fn) {
// Emit code for any incoming arguments. This must happen before
// beginning FastISel on the entry block.
if (LLVMBB == &Fn.getEntryBlock()) {
CurDAG->setRoot(SDB->getControlRoot());
SDB->clear();
CodeGenAndEmitDAG();
// Lower any arguments needed in this block if this is the entry block.
if (!FastIS->LowerArguments()) {
// Call target indepedent SDISel argument lowering code if the target
// specific routine is not successful.
LowerArguments(LLVMBB);
CurDAG->setRoot(SDB->getControlRoot());
SDB->clear();
CodeGenAndEmitDAG();
}
// If we inserted any instructions at the beginning, make a note of
// where they are, so we can be sure to emit subsequent instructions
@ -1156,6 +1158,10 @@ void SelectionDAGISel::SelectAllBasicBlocks(const Function &Fn) {
}
FastIS->recomputeInsertPt();
} else {
// Lower any arguments needed in this block if this is the entry block.
if (LLVMBB == &Fn.getEntryBlock())
LowerArguments(LLVMBB);
}
if (Begin != BI)

View File

@ -146,6 +146,7 @@ class ARMFastISel : public FastISel {
virtual unsigned TargetMaterializeAlloca(const AllocaInst *AI);
virtual bool TryToFoldLoad(MachineInstr *MI, unsigned OpNo,
const LoadInst *LI);
virtual bool FastLowerArguments();
private:
#include "ARMGenFastISel.inc"
@ -2884,6 +2885,79 @@ unsigned ARMFastISel::ARMLowerPICELF(const GlobalValue *GV,
return DestReg2;
}
bool ARMFastISel::FastLowerArguments() {
if (!FuncInfo.CanLowerReturn)
return false;
const Function *F = FuncInfo.Fn;
if (F->isVarArg())
return false;
CallingConv::ID CC = F->getCallingConv();
switch (CC) {
default:
return false;
case CallingConv::Fast:
case CallingConv::C:
case CallingConv::ARM_AAPCS_VFP:
case CallingConv::ARM_AAPCS:
case CallingConv::ARM_APCS:
break;
}
// Only handle simple cases. i.e. Up to 4 i8/i16/i32 scalar arguments
// which are passed in r0 - r3.
unsigned Idx = 1;
for (Function::const_arg_iterator I = F->arg_begin(), E = F->arg_end();
I != E; ++I, ++Idx) {
if (Idx > 4)
return false;
if (F->getAttributes().hasAttribute(Idx, Attribute::InReg) ||
F->getAttributes().hasAttribute(Idx, Attribute::StructRet) ||
F->getAttributes().hasAttribute(Idx, Attribute::ByVal))
return false;
Type *ArgTy = I->getType();
if (ArgTy->isStructTy() || ArgTy->isArrayTy() || ArgTy->isVectorTy())
return false;
EVT ArgVT = TLI.getValueType(ArgTy);
switch (ArgVT.getSimpleVT().SimpleTy) {
case MVT::i8:
case MVT::i16:
case MVT::i32:
break;
default:
return false;
}
}
static const uint16_t GPRArgRegs[] = {
ARM::R0, ARM::R1, ARM::R2, ARM::R3
};
const TargetRegisterClass *RC = TLI.getRegClassFor(MVT::i32);
Idx = 0;
for (Function::const_arg_iterator I = F->arg_begin(), E = F->arg_end();
I != E; ++I, ++Idx) {
if (I->use_empty())
continue;
unsigned SrcReg = GPRArgRegs[Idx];
unsigned DstReg = FuncInfo.MF->addLiveIn(SrcReg, RC);
// FIXME: Unfortunately it's necessary to emit a copy from the livein copy.
// Without this, EmitLiveInCopies may eliminate the livein if its only
// use is a bitcast (which isn't turned into an instruction).
unsigned ResultReg = createResultReg(RC);
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(TargetOpcode::COPY),
ResultReg).addReg(DstReg, getKillRegState(true));
UpdateValueMap(I, ResultReg);
}
return true;
}
namespace llvm {
FastISel *ARM::createFastISel(FunctionLoweringInfo &funcInfo,
const TargetLibraryInfo *libInfo) {