SelectionDAGISel.cpp [plain text]
#define DEBUG_TYPE "isel"
#include "ScheduleDAGSDNodes.h"
#include "SelectionDAGBuild.h"
#include "llvm/CodeGen/SelectionDAGISel.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Constants.h"
#include "llvm/CallingConv.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Function.h"
#include "llvm/GlobalVariable.h"
#include "llvm/InlineAsm.h"
#include "llvm/Instructions.h"
#include "llvm/Intrinsics.h"
#include "llvm/IntrinsicInst.h"
#include "llvm/CodeGen/FastISel.h"
#include "llvm/CodeGen/GCStrategy.h"
#include "llvm/CodeGen/GCMetadata.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineJumpTableInfo.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/ScheduleHazardRecognizer.h"
#include "llvm/CodeGen/SchedulerRegistry.h"
#include "llvm/CodeGen/SelectionDAG.h"
#include "llvm/CodeGen/DwarfWriter.h"
#include "llvm/Target/TargetRegisterInfo.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Target/TargetFrameInfo.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetLowering.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/Timer.h"
#include <algorithm>
using namespace llvm;
static cl::opt<bool>
DisableLegalizeTypes("disable-legalize-types", cl::Hidden);
#ifndef NDEBUG
static cl::opt<bool>
EnableFastISelVerbose("fast-isel-verbose", cl::Hidden,
cl::desc("Enable verbose messages in the \"fast\" "
"instruction selector"));
static cl::opt<bool>
EnableFastISelAbort("fast-isel-abort", cl::Hidden,
cl::desc("Enable abort calls when \"fast\" instruction fails"));
#else
static const bool EnableFastISelVerbose = false,
EnableFastISelAbort = false;
#endif
static cl::opt<bool>
SchedLiveInCopies("schedule-livein-copies",
cl::desc("Schedule copies of livein registers"),
cl::init(false));
#ifndef NDEBUG
static cl::opt<bool>
ViewDAGCombine1("view-dag-combine1-dags", cl::Hidden,
cl::desc("Pop up a window to show dags before the first "
"dag combine pass"));
static cl::opt<bool>
ViewLegalizeTypesDAGs("view-legalize-types-dags", cl::Hidden,
cl::desc("Pop up a window to show dags before legalize types"));
static cl::opt<bool>
ViewLegalizeDAGs("view-legalize-dags", cl::Hidden,
cl::desc("Pop up a window to show dags before legalize"));
static cl::opt<bool>
ViewDAGCombine2("view-dag-combine2-dags", cl::Hidden,
cl::desc("Pop up a window to show dags before the second "
"dag combine pass"));
static cl::opt<bool>
ViewDAGCombineLT("view-dag-combine-lt-dags", cl::Hidden,
cl::desc("Pop up a window to show dags before the post legalize types"
" dag combine pass"));
static cl::opt<bool>
ViewISelDAGs("view-isel-dags", cl::Hidden,
cl::desc("Pop up a window to show isel dags as they are selected"));
static cl::opt<bool>
ViewSchedDAGs("view-sched-dags", cl::Hidden,
cl::desc("Pop up a window to show sched dags as they are processed"));
static cl::opt<bool>
ViewSUnitDAGs("view-sunit-dags", cl::Hidden,
cl::desc("Pop up a window to show SUnit dags after they are processed"));
#else
static const bool ViewDAGCombine1 = false,
ViewLegalizeTypesDAGs = false, ViewLegalizeDAGs = false,
ViewDAGCombine2 = false,
ViewDAGCombineLT = false,
ViewISelDAGs = false, ViewSchedDAGs = false,
ViewSUnitDAGs = false;
#endif
MachinePassRegistry RegisterScheduler::Registry;
static cl::opt<RegisterScheduler::FunctionPassCtor, false,
RegisterPassParser<RegisterScheduler> >
ISHeuristic("pre-RA-sched",
cl::init(&createDefaultScheduler),
cl::desc("Instruction schedulers available (before register"
" allocation):"));
static RegisterScheduler
defaultListDAGScheduler("default", "Best scheduler for the target",
createDefaultScheduler);
namespace llvm {
ScheduleDAGSDNodes* createDefaultScheduler(SelectionDAGISel *IS,
CodeGenOpt::Level OptLevel) {
const TargetLowering &TLI = IS->getTargetLowering();
if (OptLevel == CodeGenOpt::None)
return createFastDAGScheduler(IS, OptLevel);
if (TLI.getSchedulingPreference() == TargetLowering::SchedulingForLatency)
return createTDListDAGScheduler(IS, OptLevel);
assert(TLI.getSchedulingPreference() ==
TargetLowering::SchedulingForRegPressure && "Unknown sched type!");
return createBURRListDAGScheduler(IS, OptLevel);
}
}
MachineBasicBlock *TargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI,
MachineBasicBlock *MBB) const {
cerr << "If a target marks an instruction with "
<< "'usesCustomDAGSchedInserter', it must implement "
<< "TargetLowering::EmitInstrWithCustomInserter!\n";
abort();
return 0;
}
static void EmitLiveInCopy(MachineBasicBlock *MBB,
MachineBasicBlock::iterator &InsertPos,
unsigned VirtReg, unsigned PhysReg,
const TargetRegisterClass *RC,
DenseMap<MachineInstr*, unsigned> &CopyRegMap,
const MachineRegisterInfo &MRI,
const TargetRegisterInfo &TRI,
const TargetInstrInfo &TII) {
unsigned NumUses = 0;
MachineInstr *UseMI = NULL;
for (MachineRegisterInfo::use_iterator UI = MRI.use_begin(VirtReg),
UE = MRI.use_end(); UI != UE; ++UI) {
UseMI = &*UI;
if (++NumUses > 1)
break;
}
bool Coalesced = false;
unsigned SrcReg, DstReg, SrcSubReg, DstSubReg;
if (NumUses == 1 &&
TII.isMoveInstr(*UseMI, SrcReg, DstReg, SrcSubReg, DstSubReg) &&
TargetRegisterInfo::isVirtualRegister(DstReg)) {
VirtReg = DstReg;
Coalesced = true;
}
MachineBasicBlock::iterator Pos = InsertPos;
while (Pos != MBB->begin()) {
MachineInstr *PrevMI = prior(Pos);
DenseMap<MachineInstr*, unsigned>::iterator RI = CopyRegMap.find(PrevMI);
unsigned CopyDstReg = (RI == CopyRegMap.end()) ? 0 : RI->second;
if (CopyDstReg && !TRI.regsOverlap(CopyDstReg, PhysReg))
break; --Pos;
}
TII.copyRegToReg(*MBB, Pos, VirtReg, PhysReg, RC, RC);
CopyRegMap.insert(std::make_pair(prior(Pos), VirtReg));
if (Coalesced) {
if (&*InsertPos == UseMI) ++InsertPos;
MBB->erase(UseMI);
}
}
static void EmitLiveInCopies(MachineBasicBlock *EntryMBB,
const MachineRegisterInfo &MRI,
const TargetRegisterInfo &TRI,
const TargetInstrInfo &TII) {
if (SchedLiveInCopies) {
DenseMap<MachineInstr*, unsigned> CopyRegMap;
MachineBasicBlock::iterator InsertPos = EntryMBB->begin();
for (MachineRegisterInfo::livein_iterator LI = MRI.livein_begin(),
E = MRI.livein_end(); LI != E; ++LI)
if (LI->second) {
const TargetRegisterClass *RC = MRI.getRegClass(LI->second);
EmitLiveInCopy(EntryMBB, InsertPos, LI->second, LI->first,
RC, CopyRegMap, MRI, TRI, TII);
}
} else {
for (MachineRegisterInfo::livein_iterator LI = MRI.livein_begin(),
E = MRI.livein_end(); LI != E; ++LI)
if (LI->second) {
const TargetRegisterClass *RC = MRI.getRegClass(LI->second);
TII.copyRegToReg(*EntryMBB, EntryMBB->begin(),
LI->second, LI->first, RC, RC);
}
}
}
SelectionDAGISel::SelectionDAGISel(TargetMachine &tm, CodeGenOpt::Level OL) :
FunctionPass(&ID), TM(tm), TLI(*tm.getTargetLowering()),
FuncInfo(new FunctionLoweringInfo(TLI)),
CurDAG(new SelectionDAG(TLI, *FuncInfo)),
SDL(new SelectionDAGLowering(*CurDAG, TLI, *FuncInfo, OL)),
GFI(),
OptLevel(OL),
DAGSize(0)
{}
SelectionDAGISel::~SelectionDAGISel() {
delete SDL;
delete CurDAG;
delete FuncInfo;
}
unsigned SelectionDAGISel::MakeReg(MVT VT) {
return RegInfo->createVirtualRegister(TLI.getRegClassFor(VT));
}
void SelectionDAGISel::getAnalysisUsage(AnalysisUsage &AU) const {
AU.addRequired<AliasAnalysis>();
AU.addRequired<GCModuleInfo>();
AU.addRequired<DwarfWriter>();
AU.setPreservesAll();
}
bool SelectionDAGISel::runOnFunction(Function &Fn) {
assert((!EnableFastISelVerbose || EnableFastISel) &&
"-fast-isel-verbose requires -fast-isel");
assert((!EnableFastISelAbort || EnableFastISel) &&
"-fast-isel-abort requires -fast-isel");
if (Fn.hasAvailableExternallyLinkage())
return false;
AA = &getAnalysis<AliasAnalysis>();
TargetMachine &TM = TLI.getTargetMachine();
MF = &MachineFunction::construct(&Fn, TM);
const TargetInstrInfo &TII = *TM.getInstrInfo();
const TargetRegisterInfo &TRI = *TM.getRegisterInfo();
if (MF->getFunction()->hasGC())
GFI = &getAnalysis<GCModuleInfo>().getFunctionInfo(*MF->getFunction());
else
GFI = 0;
RegInfo = &MF->getRegInfo();
DOUT << "\n\n\n=== " << Fn.getName() << "\n";
MachineModuleInfo *MMI = getAnalysisIfAvailable<MachineModuleInfo>();
DwarfWriter *DW = getAnalysisIfAvailable<DwarfWriter>();
CurDAG->init(*MF, MMI, DW);
FuncInfo->set(Fn, *MF, *CurDAG, EnableFastISel);
SDL->init(GFI, *AA);
for (Function::iterator I = Fn.begin(), E = Fn.end(); I != E; ++I)
if (InvokeInst *Invoke = dyn_cast<InvokeInst>(I->getTerminator()))
FuncInfo->MBBMap[Invoke->getSuccessor(1)]->setIsLandingPad();
SelectAllBasicBlocks(Fn, *MF, MMI, DW, TII);
EmitLiveInCopies(MF->begin(), *RegInfo, TRI, TII);
for (MachineRegisterInfo::livein_iterator I = RegInfo->livein_begin(),
E = RegInfo->livein_end(); I != E; ++I)
MF->begin()->addLiveIn(I->first);
#ifndef NDEBUG
assert(FuncInfo->CatchInfoFound.size() == FuncInfo->CatchInfoLost.size() &&
"Not all catch info was assigned to a landing pad!");
#endif
FuncInfo->clear();
return true;
}
static void copyCatchInfo(BasicBlock *SrcBB, BasicBlock *DestBB,
MachineModuleInfo *MMI, FunctionLoweringInfo &FLI) {
for (BasicBlock::iterator I = SrcBB->begin(), E = --SrcBB->end(); I != E; ++I)
if (EHSelectorInst *EHSel = dyn_cast<EHSelectorInst>(I)) {
AddCatchInfo(*EHSel, MMI, FLI.MBBMap[DestBB]);
#ifndef NDEBUG
if (!FLI.MBBMap[SrcBB]->isLandingPad())
FLI.CatchInfoFound.insert(EHSel);
#endif
}
}
static bool
IsFixedFrameObjectWithPosOffset(MachineFrameInfo *MFI, SDValue Op) {
if (!isa<FrameIndexSDNode>(Op)) return false;
FrameIndexSDNode * FrameIdxNode = dyn_cast<FrameIndexSDNode>(Op);
int FrameIdx = FrameIdxNode->getIndex();
return MFI->isFixedObjectIndex(FrameIdx) &&
MFI->getObjectOffset(FrameIdx) >= 0;
}
static bool IsPossiblyOverwrittenArgumentOfTailCall(SDValue Op,
MachineFrameInfo *MFI) {
RegisterSDNode * OpReg = NULL;
if (Op.getOpcode() == ISD::FORMAL_ARGUMENTS ||
(Op.getOpcode()== ISD::CopyFromReg &&
(OpReg = dyn_cast<RegisterSDNode>(Op.getOperand(1))) &&
(OpReg->getReg() >= TargetRegisterInfo::FirstVirtualRegister)) ||
(Op.getOpcode() == ISD::LOAD &&
IsFixedFrameObjectWithPosOffset(MFI, Op.getOperand(1))) ||
(Op.getOpcode() == ISD::MERGE_VALUES &&
Op.getOperand(Op.getResNo()).getOpcode() == ISD::LOAD &&
IsFixedFrameObjectWithPosOffset(MFI, Op.getOperand(Op.getResNo()).
getOperand(1))))
return true;
return false;
}
static void CheckDAGForTailCallsAndFixThem(SelectionDAG &DAG,
const TargetLowering& TLI) {
SDNode * Ret = NULL;
SDValue Terminator = DAG.getRoot();
if (Terminator.getOpcode() == ISD::RET) {
Ret = Terminator.getNode();
}
for (SelectionDAG::allnodes_iterator BE = DAG.allnodes_begin(),
BI = DAG.allnodes_end(); BI != BE; ) {
--BI;
if (CallSDNode *TheCall = dyn_cast<CallSDNode>(BI)) {
SDValue OpRet(Ret, 0);
SDValue OpCall(BI, 0);
bool isMarkedTailCall = TheCall->isTailCall();
if (!isMarkedTailCall) continue;
if (Ret==NULL ||
!TLI.IsEligibleForTailCallOptimization(TheCall, OpRet, DAG)) {
TheCall->setNotTailCall();
} else {
SmallVector<SDValue, 32> Ops;
SDValue Chain = TheCall->getChain(), InFlag;
Ops.push_back(Chain);
Ops.push_back(TheCall->getCallee());
for (unsigned i = 0, e = TheCall->getNumArgs(); i != e; ++i) {
SDValue Arg = TheCall->getArg(i);
bool isByVal = TheCall->getArgFlags(i).isByVal();
MachineFunction &MF = DAG.getMachineFunction();
MachineFrameInfo *MFI = MF.getFrameInfo();
if (!isByVal &&
IsPossiblyOverwrittenArgumentOfTailCall(Arg, MFI)) {
MVT VT = Arg.getValueType();
unsigned VReg = MF.getRegInfo().
createVirtualRegister(TLI.getRegClassFor(VT));
Chain = DAG.getCopyToReg(Chain, Arg.getDebugLoc(),
VReg, Arg, InFlag);
InFlag = Chain.getValue(1);
Arg = DAG.getCopyFromReg(Chain, Arg.getDebugLoc(),
VReg, VT, InFlag);
Chain = Arg.getValue(1);
InFlag = Arg.getValue(2);
}
Ops.push_back(Arg);
Ops.push_back(TheCall->getArgFlagsVal(i));
}
Ops[0] = Chain;
DAG.UpdateNodeOperands(OpCall, Ops.begin(), Ops.size());
}
}
}
}
void SelectionDAGISel::SelectBasicBlock(BasicBlock *LLVMBB,
BasicBlock::iterator Begin,
BasicBlock::iterator End) {
SDL->setCurrentBasicBlock(BB);
for (BasicBlock::iterator I = Begin; I != End; ++I)
if (!isa<TerminatorInst>(I))
SDL->visit(*I);
for (BasicBlock::iterator I = Begin; I != End; ++I)
if (!isa<PHINode>(I) && !isa<InvokeInst>(I))
SDL->CopyToExportRegsIfNeeded(I);
if (End == LLVMBB->end()) {
HandlePHINodesInSuccessorBlocks(LLVMBB);
SDL->visit(*LLVMBB->getTerminator());
}
CurDAG->setRoot(SDL->getControlRoot());
if (PerformTailCallOpt)
CheckDAGForTailCallsAndFixThem(*CurDAG, TLI);
CodeGenAndEmitDAG();
SDL->clear();
}
void SelectionDAGISel::ComputeLiveOutVRegInfo() {
SmallPtrSet<SDNode*, 128> VisitedNodes;
SmallVector<SDNode*, 128> Worklist;
Worklist.push_back(CurDAG->getRoot().getNode());
APInt Mask;
APInt KnownZero;
APInt KnownOne;
while (!Worklist.empty()) {
SDNode *N = Worklist.back();
Worklist.pop_back();
if (!VisitedNodes.insert(N))
continue;
for (unsigned i = 0, e = N->getNumOperands(); i != e; ++i)
if (N->getOperand(i).getValueType() == MVT::Other)
Worklist.push_back(N->getOperand(i).getNode());
if (N->getOpcode() != ISD::CopyToReg)
continue;
unsigned DestReg = cast<RegisterSDNode>(N->getOperand(1))->getReg();
if (!TargetRegisterInfo::isVirtualRegister(DestReg))
continue;
SDValue Src = N->getOperand(2);
MVT SrcVT = Src.getValueType();
if (!SrcVT.isInteger() || SrcVT.isVector())
continue;
unsigned NumSignBits = CurDAG->ComputeNumSignBits(Src);
Mask = APInt::getAllOnesValue(SrcVT.getSizeInBits());
CurDAG->ComputeMaskedBits(Src, Mask, KnownZero, KnownOne);
if (NumSignBits != 1 || KnownZero != 0 || KnownOne != 0) {
DestReg -= TargetRegisterInfo::FirstVirtualRegister;
FunctionLoweringInfo &FLI = CurDAG->getFunctionLoweringInfo();
if (DestReg >= FLI.LiveOutRegInfo.size())
FLI.LiveOutRegInfo.resize(DestReg+1);
FunctionLoweringInfo::LiveOutInfo &LOI = FLI.LiveOutRegInfo[DestReg];
LOI.NumSignBits = NumSignBits;
LOI.KnownOne = KnownOne;
LOI.KnownZero = KnownZero;
}
}
}
void SelectionDAGISel::CodeGenAndEmitDAG() {
std::string GroupName;
if (TimePassesIsEnabled)
GroupName = "Instruction Selection and Scheduling";
std::string BlockName;
if (ViewDAGCombine1 || ViewLegalizeTypesDAGs || ViewLegalizeDAGs ||
ViewDAGCombine2 || ViewDAGCombineLT || ViewISelDAGs || ViewSchedDAGs ||
ViewSUnitDAGs)
BlockName = CurDAG->getMachineFunction().getFunction()->getName() + ':' +
BB->getBasicBlock()->getName();
DOUT << "Initial selection DAG:\n";
DEBUG(CurDAG->dump());
if (ViewDAGCombine1) CurDAG->viewGraph("dag-combine1 input for " + BlockName);
if (TimePassesIsEnabled) {
NamedRegionTimer T("DAG Combining 1", GroupName);
CurDAG->Combine(Unrestricted, *AA, OptLevel);
} else {
CurDAG->Combine(Unrestricted, *AA, OptLevel);
}
DOUT << "Optimized lowered selection DAG:\n";
DEBUG(CurDAG->dump());
if (!DisableLegalizeTypes) {
if (ViewLegalizeTypesDAGs) CurDAG->viewGraph("legalize-types input for " +
BlockName);
bool Changed;
if (TimePassesIsEnabled) {
NamedRegionTimer T("Type Legalization", GroupName);
Changed = CurDAG->LegalizeTypes();
} else {
Changed = CurDAG->LegalizeTypes();
}
DOUT << "Type-legalized selection DAG:\n";
DEBUG(CurDAG->dump());
if (Changed) {
if (ViewDAGCombineLT)
CurDAG->viewGraph("dag-combine-lt input for " + BlockName);
if (TimePassesIsEnabled) {
NamedRegionTimer T("DAG Combining after legalize types", GroupName);
CurDAG->Combine(NoIllegalTypes, *AA, OptLevel);
} else {
CurDAG->Combine(NoIllegalTypes, *AA, OptLevel);
}
DOUT << "Optimized type-legalized selection DAG:\n";
DEBUG(CurDAG->dump());
}
}
if (ViewLegalizeDAGs) CurDAG->viewGraph("legalize input for " + BlockName);
if (TimePassesIsEnabled) {
NamedRegionTimer T("DAG Legalization", GroupName);
CurDAG->Legalize(DisableLegalizeTypes, OptLevel);
} else {
CurDAG->Legalize(DisableLegalizeTypes, OptLevel);
}
DOUT << "Legalized selection DAG:\n";
DEBUG(CurDAG->dump());
if (ViewDAGCombine2) CurDAG->viewGraph("dag-combine2 input for " + BlockName);
if (TimePassesIsEnabled) {
NamedRegionTimer T("DAG Combining 2", GroupName);
CurDAG->Combine(NoIllegalOperations, *AA, OptLevel);
} else {
CurDAG->Combine(NoIllegalOperations, *AA, OptLevel);
}
DOUT << "Optimized legalized selection DAG:\n";
DEBUG(CurDAG->dump());
if (ViewISelDAGs) CurDAG->viewGraph("isel input for " + BlockName);
if (OptLevel != CodeGenOpt::None)
ComputeLiveOutVRegInfo();
if (TimePassesIsEnabled) {
NamedRegionTimer T("Instruction Selection", GroupName);
InstructionSelect();
} else {
InstructionSelect();
}
DOUT << "Selected selection DAG:\n";
DEBUG(CurDAG->dump());
if (ViewSchedDAGs) CurDAG->viewGraph("scheduler input for " + BlockName);
ScheduleDAGSDNodes *Scheduler = CreateScheduler();
if (TimePassesIsEnabled) {
NamedRegionTimer T("Instruction Scheduling", GroupName);
Scheduler->Run(CurDAG, BB, BB->end());
} else {
Scheduler->Run(CurDAG, BB, BB->end());
}
if (ViewSUnitDAGs) Scheduler->viewGraph();
if (TimePassesIsEnabled) {
NamedRegionTimer T("Instruction Creation", GroupName);
BB = Scheduler->EmitSchedule();
} else {
BB = Scheduler->EmitSchedule();
}
if (TimePassesIsEnabled) {
NamedRegionTimer T("Instruction Scheduling Cleanup", GroupName);
delete Scheduler;
} else {
delete Scheduler;
}
DOUT << "Selected machine code:\n";
DEBUG(BB->dump());
}
void SelectionDAGISel::SelectAllBasicBlocks(Function &Fn,
MachineFunction &MF,
MachineModuleInfo *MMI,
DwarfWriter *DW,
const TargetInstrInfo &TII) {
FastISel *FastIS = 0;
if (EnableFastISel)
FastIS = TLI.createFastISel(MF, MMI, DW,
FuncInfo->ValueMap,
FuncInfo->MBBMap,
FuncInfo->StaticAllocaMap
#ifndef NDEBUG
, FuncInfo->CatchInfoLost
#endif
);
for (Function::iterator I = Fn.begin(), E = Fn.end(); I != E; ++I) {
BasicBlock *LLVMBB = &*I;
BB = FuncInfo->MBBMap[LLVMBB];
BasicBlock::iterator const Begin = LLVMBB->begin();
BasicBlock::iterator const End = LLVMBB->end();
BasicBlock::iterator BI = Begin;
bool SuppressFastISel = false;
if (LLVMBB == &Fn.getEntryBlock()) {
LowerArguments(LLVMBB);
if (FastIS) {
unsigned j = 1;
for (Function::arg_iterator I = Fn.arg_begin(), E = Fn.arg_end();
I != E; ++I, ++j)
if (Fn.paramHasAttr(j, Attribute::ByVal)) {
if (EnableFastISelVerbose || EnableFastISelAbort)
cerr << "FastISel skips entry block due to byval argument\n";
SuppressFastISel = true;
break;
}
}
}
if (MMI && BB->isLandingPad()) {
unsigned LabelID = MMI->addLandingPad(BB);
const TargetInstrDesc &II = TII.get(TargetInstrInfo::EH_LABEL);
BuildMI(BB, SDL->getCurDebugLoc(), II).addImm(LabelID);
unsigned Reg = TLI.getExceptionAddressRegister();
if (Reg) BB->addLiveIn(Reg);
Reg = TLI.getExceptionSelectorRegister();
if (Reg) BB->addLiveIn(Reg);
BranchInst *Br = dyn_cast<BranchInst>(LLVMBB->getTerminator());
if (Br && Br->isUnconditional()) { BasicBlock::iterator I, E;
for (I = LLVMBB->begin(), E = --LLVMBB->end(); I != E; ++I)
if (isa<EHSelectorInst>(I))
break;
if (I == E)
copyCatchInfo(Br->getSuccessor(0), LLVMBB, MMI, *FuncInfo);
}
}
if (FastIS && !SuppressFastISel) {
if (LLVMBB == &Fn.getEntryBlock()) {
CurDAG->setRoot(SDL->getControlRoot());
CodeGenAndEmitDAG();
SDL->clear();
}
FastIS->startNewBlock(BB);
for (; BI != End; ++BI) {
if (isa<TerminatorInst>(BI))
if (!HandlePHINodesInSuccessorBlocksFast(LLVMBB, FastIS)) {
if (EnableFastISelVerbose || EnableFastISelAbort) {
cerr << "FastISel miss: ";
BI->dump();
}
if (EnableFastISelAbort)
assert(0 && "FastISel didn't handle a PHI in a successor");
break;
}
if (FastIS->SelectInstruction(BI))
continue;
if (FastIS->TargetSelectInstruction(BI))
continue;
if (isa<CallInst>(BI)) {
if (EnableFastISelVerbose || EnableFastISelAbort) {
cerr << "FastISel missed call: ";
BI->dump();
}
if (BI->getType() != Type::VoidTy) {
unsigned &R = FuncInfo->ValueMap[BI];
if (!R)
R = FuncInfo->CreateRegForValue(BI);
}
SDL->setCurDebugLoc(FastIS->getCurDebugLoc());
SelectBasicBlock(LLVMBB, BI, next(BI));
FastIS->setCurrentBlock(BB);
continue;
}
if (!isa<TerminatorInst>(BI) || isa<BranchInst>(BI)) {
if (EnableFastISelVerbose || EnableFastISelAbort) {
cerr << "FastISel miss: ";
BI->dump();
}
if (EnableFastISelAbort)
assert(0 && "FastISel didn't select the entire block");
}
break;
}
}
if (BI != End) {
if (FastIS && !FastIS->getCurDebugLoc().isUnknown())
SDL->setCurDebugLoc(FastIS->getCurDebugLoc());
SelectBasicBlock(LLVMBB, BI, End);
}
FinishBasicBlock();
}
delete FastIS;
}
void
SelectionDAGISel::FinishBasicBlock() {
DOUT << "Target-post-processed machine code:\n";
DEBUG(BB->dump());
DOUT << "Total amount of phi nodes to update: "
<< SDL->PHINodesToUpdate.size() << "\n";
DEBUG(for (unsigned i = 0, e = SDL->PHINodesToUpdate.size(); i != e; ++i)
DOUT << "Node " << i << " : (" << SDL->PHINodesToUpdate[i].first
<< ", " << SDL->PHINodesToUpdate[i].second << ")\n";);
if (SDL->SwitchCases.empty() &&
SDL->JTCases.empty() &&
SDL->BitTestCases.empty()) {
for (unsigned i = 0, e = SDL->PHINodesToUpdate.size(); i != e; ++i) {
MachineInstr *PHI = SDL->PHINodesToUpdate[i].first;
assert(PHI->getOpcode() == TargetInstrInfo::PHI &&
"This is not a machine PHI node that we are updating!");
PHI->addOperand(MachineOperand::CreateReg(SDL->PHINodesToUpdate[i].second,
false));
PHI->addOperand(MachineOperand::CreateMBB(BB));
}
SDL->PHINodesToUpdate.clear();
return;
}
for (unsigned i = 0, e = SDL->BitTestCases.size(); i != e; ++i) {
if (!SDL->BitTestCases[i].Emitted) {
BB = SDL->BitTestCases[i].Parent;
SDL->setCurrentBasicBlock(BB);
SDL->visitBitTestHeader(SDL->BitTestCases[i]);
CurDAG->setRoot(SDL->getRoot());
CodeGenAndEmitDAG();
SDL->clear();
}
for (unsigned j = 0, ej = SDL->BitTestCases[i].Cases.size(); j != ej; ++j) {
BB = SDL->BitTestCases[i].Cases[j].ThisBB;
SDL->setCurrentBasicBlock(BB);
if (j+1 != ej)
SDL->visitBitTestCase(SDL->BitTestCases[i].Cases[j+1].ThisBB,
SDL->BitTestCases[i].Reg,
SDL->BitTestCases[i].Cases[j]);
else
SDL->visitBitTestCase(SDL->BitTestCases[i].Default,
SDL->BitTestCases[i].Reg,
SDL->BitTestCases[i].Cases[j]);
CurDAG->setRoot(SDL->getRoot());
CodeGenAndEmitDAG();
SDL->clear();
}
for (unsigned pi = 0, pe = SDL->PHINodesToUpdate.size(); pi != pe; ++pi) {
MachineInstr *PHI = SDL->PHINodesToUpdate[pi].first;
MachineBasicBlock *PHIBB = PHI->getParent();
assert(PHI->getOpcode() == TargetInstrInfo::PHI &&
"This is not a machine PHI node that we are updating!");
if (PHIBB == SDL->BitTestCases[i].Default) {
PHI->addOperand(MachineOperand::CreateReg(SDL->PHINodesToUpdate[pi].second,
false));
PHI->addOperand(MachineOperand::CreateMBB(SDL->BitTestCases[i].Parent));
PHI->addOperand(MachineOperand::CreateReg(SDL->PHINodesToUpdate[pi].second,
false));
PHI->addOperand(MachineOperand::CreateMBB(SDL->BitTestCases[i].Cases.
back().ThisBB));
}
for (unsigned j = 0, ej = SDL->BitTestCases[i].Cases.size();
j != ej; ++j) {
MachineBasicBlock* cBB = SDL->BitTestCases[i].Cases[j].ThisBB;
if (cBB->succ_end() !=
std::find(cBB->succ_begin(),cBB->succ_end(), PHIBB)) {
PHI->addOperand(MachineOperand::CreateReg(SDL->PHINodesToUpdate[pi].second,
false));
PHI->addOperand(MachineOperand::CreateMBB(cBB));
}
}
}
}
SDL->BitTestCases.clear();
for (unsigned i = 0, e = SDL->JTCases.size(); i != e; ++i) {
if (!SDL->JTCases[i].first.Emitted) {
BB = SDL->JTCases[i].first.HeaderBB;
SDL->setCurrentBasicBlock(BB);
SDL->visitJumpTableHeader(SDL->JTCases[i].second, SDL->JTCases[i].first);
CurDAG->setRoot(SDL->getRoot());
CodeGenAndEmitDAG();
SDL->clear();
}
BB = SDL->JTCases[i].second.MBB;
SDL->setCurrentBasicBlock(BB);
SDL->visitJumpTable(SDL->JTCases[i].second);
CurDAG->setRoot(SDL->getRoot());
CodeGenAndEmitDAG();
SDL->clear();
for (unsigned pi = 0, pe = SDL->PHINodesToUpdate.size(); pi != pe; ++pi) {
MachineInstr *PHI = SDL->PHINodesToUpdate[pi].first;
MachineBasicBlock *PHIBB = PHI->getParent();
assert(PHI->getOpcode() == TargetInstrInfo::PHI &&
"This is not a machine PHI node that we are updating!");
if (PHIBB == SDL->JTCases[i].second.Default) {
PHI->addOperand(MachineOperand::CreateReg(SDL->PHINodesToUpdate[pi].second,
false));
PHI->addOperand(MachineOperand::CreateMBB(SDL->JTCases[i].first.HeaderBB));
}
if (BB->succ_end() != std::find(BB->succ_begin(),BB->succ_end(), PHIBB)) {
PHI->addOperand(MachineOperand::CreateReg(SDL->PHINodesToUpdate[pi].second,
false));
PHI->addOperand(MachineOperand::CreateMBB(BB));
}
}
}
SDL->JTCases.clear();
for (unsigned i = 0, e = SDL->PHINodesToUpdate.size(); i != e; ++i) {
MachineInstr *PHI = SDL->PHINodesToUpdate[i].first;
assert(PHI->getOpcode() == TargetInstrInfo::PHI &&
"This is not a machine PHI node that we are updating!");
if (BB->isSuccessor(PHI->getParent())) {
PHI->addOperand(MachineOperand::CreateReg(SDL->PHINodesToUpdate[i].second,
false));
PHI->addOperand(MachineOperand::CreateMBB(BB));
}
}
for (unsigned i = 0, e = SDL->SwitchCases.size(); i != e; ++i) {
BB = SDL->SwitchCases[i].ThisBB;
SDL->setCurrentBasicBlock(BB);
SDL->visitSwitchCase(SDL->SwitchCases[i]);
CurDAG->setRoot(SDL->getRoot());
CodeGenAndEmitDAG();
SDL->clear();
while ((BB = SDL->SwitchCases[i].TrueBB)) { for (MachineBasicBlock::iterator Phi = BB->begin();
Phi != BB->end() && Phi->getOpcode() == TargetInstrInfo::PHI; ++Phi){
for (unsigned pn = 0; ; ++pn) {
assert(pn != SDL->PHINodesToUpdate.size() &&
"Didn't find PHI entry!");
if (SDL->PHINodesToUpdate[pn].first == Phi) {
Phi->addOperand(MachineOperand::CreateReg(SDL->PHINodesToUpdate[pn].
second, false));
Phi->addOperand(MachineOperand::CreateMBB(SDL->SwitchCases[i].ThisBB));
break;
}
}
}
if (BB == SDL->SwitchCases[i].FalseBB)
SDL->SwitchCases[i].FalseBB = 0;
SDL->SwitchCases[i].TrueBB = SDL->SwitchCases[i].FalseBB;
SDL->SwitchCases[i].FalseBB = 0;
}
assert(SDL->SwitchCases[i].TrueBB == 0 && SDL->SwitchCases[i].FalseBB == 0);
}
SDL->SwitchCases.clear();
SDL->PHINodesToUpdate.clear();
}
ScheduleDAGSDNodes *SelectionDAGISel::CreateScheduler() {
RegisterScheduler::FunctionPassCtor Ctor = RegisterScheduler::getDefault();
if (!Ctor) {
Ctor = ISHeuristic;
RegisterScheduler::setDefault(Ctor);
}
return Ctor(this, OptLevel);
}
ScheduleHazardRecognizer *SelectionDAGISel::CreateTargetHazardRecognizer() {
return new ScheduleHazardRecognizer();
}
bool SelectionDAGISel::CheckAndMask(SDValue LHS, ConstantSDNode *RHS,
int64_t DesiredMaskS) const {
const APInt &ActualMask = RHS->getAPIntValue();
const APInt &DesiredMask = APInt(LHS.getValueSizeInBits(), DesiredMaskS);
if (ActualMask == DesiredMask)
return true;
if (ActualMask.intersects(~DesiredMask))
return false;
APInt NeededMask = DesiredMask & ~ActualMask;
if (CurDAG->MaskedValueIsZero(LHS, NeededMask))
return true;
return false;
}
bool SelectionDAGISel::CheckOrMask(SDValue LHS, ConstantSDNode *RHS,
int64_t DesiredMaskS) const {
const APInt &ActualMask = RHS->getAPIntValue();
const APInt &DesiredMask = APInt(LHS.getValueSizeInBits(), DesiredMaskS);
if (ActualMask == DesiredMask)
return true;
if (ActualMask.intersects(~DesiredMask))
return false;
APInt NeededMask = DesiredMask & ~ActualMask;
APInt KnownZero, KnownOne;
CurDAG->ComputeMaskedBits(LHS, NeededMask, KnownZero, KnownOne);
if ((NeededMask & KnownOne) == NeededMask)
return true;
return false;
}
void SelectionDAGISel::
SelectInlineAsmMemoryOperands(std::vector<SDValue> &Ops) {
std::vector<SDValue> InOps;
std::swap(InOps, Ops);
Ops.push_back(InOps[0]); Ops.push_back(InOps[1]);
unsigned i = 2, e = InOps.size();
if (InOps[e-1].getValueType() == MVT::Flag)
--e;
while (i != e) {
unsigned Flags = cast<ConstantSDNode>(InOps[i])->getZExtValue();
if ((Flags & 7) != 4 ) {
Ops.insert(Ops.end(), InOps.begin()+i,
InOps.begin()+i+InlineAsm::getNumOperandRegisters(Flags) + 1);
i += InlineAsm::getNumOperandRegisters(Flags) + 1;
} else {
assert(InlineAsm::getNumOperandRegisters(Flags) == 1 &&
"Memory operand with multiple values?");
std::vector<SDValue> SelOps;
if (SelectInlineAsmMemoryOperand(InOps[i+1], 'm', SelOps)) {
cerr << "Could not match memory address. Inline asm failure!\n";
exit(1);
}
MVT IntPtrTy = CurDAG->getTargetLoweringInfo().getPointerTy();
Ops.push_back(CurDAG->getTargetConstant(4 | (SelOps.size()<< 3),
IntPtrTy));
Ops.insert(Ops.end(), SelOps.begin(), SelOps.end());
i += 2;
}
}
if (e != InOps.size())
Ops.push_back(InOps.back());
}
char SelectionDAGISel::ID = 0;