mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-26 04:32:44 +01:00
f7216ac2fb
This uses a straightforward port of findUnwindDestinations() from SelectionDAG. Differential Revision: https://reviews.llvm.org/D93256
704 lines
28 KiB
C++
704 lines
28 KiB
C++
//===- llvm/CodeGen/GlobalISel/IRTranslator.h - IRTranslator ----*- C++ -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
/// \file
|
|
/// This file declares the IRTranslator pass.
|
|
/// This pass is responsible for translating LLVM IR into MachineInstr.
|
|
/// It uses target hooks to lower the ABI but aside from that, the pass
|
|
/// generated code is generic. This is the default translator used for
|
|
/// GlobalISel.
|
|
///
|
|
/// \todo Replace the comments with actual doxygen comments.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef LLVM_CODEGEN_GLOBALISEL_IRTRANSLATOR_H
|
|
#define LLVM_CODEGEN_GLOBALISEL_IRTRANSLATOR_H
|
|
|
|
#include "llvm/ADT/DenseMap.h"
|
|
#include "llvm/ADT/SmallVector.h"
|
|
#include "llvm/CodeGen/FunctionLoweringInfo.h"
|
|
#include "llvm/CodeGen/GlobalISel/CSEMIRBuilder.h"
|
|
#include "llvm/CodeGen/MachineFunctionPass.h"
|
|
#include "llvm/CodeGen/SwiftErrorValueTracking.h"
|
|
#include "llvm/CodeGen/SwitchLoweringUtils.h"
|
|
#include "llvm/IR/Intrinsics.h"
|
|
#include "llvm/Support/Allocator.h"
|
|
#include "llvm/Support/CodeGen.h"
|
|
#include <memory>
|
|
#include <utility>
|
|
|
|
namespace llvm {
|
|
|
|
class AllocaInst;
|
|
class BasicBlock;
|
|
class CallInst;
|
|
class CallLowering;
|
|
class Constant;
|
|
class ConstrainedFPIntrinsic;
|
|
class DataLayout;
|
|
class Instruction;
|
|
class MachineBasicBlock;
|
|
class MachineFunction;
|
|
class MachineInstr;
|
|
class MachineRegisterInfo;
|
|
class OptimizationRemarkEmitter;
|
|
class PHINode;
|
|
class TargetPassConfig;
|
|
class User;
|
|
class Value;
|
|
|
|
// Technically the pass should run on an hypothetical MachineModule,
|
|
// since it should translate Global into some sort of MachineGlobal.
|
|
// The MachineGlobal should ultimately just be a transfer of ownership of
|
|
// the interesting bits that are relevant to represent a global value.
|
|
// That being said, we could investigate what would it cost to just duplicate
|
|
// the information from the LLVM IR.
|
|
// The idea is that ultimately we would be able to free up the memory used
|
|
// by the LLVM IR as soon as the translation is over.
|
|
class IRTranslator : public MachineFunctionPass {
|
|
public:
|
|
static char ID;
|
|
|
|
private:
|
|
/// Interface used to lower the everything related to calls.
|
|
const CallLowering *CLI;
|
|
|
|
/// This class contains the mapping between the Values to vreg related data.
|
|
class ValueToVRegInfo {
|
|
public:
|
|
ValueToVRegInfo() = default;
|
|
|
|
using VRegListT = SmallVector<Register, 1>;
|
|
using OffsetListT = SmallVector<uint64_t, 1>;
|
|
|
|
using const_vreg_iterator =
|
|
DenseMap<const Value *, VRegListT *>::const_iterator;
|
|
using const_offset_iterator =
|
|
DenseMap<const Value *, OffsetListT *>::const_iterator;
|
|
|
|
inline const_vreg_iterator vregs_end() const { return ValToVRegs.end(); }
|
|
|
|
VRegListT *getVRegs(const Value &V) {
|
|
auto It = ValToVRegs.find(&V);
|
|
if (It != ValToVRegs.end())
|
|
return It->second;
|
|
|
|
return insertVRegs(V);
|
|
}
|
|
|
|
OffsetListT *getOffsets(const Value &V) {
|
|
auto It = TypeToOffsets.find(V.getType());
|
|
if (It != TypeToOffsets.end())
|
|
return It->second;
|
|
|
|
return insertOffsets(V);
|
|
}
|
|
|
|
const_vreg_iterator findVRegs(const Value &V) const {
|
|
return ValToVRegs.find(&V);
|
|
}
|
|
|
|
bool contains(const Value &V) const {
|
|
return ValToVRegs.find(&V) != ValToVRegs.end();
|
|
}
|
|
|
|
void reset() {
|
|
ValToVRegs.clear();
|
|
TypeToOffsets.clear();
|
|
VRegAlloc.DestroyAll();
|
|
OffsetAlloc.DestroyAll();
|
|
}
|
|
|
|
private:
|
|
VRegListT *insertVRegs(const Value &V) {
|
|
assert(ValToVRegs.find(&V) == ValToVRegs.end() && "Value already exists");
|
|
|
|
// We placement new using our fast allocator since we never try to free
|
|
// the vectors until translation is finished.
|
|
auto *VRegList = new (VRegAlloc.Allocate()) VRegListT();
|
|
ValToVRegs[&V] = VRegList;
|
|
return VRegList;
|
|
}
|
|
|
|
OffsetListT *insertOffsets(const Value &V) {
|
|
assert(TypeToOffsets.find(V.getType()) == TypeToOffsets.end() &&
|
|
"Type already exists");
|
|
|
|
auto *OffsetList = new (OffsetAlloc.Allocate()) OffsetListT();
|
|
TypeToOffsets[V.getType()] = OffsetList;
|
|
return OffsetList;
|
|
}
|
|
SpecificBumpPtrAllocator<VRegListT> VRegAlloc;
|
|
SpecificBumpPtrAllocator<OffsetListT> OffsetAlloc;
|
|
|
|
// We store pointers to vectors here since references may be invalidated
|
|
// while we hold them if we stored the vectors directly.
|
|
DenseMap<const Value *, VRegListT*> ValToVRegs;
|
|
DenseMap<const Type *, OffsetListT*> TypeToOffsets;
|
|
};
|
|
|
|
/// Mapping of the values of the current LLVM IR function to the related
|
|
/// virtual registers and offsets.
|
|
ValueToVRegInfo VMap;
|
|
|
|
// N.b. it's not completely obvious that this will be sufficient for every
|
|
// LLVM IR construct (with "invoke" being the obvious candidate to mess up our
|
|
// lives.
|
|
DenseMap<const BasicBlock *, MachineBasicBlock *> BBToMBB;
|
|
|
|
// One BasicBlock can be translated to multiple MachineBasicBlocks. For such
|
|
// BasicBlocks translated to multiple MachineBasicBlocks, MachinePreds retains
|
|
// a mapping between the edges arriving at the BasicBlock to the corresponding
|
|
// created MachineBasicBlocks. Some BasicBlocks that get translated to a
|
|
// single MachineBasicBlock may also end up in this Map.
|
|
using CFGEdge = std::pair<const BasicBlock *, const BasicBlock *>;
|
|
DenseMap<CFGEdge, SmallVector<MachineBasicBlock *, 1>> MachinePreds;
|
|
|
|
// List of stubbed PHI instructions, for values and basic blocks to be filled
|
|
// in once all MachineBasicBlocks have been created.
|
|
SmallVector<std::pair<const PHINode *, SmallVector<MachineInstr *, 1>>, 4>
|
|
PendingPHIs;
|
|
|
|
/// Record of what frame index has been allocated to specified allocas for
|
|
/// this function.
|
|
DenseMap<const AllocaInst *, int> FrameIndices;
|
|
|
|
SwiftErrorValueTracking SwiftError;
|
|
|
|
/// \name Methods for translating form LLVM IR to MachineInstr.
|
|
/// \see ::translate for general information on the translate methods.
|
|
/// @{
|
|
|
|
/// Translate \p Inst into its corresponding MachineInstr instruction(s).
|
|
/// Insert the newly translated instruction(s) right where the CurBuilder
|
|
/// is set.
|
|
///
|
|
/// The general algorithm is:
|
|
/// 1. Look for a virtual register for each operand or
|
|
/// create one.
|
|
/// 2 Update the VMap accordingly.
|
|
/// 2.alt. For constant arguments, if they are compile time constants,
|
|
/// produce an immediate in the right operand and do not touch
|
|
/// ValToReg. Actually we will go with a virtual register for each
|
|
/// constants because it may be expensive to actually materialize the
|
|
/// constant. Moreover, if the constant spans on several instructions,
|
|
/// CSE may not catch them.
|
|
/// => Update ValToVReg and remember that we saw a constant in Constants.
|
|
/// We will materialize all the constants in finalize.
|
|
/// Note: we would need to do something so that we can recognize such operand
|
|
/// as constants.
|
|
/// 3. Create the generic instruction.
|
|
///
|
|
/// \return true if the translation succeeded.
|
|
bool translate(const Instruction &Inst);
|
|
|
|
/// Materialize \p C into virtual-register \p Reg. The generic instructions
|
|
/// performing this materialization will be inserted into the entry block of
|
|
/// the function.
|
|
///
|
|
/// \return true if the materialization succeeded.
|
|
bool translate(const Constant &C, Register Reg);
|
|
|
|
// Translate U as a copy of V.
|
|
bool translateCopy(const User &U, const Value &V,
|
|
MachineIRBuilder &MIRBuilder);
|
|
|
|
/// Translate an LLVM bitcast into generic IR. Either a COPY or a G_BITCAST is
|
|
/// emitted.
|
|
bool translateBitCast(const User &U, MachineIRBuilder &MIRBuilder);
|
|
|
|
/// Translate an LLVM load instruction into generic IR.
|
|
bool translateLoad(const User &U, MachineIRBuilder &MIRBuilder);
|
|
|
|
/// Translate an LLVM store instruction into generic IR.
|
|
bool translateStore(const User &U, MachineIRBuilder &MIRBuilder);
|
|
|
|
/// Translate an LLVM string intrinsic (memcpy, memset, ...).
|
|
bool translateMemFunc(const CallInst &CI, MachineIRBuilder &MIRBuilder,
|
|
unsigned Opcode);
|
|
|
|
void getStackGuard(Register DstReg, MachineIRBuilder &MIRBuilder);
|
|
|
|
bool translateOverflowIntrinsic(const CallInst &CI, unsigned Op,
|
|
MachineIRBuilder &MIRBuilder);
|
|
bool translateFixedPointIntrinsic(unsigned Op, const CallInst &CI,
|
|
MachineIRBuilder &MIRBuilder);
|
|
|
|
/// Helper function for translateSimpleIntrinsic.
|
|
/// \return The generic opcode for \p IntrinsicID if \p IntrinsicID is a
|
|
/// simple intrinsic (ceil, fabs, etc.). Otherwise, returns
|
|
/// Intrinsic::not_intrinsic.
|
|
unsigned getSimpleIntrinsicOpcode(Intrinsic::ID ID);
|
|
|
|
/// Translates the intrinsics defined in getSimpleIntrinsicOpcode.
|
|
/// \return true if the translation succeeded.
|
|
bool translateSimpleIntrinsic(const CallInst &CI, Intrinsic::ID ID,
|
|
MachineIRBuilder &MIRBuilder);
|
|
|
|
bool translateConstrainedFPIntrinsic(const ConstrainedFPIntrinsic &FPI,
|
|
MachineIRBuilder &MIRBuilder);
|
|
|
|
bool translateKnownIntrinsic(const CallInst &CI, Intrinsic::ID ID,
|
|
MachineIRBuilder &MIRBuilder);
|
|
|
|
bool translateInlineAsm(const CallBase &CB, MachineIRBuilder &MIRBuilder);
|
|
|
|
/// Returns true if the value should be split into multiple LLTs.
|
|
/// If \p Offsets is given then the split type's offsets will be stored in it.
|
|
/// If \p Offsets is not empty it will be cleared first.
|
|
bool valueIsSplit(const Value &V,
|
|
SmallVectorImpl<uint64_t> *Offsets = nullptr);
|
|
|
|
/// Common code for translating normal calls or invokes.
|
|
bool translateCallBase(const CallBase &CB, MachineIRBuilder &MIRBuilder);
|
|
|
|
/// Translate call instruction.
|
|
/// \pre \p U is a call instruction.
|
|
bool translateCall(const User &U, MachineIRBuilder &MIRBuilder);
|
|
|
|
/// When an invoke or a cleanupret unwinds to the next EH pad, there are
|
|
/// many places it could ultimately go. In the IR, we have a single unwind
|
|
/// destination, but in the machine CFG, we enumerate all the possible blocks.
|
|
/// This function skips over imaginary basic blocks that hold catchswitch
|
|
/// instructions, and finds all the "real" machine
|
|
/// basic block destinations. As those destinations may not be successors of
|
|
/// EHPadBB, here we also calculate the edge probability to those
|
|
/// destinations. The passed-in Prob is the edge probability to EHPadBB.
|
|
bool findUnwindDestinations(
|
|
const BasicBlock *EHPadBB, BranchProbability Prob,
|
|
SmallVectorImpl<std::pair<MachineBasicBlock *, BranchProbability>>
|
|
&UnwindDests);
|
|
|
|
bool translateInvoke(const User &U, MachineIRBuilder &MIRBuilder);
|
|
|
|
bool translateCallBr(const User &U, MachineIRBuilder &MIRBuilder);
|
|
|
|
bool translateLandingPad(const User &U, MachineIRBuilder &MIRBuilder);
|
|
|
|
/// Translate one of LLVM's cast instructions into MachineInstrs, with the
|
|
/// given generic Opcode.
|
|
bool translateCast(unsigned Opcode, const User &U,
|
|
MachineIRBuilder &MIRBuilder);
|
|
|
|
/// Translate a phi instruction.
|
|
bool translatePHI(const User &U, MachineIRBuilder &MIRBuilder);
|
|
|
|
/// Translate a comparison (icmp or fcmp) instruction or constant.
|
|
bool translateCompare(const User &U, MachineIRBuilder &MIRBuilder);
|
|
|
|
/// Translate an integer compare instruction (or constant).
|
|
bool translateICmp(const User &U, MachineIRBuilder &MIRBuilder) {
|
|
return translateCompare(U, MIRBuilder);
|
|
}
|
|
|
|
/// Translate a floating-point compare instruction (or constant).
|
|
bool translateFCmp(const User &U, MachineIRBuilder &MIRBuilder) {
|
|
return translateCompare(U, MIRBuilder);
|
|
}
|
|
|
|
/// Add remaining operands onto phis we've translated. Executed after all
|
|
/// MachineBasicBlocks for the function have been created.
|
|
void finishPendingPhis();
|
|
|
|
/// Translate \p Inst into a unary operation \p Opcode.
|
|
/// \pre \p U is a unary operation.
|
|
bool translateUnaryOp(unsigned Opcode, const User &U,
|
|
MachineIRBuilder &MIRBuilder);
|
|
|
|
/// Translate \p Inst into a binary operation \p Opcode.
|
|
/// \pre \p U is a binary operation.
|
|
bool translateBinaryOp(unsigned Opcode, const User &U,
|
|
MachineIRBuilder &MIRBuilder);
|
|
|
|
/// If the set of cases should be emitted as a series of branches, return
|
|
/// true. If we should emit this as a bunch of and/or'd together conditions,
|
|
/// return false.
|
|
bool shouldEmitAsBranches(const std::vector<SwitchCG::CaseBlock> &Cases);
|
|
/// Helper method for findMergedConditions.
|
|
/// This function emits a branch and is used at the leaves of an OR or an
|
|
/// AND operator tree.
|
|
void emitBranchForMergedCondition(const Value *Cond, MachineBasicBlock *TBB,
|
|
MachineBasicBlock *FBB,
|
|
MachineBasicBlock *CurBB,
|
|
MachineBasicBlock *SwitchBB,
|
|
BranchProbability TProb,
|
|
BranchProbability FProb, bool InvertCond);
|
|
/// Used during condbr translation to find trees of conditions that can be
|
|
/// optimized.
|
|
void findMergedConditions(const Value *Cond, MachineBasicBlock *TBB,
|
|
MachineBasicBlock *FBB, MachineBasicBlock *CurBB,
|
|
MachineBasicBlock *SwitchBB,
|
|
Instruction::BinaryOps Opc, BranchProbability TProb,
|
|
BranchProbability FProb, bool InvertCond);
|
|
|
|
/// Translate branch (br) instruction.
|
|
/// \pre \p U is a branch instruction.
|
|
bool translateBr(const User &U, MachineIRBuilder &MIRBuilder);
|
|
|
|
// Begin switch lowering functions.
|
|
bool emitJumpTableHeader(SwitchCG::JumpTable &JT,
|
|
SwitchCG::JumpTableHeader &JTH,
|
|
MachineBasicBlock *HeaderBB);
|
|
void emitJumpTable(SwitchCG::JumpTable &JT, MachineBasicBlock *MBB);
|
|
|
|
void emitSwitchCase(SwitchCG::CaseBlock &CB, MachineBasicBlock *SwitchBB,
|
|
MachineIRBuilder &MIB);
|
|
|
|
/// Generate for for the BitTest header block, which precedes each sequence of
|
|
/// BitTestCases.
|
|
void emitBitTestHeader(SwitchCG::BitTestBlock &BTB,
|
|
MachineBasicBlock *SwitchMBB);
|
|
/// Generate code to produces one "bit test" for a given BitTestCase \p B.
|
|
void emitBitTestCase(SwitchCG::BitTestBlock &BB, MachineBasicBlock *NextMBB,
|
|
BranchProbability BranchProbToNext, Register Reg,
|
|
SwitchCG::BitTestCase &B, MachineBasicBlock *SwitchBB);
|
|
|
|
bool lowerJumpTableWorkItem(
|
|
SwitchCG::SwitchWorkListItem W, MachineBasicBlock *SwitchMBB,
|
|
MachineBasicBlock *CurMBB, MachineBasicBlock *DefaultMBB,
|
|
MachineIRBuilder &MIB, MachineFunction::iterator BBI,
|
|
BranchProbability UnhandledProbs, SwitchCG::CaseClusterIt I,
|
|
MachineBasicBlock *Fallthrough, bool FallthroughUnreachable);
|
|
|
|
bool lowerSwitchRangeWorkItem(SwitchCG::CaseClusterIt I, Value *Cond,
|
|
MachineBasicBlock *Fallthrough,
|
|
bool FallthroughUnreachable,
|
|
BranchProbability UnhandledProbs,
|
|
MachineBasicBlock *CurMBB,
|
|
MachineIRBuilder &MIB,
|
|
MachineBasicBlock *SwitchMBB);
|
|
|
|
bool lowerBitTestWorkItem(
|
|
SwitchCG::SwitchWorkListItem W, MachineBasicBlock *SwitchMBB,
|
|
MachineBasicBlock *CurMBB, MachineBasicBlock *DefaultMBB,
|
|
MachineIRBuilder &MIB, MachineFunction::iterator BBI,
|
|
BranchProbability DefaultProb, BranchProbability UnhandledProbs,
|
|
SwitchCG::CaseClusterIt I, MachineBasicBlock *Fallthrough,
|
|
bool FallthroughUnreachable);
|
|
|
|
bool lowerSwitchWorkItem(SwitchCG::SwitchWorkListItem W, Value *Cond,
|
|
MachineBasicBlock *SwitchMBB,
|
|
MachineBasicBlock *DefaultMBB,
|
|
MachineIRBuilder &MIB);
|
|
|
|
bool translateSwitch(const User &U, MachineIRBuilder &MIRBuilder);
|
|
// End switch lowering section.
|
|
|
|
bool translateIndirectBr(const User &U, MachineIRBuilder &MIRBuilder);
|
|
|
|
bool translateExtractValue(const User &U, MachineIRBuilder &MIRBuilder);
|
|
|
|
bool translateInsertValue(const User &U, MachineIRBuilder &MIRBuilder);
|
|
|
|
bool translateSelect(const User &U, MachineIRBuilder &MIRBuilder);
|
|
|
|
bool translateGetElementPtr(const User &U, MachineIRBuilder &MIRBuilder);
|
|
|
|
bool translateAlloca(const User &U, MachineIRBuilder &MIRBuilder);
|
|
|
|
/// Translate return (ret) instruction.
|
|
/// The target needs to implement CallLowering::lowerReturn for
|
|
/// this to succeed.
|
|
/// \pre \p U is a return instruction.
|
|
bool translateRet(const User &U, MachineIRBuilder &MIRBuilder);
|
|
|
|
bool translateFNeg(const User &U, MachineIRBuilder &MIRBuilder);
|
|
|
|
bool translateAdd(const User &U, MachineIRBuilder &MIRBuilder) {
|
|
return translateBinaryOp(TargetOpcode::G_ADD, U, MIRBuilder);
|
|
}
|
|
bool translateSub(const User &U, MachineIRBuilder &MIRBuilder) {
|
|
return translateBinaryOp(TargetOpcode::G_SUB, U, MIRBuilder);
|
|
}
|
|
bool translateAnd(const User &U, MachineIRBuilder &MIRBuilder) {
|
|
return translateBinaryOp(TargetOpcode::G_AND, U, MIRBuilder);
|
|
}
|
|
bool translateMul(const User &U, MachineIRBuilder &MIRBuilder) {
|
|
return translateBinaryOp(TargetOpcode::G_MUL, U, MIRBuilder);
|
|
}
|
|
bool translateOr(const User &U, MachineIRBuilder &MIRBuilder) {
|
|
return translateBinaryOp(TargetOpcode::G_OR, U, MIRBuilder);
|
|
}
|
|
bool translateXor(const User &U, MachineIRBuilder &MIRBuilder) {
|
|
return translateBinaryOp(TargetOpcode::G_XOR, U, MIRBuilder);
|
|
}
|
|
|
|
bool translateUDiv(const User &U, MachineIRBuilder &MIRBuilder) {
|
|
return translateBinaryOp(TargetOpcode::G_UDIV, U, MIRBuilder);
|
|
}
|
|
bool translateSDiv(const User &U, MachineIRBuilder &MIRBuilder) {
|
|
return translateBinaryOp(TargetOpcode::G_SDIV, U, MIRBuilder);
|
|
}
|
|
bool translateURem(const User &U, MachineIRBuilder &MIRBuilder) {
|
|
return translateBinaryOp(TargetOpcode::G_UREM, U, MIRBuilder);
|
|
}
|
|
bool translateSRem(const User &U, MachineIRBuilder &MIRBuilder) {
|
|
return translateBinaryOp(TargetOpcode::G_SREM, U, MIRBuilder);
|
|
}
|
|
bool translateIntToPtr(const User &U, MachineIRBuilder &MIRBuilder) {
|
|
return translateCast(TargetOpcode::G_INTTOPTR, U, MIRBuilder);
|
|
}
|
|
bool translatePtrToInt(const User &U, MachineIRBuilder &MIRBuilder) {
|
|
return translateCast(TargetOpcode::G_PTRTOINT, U, MIRBuilder);
|
|
}
|
|
bool translateTrunc(const User &U, MachineIRBuilder &MIRBuilder) {
|
|
return translateCast(TargetOpcode::G_TRUNC, U, MIRBuilder);
|
|
}
|
|
bool translateFPTrunc(const User &U, MachineIRBuilder &MIRBuilder) {
|
|
return translateCast(TargetOpcode::G_FPTRUNC, U, MIRBuilder);
|
|
}
|
|
bool translateFPExt(const User &U, MachineIRBuilder &MIRBuilder) {
|
|
return translateCast(TargetOpcode::G_FPEXT, U, MIRBuilder);
|
|
}
|
|
bool translateFPToUI(const User &U, MachineIRBuilder &MIRBuilder) {
|
|
return translateCast(TargetOpcode::G_FPTOUI, U, MIRBuilder);
|
|
}
|
|
bool translateFPToSI(const User &U, MachineIRBuilder &MIRBuilder) {
|
|
return translateCast(TargetOpcode::G_FPTOSI, U, MIRBuilder);
|
|
}
|
|
bool translateUIToFP(const User &U, MachineIRBuilder &MIRBuilder) {
|
|
return translateCast(TargetOpcode::G_UITOFP, U, MIRBuilder);
|
|
}
|
|
bool translateSIToFP(const User &U, MachineIRBuilder &MIRBuilder) {
|
|
return translateCast(TargetOpcode::G_SITOFP, U, MIRBuilder);
|
|
}
|
|
bool translateUnreachable(const User &U, MachineIRBuilder &MIRBuilder) {
|
|
return true;
|
|
}
|
|
bool translateSExt(const User &U, MachineIRBuilder &MIRBuilder) {
|
|
return translateCast(TargetOpcode::G_SEXT, U, MIRBuilder);
|
|
}
|
|
|
|
bool translateZExt(const User &U, MachineIRBuilder &MIRBuilder) {
|
|
return translateCast(TargetOpcode::G_ZEXT, U, MIRBuilder);
|
|
}
|
|
|
|
bool translateShl(const User &U, MachineIRBuilder &MIRBuilder) {
|
|
return translateBinaryOp(TargetOpcode::G_SHL, U, MIRBuilder);
|
|
}
|
|
bool translateLShr(const User &U, MachineIRBuilder &MIRBuilder) {
|
|
return translateBinaryOp(TargetOpcode::G_LSHR, U, MIRBuilder);
|
|
}
|
|
bool translateAShr(const User &U, MachineIRBuilder &MIRBuilder) {
|
|
return translateBinaryOp(TargetOpcode::G_ASHR, U, MIRBuilder);
|
|
}
|
|
|
|
bool translateFAdd(const User &U, MachineIRBuilder &MIRBuilder) {
|
|
return translateBinaryOp(TargetOpcode::G_FADD, U, MIRBuilder);
|
|
}
|
|
bool translateFSub(const User &U, MachineIRBuilder &MIRBuilder) {
|
|
return translateBinaryOp(TargetOpcode::G_FSUB, U, MIRBuilder);
|
|
}
|
|
bool translateFMul(const User &U, MachineIRBuilder &MIRBuilder) {
|
|
return translateBinaryOp(TargetOpcode::G_FMUL, U, MIRBuilder);
|
|
}
|
|
bool translateFDiv(const User &U, MachineIRBuilder &MIRBuilder) {
|
|
return translateBinaryOp(TargetOpcode::G_FDIV, U, MIRBuilder);
|
|
}
|
|
bool translateFRem(const User &U, MachineIRBuilder &MIRBuilder) {
|
|
return translateBinaryOp(TargetOpcode::G_FREM, U, MIRBuilder);
|
|
}
|
|
|
|
bool translateVAArg(const User &U, MachineIRBuilder &MIRBuilder);
|
|
|
|
bool translateInsertElement(const User &U, MachineIRBuilder &MIRBuilder);
|
|
|
|
bool translateExtractElement(const User &U, MachineIRBuilder &MIRBuilder);
|
|
|
|
bool translateShuffleVector(const User &U, MachineIRBuilder &MIRBuilder);
|
|
|
|
bool translateAtomicCmpXchg(const User &U, MachineIRBuilder &MIRBuilder);
|
|
bool translateAtomicRMW(const User &U, MachineIRBuilder &MIRBuilder);
|
|
bool translateFence(const User &U, MachineIRBuilder &MIRBuilder);
|
|
bool translateFreeze(const User &U, MachineIRBuilder &MIRBuilder);
|
|
|
|
// Stubs to keep the compiler happy while we implement the rest of the
|
|
// translation.
|
|
bool translateResume(const User &U, MachineIRBuilder &MIRBuilder) {
|
|
return false;
|
|
}
|
|
bool translateCleanupRet(const User &U, MachineIRBuilder &MIRBuilder) {
|
|
return false;
|
|
}
|
|
bool translateCatchRet(const User &U, MachineIRBuilder &MIRBuilder) {
|
|
return false;
|
|
}
|
|
bool translateCatchSwitch(const User &U, MachineIRBuilder &MIRBuilder) {
|
|
return false;
|
|
}
|
|
bool translateAddrSpaceCast(const User &U, MachineIRBuilder &MIRBuilder) {
|
|
return translateCast(TargetOpcode::G_ADDRSPACE_CAST, U, MIRBuilder);
|
|
}
|
|
bool translateCleanupPad(const User &U, MachineIRBuilder &MIRBuilder) {
|
|
return false;
|
|
}
|
|
bool translateCatchPad(const User &U, MachineIRBuilder &MIRBuilder) {
|
|
return false;
|
|
}
|
|
bool translateUserOp1(const User &U, MachineIRBuilder &MIRBuilder) {
|
|
return false;
|
|
}
|
|
bool translateUserOp2(const User &U, MachineIRBuilder &MIRBuilder) {
|
|
return false;
|
|
}
|
|
|
|
/// @}
|
|
|
|
// Builder for machine instruction a la IRBuilder.
|
|
// I.e., compared to regular MIBuilder, this one also inserts the instruction
|
|
// in the current block, it can creates block, etc., basically a kind of
|
|
// IRBuilder, but for Machine IR.
|
|
// CSEMIRBuilder CurBuilder;
|
|
std::unique_ptr<MachineIRBuilder> CurBuilder;
|
|
|
|
// Builder set to the entry block (just after ABI lowering instructions). Used
|
|
// as a convenient location for Constants.
|
|
// CSEMIRBuilder EntryBuilder;
|
|
std::unique_ptr<MachineIRBuilder> EntryBuilder;
|
|
|
|
// The MachineFunction currently being translated.
|
|
MachineFunction *MF;
|
|
|
|
/// MachineRegisterInfo used to create virtual registers.
|
|
MachineRegisterInfo *MRI = nullptr;
|
|
|
|
const DataLayout *DL;
|
|
|
|
/// Current target configuration. Controls how the pass handles errors.
|
|
const TargetPassConfig *TPC;
|
|
|
|
CodeGenOpt::Level OptLevel;
|
|
|
|
/// Current optimization remark emitter. Used to report failures.
|
|
std::unique_ptr<OptimizationRemarkEmitter> ORE;
|
|
|
|
FunctionLoweringInfo FuncInfo;
|
|
|
|
// True when either the Target Machine specifies no optimizations or the
|
|
// function has the optnone attribute.
|
|
bool EnableOpts = false;
|
|
|
|
/// True when the block contains a tail call. This allows the IRTranslator to
|
|
/// stop translating such blocks early.
|
|
bool HasTailCall = false;
|
|
|
|
/// Switch analysis and optimization.
|
|
class GISelSwitchLowering : public SwitchCG::SwitchLowering {
|
|
public:
|
|
GISelSwitchLowering(IRTranslator *irt, FunctionLoweringInfo &funcinfo)
|
|
: SwitchLowering(funcinfo), IRT(irt) {
|
|
assert(irt && "irt is null!");
|
|
}
|
|
|
|
virtual void addSuccessorWithProb(
|
|
MachineBasicBlock *Src, MachineBasicBlock *Dst,
|
|
BranchProbability Prob = BranchProbability::getUnknown()) override {
|
|
IRT->addSuccessorWithProb(Src, Dst, Prob);
|
|
}
|
|
|
|
virtual ~GISelSwitchLowering() = default;
|
|
|
|
private:
|
|
IRTranslator *IRT;
|
|
};
|
|
|
|
std::unique_ptr<GISelSwitchLowering> SL;
|
|
|
|
// * Insert all the code needed to materialize the constants
|
|
// at the proper place. E.g., Entry block or dominator block
|
|
// of each constant depending on how fancy we want to be.
|
|
// * Clear the different maps.
|
|
void finalizeFunction();
|
|
|
|
// Handle emitting jump tables for each basic block.
|
|
void finalizeBasicBlock();
|
|
|
|
/// Get the VRegs that represent \p Val.
|
|
/// Non-aggregate types have just one corresponding VReg and the list can be
|
|
/// used as a single "unsigned". Aggregates get flattened. If such VRegs do
|
|
/// not exist, they are created.
|
|
ArrayRef<Register> getOrCreateVRegs(const Value &Val);
|
|
|
|
Register getOrCreateVReg(const Value &Val) {
|
|
auto Regs = getOrCreateVRegs(Val);
|
|
if (Regs.empty())
|
|
return 0;
|
|
assert(Regs.size() == 1 &&
|
|
"attempt to get single VReg for aggregate or void");
|
|
return Regs[0];
|
|
}
|
|
|
|
/// Allocate some vregs and offsets in the VMap. Then populate just the
|
|
/// offsets while leaving the vregs empty.
|
|
ValueToVRegInfo::VRegListT &allocateVRegs(const Value &Val);
|
|
|
|
/// Get the frame index that represents \p Val.
|
|
/// If such VReg does not exist, it is created.
|
|
int getOrCreateFrameIndex(const AllocaInst &AI);
|
|
|
|
/// Get the alignment of the given memory operation instruction. This will
|
|
/// either be the explicitly specified value or the ABI-required alignment for
|
|
/// the type being accessed (according to the Module's DataLayout).
|
|
Align getMemOpAlign(const Instruction &I);
|
|
|
|
/// Get the MachineBasicBlock that represents \p BB. Specifically, the block
|
|
/// returned will be the head of the translated block (suitable for branch
|
|
/// destinations).
|
|
MachineBasicBlock &getMBB(const BasicBlock &BB);
|
|
|
|
/// Record \p NewPred as a Machine predecessor to `Edge.second`, corresponding
|
|
/// to `Edge.first` at the IR level. This is used when IRTranslation creates
|
|
/// multiple MachineBasicBlocks for a given IR block and the CFG is no longer
|
|
/// represented simply by the IR-level CFG.
|
|
void addMachineCFGPred(CFGEdge Edge, MachineBasicBlock *NewPred);
|
|
|
|
/// Returns the Machine IR predecessors for the given IR CFG edge. Usually
|
|
/// this is just the single MachineBasicBlock corresponding to the predecessor
|
|
/// in the IR. More complex lowering can result in multiple MachineBasicBlocks
|
|
/// preceding the original though (e.g. switch instructions).
|
|
SmallVector<MachineBasicBlock *, 1> getMachinePredBBs(CFGEdge Edge) {
|
|
auto RemappedEdge = MachinePreds.find(Edge);
|
|
if (RemappedEdge != MachinePreds.end())
|
|
return RemappedEdge->second;
|
|
return SmallVector<MachineBasicBlock *, 4>(1, &getMBB(*Edge.first));
|
|
}
|
|
|
|
/// Return branch probability calculated by BranchProbabilityInfo for IR
|
|
/// blocks.
|
|
BranchProbability getEdgeProbability(const MachineBasicBlock *Src,
|
|
const MachineBasicBlock *Dst) const;
|
|
|
|
void addSuccessorWithProb(
|
|
MachineBasicBlock *Src, MachineBasicBlock *Dst,
|
|
BranchProbability Prob = BranchProbability::getUnknown());
|
|
|
|
public:
|
|
IRTranslator(CodeGenOpt::Level OptLevel = CodeGenOpt::None);
|
|
|
|
StringRef getPassName() const override { return "IRTranslator"; }
|
|
|
|
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
|
|
|
// Algo:
|
|
// CallLowering = MF.subtarget.getCallLowering()
|
|
// F = MF.getParent()
|
|
// MIRBuilder.reset(MF)
|
|
// getMBB(F.getEntryBB())
|
|
// CallLowering->translateArguments(MIRBuilder, F, ValToVReg)
|
|
// for each bb in F
|
|
// getMBB(bb)
|
|
// for each inst in bb
|
|
// if (!translate(MIRBuilder, inst, ValToVReg, ConstantToSequence))
|
|
// report_fatal_error("Don't know how to translate input");
|
|
// finalize()
|
|
bool runOnMachineFunction(MachineFunction &MF) override;
|
|
};
|
|
|
|
} // end namespace llvm
|
|
|
|
#endif // LLVM_CODEGEN_GLOBALISEL_IRTRANSLATOR_H
|