diff options
author | dim <dim@FreeBSD.org> | 2017-04-02 17:24:58 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2017-04-02 17:24:58 +0000 |
commit | 60b571e49a90d38697b3aca23020d9da42fc7d7f (patch) | |
tree | 99351324c24d6cb146b6285b6caffa4d26fce188 /contrib/llvm/lib/CodeGen/GlobalISel | |
parent | bea1b22c7a9bce1dfdd73e6e5b65bc4752215180 (diff) | |
download | FreeBSD-src-60b571e49a90d38697b3aca23020d9da42fc7d7f.zip FreeBSD-src-60b571e49a90d38697b3aca23020d9da42fc7d7f.tar.gz |
Update clang, llvm, lld, lldb, compiler-rt and libc++ to 4.0.0 release:
MFC r309142 (by emaste):
Add WITH_LLD_AS_LD build knob
If set it installs LLD as /usr/bin/ld. LLD (as of version 3.9) is not
capable of linking the world and kernel, but can self-host and link many
substantial applications. GNU ld continues to be used for the world and
kernel build, regardless of how this knob is set.
It is on by default for arm64, and off for all other CPU architectures.
Sponsored by: The FreeBSD Foundation
MFC r310840:
Reapply 310775, now it also builds correctly if lldb is disabled:
Move llvm-objdump from CLANG_EXTRAS to installed by default
We currently install three tools from binutils 2.17.50: as, ld, and
objdump. Work is underway to migrate to a permissively-licensed
tool-chain, with one goal being the retirement of binutils 2.17.50.
LLVM's llvm-objdump is intended to be compatible with GNU objdump
although it is currently missing some options and may have formatting
differences. Enable it by default for testing and further investigation.
It may later be changed to install as /usr/bin/objdump, it becomes a
fully viable replacement.
Reviewed by: emaste
Differential Revision: https://reviews.freebsd.org/D8879
MFC r312855 (by emaste):
Rename LLD_AS_LD to LLD_IS_LD, for consistency with CLANG_IS_CC
Reported by: Dan McGregor <dan.mcgregor usask.ca>
MFC r313559 | glebius | 2017-02-10 18:34:48 +0100 (Fri, 10 Feb 2017) | 5 lines
Don't check struct rtentry on FreeBSD, it is an internal kernel structure.
On other systems it may be API structure for SIOCADDRT/SIOCDELRT.
Reviewed by: emaste, dim
MFC r314152 (by jkim):
Remove an assembler flag, which is redundant since r309124. The upstream
took care of it by introducing a macro NO_EXEC_STACK_DIRECTIVE.
http://llvm.org/viewvc/llvm-project?rev=273500&view=rev
Reviewed by: dim
MFC r314564:
Upgrade our copies of clang, llvm, lld, lldb, compiler-rt and libc++ to
4.0.0 (branches/release_40 296509). The release will follow soon.
Please note that from 3.5.0 onwards, clang, llvm and lldb require C++11
support to build; see UPDATING for more information.
Also note that as of 4.0.0, lld should be able to link the base system
on amd64 and aarch64. See the WITH_LLD_IS_LLD setting in src.conf(5).
Though please be aware that this is work in progress.
Release notes for llvm, clang and lld will be available here:
<http://releases.llvm.org/4.0.0/docs/ReleaseNotes.html>
<http://releases.llvm.org/4.0.0/tools/clang/docs/ReleaseNotes.html>
<http://releases.llvm.org/4.0.0/tools/lld/docs/ReleaseNotes.html>
Thanks to Ed Maste, Jan Beich, Antoine Brodin and Eric Fiselier for
their help.
Relnotes: yes
Exp-run: antoine
PR: 215969, 216008
MFC r314708:
For now, revert r287232 from upstream llvm trunk (by Daniil Fukalov):
[SCEV] limit recursion depth of CompareSCEVComplexity
Summary:
CompareSCEVComplexity goes too deep (50+ on a quite a big unrolled
loop) and runs almost infinite time.
Added cache of "equal" SCEV pairs to earlier cutoff of further
estimation. Recursion depth limit was also introduced as a parameter.
Reviewers: sanjoy
Subscribers: mzolotukhin, tstellarAMD, llvm-commits
Differential Revision: https://reviews.llvm.org/D26389
This commit is the cause of excessive compile times on skein_block.c
(and possibly other files) during kernel builds on amd64.
We never saw the problematic behavior described in this upstream commit,
so for now it is better to revert it. An upstream bug has been filed
here: https://bugs.llvm.org/show_bug.cgi?id=32142
Reported by: mjg
MFC r314795:
Reapply r287232 from upstream llvm trunk (by Daniil Fukalov):
[SCEV] limit recursion depth of CompareSCEVComplexity
Summary:
CompareSCEVComplexity goes too deep (50+ on a quite a big unrolled
loop) and runs almost infinite time.
Added cache of "equal" SCEV pairs to earlier cutoff of further
estimation. Recursion depth limit was also introduced as a parameter.
Reviewers: sanjoy
Subscribers: mzolotukhin, tstellarAMD, llvm-commits
Differential Revision: https://reviews.llvm.org/D26389
Pull in r296992 from upstream llvm trunk (by Sanjoy Das):
[SCEV] Decrease the recursion threshold for CompareValueComplexity
Fixes PR32142.
r287232 accidentally increased the recursion threshold for
CompareValueComplexity from 2 to 32. This change reverses that
change by introducing a separate flag for CompareValueComplexity's
threshold.
The latter revision fixes the excessive compile times for skein_block.c.
MFC r314907 | mmel | 2017-03-08 12:40:27 +0100 (Wed, 08 Mar 2017) | 7 lines
Unbreak ARMv6 world.
The new compiler_rt library imported with clang 4.0.0 have several fatal
issues (non-functional __udivsi3 for example) with ARM specific instrict
functions. As temporary workaround, until upstream solve these problems,
disable all thumb[1][2] related feature.
MFC r315016:
Update clang, llvm, lld, lldb, compiler-rt and libc++ to 4.0.0 release.
We were already very close to the last release candidate, so this is a
pretty minor update.
Relnotes: yes
MFC r316005:
Revert r314907, and pull in r298713 from upstream compiler-rt trunk (by
Weiming Zhao):
builtins: Select correct code fragments when compiling for Thumb1/Thum2/ARM ISA.
Summary:
Value of __ARM_ARCH_ISA_THUMB isn't based on the actual compilation
mode (-mthumb, -marm), it reflect's capability of given CPU.
Due to this:
- use __tbumb__ and __thumb2__ insteand of __ARM_ARCH_ISA_THUMB
- use '.thumb' directive consistently in all affected files
- decorate all thumb functions using
DEFINE_COMPILERRT_THUMB_FUNCTION()
---------
Note: This patch doesn't fix broken Thumb1 variant of __udivsi3 !
Reviewers: weimingz, rengolin, compnerd
Subscribers: aemerson, dim
Differential Revision: https://reviews.llvm.org/D30938
Discussed with: mmel
Diffstat (limited to 'contrib/llvm/lib/CodeGen/GlobalISel')
-rw-r--r-- | contrib/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp | 170 | ||||
-rw-r--r-- | contrib/llvm/lib/CodeGen/GlobalISel/GlobalISel.cpp | 2 | ||||
-rw-r--r-- | contrib/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp | 839 | ||||
-rw-r--r-- | contrib/llvm/lib/CodeGen/GlobalISel/InstructionSelect.cpp | 175 | ||||
-rw-r--r-- | contrib/llvm/lib/CodeGen/GlobalISel/InstructionSelector.cpp | 60 | ||||
-rw-r--r-- | contrib/llvm/lib/CodeGen/GlobalISel/Legalizer.cpp | 180 | ||||
-rw-r--r-- | contrib/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp | 354 | ||||
-rw-r--r-- | contrib/llvm/lib/CodeGen/GlobalISel/LegalizerInfo.cpp | 182 | ||||
-rw-r--r-- | contrib/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp | 427 | ||||
-rw-r--r-- | contrib/llvm/lib/CodeGen/GlobalISel/RegBankSelect.cpp | 171 | ||||
-rw-r--r-- | contrib/llvm/lib/CodeGen/GlobalISel/RegisterBank.cpp | 11 | ||||
-rw-r--r-- | contrib/llvm/lib/CodeGen/GlobalISel/RegisterBankInfo.cpp | 474 | ||||
-rw-r--r-- | contrib/llvm/lib/CodeGen/GlobalISel/Utils.cpp | 45 |
13 files changed, 2706 insertions, 384 deletions
diff --git a/contrib/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp b/contrib/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp new file mode 100644 index 0000000..1321221 --- /dev/null +++ b/contrib/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp @@ -0,0 +1,170 @@ +//===-- lib/CodeGen/GlobalISel/CallLowering.cpp - Call lowering -----------===// +// +// 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 some simple delegations needed for call lowering. +/// +//===----------------------------------------------------------------------===// + +#include "llvm/CodeGen/GlobalISel/CallLowering.h" +#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" +#include "llvm/CodeGen/MachineOperand.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Module.h" +#include "llvm/Target/TargetLowering.h" + +using namespace llvm; + +bool CallLowering::lowerCall( + MachineIRBuilder &MIRBuilder, const CallInst &CI, unsigned ResReg, + ArrayRef<unsigned> ArgRegs, std::function<unsigned()> GetCalleeReg) const { + auto &DL = CI.getParent()->getParent()->getParent()->getDataLayout(); + + // First step is to marshall all the function's parameters into the correct + // physregs and memory locations. Gather the sequence of argument types that + // we'll pass to the assigner function. + SmallVector<ArgInfo, 8> OrigArgs; + unsigned i = 0; + for (auto &Arg : CI.arg_operands()) { + ArgInfo OrigArg{ArgRegs[i], Arg->getType(), ISD::ArgFlagsTy{}}; + setArgFlags(OrigArg, i + 1, DL, CI); + OrigArgs.push_back(OrigArg); + ++i; + } + + MachineOperand Callee = MachineOperand::CreateImm(0); + if (Function *F = CI.getCalledFunction()) + Callee = MachineOperand::CreateGA(F, 0); + else + Callee = MachineOperand::CreateReg(GetCalleeReg(), false); + + ArgInfo OrigRet{ResReg, CI.getType(), ISD::ArgFlagsTy{}}; + if (!OrigRet.Ty->isVoidTy()) + setArgFlags(OrigRet, AttributeSet::ReturnIndex, DL, CI); + + return lowerCall(MIRBuilder, Callee, OrigRet, OrigArgs); +} + +template <typename FuncInfoTy> +void CallLowering::setArgFlags(CallLowering::ArgInfo &Arg, unsigned OpIdx, + const DataLayout &DL, + const FuncInfoTy &FuncInfo) const { + const AttributeSet &Attrs = FuncInfo.getAttributes(); + if (Attrs.hasAttribute(OpIdx, Attribute::ZExt)) + Arg.Flags.setZExt(); + if (Attrs.hasAttribute(OpIdx, Attribute::SExt)) + Arg.Flags.setSExt(); + if (Attrs.hasAttribute(OpIdx, Attribute::InReg)) + Arg.Flags.setInReg(); + if (Attrs.hasAttribute(OpIdx, Attribute::StructRet)) + Arg.Flags.setSRet(); + if (Attrs.hasAttribute(OpIdx, Attribute::SwiftSelf)) + Arg.Flags.setSwiftSelf(); + if (Attrs.hasAttribute(OpIdx, Attribute::SwiftError)) + Arg.Flags.setSwiftError(); + if (Attrs.hasAttribute(OpIdx, Attribute::ByVal)) + Arg.Flags.setByVal(); + if (Attrs.hasAttribute(OpIdx, Attribute::InAlloca)) + Arg.Flags.setInAlloca(); + + if (Arg.Flags.isByVal() || Arg.Flags.isInAlloca()) { + Type *ElementTy = cast<PointerType>(Arg.Ty)->getElementType(); + Arg.Flags.setByValSize(DL.getTypeAllocSize(ElementTy)); + // For ByVal, alignment should be passed from FE. BE will guess if + // this info is not there but there are cases it cannot get right. + unsigned FrameAlign; + if (FuncInfo.getParamAlignment(OpIdx)) + FrameAlign = FuncInfo.getParamAlignment(OpIdx); + else + FrameAlign = getTLI()->getByValTypeAlignment(ElementTy, DL); + Arg.Flags.setByValAlign(FrameAlign); + } + if (Attrs.hasAttribute(OpIdx, Attribute::Nest)) + Arg.Flags.setNest(); + Arg.Flags.setOrigAlign(DL.getABITypeAlignment(Arg.Ty)); +} + +template void +CallLowering::setArgFlags<Function>(CallLowering::ArgInfo &Arg, unsigned OpIdx, + const DataLayout &DL, + const Function &FuncInfo) const; + +template void +CallLowering::setArgFlags<CallInst>(CallLowering::ArgInfo &Arg, unsigned OpIdx, + const DataLayout &DL, + const CallInst &FuncInfo) const; + +bool CallLowering::handleAssignments(MachineIRBuilder &MIRBuilder, + CCAssignFn *AssignFn, + ArrayRef<ArgInfo> Args, + ValueHandler &Handler) const { + MachineFunction &MF = MIRBuilder.getMF(); + const Function &F = *MF.getFunction(); + const DataLayout &DL = F.getParent()->getDataLayout(); + + SmallVector<CCValAssign, 16> ArgLocs; + CCState CCInfo(F.getCallingConv(), F.isVarArg(), MF, ArgLocs, F.getContext()); + + unsigned NumArgs = Args.size(); + for (unsigned i = 0; i != NumArgs; ++i) { + MVT CurVT = MVT::getVT(Args[i].Ty); + if (AssignFn(i, CurVT, CurVT, CCValAssign::Full, Args[i].Flags, CCInfo)) + return false; + } + + for (unsigned i = 0, e = Args.size(); i != e; ++i) { + CCValAssign &VA = ArgLocs[i]; + + if (VA.isRegLoc()) + Handler.assignValueToReg(Args[i].Reg, VA.getLocReg(), VA); + else if (VA.isMemLoc()) { + unsigned Size = VA.getValVT() == MVT::iPTR + ? DL.getPointerSize() + : alignTo(VA.getValVT().getSizeInBits(), 8) / 8; + unsigned Offset = VA.getLocMemOffset(); + MachinePointerInfo MPO; + unsigned StackAddr = Handler.getStackAddress(Size, Offset, MPO); + Handler.assignValueToAddress(Args[i].Reg, StackAddr, Size, MPO, VA); + } else { + // FIXME: Support byvals and other weirdness + return false; + } + } + return true; +} + +unsigned CallLowering::ValueHandler::extendRegister(unsigned ValReg, + CCValAssign &VA) { + LLT LocTy{VA.getLocVT()}; + switch (VA.getLocInfo()) { + default: break; + case CCValAssign::Full: + case CCValAssign::BCvt: + // FIXME: bitconverting between vector types may or may not be a + // nop in big-endian situations. + return ValReg; + case CCValAssign::AExt: + assert(!VA.getLocVT().isVector() && "unexpected vector extend"); + // Otherwise, it's a nop. + return ValReg; + case CCValAssign::SExt: { + unsigned NewReg = MRI.createGenericVirtualRegister(LocTy); + MIRBuilder.buildSExt(NewReg, ValReg); + return NewReg; + } + case CCValAssign::ZExt: { + unsigned NewReg = MRI.createGenericVirtualRegister(LocTy); + MIRBuilder.buildZExt(NewReg, ValReg); + return NewReg; + } + } + llvm_unreachable("unable to extend register"); +} diff --git a/contrib/llvm/lib/CodeGen/GlobalISel/GlobalISel.cpp b/contrib/llvm/lib/CodeGen/GlobalISel/GlobalISel.cpp index 231e5ac..fcd2722 100644 --- a/contrib/llvm/lib/CodeGen/GlobalISel/GlobalISel.cpp +++ b/contrib/llvm/lib/CodeGen/GlobalISel/GlobalISel.cpp @@ -25,6 +25,8 @@ void llvm::initializeGlobalISel(PassRegistry &Registry) { void llvm::initializeGlobalISel(PassRegistry &Registry) { initializeIRTranslatorPass(Registry); + initializeLegalizerPass(Registry); initializeRegBankSelectPass(Registry); + initializeInstructionSelectPass(Registry); } #endif // LLVM_BUILD_GLOBAL_ISEL diff --git a/contrib/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp b/contrib/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp index b8a960c..89a042f 100644 --- a/contrib/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp +++ b/contrib/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp @@ -14,12 +14,19 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/CodeGen/GlobalISel/CallLowering.h" +#include "llvm/CodeGen/Analysis.h" #include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/TargetPassConfig.h" #include "llvm/IR/Constant.h" #include "llvm/IR/Function.h" +#include "llvm/IR/GetElementPtrTypeIterator.h" +#include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Type.h" #include "llvm/IR/Value.h" +#include "llvm/Target/TargetIntrinsicInfo.h" #include "llvm/Target/TargetLowering.h" #define DEBUG_TYPE "irtranslator" @@ -27,13 +34,29 @@ using namespace llvm; char IRTranslator::ID = 0; -INITIALIZE_PASS(IRTranslator, "irtranslator", "IRTranslator LLVM IR -> MI", - false, false); +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", + false, false) + +static void reportTranslationError(const Value &V, const Twine &Message) { + std::string ErrStorage; + raw_string_ostream Err(ErrStorage); + Err << Message << ": " << V << '\n'; + report_fatal_error(Err.str()); +} IRTranslator::IRTranslator() : MachineFunctionPass(ID), MRI(nullptr) { initializeIRTranslatorPass(*PassRegistry::getPassRegistry()); } +void IRTranslator::getAnalysisUsage(AnalysisUsage &AU) const { + AU.addRequired<TargetPassConfig>(); + MachineFunctionPass::getAnalysisUsage(AU); +} + + unsigned IRTranslator::getOrCreateVReg(const Value &Val) { unsigned &ValReg = ValToVReg[&Val]; // Check if this is the first time we see Val. @@ -42,56 +65,132 @@ unsigned IRTranslator::getOrCreateVReg(const Value &Val) { // we need to concat together to produce the value. assert(Val.getType()->isSized() && "Don't know how to create an empty vreg"); - assert(!Val.getType()->isAggregateType() && "Not yet implemented"); - unsigned Size = Val.getType()->getPrimitiveSizeInBits(); - unsigned VReg = MRI->createGenericVirtualRegister(Size); + unsigned VReg = MRI->createGenericVirtualRegister(LLT{*Val.getType(), *DL}); ValReg = VReg; - assert(!isa<Constant>(Val) && "Not yet implemented"); + + if (auto CV = dyn_cast<Constant>(&Val)) { + bool Success = translate(*CV, VReg); + if (!Success) { + if (!TPC->isGlobalISelAbortEnabled()) { + MF->getProperties().set( + MachineFunctionProperties::Property::FailedISel); + return VReg; + } + reportTranslationError(Val, "unable to translate constant"); + } + } } return ValReg; } +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]; + FI = MF->getFrameInfo().CreateStackObject(Size, Alignment, false, &AI); + return FI; +} + +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(); + } else if (!TPC->isGlobalISelAbortEnabled()) { + MF->getProperties().set( + MachineFunctionProperties::Property::FailedISel); + return 1; + } else + llvm_unreachable("unhandled memory instruction"); + + return Alignment ? Alignment : DL->getABITypeAlignment(ValTy); +} + MachineBasicBlock &IRTranslator::getOrCreateBB(const BasicBlock &BB) { MachineBasicBlock *&MBB = BBToMBB[&BB]; if (!MBB) { - MachineFunction &MF = MIRBuilder.getMF(); - MBB = MF.CreateMachineBasicBlock(); - MF.push_back(MBB); + MBB = MF->CreateMachineBasicBlock(&BB); + MF->push_back(MBB); + + if (BB.hasAddressTaken()) + MBB->setHasAddressTaken(); } return *MBB; } -bool IRTranslator::translateBinaryOp(unsigned Opcode, const Instruction &Inst) { +bool IRTranslator::translateBinaryOp(unsigned Opcode, const User &U, + MachineIRBuilder &MIRBuilder) { + // FIXME: handle signed/unsigned wrapping flags. + // 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. - unsigned Op0 = getOrCreateVReg(*Inst.getOperand(0)); - unsigned Op1 = getOrCreateVReg(*Inst.getOperand(1)); - unsigned Res = getOrCreateVReg(Inst); - MIRBuilder.buildInstr(Opcode, Inst.getType(), Res, Op0, Op1); + unsigned Op0 = getOrCreateVReg(*U.getOperand(0)); + unsigned Op1 = getOrCreateVReg(*U.getOperand(1)); + unsigned Res = getOrCreateVReg(U); + MIRBuilder.buildInstr(Opcode).addDef(Res).addUse(Op0).addUse(Op1); return true; } -bool IRTranslator::translateReturn(const Instruction &Inst) { - assert(isa<ReturnInst>(Inst) && "Return expected"); - const Value *Ret = cast<ReturnInst>(Inst).getReturnValue(); +bool IRTranslator::translateCompare(const User &U, + MachineIRBuilder &MIRBuilder) { + 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)) + MIRBuilder.buildICmp(Pred, Res, Op0, Op1); + else + MIRBuilder.buildFCmp(Pred, Res, Op0, Op1); + + return true; +} + +bool IRTranslator::translateRet(const User &U, MachineIRBuilder &MIRBuilder) { + const ReturnInst &RI = cast<ReturnInst>(U); + const Value *Ret = RI.getReturnValue(); // 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. return CLI->lowerReturn(MIRBuilder, Ret, !Ret ? 0 : getOrCreateVReg(*Ret)); } -bool IRTranslator::translateBr(const Instruction &Inst) { - assert(isa<BranchInst>(Inst) && "Branch expected"); - const BranchInst &BrInst = *cast<BranchInst>(&Inst); - if (BrInst.isUnconditional()) { - const BasicBlock &BrTgt = *cast<BasicBlock>(BrInst.getOperand(0)); - MachineBasicBlock &TgtBB = getOrCreateBB(BrTgt); - MIRBuilder.buildInstr(TargetOpcode::G_BR, BrTgt.getType(), TgtBB); - } else { - assert(0 && "Not yet implemented"); +bool IRTranslator::translateBr(const User &U, MachineIRBuilder &MIRBuilder) { + const BranchInst &BrInst = cast<BranchInst>(U); + 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); + MIRBuilder.buildBrCond(Tst, TrueBB); } + + const BasicBlock &BrTgt = *cast<BasicBlock>(BrInst.getSuccessor(Succ)); + MachineBasicBlock &TgtBB = getOrCreateBB(BrTgt); + MIRBuilder.buildBr(TgtBB); + // Link successors. MachineBasicBlock &CurBB = MIRBuilder.getMBB(); for (const BasicBlock *Succ : BrInst.successors()) @@ -99,66 +198,694 @@ bool IRTranslator::translateBr(const Instruction &Inst) { return true; } +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()); + + LLT LLTi1 = LLT(*Type::getInt1Ty(U.getContext()), *DL); + 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); + MachineBasicBlock &CurBB = MIRBuilder.getMBB(); + MachineBasicBlock &TrueBB = getOrCreateBB(*CaseIt.getCaseSuccessor()); + + MIRBuilder.buildBrCond(Tst, TrueBB); + CurBB.addSuccessor(&TrueBB); + + MachineBasicBlock *FalseBB = + MF->CreateMachineBasicBlock(SwInst.getParent()); + MF->push_back(FalseBB); + MIRBuilder.buildBr(*FalseBB); + CurBB.addSuccessor(FalseBB); + + MIRBuilder.setMBB(*FalseBB); + } + // handle default case + MachineBasicBlock &DefaultBB = getOrCreateBB(*SwInst.getDefaultDest()); + MIRBuilder.buildBr(DefaultBB); + MIRBuilder.getMBB().addSuccessor(&DefaultBB); + + return true; +} + +bool IRTranslator::translateLoad(const User &U, MachineIRBuilder &MIRBuilder) { + const LoadInst &LI = cast<LoadInst>(U); + + if (!TPC->isGlobalISelAbortEnabled() && LI.isAtomic()) + return false; + + assert(!LI.isAtomic() && "only non-atomic loads are supported at the moment"); + auto Flags = LI.isVolatile() ? MachineMemOperand::MOVolatile + : MachineMemOperand::MONone; + Flags |= MachineMemOperand::MOLoad; + + unsigned Res = getOrCreateVReg(LI); + unsigned Addr = getOrCreateVReg(*LI.getPointerOperand()); + LLT VTy{*LI.getType(), *DL}, PTy{*LI.getPointerOperand()->getType(), *DL}; + MIRBuilder.buildLoad( + Res, Addr, + *MF->getMachineMemOperand(MachinePointerInfo(LI.getPointerOperand()), + Flags, DL->getTypeStoreSize(LI.getType()), + getMemOpAlignment(LI))); + return true; +} + +bool IRTranslator::translateStore(const User &U, MachineIRBuilder &MIRBuilder) { + const StoreInst &SI = cast<StoreInst>(U); + + if (!TPC->isGlobalISelAbortEnabled() && SI.isAtomic()) + return false; + + assert(!SI.isAtomic() && "only non-atomic stores supported at the moment"); + auto Flags = SI.isVolatile() ? MachineMemOperand::MOVolatile + : MachineMemOperand::MONone; + Flags |= MachineMemOperand::MOStore; + + unsigned Val = getOrCreateVReg(*SI.getValueOperand()); + unsigned Addr = getOrCreateVReg(*SI.getPointerOperand()); + LLT VTy{*SI.getValueOperand()->getType(), *DL}, + PTy{*SI.getPointerOperand()->getType(), *DL}; + + MIRBuilder.buildStore( + Val, Addr, + *MF->getMachineMemOperand( + MachinePointerInfo(SI.getPointerOperand()), Flags, + DL->getTypeStoreSize(SI.getValueOperand()->getType()), + getMemOpAlignment(SI))); + return true; +} + +bool IRTranslator::translateExtractValue(const User &U, + MachineIRBuilder &MIRBuilder) { + const Value *Src = U.getOperand(0); + Type *Int32Ty = Type::getInt32Ty(U.getContext()); + 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)); + + 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)); + } + + uint64_t Offset = 8 * DL->getIndexedOffsetInType(Src->getType(), Indices); + + unsigned Res = getOrCreateVReg(U); + MIRBuilder.buildExtract(Res, Offset, getOrCreateVReg(*Src)); + + return true; +} + +bool IRTranslator::translateInsertValue(const User &U, + MachineIRBuilder &MIRBuilder) { + const Value *Src = U.getOperand(0); + Type *Int32Ty = Type::getInt32Ty(U.getContext()); + 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)); + + 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)); + } + + uint64_t Offset = 8 * DL->getIndexedOffsetInType(Src->getType(), Indices); + + unsigned Res = getOrCreateVReg(U); + const Value &Inserted = *U.getOperand(1); + MIRBuilder.buildInsert(Res, getOrCreateVReg(*Src), getOrCreateVReg(Inserted), + Offset); + + return true; +} + +bool IRTranslator::translateSelect(const User &U, + MachineIRBuilder &MIRBuilder) { + MIRBuilder.buildSelect(getOrCreateVReg(U), getOrCreateVReg(*U.getOperand(0)), + getOrCreateVReg(*U.getOperand(1)), + getOrCreateVReg(*U.getOperand(2))); + return true; +} + +bool IRTranslator::translateBitCast(const User &U, + MachineIRBuilder &MIRBuilder) { + if (LLT{*U.getOperand(0)->getType(), *DL} == LLT{*U.getType(), *DL}) { + unsigned &Reg = ValToVReg[&U]; + if (Reg) + MIRBuilder.buildCopy(Reg, getOrCreateVReg(*U.getOperand(0))); + else + Reg = getOrCreateVReg(*U.getOperand(0)); + return true; + } + return translateCast(TargetOpcode::G_BITCAST, U, MIRBuilder); +} + +bool IRTranslator::translateCast(unsigned Opcode, const User &U, + MachineIRBuilder &MIRBuilder) { + unsigned Op = getOrCreateVReg(*U.getOperand(0)); + unsigned Res = getOrCreateVReg(U); + MIRBuilder.buildInstr(Opcode).addDef(Res).addUse(Op); + return true; +} + +bool IRTranslator::translateGetElementPtr(const User &U, + MachineIRBuilder &MIRBuilder) { + // FIXME: support vector GEPs. + if (U.getType()->isVectorTy()) + return false; + + Value &Op0 = *U.getOperand(0); + unsigned BaseReg = getOrCreateVReg(Op0); + LLT PtrTy{*Op0.getType(), *DL}; + 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(); + if (StructType *StTy = GTI.getStructTypeOrNull()) { + 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; +} + +bool IRTranslator::translateMemcpy(const CallInst &CI, + MachineIRBuilder &MIRBuilder) { + LLT SizeTy{*CI.getArgOperand(2)->getType(), *DL}; + if (cast<PointerType>(CI.getArgOperand(0)->getType())->getAddressSpace() != + 0 || + cast<PointerType>(CI.getArgOperand(1)->getType())->getAddressSpace() != + 0 || + 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()); + } + + MachineOperand Callee = MachineOperand::CreateES("memcpy"); + + return CLI->lowerCall(MIRBuilder, Callee, + CallLowering::ArgInfo(0, CI.getType()), Args); +} + +void IRTranslator::getStackGuard(unsigned DstReg, + MachineIRBuilder &MIRBuilder) { + auto MIB = MIRBuilder.buildInstr(TargetOpcode::LOAD_STACK_GUARD); + MIB.addDef(DstReg); + + auto &TLI = *MF->getSubtarget().getTargetLowering(); + Value *Global = TLI.getSDagStackGuard(*MF->getFunction()->getParent()); + if (!Global) + return; + + MachinePointerInfo MPInfo(Global); + MachineInstr::mmo_iterator MemRefs = MF->allocateMemRefsArray(1); + auto Flags = MachineMemOperand::MOLoad | MachineMemOperand::MOInvariant | + MachineMemOperand::MODereferenceable; + *MemRefs = + MF->getMachineMemOperand(MPInfo, Flags, DL->getPointerSizeInBits() / 8, + DL->getPointerABIAlignment()); + MIB.setMemRefs(MemRefs, MemRefs + 1); +} + +bool IRTranslator::translateOverflowIntrinsic(const CallInst &CI, unsigned Op, + MachineIRBuilder &MIRBuilder) { + LLT Ty{*CI.getOperand(0)->getType(), *DL}; + 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; +} + +bool IRTranslator::translateKnownIntrinsic(const CallInst &CI, Intrinsic::ID ID, + MachineIRBuilder &MIRBuilder) { + switch (ID) { + default: + break; + case Intrinsic::dbg_declare: + case Intrinsic::dbg_value: + // FIXME: these obviously need to be supported properly. + MF->getProperties().set( + MachineFunctionProperties::Property::FailedISel); + return true; + 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); + case Intrinsic::memcpy: + return translateMemcpy(CI, MIRBuilder); + case Intrinsic::eh_typeid_for: { + GlobalValue *GV = ExtractTypeInfo(CI.getArgOperand(0)); + unsigned Reg = getOrCreateVReg(CI); + unsigned TypeID = MF->getTypeIDFor(GV); + MIRBuilder.buildConstant(Reg, TypeID); + return true; + } + 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; + } + case Intrinsic::stackguard: + getStackGuard(getOrCreateVReg(CI), MIRBuilder); + return true; + case Intrinsic::stackprotector: { + LLT PtrTy{*CI.getArgOperand(0)->getType(), *DL}; + unsigned GuardVal = MRI->createGenericVirtualRegister(PtrTy); + getStackGuard(GuardVal, MIRBuilder); + + AllocaInst *Slot = cast<AllocaInst>(CI.getArgOperand(1)); + MIRBuilder.buildStore( + GuardVal, getOrCreateVReg(*Slot), + *MF->getMachineMemOperand( + MachinePointerInfo::getFixedStack(*MF, + getOrCreateFrameIndex(*Slot)), + MachineMemOperand::MOStore | MachineMemOperand::MOVolatile, + PtrTy.getSizeInBits() / 8, 8)); + return true; + } + } + return false; +} + +bool IRTranslator::translateCall(const User &U, MachineIRBuilder &MIRBuilder) { + const CallInst &CI = cast<CallInst>(U); + auto TII = MF->getTarget().getIntrinsicInfo(); + const Function *F = CI.getCalledFunction(); + + 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)); + + return CLI->lowerCall(MIRBuilder, CI, Res, Args, [&]() { + return getOrCreateVReg(*CI.getCalledValue()); + }); + } + + Intrinsic::ID ID = F->getIntrinsicID(); + if (TII && ID == Intrinsic::not_intrinsic) + ID = static_cast<Intrinsic::ID>(TII->getIntrinsicID(F)); + + assert(ID != Intrinsic::not_intrinsic && "unknown intrinsic"); + + if (translateKnownIntrinsic(CI, ID, MIRBuilder)) + return true; + + unsigned Res = CI.getType()->isVoidTy() ? 0 : getOrCreateVReg(CI); + MachineInstrBuilder MIB = + MIRBuilder.buildIntrinsic(ID, Res, !CI.doesNotAccessMemory()); + + for (auto &Arg : CI.arg_operands()) { + if (ConstantInt *CI = dyn_cast<ConstantInt>(Arg)) + MIB.addImm(CI->getSExtValue()); + else + MIB.addUse(getOrCreateVReg(*Arg)); + } + return true; +} + +bool IRTranslator::translateInvoke(const User &U, + MachineIRBuilder &MIRBuilder) { + const InvokeInst &I = cast<InvokeInst>(U); + MCContext &Context = MF->getContext(); + + const BasicBlock *ReturnBB = I.getSuccessor(0); + const BasicBlock *EHPadBB = I.getSuccessor(1); + + const Value *Callee(I.getCalledValue()); + 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; + + + // Emit the actual call, bracketed by EH_LABELs so that the MF knows about + // the region covered by the try. + MCSymbol *BeginSymbol = Context.createTempSymbol(); + MIRBuilder.buildInstr(TargetOpcode::EH_LABEL).addSym(BeginSymbol); + + unsigned Res = I.getType()->isVoidTy() ? 0 : getOrCreateVReg(I); + SmallVector<CallLowering::ArgInfo, 8> Args; + for (auto &Arg: I.arg_operands()) + Args.emplace_back(getOrCreateVReg(*Arg), Arg->getType()); + + if (!CLI->lowerCall(MIRBuilder, MachineOperand::CreateGA(Fn, 0), + CallLowering::ArgInfo(Res, I.getType()), Args)) + return false; + + MCSymbol *EndSymbol = Context.createTempSymbol(); + MIRBuilder.buildInstr(TargetOpcode::EH_LABEL).addSym(EndSymbol); + + // FIXME: track probabilities. + MachineBasicBlock &EHPadMBB = getOrCreateBB(*EHPadBB), + &ReturnMBB = getOrCreateBB(*ReturnBB); + MF->addInvoke(&EHPadMBB, BeginSymbol, EndSymbol); + MIRBuilder.getMBB().addSuccessor(&ReturnMBB); + MIRBuilder.getMBB().addSuccessor(&EHPadMBB); + + return true; +} + +bool IRTranslator::translateLandingPad(const User &U, + MachineIRBuilder &MIRBuilder) { + const LandingPadInst &LP = cast<LandingPadInst>(U); + + MachineBasicBlock &MBB = MIRBuilder.getMBB(); + addLandingPadInfo(LP, MBB); + + MBB.setIsEHPad(); + + // If there aren't registers to copy the values into (e.g., during SjLj + // exceptions), then don't bother. + auto &TLI = *MF->getSubtarget().getTargetLowering(); + const Constant *PersonalityFn = MF->getFunction()->getPersonalityFn(); + 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) + .addSym(MF->addLandingPad(&MBB)); + + // Mark exception register as live in. + SmallVector<unsigned, 2> Regs; + SmallVector<uint64_t, 2> Offsets; + LLT p0 = LLT::pointer(0, DL->getPointerSizeInBits()); + if (unsigned Reg = TLI.getExceptionPointerRegister(PersonalityFn)) { + unsigned VReg = MRI->createGenericVirtualRegister(p0); + MIRBuilder.buildCopy(VReg, Reg); + Regs.push_back(VReg); + Offsets.push_back(0); + } + + if (unsigned Reg = TLI.getExceptionSelectorRegister(PersonalityFn)) { + unsigned VReg = MRI->createGenericVirtualRegister(p0); + MIRBuilder.buildCopy(VReg, Reg); + Regs.push_back(VReg); + Offsets.push_back(p0.getSizeInBits()); + } + + MIRBuilder.buildSequence(getOrCreateVReg(LP), Regs, Offsets); + return true; +} + +bool IRTranslator::translateStaticAlloca(const AllocaInst &AI, + MachineIRBuilder &MIRBuilder) { + if (!TPC->isGlobalISelAbortEnabled() && !AI.isStaticAlloca()) + return false; + + assert(AI.isStaticAlloca() && "only handle static allocas now"); + unsigned Res = getOrCreateVReg(AI); + int FI = getOrCreateFrameIndex(AI); + MIRBuilder.buildFrameIndex(Res, FI); + return true; +} + +bool IRTranslator::translatePHI(const User &U, MachineIRBuilder &MIRBuilder) { + const PHINode &PI = cast<PHINode>(U); + auto MIB = MIRBuilder.buildInstr(TargetOpcode::PHI); + 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; + MachineInstrBuilder MIB(*MF, Phi.second); + + // 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). + for (unsigned i = 0; i < PI->getNumIncomingValues(); ++i) { + assert(BBToMBB[PI->getIncomingBlock(i)]->isSuccessor(MIB->getParent()) && + "I appear to have misunderstood Machine PHIs"); + MIB.addUse(getOrCreateVReg(*PI->getIncomingValue(i))); + MIB.addMBB(BBToMBB[PI->getIncomingBlock(i)]); + } + } +} + bool IRTranslator::translate(const Instruction &Inst) { - MIRBuilder.setDebugLoc(Inst.getDebugLoc()); + CurBuilder.setDebugLoc(Inst.getDebugLoc()); switch(Inst.getOpcode()) { - case Instruction::Add: - return translateBinaryOp(TargetOpcode::G_ADD, Inst); - case Instruction::Or: - return translateBinaryOp(TargetOpcode::G_OR, Inst); - case Instruction::Br: - return translateBr(Inst); - case Instruction::Ret: - return translateReturn(Inst); - +#define HANDLE_INST(NUM, OPCODE, CLASS) \ + case Instruction::OPCODE: return translate##OPCODE(Inst, CurBuilder); +#include "llvm/IR/Instruction.def" default: - llvm_unreachable("Opcode not supported"); + if (!TPC->isGlobalISelAbortEnabled()) + return false; + llvm_unreachable("unknown opcode"); } } +bool IRTranslator::translate(const Constant &C, unsigned Reg) { + if (auto CI = dyn_cast<ConstantInt>(&C)) + EntryBuilder.buildConstant(Reg, *CI); + else if (auto CF = dyn_cast<ConstantFP>(&C)) + EntryBuilder.buildFConstant(Reg, *CF); + else if (isa<UndefValue>(C)) + EntryBuilder.buildInstr(TargetOpcode::IMPLICIT_DEF).addDef(Reg); + else if (isa<ConstantPointerNull>(C)) + EntryBuilder.buildConstant(Reg, 0); + else if (auto GV = dyn_cast<GlobalValue>(&C)) + EntryBuilder.buildGlobalValue(Reg, GV); + else if (auto CE = dyn_cast<ConstantExpr>(&C)) { + switch(CE->getOpcode()) { +#define HANDLE_INST(NUM, OPCODE, CLASS) \ + case Instruction::OPCODE: return translate##OPCODE(*CE, EntryBuilder); +#include "llvm/IR/Instruction.def" + default: + if (!TPC->isGlobalISelAbortEnabled()) + return false; + llvm_unreachable("unknown opcode"); + } + } else if (!TPC->isGlobalISelAbortEnabled()) + return false; + else + llvm_unreachable("unhandled constant kind"); + + return true; +} -void IRTranslator::finalize() { +void IRTranslator::finalizeFunction() { // Release the memory used by the different maps we // needed during the translation. + PendingPHIs.clear(); ValToVReg.clear(); + FrameIndices.clear(); Constants.clear(); } -bool IRTranslator::runOnMachineFunction(MachineFunction &MF) { - const Function &F = *MF.getFunction(); +bool IRTranslator::runOnMachineFunction(MachineFunction &CurMF) { + MF = &CurMF; + const Function &F = *MF->getFunction(); if (F.empty()) return false; - CLI = MF.getSubtarget().getCallLowering(); - MIRBuilder.setMF(MF); - MRI = &MF.getRegInfo(); - // Setup the arguments. - MachineBasicBlock &MBB = getOrCreateBB(F.front()); - MIRBuilder.setMBB(MBB); + CLI = MF->getSubtarget().getCallLowering(); + CurBuilder.setMF(*MF); + EntryBuilder.setMF(*MF); + MRI = &MF->getRegInfo(); + DL = &F.getParent()->getDataLayout(); + TPC = &getAnalysis<TargetPassConfig>(); + + assert(PendingPHIs.empty() && "stale PHIs"); + + // Setup a separate basic-block for the arguments and constants, falling + // through to the IR-level Function's entry block. + MachineBasicBlock *EntryBB = MF->CreateMachineBasicBlock(); + MF->push_back(EntryBB); + EntryBB->addSuccessor(&getOrCreateBB(F.front())); + EntryBuilder.setMBB(*EntryBB); + + // Lower the actual args into this basic block. SmallVector<unsigned, 8> VRegArgs; for (const Argument &Arg: F.args()) VRegArgs.push_back(getOrCreateVReg(Arg)); - bool Succeeded = - CLI->lowerFormalArguments(MIRBuilder, F.getArgumentList(), VRegArgs); - if (!Succeeded) + bool Succeeded = CLI->lowerFormalArguments(EntryBuilder, F, VRegArgs); + if (!Succeeded) { + if (!TPC->isGlobalISelAbortEnabled()) { + MF->getProperties().set( + MachineFunctionProperties::Property::FailedISel); + finalizeFunction(); + return false; + } report_fatal_error("Unable to lower arguments"); + } + // And translate the function! for (const BasicBlock &BB: F) { MachineBasicBlock &MBB = getOrCreateBB(BB); // Set the insertion point of all the following translations to // the end of this basic block. - MIRBuilder.setMBB(MBB); + CurBuilder.setMBB(MBB); + for (const Instruction &Inst: BB) { - bool Succeeded = translate(Inst); + Succeeded &= translate(Inst); if (!Succeeded) { - DEBUG(dbgs() << "Cannot translate: " << Inst << '\n'); - report_fatal_error("Unable to translate instruction"); + if (TPC->isGlobalISelAbortEnabled()) + reportTranslationError(Inst, "unable to translate instruction"); + MF->getProperties().set( + MachineFunctionProperties::Property::FailedISel); + break; } } } - // Now that the MachineFrameInfo has been configured, no further changes to - // the reserved registers are possible. - MRI->freezeReservedRegs(MF); + if (Succeeded) { + 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); + + assert(&MF->front() == &NewEntryBB && + "New entry wasn't next in the list of basic block!"); + } + + finalizeFunction(); return false; } diff --git a/contrib/llvm/lib/CodeGen/GlobalISel/InstructionSelect.cpp b/contrib/llvm/lib/CodeGen/GlobalISel/InstructionSelect.cpp new file mode 100644 index 0000000..1d205cd --- /dev/null +++ b/contrib/llvm/lib/CodeGen/GlobalISel/InstructionSelect.cpp @@ -0,0 +1,175 @@ +//===- llvm/CodeGen/GlobalISel/InstructionSelect.cpp - InstructionSelect ---==// +// +// 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 InstructionSelect class. +//===----------------------------------------------------------------------===// + +#include "llvm/CodeGen/GlobalISel/InstructionSelect.h" +#include "llvm/ADT/PostOrderIterator.h" +#include "llvm/ADT/Twine.h" +#include "llvm/CodeGen/GlobalISel/InstructionSelector.h" +#include "llvm/CodeGen/GlobalISel/LegalizerInfo.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/TargetPassConfig.h" +#include "llvm/IR/Function.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Target/TargetSubtargetInfo.h" + +#define DEBUG_TYPE "instruction-select" + +using namespace llvm; + +char InstructionSelect::ID = 0; +INITIALIZE_PASS_BEGIN(InstructionSelect, DEBUG_TYPE, + "Select target instructions out of generic instructions", + false, false) +INITIALIZE_PASS_DEPENDENCY(TargetPassConfig) +INITIALIZE_PASS_END(InstructionSelect, DEBUG_TYPE, + "Select target instructions out of generic instructions", + false, false) + +InstructionSelect::InstructionSelect() : MachineFunctionPass(ID) { + initializeInstructionSelectPass(*PassRegistry::getPassRegistry()); +} + +void InstructionSelect::getAnalysisUsage(AnalysisUsage &AU) const { + AU.addRequired<TargetPassConfig>(); + MachineFunctionPass::getAnalysisUsage(AU); +} + +static void reportSelectionError(const MachineInstr *MI, const Twine &Message) { + const MachineFunction &MF = *MI->getParent()->getParent(); + std::string ErrStorage; + raw_string_ostream Err(ErrStorage); + Err << Message << ":\nIn function: " << MF.getName() << '\n'; + if (MI) + Err << *MI << '\n'; + report_fatal_error(Err.str()); +} + +bool InstructionSelect::runOnMachineFunction(MachineFunction &MF) { + // If the ISel pipeline failed, do not bother running that pass. + if (MF.getProperties().hasProperty( + MachineFunctionProperties::Property::FailedISel)) + return false; + + DEBUG(dbgs() << "Selecting function: " << MF.getName() << '\n'); + + const TargetPassConfig &TPC = getAnalysis<TargetPassConfig>(); + const InstructionSelector *ISel = MF.getSubtarget().getInstructionSelector(); + assert(ISel && "Cannot work without InstructionSelector"); + + // FIXME: freezeReservedRegs is now done in IRTranslator, but there are many + // other MF/MFI fields we need to initialize. + + const MachineRegisterInfo &MRI = MF.getRegInfo(); + +#ifndef NDEBUG + // Check that our input is fully legal: we require the function to have the + // Legalized property, so it should be. + // FIXME: This should be in the MachineVerifier, but it can't use the + // LegalizerInfo as it's currently in the separate GlobalISel library. + // The RegBankSelected property is already checked in the verifier. Note + // that it has the same layering problem, but we only use inline methods so + // end up not needing to link against the GlobalISel library. + if (const LegalizerInfo *MLI = MF.getSubtarget().getLegalizerInfo()) + for (const MachineBasicBlock &MBB : MF) + for (const MachineInstr &MI : MBB) + if (isPreISelGenericOpcode(MI.getOpcode()) && !MLI->isLegal(MI, MRI)) + reportSelectionError(&MI, "Instruction is not legal"); + +#endif + // FIXME: We could introduce new blocks and will need to fix the outer loop. + // Until then, keep track of the number of blocks to assert that we don't. + const size_t NumBlocks = MF.size(); + + bool Failed = false; + for (MachineBasicBlock *MBB : post_order(&MF)) { + if (MBB->empty()) + continue; + + // Select instructions in reverse block order. We permit erasing so have + // to resort to manually iterating and recognizing the begin (rend) case. + bool ReachedBegin = false; + for (auto MII = std::prev(MBB->end()), Begin = MBB->begin(); + !ReachedBegin;) { +#ifndef NDEBUG + // Keep track of the insertion range for debug printing. + const auto AfterIt = std::next(MII); +#endif + // Select this instruction. + MachineInstr &MI = *MII; + + // And have our iterator point to the next instruction, if there is one. + if (MII == Begin) + ReachedBegin = true; + else + --MII; + + DEBUG(dbgs() << "Selecting: \n " << MI); + + if (!ISel->select(MI)) { + if (TPC.isGlobalISelAbortEnabled()) + // FIXME: It would be nice to dump all inserted instructions. It's + // not + // obvious how, esp. considering select() can insert after MI. + reportSelectionError(&MI, "Cannot select"); + Failed = true; + break; + } + + // Dump the range of instructions that MI expanded into. + DEBUG({ + auto InsertedBegin = ReachedBegin ? MBB->begin() : std::next(MII); + dbgs() << "Into:\n"; + for (auto &InsertedMI : make_range(InsertedBegin, AfterIt)) + dbgs() << " " << InsertedMI; + dbgs() << '\n'; + }); + } + } + + // Now that selection is complete, there are no more generic vregs. Verify + // that the size of the now-constrained vreg is unchanged and that it has a + // register class. + for (auto &VRegToType : MRI.getVRegToType()) { + unsigned VReg = VRegToType.first; + auto *RC = MRI.getRegClassOrNull(VReg); + auto *MI = MRI.def_instr_begin(VReg) == MRI.def_instr_end() + ? nullptr + : &*MRI.def_instr_begin(VReg); + if (!RC) { + if (TPC.isGlobalISelAbortEnabled()) + reportSelectionError(MI, "VReg as no regclass after selection"); + Failed = true; + break; + } + + if (VRegToType.second.isValid() && + VRegToType.second.getSizeInBits() > (RC->getSize() * 8)) { + if (TPC.isGlobalISelAbortEnabled()) + reportSelectionError( + MI, "VReg has explicit size different from class size"); + Failed = true; + break; + } + } + + MRI.getVRegToType().clear(); + + if (!TPC.isGlobalISelAbortEnabled() && (Failed || MF.size() != NumBlocks)) { + MF.getProperties().set(MachineFunctionProperties::Property::FailedISel); + return false; + } + assert(MF.size() == NumBlocks && "Inserting blocks is not supported yet"); + + // FIXME: Should we accurately track changes? + return true; +} diff --git a/contrib/llvm/lib/CodeGen/GlobalISel/InstructionSelector.cpp b/contrib/llvm/lib/CodeGen/GlobalISel/InstructionSelector.cpp new file mode 100644 index 0000000..5c34da0 --- /dev/null +++ b/contrib/llvm/lib/CodeGen/GlobalISel/InstructionSelector.cpp @@ -0,0 +1,60 @@ +//===- llvm/CodeGen/GlobalISel/InstructionSelector.cpp -----------*- 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 InstructionSelector class. +//===----------------------------------------------------------------------===// + +#include "llvm/CodeGen/GlobalISel/InstructionSelector.h" +#include "llvm/CodeGen/GlobalISel/RegisterBankInfo.h" +#include "llvm/CodeGen/GlobalISel/Utils.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/Target/TargetInstrInfo.h" +#include "llvm/Target/TargetRegisterInfo.h" + +#define DEBUG_TYPE "instructionselector" + +using namespace llvm; + +InstructionSelector::InstructionSelector() {} + +bool InstructionSelector::constrainSelectedInstRegOperands( + MachineInstr &I, const TargetInstrInfo &TII, const TargetRegisterInfo &TRI, + const RegisterBankInfo &RBI) const { + MachineBasicBlock &MBB = *I.getParent(); + MachineFunction &MF = *MBB.getParent(); + MachineRegisterInfo &MRI = MF.getRegInfo(); + + for (unsigned OpI = 0, OpE = I.getNumExplicitOperands(); OpI != OpE; ++OpI) { + MachineOperand &MO = I.getOperand(OpI); + + // There's nothing to be done on non-register operands. + if (!MO.isReg()) + continue; + + DEBUG(dbgs() << "Converting operand: " << MO << '\n'); + assert(MO.isReg() && "Unsupported non-reg operand"); + + unsigned Reg = MO.getReg(); + // Physical registers don't need to be constrained. + if (TRI.isPhysicalRegister(Reg)) + continue; + + // Register operands with a value of 0 (e.g. predicate operands) don't need + // to be constrained. + if (Reg == 0) + continue; + + // If the operand is a vreg, we should constrain its regclass, and only + // insert COPYs if that's impossible. + // constrainOperandRegClass does that for us. + MO.setReg(constrainOperandRegClass(MF, TRI, MRI, TII, RBI, I, I.getDesc(), + Reg, OpI)); + } + return true; +} diff --git a/contrib/llvm/lib/CodeGen/GlobalISel/Legalizer.cpp b/contrib/llvm/lib/CodeGen/GlobalISel/Legalizer.cpp new file mode 100644 index 0000000..e863568 --- /dev/null +++ b/contrib/llvm/lib/CodeGen/GlobalISel/Legalizer.cpp @@ -0,0 +1,180 @@ +//===-- llvm/CodeGen/GlobalISel/Legalizer.cpp -----------------------------===// +// +// 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 LegalizerHelper class to legalize individual +/// instructions and the LegalizePass wrapper pass for the primary +/// legalization. +// +//===----------------------------------------------------------------------===// + +#include "llvm/CodeGen/GlobalISel/Legalizer.h" +#include "llvm/CodeGen/GlobalISel/LegalizerHelper.h" +#include "llvm/CodeGen/GlobalISel/Legalizer.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/TargetPassConfig.h" +#include "llvm/Support/Debug.h" +#include "llvm/Target/TargetInstrInfo.h" +#include "llvm/Target/TargetSubtargetInfo.h" + +#define DEBUG_TYPE "legalizer" + +using namespace llvm; + +char Legalizer::ID = 0; +INITIALIZE_PASS_BEGIN(Legalizer, DEBUG_TYPE, + "Legalize the Machine IR a function's Machine IR", false, + false) +INITIALIZE_PASS_DEPENDENCY(TargetPassConfig) +INITIALIZE_PASS_END(Legalizer, DEBUG_TYPE, + "Legalize the Machine IR a function's Machine IR", false, + false) + +Legalizer::Legalizer() : MachineFunctionPass(ID) { + initializeLegalizerPass(*PassRegistry::getPassRegistry()); +} + +void Legalizer::getAnalysisUsage(AnalysisUsage &AU) const { + AU.addRequired<TargetPassConfig>(); + MachineFunctionPass::getAnalysisUsage(AU); +} + +void Legalizer::init(MachineFunction &MF) { +} + +bool Legalizer::combineExtracts(MachineInstr &MI, MachineRegisterInfo &MRI, + const TargetInstrInfo &TII) { + bool Changed = false; + if (MI.getOpcode() != TargetOpcode::G_EXTRACT) + return Changed; + + unsigned NumDefs = (MI.getNumOperands() - 1) / 2; + unsigned SrcReg = MI.getOperand(NumDefs).getReg(); + MachineInstr &SeqI = *MRI.def_instr_begin(SrcReg); + if (SeqI.getOpcode() != TargetOpcode::G_SEQUENCE) + return Changed; + + unsigned NumSeqSrcs = (SeqI.getNumOperands() - 1) / 2; + bool AllDefsReplaced = true; + + // Try to match each register extracted with a corresponding insertion formed + // by the G_SEQUENCE. + for (unsigned Idx = 0, SeqIdx = 0; Idx < NumDefs; ++Idx) { + MachineOperand &ExtractMO = MI.getOperand(Idx); + assert(ExtractMO.isReg() && ExtractMO.isDef() && + "unexpected extract operand"); + + unsigned ExtractReg = ExtractMO.getReg(); + unsigned ExtractPos = MI.getOperand(NumDefs + Idx + 1).getImm(); + + while (SeqIdx < NumSeqSrcs && + SeqI.getOperand(2 * SeqIdx + 2).getImm() < ExtractPos) + ++SeqIdx; + + if (SeqIdx == NumSeqSrcs) { + AllDefsReplaced = false; + continue; + } + + unsigned OrigReg = SeqI.getOperand(2 * SeqIdx + 1).getReg(); + if (SeqI.getOperand(2 * SeqIdx + 2).getImm() != ExtractPos || + MRI.getType(OrigReg) != MRI.getType(ExtractReg)) { + AllDefsReplaced = false; + continue; + } + + assert(!TargetRegisterInfo::isPhysicalRegister(OrigReg) && + "unexpected physical register in G_SEQUENCE"); + + // Finally we can replace the uses. + for (auto &Use : MRI.use_operands(ExtractReg)) { + Changed = true; + Use.setReg(OrigReg); + } + } + + if (AllDefsReplaced) { + // If SeqI was the next instruction in the BB and we removed it, we'd break + // the outer iteration. + assert(std::next(MachineBasicBlock::iterator(MI)) != SeqI && + "G_SEQUENCE does not dominate G_EXTRACT"); + + MI.eraseFromParent(); + + if (MRI.use_empty(SrcReg)) + SeqI.eraseFromParent(); + Changed = true; + } + + return Changed; +} + +bool Legalizer::runOnMachineFunction(MachineFunction &MF) { + // If the ISel pipeline failed, do not bother running that pass. + if (MF.getProperties().hasProperty( + MachineFunctionProperties::Property::FailedISel)) + return false; + DEBUG(dbgs() << "Legalize Machine IR for: " << MF.getName() << '\n'); + init(MF); + const TargetPassConfig &TPC = getAnalysis<TargetPassConfig>(); + const LegalizerInfo &LegalizerInfo = *MF.getSubtarget().getLegalizerInfo(); + LegalizerHelper Helper(MF); + + // FIXME: an instruction may need more than one pass before it is legal. For + // example on most architectures <3 x i3> is doubly-illegal. It would + // typically proceed along a path like: <3 x i3> -> <3 x i8> -> <8 x i8>. We + // probably want a worklist of instructions rather than naive iterate until + // convergence for performance reasons. + bool Changed = false; + MachineBasicBlock::iterator NextMI; + for (auto &MBB : MF) + for (auto MI = MBB.begin(); MI != MBB.end(); MI = NextMI) { + // Get the next Instruction before we try to legalize, because there's a + // good chance MI will be deleted. + NextMI = std::next(MI); + + // Only legalize pre-isel generic instructions: others don't have types + // and are assumed to be legal. + if (!isPreISelGenericOpcode(MI->getOpcode())) + continue; + + auto Res = Helper.legalizeInstr(*MI, LegalizerInfo); + + // Error out if we couldn't legalize this instruction. We may want to fall + // back to DAG ISel instead in the future. + if (Res == LegalizerHelper::UnableToLegalize) { + if (!TPC.isGlobalISelAbortEnabled()) { + MF.getProperties().set( + MachineFunctionProperties::Property::FailedISel); + return false; + } + std::string Msg; + raw_string_ostream OS(Msg); + OS << "unable to legalize instruction: "; + MI->print(OS); + report_fatal_error(OS.str()); + } + + Changed |= Res == LegalizerHelper::Legalized; + } + + + MachineRegisterInfo &MRI = MF.getRegInfo(); + const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo(); + for (auto &MBB : MF) { + for (auto MI = MBB.begin(); MI != MBB.end(); MI = NextMI) { + // Get the next Instruction before we try to legalize, because there's a + // good chance MI will be deleted. + NextMI = std::next(MI); + + Changed |= combineExtracts(*MI, MRI, TII); + } + } + + return Changed; +} diff --git a/contrib/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/contrib/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp new file mode 100644 index 0000000..eb25b6c --- /dev/null +++ b/contrib/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp @@ -0,0 +1,354 @@ +//===-- llvm/CodeGen/GlobalISel/LegalizerHelper.cpp -----------------------===// +// +// 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 LegalizerHelper class to legalize +/// individual instructions and the LegalizeMachineIR wrapper pass for the +/// primary legalization. +// +//===----------------------------------------------------------------------===// + +#include "llvm/CodeGen/GlobalISel/LegalizerHelper.h" +#include "llvm/CodeGen/GlobalISel/CallLowering.h" +#include "llvm/CodeGen/GlobalISel/LegalizerInfo.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetLowering.h" +#include "llvm/Target/TargetSubtargetInfo.h" + +#include <sstream> + +#define DEBUG_TYPE "legalize-mir" + +using namespace llvm; + +LegalizerHelper::LegalizerHelper(MachineFunction &MF) + : MRI(MF.getRegInfo()) { + MIRBuilder.setMF(MF); +} + +LegalizerHelper::LegalizeResult +LegalizerHelper::legalizeInstrStep(MachineInstr &MI, + const LegalizerInfo &LegalizerInfo) { + auto Action = LegalizerInfo.getAction(MI, MRI); + switch (std::get<0>(Action)) { + case LegalizerInfo::Legal: + return AlreadyLegal; + case LegalizerInfo::Libcall: + return libcall(MI); + case LegalizerInfo::NarrowScalar: + return narrowScalar(MI, std::get<1>(Action), std::get<2>(Action)); + case LegalizerInfo::WidenScalar: + return widenScalar(MI, std::get<1>(Action), std::get<2>(Action)); + case LegalizerInfo::Lower: + return lower(MI, std::get<1>(Action), std::get<2>(Action)); + case LegalizerInfo::FewerElements: + return fewerElementsVector(MI, std::get<1>(Action), std::get<2>(Action)); + default: + return UnableToLegalize; + } +} + +LegalizerHelper::LegalizeResult +LegalizerHelper::legalizeInstr(MachineInstr &MI, + const LegalizerInfo &LegalizerInfo) { + SmallVector<MachineInstr *, 4> WorkList; + MIRBuilder.recordInsertions( + [&](MachineInstr *MI) { WorkList.push_back(MI); }); + WorkList.push_back(&MI); + + bool Changed = false; + LegalizeResult Res; + unsigned Idx = 0; + do { + Res = legalizeInstrStep(*WorkList[Idx], LegalizerInfo); + if (Res == UnableToLegalize) { + MIRBuilder.stopRecordingInsertions(); + return UnableToLegalize; + } + Changed |= Res == Legalized; + ++Idx; + } while (Idx < WorkList.size()); + + MIRBuilder.stopRecordingInsertions(); + + return Changed ? Legalized : AlreadyLegal; +} + +void LegalizerHelper::extractParts(unsigned Reg, LLT Ty, int NumParts, + SmallVectorImpl<unsigned> &VRegs) { + unsigned Size = Ty.getSizeInBits(); + SmallVector<uint64_t, 4> Indexes; + for (int i = 0; i < NumParts; ++i) { + VRegs.push_back(MRI.createGenericVirtualRegister(Ty)); + Indexes.push_back(i * Size); + } + MIRBuilder.buildExtract(VRegs, Indexes, Reg); +} + +LegalizerHelper::LegalizeResult +LegalizerHelper::libcall(MachineInstr &MI) { + LLT Ty = MRI.getType(MI.getOperand(0).getReg()); + unsigned Size = Ty.getSizeInBits(); + MIRBuilder.setInstr(MI); + + switch (MI.getOpcode()) { + default: + return UnableToLegalize; + case TargetOpcode::G_FREM: { + auto &Ctx = MIRBuilder.getMF().getFunction()->getContext(); + Type *Ty = Size == 64 ? Type::getDoubleTy(Ctx) : Type::getFloatTy(Ctx); + auto &CLI = *MIRBuilder.getMF().getSubtarget().getCallLowering(); + auto &TLI = *MIRBuilder.getMF().getSubtarget().getTargetLowering(); + const char *Name = + TLI.getLibcallName(Size == 64 ? RTLIB::REM_F64 : RTLIB::REM_F32); + + CLI.lowerCall( + MIRBuilder, MachineOperand::CreateES(Name), + {MI.getOperand(0).getReg(), Ty}, + {{MI.getOperand(1).getReg(), Ty}, {MI.getOperand(2).getReg(), Ty}}); + MI.eraseFromParent(); + return Legalized; + } + } +} + +LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI, + unsigned TypeIdx, + LLT NarrowTy) { + // FIXME: Don't know how to handle secondary types yet. + if (TypeIdx != 0) + return UnableToLegalize; + switch (MI.getOpcode()) { + default: + return UnableToLegalize; + case TargetOpcode::G_ADD: { + // Expand in terms of carry-setting/consuming G_ADDE instructions. + unsigned NarrowSize = NarrowTy.getSizeInBits(); + int NumParts = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits() / + NarrowTy.getSizeInBits(); + + MIRBuilder.setInstr(MI); + + SmallVector<unsigned, 2> Src1Regs, Src2Regs, DstRegs; + SmallVector<uint64_t, 2> Indexes; + extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, Src1Regs); + extractParts(MI.getOperand(2).getReg(), NarrowTy, NumParts, Src2Regs); + + unsigned CarryIn = MRI.createGenericVirtualRegister(LLT::scalar(1)); + MIRBuilder.buildConstant(CarryIn, 0); + + for (int i = 0; i < NumParts; ++i) { + unsigned DstReg = MRI.createGenericVirtualRegister(NarrowTy); + unsigned CarryOut = MRI.createGenericVirtualRegister(LLT::scalar(1)); + + MIRBuilder.buildUAdde(DstReg, CarryOut, Src1Regs[i], + Src2Regs[i], CarryIn); + + DstRegs.push_back(DstReg); + Indexes.push_back(i * NarrowSize); + CarryIn = CarryOut; + } + unsigned DstReg = MI.getOperand(0).getReg(); + MIRBuilder.buildSequence(DstReg, DstRegs, Indexes); + MI.eraseFromParent(); + return Legalized; + } + } +} + +LegalizerHelper::LegalizeResult +LegalizerHelper::widenScalar(MachineInstr &MI, unsigned TypeIdx, LLT WideTy) { + MIRBuilder.setInstr(MI); + + switch (MI.getOpcode()) { + default: + return UnableToLegalize; + case TargetOpcode::G_ADD: + case TargetOpcode::G_AND: + case TargetOpcode::G_MUL: + case TargetOpcode::G_OR: + case TargetOpcode::G_XOR: + case TargetOpcode::G_SUB: { + // Perform operation at larger width (any extension is fine here, high bits + // don't affect the result) and then truncate the result back to the + // original type. + unsigned Src1Ext = MRI.createGenericVirtualRegister(WideTy); + unsigned Src2Ext = MRI.createGenericVirtualRegister(WideTy); + MIRBuilder.buildAnyExt(Src1Ext, MI.getOperand(1).getReg()); + MIRBuilder.buildAnyExt(Src2Ext, MI.getOperand(2).getReg()); + + unsigned DstExt = MRI.createGenericVirtualRegister(WideTy); + MIRBuilder.buildInstr(MI.getOpcode()) + .addDef(DstExt) + .addUse(Src1Ext) + .addUse(Src2Ext); + + MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), DstExt); + MI.eraseFromParent(); + return Legalized; + } + case TargetOpcode::G_SDIV: + case TargetOpcode::G_UDIV: { + unsigned ExtOp = MI.getOpcode() == TargetOpcode::G_SDIV + ? TargetOpcode::G_SEXT + : TargetOpcode::G_ZEXT; + + unsigned LHSExt = MRI.createGenericVirtualRegister(WideTy); + MIRBuilder.buildInstr(ExtOp).addDef(LHSExt).addUse( + MI.getOperand(1).getReg()); + + unsigned RHSExt = MRI.createGenericVirtualRegister(WideTy); + MIRBuilder.buildInstr(ExtOp).addDef(RHSExt).addUse( + MI.getOperand(2).getReg()); + + unsigned ResExt = MRI.createGenericVirtualRegister(WideTy); + MIRBuilder.buildInstr(MI.getOpcode()) + .addDef(ResExt) + .addUse(LHSExt) + .addUse(RHSExt); + + MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), ResExt); + MI.eraseFromParent(); + return Legalized; + } + case TargetOpcode::G_LOAD: { + assert(alignTo(MRI.getType(MI.getOperand(0).getReg()).getSizeInBits(), 8) == + WideTy.getSizeInBits() && + "illegal to increase number of bytes loaded"); + + unsigned DstExt = MRI.createGenericVirtualRegister(WideTy); + MIRBuilder.buildLoad(DstExt, MI.getOperand(1).getReg(), + **MI.memoperands_begin()); + MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), DstExt); + MI.eraseFromParent(); + return Legalized; + } + case TargetOpcode::G_STORE: { + assert(alignTo(MRI.getType(MI.getOperand(0).getReg()).getSizeInBits(), 8) == + WideTy.getSizeInBits() && + "illegal to increase number of bytes modified by a store"); + + unsigned SrcExt = MRI.createGenericVirtualRegister(WideTy); + MIRBuilder.buildAnyExt(SrcExt, MI.getOperand(0).getReg()); + MIRBuilder.buildStore(SrcExt, MI.getOperand(1).getReg(), + **MI.memoperands_begin()); + MI.eraseFromParent(); + return Legalized; + } + case TargetOpcode::G_CONSTANT: { + unsigned DstExt = MRI.createGenericVirtualRegister(WideTy); + MIRBuilder.buildConstant(DstExt, *MI.getOperand(1).getCImm()); + MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), DstExt); + MI.eraseFromParent(); + return Legalized; + } + case TargetOpcode::G_FCONSTANT: { + unsigned DstExt = MRI.createGenericVirtualRegister(WideTy); + MIRBuilder.buildFConstant(DstExt, *MI.getOperand(1).getFPImm()); + MIRBuilder.buildFPTrunc(MI.getOperand(0).getReg(), DstExt); + MI.eraseFromParent(); + return Legalized; + } + case TargetOpcode::G_BRCOND: { + unsigned TstExt = MRI.createGenericVirtualRegister(WideTy); + MIRBuilder.buildAnyExt(TstExt, MI.getOperand(0).getReg()); + MIRBuilder.buildBrCond(TstExt, *MI.getOperand(1).getMBB()); + MI.eraseFromParent(); + return Legalized; + } + case TargetOpcode::G_ICMP: { + assert(TypeIdx == 1 && "unable to legalize predicate"); + bool IsSigned = CmpInst::isSigned( + static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate())); + unsigned Op0Ext = MRI.createGenericVirtualRegister(WideTy); + unsigned Op1Ext = MRI.createGenericVirtualRegister(WideTy); + if (IsSigned) { + MIRBuilder.buildSExt(Op0Ext, MI.getOperand(2).getReg()); + MIRBuilder.buildSExt(Op1Ext, MI.getOperand(3).getReg()); + } else { + MIRBuilder.buildZExt(Op0Ext, MI.getOperand(2).getReg()); + MIRBuilder.buildZExt(Op1Ext, MI.getOperand(3).getReg()); + } + MIRBuilder.buildICmp( + static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate()), + MI.getOperand(0).getReg(), Op0Ext, Op1Ext); + MI.eraseFromParent(); + return Legalized; + } + case TargetOpcode::G_GEP: { + assert(TypeIdx == 1 && "unable to legalize pointer of GEP"); + unsigned OffsetExt = MRI.createGenericVirtualRegister(WideTy); + MIRBuilder.buildSExt(OffsetExt, MI.getOperand(2).getReg()); + MI.getOperand(2).setReg(OffsetExt); + return Legalized; + } + } +} + +LegalizerHelper::LegalizeResult +LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT Ty) { + using namespace TargetOpcode; + MIRBuilder.setInstr(MI); + + switch(MI.getOpcode()) { + default: + return UnableToLegalize; + case TargetOpcode::G_SREM: + case TargetOpcode::G_UREM: { + unsigned QuotReg = MRI.createGenericVirtualRegister(Ty); + MIRBuilder.buildInstr(MI.getOpcode() == G_SREM ? G_SDIV : G_UDIV) + .addDef(QuotReg) + .addUse(MI.getOperand(1).getReg()) + .addUse(MI.getOperand(2).getReg()); + + unsigned ProdReg = MRI.createGenericVirtualRegister(Ty); + MIRBuilder.buildMul(ProdReg, QuotReg, MI.getOperand(2).getReg()); + MIRBuilder.buildSub(MI.getOperand(0).getReg(), MI.getOperand(1).getReg(), + ProdReg); + MI.eraseFromParent(); + return Legalized; + } + } +} + +LegalizerHelper::LegalizeResult +LegalizerHelper::fewerElementsVector(MachineInstr &MI, unsigned TypeIdx, + LLT NarrowTy) { + // FIXME: Don't know how to handle secondary types yet. + if (TypeIdx != 0) + return UnableToLegalize; + switch (MI.getOpcode()) { + default: + return UnableToLegalize; + case TargetOpcode::G_ADD: { + unsigned NarrowSize = NarrowTy.getSizeInBits(); + unsigned DstReg = MI.getOperand(0).getReg(); + int NumParts = MRI.getType(DstReg).getSizeInBits() / NarrowSize; + + MIRBuilder.setInstr(MI); + + SmallVector<unsigned, 2> Src1Regs, Src2Regs, DstRegs; + SmallVector<uint64_t, 2> Indexes; + extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, Src1Regs); + extractParts(MI.getOperand(2).getReg(), NarrowTy, NumParts, Src2Regs); + + for (int i = 0; i < NumParts; ++i) { + unsigned DstReg = MRI.createGenericVirtualRegister(NarrowTy); + MIRBuilder.buildAdd(DstReg, Src1Regs[i], Src2Regs[i]); + DstRegs.push_back(DstReg); + Indexes.push_back(i * NarrowSize); + } + + MIRBuilder.buildSequence(DstReg, DstRegs, Indexes); + MI.eraseFromParent(); + return Legalized; + } + } +} diff --git a/contrib/llvm/lib/CodeGen/GlobalISel/LegalizerInfo.cpp b/contrib/llvm/lib/CodeGen/GlobalISel/LegalizerInfo.cpp new file mode 100644 index 0000000..e496620 --- /dev/null +++ b/contrib/llvm/lib/CodeGen/GlobalISel/LegalizerInfo.cpp @@ -0,0 +1,182 @@ +//===---- lib/CodeGen/GlobalISel/LegalizerInfo.cpp - Legalizer -------==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Implement an interface to specify and query how an illegal operation on a +// given type should be expanded. +// +// Issues to be resolved: +// + Make it fast. +// + Support weird types like i3, <7 x i3>, ... +// + Operations with more than one type (ICMP, CMPXCHG, intrinsics, ...) +// +//===----------------------------------------------------------------------===// + +#include "llvm/CodeGen/GlobalISel/LegalizerInfo.h" + +#include "llvm/ADT/SmallBitVector.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/ValueTypes.h" +#include "llvm/IR/Type.h" +#include "llvm/Target/TargetOpcodes.h" +using namespace llvm; + +LegalizerInfo::LegalizerInfo() : TablesInitialized(false) { + // FIXME: these two can be legalized to the fundamental load/store Jakob + // proposed. Once loads & stores are supported. + DefaultActions[TargetOpcode::G_ANYEXT] = Legal; + DefaultActions[TargetOpcode::G_TRUNC] = Legal; + + DefaultActions[TargetOpcode::G_INTRINSIC] = Legal; + DefaultActions[TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS] = Legal; + + DefaultActions[TargetOpcode::G_ADD] = NarrowScalar; + DefaultActions[TargetOpcode::G_LOAD] = NarrowScalar; + DefaultActions[TargetOpcode::G_STORE] = NarrowScalar; + + DefaultActions[TargetOpcode::G_BRCOND] = WidenScalar; +} + +void LegalizerInfo::computeTables() { + for (unsigned Opcode = 0; Opcode <= LastOp - FirstOp; ++Opcode) { + for (unsigned Idx = 0; Idx != Actions[Opcode].size(); ++Idx) { + for (auto &Action : Actions[Opcode][Idx]) { + LLT Ty = Action.first; + if (!Ty.isVector()) + continue; + + auto &Entry = MaxLegalVectorElts[std::make_pair(Opcode + FirstOp, + Ty.getElementType())]; + Entry = std::max(Entry, Ty.getNumElements()); + } + } + } + + TablesInitialized = true; +} + +// FIXME: inefficient implementation for now. Without ComputeValueVTs we're +// probably going to need specialized lookup structures for various types before +// we have any hope of doing well with something like <13 x i3>. Even the common +// cases should do better than what we have now. +std::pair<LegalizerInfo::LegalizeAction, LLT> +LegalizerInfo::getAction(const InstrAspect &Aspect) const { + assert(TablesInitialized && "backend forgot to call computeTables"); + // These *have* to be implemented for now, they're the fundamental basis of + // how everything else is transformed. + + // Nothing is going to go well with types that aren't a power of 2 yet, so + // don't even try because we might make things worse. + if (!isPowerOf2_64(Aspect.Type.getSizeInBits())) + return std::make_pair(Unsupported, LLT()); + + // FIXME: the long-term plan calls for expansion in terms of load/store (if + // they're not legal). + if (Aspect.Opcode == TargetOpcode::G_SEQUENCE || + Aspect.Opcode == TargetOpcode::G_EXTRACT) + return std::make_pair(Legal, Aspect.Type); + + LegalizeAction Action = findInActions(Aspect); + if (Action != NotFound) + return findLegalAction(Aspect, Action); + + unsigned Opcode = Aspect.Opcode; + LLT Ty = Aspect.Type; + if (!Ty.isVector()) { + auto DefaultAction = DefaultActions.find(Aspect.Opcode); + if (DefaultAction != DefaultActions.end() && DefaultAction->second == Legal) + return std::make_pair(Legal, Ty); + + if (DefaultAction == DefaultActions.end() || + DefaultAction->second != NarrowScalar) + return std::make_pair(Unsupported, LLT()); + return findLegalAction(Aspect, NarrowScalar); + } + + LLT EltTy = Ty.getElementType(); + int NumElts = Ty.getNumElements(); + + auto ScalarAction = ScalarInVectorActions.find(std::make_pair(Opcode, EltTy)); + if (ScalarAction != ScalarInVectorActions.end() && + ScalarAction->second != Legal) + return findLegalAction(Aspect, ScalarAction->second); + + // The element type is legal in principle, but the number of elements is + // wrong. + auto MaxLegalElts = MaxLegalVectorElts.lookup(std::make_pair(Opcode, EltTy)); + if (MaxLegalElts > NumElts) + return findLegalAction(Aspect, MoreElements); + + if (MaxLegalElts == 0) { + // Scalarize if there's no legal vector type, which is just a special case + // of FewerElements. + return std::make_pair(FewerElements, EltTy); + } + + return findLegalAction(Aspect, FewerElements); +} + +std::tuple<LegalizerInfo::LegalizeAction, unsigned, LLT> +LegalizerInfo::getAction(const MachineInstr &MI, + const MachineRegisterInfo &MRI) const { + SmallBitVector SeenTypes(8); + const MCOperandInfo *OpInfo = MI.getDesc().OpInfo; + for (unsigned i = 0; i < MI.getDesc().getNumOperands(); ++i) { + if (!OpInfo[i].isGenericType()) + continue; + + // We don't want to repeatedly check the same operand index, that + // could get expensive. + unsigned TypeIdx = OpInfo[i].getGenericTypeIndex(); + if (SeenTypes[TypeIdx]) + continue; + + SeenTypes.set(TypeIdx); + + LLT Ty = MRI.getType(MI.getOperand(i).getReg()); + auto Action = getAction({MI.getOpcode(), TypeIdx, Ty}); + if (Action.first != Legal) + return std::make_tuple(Action.first, TypeIdx, Action.second); + } + return std::make_tuple(Legal, 0, LLT{}); +} + +bool LegalizerInfo::isLegal(const MachineInstr &MI, + const MachineRegisterInfo &MRI) const { + return std::get<0>(getAction(MI, MRI)) == Legal; +} + +LLT LegalizerInfo::findLegalType(const InstrAspect &Aspect, + LegalizeAction Action) const { + switch(Action) { + default: + llvm_unreachable("Cannot find legal type"); + case Legal: + case Lower: + case Libcall: + return Aspect.Type; + case NarrowScalar: { + return findLegalType(Aspect, + [&](LLT Ty) -> LLT { return Ty.halfScalarSize(); }); + } + case WidenScalar: { + return findLegalType(Aspect, [&](LLT Ty) -> LLT { + return Ty.getSizeInBits() < 8 ? LLT::scalar(8) : Ty.doubleScalarSize(); + }); + } + case FewerElements: { + return findLegalType(Aspect, + [&](LLT Ty) -> LLT { return Ty.halfElements(); }); + } + case MoreElements: { + return findLegalType(Aspect, + [&](LLT Ty) -> LLT { return Ty.doubleElements(); }); + } + } +} diff --git a/contrib/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp b/contrib/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp index 2f19bcf..c04f6e4 100644 --- a/contrib/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp +++ b/contrib/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp @@ -14,6 +14,7 @@ #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/Target/TargetInstrInfo.h" #include "llvm/Target/TargetOpcodes.h" #include "llvm/Target/TargetSubtargetInfo.h" @@ -23,82 +24,408 @@ using namespace llvm; void MachineIRBuilder::setMF(MachineFunction &MF) { this->MF = &MF; this->MBB = nullptr; + this->MRI = &MF.getRegInfo(); this->TII = MF.getSubtarget().getInstrInfo(); this->DL = DebugLoc(); - this->MI = nullptr; + this->II = MachineBasicBlock::iterator(); + this->InsertedInstr = nullptr; } -void MachineIRBuilder::setMBB(MachineBasicBlock &MBB, bool Beginning) { +void MachineIRBuilder::setMBB(MachineBasicBlock &MBB) { this->MBB = &MBB; - Before = Beginning; + this->II = MBB.end(); assert(&getMF() == MBB.getParent() && "Basic block is in a different function"); } -void MachineIRBuilder::setInstr(MachineInstr &MI, bool Before) { +void MachineIRBuilder::setInstr(MachineInstr &MI) { assert(MI.getParent() && "Instruction is not part of a basic block"); setMBB(*MI.getParent()); - this->MI = &MI; - this->Before = Before; + this->II = MI.getIterator(); } -MachineBasicBlock::iterator MachineIRBuilder::getInsertPt() { - if (MI) { - if (Before) - return MI; - if (!MI->getNextNode()) - return getMBB().end(); - return MI->getNextNode(); - } - return Before ? getMBB().begin() : getMBB().end(); +void MachineIRBuilder::setInsertPt(MachineBasicBlock &MBB, + MachineBasicBlock::iterator II) { + assert(MBB.getParent() == &getMF() && + "Basic block is in a different function"); + this->MBB = &MBB; + this->II = II; +} + +void MachineIRBuilder::recordInsertions( + std::function<void(MachineInstr *)> Inserted) { + InsertedInstr = Inserted; +} + +void MachineIRBuilder::stopRecordingInsertions() { + InsertedInstr = nullptr; } //------------------------------------------------------------------------------ // Build instruction variants. //------------------------------------------------------------------------------ -MachineInstr *MachineIRBuilder::buildInstr(unsigned Opcode, Type *Ty) { - MachineInstr *NewMI = BuildMI(getMF(), DL, getTII().get(Opcode)); - if (Ty) { - assert(isPreISelGenericOpcode(Opcode) && - "Only generic instruction can have a type"); - NewMI->setType(Ty); - } else - assert(!isPreISelGenericOpcode(Opcode) && - "Generic instruction must have a type"); - getMBB().insert(getInsertPt(), NewMI); - return NewMI; + +MachineInstrBuilder MachineIRBuilder::buildInstr(unsigned Opcode) { + return insertInstr(buildInstrNoInsert(Opcode)); } -MachineInstr *MachineIRBuilder::buildInstr(unsigned Opcode, unsigned Res, - unsigned Op0, unsigned Op1) { - return buildInstr(Opcode, nullptr, Res, Op0, Op1); +MachineInstrBuilder MachineIRBuilder::buildInstrNoInsert(unsigned Opcode) { + MachineInstrBuilder MIB = BuildMI(getMF(), DL, getTII().get(Opcode)); + return MIB; } -MachineInstr *MachineIRBuilder::buildInstr(unsigned Opcode, Type *Ty, - unsigned Res, unsigned Op0, - unsigned Op1) { - MachineInstr *NewMI = buildInstr(Opcode, Ty); - MachineInstrBuilder(getMF(), NewMI) - .addReg(Res, RegState::Define) - .addReg(Op0) - .addReg(Op1); - return NewMI; + +MachineInstrBuilder MachineIRBuilder::insertInstr(MachineInstrBuilder MIB) { + getMBB().insert(getInsertPt(), MIB); + if (InsertedInstr) + InsertedInstr(MIB); + return MIB; } -MachineInstr *MachineIRBuilder::buildInstr(unsigned Opcode, unsigned Res, - unsigned Op0) { - MachineInstr *NewMI = buildInstr(Opcode, nullptr); - MachineInstrBuilder(getMF(), NewMI).addReg(Res, RegState::Define).addReg(Op0); - return NewMI; +MachineInstrBuilder MachineIRBuilder::buildFrameIndex(unsigned Res, int Idx) { + assert(MRI->getType(Res).isPointer() && "invalid operand type"); + return buildInstr(TargetOpcode::G_FRAME_INDEX) + .addDef(Res) + .addFrameIndex(Idx); } -MachineInstr *MachineIRBuilder::buildInstr(unsigned Opcode) { - return buildInstr(Opcode, nullptr); +MachineInstrBuilder MachineIRBuilder::buildGlobalValue(unsigned Res, + const GlobalValue *GV) { + assert(MRI->getType(Res).isPointer() && "invalid operand type"); + assert(MRI->getType(Res).getAddressSpace() == + GV->getType()->getAddressSpace() && + "address space mismatch"); + + return buildInstr(TargetOpcode::G_GLOBAL_VALUE) + .addDef(Res) + .addGlobalAddress(GV); +} + +MachineInstrBuilder MachineIRBuilder::buildAdd(unsigned Res, unsigned Op0, + unsigned Op1) { + assert((MRI->getType(Res).isScalar() || MRI->getType(Res).isVector()) && + "invalid operand type"); + assert(MRI->getType(Res) == MRI->getType(Op0) && + MRI->getType(Res) == MRI->getType(Op1) && "type mismatch"); + + return buildInstr(TargetOpcode::G_ADD) + .addDef(Res) + .addUse(Op0) + .addUse(Op1); +} + +MachineInstrBuilder MachineIRBuilder::buildGEP(unsigned Res, unsigned Op0, + unsigned Op1) { + assert(MRI->getType(Res).isPointer() && + MRI->getType(Res) == MRI->getType(Op0) && "type mismatch"); + assert(MRI->getType(Op1).isScalar() && "invalid offset type"); + + return buildInstr(TargetOpcode::G_GEP) + .addDef(Res) + .addUse(Op0) + .addUse(Op1); +} + +MachineInstrBuilder MachineIRBuilder::buildSub(unsigned Res, unsigned Op0, + unsigned Op1) { + assert((MRI->getType(Res).isScalar() || MRI->getType(Res).isVector()) && + "invalid operand type"); + assert(MRI->getType(Res) == MRI->getType(Op0) && + MRI->getType(Res) == MRI->getType(Op1) && "type mismatch"); + + return buildInstr(TargetOpcode::G_SUB) + .addDef(Res) + .addUse(Op0) + .addUse(Op1); +} + +MachineInstrBuilder MachineIRBuilder::buildMul(unsigned Res, unsigned Op0, + unsigned Op1) { + assert((MRI->getType(Res).isScalar() || MRI->getType(Res).isVector()) && + "invalid operand type"); + assert(MRI->getType(Res) == MRI->getType(Op0) && + MRI->getType(Res) == MRI->getType(Op1) && "type mismatch"); + + return buildInstr(TargetOpcode::G_MUL) + .addDef(Res) + .addUse(Op0) + .addUse(Op1); } -MachineInstr *MachineIRBuilder::buildInstr(unsigned Opcode, Type *Ty, - MachineBasicBlock &BB) { - MachineInstr *NewMI = buildInstr(Opcode, Ty); - MachineInstrBuilder(getMF(), NewMI).addMBB(&BB); - return NewMI; +MachineInstrBuilder MachineIRBuilder::buildBr(MachineBasicBlock &Dest) { + return buildInstr(TargetOpcode::G_BR).addMBB(&Dest); +} + +MachineInstrBuilder MachineIRBuilder::buildCopy(unsigned Res, unsigned Op) { + return buildInstr(TargetOpcode::COPY).addDef(Res).addUse(Op); +} + +MachineInstrBuilder MachineIRBuilder::buildConstant(unsigned Res, + const ConstantInt &Val) { + LLT Ty = MRI->getType(Res); + + assert((Ty.isScalar() || Ty.isPointer()) && "invalid operand type"); + + const ConstantInt *NewVal = &Val; + if (Ty.getSizeInBits() != Val.getBitWidth()) + NewVal = ConstantInt::get(MF->getFunction()->getContext(), + Val.getValue().sextOrTrunc(Ty.getSizeInBits())); + + return buildInstr(TargetOpcode::G_CONSTANT).addDef(Res).addCImm(NewVal); +} + +MachineInstrBuilder MachineIRBuilder::buildConstant(unsigned Res, + int64_t Val) { + auto IntN = IntegerType::get(MF->getFunction()->getContext(), + MRI->getType(Res).getSizeInBits()); + ConstantInt *CI = ConstantInt::get(IntN, Val, true); + return buildConstant(Res, *CI); +} + +MachineInstrBuilder MachineIRBuilder::buildFConstant(unsigned Res, + const ConstantFP &Val) { + assert(MRI->getType(Res).isScalar() && "invalid operand type"); + + return buildInstr(TargetOpcode::G_FCONSTANT).addDef(Res).addFPImm(&Val); +} + +MachineInstrBuilder MachineIRBuilder::buildBrCond(unsigned Tst, + MachineBasicBlock &Dest) { + assert(MRI->getType(Tst).isScalar() && "invalid operand type"); + + return buildInstr(TargetOpcode::G_BRCOND).addUse(Tst).addMBB(&Dest); +} + +MachineInstrBuilder MachineIRBuilder::buildLoad(unsigned Res, unsigned Addr, + MachineMemOperand &MMO) { + assert(MRI->getType(Res).isValid() && "invalid operand type"); + assert(MRI->getType(Addr).isPointer() && "invalid operand type"); + + return buildInstr(TargetOpcode::G_LOAD) + .addDef(Res) + .addUse(Addr) + .addMemOperand(&MMO); +} + +MachineInstrBuilder MachineIRBuilder::buildStore(unsigned Val, unsigned Addr, + MachineMemOperand &MMO) { + assert(MRI->getType(Val).isValid() && "invalid operand type"); + assert(MRI->getType(Addr).isPointer() && "invalid operand type"); + + return buildInstr(TargetOpcode::G_STORE) + .addUse(Val) + .addUse(Addr) + .addMemOperand(&MMO); +} + +MachineInstrBuilder MachineIRBuilder::buildUAdde(unsigned Res, + unsigned CarryOut, + unsigned Op0, unsigned Op1, + unsigned CarryIn) { + assert(MRI->getType(Res).isScalar() && "invalid operand type"); + assert(MRI->getType(Res) == MRI->getType(Op0) && + MRI->getType(Res) == MRI->getType(Op1) && "type mismatch"); + assert(MRI->getType(CarryOut).isScalar() && "invalid operand type"); + assert(MRI->getType(CarryOut) == MRI->getType(CarryIn) && "type mismatch"); + + return buildInstr(TargetOpcode::G_UADDE) + .addDef(Res) + .addDef(CarryOut) + .addUse(Op0) + .addUse(Op1) + .addUse(CarryIn); +} + +MachineInstrBuilder MachineIRBuilder::buildAnyExt(unsigned Res, unsigned Op) { + validateTruncExt(Res, Op, true); + return buildInstr(TargetOpcode::G_ANYEXT).addDef(Res).addUse(Op); +} + +MachineInstrBuilder MachineIRBuilder::buildSExt(unsigned Res, unsigned Op) { + validateTruncExt(Res, Op, true); + return buildInstr(TargetOpcode::G_SEXT).addDef(Res).addUse(Op); +} + +MachineInstrBuilder MachineIRBuilder::buildZExt(unsigned Res, unsigned Op) { + validateTruncExt(Res, Op, true); + return buildInstr(TargetOpcode::G_ZEXT).addDef(Res).addUse(Op); +} + +MachineInstrBuilder MachineIRBuilder::buildSExtOrTrunc(unsigned Res, + unsigned Op) { + unsigned Opcode = TargetOpcode::COPY; + if (MRI->getType(Res).getSizeInBits() > MRI->getType(Op).getSizeInBits()) + Opcode = TargetOpcode::G_SEXT; + else if (MRI->getType(Res).getSizeInBits() < MRI->getType(Op).getSizeInBits()) + Opcode = TargetOpcode::G_TRUNC; + + return buildInstr(Opcode).addDef(Res).addUse(Op); +} + +MachineInstrBuilder MachineIRBuilder::buildExtract(ArrayRef<unsigned> Results, + ArrayRef<uint64_t> Indices, + unsigned Src) { +#ifndef NDEBUG + assert(Results.size() == Indices.size() && "inconsistent number of regs"); + assert(!Results.empty() && "invalid trivial extract"); + assert(std::is_sorted(Indices.begin(), Indices.end()) && + "extract offsets must be in ascending order"); + + assert(MRI->getType(Src).isValid() && "invalid operand type"); + for (auto Res : Results) + assert(MRI->getType(Res).isValid() && "invalid operand type"); +#endif + + auto MIB = BuildMI(getMF(), DL, getTII().get(TargetOpcode::G_EXTRACT)); + for (auto Res : Results) + MIB.addDef(Res); + + MIB.addUse(Src); + + for (auto Idx : Indices) + MIB.addImm(Idx); + + getMBB().insert(getInsertPt(), MIB); + if (InsertedInstr) + InsertedInstr(MIB); + + return MIB; +} + +MachineInstrBuilder +MachineIRBuilder::buildSequence(unsigned Res, + ArrayRef<unsigned> Ops, + ArrayRef<uint64_t> Indices) { +#ifndef NDEBUG + assert(Ops.size() == Indices.size() && "incompatible args"); + assert(!Ops.empty() && "invalid trivial sequence"); + assert(std::is_sorted(Indices.begin(), Indices.end()) && + "sequence offsets must be in ascending order"); + + assert(MRI->getType(Res).isValid() && "invalid operand type"); + for (auto Op : Ops) + assert(MRI->getType(Op).isValid() && "invalid operand type"); +#endif + + MachineInstrBuilder MIB = buildInstr(TargetOpcode::G_SEQUENCE); + MIB.addDef(Res); + for (unsigned i = 0; i < Ops.size(); ++i) { + MIB.addUse(Ops[i]); + MIB.addImm(Indices[i]); + } + return MIB; +} + +MachineInstrBuilder MachineIRBuilder::buildIntrinsic(Intrinsic::ID ID, + unsigned Res, + bool HasSideEffects) { + auto MIB = + buildInstr(HasSideEffects ? TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS + : TargetOpcode::G_INTRINSIC); + if (Res) + MIB.addDef(Res); + MIB.addIntrinsicID(ID); + return MIB; +} + +MachineInstrBuilder MachineIRBuilder::buildTrunc(unsigned Res, unsigned Op) { + validateTruncExt(Res, Op, false); + return buildInstr(TargetOpcode::G_TRUNC).addDef(Res).addUse(Op); +} + +MachineInstrBuilder MachineIRBuilder::buildFPTrunc(unsigned Res, unsigned Op) { + validateTruncExt(Res, Op, false); + return buildInstr(TargetOpcode::G_FPTRUNC).addDef(Res).addUse(Op); +} + +MachineInstrBuilder MachineIRBuilder::buildICmp(CmpInst::Predicate Pred, + unsigned Res, unsigned Op0, + unsigned Op1) { +#ifndef NDEBUG + assert(MRI->getType(Op0) == MRI->getType(Op0) && "type mismatch"); + assert(CmpInst::isIntPredicate(Pred) && "invalid predicate"); + if (MRI->getType(Op0).isScalar() || MRI->getType(Op0).isPointer()) + assert(MRI->getType(Res).isScalar() && "type mismatch"); + else + assert(MRI->getType(Res).isVector() && + MRI->getType(Res).getNumElements() == + MRI->getType(Op0).getNumElements() && + "type mismatch"); +#endif + + return buildInstr(TargetOpcode::G_ICMP) + .addDef(Res) + .addPredicate(Pred) + .addUse(Op0) + .addUse(Op1); +} + +MachineInstrBuilder MachineIRBuilder::buildFCmp(CmpInst::Predicate Pred, + unsigned Res, unsigned Op0, + unsigned Op1) { +#ifndef NDEBUG + assert((MRI->getType(Op0).isScalar() || MRI->getType(Op0).isVector()) && + "invalid operand type"); + assert(MRI->getType(Op0) == MRI->getType(Op1) && "type mismatch"); + assert(CmpInst::isFPPredicate(Pred) && "invalid predicate"); + if (MRI->getType(Op0).isScalar()) + assert(MRI->getType(Res).isScalar() && "type mismatch"); + else + assert(MRI->getType(Res).isVector() && + MRI->getType(Res).getNumElements() == + MRI->getType(Op0).getNumElements() && + "type mismatch"); +#endif + + return buildInstr(TargetOpcode::G_FCMP) + .addDef(Res) + .addPredicate(Pred) + .addUse(Op0) + .addUse(Op1); +} + +MachineInstrBuilder MachineIRBuilder::buildSelect(unsigned Res, unsigned Tst, + unsigned Op0, unsigned Op1) { +#ifndef NDEBUG + LLT ResTy = MRI->getType(Res); + assert((ResTy.isScalar() || ResTy.isVector() || ResTy.isPointer()) && + "invalid operand type"); + assert(ResTy == MRI->getType(Op0) && ResTy == MRI->getType(Op1) && + "type mismatch"); + if (ResTy.isScalar() || ResTy.isPointer()) + assert(MRI->getType(Tst).isScalar() && "type mismatch"); + else + assert(MRI->getType(Tst).isVector() && + MRI->getType(Tst).getNumElements() == + MRI->getType(Op0).getNumElements() && + "type mismatch"); +#endif + + return buildInstr(TargetOpcode::G_SELECT) + .addDef(Res) + .addUse(Tst) + .addUse(Op0) + .addUse(Op1); +} + +void MachineIRBuilder::validateTruncExt(unsigned Dst, unsigned Src, + bool IsExtend) { +#ifndef NDEBUG + LLT SrcTy = MRI->getType(Src); + LLT DstTy = MRI->getType(Dst); + + if (DstTy.isVector()) { + assert(SrcTy.isVector() && "mismatched cast between vecot and non-vector"); + assert(SrcTy.getNumElements() == DstTy.getNumElements() && + "different number of elements in a trunc/ext"); + } else + assert(DstTy.isScalar() && SrcTy.isScalar() && "invalid extend/trunc"); + + if (IsExtend) + assert(DstTy.getSizeInBits() > SrcTy.getSizeInBits() && + "invalid narrowing extend"); + else + assert(DstTy.getSizeInBits() < SrcTy.getSizeInBits() && + "invalid widening trunc"); +#endif } diff --git a/contrib/llvm/lib/CodeGen/GlobalISel/RegBankSelect.cpp b/contrib/llvm/lib/CodeGen/GlobalISel/RegBankSelect.cpp index 419e270..cc026ef 100644 --- a/contrib/llvm/lib/CodeGen/GlobalISel/RegBankSelect.cpp +++ b/contrib/llvm/lib/CodeGen/GlobalISel/RegBankSelect.cpp @@ -12,10 +12,12 @@ #include "llvm/CodeGen/GlobalISel/RegBankSelect.h" #include "llvm/ADT/PostOrderIterator.h" +#include "llvm/CodeGen/GlobalISel/LegalizerInfo.h" #include "llvm/CodeGen/GlobalISel/RegisterBank.h" #include "llvm/CodeGen/MachineBlockFrequencyInfo.h" #include "llvm/CodeGen/MachineBranchProbabilityInfo.h" #include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/TargetPassConfig.h" #include "llvm/IR/Function.h" #include "llvm/Support/BlockFrequency.h" #include "llvm/Support/CommandLine.h" @@ -31,18 +33,18 @@ static cl::opt<RegBankSelect::Mode> RegBankSelectMode( cl::values(clEnumValN(RegBankSelect::Mode::Fast, "regbankselect-fast", "Run the Fast mode (default mapping)"), clEnumValN(RegBankSelect::Mode::Greedy, "regbankselect-greedy", - "Use the Greedy mode (best local mapping)"), - clEnumValEnd)); + "Use the Greedy mode (best local mapping)"))); char RegBankSelect::ID = 0; -INITIALIZE_PASS_BEGIN(RegBankSelect, "regbankselect", +INITIALIZE_PASS_BEGIN(RegBankSelect, DEBUG_TYPE, "Assign register bank of generic virtual registers", false, false); INITIALIZE_PASS_DEPENDENCY(MachineBlockFrequencyInfo) INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfo) -INITIALIZE_PASS_END(RegBankSelect, "regbankselect", +INITIALIZE_PASS_DEPENDENCY(TargetPassConfig) +INITIALIZE_PASS_END(RegBankSelect, DEBUG_TYPE, "Assign register bank of generic virtual registers", false, - false); + false) RegBankSelect::RegBankSelect(Mode RunningMode) : MachineFunctionPass(ID), RBI(nullptr), MRI(nullptr), TRI(nullptr), @@ -60,6 +62,7 @@ void RegBankSelect::init(MachineFunction &MF) { assert(RBI && "Cannot work without RegisterBankInfo"); MRI = &MF.getRegInfo(); TRI = MF.getSubtarget().getRegisterInfo(); + TPC = &getAnalysis<TargetPassConfig>(); if (OptMode != Mode::Fast) { MBFI = &getAnalysis<MachineBlockFrequencyInfo>(); MBPI = &getAnalysis<MachineBranchProbabilityInfo>(); @@ -77,6 +80,7 @@ void RegBankSelect::getAnalysisUsage(AnalysisUsage &AU) const { AU.addRequired<MachineBlockFrequencyInfo>(); AU.addRequired<MachineBranchProbabilityInfo>(); } + AU.addRequired<TargetPassConfig>(); MachineFunctionPass::getAnalysisUsage(AU); } @@ -87,7 +91,7 @@ bool RegBankSelect::assignmentMatch( OnlyAssign = false; // Each part of a break down needs to end up in a different register. // In other word, Reg assignement does not match. - if (ValMapping.BreakDown.size() > 1) + if (ValMapping.NumBreakDowns > 1) return false; const RegisterBank *CurRegBank = RBI->getRegBank(Reg, *MRI, *TRI); @@ -103,11 +107,13 @@ bool RegBankSelect::assignmentMatch( return CurRegBank == DesiredRegBrank; } -void RegBankSelect::repairReg( +bool RegBankSelect::repairReg( MachineOperand &MO, const RegisterBankInfo::ValueMapping &ValMapping, RegBankSelect::RepairingPlacement &RepairPt, const iterator_range<SmallVectorImpl<unsigned>::const_iterator> &NewVRegs) { - assert(ValMapping.BreakDown.size() == 1 && "Not yet implemented"); + if (ValMapping.NumBreakDowns != 1 && !TPC->isGlobalISelAbortEnabled()) + return false; + assert(ValMapping.NumBreakDowns == 1 && "Not yet implemented"); // An empty range of new register means no repairing. assert(NewVRegs.begin() != NewVRegs.end() && "We should not have to repair"); @@ -126,7 +132,7 @@ void RegBankSelect::repairReg( "We are about to create several defs for Dst"); // Build the instruction used to repair, then clone it at the right places. - MachineInstr *MI = MIRBuilder.buildInstr(TargetOpcode::COPY, Dst, Src); + MachineInstr *MI = MIRBuilder.buildCopy(Dst, Src); MI->removeFromParent(); DEBUG(dbgs() << "Copy: " << PrintReg(Src) << " to: " << PrintReg(Dst) << '\n'); @@ -149,15 +155,16 @@ void RegBankSelect::repairReg( } // TODO: // Legalize NewInstrs if need be. + return true; } uint64_t RegBankSelect::getRepairCost( const MachineOperand &MO, const RegisterBankInfo::ValueMapping &ValMapping) const { assert(MO.isReg() && "We should only repair register operand"); - assert(!ValMapping.BreakDown.empty() && "Nothing to map??"); + assert(ValMapping.NumBreakDowns && "Nothing to map??"); - bool IsSameNumOfValues = ValMapping.BreakDown.size() == 1; + bool IsSameNumOfValues = ValMapping.NumBreakDowns == 1; const RegisterBank *CurRegBank = RBI->getRegBank(MO.getReg(), *MRI, *TRI); // If MO does not have a register bank, we should have just been // able to set one unless we have to break the value down. @@ -195,16 +202,20 @@ uint64_t RegBankSelect::getRepairCost( // TODO: use a dedicated constant for ImpossibleCost. if (Cost != UINT_MAX) return Cost; - assert(false && "Legalization not available yet"); + assert(!TPC->isGlobalISelAbortEnabled() && + "Legalization not available yet"); // Return the legalization cost of that repairing. } - assert(false && "Complex repairing not implemented yet"); - return 1; + assert(!TPC->isGlobalISelAbortEnabled() && + "Complex repairing not implemented yet"); + return UINT_MAX; } RegisterBankInfo::InstructionMapping &RegBankSelect::findBestMapping( MachineInstr &MI, RegisterBankInfo::InstructionMappings &PossibleMappings, SmallVectorImpl<RepairingPlacement> &RepairPts) { + assert(!PossibleMappings.empty() && + "Do not know how to map this instruction"); RegisterBankInfo::InstructionMapping *BestMapping = nullptr; MappingCost Cost = MappingCost::ImpossibleCost(); @@ -212,6 +223,7 @@ RegisterBankInfo::InstructionMapping &RegBankSelect::findBestMapping( for (RegisterBankInfo::InstructionMapping &CurMapping : PossibleMappings) { MappingCost CurCost = computeMapping(MI, CurMapping, LocalRepairPts, &Cost); if (CurCost < Cost) { + DEBUG(dbgs() << "New best: " << CurCost << '\n'); Cost = CurCost; BestMapping = &CurMapping; RepairPts.clear(); @@ -219,7 +231,15 @@ RegisterBankInfo::InstructionMapping &RegBankSelect::findBestMapping( RepairPts.emplace_back(std::move(RepairPt)); } } - assert(BestMapping && "No suitable mapping for instruction"); + if (!BestMapping && !TPC->isGlobalISelAbortEnabled()) { + // If none of the mapping worked that means they are all impossible. + // Thus, pick the first one and set an impossible repairing point. + // It will trigger the failed isel mode. + BestMapping = &(*PossibleMappings.begin()); + RepairPts.emplace_back( + RepairingPlacement(MI, 0, *TRI, *this, RepairingPlacement::Impossible)); + } else + assert(BestMapping && "No suitable mapping for instruction"); return *BestMapping; } @@ -250,7 +270,7 @@ void RegBankSelect::tryAvoidingSplit( // For the PHI case, the split may not be actually required. // In the copy case, a phi is already a copy on the incoming edge, // therefore there is no need to split. - if (ValMapping.BreakDown.size() == 1) + if (ValMapping.NumBreakDowns == 1) // This is a already a copy, there is nothing to do. RepairPt.switchTo(RepairingPlacement::RepairingKind::Reassign); } @@ -327,7 +347,7 @@ void RegBankSelect::tryAvoidingSplit( // We will split all the edges and repair there. } else { // This is a virtual register defined by a terminator. - if (ValMapping.BreakDown.size() == 1) { + if (ValMapping.NumBreakDowns == 1) { // There is nothing to repair, but we may actually lie on // the repairing cost because of the PHIs already proceeded // as already stated. @@ -348,6 +368,9 @@ RegBankSelect::MappingCost RegBankSelect::computeMapping( const RegBankSelect::MappingCost *BestCost) { assert((MBFI || !BestCost) && "Costs comparison require MBFI"); + if (!InstrMapping.isValid()) + return MappingCost::ImpossibleCost(); + // If mapped with InstrMapping, MI will have the recorded cost. MappingCost Cost(MBFI ? MBFI->getBlockFreq(MI.getParent()) : 1); bool Saturated = Cost.addLocalCost(InstrMapping.getCost()); @@ -355,32 +378,34 @@ RegBankSelect::MappingCost RegBankSelect::computeMapping( DEBUG(dbgs() << "Evaluating mapping cost for: " << MI); DEBUG(dbgs() << "With: " << InstrMapping << '\n'); RepairPts.clear(); - if (BestCost && Cost > *BestCost) + if (BestCost && Cost > *BestCost) { + DEBUG(dbgs() << "Mapping is too expensive from the start\n"); return Cost; + } // Moreover, to realize this mapping, the register bank of each operand must // match this mapping. In other words, we may need to locally reassign the // register banks. Account for that repairing cost as well. // In this context, local means in the surrounding of MI. - for (unsigned OpIdx = 0, EndOpIdx = MI.getNumOperands(); OpIdx != EndOpIdx; - ++OpIdx) { + for (unsigned OpIdx = 0, EndOpIdx = InstrMapping.getNumOperands(); + OpIdx != EndOpIdx; ++OpIdx) { const MachineOperand &MO = MI.getOperand(OpIdx); if (!MO.isReg()) continue; unsigned Reg = MO.getReg(); if (!Reg) continue; - DEBUG(dbgs() << "Opd" << OpIdx); + DEBUG(dbgs() << "Opd" << OpIdx << '\n'); const RegisterBankInfo::ValueMapping &ValMapping = InstrMapping.getOperandMapping(OpIdx); // If Reg is already properly mapped, this is free. bool Assign; if (assignmentMatch(Reg, ValMapping, Assign)) { - DEBUG(dbgs() << " is free (match).\n"); + DEBUG(dbgs() << "=> is free (match).\n"); continue; } if (Assign) { - DEBUG(dbgs() << " is free (simple assignment).\n"); + DEBUG(dbgs() << "=> is free (simple assignment).\n"); RepairPts.emplace_back(RepairingPlacement(MI, OpIdx, *TRI, *this, RepairingPlacement::Reassign)); continue; @@ -398,8 +423,10 @@ RegBankSelect::MappingCost RegBankSelect::computeMapping( tryAvoidingSplit(RepairPt, MO, ValMapping); // Check that the materialization of the repairing is possible. - if (!RepairPt.canMaterialize()) + if (!RepairPt.canMaterialize()) { + DEBUG(dbgs() << "Mapping involves impossible repairing\n"); return MappingCost::ImpossibleCost(); + } // Account for the split cost and repair cost. // Unless the cost is already saturated or we do not care about the cost. @@ -454,8 +481,10 @@ RegBankSelect::MappingCost RegBankSelect::computeMapping( // Stop looking into what it takes to repair, this is already // too expensive. - if (BestCost && Cost > *BestCost) + if (BestCost && Cost > *BestCost) { + DEBUG(dbgs() << "Mapping is too expensive, stop processing\n"); return Cost; + } // No need to accumulate more cost information. // We need to still gather the repairing information though. @@ -463,10 +492,11 @@ RegBankSelect::MappingCost RegBankSelect::computeMapping( break; } } + DEBUG(dbgs() << "Total cost is: " << Cost << "\n"); return Cost; } -void RegBankSelect::applyMapping( +bool RegBankSelect::applyMapping( MachineInstr &MI, const RegisterBankInfo::InstructionMapping &InstrMapping, SmallVectorImpl<RegBankSelect::RepairingPlacement> &RepairPts) { // OpdMapper will hold all the information needed for the rewritting. @@ -474,28 +504,27 @@ void RegBankSelect::applyMapping( // First, place the repairing code. for (RepairingPlacement &RepairPt : RepairPts) { - assert(RepairPt.canMaterialize() && - RepairPt.getKind() != RepairingPlacement::Impossible && - "This mapping is impossible"); + if (!RepairPt.canMaterialize() || + RepairPt.getKind() == RepairingPlacement::Impossible) + return false; assert(RepairPt.getKind() != RepairingPlacement::None && "This should not make its way in the list"); unsigned OpIdx = RepairPt.getOpIdx(); MachineOperand &MO = MI.getOperand(OpIdx); const RegisterBankInfo::ValueMapping &ValMapping = InstrMapping.getOperandMapping(OpIdx); - unsigned BreakDownSize = ValMapping.BreakDown.size(); - (void)BreakDownSize; unsigned Reg = MO.getReg(); switch (RepairPt.getKind()) { case RepairingPlacement::Reassign: - assert(BreakDownSize == 1 && + assert(ValMapping.NumBreakDowns == 1 && "Reassignment should only be for simple mapping"); MRI->setRegBank(Reg, *ValMapping.BreakDown[0].RegBank); break; case RepairingPlacement::Insert: OpdMapper.createVRegs(OpIdx); - repairReg(MO, ValMapping, RepairPt, OpdMapper.getVRegs(OpIdx)); + if (!repairReg(MO, ValMapping, RepairPt, OpdMapper.getVRegs(OpIdx))) + return false; break; default: llvm_unreachable("Other kind should not happen"); @@ -504,9 +533,10 @@ void RegBankSelect::applyMapping( // Second, rewrite the instruction. DEBUG(dbgs() << "Actual mapping of the operands: " << OpdMapper << '\n'); RBI->applyMapping(OpdMapper); + return true; } -void RegBankSelect::assignInstr(MachineInstr &MI) { +bool RegBankSelect::assignInstr(MachineInstr &MI) { DEBUG(dbgs() << "Assign: " << MI); // Remember the repairing placement for all the operands. SmallVector<RepairingPlacement, 4> RepairPts; @@ -516,32 +546,63 @@ void RegBankSelect::assignInstr(MachineInstr &MI) { BestMapping = RBI->getInstrMapping(MI); MappingCost DefaultCost = computeMapping(MI, BestMapping, RepairPts); (void)DefaultCost; - assert(DefaultCost != MappingCost::ImpossibleCost() && - "Default mapping is not suited"); + if (DefaultCost == MappingCost::ImpossibleCost()) + return false; } else { RegisterBankInfo::InstructionMappings PossibleMappings = RBI->getInstrPossibleMappings(MI); - assert(!PossibleMappings.empty() && - "Do not know how to map this instruction"); + if (PossibleMappings.empty()) + return false; BestMapping = std::move(findBestMapping(MI, PossibleMappings, RepairPts)); } // Make sure the mapping is valid for MI. assert(BestMapping.verify(MI) && "Invalid instruction mapping"); - DEBUG(dbgs() << "Mapping: " << BestMapping << '\n'); + DEBUG(dbgs() << "Best Mapping: " << BestMapping << '\n'); // After this call, MI may not be valid anymore. // Do not use it. - applyMapping(MI, BestMapping, RepairPts); + return applyMapping(MI, BestMapping, RepairPts); } bool RegBankSelect::runOnMachineFunction(MachineFunction &MF) { + // If the ISel pipeline failed, do not bother running that pass. + if (MF.getProperties().hasProperty( + MachineFunctionProperties::Property::FailedISel)) + return false; + DEBUG(dbgs() << "Assign register banks for: " << MF.getName() << '\n'); const Function *F = MF.getFunction(); Mode SaveOptMode = OptMode; if (F->hasFnAttribute(Attribute::OptimizeNone)) OptMode = Mode::Fast; init(MF); + +#ifndef NDEBUG + // Check that our input is fully legal: we require the function to have the + // Legalized property, so it should be. + // FIXME: This should be in the MachineVerifier, but it can't use the + // LegalizerInfo as it's currently in the separate GlobalISel library. + const MachineRegisterInfo &MRI = MF.getRegInfo(); + if (const LegalizerInfo *MLI = MF.getSubtarget().getLegalizerInfo()) { + for (const MachineBasicBlock &MBB : MF) { + for (const MachineInstr &MI : MBB) { + if (isPreISelGenericOpcode(MI.getOpcode()) && !MLI->isLegal(MI, MRI)) { + if (!TPC->isGlobalISelAbortEnabled()) { + MF.getProperties().set( + MachineFunctionProperties::Property::FailedISel); + return false; + } + std::string ErrStorage; + raw_string_ostream Err(ErrStorage); + Err << "Instruction is not legal: " << MI << '\n'; + report_fatal_error(Err.str()); + } + } + } + } +#endif + // Walk the function and assign register banks to all operands. // Use a RPOT to make sure all registers are assigned before we choose // the best mapping of the current instruction. @@ -554,7 +615,18 @@ bool RegBankSelect::runOnMachineFunction(MachineFunction &MF) { MII != End;) { // MI might be invalidated by the assignment, so move the // iterator before hand. - assignInstr(*MII++); + MachineInstr &MI = *MII++; + + // Ignore target-specific instructions: they should use proper regclasses. + if (isTargetSpecificOpcode(MI.getOpcode())) + continue; + + if (!assignInstr(MI)) { + if (TPC->isGlobalISelAbortEnabled()) + report_fatal_error("Unable to map instruction"); + MF.getProperties().set(MachineFunctionProperties::Property::FailedISel); + return false; + } } } OptMode = SaveOptMode; @@ -895,3 +967,20 @@ bool RegBankSelect::MappingCost::operator==(const MappingCost &Cost) const { return LocalCost == Cost.LocalCost && NonLocalCost == Cost.NonLocalCost && LocalFreq == Cost.LocalFreq; } + +void RegBankSelect::MappingCost::dump() const { + print(dbgs()); + dbgs() << '\n'; +} + +void RegBankSelect::MappingCost::print(raw_ostream &OS) const { + if (*this == ImpossibleCost()) { + OS << "impossible"; + return; + } + if (isSaturated()) { + OS << "saturated"; + return; + } + OS << LocalFreq << " * " << LocalCost << " + " << NonLocalCost; +} diff --git a/contrib/llvm/lib/CodeGen/GlobalISel/RegisterBank.cpp b/contrib/llvm/lib/CodeGen/GlobalISel/RegisterBank.cpp index a911225..49d676f 100644 --- a/contrib/llvm/lib/CodeGen/GlobalISel/RegisterBank.cpp +++ b/contrib/llvm/lib/CodeGen/GlobalISel/RegisterBank.cpp @@ -19,12 +19,15 @@ using namespace llvm; const unsigned RegisterBank::InvalidID = UINT_MAX; -RegisterBank::RegisterBank() : ID(InvalidID), Name(nullptr), Size(0) {} +RegisterBank::RegisterBank(unsigned ID, const char *Name, unsigned Size, + const uint32_t *CoveredClasses) + : ID(ID), Name(Name), Size(Size) { + ContainedRegClasses.resize(200); + ContainedRegClasses.setBitsInMask(CoveredClasses); +} bool RegisterBank::verify(const TargetRegisterInfo &TRI) const { assert(isValid() && "Invalid register bank"); - assert(ContainedRegClasses.size() == TRI.getNumRegClasses() && - "TRI does not match the initialization process?"); for (unsigned RCId = 0, End = TRI.getNumRegClasses(); RCId != End; ++RCId) { const TargetRegisterClass &RC = *TRI.getRegClass(RCId); @@ -72,7 +75,7 @@ bool RegisterBank::operator==(const RegisterBank &OtherRB) const { return &OtherRB == this; } -void RegisterBank::dump(const TargetRegisterInfo *TRI) const { +LLVM_DUMP_METHOD void RegisterBank::dump(const TargetRegisterInfo *TRI) const { print(dbgs(), /* IsForDebug */ true, TRI); } diff --git a/contrib/llvm/lib/CodeGen/GlobalISel/RegisterBankInfo.cpp b/contrib/llvm/lib/CodeGen/GlobalISel/RegisterBankInfo.cpp index ef8e4f6..da5ab0b 100644 --- a/contrib/llvm/lib/CodeGen/GlobalISel/RegisterBankInfo.cpp +++ b/contrib/llvm/lib/CodeGen/GlobalISel/RegisterBankInfo.cpp @@ -13,6 +13,7 @@ #include "llvm/CodeGen/GlobalISel/RegisterBankInfo.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/Statistic.h" #include "llvm/ADT/iterator_range.h" #include "llvm/CodeGen/GlobalISel/RegisterBank.h" #include "llvm/CodeGen/MachineBasicBlock.h" @@ -32,139 +33,56 @@ using namespace llvm; +STATISTIC(NumPartialMappingsCreated, + "Number of partial mappings dynamically created"); +STATISTIC(NumPartialMappingsAccessed, + "Number of partial mappings dynamically accessed"); +STATISTIC(NumValueMappingsCreated, + "Number of value mappings dynamically created"); +STATISTIC(NumValueMappingsAccessed, + "Number of value mappings dynamically accessed"); +STATISTIC(NumOperandsMappingsCreated, + "Number of operands mappings dynamically created"); +STATISTIC(NumOperandsMappingsAccessed, + "Number of operands mappings dynamically accessed"); + const unsigned RegisterBankInfo::DefaultMappingID = UINT_MAX; const unsigned RegisterBankInfo::InvalidMappingID = UINT_MAX - 1; //------------------------------------------------------------------------------ // RegisterBankInfo implementation. //------------------------------------------------------------------------------ -RegisterBankInfo::RegisterBankInfo(unsigned NumRegBanks) - : NumRegBanks(NumRegBanks) { - RegBanks.reset(new RegisterBank[NumRegBanks]); +RegisterBankInfo::RegisterBankInfo(RegisterBank **RegBanks, + unsigned NumRegBanks) + : RegBanks(RegBanks), NumRegBanks(NumRegBanks) { +#ifndef NDEBUG + for (unsigned Idx = 0, End = getNumRegBanks(); Idx != End; ++Idx) { + assert(RegBanks[Idx] != nullptr && "Invalid RegisterBank"); + assert(RegBanks[Idx]->isValid() && "RegisterBank should be valid"); + } +#endif // NDEBUG +} + +RegisterBankInfo::~RegisterBankInfo() { + for (auto It : MapOfPartialMappings) + delete It.second; + for (auto It : MapOfValueMappings) + delete It.second; } bool RegisterBankInfo::verify(const TargetRegisterInfo &TRI) const { - DEBUG(for (unsigned Idx = 0, End = getNumRegBanks(); Idx != End; ++Idx) { +#ifndef NDEBUG + for (unsigned Idx = 0, End = getNumRegBanks(); Idx != End; ++Idx) { const RegisterBank &RegBank = getRegBank(Idx); assert(Idx == RegBank.getID() && "ID does not match the index in the array"); - dbgs() << "Verify " << RegBank << '\n'; + DEBUG(dbgs() << "Verify " << RegBank << '\n'); assert(RegBank.verify(TRI) && "RegBank is invalid"); - }); + } +#endif // NDEBUG return true; } -void RegisterBankInfo::createRegisterBank(unsigned ID, const char *Name) { - DEBUG(dbgs() << "Create register bank: " << ID << " with name \"" << Name - << "\"\n"); - RegisterBank &RegBank = getRegBank(ID); - assert(RegBank.getID() == RegisterBank::InvalidID && - "A register bank should be created only once"); - RegBank.ID = ID; - RegBank.Name = Name; -} - -void RegisterBankInfo::addRegBankCoverage(unsigned ID, unsigned RCId, - const TargetRegisterInfo &TRI, - bool AddTypeMapping) { - RegisterBank &RB = getRegBank(ID); - unsigned NbOfRegClasses = TRI.getNumRegClasses(); - - DEBUG(dbgs() << "Add coverage for: " << RB << '\n'); - - // Check if RB is underconstruction. - if (!RB.isValid()) - RB.ContainedRegClasses.resize(NbOfRegClasses); - else if (RB.covers(*TRI.getRegClass(RCId))) - // If RB already covers this register class, there is nothing - // to do. - return; - - BitVector &Covered = RB.ContainedRegClasses; - SmallVector<unsigned, 8> WorkList; - - WorkList.push_back(RCId); - Covered.set(RCId); - - unsigned &MaxSize = RB.Size; - do { - unsigned RCId = WorkList.pop_back_val(); - - const TargetRegisterClass &CurRC = *TRI.getRegClass(RCId); - - DEBUG(dbgs() << "Examine: " << TRI.getRegClassName(&CurRC) - << "(Size*8: " << (CurRC.getSize() * 8) << ")\n"); - - // Remember the biggest size in bits. - MaxSize = std::max(MaxSize, CurRC.getSize() * 8); - - // If we have been asked to record the type supported by this - // register bank, do it now. - if (AddTypeMapping) - for (MVT::SimpleValueType SVT : - make_range(CurRC.vt_begin(), CurRC.vt_end())) - recordRegBankForType(getRegBank(ID), SVT); - - // Walk through all sub register classes and push them into the worklist. - bool First = true; - for (BitMaskClassIterator It(CurRC.getSubClassMask(), TRI); It.isValid(); - ++It) { - unsigned SubRCId = It.getID(); - if (!Covered.test(SubRCId)) { - if (First) - DEBUG(dbgs() << " Enqueue sub-class: "); - DEBUG(dbgs() << TRI.getRegClassName(TRI.getRegClass(SubRCId)) << ", "); - WorkList.push_back(SubRCId); - // Remember that we saw the sub class. - Covered.set(SubRCId); - First = false; - } - } - if (!First) - DEBUG(dbgs() << '\n'); - - // Push also all the register classes that can be accessed via a - // subreg index, i.e., its subreg-class (which is different than - // its subclass). - // - // Note: It would probably be faster to go the other way around - // and have this method add only super classes, since this - // information is available in a more efficient way. However, it - // feels less natural for the client of this APIs plus we will - // TableGen the whole bitset at some point, so compile time for - // the initialization is not very important. - First = true; - for (unsigned SubRCId = 0; SubRCId < NbOfRegClasses; ++SubRCId) { - if (Covered.test(SubRCId)) - continue; - bool Pushed = false; - const TargetRegisterClass *SubRC = TRI.getRegClass(SubRCId); - for (SuperRegClassIterator SuperRCIt(SubRC, &TRI); SuperRCIt.isValid(); - ++SuperRCIt) { - if (Pushed) - break; - for (BitMaskClassIterator It(SuperRCIt.getMask(), TRI); It.isValid(); - ++It) { - unsigned SuperRCId = It.getID(); - if (SuperRCId == RCId) { - if (First) - DEBUG(dbgs() << " Enqueue subreg-class: "); - DEBUG(dbgs() << TRI.getRegClassName(SubRC) << ", "); - WorkList.push_back(SubRCId); - // Remember that we saw the sub class. - Covered.set(SubRCId); - Pushed = true; - First = false; - break; - } - } - } - } - if (!First) - DEBUG(dbgs() << '\n'); - } while (!WorkList.empty()); -} - const RegisterBank * RegisterBankInfo::getRegBank(unsigned Reg, const MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI) const { @@ -173,11 +91,9 @@ RegisterBankInfo::getRegBank(unsigned Reg, const MachineRegisterInfo &MRI, assert(Reg && "NoRegister does not have a register bank"); const RegClassOrRegBank &RegClassOrBank = MRI.getRegClassOrRegBank(Reg); - if (RegClassOrBank.is<const RegisterBank *>()) - return RegClassOrBank.get<const RegisterBank *>(); - const TargetRegisterClass *RC = - RegClassOrBank.get<const TargetRegisterClass *>(); - if (RC) + if (auto *RB = RegClassOrBank.dyn_cast<const RegisterBank *>()) + return RB; + if (auto *RC = RegClassOrBank.dyn_cast<const TargetRegisterClass *>()) return &getRegBankFromRegClass(*RC); return nullptr; } @@ -199,10 +115,37 @@ const RegisterBank *RegisterBankInfo::getRegBankFromConstraints( return &RegBank; } +const TargetRegisterClass *RegisterBankInfo::constrainGenericRegister( + unsigned Reg, const TargetRegisterClass &RC, MachineRegisterInfo &MRI) { + + // If the register already has a class, fallback to MRI::constrainRegClass. + auto &RegClassOrBank = MRI.getRegClassOrRegBank(Reg); + if (RegClassOrBank.is<const TargetRegisterClass *>()) + return MRI.constrainRegClass(Reg, &RC); + + const RegisterBank *RB = RegClassOrBank.get<const RegisterBank *>(); + // Otherwise, all we can do is ensure the bank covers the class, and set it. + if (RB && !RB->covers(RC)) + return nullptr; + + // If nothing was set or the class is simply compatible, set it. + MRI.setRegClass(Reg, &RC); + return &RC; +} + RegisterBankInfo::InstructionMapping RegisterBankInfo::getInstrMappingImpl(const MachineInstr &MI) const { + // For copies we want to walk over the operands and try to find one + // that has a register bank since the instruction itself will not get + // us any constraint. + bool isCopyLike = MI.isCopy() || MI.isPHI(); + // For copy like instruction, only the mapping of the definition + // is important. The rest is not constrained. + unsigned NumOperandsForMapping = isCopyLike ? 1 : MI.getNumOperands(); + RegisterBankInfo::InstructionMapping Mapping(DefaultMappingID, /*Cost*/ 1, - MI.getNumOperands()); + /*OperandsMapping*/ nullptr, + NumOperandsForMapping); const MachineFunction &MF = *MI.getParent()->getParent(); const TargetSubtargetInfo &STI = MF.getSubtarget(); const TargetRegisterInfo &TRI = *STI.getRegisterInfo(); @@ -213,14 +156,10 @@ RegisterBankInfo::getInstrMappingImpl(const MachineInstr &MI) const { // Before doing anything complicated check if the mapping is not // directly available. bool CompleteMapping = true; - // For copies we want to walk over the operands and try to find one - // that has a register bank. - bool isCopyLike = MI.isCopy() || MI.isPHI(); - // Remember the register bank for reuse for copy-like instructions. - const RegisterBank *RegBank = nullptr; - // Remember the size of the register for reuse for copy-like instructions. - unsigned RegSize = 0; - for (unsigned OpIdx = 0, End = MI.getNumOperands(); OpIdx != End; ++OpIdx) { + + SmallVector<const ValueMapping *, 8> OperandsMapping(NumOperandsForMapping); + for (unsigned OpIdx = 0, EndIdx = MI.getNumOperands(); OpIdx != EndIdx; + ++OpIdx) { const MachineOperand &MO = MI.getOperand(OpIdx); if (!MO.isReg()) continue; @@ -242,71 +181,147 @@ RegisterBankInfo::getInstrMappingImpl(const MachineInstr &MI) const { // the register bank from the encoding constraints. CurRegBank = getRegBankFromConstraints(MI, OpIdx, TII, TRI); if (!CurRegBank) { - // Check if we can deduce the register bank from the type of - // the instruction. - Type *MITy = MI.getType(); - if (MITy) - CurRegBank = getRegBankForType( - MVT::getVT(MITy, /*HandleUnknown*/ true).SimpleTy); - if (!CurRegBank) - // Use the current assigned register bank. - // That may not make much sense though. - CurRegBank = AltRegBank; - if (!CurRegBank) { - // All our attempts failed, give up. - CompleteMapping = false; - - if (!isCopyLike) - // MI does not carry enough information to guess the mapping. - return InstructionMapping(); - - // For copies, we want to keep interating to find a register - // bank for the other operands if we did not find one yet. - if (RegBank) - break; - continue; - } + // All our attempts failed, give up. + CompleteMapping = false; + + if (!isCopyLike) + // MI does not carry enough information to guess the mapping. + return InstructionMapping(); + continue; } } - RegBank = CurRegBank; - RegSize = getSizeInBits(Reg, MRI, TRI); - Mapping.setOperandMapping(OpIdx, RegSize, *CurRegBank); + const ValueMapping *ValMapping = + &getValueMapping(0, getSizeInBits(Reg, MRI, TRI), *CurRegBank); + if (isCopyLike) { + OperandsMapping[0] = ValMapping; + CompleteMapping = true; + break; + } + OperandsMapping[OpIdx] = ValMapping; } - if (CompleteMapping) - return Mapping; - - assert(isCopyLike && "We should have bailed on non-copies at this point"); - // For copy like instruction, if none of the operand has a register - // bank avialable, there is nothing we can propagate. - if (!RegBank) + if (isCopyLike && !CompleteMapping) + // No way to deduce the type from what we have. return InstructionMapping(); - // This is a copy-like instruction. - // Propagate RegBank to all operands that do not have a - // mapping yet. - for (unsigned OpIdx = 0, End = MI.getNumOperands(); OpIdx != End; ++OpIdx) { - const MachineOperand &MO = MI.getOperand(OpIdx); - // Don't assign a mapping for non-reg operands. - if (!MO.isReg()) - continue; + assert(CompleteMapping && "Setting an uncomplete mapping"); + Mapping.setOperandsMapping(getOperandsMapping(OperandsMapping)); + return Mapping; +} - // If a mapping already exists, do not touch it. - if (!static_cast<const InstructionMapping *>(&Mapping) - ->getOperandMapping(OpIdx) - .BreakDown.empty()) - continue; +/// Hashing function for PartialMapping. +static hash_code hashPartialMapping(unsigned StartIdx, unsigned Length, + const RegisterBank *RegBank) { + return hash_combine(StartIdx, Length, RegBank ? RegBank->getID() : 0); +} + +/// Overloaded version of hash_value for a PartialMapping. +hash_code +llvm::hash_value(const RegisterBankInfo::PartialMapping &PartMapping) { + return hashPartialMapping(PartMapping.StartIdx, PartMapping.Length, + PartMapping.RegBank); +} + +const RegisterBankInfo::PartialMapping & +RegisterBankInfo::getPartialMapping(unsigned StartIdx, unsigned Length, + const RegisterBank &RegBank) const { + ++NumPartialMappingsAccessed; + + hash_code Hash = hashPartialMapping(StartIdx, Length, &RegBank); + const auto &It = MapOfPartialMappings.find(Hash); + if (It != MapOfPartialMappings.end()) + return *It->second; + + ++NumPartialMappingsCreated; + + const PartialMapping *&PartMapping = MapOfPartialMappings[Hash]; + PartMapping = new PartialMapping{StartIdx, Length, RegBank}; + return *PartMapping; +} + +const RegisterBankInfo::ValueMapping & +RegisterBankInfo::getValueMapping(unsigned StartIdx, unsigned Length, + const RegisterBank &RegBank) const { + return getValueMapping(&getPartialMapping(StartIdx, Length, RegBank), 1); +} + +static hash_code +hashValueMapping(const RegisterBankInfo::PartialMapping *BreakDown, + unsigned NumBreakDowns) { + if (LLVM_LIKELY(NumBreakDowns == 1)) + return hash_value(*BreakDown); + SmallVector<size_t, 8> Hashes(NumBreakDowns); + for (unsigned Idx = 0; Idx != NumBreakDowns; ++Idx) + Hashes.push_back(hash_value(BreakDown[Idx])); + return hash_combine_range(Hashes.begin(), Hashes.end()); +} + +const RegisterBankInfo::ValueMapping & +RegisterBankInfo::getValueMapping(const PartialMapping *BreakDown, + unsigned NumBreakDowns) const { + ++NumValueMappingsAccessed; + + hash_code Hash = hashValueMapping(BreakDown, NumBreakDowns); + const auto &It = MapOfValueMappings.find(Hash); + if (It != MapOfValueMappings.end()) + return *It->second; + + ++NumValueMappingsCreated; + + const ValueMapping *&ValMapping = MapOfValueMappings[Hash]; + ValMapping = new ValueMapping{BreakDown, NumBreakDowns}; + return *ValMapping; +} - Mapping.setOperandMapping(OpIdx, RegSize, *RegBank); +template <typename Iterator> +const RegisterBankInfo::ValueMapping * +RegisterBankInfo::getOperandsMapping(Iterator Begin, Iterator End) const { + + ++NumOperandsMappingsAccessed; + + // The addresses of the value mapping are unique. + // Therefore, we can use them directly to hash the operand mapping. + hash_code Hash = hash_combine_range(Begin, End); + const auto &It = MapOfOperandsMappings.find(Hash); + if (It != MapOfOperandsMappings.end()) + return It->second; + + ++NumOperandsMappingsCreated; + + // Create the array of ValueMapping. + // Note: this array will not hash to this instance of operands + // mapping, because we use the pointer of the ValueMapping + // to hash and we expect them to uniquely identify an instance + // of value mapping. + ValueMapping *&Res = MapOfOperandsMappings[Hash]; + Res = new ValueMapping[std::distance(Begin, End)]; + unsigned Idx = 0; + for (Iterator It = Begin; It != End; ++It, ++Idx) { + const ValueMapping *ValMap = *It; + if (!ValMap) + continue; + Res[Idx] = *ValMap; } - return Mapping; + return Res; +} + +const RegisterBankInfo::ValueMapping *RegisterBankInfo::getOperandsMapping( + const SmallVectorImpl<const RegisterBankInfo::ValueMapping *> &OpdsMapping) + const { + return getOperandsMapping(OpdsMapping.begin(), OpdsMapping.end()); +} + +const RegisterBankInfo::ValueMapping *RegisterBankInfo::getOperandsMapping( + std::initializer_list<const RegisterBankInfo::ValueMapping *> OpdsMapping) + const { + return getOperandsMapping(OpdsMapping.begin(), OpdsMapping.end()); } RegisterBankInfo::InstructionMapping RegisterBankInfo::getInstrMapping(const MachineInstr &MI) const { - RegisterBankInfo::InstructionMapping Mapping = getInstrMappingImpl(MI); - if (Mapping.isValid()) - return Mapping; + RegisterBankInfo::InstructionMapping Mapping = getInstrMappingImpl(MI); + if (Mapping.isValid()) + return Mapping; llvm_unreachable("The target must implement this"); } @@ -335,18 +350,18 @@ RegisterBankInfo::getInstrAlternativeMappings(const MachineInstr &MI) const { void RegisterBankInfo::applyDefaultMapping(const OperandsMapper &OpdMapper) { MachineInstr &MI = OpdMapper.getMI(); DEBUG(dbgs() << "Applying default-like mapping\n"); - for (unsigned OpIdx = 0, EndIdx = MI.getNumOperands(); OpIdx != EndIdx; - ++OpIdx) { + for (unsigned OpIdx = 0, + EndIdx = OpdMapper.getInstrMapping().getNumOperands(); + OpIdx != EndIdx; ++OpIdx) { DEBUG(dbgs() << "OpIdx " << OpIdx); MachineOperand &MO = MI.getOperand(OpIdx); if (!MO.isReg()) { DEBUG(dbgs() << " is not a register, nothing to be done\n"); continue; } - assert( - OpdMapper.getInstrMapping().getOperandMapping(OpIdx).BreakDown.size() == - 1 && - "This mapping is too complex for this function"); + assert(OpdMapper.getInstrMapping().getOperandMapping(OpIdx).NumBreakDowns == + 1 && + "This mapping is too complex for this function"); iterator_range<SmallVectorImpl<unsigned>::const_iterator> NewRegs = OpdMapper.getVRegs(OpIdx); if (NewRegs.begin() == NewRegs.end()) { @@ -369,7 +384,8 @@ unsigned RegisterBankInfo::getSizeInBits(unsigned Reg, // get the size of that register class. RC = TRI.getMinimalPhysRegClass(Reg); } else { - unsigned RegSize = MRI.getSize(Reg); + LLT Ty = MRI.getType(Reg); + unsigned RegSize = Ty.isValid() ? Ty.getSizeInBits() : 0; // If Reg is not a generic register, query the register class to // get its size. if (RegSize) @@ -384,7 +400,7 @@ unsigned RegisterBankInfo::getSizeInBits(unsigned Reg, //------------------------------------------------------------------------------ // Helper classes implementation. //------------------------------------------------------------------------------ -void RegisterBankInfo::PartialMapping::dump() const { +LLVM_DUMP_METHOD void RegisterBankInfo::PartialMapping::dump() const { print(dbgs()); dbgs() << '\n'; } @@ -392,7 +408,7 @@ void RegisterBankInfo::PartialMapping::dump() const { bool RegisterBankInfo::PartialMapping::verify() const { assert(RegBank && "Register bank not set"); assert(Length && "Empty mapping"); - assert((StartIdx < getHighBitIdx()) && "Overflow, switch to APInt?"); + assert((StartIdx <= getHighBitIdx()) && "Overflow, switch to APInt?"); // Check if the minimum width fits into RegBank. assert(RegBank->getSize() >= Length && "Register bank too small for Mask"); return true; @@ -406,10 +422,10 @@ void RegisterBankInfo::PartialMapping::print(raw_ostream &OS) const { OS << "nullptr"; } -bool RegisterBankInfo::ValueMapping::verify(unsigned ExpectedBitWidth) const { - assert(!BreakDown.empty() && "Value mapped nowhere?!"); +bool RegisterBankInfo::ValueMapping::verify(unsigned MeaningfulBitWidth) const { + assert(NumBreakDowns && "Value mapped nowhere?!"); unsigned OrigValueBitWidth = 0; - for (const RegisterBankInfo::PartialMapping &PartMap : BreakDown) { + for (const RegisterBankInfo::PartialMapping &PartMap : *this) { // Check that each register bank is big enough to hold the partial value: // this check is done by PartialMapping::verify assert(PartMap.verify() && "Partial mapping is invalid"); @@ -418,9 +434,10 @@ bool RegisterBankInfo::ValueMapping::verify(unsigned ExpectedBitWidth) const { OrigValueBitWidth = std::max(OrigValueBitWidth, PartMap.getHighBitIdx() + 1); } - assert(OrigValueBitWidth == ExpectedBitWidth && "BitWidth does not match"); + assert(OrigValueBitWidth >= MeaningfulBitWidth && + "Meaningful bits not covered by the mapping"); APInt ValueMask(OrigValueBitWidth, 0); - for (const RegisterBankInfo::PartialMapping &PartMap : BreakDown) { + for (const RegisterBankInfo::PartialMapping &PartMap : *this) { // Check that the union of the partial mappings covers the whole value, // without overlaps. // The high bit is exclusive in the APInt API, thus getHighBitIdx + 1. @@ -434,15 +451,15 @@ bool RegisterBankInfo::ValueMapping::verify(unsigned ExpectedBitWidth) const { return true; } -void RegisterBankInfo::ValueMapping::dump() const { +LLVM_DUMP_METHOD void RegisterBankInfo::ValueMapping::dump() const { print(dbgs()); dbgs() << '\n'; } void RegisterBankInfo::ValueMapping::print(raw_ostream &OS) const { - OS << "#BreakDown: " << BreakDown.size() << " "; + OS << "#BreakDown: " << NumBreakDowns << " "; bool IsFirst = true; - for (const PartialMapping &PartMap : BreakDown) { + for (const PartialMapping &PartMap : *this) { if (!IsFirst) OS << ", "; OS << '[' << PartMap << ']'; @@ -450,21 +467,13 @@ void RegisterBankInfo::ValueMapping::print(raw_ostream &OS) const { } } -void RegisterBankInfo::InstructionMapping::setOperandMapping( - unsigned OpIdx, unsigned MaskSize, const RegisterBank &RegBank) { - // Build the value mapping. - assert(MaskSize <= RegBank.getSize() && "Register bank is too small"); - - // Create the mapping object. - getOperandMapping(OpIdx).BreakDown.push_back( - PartialMapping(0, MaskSize, RegBank)); -} - bool RegisterBankInfo::InstructionMapping::verify( const MachineInstr &MI) const { // Check that all the register operands are properly mapped. // Check the constructor invariant. - assert(NumOperands == MI.getNumOperands() && + // For PHI, we only care about mapping the definition. + assert(NumOperands == + ((MI.isCopy() || MI.isPHI()) ? 1 : MI.getNumOperands()) && "NumOperands must match, see constructor"); assert(MI.getParent() && MI.getParent()->getParent() && "MI must be connected to a MachineFunction"); @@ -473,16 +482,18 @@ bool RegisterBankInfo::InstructionMapping::verify( for (unsigned Idx = 0; Idx < NumOperands; ++Idx) { const MachineOperand &MO = MI.getOperand(Idx); - const RegisterBankInfo::ValueMapping &MOMapping = getOperandMapping(Idx); - (void)MOMapping; if (!MO.isReg()) { - assert(MOMapping.BreakDown.empty() && + assert(!getOperandMapping(Idx).isValid() && "We should not care about non-reg mapping"); continue; } unsigned Reg = MO.getReg(); if (!Reg) continue; + assert(getOperandMapping(Idx).isValid() && + "We must have a mapping for reg operands"); + const RegisterBankInfo::ValueMapping &MOMapping = getOperandMapping(Idx); + (void)MOMapping; // Register size in bits. // This size must match what the mapping expects. assert(MOMapping.verify(getSizeInBits( @@ -492,7 +503,7 @@ bool RegisterBankInfo::InstructionMapping::verify( return true; } -void RegisterBankInfo::InstructionMapping::dump() const { +LLVM_DUMP_METHOD void RegisterBankInfo::InstructionMapping::dump() const { print(dbgs()); dbgs() << '\n'; } @@ -514,18 +525,16 @@ RegisterBankInfo::OperandsMapper::OperandsMapper( MachineInstr &MI, const InstructionMapping &InstrMapping, MachineRegisterInfo &MRI) : MRI(MRI), MI(MI), InstrMapping(InstrMapping) { - unsigned NumOpds = MI.getNumOperands(); - OpToNewVRegIdx.reset(new int[NumOpds]); - std::fill(&OpToNewVRegIdx[0], &OpToNewVRegIdx[NumOpds], - OperandsMapper::DontKnowIdx); + unsigned NumOpds = InstrMapping.getNumOperands(); + OpToNewVRegIdx.resize(NumOpds, OperandsMapper::DontKnowIdx); assert(InstrMapping.verify(MI) && "Invalid mapping for MI"); } iterator_range<SmallVectorImpl<unsigned>::iterator> RegisterBankInfo::OperandsMapper::getVRegsMem(unsigned OpIdx) { - assert(OpIdx < getMI().getNumOperands() && "Out-of-bound access"); + assert(OpIdx < getInstrMapping().getNumOperands() && "Out-of-bound access"); unsigned NumPartialVal = - getInstrMapping().getOperandMapping(OpIdx).BreakDown.size(); + getInstrMapping().getOperandMapping(OpIdx).NumBreakDowns; int StartIdx = OpToNewVRegIdx[OpIdx]; if (StartIdx == OperandsMapper::DontKnowIdx) { @@ -559,16 +568,15 @@ RegisterBankInfo::OperandsMapper::getNewVRegsEnd(unsigned StartIdx, } void RegisterBankInfo::OperandsMapper::createVRegs(unsigned OpIdx) { - assert(OpIdx < getMI().getNumOperands() && "Out-of-bound access"); + assert(OpIdx < getInstrMapping().getNumOperands() && "Out-of-bound access"); iterator_range<SmallVectorImpl<unsigned>::iterator> NewVRegsForOpIdx = getVRegsMem(OpIdx); - const SmallVectorImpl<PartialMapping> &PartMapList = - getInstrMapping().getOperandMapping(OpIdx).BreakDown; - SmallVectorImpl<PartialMapping>::const_iterator PartMap = PartMapList.begin(); + const ValueMapping &ValMapping = getInstrMapping().getOperandMapping(OpIdx); + const PartialMapping *PartMap = ValMapping.begin(); for (unsigned &NewVReg : NewVRegsForOpIdx) { - assert(PartMap != PartMapList.end() && "Out-of-bound access"); + assert(PartMap != ValMapping.end() && "Out-of-bound access"); assert(NewVReg == 0 && "Register has already been created"); - NewVReg = MRI.createGenericVirtualRegister(PartMap->Length); + NewVReg = MRI.createGenericVirtualRegister(LLT::scalar(PartMap->Length)); MRI.setRegBank(NewVReg, *PartMap->RegBank); ++PartMap; } @@ -577,8 +585,8 @@ void RegisterBankInfo::OperandsMapper::createVRegs(unsigned OpIdx) { void RegisterBankInfo::OperandsMapper::setVRegs(unsigned OpIdx, unsigned PartialMapIdx, unsigned NewVReg) { - assert(OpIdx < getMI().getNumOperands() && "Out-of-bound access"); - assert(getInstrMapping().getOperandMapping(OpIdx).BreakDown.size() > + assert(OpIdx < getInstrMapping().getNumOperands() && "Out-of-bound access"); + assert(getInstrMapping().getOperandMapping(OpIdx).NumBreakDowns > PartialMapIdx && "Out-of-bound access for partial mapping"); // Make sure the memory is initialized for that operand. @@ -592,14 +600,14 @@ iterator_range<SmallVectorImpl<unsigned>::const_iterator> RegisterBankInfo::OperandsMapper::getVRegs(unsigned OpIdx, bool ForDebug) const { (void)ForDebug; - assert(OpIdx < getMI().getNumOperands() && "Out-of-bound access"); + assert(OpIdx < getInstrMapping().getNumOperands() && "Out-of-bound access"); int StartIdx = OpToNewVRegIdx[OpIdx]; if (StartIdx == OperandsMapper::DontKnowIdx) return make_range(NewVRegs.end(), NewVRegs.end()); unsigned PartMapSize = - getInstrMapping().getOperandMapping(OpIdx).BreakDown.size(); + getInstrMapping().getOperandMapping(OpIdx).NumBreakDowns; SmallVectorImpl<unsigned>::const_iterator End = getNewVRegsEnd(StartIdx, PartMapSize); iterator_range<SmallVectorImpl<unsigned>::const_iterator> Res = @@ -611,14 +619,14 @@ RegisterBankInfo::OperandsMapper::getVRegs(unsigned OpIdx, return Res; } -void RegisterBankInfo::OperandsMapper::dump() const { +LLVM_DUMP_METHOD void RegisterBankInfo::OperandsMapper::dump() const { print(dbgs(), true); dbgs() << '\n'; } void RegisterBankInfo::OperandsMapper::print(raw_ostream &OS, bool ForDebug) const { - unsigned NumOpds = getMI().getNumOperands(); + unsigned NumOpds = getInstrMapping().getNumOperands(); if (ForDebug) { OS << "Mapping for " << getMI() << "\nwith " << getInstrMapping() << '\n'; // Print out the internal state of the index table. diff --git a/contrib/llvm/lib/CodeGen/GlobalISel/Utils.cpp b/contrib/llvm/lib/CodeGen/GlobalISel/Utils.cpp new file mode 100644 index 0000000..e500918 --- /dev/null +++ b/contrib/llvm/lib/CodeGen/GlobalISel/Utils.cpp @@ -0,0 +1,45 @@ +//===- llvm/CodeGen/GlobalISel/Utils.cpp -------------------------*- 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 utility functions used by the GlobalISel +/// pipeline. +//===----------------------------------------------------------------------===// + +#include "llvm/CodeGen/GlobalISel/Utils.h" +#include "llvm/CodeGen/GlobalISel/RegisterBankInfo.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/Target/TargetInstrInfo.h" +#include "llvm/Target/TargetRegisterInfo.h" + +#define DEBUG_TYPE "globalisel-utils" + +using namespace llvm; + +unsigned llvm::constrainOperandRegClass( + const MachineFunction &MF, const TargetRegisterInfo &TRI, + MachineRegisterInfo &MRI, const TargetInstrInfo &TII, + const RegisterBankInfo &RBI, MachineInstr &InsertPt, const MCInstrDesc &II, + unsigned Reg, unsigned OpIdx) { + // Assume physical registers are properly constrained. + assert(TargetRegisterInfo::isVirtualRegister(Reg) && + "PhysReg not implemented"); + + const TargetRegisterClass *RegClass = TII.getRegClass(II, OpIdx, &TRI, MF); + + if (!RBI.constrainGenericRegister(Reg, *RegClass, MRI)) { + unsigned NewReg = MRI.createVirtualRegister(RegClass); + BuildMI(*InsertPt.getParent(), InsertPt, InsertPt.getDebugLoc(), + TII.get(TargetOpcode::COPY), NewReg) + .addReg(Reg); + return NewReg; + } + + return Reg; +} |