2016-01-21 04:58:56 +08:00
|
|
|
//===-- llvm/CodeGen/GlobalISel/IRTranslator.cpp - IRTranslator --*- C++ -*-==//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
/// \file
|
|
|
|
/// This file implements the IRTranslator class.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "llvm/CodeGen/GlobalISel/IRTranslator.h"
|
|
|
|
|
2017-02-24 07:57:28 +08:00
|
|
|
#include "llvm/ADT/ScopeExit.h"
|
2017-01-18 06:13:50 +08:00
|
|
|
#include "llvm/ADT/SmallSet.h"
|
2016-02-12 03:59:41 +08:00
|
|
|
#include "llvm/ADT/SmallVector.h"
|
2017-02-24 05:05:42 +08:00
|
|
|
#include "llvm/Analysis/OptimizationDiagnosticInfo.h"
|
2016-02-17 03:26:02 +08:00
|
|
|
#include "llvm/CodeGen/GlobalISel/CallLowering.h"
|
2016-11-10 06:39:54 +08:00
|
|
|
#include "llvm/CodeGen/Analysis.h"
|
2016-02-11 06:59:27 +08:00
|
|
|
#include "llvm/CodeGen/MachineFunction.h"
|
2016-07-23 00:59:52 +08:00
|
|
|
#include "llvm/CodeGen/MachineFrameInfo.h"
|
2016-11-10 06:39:54 +08:00
|
|
|
#include "llvm/CodeGen/MachineModuleInfo.h"
|
2016-02-12 01:51:31 +08:00
|
|
|
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
2016-08-27 07:49:05 +08:00
|
|
|
#include "llvm/CodeGen/TargetPassConfig.h"
|
2016-02-12 01:51:31 +08:00
|
|
|
#include "llvm/IR/Constant.h"
|
2017-01-27 07:39:14 +08:00
|
|
|
#include "llvm/IR/DebugInfo.h"
|
2016-02-11 06:59:27 +08:00
|
|
|
#include "llvm/IR/Function.h"
|
2016-09-12 19:20:22 +08:00
|
|
|
#include "llvm/IR/GetElementPtrTypeIterator.h"
|
2016-07-30 06:32:36 +08:00
|
|
|
#include "llvm/IR/IntrinsicInst.h"
|
2016-02-12 01:51:31 +08:00
|
|
|
#include "llvm/IR/Type.h"
|
|
|
|
#include "llvm/IR/Value.h"
|
2017-02-04 02:22:45 +08:00
|
|
|
#include "llvm/Target/TargetFrameLowering.h"
|
2016-07-30 06:32:36 +08:00
|
|
|
#include "llvm/Target/TargetIntrinsicInfo.h"
|
2016-02-12 02:53:28 +08:00
|
|
|
#include "llvm/Target/TargetLowering.h"
|
2016-02-11 06:59:27 +08:00
|
|
|
|
|
|
|
#define DEBUG_TYPE "irtranslator"
|
|
|
|
|
2016-01-21 04:58:56 +08:00
|
|
|
using namespace llvm;
|
|
|
|
|
|
|
|
char IRTranslator::ID = 0;
|
2016-08-27 07:49:05 +08:00
|
|
|
INITIALIZE_PASS_BEGIN(IRTranslator, DEBUG_TYPE, "IRTranslator LLVM IR -> MI",
|
|
|
|
false, false)
|
|
|
|
INITIALIZE_PASS_DEPENDENCY(TargetPassConfig)
|
|
|
|
INITIALIZE_PASS_END(IRTranslator, DEBUG_TYPE, "IRTranslator LLVM IR -> MI",
|
2016-07-26 11:29:18 +08:00
|
|
|
false, false)
|
2016-01-21 04:58:56 +08:00
|
|
|
|
2017-02-24 05:05:42 +08:00
|
|
|
static void reportTranslationError(MachineFunction &MF,
|
|
|
|
const TargetPassConfig &TPC,
|
|
|
|
OptimizationRemarkEmitter &ORE,
|
|
|
|
OptimizationRemarkMissed &R) {
|
|
|
|
MF.getProperties().set(MachineFunctionProperties::Property::FailedISel);
|
|
|
|
|
|
|
|
// Print the function name explicitly if we don't have a debug location (which
|
|
|
|
// makes the diagnostic less useful) or if we're going to emit a raw error.
|
|
|
|
if (!R.getLocation().isValid() || TPC.isGlobalISelAbortEnabled())
|
|
|
|
R << (" (in function: " + MF.getName() + ")").str();
|
|
|
|
|
|
|
|
if (TPC.isGlobalISelAbortEnabled())
|
|
|
|
report_fatal_error(R.getMsg());
|
|
|
|
else
|
|
|
|
ORE.emit(R);
|
2016-11-08 09:12:17 +08:00
|
|
|
}
|
|
|
|
|
2016-02-12 01:53:23 +08:00
|
|
|
IRTranslator::IRTranslator() : MachineFunctionPass(ID), MRI(nullptr) {
|
2016-03-08 09:38:55 +08:00
|
|
|
initializeIRTranslatorPass(*PassRegistry::getPassRegistry());
|
2016-02-12 01:53:23 +08:00
|
|
|
}
|
|
|
|
|
2016-08-27 07:49:05 +08:00
|
|
|
void IRTranslator::getAnalysisUsage(AnalysisUsage &AU) const {
|
|
|
|
AU.addRequired<TargetPassConfig>();
|
|
|
|
MachineFunctionPass::getAnalysisUsage(AU);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-03-12 01:27:54 +08:00
|
|
|
unsigned IRTranslator::getOrCreateVReg(const Value &Val) {
|
|
|
|
unsigned &ValReg = ValToVReg[&Val];
|
2017-01-26 04:58:22 +08:00
|
|
|
|
|
|
|
if (ValReg)
|
|
|
|
return ValReg;
|
|
|
|
|
|
|
|
// Fill ValRegsSequence with the sequence of registers
|
|
|
|
// we need to concat together to produce the value.
|
|
|
|
assert(Val.getType()->isSized() &&
|
|
|
|
"Don't know how to create an empty vreg");
|
Recommit: [globalisel] Change LLT constructor string into an LLT-based object that knows how to generate it.
Summary:
This will allow future patches to inspect the details of the LLT. The implementation is now split between
the Support and CodeGen libraries to allow TableGen to use this class without introducing layering concerns.
Thanks to Ahmed Bougacha for finding a reasonable way to avoid the layering issue and providing the version of this patch without that problem.
The problem with the previous commit appears to have been that TableGen was including CodeGen/LowLevelType.h instead of Support/LowLevelTypeImpl.h.
Reviewers: t.p.northover, qcolombet, rovka, aditya_nandakumar, ab, javed.absar
Subscribers: arsenm, nhaehnle, mgorny, dberris, llvm-commits, kristof.beyls
Differential Revision: https://reviews.llvm.org/D30046
llvm-svn: 297241
2017-03-08 07:20:35 +08:00
|
|
|
unsigned VReg =
|
|
|
|
MRI->createGenericVirtualRegister(getLLTForType(*Val.getType(), *DL));
|
2017-01-26 04:58:22 +08:00
|
|
|
ValReg = VReg;
|
|
|
|
|
|
|
|
if (auto CV = dyn_cast<Constant>(&Val)) {
|
|
|
|
bool Success = translate(*CV, VReg);
|
|
|
|
if (!Success) {
|
2017-02-24 05:05:42 +08:00
|
|
|
OptimizationRemarkMissed R("gisel-irtranslator", "GISelFailure",
|
2017-02-24 08:34:44 +08:00
|
|
|
MF->getFunction()->getSubprogram(),
|
2017-02-24 05:05:42 +08:00
|
|
|
&MF->getFunction()->getEntryBlock());
|
|
|
|
R << "unable to translate constant: " << ore::NV("Type", Val.getType());
|
|
|
|
reportTranslationError(*MF, *TPC, *ORE, R);
|
|
|
|
return VReg;
|
2016-08-10 05:28:04 +08:00
|
|
|
}
|
2016-02-12 01:51:31 +08:00
|
|
|
}
|
2017-01-21 07:25:17 +08:00
|
|
|
|
2017-01-26 04:58:22 +08:00
|
|
|
return VReg;
|
2016-02-12 01:51:31 +08:00
|
|
|
}
|
|
|
|
|
2016-11-01 02:30:59 +08:00
|
|
|
int IRTranslator::getOrCreateFrameIndex(const AllocaInst &AI) {
|
|
|
|
if (FrameIndices.find(&AI) != FrameIndices.end())
|
|
|
|
return FrameIndices[&AI];
|
|
|
|
|
|
|
|
unsigned ElementSize = DL->getTypeStoreSize(AI.getAllocatedType());
|
|
|
|
unsigned Size =
|
|
|
|
ElementSize * cast<ConstantInt>(AI.getArraySize())->getZExtValue();
|
|
|
|
|
|
|
|
// Always allocate at least one byte.
|
|
|
|
Size = std::max(Size, 1u);
|
|
|
|
|
|
|
|
unsigned Alignment = AI.getAlignment();
|
|
|
|
if (!Alignment)
|
|
|
|
Alignment = DL->getABITypeAlignment(AI.getAllocatedType());
|
|
|
|
|
|
|
|
int &FI = FrameIndices[&AI];
|
2016-12-08 05:17:47 +08:00
|
|
|
FI = MF->getFrameInfo().CreateStackObject(Size, Alignment, false, &AI);
|
2016-11-01 02:30:59 +08:00
|
|
|
return FI;
|
|
|
|
}
|
|
|
|
|
2016-07-27 04:23:26 +08:00
|
|
|
unsigned IRTranslator::getMemOpAlignment(const Instruction &I) {
|
|
|
|
unsigned Alignment = 0;
|
|
|
|
Type *ValTy = nullptr;
|
|
|
|
if (const StoreInst *SI = dyn_cast<StoreInst>(&I)) {
|
|
|
|
Alignment = SI->getAlignment();
|
|
|
|
ValTy = SI->getValueOperand()->getType();
|
|
|
|
} else if (const LoadInst *LI = dyn_cast<LoadInst>(&I)) {
|
|
|
|
Alignment = LI->getAlignment();
|
|
|
|
ValTy = LI->getType();
|
2017-02-24 05:05:42 +08:00
|
|
|
} else {
|
|
|
|
OptimizationRemarkMissed R("gisel-irtranslator", "", &I);
|
|
|
|
R << "unable to translate memop: " << ore::NV("Opcode", &I);
|
|
|
|
reportTranslationError(*MF, *TPC, *ORE, R);
|
2016-08-27 07:49:05 +08:00
|
|
|
return 1;
|
2017-02-24 05:05:42 +08:00
|
|
|
}
|
2016-07-27 04:23:26 +08:00
|
|
|
|
|
|
|
return Alignment ? Alignment : DL->getABITypeAlignment(ValTy);
|
|
|
|
}
|
|
|
|
|
2016-03-12 01:27:43 +08:00
|
|
|
MachineBasicBlock &IRTranslator::getOrCreateBB(const BasicBlock &BB) {
|
|
|
|
MachineBasicBlock *&MBB = BBToMBB[&BB];
|
2016-02-12 01:51:31 +08:00
|
|
|
if (!MBB) {
|
2017-01-05 21:27:52 +08:00
|
|
|
MBB = MF->CreateMachineBasicBlock(&BB);
|
2016-12-08 05:17:47 +08:00
|
|
|
MF->push_back(MBB);
|
2017-01-05 21:27:52 +08:00
|
|
|
|
|
|
|
if (BB.hasAddressTaken())
|
|
|
|
MBB->setHasAddressTaken();
|
2016-02-12 01:51:31 +08:00
|
|
|
}
|
|
|
|
return *MBB;
|
|
|
|
}
|
|
|
|
|
2017-01-18 06:13:50 +08:00
|
|
|
void IRTranslator::addMachineCFGPred(CFGEdge Edge, MachineBasicBlock *NewPred) {
|
|
|
|
assert(NewPred && "new predecessor must be a real MachineBasicBlock");
|
|
|
|
MachinePreds[Edge].push_back(NewPred);
|
|
|
|
}
|
|
|
|
|
2016-12-08 05:29:15 +08:00
|
|
|
bool IRTranslator::translateBinaryOp(unsigned Opcode, const User &U,
|
|
|
|
MachineIRBuilder &MIRBuilder) {
|
2016-07-30 02:11:21 +08:00
|
|
|
// FIXME: handle signed/unsigned wrapping flags.
|
|
|
|
|
2016-02-11 06:59:27 +08:00
|
|
|
// Get or create a virtual register for each value.
|
|
|
|
// Unless the value is a Constant => loadimm cst?
|
|
|
|
// or inline constant each time?
|
|
|
|
// Creation of a virtual register needs to have a size.
|
2016-08-11 07:02:41 +08:00
|
|
|
unsigned Op0 = getOrCreateVReg(*U.getOperand(0));
|
|
|
|
unsigned Op1 = getOrCreateVReg(*U.getOperand(1));
|
|
|
|
unsigned Res = getOrCreateVReg(U);
|
2016-09-09 19:46:34 +08:00
|
|
|
MIRBuilder.buildInstr(Opcode).addDef(Res).addUse(Op0).addUse(Op1);
|
2016-02-12 01:51:31 +08:00
|
|
|
return true;
|
2016-01-21 04:58:56 +08:00
|
|
|
}
|
|
|
|
|
2017-03-08 02:03:28 +08:00
|
|
|
bool IRTranslator::translateFSub(const User &U, MachineIRBuilder &MIRBuilder) {
|
|
|
|
// -0.0 - X --> G_FNEG
|
|
|
|
if (isa<Constant>(U.getOperand(0)) &&
|
|
|
|
U.getOperand(0) == ConstantFP::getZeroValueForNegation(U.getType())) {
|
|
|
|
MIRBuilder.buildInstr(TargetOpcode::G_FNEG)
|
|
|
|
.addDef(getOrCreateVReg(U))
|
|
|
|
.addUse(getOrCreateVReg(*U.getOperand(1)));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return translateBinaryOp(TargetOpcode::G_FSUB, U, MIRBuilder);
|
|
|
|
}
|
|
|
|
|
2016-12-08 05:29:15 +08:00
|
|
|
bool IRTranslator::translateCompare(const User &U,
|
|
|
|
MachineIRBuilder &MIRBuilder) {
|
2016-08-20 04:48:16 +08:00
|
|
|
const CmpInst *CI = dyn_cast<CmpInst>(&U);
|
|
|
|
unsigned Op0 = getOrCreateVReg(*U.getOperand(0));
|
|
|
|
unsigned Op1 = getOrCreateVReg(*U.getOperand(1));
|
|
|
|
unsigned Res = getOrCreateVReg(U);
|
|
|
|
CmpInst::Predicate Pred =
|
|
|
|
CI ? CI->getPredicate() : static_cast<CmpInst::Predicate>(
|
|
|
|
cast<ConstantExpr>(U).getPredicate());
|
|
|
|
if (CmpInst::isIntPredicate(Pred))
|
2016-09-09 19:46:34 +08:00
|
|
|
MIRBuilder.buildICmp(Pred, Res, Op0, Op1);
|
2017-03-09 02:49:54 +08:00
|
|
|
else if (Pred == CmpInst::FCMP_FALSE)
|
|
|
|
MIRBuilder.buildConstant(Res, 0);
|
|
|
|
else if (Pred == CmpInst::FCMP_TRUE)
|
|
|
|
MIRBuilder.buildConstant(Res, 1);
|
2016-08-20 04:48:16 +08:00
|
|
|
else
|
2016-09-09 19:46:34 +08:00
|
|
|
MIRBuilder.buildFCmp(Pred, Res, Op0, Op1);
|
2016-08-20 04:48:16 +08:00
|
|
|
|
2016-08-18 04:25:25 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-12-08 05:29:15 +08:00
|
|
|
bool IRTranslator::translateRet(const User &U, MachineIRBuilder &MIRBuilder) {
|
2016-08-11 07:02:41 +08:00
|
|
|
const ReturnInst &RI = cast<ReturnInst>(U);
|
2016-07-30 02:11:21 +08:00
|
|
|
const Value *Ret = RI.getReturnValue();
|
2016-02-12 02:53:28 +08:00
|
|
|
// The target may mess up with the insertion point, but
|
|
|
|
// this is not important as a return is the last instruction
|
|
|
|
// of the block anyway.
|
2016-04-15 01:23:33 +08:00
|
|
|
return CLI->lowerReturn(MIRBuilder, Ret, !Ret ? 0 : getOrCreateVReg(*Ret));
|
2016-02-12 02:53:28 +08:00
|
|
|
}
|
|
|
|
|
2016-12-08 05:29:15 +08:00
|
|
|
bool IRTranslator::translateBr(const User &U, MachineIRBuilder &MIRBuilder) {
|
2016-08-11 07:02:41 +08:00
|
|
|
const BranchInst &BrInst = cast<BranchInst>(U);
|
2016-07-30 01:58:00 +08:00
|
|
|
unsigned Succ = 0;
|
|
|
|
if (!BrInst.isUnconditional()) {
|
|
|
|
// We want a G_BRCOND to the true BB followed by an unconditional branch.
|
|
|
|
unsigned Tst = getOrCreateVReg(*BrInst.getCondition());
|
|
|
|
const BasicBlock &TrueTgt = *cast<BasicBlock>(BrInst.getSuccessor(Succ++));
|
|
|
|
MachineBasicBlock &TrueBB = getOrCreateBB(TrueTgt);
|
2016-09-09 19:46:34 +08:00
|
|
|
MIRBuilder.buildBrCond(Tst, TrueBB);
|
2016-03-12 01:28:03 +08:00
|
|
|
}
|
2016-07-30 01:58:00 +08:00
|
|
|
|
|
|
|
const BasicBlock &BrTgt = *cast<BasicBlock>(BrInst.getSuccessor(Succ));
|
|
|
|
MachineBasicBlock &TgtBB = getOrCreateBB(BrTgt);
|
|
|
|
MIRBuilder.buildBr(TgtBB);
|
|
|
|
|
2016-03-12 01:28:03 +08:00
|
|
|
// Link successors.
|
|
|
|
MachineBasicBlock &CurBB = MIRBuilder.getMBB();
|
|
|
|
for (const BasicBlock *Succ : BrInst.successors())
|
|
|
|
CurBB.addSuccessor(&getOrCreateBB(*Succ));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-01-05 19:28:51 +08:00
|
|
|
bool IRTranslator::translateSwitch(const User &U,
|
|
|
|
MachineIRBuilder &MIRBuilder) {
|
|
|
|
// For now, just translate as a chain of conditional branches.
|
|
|
|
// FIXME: could we share most of the logic/code in
|
|
|
|
// SelectionDAGBuilder::visitSwitch between SelectionDAG and GlobalISel?
|
|
|
|
// At first sight, it seems most of the logic in there is independent of
|
|
|
|
// SelectionDAG-specifics and a lot of work went in to optimize switch
|
|
|
|
// lowering in there.
|
|
|
|
|
|
|
|
const SwitchInst &SwInst = cast<SwitchInst>(U);
|
|
|
|
const unsigned SwCondValue = getOrCreateVReg(*SwInst.getCondition());
|
2017-01-18 06:13:50 +08:00
|
|
|
const BasicBlock *OrigBB = SwInst.getParent();
|
2017-01-05 19:28:51 +08:00
|
|
|
|
Recommit: [globalisel] Change LLT constructor string into an LLT-based object that knows how to generate it.
Summary:
This will allow future patches to inspect the details of the LLT. The implementation is now split between
the Support and CodeGen libraries to allow TableGen to use this class without introducing layering concerns.
Thanks to Ahmed Bougacha for finding a reasonable way to avoid the layering issue and providing the version of this patch without that problem.
The problem with the previous commit appears to have been that TableGen was including CodeGen/LowLevelType.h instead of Support/LowLevelTypeImpl.h.
Reviewers: t.p.northover, qcolombet, rovka, aditya_nandakumar, ab, javed.absar
Subscribers: arsenm, nhaehnle, mgorny, dberris, llvm-commits, kristof.beyls
Differential Revision: https://reviews.llvm.org/D30046
llvm-svn: 297241
2017-03-08 07:20:35 +08:00
|
|
|
LLT LLTi1 = getLLTForType(*Type::getInt1Ty(U.getContext()), *DL);
|
2017-01-05 19:28:51 +08:00
|
|
|
for (auto &CaseIt : SwInst.cases()) {
|
|
|
|
const unsigned CaseValueReg = getOrCreateVReg(*CaseIt.getCaseValue());
|
|
|
|
const unsigned Tst = MRI->createGenericVirtualRegister(LLTi1);
|
|
|
|
MIRBuilder.buildICmp(CmpInst::ICMP_EQ, Tst, CaseValueReg, SwCondValue);
|
2017-01-18 06:13:50 +08:00
|
|
|
MachineBasicBlock &CurMBB = MIRBuilder.getMBB();
|
|
|
|
const BasicBlock *TrueBB = CaseIt.getCaseSuccessor();
|
|
|
|
MachineBasicBlock &TrueMBB = getOrCreateBB(*TrueBB);
|
2017-01-05 19:28:51 +08:00
|
|
|
|
2017-01-18 06:13:50 +08:00
|
|
|
MIRBuilder.buildBrCond(Tst, TrueMBB);
|
|
|
|
CurMBB.addSuccessor(&TrueMBB);
|
|
|
|
addMachineCFGPred({OrigBB, TrueBB}, &CurMBB);
|
2017-01-05 19:28:51 +08:00
|
|
|
|
2017-01-18 06:13:50 +08:00
|
|
|
MachineBasicBlock *FalseMBB =
|
2017-01-05 19:28:51 +08:00
|
|
|
MF->CreateMachineBasicBlock(SwInst.getParent());
|
2017-01-18 06:13:50 +08:00
|
|
|
MF->push_back(FalseMBB);
|
|
|
|
MIRBuilder.buildBr(*FalseMBB);
|
|
|
|
CurMBB.addSuccessor(FalseMBB);
|
2017-01-05 19:28:51 +08:00
|
|
|
|
2017-01-18 06:13:50 +08:00
|
|
|
MIRBuilder.setMBB(*FalseMBB);
|
2017-01-05 19:28:51 +08:00
|
|
|
}
|
|
|
|
// handle default case
|
2017-01-18 06:13:50 +08:00
|
|
|
const BasicBlock *DefaultBB = SwInst.getDefaultDest();
|
|
|
|
MachineBasicBlock &DefaultMBB = getOrCreateBB(*DefaultBB);
|
|
|
|
MIRBuilder.buildBr(DefaultMBB);
|
|
|
|
MachineBasicBlock &CurMBB = MIRBuilder.getMBB();
|
|
|
|
CurMBB.addSuccessor(&DefaultMBB);
|
|
|
|
addMachineCFGPred({OrigBB, DefaultBB}, &CurMBB);
|
2017-01-05 19:28:51 +08:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-01-30 17:13:18 +08:00
|
|
|
bool IRTranslator::translateIndirectBr(const User &U,
|
|
|
|
MachineIRBuilder &MIRBuilder) {
|
|
|
|
const IndirectBrInst &BrInst = cast<IndirectBrInst>(U);
|
|
|
|
|
|
|
|
const unsigned Tgt = getOrCreateVReg(*BrInst.getAddress());
|
|
|
|
MIRBuilder.buildBrIndirect(Tgt);
|
|
|
|
|
|
|
|
// Link successors.
|
|
|
|
MachineBasicBlock &CurBB = MIRBuilder.getMBB();
|
|
|
|
for (const BasicBlock *Succ : BrInst.successors())
|
|
|
|
CurBB.addSuccessor(&getOrCreateBB(*Succ));
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-12-08 05:29:15 +08:00
|
|
|
bool IRTranslator::translateLoad(const User &U, MachineIRBuilder &MIRBuilder) {
|
2016-08-11 07:02:41 +08:00
|
|
|
const LoadInst &LI = cast<LoadInst>(U);
|
2016-08-27 07:49:05 +08:00
|
|
|
|
2016-10-19 23:55:06 +08:00
|
|
|
auto Flags = LI.isVolatile() ? MachineMemOperand::MOVolatile
|
|
|
|
: MachineMemOperand::MONone;
|
|
|
|
Flags |= MachineMemOperand::MOLoad;
|
2016-07-27 04:23:26 +08:00
|
|
|
|
|
|
|
unsigned Res = getOrCreateVReg(LI);
|
|
|
|
unsigned Addr = getOrCreateVReg(*LI.getPointerOperand());
|
Recommit: [globalisel] Change LLT constructor string into an LLT-based object that knows how to generate it.
Summary:
This will allow future patches to inspect the details of the LLT. The implementation is now split between
the Support and CodeGen libraries to allow TableGen to use this class without introducing layering concerns.
Thanks to Ahmed Bougacha for finding a reasonable way to avoid the layering issue and providing the version of this patch without that problem.
The problem with the previous commit appears to have been that TableGen was including CodeGen/LowLevelType.h instead of Support/LowLevelTypeImpl.h.
Reviewers: t.p.northover, qcolombet, rovka, aditya_nandakumar, ab, javed.absar
Subscribers: arsenm, nhaehnle, mgorny, dberris, llvm-commits, kristof.beyls
Differential Revision: https://reviews.llvm.org/D30046
llvm-svn: 297241
2017-03-08 07:20:35 +08:00
|
|
|
|
2016-07-27 04:23:26 +08:00
|
|
|
MIRBuilder.buildLoad(
|
2016-09-09 19:46:34 +08:00
|
|
|
Res, Addr,
|
2016-12-08 05:17:47 +08:00
|
|
|
*MF->getMachineMemOperand(MachinePointerInfo(LI.getPointerOperand()),
|
|
|
|
Flags, DL->getTypeStoreSize(LI.getType()),
|
2017-02-14 06:14:16 +08:00
|
|
|
getMemOpAlignment(LI), AAMDNodes(), nullptr,
|
|
|
|
LI.getSynchScope(), LI.getOrdering()));
|
2016-07-27 04:23:26 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-12-08 05:29:15 +08:00
|
|
|
bool IRTranslator::translateStore(const User &U, MachineIRBuilder &MIRBuilder) {
|
2016-08-11 07:02:41 +08:00
|
|
|
const StoreInst &SI = cast<StoreInst>(U);
|
2016-10-19 23:55:06 +08:00
|
|
|
auto Flags = SI.isVolatile() ? MachineMemOperand::MOVolatile
|
|
|
|
: MachineMemOperand::MONone;
|
|
|
|
Flags |= MachineMemOperand::MOStore;
|
2016-07-27 04:23:26 +08:00
|
|
|
|
|
|
|
unsigned Val = getOrCreateVReg(*SI.getValueOperand());
|
|
|
|
unsigned Addr = getOrCreateVReg(*SI.getPointerOperand());
|
|
|
|
|
|
|
|
MIRBuilder.buildStore(
|
2016-12-08 05:17:47 +08:00
|
|
|
Val, Addr,
|
|
|
|
*MF->getMachineMemOperand(
|
|
|
|
MachinePointerInfo(SI.getPointerOperand()), Flags,
|
|
|
|
DL->getTypeStoreSize(SI.getValueOperand()->getType()),
|
2017-02-14 06:14:16 +08:00
|
|
|
getMemOpAlignment(SI), AAMDNodes(), nullptr, SI.getSynchScope(),
|
|
|
|
SI.getOrdering()));
|
2016-07-27 04:23:26 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-12-08 05:29:15 +08:00
|
|
|
bool IRTranslator::translateExtractValue(const User &U,
|
|
|
|
MachineIRBuilder &MIRBuilder) {
|
2016-08-20 04:09:03 +08:00
|
|
|
const Value *Src = U.getOperand(0);
|
|
|
|
Type *Int32Ty = Type::getInt32Ty(U.getContext());
|
2016-08-20 01:47:05 +08:00
|
|
|
SmallVector<Value *, 1> Indices;
|
|
|
|
|
|
|
|
// getIndexedOffsetInType is designed for GEPs, so the first index is the
|
|
|
|
// usual array element rather than looking into the actual aggregate.
|
|
|
|
Indices.push_back(ConstantInt::get(Int32Ty, 0));
|
2016-08-20 04:09:03 +08:00
|
|
|
|
|
|
|
if (const ExtractValueInst *EVI = dyn_cast<ExtractValueInst>(&U)) {
|
|
|
|
for (auto Idx : EVI->indices())
|
|
|
|
Indices.push_back(ConstantInt::get(Int32Ty, Idx));
|
|
|
|
} else {
|
|
|
|
for (unsigned i = 1; i < U.getNumOperands(); ++i)
|
|
|
|
Indices.push_back(U.getOperand(i));
|
|
|
|
}
|
2016-08-20 01:47:05 +08:00
|
|
|
|
|
|
|
uint64_t Offset = 8 * DL->getIndexedOffsetInType(Src->getType(), Indices);
|
|
|
|
|
2016-08-20 04:09:03 +08:00
|
|
|
unsigned Res = getOrCreateVReg(U);
|
2017-03-07 07:50:28 +08:00
|
|
|
MIRBuilder.buildExtract(Res, getOrCreateVReg(*Src), Offset);
|
2016-08-20 01:47:05 +08:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-12-08 05:29:15 +08:00
|
|
|
bool IRTranslator::translateInsertValue(const User &U,
|
|
|
|
MachineIRBuilder &MIRBuilder) {
|
2016-08-20 04:09:03 +08:00
|
|
|
const Value *Src = U.getOperand(0);
|
|
|
|
Type *Int32Ty = Type::getInt32Ty(U.getContext());
|
2016-08-20 04:08:55 +08:00
|
|
|
SmallVector<Value *, 1> Indices;
|
|
|
|
|
|
|
|
// getIndexedOffsetInType is designed for GEPs, so the first index is the
|
|
|
|
// usual array element rather than looking into the actual aggregate.
|
|
|
|
Indices.push_back(ConstantInt::get(Int32Ty, 0));
|
2016-08-20 04:09:03 +08:00
|
|
|
|
|
|
|
if (const InsertValueInst *IVI = dyn_cast<InsertValueInst>(&U)) {
|
|
|
|
for (auto Idx : IVI->indices())
|
|
|
|
Indices.push_back(ConstantInt::get(Int32Ty, Idx));
|
|
|
|
} else {
|
|
|
|
for (unsigned i = 2; i < U.getNumOperands(); ++i)
|
|
|
|
Indices.push_back(U.getOperand(i));
|
|
|
|
}
|
2016-08-20 04:08:55 +08:00
|
|
|
|
|
|
|
uint64_t Offset = 8 * DL->getIndexedOffsetInType(Src->getType(), Indices);
|
|
|
|
|
2016-08-20 04:09:03 +08:00
|
|
|
unsigned Res = getOrCreateVReg(U);
|
|
|
|
const Value &Inserted = *U.getOperand(1);
|
2016-09-09 19:46:34 +08:00
|
|
|
MIRBuilder.buildInsert(Res, getOrCreateVReg(*Src), getOrCreateVReg(Inserted),
|
|
|
|
Offset);
|
2016-08-20 04:08:55 +08:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-12-08 05:29:15 +08:00
|
|
|
bool IRTranslator::translateSelect(const User &U,
|
|
|
|
MachineIRBuilder &MIRBuilder) {
|
2016-09-09 19:46:34 +08:00
|
|
|
MIRBuilder.buildSelect(getOrCreateVReg(U), getOrCreateVReg(*U.getOperand(0)),
|
|
|
|
getOrCreateVReg(*U.getOperand(1)),
|
|
|
|
getOrCreateVReg(*U.getOperand(2)));
|
2016-08-20 04:09:07 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-12-08 05:29:15 +08:00
|
|
|
bool IRTranslator::translateBitCast(const User &U,
|
|
|
|
MachineIRBuilder &MIRBuilder) {
|
2017-03-08 04:53:06 +08:00
|
|
|
// If we're bitcasting to the source type, we can reuse the source vreg.
|
Recommit: [globalisel] Change LLT constructor string into an LLT-based object that knows how to generate it.
Summary:
This will allow future patches to inspect the details of the LLT. The implementation is now split between
the Support and CodeGen libraries to allow TableGen to use this class without introducing layering concerns.
Thanks to Ahmed Bougacha for finding a reasonable way to avoid the layering issue and providing the version of this patch without that problem.
The problem with the previous commit appears to have been that TableGen was including CodeGen/LowLevelType.h instead of Support/LowLevelTypeImpl.h.
Reviewers: t.p.northover, qcolombet, rovka, aditya_nandakumar, ab, javed.absar
Subscribers: arsenm, nhaehnle, mgorny, dberris, llvm-commits, kristof.beyls
Differential Revision: https://reviews.llvm.org/D30046
llvm-svn: 297241
2017-03-08 07:20:35 +08:00
|
|
|
if (getLLTForType(*U.getOperand(0)->getType(), *DL) ==
|
|
|
|
getLLTForType(*U.getType(), *DL)) {
|
2017-03-08 04:53:06 +08:00
|
|
|
// Get the source vreg now, to avoid invalidating ValToVReg.
|
|
|
|
unsigned SrcReg = getOrCreateVReg(*U.getOperand(0));
|
2016-08-11 07:02:41 +08:00
|
|
|
unsigned &Reg = ValToVReg[&U];
|
2017-03-08 04:53:06 +08:00
|
|
|
// If we already assigned a vreg for this bitcast, we can't change that.
|
|
|
|
// Emit a copy to satisfy the users we already emitted.
|
2016-08-11 00:51:14 +08:00
|
|
|
if (Reg)
|
2017-03-08 04:53:06 +08:00
|
|
|
MIRBuilder.buildCopy(Reg, SrcReg);
|
2016-08-11 00:51:14 +08:00
|
|
|
else
|
2017-03-08 04:53:06 +08:00
|
|
|
Reg = SrcReg;
|
2016-07-26 05:01:29 +08:00
|
|
|
return true;
|
|
|
|
}
|
2016-12-08 05:29:15 +08:00
|
|
|
return translateCast(TargetOpcode::G_BITCAST, U, MIRBuilder);
|
2016-07-26 05:01:29 +08:00
|
|
|
}
|
|
|
|
|
2016-12-08 05:29:15 +08:00
|
|
|
bool IRTranslator::translateCast(unsigned Opcode, const User &U,
|
|
|
|
MachineIRBuilder &MIRBuilder) {
|
2016-08-11 07:02:41 +08:00
|
|
|
unsigned Op = getOrCreateVReg(*U.getOperand(0));
|
|
|
|
unsigned Res = getOrCreateVReg(U);
|
2016-09-09 19:46:34 +08:00
|
|
|
MIRBuilder.buildInstr(Opcode).addDef(Res).addUse(Op);
|
2016-07-26 05:01:29 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-12-08 05:29:15 +08:00
|
|
|
bool IRTranslator::translateGetElementPtr(const User &U,
|
|
|
|
MachineIRBuilder &MIRBuilder) {
|
2016-09-12 19:20:22 +08:00
|
|
|
// FIXME: support vector GEPs.
|
|
|
|
if (U.getType()->isVectorTy())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
Value &Op0 = *U.getOperand(0);
|
|
|
|
unsigned BaseReg = getOrCreateVReg(Op0);
|
Recommit: [globalisel] Change LLT constructor string into an LLT-based object that knows how to generate it.
Summary:
This will allow future patches to inspect the details of the LLT. The implementation is now split between
the Support and CodeGen libraries to allow TableGen to use this class without introducing layering concerns.
Thanks to Ahmed Bougacha for finding a reasonable way to avoid the layering issue and providing the version of this patch without that problem.
The problem with the previous commit appears to have been that TableGen was including CodeGen/LowLevelType.h instead of Support/LowLevelTypeImpl.h.
Reviewers: t.p.northover, qcolombet, rovka, aditya_nandakumar, ab, javed.absar
Subscribers: arsenm, nhaehnle, mgorny, dberris, llvm-commits, kristof.beyls
Differential Revision: https://reviews.llvm.org/D30046
llvm-svn: 297241
2017-03-08 07:20:35 +08:00
|
|
|
LLT PtrTy = getLLTForType(*Op0.getType(), *DL);
|
2016-09-12 19:20:22 +08:00
|
|
|
unsigned PtrSize = DL->getPointerSizeInBits(PtrTy.getAddressSpace());
|
|
|
|
LLT OffsetTy = LLT::scalar(PtrSize);
|
|
|
|
|
|
|
|
int64_t Offset = 0;
|
|
|
|
for (gep_type_iterator GTI = gep_type_begin(&U), E = gep_type_end(&U);
|
|
|
|
GTI != E; ++GTI) {
|
|
|
|
const Value *Idx = GTI.getOperand();
|
2016-12-02 10:55:30 +08:00
|
|
|
if (StructType *StTy = GTI.getStructTypeOrNull()) {
|
2016-09-12 19:20:22 +08:00
|
|
|
unsigned Field = cast<Constant>(Idx)->getUniqueInteger().getZExtValue();
|
|
|
|
Offset += DL->getStructLayout(StTy)->getElementOffset(Field);
|
|
|
|
continue;
|
|
|
|
} else {
|
|
|
|
uint64_t ElementSize = DL->getTypeAllocSize(GTI.getIndexedType());
|
|
|
|
|
|
|
|
// If this is a scalar constant or a splat vector of constants,
|
|
|
|
// handle it quickly.
|
|
|
|
if (const auto *CI = dyn_cast<ConstantInt>(Idx)) {
|
|
|
|
Offset += ElementSize * CI->getSExtValue();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Offset != 0) {
|
|
|
|
unsigned NewBaseReg = MRI->createGenericVirtualRegister(PtrTy);
|
|
|
|
unsigned OffsetReg = MRI->createGenericVirtualRegister(OffsetTy);
|
|
|
|
MIRBuilder.buildConstant(OffsetReg, Offset);
|
|
|
|
MIRBuilder.buildGEP(NewBaseReg, BaseReg, OffsetReg);
|
|
|
|
|
|
|
|
BaseReg = NewBaseReg;
|
|
|
|
Offset = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// N = N + Idx * ElementSize;
|
|
|
|
unsigned ElementSizeReg = MRI->createGenericVirtualRegister(OffsetTy);
|
|
|
|
MIRBuilder.buildConstant(ElementSizeReg, ElementSize);
|
|
|
|
|
|
|
|
unsigned IdxReg = getOrCreateVReg(*Idx);
|
|
|
|
if (MRI->getType(IdxReg) != OffsetTy) {
|
|
|
|
unsigned NewIdxReg = MRI->createGenericVirtualRegister(OffsetTy);
|
|
|
|
MIRBuilder.buildSExtOrTrunc(NewIdxReg, IdxReg);
|
|
|
|
IdxReg = NewIdxReg;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned OffsetReg = MRI->createGenericVirtualRegister(OffsetTy);
|
|
|
|
MIRBuilder.buildMul(OffsetReg, ElementSizeReg, IdxReg);
|
|
|
|
|
|
|
|
unsigned NewBaseReg = MRI->createGenericVirtualRegister(PtrTy);
|
|
|
|
MIRBuilder.buildGEP(NewBaseReg, BaseReg, OffsetReg);
|
|
|
|
BaseReg = NewBaseReg;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Offset != 0) {
|
|
|
|
unsigned OffsetReg = MRI->createGenericVirtualRegister(OffsetTy);
|
|
|
|
MIRBuilder.buildConstant(OffsetReg, Offset);
|
|
|
|
MIRBuilder.buildGEP(getOrCreateVReg(U), BaseReg, OffsetReg);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
MIRBuilder.buildCopy(getOrCreateVReg(U), BaseReg);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-01-31 03:33:07 +08:00
|
|
|
bool IRTranslator::translateMemfunc(const CallInst &CI,
|
|
|
|
MachineIRBuilder &MIRBuilder,
|
|
|
|
unsigned ID) {
|
Recommit: [globalisel] Change LLT constructor string into an LLT-based object that knows how to generate it.
Summary:
This will allow future patches to inspect the details of the LLT. The implementation is now split between
the Support and CodeGen libraries to allow TableGen to use this class without introducing layering concerns.
Thanks to Ahmed Bougacha for finding a reasonable way to avoid the layering issue and providing the version of this patch without that problem.
The problem with the previous commit appears to have been that TableGen was including CodeGen/LowLevelType.h instead of Support/LowLevelTypeImpl.h.
Reviewers: t.p.northover, qcolombet, rovka, aditya_nandakumar, ab, javed.absar
Subscribers: arsenm, nhaehnle, mgorny, dberris, llvm-commits, kristof.beyls
Differential Revision: https://reviews.llvm.org/D30046
llvm-svn: 297241
2017-03-08 07:20:35 +08:00
|
|
|
LLT SizeTy = getLLTForType(*CI.getArgOperand(2)->getType(), *DL);
|
2017-01-31 03:33:07 +08:00
|
|
|
Type *DstTy = CI.getArgOperand(0)->getType();
|
|
|
|
if (cast<PointerType>(DstTy)->getAddressSpace() != 0 ||
|
2016-10-19 04:03:45 +08:00
|
|
|
SizeTy.getSizeInBits() != DL->getPointerSizeInBits(0))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
SmallVector<CallLowering::ArgInfo, 8> Args;
|
|
|
|
for (int i = 0; i < 3; ++i) {
|
|
|
|
const auto &Arg = CI.getArgOperand(i);
|
|
|
|
Args.emplace_back(getOrCreateVReg(*Arg), Arg->getType());
|
|
|
|
}
|
|
|
|
|
2017-01-31 03:33:07 +08:00
|
|
|
const char *Callee;
|
|
|
|
switch (ID) {
|
|
|
|
case Intrinsic::memmove:
|
|
|
|
case Intrinsic::memcpy: {
|
|
|
|
Type *SrcTy = CI.getArgOperand(1)->getType();
|
|
|
|
if(cast<PointerType>(SrcTy)->getAddressSpace() != 0)
|
|
|
|
return false;
|
|
|
|
Callee = ID == Intrinsic::memcpy ? "memcpy" : "memmove";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Intrinsic::memset:
|
|
|
|
Callee = "memset";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
2016-10-19 04:03:45 +08:00
|
|
|
|
2017-01-31 03:33:07 +08:00
|
|
|
return CLI->lowerCall(MIRBuilder, MachineOperand::CreateES(Callee),
|
2016-10-19 04:03:45 +08:00
|
|
|
CallLowering::ArgInfo(0, CI.getType()), Args);
|
|
|
|
}
|
2016-09-12 19:20:22 +08:00
|
|
|
|
2016-12-08 05:29:15 +08:00
|
|
|
void IRTranslator::getStackGuard(unsigned DstReg,
|
|
|
|
MachineIRBuilder &MIRBuilder) {
|
2017-01-28 05:31:24 +08:00
|
|
|
const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo();
|
|
|
|
MRI->setRegClass(DstReg, TRI->getPointerRegClass(*MF));
|
2016-11-01 02:30:59 +08:00
|
|
|
auto MIB = MIRBuilder.buildInstr(TargetOpcode::LOAD_STACK_GUARD);
|
|
|
|
MIB.addDef(DstReg);
|
|
|
|
|
2016-12-08 05:17:47 +08:00
|
|
|
auto &TLI = *MF->getSubtarget().getTargetLowering();
|
|
|
|
Value *Global = TLI.getSDagStackGuard(*MF->getFunction()->getParent());
|
2016-11-01 02:30:59 +08:00
|
|
|
if (!Global)
|
|
|
|
return;
|
|
|
|
|
|
|
|
MachinePointerInfo MPInfo(Global);
|
2016-12-08 05:17:47 +08:00
|
|
|
MachineInstr::mmo_iterator MemRefs = MF->allocateMemRefsArray(1);
|
2016-11-01 02:30:59 +08:00
|
|
|
auto Flags = MachineMemOperand::MOLoad | MachineMemOperand::MOInvariant |
|
|
|
|
MachineMemOperand::MODereferenceable;
|
|
|
|
*MemRefs =
|
2016-12-08 05:17:47 +08:00
|
|
|
MF->getMachineMemOperand(MPInfo, Flags, DL->getPointerSizeInBits() / 8,
|
|
|
|
DL->getPointerABIAlignment());
|
2016-11-01 02:30:59 +08:00
|
|
|
MIB.setMemRefs(MemRefs, MemRefs + 1);
|
|
|
|
}
|
|
|
|
|
2016-12-09 06:44:00 +08:00
|
|
|
bool IRTranslator::translateOverflowIntrinsic(const CallInst &CI, unsigned Op,
|
|
|
|
MachineIRBuilder &MIRBuilder) {
|
Recommit: [globalisel] Change LLT constructor string into an LLT-based object that knows how to generate it.
Summary:
This will allow future patches to inspect the details of the LLT. The implementation is now split between
the Support and CodeGen libraries to allow TableGen to use this class without introducing layering concerns.
Thanks to Ahmed Bougacha for finding a reasonable way to avoid the layering issue and providing the version of this patch without that problem.
The problem with the previous commit appears to have been that TableGen was including CodeGen/LowLevelType.h instead of Support/LowLevelTypeImpl.h.
Reviewers: t.p.northover, qcolombet, rovka, aditya_nandakumar, ab, javed.absar
Subscribers: arsenm, nhaehnle, mgorny, dberris, llvm-commits, kristof.beyls
Differential Revision: https://reviews.llvm.org/D30046
llvm-svn: 297241
2017-03-08 07:20:35 +08:00
|
|
|
LLT Ty = getLLTForType(*CI.getOperand(0)->getType(), *DL);
|
2016-12-09 06:44:00 +08:00
|
|
|
LLT s1 = LLT::scalar(1);
|
|
|
|
unsigned Width = Ty.getSizeInBits();
|
|
|
|
unsigned Res = MRI->createGenericVirtualRegister(Ty);
|
|
|
|
unsigned Overflow = MRI->createGenericVirtualRegister(s1);
|
|
|
|
auto MIB = MIRBuilder.buildInstr(Op)
|
|
|
|
.addDef(Res)
|
|
|
|
.addDef(Overflow)
|
|
|
|
.addUse(getOrCreateVReg(*CI.getOperand(0)))
|
|
|
|
.addUse(getOrCreateVReg(*CI.getOperand(1)));
|
|
|
|
|
|
|
|
if (Op == TargetOpcode::G_UADDE || Op == TargetOpcode::G_USUBE) {
|
|
|
|
unsigned Zero = MRI->createGenericVirtualRegister(s1);
|
|
|
|
EntryBuilder.buildConstant(Zero, 0);
|
|
|
|
MIB.addUse(Zero);
|
|
|
|
}
|
|
|
|
|
|
|
|
MIRBuilder.buildSequence(getOrCreateVReg(CI), Res, 0, Overflow, Width);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-12-08 05:29:15 +08:00
|
|
|
bool IRTranslator::translateKnownIntrinsic(const CallInst &CI, Intrinsic::ID ID,
|
|
|
|
MachineIRBuilder &MIRBuilder) {
|
2016-08-20 01:17:06 +08:00
|
|
|
switch (ID) {
|
2016-12-09 06:44:00 +08:00
|
|
|
default:
|
|
|
|
break;
|
2017-02-11 03:10:38 +08:00
|
|
|
case Intrinsic::lifetime_start:
|
|
|
|
case Intrinsic::lifetime_end:
|
|
|
|
// Stack coloring is not enabled in O0 (which we care about now) so we can
|
|
|
|
// drop these. Make sure someone notices when we start compiling at higher
|
|
|
|
// opts though.
|
|
|
|
if (MF->getTarget().getOptLevel() != CodeGenOpt::None)
|
|
|
|
return false;
|
|
|
|
return true;
|
2017-01-27 07:39:14 +08:00
|
|
|
case Intrinsic::dbg_declare: {
|
|
|
|
const DbgDeclareInst &DI = cast<DbgDeclareInst>(CI);
|
|
|
|
assert(DI.getVariable() && "Missing variable");
|
|
|
|
|
|
|
|
const Value *Address = DI.getAddress();
|
|
|
|
if (!Address || isa<UndefValue>(Address)) {
|
|
|
|
DEBUG(dbgs() << "Dropping debug info for " << DI << "\n");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(DI.getVariable()->isValidLocationForIntrinsic(
|
|
|
|
MIRBuilder.getDebugLoc()) &&
|
|
|
|
"Expected inlined-at fields to agree");
|
2017-03-10 05:12:06 +08:00
|
|
|
auto AI = dyn_cast<AllocaInst>(Address);
|
|
|
|
if (AI && AI->isStaticAlloca()) {
|
|
|
|
// Static allocas are tracked at the MF level, no need for DBG_VALUE
|
|
|
|
// instructions (in fact, they get ignored if they *do* exist).
|
|
|
|
MF->setVariableDbgInfo(DI.getVariable(), DI.getExpression(),
|
|
|
|
getOrCreateFrameIndex(*AI), DI.getDebugLoc());
|
2017-01-27 07:39:14 +08:00
|
|
|
} else
|
2017-03-10 05:12:06 +08:00
|
|
|
MIRBuilder.buildDirectDbgValue(getOrCreateVReg(*Address),
|
|
|
|
DI.getVariable(), DI.getExpression());
|
2016-12-09 06:44:13 +08:00
|
|
|
return true;
|
2017-01-27 07:39:14 +08:00
|
|
|
}
|
2017-02-08 04:08:59 +08:00
|
|
|
case Intrinsic::vaend:
|
|
|
|
// No target I know of cares about va_end. Certainly no in-tree target
|
|
|
|
// does. Simplest intrinsic ever!
|
|
|
|
return true;
|
2017-02-09 01:57:20 +08:00
|
|
|
case Intrinsic::vastart: {
|
|
|
|
auto &TLI = *MF->getSubtarget().getTargetLowering();
|
|
|
|
Value *Ptr = CI.getArgOperand(0);
|
|
|
|
unsigned ListSize = TLI.getVaListSizeInBits(*DL) / 8;
|
|
|
|
|
|
|
|
MIRBuilder.buildInstr(TargetOpcode::G_VASTART)
|
|
|
|
.addUse(getOrCreateVReg(*Ptr))
|
|
|
|
.addMemOperand(MF->getMachineMemOperand(
|
|
|
|
MachinePointerInfo(Ptr), MachineMemOperand::MOStore, ListSize, 0));
|
|
|
|
return true;
|
|
|
|
}
|
2017-01-27 07:39:14 +08:00
|
|
|
case Intrinsic::dbg_value: {
|
|
|
|
// This form of DBG_VALUE is target-independent.
|
|
|
|
const DbgValueInst &DI = cast<DbgValueInst>(CI);
|
|
|
|
const Value *V = DI.getValue();
|
|
|
|
assert(DI.getVariable()->isValidLocationForIntrinsic(
|
|
|
|
MIRBuilder.getDebugLoc()) &&
|
|
|
|
"Expected inlined-at fields to agree");
|
|
|
|
if (!V) {
|
|
|
|
// Currently the optimizer can produce this; insert an undef to
|
|
|
|
// help debugging. Probably the optimizer should not do this.
|
|
|
|
MIRBuilder.buildIndirectDbgValue(0, DI.getOffset(), DI.getVariable(),
|
|
|
|
DI.getExpression());
|
|
|
|
} else if (const auto *CI = dyn_cast<Constant>(V)) {
|
|
|
|
MIRBuilder.buildConstDbgValue(*CI, DI.getOffset(), DI.getVariable(),
|
|
|
|
DI.getExpression());
|
|
|
|
} else {
|
|
|
|
unsigned Reg = getOrCreateVReg(*V);
|
|
|
|
// FIXME: This does not handle register-indirect values at offset 0. The
|
|
|
|
// direct/indirect thing shouldn't really be handled by something as
|
|
|
|
// implicit as reg+noreg vs reg+imm in the first palce, but it seems
|
|
|
|
// pretty baked in right now.
|
|
|
|
if (DI.getOffset() != 0)
|
|
|
|
MIRBuilder.buildIndirectDbgValue(Reg, DI.getOffset(), DI.getVariable(),
|
|
|
|
DI.getExpression());
|
|
|
|
else
|
|
|
|
MIRBuilder.buildDirectDbgValue(Reg, DI.getVariable(),
|
|
|
|
DI.getExpression());
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2016-12-09 06:44:00 +08:00
|
|
|
case Intrinsic::uadd_with_overflow:
|
|
|
|
return translateOverflowIntrinsic(CI, TargetOpcode::G_UADDE, MIRBuilder);
|
|
|
|
case Intrinsic::sadd_with_overflow:
|
|
|
|
return translateOverflowIntrinsic(CI, TargetOpcode::G_SADDO, MIRBuilder);
|
|
|
|
case Intrinsic::usub_with_overflow:
|
|
|
|
return translateOverflowIntrinsic(CI, TargetOpcode::G_USUBE, MIRBuilder);
|
|
|
|
case Intrinsic::ssub_with_overflow:
|
|
|
|
return translateOverflowIntrinsic(CI, TargetOpcode::G_SSUBO, MIRBuilder);
|
|
|
|
case Intrinsic::umul_with_overflow:
|
|
|
|
return translateOverflowIntrinsic(CI, TargetOpcode::G_UMULO, MIRBuilder);
|
|
|
|
case Intrinsic::smul_with_overflow:
|
|
|
|
return translateOverflowIntrinsic(CI, TargetOpcode::G_SMULO, MIRBuilder);
|
2017-02-09 07:23:32 +08:00
|
|
|
case Intrinsic::pow:
|
|
|
|
MIRBuilder.buildInstr(TargetOpcode::G_FPOW)
|
|
|
|
.addDef(getOrCreateVReg(CI))
|
|
|
|
.addUse(getOrCreateVReg(*CI.getArgOperand(0)))
|
|
|
|
.addUse(getOrCreateVReg(*CI.getArgOperand(1)));
|
|
|
|
return true;
|
2016-10-19 04:03:45 +08:00
|
|
|
case Intrinsic::memcpy:
|
2017-01-31 03:33:07 +08:00
|
|
|
case Intrinsic::memmove:
|
|
|
|
case Intrinsic::memset:
|
|
|
|
return translateMemfunc(CI, MIRBuilder, ID);
|
2016-11-10 06:39:54 +08:00
|
|
|
case Intrinsic::eh_typeid_for: {
|
|
|
|
GlobalValue *GV = ExtractTypeInfo(CI.getArgOperand(0));
|
|
|
|
unsigned Reg = getOrCreateVReg(CI);
|
2016-12-08 05:17:47 +08:00
|
|
|
unsigned TypeID = MF->getTypeIDFor(GV);
|
2016-11-10 06:39:54 +08:00
|
|
|
MIRBuilder.buildConstant(Reg, TypeID);
|
|
|
|
return true;
|
|
|
|
}
|
2016-10-19 04:03:51 +08:00
|
|
|
case Intrinsic::objectsize: {
|
|
|
|
// If we don't know by now, we're never going to know.
|
|
|
|
const ConstantInt *Min = cast<ConstantInt>(CI.getArgOperand(1));
|
|
|
|
|
|
|
|
MIRBuilder.buildConstant(getOrCreateVReg(CI), Min->isZero() ? -1ULL : 0);
|
|
|
|
return true;
|
|
|
|
}
|
2016-11-01 02:30:59 +08:00
|
|
|
case Intrinsic::stackguard:
|
2016-12-08 05:29:15 +08:00
|
|
|
getStackGuard(getOrCreateVReg(CI), MIRBuilder);
|
2016-11-01 02:30:59 +08:00
|
|
|
return true;
|
|
|
|
case Intrinsic::stackprotector: {
|
Recommit: [globalisel] Change LLT constructor string into an LLT-based object that knows how to generate it.
Summary:
This will allow future patches to inspect the details of the LLT. The implementation is now split between
the Support and CodeGen libraries to allow TableGen to use this class without introducing layering concerns.
Thanks to Ahmed Bougacha for finding a reasonable way to avoid the layering issue and providing the version of this patch without that problem.
The problem with the previous commit appears to have been that TableGen was including CodeGen/LowLevelType.h instead of Support/LowLevelTypeImpl.h.
Reviewers: t.p.northover, qcolombet, rovka, aditya_nandakumar, ab, javed.absar
Subscribers: arsenm, nhaehnle, mgorny, dberris, llvm-commits, kristof.beyls
Differential Revision: https://reviews.llvm.org/D30046
llvm-svn: 297241
2017-03-08 07:20:35 +08:00
|
|
|
LLT PtrTy = getLLTForType(*CI.getArgOperand(0)->getType(), *DL);
|
2016-11-01 02:30:59 +08:00
|
|
|
unsigned GuardVal = MRI->createGenericVirtualRegister(PtrTy);
|
2016-12-08 05:29:15 +08:00
|
|
|
getStackGuard(GuardVal, MIRBuilder);
|
2016-11-01 02:30:59 +08:00
|
|
|
|
|
|
|
AllocaInst *Slot = cast<AllocaInst>(CI.getArgOperand(1));
|
|
|
|
MIRBuilder.buildStore(
|
|
|
|
GuardVal, getOrCreateVReg(*Slot),
|
2016-12-08 05:17:47 +08:00
|
|
|
*MF->getMachineMemOperand(
|
|
|
|
MachinePointerInfo::getFixedStack(*MF,
|
|
|
|
getOrCreateFrameIndex(*Slot)),
|
2016-11-01 02:30:59 +08:00
|
|
|
MachineMemOperand::MOStore | MachineMemOperand::MOVolatile,
|
|
|
|
PtrTy.getSizeInBits() / 8, 8));
|
|
|
|
return true;
|
|
|
|
}
|
2016-08-20 01:17:06 +08:00
|
|
|
}
|
2016-12-09 06:44:00 +08:00
|
|
|
return false;
|
2016-08-20 01:17:06 +08:00
|
|
|
}
|
|
|
|
|
2017-03-10 07:36:26 +08:00
|
|
|
bool IRTranslator::translateInlineAsm(const CallInst &CI,
|
|
|
|
MachineIRBuilder &MIRBuilder) {
|
|
|
|
const InlineAsm &IA = cast<InlineAsm>(*CI.getCalledValue());
|
|
|
|
if (!IA.getConstraintString().empty())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
unsigned ExtraInfo = 0;
|
|
|
|
if (IA.hasSideEffects())
|
|
|
|
ExtraInfo |= InlineAsm::Extra_HasSideEffects;
|
|
|
|
if (IA.getDialect() == InlineAsm::AD_Intel)
|
|
|
|
ExtraInfo |= InlineAsm::Extra_AsmDialect;
|
|
|
|
|
|
|
|
MIRBuilder.buildInstr(TargetOpcode::INLINEASM)
|
|
|
|
.addExternalSymbol(IA.getAsmString().c_str())
|
|
|
|
.addImm(ExtraInfo);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-12-08 05:29:15 +08:00
|
|
|
bool IRTranslator::translateCall(const User &U, MachineIRBuilder &MIRBuilder) {
|
2016-08-11 07:02:41 +08:00
|
|
|
const CallInst &CI = cast<CallInst>(U);
|
2016-12-08 05:17:47 +08:00
|
|
|
auto TII = MF->getTarget().getIntrinsicInfo();
|
2016-08-11 05:44:01 +08:00
|
|
|
const Function *F = CI.getCalledFunction();
|
|
|
|
|
2017-01-20 07:59:35 +08:00
|
|
|
if (CI.isInlineAsm())
|
2017-03-10 07:36:26 +08:00
|
|
|
return translateInlineAsm(CI, MIRBuilder);
|
2017-01-20 07:59:35 +08:00
|
|
|
|
2016-08-11 05:44:01 +08:00
|
|
|
if (!F || !F->isIntrinsic()) {
|
|
|
|
unsigned Res = CI.getType()->isVoidTy() ? 0 : getOrCreateVReg(CI);
|
|
|
|
SmallVector<unsigned, 8> Args;
|
|
|
|
for (auto &Arg: CI.arg_operands())
|
|
|
|
Args.push_back(getOrCreateVReg(*Arg));
|
|
|
|
|
2017-03-10 06:00:39 +08:00
|
|
|
MF->getFrameInfo().setHasCalls(true);
|
2017-03-10 08:25:44 +08:00
|
|
|
return CLI->lowerCall(MIRBuilder, &CI, Res, Args, [&]() {
|
2016-08-30 03:07:08 +08:00
|
|
|
return getOrCreateVReg(*CI.getCalledValue());
|
|
|
|
});
|
2016-08-11 05:44:01 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
Intrinsic::ID ID = F->getIntrinsicID();
|
2016-07-30 06:32:36 +08:00
|
|
|
if (TII && ID == Intrinsic::not_intrinsic)
|
2016-08-11 05:44:01 +08:00
|
|
|
ID = static_cast<Intrinsic::ID>(TII->getIntrinsicID(F));
|
2016-07-30 06:32:36 +08:00
|
|
|
|
2016-08-11 05:44:01 +08:00
|
|
|
assert(ID != Intrinsic::not_intrinsic && "unknown intrinsic");
|
2016-07-30 06:32:36 +08:00
|
|
|
|
2016-12-08 05:29:15 +08:00
|
|
|
if (translateKnownIntrinsic(CI, ID, MIRBuilder))
|
2016-08-20 01:17:06 +08:00
|
|
|
return true;
|
|
|
|
|
2016-07-30 06:32:36 +08:00
|
|
|
unsigned Res = CI.getType()->isVoidTy() ? 0 : getOrCreateVReg(CI);
|
|
|
|
MachineInstrBuilder MIB =
|
2016-09-09 19:46:34 +08:00
|
|
|
MIRBuilder.buildIntrinsic(ID, Res, !CI.doesNotAccessMemory());
|
2016-07-30 06:32:36 +08:00
|
|
|
|
|
|
|
for (auto &Arg : CI.arg_operands()) {
|
2017-03-08 04:53:09 +08:00
|
|
|
// Some intrinsics take metadata parameters. Reject them.
|
|
|
|
if (isa<MetadataAsValue>(Arg))
|
|
|
|
return false;
|
2016-07-30 06:32:36 +08:00
|
|
|
if (ConstantInt *CI = dyn_cast<ConstantInt>(Arg))
|
|
|
|
MIB.addImm(CI->getSExtValue());
|
|
|
|
else
|
|
|
|
MIB.addUse(getOrCreateVReg(*Arg));
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-12-08 05:29:15 +08:00
|
|
|
bool IRTranslator::translateInvoke(const User &U,
|
|
|
|
MachineIRBuilder &MIRBuilder) {
|
2016-11-10 06:39:54 +08:00
|
|
|
const InvokeInst &I = cast<InvokeInst>(U);
|
2016-12-08 05:17:47 +08:00
|
|
|
MCContext &Context = MF->getContext();
|
2016-11-10 06:39:54 +08:00
|
|
|
|
|
|
|
const BasicBlock *ReturnBB = I.getSuccessor(0);
|
|
|
|
const BasicBlock *EHPadBB = I.getSuccessor(1);
|
|
|
|
|
2017-03-10 08:25:35 +08:00
|
|
|
const Value *Callee = I.getCalledValue();
|
2016-11-10 06:39:54 +08:00
|
|
|
const Function *Fn = dyn_cast<Function>(Callee);
|
|
|
|
if (isa<InlineAsm>(Callee))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// FIXME: support invoking patchpoint and statepoint intrinsics.
|
|
|
|
if (Fn && Fn->isIntrinsic())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// FIXME: support whatever these are.
|
|
|
|
if (I.countOperandBundlesOfType(LLVMContext::OB_deopt))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// FIXME: support Windows exception handling.
|
|
|
|
if (!isa<LandingPadInst>(EHPadBB->front()))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
2016-12-02 03:32:15 +08:00
|
|
|
// Emit the actual call, bracketed by EH_LABELs so that the MF knows about
|
2016-11-10 06:39:54 +08:00
|
|
|
// the region covered by the try.
|
2016-12-02 03:32:15 +08:00
|
|
|
MCSymbol *BeginSymbol = Context.createTempSymbol();
|
2016-11-10 06:39:54 +08:00
|
|
|
MIRBuilder.buildInstr(TargetOpcode::EH_LABEL).addSym(BeginSymbol);
|
|
|
|
|
|
|
|
unsigned Res = I.getType()->isVoidTy() ? 0 : getOrCreateVReg(I);
|
2017-02-01 02:36:11 +08:00
|
|
|
SmallVector<unsigned, 8> Args;
|
2016-11-10 06:39:54 +08:00
|
|
|
for (auto &Arg: I.arg_operands())
|
2017-02-01 02:36:11 +08:00
|
|
|
Args.push_back(getOrCreateVReg(*Arg));
|
2016-11-10 06:39:54 +08:00
|
|
|
|
2017-03-10 08:25:44 +08:00
|
|
|
if (!CLI->lowerCall(MIRBuilder, &I, Res, Args,
|
2017-03-10 08:25:35 +08:00
|
|
|
[&]() { return getOrCreateVReg(*I.getCalledValue()); }))
|
|
|
|
return false;
|
2016-11-10 06:39:54 +08:00
|
|
|
|
2016-12-02 03:32:15 +08:00
|
|
|
MCSymbol *EndSymbol = Context.createTempSymbol();
|
2016-11-10 06:39:54 +08:00
|
|
|
MIRBuilder.buildInstr(TargetOpcode::EH_LABEL).addSym(EndSymbol);
|
|
|
|
|
|
|
|
// FIXME: track probabilities.
|
|
|
|
MachineBasicBlock &EHPadMBB = getOrCreateBB(*EHPadBB),
|
|
|
|
&ReturnMBB = getOrCreateBB(*ReturnBB);
|
2016-12-08 05:17:47 +08:00
|
|
|
MF->addInvoke(&EHPadMBB, BeginSymbol, EndSymbol);
|
2016-11-10 06:39:54 +08:00
|
|
|
MIRBuilder.getMBB().addSuccessor(&ReturnMBB);
|
|
|
|
MIRBuilder.getMBB().addSuccessor(&EHPadMBB);
|
2017-02-01 04:12:18 +08:00
|
|
|
MIRBuilder.buildBr(ReturnMBB);
|
2016-11-10 06:39:54 +08:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-12-08 05:29:15 +08:00
|
|
|
bool IRTranslator::translateLandingPad(const User &U,
|
|
|
|
MachineIRBuilder &MIRBuilder) {
|
2016-11-10 06:39:54 +08:00
|
|
|
const LandingPadInst &LP = cast<LandingPadInst>(U);
|
|
|
|
|
|
|
|
MachineBasicBlock &MBB = MIRBuilder.getMBB();
|
2016-12-02 03:32:15 +08:00
|
|
|
addLandingPadInfo(LP, MBB);
|
2016-11-10 06:39:54 +08:00
|
|
|
|
|
|
|
MBB.setIsEHPad();
|
|
|
|
|
|
|
|
// If there aren't registers to copy the values into (e.g., during SjLj
|
|
|
|
// exceptions), then don't bother.
|
2016-12-08 05:17:47 +08:00
|
|
|
auto &TLI = *MF->getSubtarget().getTargetLowering();
|
|
|
|
const Constant *PersonalityFn = MF->getFunction()->getPersonalityFn();
|
2016-11-10 06:39:54 +08:00
|
|
|
if (TLI.getExceptionPointerRegister(PersonalityFn) == 0 &&
|
|
|
|
TLI.getExceptionSelectorRegister(PersonalityFn) == 0)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// If landingpad's return type is token type, we don't create DAG nodes
|
|
|
|
// for its exception pointer and selector value. The extraction of exception
|
|
|
|
// pointer or selector value from token type landingpads is not currently
|
|
|
|
// supported.
|
|
|
|
if (LP.getType()->isTokenTy())
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// Add a label to mark the beginning of the landing pad. Deletion of the
|
|
|
|
// landing pad can thus be detected via the MachineModuleInfo.
|
|
|
|
MIRBuilder.buildInstr(TargetOpcode::EH_LABEL)
|
2016-12-08 05:17:47 +08:00
|
|
|
.addSym(MF->addLandingPad(&MBB));
|
2016-11-10 06:39:54 +08:00
|
|
|
|
2017-03-08 07:32:10 +08:00
|
|
|
LLT Ty = getLLTForType(*LP.getType(), *DL);
|
2017-03-08 07:04:06 +08:00
|
|
|
unsigned Undef = MRI->createGenericVirtualRegister(Ty);
|
|
|
|
MIRBuilder.buildUndef(Undef);
|
|
|
|
|
2017-01-25 08:16:53 +08:00
|
|
|
SmallVector<LLT, 2> Tys;
|
|
|
|
for (Type *Ty : cast<StructType>(LP.getType())->elements())
|
Recommit: [globalisel] Change LLT constructor string into an LLT-based object that knows how to generate it.
Summary:
This will allow future patches to inspect the details of the LLT. The implementation is now split between
the Support and CodeGen libraries to allow TableGen to use this class without introducing layering concerns.
Thanks to Ahmed Bougacha for finding a reasonable way to avoid the layering issue and providing the version of this patch without that problem.
The problem with the previous commit appears to have been that TableGen was including CodeGen/LowLevelType.h instead of Support/LowLevelTypeImpl.h.
Reviewers: t.p.northover, qcolombet, rovka, aditya_nandakumar, ab, javed.absar
Subscribers: arsenm, nhaehnle, mgorny, dberris, llvm-commits, kristof.beyls
Differential Revision: https://reviews.llvm.org/D30046
llvm-svn: 297241
2017-03-08 07:20:35 +08:00
|
|
|
Tys.push_back(getLLTForType(*Ty, *DL));
|
2017-01-25 08:16:53 +08:00
|
|
|
assert(Tys.size() == 2 && "Only two-valued landingpads are supported");
|
|
|
|
|
2016-11-10 06:39:54 +08:00
|
|
|
// Mark exception register as live in.
|
2017-03-08 07:04:06 +08:00
|
|
|
unsigned ExceptionReg = TLI.getExceptionPointerRegister(PersonalityFn);
|
|
|
|
if (!ExceptionReg)
|
|
|
|
return false;
|
2016-11-10 06:39:54 +08:00
|
|
|
|
2017-03-08 07:04:06 +08:00
|
|
|
MBB.addLiveIn(ExceptionReg);
|
|
|
|
unsigned VReg = MRI->createGenericVirtualRegister(Tys[0]),
|
|
|
|
Tmp = MRI->createGenericVirtualRegister(Ty);
|
|
|
|
MIRBuilder.buildCopy(VReg, ExceptionReg);
|
|
|
|
MIRBuilder.buildInsert(Tmp, Undef, VReg, 0);
|
|
|
|
|
|
|
|
unsigned SelectorReg = TLI.getExceptionSelectorRegister(PersonalityFn);
|
|
|
|
if (!SelectorReg)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
MBB.addLiveIn(SelectorReg);
|
|
|
|
|
|
|
|
// N.b. the exception selector register always has pointer type and may not
|
|
|
|
// match the actual IR-level type in the landingpad so an extra cast is
|
|
|
|
// needed.
|
|
|
|
unsigned PtrVReg = MRI->createGenericVirtualRegister(Tys[0]);
|
|
|
|
MIRBuilder.buildCopy(PtrVReg, SelectorReg);
|
2016-11-10 06:39:54 +08:00
|
|
|
|
2017-03-08 07:04:06 +08:00
|
|
|
VReg = MRI->createGenericVirtualRegister(Tys[1]);
|
|
|
|
MIRBuilder.buildInstr(TargetOpcode::G_PTRTOINT).addDef(VReg).addUse(PtrVReg);
|
|
|
|
MIRBuilder.buildInsert(getOrCreateVReg(LP), Tmp, VReg,
|
|
|
|
Tys[0].getSizeInBits());
|
2016-11-10 06:39:54 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-02-04 02:22:45 +08:00
|
|
|
bool IRTranslator::translateAlloca(const User &U,
|
|
|
|
MachineIRBuilder &MIRBuilder) {
|
|
|
|
auto &AI = cast<AllocaInst>(U);
|
|
|
|
|
|
|
|
if (AI.isStaticAlloca()) {
|
|
|
|
unsigned Res = getOrCreateVReg(AI);
|
|
|
|
int FI = getOrCreateFrameIndex(AI);
|
|
|
|
MIRBuilder.buildFrameIndex(Res, FI);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now we're in the harder dynamic case.
|
|
|
|
Type *Ty = AI.getAllocatedType();
|
|
|
|
unsigned Align =
|
|
|
|
std::max((unsigned)DL->getPrefTypeAlignment(Ty), AI.getAlignment());
|
|
|
|
|
|
|
|
unsigned NumElts = getOrCreateVReg(*AI.getArraySize());
|
|
|
|
|
|
|
|
LLT IntPtrTy = LLT::scalar(DL->getPointerSizeInBits());
|
|
|
|
if (MRI->getType(NumElts) != IntPtrTy) {
|
|
|
|
unsigned ExtElts = MRI->createGenericVirtualRegister(IntPtrTy);
|
|
|
|
MIRBuilder.buildZExtOrTrunc(ExtElts, NumElts);
|
|
|
|
NumElts = ExtElts;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned AllocSize = MRI->createGenericVirtualRegister(IntPtrTy);
|
|
|
|
unsigned TySize = MRI->createGenericVirtualRegister(IntPtrTy);
|
2017-02-15 04:56:18 +08:00
|
|
|
MIRBuilder.buildConstant(TySize, -DL->getTypeAllocSize(Ty));
|
2017-02-04 02:22:45 +08:00
|
|
|
MIRBuilder.buildMul(AllocSize, NumElts, TySize);
|
|
|
|
|
Recommit: [globalisel] Change LLT constructor string into an LLT-based object that knows how to generate it.
Summary:
This will allow future patches to inspect the details of the LLT. The implementation is now split between
the Support and CodeGen libraries to allow TableGen to use this class without introducing layering concerns.
Thanks to Ahmed Bougacha for finding a reasonable way to avoid the layering issue and providing the version of this patch without that problem.
The problem with the previous commit appears to have been that TableGen was including CodeGen/LowLevelType.h instead of Support/LowLevelTypeImpl.h.
Reviewers: t.p.northover, qcolombet, rovka, aditya_nandakumar, ab, javed.absar
Subscribers: arsenm, nhaehnle, mgorny, dberris, llvm-commits, kristof.beyls
Differential Revision: https://reviews.llvm.org/D30046
llvm-svn: 297241
2017-03-08 07:20:35 +08:00
|
|
|
LLT PtrTy = getLLTForType(*AI.getType(), *DL);
|
2017-02-04 02:22:45 +08:00
|
|
|
auto &TLI = *MF->getSubtarget().getTargetLowering();
|
|
|
|
unsigned SPReg = TLI.getStackPointerRegisterToSaveRestore();
|
|
|
|
|
|
|
|
unsigned SPTmp = MRI->createGenericVirtualRegister(PtrTy);
|
|
|
|
MIRBuilder.buildCopy(SPTmp, SPReg);
|
|
|
|
|
2017-02-15 04:56:18 +08:00
|
|
|
unsigned AllocTmp = MRI->createGenericVirtualRegister(PtrTy);
|
|
|
|
MIRBuilder.buildGEP(AllocTmp, SPTmp, AllocSize);
|
2017-02-04 02:22:45 +08:00
|
|
|
|
|
|
|
// Handle alignment. We have to realign if the allocation granule was smaller
|
|
|
|
// than stack alignment, or the specific alloca requires more than stack
|
|
|
|
// alignment.
|
|
|
|
unsigned StackAlign =
|
|
|
|
MF->getSubtarget().getFrameLowering()->getStackAlignment();
|
|
|
|
Align = std::max(Align, StackAlign);
|
|
|
|
if (Align > StackAlign || DL->getTypeAllocSize(Ty) % StackAlign != 0) {
|
|
|
|
// Round the size of the allocation up to the stack alignment size
|
|
|
|
// by add SA-1 to the size. This doesn't overflow because we're computing
|
|
|
|
// an address inside an alloca.
|
2017-02-15 04:56:18 +08:00
|
|
|
unsigned AlignedAlloc = MRI->createGenericVirtualRegister(PtrTy);
|
|
|
|
MIRBuilder.buildPtrMask(AlignedAlloc, AllocTmp, Log2_32(Align));
|
|
|
|
AllocTmp = AlignedAlloc;
|
2017-02-04 02:22:45 +08:00
|
|
|
}
|
|
|
|
|
2017-02-15 04:56:18 +08:00
|
|
|
MIRBuilder.buildCopy(SPReg, AllocTmp);
|
|
|
|
MIRBuilder.buildCopy(getOrCreateVReg(AI), AllocTmp);
|
2016-08-27 07:49:05 +08:00
|
|
|
|
2017-02-04 02:22:45 +08:00
|
|
|
MF->getFrameInfo().CreateVariableSizedObject(Align ? Align : 1, &AI);
|
|
|
|
assert(MF->getFrameInfo().hasVarSizedObjects());
|
2016-07-23 00:59:52 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-02-16 07:22:33 +08:00
|
|
|
bool IRTranslator::translateVAArg(const User &U, MachineIRBuilder &MIRBuilder) {
|
|
|
|
// FIXME: We may need more info about the type. Because of how LLT works,
|
|
|
|
// we're completely discarding the i64/double distinction here (amongst
|
|
|
|
// others). Fortunately the ABIs I know of where that matters don't use va_arg
|
|
|
|
// anyway but that's not guaranteed.
|
|
|
|
MIRBuilder.buildInstr(TargetOpcode::G_VAARG)
|
|
|
|
.addDef(getOrCreateVReg(U))
|
|
|
|
.addUse(getOrCreateVReg(*U.getOperand(0)))
|
|
|
|
.addImm(DL->getABITypeAlignment(U.getType()));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-03-11 03:08:28 +08:00
|
|
|
bool IRTranslator::translateInsertElement(const User &U,
|
|
|
|
MachineIRBuilder &MIRBuilder) {
|
|
|
|
// If it is a <1 x Ty> vector, use the scalar as it is
|
|
|
|
// not a legal vector type in LLT.
|
|
|
|
if (U.getType()->getVectorNumElements() == 1) {
|
|
|
|
unsigned Elt = getOrCreateVReg(*U.getOperand(1));
|
|
|
|
ValToVReg[&U] = Elt;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
MIRBuilder.buildInsertVectorElement(
|
|
|
|
getOrCreateVReg(U), getOrCreateVReg(*U.getOperand(0)),
|
|
|
|
getOrCreateVReg(*U.getOperand(1)), getOrCreateVReg(*U.getOperand(2)));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IRTranslator::translateExtractElement(const User &U,
|
|
|
|
MachineIRBuilder &MIRBuilder) {
|
|
|
|
// If it is a <1 x Ty> vector, use the scalar as it is
|
|
|
|
// not a legal vector type in LLT.
|
|
|
|
if (U.getOperand(0)->getType()->getVectorNumElements() == 1) {
|
|
|
|
unsigned Elt = getOrCreateVReg(*U.getOperand(0));
|
|
|
|
ValToVReg[&U] = Elt;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
MIRBuilder.buildExtractVectorElement(getOrCreateVReg(U),
|
|
|
|
getOrCreateVReg(*U.getOperand(0)),
|
|
|
|
getOrCreateVReg(*U.getOperand(1)));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-12-08 05:29:15 +08:00
|
|
|
bool IRTranslator::translatePHI(const User &U, MachineIRBuilder &MIRBuilder) {
|
2016-08-11 07:02:41 +08:00
|
|
|
const PHINode &PI = cast<PHINode>(U);
|
2016-09-09 19:47:31 +08:00
|
|
|
auto MIB = MIRBuilder.buildInstr(TargetOpcode::PHI);
|
2016-08-06 01:16:40 +08:00
|
|
|
MIB.addDef(getOrCreateVReg(PI));
|
|
|
|
|
|
|
|
PendingPHIs.emplace_back(&PI, MIB.getInstr());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void IRTranslator::finishPendingPhis() {
|
|
|
|
for (std::pair<const PHINode *, MachineInstr *> &Phi : PendingPHIs) {
|
|
|
|
const PHINode *PI = Phi.first;
|
2016-12-08 05:29:15 +08:00
|
|
|
MachineInstrBuilder MIB(*MF, Phi.second);
|
2016-08-06 01:16:40 +08:00
|
|
|
|
|
|
|
// All MachineBasicBlocks exist, add them to the PHI. We assume IRTranslator
|
|
|
|
// won't create extra control flow here, otherwise we need to find the
|
|
|
|
// dominating predecessor here (or perhaps force the weirder IRTranslators
|
|
|
|
// to provide a simple boundary).
|
2017-01-18 06:13:50 +08:00
|
|
|
SmallSet<const BasicBlock *, 4> HandledPreds;
|
|
|
|
|
2016-08-06 01:16:40 +08:00
|
|
|
for (unsigned i = 0; i < PI->getNumIncomingValues(); ++i) {
|
2017-01-18 06:13:50 +08:00
|
|
|
auto IRPred = PI->getIncomingBlock(i);
|
|
|
|
if (HandledPreds.count(IRPred))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
HandledPreds.insert(IRPred);
|
|
|
|
unsigned ValReg = getOrCreateVReg(*PI->getIncomingValue(i));
|
|
|
|
for (auto Pred : getMachinePredBBs({IRPred, PI->getParent()})) {
|
|
|
|
assert(Pred->isSuccessor(MIB->getParent()) &&
|
|
|
|
"incorrect CFG at MachineBasicBlock level");
|
|
|
|
MIB.addUse(ValReg);
|
|
|
|
MIB.addMBB(Pred);
|
|
|
|
}
|
2016-08-06 01:16:40 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-11 06:59:27 +08:00
|
|
|
bool IRTranslator::translate(const Instruction &Inst) {
|
2016-12-08 05:29:15 +08:00
|
|
|
CurBuilder.setDebugLoc(Inst.getDebugLoc());
|
2016-02-11 06:59:27 +08:00
|
|
|
switch(Inst.getOpcode()) {
|
2016-08-11 07:02:41 +08:00
|
|
|
#define HANDLE_INST(NUM, OPCODE, CLASS) \
|
2016-12-08 05:29:15 +08:00
|
|
|
case Instruction::OPCODE: return translate##OPCODE(Inst, CurBuilder);
|
2016-08-11 07:02:41 +08:00
|
|
|
#include "llvm/IR/Instruction.def"
|
2016-02-12 02:53:28 +08:00
|
|
|
default:
|
2017-03-11 08:28:33 +08:00
|
|
|
return false;
|
2016-02-11 06:59:27 +08:00
|
|
|
}
|
2016-01-21 04:58:56 +08:00
|
|
|
}
|
|
|
|
|
2016-08-10 05:28:04 +08:00
|
|
|
bool IRTranslator::translate(const Constant &C, unsigned Reg) {
|
2016-08-10 07:01:30 +08:00
|
|
|
if (auto CI = dyn_cast<ConstantInt>(&C))
|
2016-12-06 05:54:17 +08:00
|
|
|
EntryBuilder.buildConstant(Reg, *CI);
|
2016-08-20 04:09:15 +08:00
|
|
|
else if (auto CF = dyn_cast<ConstantFP>(&C))
|
2016-09-09 19:46:34 +08:00
|
|
|
EntryBuilder.buildFConstant(Reg, *CF);
|
2016-08-10 07:01:30 +08:00
|
|
|
else if (isa<UndefValue>(C))
|
2017-03-07 02:36:40 +08:00
|
|
|
EntryBuilder.buildUndef(Reg);
|
2016-08-12 05:40:55 +08:00
|
|
|
else if (isa<ConstantPointerNull>(C))
|
2016-12-06 05:47:07 +08:00
|
|
|
EntryBuilder.buildConstant(Reg, 0);
|
2016-09-12 20:10:41 +08:00
|
|
|
else if (auto GV = dyn_cast<GlobalValue>(&C))
|
|
|
|
EntryBuilder.buildGlobalValue(Reg, GV);
|
2017-03-11 05:23:13 +08:00
|
|
|
else if (auto CAZ = dyn_cast<ConstantAggregateZero>(&C)) {
|
|
|
|
if (!CAZ->getType()->isVectorTy())
|
|
|
|
return false;
|
2017-03-15 07:45:06 +08:00
|
|
|
// Return the scalar if it is a <1 x Ty> vector.
|
|
|
|
if (CAZ->getNumElements() == 1)
|
|
|
|
return translate(*CAZ->getElementValue(0u), Reg);
|
2017-03-11 05:23:13 +08:00
|
|
|
std::vector<unsigned> Ops;
|
|
|
|
for (unsigned i = 0; i < CAZ->getNumElements(); ++i) {
|
|
|
|
Constant &Elt = *CAZ->getElementValue(i);
|
|
|
|
Ops.push_back(getOrCreateVReg(Elt));
|
|
|
|
}
|
|
|
|
EntryBuilder.buildMerge(Reg, Ops);
|
GlobalISel: Translate ConstantDataVector
Reviewers: qcolombet, aditya_nandakumar, dsanders, t.p.northover, javed.absar, ab
Reviewed By: qcolombet, dsanders, ab
Subscribers: dberris, rovka, llvm-commits, kristof.beyls
Differential Revision: https://reviews.llvm.org/D30216
llvm-svn: 297670
2017-03-14 05:36:19 +08:00
|
|
|
} else if (auto CV = dyn_cast<ConstantDataVector>(&C)) {
|
2017-03-15 07:45:06 +08:00
|
|
|
// Return the scalar if it is a <1 x Ty> vector.
|
|
|
|
if (CV->getNumElements() == 1)
|
|
|
|
return translate(*CV->getElementAsConstant(0), Reg);
|
GlobalISel: Translate ConstantDataVector
Reviewers: qcolombet, aditya_nandakumar, dsanders, t.p.northover, javed.absar, ab
Reviewed By: qcolombet, dsanders, ab
Subscribers: dberris, rovka, llvm-commits, kristof.beyls
Differential Revision: https://reviews.llvm.org/D30216
llvm-svn: 297670
2017-03-14 05:36:19 +08:00
|
|
|
std::vector<unsigned> Ops;
|
|
|
|
for (unsigned i = 0; i < CV->getNumElements(); ++i) {
|
|
|
|
Constant &Elt = *CV->getElementAsConstant(i);
|
|
|
|
Ops.push_back(getOrCreateVReg(Elt));
|
|
|
|
}
|
|
|
|
EntryBuilder.buildMerge(Reg, Ops);
|
2017-03-11 05:23:13 +08:00
|
|
|
} else if (auto CE = dyn_cast<ConstantExpr>(&C)) {
|
2016-08-11 07:02:41 +08:00
|
|
|
switch(CE->getOpcode()) {
|
|
|
|
#define HANDLE_INST(NUM, OPCODE, CLASS) \
|
2016-12-08 05:29:15 +08:00
|
|
|
case Instruction::OPCODE: return translate##OPCODE(*CE, EntryBuilder);
|
2016-08-11 07:02:41 +08:00
|
|
|
#include "llvm/IR/Instruction.def"
|
|
|
|
default:
|
2017-03-11 08:28:33 +08:00
|
|
|
return false;
|
2016-08-11 07:02:41 +08:00
|
|
|
}
|
2017-03-11 08:28:33 +08:00
|
|
|
} else
|
2016-08-27 07:49:05 +08:00
|
|
|
return false;
|
2016-08-10 05:28:04 +08:00
|
|
|
|
2016-08-10 07:01:30 +08:00
|
|
|
return true;
|
2016-08-10 05:28:04 +08:00
|
|
|
}
|
|
|
|
|
2016-08-12 00:21:29 +08:00
|
|
|
void IRTranslator::finalizeFunction() {
|
2016-02-11 06:59:27 +08:00
|
|
|
// Release the memory used by the different maps we
|
|
|
|
// needed during the translation.
|
2016-12-06 07:10:19 +08:00
|
|
|
PendingPHIs.clear();
|
2016-02-12 05:48:32 +08:00
|
|
|
ValToVReg.clear();
|
2016-11-01 02:30:59 +08:00
|
|
|
FrameIndices.clear();
|
2017-01-18 06:13:50 +08:00
|
|
|
MachinePreds.clear();
|
2016-01-21 04:58:56 +08:00
|
|
|
}
|
|
|
|
|
2016-12-08 05:17:47 +08:00
|
|
|
bool IRTranslator::runOnMachineFunction(MachineFunction &CurMF) {
|
|
|
|
MF = &CurMF;
|
|
|
|
const Function &F = *MF->getFunction();
|
2016-02-12 03:59:41 +08:00
|
|
|
if (F.empty())
|
|
|
|
return false;
|
2016-12-08 05:17:47 +08:00
|
|
|
CLI = MF->getSubtarget().getCallLowering();
|
2016-12-08 05:29:15 +08:00
|
|
|
CurBuilder.setMF(*MF);
|
2016-12-08 05:17:47 +08:00
|
|
|
EntryBuilder.setMF(*MF);
|
|
|
|
MRI = &MF->getRegInfo();
|
2016-07-23 00:59:52 +08:00
|
|
|
DL = &F.getParent()->getDataLayout();
|
2016-08-27 07:49:05 +08:00
|
|
|
TPC = &getAnalysis<TargetPassConfig>();
|
2017-02-24 05:05:42 +08:00
|
|
|
ORE = make_unique<OptimizationRemarkEmitter>(&F);
|
2016-07-23 00:59:52 +08:00
|
|
|
|
2016-08-06 01:50:36 +08:00
|
|
|
assert(PendingPHIs.empty() && "stale PHIs");
|
|
|
|
|
2017-02-24 07:57:28 +08:00
|
|
|
// Release the per-function state when we return, whether we succeeded or not.
|
|
|
|
auto FinalizeOnReturn = make_scope_exit([this]() { finalizeFunction(); });
|
|
|
|
|
2016-12-08 05:05:38 +08:00
|
|
|
// Setup a separate basic-block for the arguments and constants, falling
|
|
|
|
// through to the IR-level Function's entry block.
|
2016-12-08 05:17:47 +08:00
|
|
|
MachineBasicBlock *EntryBB = MF->CreateMachineBasicBlock();
|
|
|
|
MF->push_back(EntryBB);
|
2016-12-08 05:05:38 +08:00
|
|
|
EntryBB->addSuccessor(&getOrCreateBB(F.front()));
|
|
|
|
EntryBuilder.setMBB(*EntryBB);
|
|
|
|
|
|
|
|
// Lower the actual args into this basic block.
|
2016-02-12 03:59:41 +08:00
|
|
|
SmallVector<unsigned, 8> VRegArgs;
|
|
|
|
for (const Argument &Arg: F.args())
|
2016-03-12 01:27:54 +08:00
|
|
|
VRegArgs.push_back(getOrCreateVReg(Arg));
|
2017-02-24 08:34:41 +08:00
|
|
|
if (!CLI->lowerFormalArguments(EntryBuilder, F, VRegArgs)) {
|
2017-02-24 08:34:44 +08:00
|
|
|
OptimizationRemarkMissed R("gisel-irtranslator", "GISelFailure",
|
|
|
|
MF->getFunction()->getSubprogram(),
|
2017-02-24 05:05:42 +08:00
|
|
|
&MF->getFunction()->getEntryBlock());
|
|
|
|
R << "unable to lower arguments: " << ore::NV("Prototype", F.getType());
|
|
|
|
reportTranslationError(*MF, *TPC, *ORE, R);
|
|
|
|
return false;
|
2016-08-27 07:49:05 +08:00
|
|
|
}
|
2016-02-12 03:59:41 +08:00
|
|
|
|
2016-12-08 05:05:38 +08:00
|
|
|
// And translate the function!
|
2016-02-11 06:59:27 +08:00
|
|
|
for (const BasicBlock &BB: F) {
|
2016-03-12 01:27:43 +08:00
|
|
|
MachineBasicBlock &MBB = getOrCreateBB(BB);
|
2016-03-12 01:27:47 +08:00
|
|
|
// Set the insertion point of all the following translations to
|
|
|
|
// the end of this basic block.
|
2016-12-08 05:29:15 +08:00
|
|
|
CurBuilder.setMBB(MBB);
|
2016-11-10 06:39:54 +08:00
|
|
|
|
2016-02-11 06:59:27 +08:00
|
|
|
for (const Instruction &Inst: BB) {
|
2017-02-24 08:34:41 +08:00
|
|
|
if (translate(Inst))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
std::string InstStrStorage;
|
|
|
|
raw_string_ostream InstStr(InstStrStorage);
|
|
|
|
InstStr << Inst;
|
|
|
|
|
2017-02-24 08:34:47 +08:00
|
|
|
OptimizationRemarkMissed R("gisel-irtranslator", "GISelFailure",
|
|
|
|
Inst.getDebugLoc(), &BB);
|
2017-02-24 08:34:41 +08:00
|
|
|
R << "unable to translate instruction: " << ore::NV("Opcode", &Inst)
|
|
|
|
<< ": '" << InstStr.str() << "'";
|
|
|
|
reportTranslationError(*MF, *TPC, *ORE, R);
|
|
|
|
return false;
|
2016-02-11 06:59:27 +08:00
|
|
|
}
|
|
|
|
}
|
2016-07-13 06:23:42 +08:00
|
|
|
|
2017-02-24 07:57:36 +08:00
|
|
|
finishPendingPhis();
|
|
|
|
|
|
|
|
// Now that the MachineFrameInfo has been configured, no further changes to
|
|
|
|
// the reserved registers are possible.
|
|
|
|
MRI->freezeReservedRegs(*MF);
|
|
|
|
|
|
|
|
// Merge the argument lowering and constants block with its single
|
|
|
|
// successor, the LLVM-IR entry block. We want the basic block to
|
|
|
|
// be maximal.
|
|
|
|
assert(EntryBB->succ_size() == 1 &&
|
|
|
|
"Custom BB used for lowering should have only one successor");
|
|
|
|
// Get the successor of the current entry block.
|
|
|
|
MachineBasicBlock &NewEntryBB = **EntryBB->succ_begin();
|
|
|
|
assert(NewEntryBB.pred_size() == 1 &&
|
|
|
|
"LLVM-IR entry block has a predecessor!?");
|
|
|
|
// Move all the instruction from the current entry block to the
|
|
|
|
// new entry block.
|
|
|
|
NewEntryBB.splice(NewEntryBB.begin(), EntryBB, EntryBB->begin(),
|
|
|
|
EntryBB->end());
|
|
|
|
|
|
|
|
// Update the live-in information for the new entry block.
|
|
|
|
for (const MachineBasicBlock::RegisterMaskPair &LiveIn : EntryBB->liveins())
|
|
|
|
NewEntryBB.addLiveIn(LiveIn);
|
|
|
|
NewEntryBB.sortUniqueLiveIns();
|
|
|
|
|
|
|
|
// Get rid of the now empty basic block.
|
|
|
|
EntryBB->removeSuccessor(&NewEntryBB);
|
|
|
|
MF->remove(EntryBB);
|
|
|
|
MF->DeleteMachineBasicBlock(EntryBB);
|
|
|
|
|
|
|
|
assert(&MF->front() == &NewEntryBB &&
|
|
|
|
"New entry wasn't next in the list of basic block!");
|
2016-08-06 01:16:40 +08:00
|
|
|
|
2016-01-21 04:58:56 +08:00
|
|
|
return false;
|
|
|
|
}
|