Vendor import of llvm trunk r304460:
https://llvm.org/svn/llvm-project/llvm/trunk@304460
This commit is contained in:
parent
ee2f195dd3
commit
f382538d47
@ -44,12 +44,12 @@ Users can control the vectorization SIMD width using the command line flag "-for
|
||||
$ clang -mllvm -force-vector-width=8 ...
|
||||
$ opt -loop-vectorize -force-vector-width=8 ...
|
||||
|
||||
Users can control the unroll factor using the command line flag "-force-vector-unroll"
|
||||
Users can control the unroll factor using the command line flag "-force-vector-interleave"
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ clang -mllvm -force-vector-unroll=2 ...
|
||||
$ opt -loop-vectorize -force-vector-unroll=2 ...
|
||||
$ clang -mllvm -force-vector-interleave=2 ...
|
||||
$ opt -loop-vectorize -force-vector-interleave=2 ...
|
||||
|
||||
Pragma loop hint directives
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -454,6 +454,9 @@ public:
|
||||
/// \brief Don't restrict interleaved unrolling to small loops.
|
||||
bool enableAggressiveInterleaving(bool LoopHasReductions) const;
|
||||
|
||||
/// \brief Enable inline expansion of memcmp
|
||||
bool expandMemCmp(Instruction *I, unsigned &MaxLoadSize) const;
|
||||
|
||||
/// \brief Enable matching of interleaved access groups.
|
||||
bool enableInterleavedAccessVectorization() const;
|
||||
|
||||
@ -828,6 +831,7 @@ public:
|
||||
unsigned VF) = 0;
|
||||
virtual bool supportsEfficientVectorElementLoadStore() = 0;
|
||||
virtual bool enableAggressiveInterleaving(bool LoopHasReductions) = 0;
|
||||
virtual bool expandMemCmp(Instruction *I, unsigned &MaxLoadSize) = 0;
|
||||
virtual bool enableInterleavedAccessVectorization() = 0;
|
||||
virtual bool isFPVectorizationPotentiallyUnsafe() = 0;
|
||||
virtual bool allowsMisalignedMemoryAccesses(LLVMContext &Context,
|
||||
@ -1047,6 +1051,9 @@ public:
|
||||
bool enableAggressiveInterleaving(bool LoopHasReductions) override {
|
||||
return Impl.enableAggressiveInterleaving(LoopHasReductions);
|
||||
}
|
||||
bool expandMemCmp(Instruction *I, unsigned &MaxLoadSize) override {
|
||||
return Impl.expandMemCmp(I, MaxLoadSize);
|
||||
}
|
||||
bool enableInterleavedAccessVectorization() override {
|
||||
return Impl.enableInterleavedAccessVectorization();
|
||||
}
|
||||
|
@ -274,6 +274,8 @@ public:
|
||||
|
||||
bool enableAggressiveInterleaving(bool LoopHasReductions) { return false; }
|
||||
|
||||
bool expandMemCmp(Instruction *I, unsigned &MaxLoadSize) { return false; }
|
||||
|
||||
bool enableInterleavedAccessVectorization() { return false; }
|
||||
|
||||
bool isFPVectorizationPotentiallyUnsafe() { return false; }
|
||||
|
@ -85,6 +85,8 @@ template <typename T> class ArrayRef;
|
||||
const Instruction *CxtI = nullptr,
|
||||
const DominatorTree *DT = nullptr);
|
||||
|
||||
bool isOnlyUsedInZeroEqualityComparison(const Instruction *CxtI);
|
||||
|
||||
/// Return true if the given value is known to be non-zero when defined. For
|
||||
/// vectors, return true if every element is known to be non-zero when
|
||||
/// defined. For pointers, if the context instruction and dominator tree are
|
||||
|
@ -396,7 +396,7 @@ protected:
|
||||
mutable DenseMap<unsigned, std::unique_ptr<const InstructionMapping>>
|
||||
MapOfInstructionMappings;
|
||||
|
||||
/// Create a RegisterBankInfo that can accomodate up to \p NumRegBanks
|
||||
/// Create a RegisterBankInfo that can accommodate up to \p NumRegBanks
|
||||
/// RegisterBank instances.
|
||||
RegisterBankInfo(RegisterBank **RegBanks, unsigned NumRegBanks);
|
||||
|
||||
|
@ -410,12 +410,22 @@ namespace ISD {
|
||||
/// then the result type must also be a vector type.
|
||||
SETCC,
|
||||
|
||||
/// Like SetCC, ops #0 and #1 are the LHS and RHS operands to compare, but
|
||||
/// Like SetCC, ops #0 and #1 are the LHS and RHS operands to compare, and
|
||||
/// op #2 is a *carry value*. This operator checks the result of
|
||||
/// "LHS - RHS - Carry", and can be used to compare two wide integers:
|
||||
/// (setcce lhshi rhshi (subc lhslo rhslo) cc). Only valid for integers.
|
||||
/// FIXME: This node is deprecated in favor of SETCCCARRY.
|
||||
/// It is kept around for now to provide a smooth transition path
|
||||
/// toward the use of SETCCCARRY and will eventually be removed.
|
||||
SETCCE,
|
||||
|
||||
/// Like SetCC, ops #0 and #1 are the LHS and RHS operands to compare, but
|
||||
/// op #2 is a boolean indicating if there is an incoming carry. This
|
||||
/// operator checks the result of "LHS - RHS - Carry", and can be used to
|
||||
/// compare two wide integers: (setcce lhshi rhshi (subc lhslo rhslo) cc).
|
||||
/// Only valid for integers.
|
||||
SETCCCARRY,
|
||||
|
||||
/// SHL_PARTS/SRA_PARTS/SRL_PARTS - These operators are used for expanded
|
||||
/// integer shift operations. The operation ordering is:
|
||||
/// [Lo,Hi] = op [LoLHS,HiLHS], Amt
|
||||
|
@ -381,7 +381,6 @@ struct MachineFunction {
|
||||
StringRef Name;
|
||||
unsigned Alignment = 0;
|
||||
bool ExposesReturnsTwice = false;
|
||||
bool NoVRegs;
|
||||
// GISel MachineFunctionProperties.
|
||||
bool Legalized = false;
|
||||
bool RegBankSelected = false;
|
||||
@ -406,7 +405,6 @@ template <> struct MappingTraits<MachineFunction> {
|
||||
YamlIO.mapRequired("name", MF.Name);
|
||||
YamlIO.mapOptional("alignment", MF.Alignment);
|
||||
YamlIO.mapOptional("exposesReturnsTwice", MF.ExposesReturnsTwice);
|
||||
YamlIO.mapOptional("noVRegs", MF.NoVRegs);
|
||||
YamlIO.mapOptional("legalized", MF.Legalized);
|
||||
YamlIO.mapOptional("regBankSelected", MF.RegBankSelected);
|
||||
YamlIO.mapOptional("selected", MF.Selected);
|
||||
|
@ -335,6 +335,9 @@ public:
|
||||
return make_range(livein_begin(), livein_end());
|
||||
}
|
||||
|
||||
/// Remove entry from the livein set and return iterator to the next.
|
||||
livein_iterator removeLiveIn(livein_iterator I);
|
||||
|
||||
/// Get the clobber mask for the start of this basic block. Funclets use this
|
||||
/// to prevent register allocation across funclet transitions.
|
||||
const uint32_t *getBeginClobberMask(const TargetRegisterInfo *TRI) const;
|
||||
|
@ -1,4 +1,4 @@
|
||||
//===-- CodeGen/MachineConstantPool.h - Abstract Constant Pool --*- C++ -*-===//
|
||||
//===- CodeGen/MachineConstantPool.h - Abstract Constant Pool ---*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -18,29 +18,28 @@
|
||||
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include "llvm/MC/SectionKind.h"
|
||||
#include <cassert>
|
||||
#include <climits>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class Constant;
|
||||
class FoldingSetNodeID;
|
||||
class DataLayout;
|
||||
class TargetMachine;
|
||||
class Type;
|
||||
class FoldingSetNodeID;
|
||||
class MachineConstantPool;
|
||||
class raw_ostream;
|
||||
class Type;
|
||||
|
||||
/// Abstract base class for all machine specific constantpool value subclasses.
|
||||
///
|
||||
class MachineConstantPoolValue {
|
||||
virtual void anchor();
|
||||
|
||||
Type *Ty;
|
||||
|
||||
public:
|
||||
explicit MachineConstantPoolValue(Type *ty) : Ty(ty) {}
|
||||
virtual ~MachineConstantPoolValue() {}
|
||||
virtual ~MachineConstantPoolValue() = default;
|
||||
|
||||
/// getType - get type of this MachineConstantPoolValue.
|
||||
///
|
||||
@ -81,6 +80,7 @@ public:
|
||||
: Alignment(A) {
|
||||
Val.ConstVal = V;
|
||||
}
|
||||
|
||||
MachineConstantPoolEntry(MachineConstantPoolValue *V, unsigned A)
|
||||
: Alignment(A) {
|
||||
Val.MachineCPVal = V;
|
||||
@ -153,13 +153,12 @@ public:
|
||||
|
||||
/// print - Used by the MachineFunction printer to print information about
|
||||
/// constant pool objects. Implemented in MachineFunction.cpp
|
||||
///
|
||||
void print(raw_ostream &OS) const;
|
||||
|
||||
/// dump - Call print(cerr) to be called from the debugger.
|
||||
void dump() const;
|
||||
};
|
||||
|
||||
} // End llvm namespace
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
#endif // LLVM_CODEGEN_MACHINECONSTANTPOOL_H
|
||||
|
@ -1,4 +1,4 @@
|
||||
//===-- llvm/CodeGen/MachineFunction.h --------------------------*- C++ -*-===//
|
||||
//===- llvm/CodeGen/MachineFunction.h ---------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -18,38 +18,61 @@
|
||||
#ifndef LLVM_CODEGEN_MACHINEFUNCTION_H
|
||||
#define LLVM_CODEGEN_MACHINEFUNCTION_H
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/BitVector.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/GraphTraits.h"
|
||||
#include "llvm/ADT/ilist.h"
|
||||
#include "llvm/ADT/iterator.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Analysis/EHPersonalities.h"
|
||||
#include "llvm/CodeGen/MachineBasicBlock.h"
|
||||
#include "llvm/CodeGen/MachineInstr.h"
|
||||
#include "llvm/CodeGen/MachineMemOperand.h"
|
||||
#include "llvm/IR/DebugLoc.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
#include "llvm/IR/Metadata.h"
|
||||
#include "llvm/MC/MCDwarf.h"
|
||||
#include "llvm/MC/MCSymbol.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/Support/ArrayRecycler.h"
|
||||
#include "llvm/Support/AtomicOrdering.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/Recycler.h"
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class Value;
|
||||
class BasicBlock;
|
||||
class BlockAddress;
|
||||
class DataLayout;
|
||||
class DIExpression;
|
||||
class DILocalVariable;
|
||||
class DILocation;
|
||||
class Function;
|
||||
class GCModuleInfo;
|
||||
class MachineRegisterInfo;
|
||||
class MachineFrameInfo;
|
||||
class GlobalValue;
|
||||
class MachineConstantPool;
|
||||
class MachineFrameInfo;
|
||||
class MachineFunction;
|
||||
class MachineJumpTableInfo;
|
||||
class MachineModuleInfo;
|
||||
class MachineRegisterInfo;
|
||||
class MCContext;
|
||||
class MCInstrDesc;
|
||||
class Pass;
|
||||
class PseudoSourceValueManager;
|
||||
class raw_ostream;
|
||||
class SlotIndexes;
|
||||
class TargetMachine;
|
||||
class TargetSubtargetInfo;
|
||||
class TargetRegisterClass;
|
||||
struct MachinePointerInfo;
|
||||
class TargetSubtargetInfo;
|
||||
struct WinEHFuncInfo;
|
||||
|
||||
template <> struct ilist_alloc_traits<MachineBasicBlock> {
|
||||
@ -137,27 +160,33 @@ public:
|
||||
bool hasProperty(Property P) const {
|
||||
return Properties[static_cast<unsigned>(P)];
|
||||
}
|
||||
|
||||
MachineFunctionProperties &set(Property P) {
|
||||
Properties.set(static_cast<unsigned>(P));
|
||||
return *this;
|
||||
}
|
||||
|
||||
MachineFunctionProperties &reset(Property P) {
|
||||
Properties.reset(static_cast<unsigned>(P));
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Reset all the properties.
|
||||
MachineFunctionProperties &reset() {
|
||||
Properties.reset();
|
||||
return *this;
|
||||
}
|
||||
|
||||
MachineFunctionProperties &set(const MachineFunctionProperties &MFP) {
|
||||
Properties |= MFP.Properties;
|
||||
return *this;
|
||||
}
|
||||
|
||||
MachineFunctionProperties &reset(const MachineFunctionProperties &MFP) {
|
||||
Properties.reset(MFP.Properties);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Returns true if all properties set in V (i.e. required by a pass) are set
|
||||
// in this.
|
||||
bool verifyRequiredProperties(const MachineFunctionProperties &V) const {
|
||||
@ -180,18 +209,17 @@ struct SEHHandler {
|
||||
const BlockAddress *RecoverBA;
|
||||
};
|
||||
|
||||
|
||||
/// This structure is used to retain landing pad info for the current function.
|
||||
struct LandingPadInfo {
|
||||
MachineBasicBlock *LandingPadBlock; // Landing pad block.
|
||||
SmallVector<MCSymbol *, 1> BeginLabels; // Labels prior to invoke.
|
||||
SmallVector<MCSymbol *, 1> EndLabels; // Labels after invoke.
|
||||
SmallVector<SEHHandler, 1> SEHHandlers; // SEH handlers active at this lpad.
|
||||
MCSymbol *LandingPadLabel; // Label at beginning of landing pad.
|
||||
std::vector<int> TypeIds; // List of type ids (filters negative).
|
||||
MCSymbol *LandingPadLabel = nullptr; // Label at beginning of landing pad.
|
||||
std::vector<int> TypeIds; // List of type ids (filters negative).
|
||||
|
||||
explicit LandingPadInfo(MachineBasicBlock *MBB)
|
||||
: LandingPadBlock(MBB), LandingPadLabel(nullptr) {}
|
||||
: LandingPadBlock(MBB) {}
|
||||
};
|
||||
|
||||
class MachineFunction {
|
||||
@ -239,7 +267,7 @@ class MachineFunction {
|
||||
Recycler<MachineBasicBlock> BasicBlockRecycler;
|
||||
|
||||
// List of machine basic blocks in function
|
||||
typedef ilist<MachineBasicBlock> BasicBlockListType;
|
||||
using BasicBlockListType = ilist<MachineBasicBlock>;
|
||||
BasicBlockListType BasicBlocks;
|
||||
|
||||
/// FunctionNumber - This provides a unique ID for each function emitted in
|
||||
@ -281,7 +309,7 @@ class MachineFunction {
|
||||
std::vector<LandingPadInfo> LandingPads;
|
||||
|
||||
/// Map a landing pad's EH symbol to the call site indexes.
|
||||
DenseMap<MCSymbol*, SmallVector<unsigned, 4> > LPadToCallSiteMap;
|
||||
DenseMap<MCSymbol*, SmallVector<unsigned, 4>> LPadToCallSiteMap;
|
||||
|
||||
/// Map of invoke call site index values to associated begin EH_LABEL.
|
||||
DenseMap<MCSymbol*, unsigned> CallSiteMap;
|
||||
@ -303,9 +331,6 @@ class MachineFunction {
|
||||
|
||||
/// \}
|
||||
|
||||
MachineFunction(const MachineFunction &) = delete;
|
||||
void operator=(const MachineFunction&) = delete;
|
||||
|
||||
/// Clear all the members of this MachineFunction, but the ones used
|
||||
/// to initialize again the MachineFunction.
|
||||
/// More specifically, this deallocates all the dynamically allocated
|
||||
@ -316,8 +341,8 @@ class MachineFunction {
|
||||
/// In particular, the XXXInfo data structure.
|
||||
/// \pre Fn, Target, MMI, and FunctionNumber are properly set.
|
||||
void init();
|
||||
public:
|
||||
|
||||
public:
|
||||
struct VariableDbgInfo {
|
||||
const DILocalVariable *Var;
|
||||
const DIExpression *Expr;
|
||||
@ -328,11 +353,13 @@ public:
|
||||
unsigned Slot, const DILocation *Loc)
|
||||
: Var(Var), Expr(Expr), Slot(Slot), Loc(Loc) {}
|
||||
};
|
||||
typedef SmallVector<VariableDbgInfo, 4> VariableDbgInfoMapTy;
|
||||
using VariableDbgInfoMapTy = SmallVector<VariableDbgInfo, 4>;
|
||||
VariableDbgInfoMapTy VariableDbgInfos;
|
||||
|
||||
MachineFunction(const Function *Fn, const TargetMachine &TM,
|
||||
unsigned FunctionNum, MachineModuleInfo &MMI);
|
||||
MachineFunction(const MachineFunction &) = delete;
|
||||
MachineFunction &operator=(const MachineFunction &) = delete;
|
||||
~MachineFunction();
|
||||
|
||||
/// Reset the instance as if it was just created.
|
||||
@ -350,19 +377,15 @@ public:
|
||||
const DataLayout &getDataLayout() const;
|
||||
|
||||
/// getFunction - Return the LLVM function that this machine code represents
|
||||
///
|
||||
const Function *getFunction() const { return Fn; }
|
||||
|
||||
/// getName - Return the name of the corresponding LLVM function.
|
||||
///
|
||||
StringRef getName() const;
|
||||
|
||||
/// getFunctionNumber - Return a unique ID for the current function.
|
||||
///
|
||||
unsigned getFunctionNumber() const { return FunctionNumber; }
|
||||
|
||||
/// getTarget - Return the target machine this machine code is compiled with
|
||||
///
|
||||
const TargetMachine &getTarget() const { return Target; }
|
||||
|
||||
/// getSubtarget - Return the subtarget for which this machine code is being
|
||||
@ -378,14 +401,12 @@ public:
|
||||
}
|
||||
|
||||
/// getRegInfo - Return information about the registers currently in use.
|
||||
///
|
||||
MachineRegisterInfo &getRegInfo() { return *RegInfo; }
|
||||
const MachineRegisterInfo &getRegInfo() const { return *RegInfo; }
|
||||
|
||||
/// getFrameInfo - Return the frame info object for the current function.
|
||||
/// This object contains information about objects allocated on the stack
|
||||
/// frame of the current function in an abstract way.
|
||||
///
|
||||
MachineFrameInfo &getFrameInfo() { return *FrameInfo; }
|
||||
const MachineFrameInfo &getFrameInfo() const { return *FrameInfo; }
|
||||
|
||||
@ -402,7 +423,6 @@ public:
|
||||
|
||||
/// getConstantPool - Return the constant pool object for the current
|
||||
/// function.
|
||||
///
|
||||
MachineConstantPool *getConstantPool() { return ConstantPool; }
|
||||
const MachineConstantPool *getConstantPool() const { return ConstantPool; }
|
||||
|
||||
@ -413,11 +433,9 @@ public:
|
||||
WinEHFuncInfo *getWinEHFuncInfo() { return WinEHInfo; }
|
||||
|
||||
/// getAlignment - Return the alignment (log2, not bytes) of the function.
|
||||
///
|
||||
unsigned getAlignment() const { return Alignment; }
|
||||
|
||||
/// setAlignment - Set the alignment (log2, not bytes) of the function.
|
||||
///
|
||||
void setAlignment(unsigned A) { Alignment = A; }
|
||||
|
||||
/// ensureAlignment - Make sure the function is at least 1 << A bytes aligned.
|
||||
@ -487,7 +505,6 @@ public:
|
||||
bool shouldSplitStack() const;
|
||||
|
||||
/// getNumBlockIDs - Return the number of MBB ID's allocated.
|
||||
///
|
||||
unsigned getNumBlockIDs() const { return (unsigned)MBBNumbering.size(); }
|
||||
|
||||
/// RenumberBlocks - This discards all of the MachineBasicBlock numbers and
|
||||
@ -499,7 +516,6 @@ public:
|
||||
|
||||
/// print - Print out the MachineFunction in a format suitable for debugging
|
||||
/// to the specified stream.
|
||||
///
|
||||
void print(raw_ostream &OS, const SlotIndexes* = nullptr) const;
|
||||
|
||||
/// viewCFG - This function is meant for use from the debugger. You can just
|
||||
@ -507,7 +523,6 @@ public:
|
||||
/// program, displaying the CFG of the current function with the code for each
|
||||
/// basic block inside. This depends on there being a 'dot' and 'gv' program
|
||||
/// in your path.
|
||||
///
|
||||
void viewCFG() const;
|
||||
|
||||
/// viewCFGOnly - This function is meant for use from the debugger. It works
|
||||
@ -518,7 +533,6 @@ public:
|
||||
void viewCFGOnly() const;
|
||||
|
||||
/// dump - Print the current MachineFunction to cerr, useful for debugger use.
|
||||
///
|
||||
void dump() const;
|
||||
|
||||
/// Run the current MachineFunction through the machine code verifier, useful
|
||||
@ -528,10 +542,10 @@ public:
|
||||
bool AbortOnError = true) const;
|
||||
|
||||
// Provide accessors for the MachineBasicBlock list...
|
||||
typedef BasicBlockListType::iterator iterator;
|
||||
typedef BasicBlockListType::const_iterator const_iterator;
|
||||
typedef BasicBlockListType::const_reverse_iterator const_reverse_iterator;
|
||||
typedef BasicBlockListType::reverse_iterator reverse_iterator;
|
||||
using iterator = BasicBlockListType::iterator;
|
||||
using const_iterator = BasicBlockListType::const_iterator;
|
||||
using const_reverse_iterator = BasicBlockListType::const_reverse_iterator;
|
||||
using reverse_iterator = BasicBlockListType::reverse_iterator;
|
||||
|
||||
/// Support for MachineBasicBlock::getNextNode().
|
||||
static BasicBlockListType MachineFunction::*
|
||||
@ -590,11 +604,9 @@ public:
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Internal functions used to automatically number MachineBasicBlocks
|
||||
//
|
||||
|
||||
/// \brief Adds the MBB to the internal numbering. Returns the unique number
|
||||
/// assigned to the MBB.
|
||||
///
|
||||
unsigned addToMBBNumbering(MachineBasicBlock *MBB) {
|
||||
MBBNumbering.push_back(MBB);
|
||||
return (unsigned)MBBNumbering.size()-1;
|
||||
@ -610,7 +622,6 @@ public:
|
||||
|
||||
/// CreateMachineInstr - Allocate a new MachineInstr. Use this instead
|
||||
/// of `new MachineInstr'.
|
||||
///
|
||||
MachineInstr *CreateMachineInstr(const MCInstrDesc &MCID, const DebugLoc &DL,
|
||||
bool NoImp = false);
|
||||
|
||||
@ -623,16 +634,13 @@ public:
|
||||
MachineInstr *CloneMachineInstr(const MachineInstr *Orig);
|
||||
|
||||
/// DeleteMachineInstr - Delete the given MachineInstr.
|
||||
///
|
||||
void DeleteMachineInstr(MachineInstr *MI);
|
||||
|
||||
/// CreateMachineBasicBlock - Allocate a new MachineBasicBlock. Use this
|
||||
/// instead of `new MachineBasicBlock'.
|
||||
///
|
||||
MachineBasicBlock *CreateMachineBasicBlock(const BasicBlock *bb = nullptr);
|
||||
|
||||
/// DeleteMachineBasicBlock - Delete the given MachineBasicBlock.
|
||||
///
|
||||
void DeleteMachineBasicBlock(MachineBasicBlock *MBB);
|
||||
|
||||
/// getMachineMemOperand - Allocate a new MachineMemOperand.
|
||||
@ -653,7 +661,7 @@ public:
|
||||
MachineMemOperand *getMachineMemOperand(const MachineMemOperand *MMO,
|
||||
int64_t Offset, uint64_t Size);
|
||||
|
||||
typedef ArrayRecycler<MachineOperand>::Capacity OperandCapacity;
|
||||
using OperandCapacity = ArrayRecycler<MachineOperand>::Capacity;
|
||||
|
||||
/// Allocate an array of MachineOperands. This is only intended for use by
|
||||
/// internal MachineInstr functions.
|
||||
@ -700,7 +708,6 @@ public:
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Label Manipulation.
|
||||
//
|
||||
|
||||
/// getJTISymbol - Return the MCSymbol for the specified non-empty jump table.
|
||||
/// If isLinkerPrivate is specified, an 'l' label is returned, otherwise a
|
||||
@ -858,13 +865,16 @@ template <> struct GraphTraits<MachineFunction*> :
|
||||
static NodeRef getEntryNode(MachineFunction *F) { return &F->front(); }
|
||||
|
||||
// nodes_iterator/begin/end - Allow iteration over all nodes in the graph
|
||||
typedef pointer_iterator<MachineFunction::iterator> nodes_iterator;
|
||||
using nodes_iterator = pointer_iterator<MachineFunction::iterator>;
|
||||
|
||||
static nodes_iterator nodes_begin(MachineFunction *F) {
|
||||
return nodes_iterator(F->begin());
|
||||
}
|
||||
|
||||
static nodes_iterator nodes_end(MachineFunction *F) {
|
||||
return nodes_iterator(F->end());
|
||||
}
|
||||
|
||||
static unsigned size (MachineFunction *F) { return F->size(); }
|
||||
};
|
||||
template <> struct GraphTraits<const MachineFunction*> :
|
||||
@ -872,37 +882,39 @@ template <> struct GraphTraits<const MachineFunction*> :
|
||||
static NodeRef getEntryNode(const MachineFunction *F) { return &F->front(); }
|
||||
|
||||
// nodes_iterator/begin/end - Allow iteration over all nodes in the graph
|
||||
typedef pointer_iterator<MachineFunction::const_iterator> nodes_iterator;
|
||||
using nodes_iterator = pointer_iterator<MachineFunction::const_iterator>;
|
||||
|
||||
static nodes_iterator nodes_begin(const MachineFunction *F) {
|
||||
return nodes_iterator(F->begin());
|
||||
}
|
||||
|
||||
static nodes_iterator nodes_end (const MachineFunction *F) {
|
||||
return nodes_iterator(F->end());
|
||||
}
|
||||
|
||||
static unsigned size (const MachineFunction *F) {
|
||||
return F->size();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Provide specializations of GraphTraits to be able to treat a function as a
|
||||
// graph of basic blocks... and to walk it in inverse order. Inverse order for
|
||||
// a function is considered to be when traversing the predecessor edges of a BB
|
||||
// instead of the successor edges.
|
||||
//
|
||||
template <> struct GraphTraits<Inverse<MachineFunction*> > :
|
||||
public GraphTraits<Inverse<MachineBasicBlock*> > {
|
||||
template <> struct GraphTraits<Inverse<MachineFunction*>> :
|
||||
public GraphTraits<Inverse<MachineBasicBlock*>> {
|
||||
static NodeRef getEntryNode(Inverse<MachineFunction *> G) {
|
||||
return &G.Graph->front();
|
||||
}
|
||||
};
|
||||
template <> struct GraphTraits<Inverse<const MachineFunction*> > :
|
||||
public GraphTraits<Inverse<const MachineBasicBlock*> > {
|
||||
template <> struct GraphTraits<Inverse<const MachineFunction*>> :
|
||||
public GraphTraits<Inverse<const MachineBasicBlock*>> {
|
||||
static NodeRef getEntryNode(Inverse<const MachineFunction *> G) {
|
||||
return &G.Graph->front();
|
||||
}
|
||||
};
|
||||
|
||||
} // End llvm namespace
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
#endif // LLVM_CODEGEN_MACHINEFUNCTION_H
|
||||
|
@ -1,4 +1,4 @@
|
||||
//===- MachineFunctionInitializer.h - machine function initializer ---------===//
|
||||
//=- MachineFunctionInitializer.h - machine function initializer --*- C++ -*-=//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -25,7 +25,7 @@ class MachineFunctionInitializer {
|
||||
virtual void anchor();
|
||||
|
||||
public:
|
||||
virtual ~MachineFunctionInitializer() {}
|
||||
virtual ~MachineFunctionInitializer() = default;
|
||||
|
||||
/// Initialize the machine function.
|
||||
///
|
||||
@ -35,4 +35,4 @@ public:
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
#endif // LLVM_CODEGEN_MACHINEFUNCTIONINITIALIZER_H
|
||||
|
@ -1,4 +1,4 @@
|
||||
//===-- llvm/CodeGen/MachineInstr.h - MachineInstr class --------*- C++ -*-===//
|
||||
//===- llvm/CodeGen/MachineInstr.h - MachineInstr class ---------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -17,7 +17,6 @@
|
||||
#define LLVM_CODEGEN_MACHINEINSTR_H
|
||||
|
||||
#include "llvm/ADT/DenseMapInfo.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/ilist.h"
|
||||
#include "llvm/ADT/ilist_node.h"
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
@ -28,19 +27,27 @@
|
||||
#include "llvm/MC/MCInstrDesc.h"
|
||||
#include "llvm/Support/ArrayRecycler.h"
|
||||
#include "llvm/Target/TargetOpcodes.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <utility>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class StringRef;
|
||||
template <typename T> class ArrayRef;
|
||||
template <typename T> class SmallVectorImpl;
|
||||
class DILocalVariable;
|
||||
class DIExpression;
|
||||
class DILocalVariable;
|
||||
class MachineBasicBlock;
|
||||
class MachineFunction;
|
||||
class MachineMemOperand;
|
||||
class MachineRegisterInfo;
|
||||
class ModuleSlotTracker;
|
||||
class raw_ostream;
|
||||
template <typename T> class SmallVectorImpl;
|
||||
class StringRef;
|
||||
class TargetInstrInfo;
|
||||
class TargetRegisterClass;
|
||||
class TargetRegisterInfo;
|
||||
class MachineFunction;
|
||||
class MachineMemOperand;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// Representation of each machine instruction.
|
||||
@ -53,7 +60,7 @@ class MachineInstr
|
||||
: public ilist_node_with_parent<MachineInstr, MachineBasicBlock,
|
||||
ilist_sentinel_tracking<true>> {
|
||||
public:
|
||||
typedef MachineMemOperand **mmo_iterator;
|
||||
using mmo_iterator = MachineMemOperand **;
|
||||
|
||||
/// Flags to specify different kinds of comments to output in
|
||||
/// assembly code. These flags carry semantic information not
|
||||
@ -72,43 +79,39 @@ public:
|
||||
BundledPred = 1 << 2, // Instruction has bundled predecessors.
|
||||
BundledSucc = 1 << 3 // Instruction has bundled successors.
|
||||
};
|
||||
|
||||
private:
|
||||
const MCInstrDesc *MCID; // Instruction descriptor.
|
||||
MachineBasicBlock *Parent; // Pointer to the owning basic block.
|
||||
MachineBasicBlock *Parent = nullptr; // Pointer to the owning basic block.
|
||||
|
||||
// Operands are allocated by an ArrayRecycler.
|
||||
MachineOperand *Operands; // Pointer to the first operand.
|
||||
unsigned NumOperands; // Number of operands on instruction.
|
||||
typedef ArrayRecycler<MachineOperand>::Capacity OperandCapacity;
|
||||
MachineOperand *Operands = nullptr; // Pointer to the first operand.
|
||||
unsigned NumOperands = 0; // Number of operands on instruction.
|
||||
using OperandCapacity = ArrayRecycler<MachineOperand>::Capacity;
|
||||
OperandCapacity CapOperands; // Capacity of the Operands array.
|
||||
|
||||
uint8_t Flags; // Various bits of additional
|
||||
uint8_t Flags = 0; // Various bits of additional
|
||||
// information about machine
|
||||
// instruction.
|
||||
|
||||
uint8_t AsmPrinterFlags; // Various bits of information used by
|
||||
uint8_t AsmPrinterFlags = 0; // Various bits of information used by
|
||||
// the AsmPrinter to emit helpful
|
||||
// comments. This is *not* semantic
|
||||
// information. Do not use this for
|
||||
// anything other than to convey comment
|
||||
// information to AsmPrinter.
|
||||
|
||||
uint8_t NumMemRefs; // Information on memory references.
|
||||
uint8_t NumMemRefs = 0; // Information on memory references.
|
||||
// Note that MemRefs == nullptr, means 'don't know', not 'no memory access'.
|
||||
// Calling code must treat missing information conservatively. If the number
|
||||
// of memory operands required to be precise exceeds the maximum value of
|
||||
// NumMemRefs - currently 256 - we remove the operands entirely. Note also
|
||||
// that this is a non-owning reference to a shared copy on write buffer owned
|
||||
// by the MachineFunction and created via MF.allocateMemRefsArray.
|
||||
mmo_iterator MemRefs;
|
||||
mmo_iterator MemRefs = nullptr;
|
||||
|
||||
DebugLoc debugLoc; // Source line information.
|
||||
|
||||
MachineInstr(const MachineInstr&) = delete;
|
||||
void operator=(const MachineInstr&) = delete;
|
||||
// Use MachineFunction::DeleteMachineInstr() instead.
|
||||
~MachineInstr() = delete;
|
||||
|
||||
// Intrusive list support
|
||||
friend struct ilist_traits<MachineInstr>;
|
||||
friend struct ilist_callback_traits<MachineBasicBlock>;
|
||||
@ -128,6 +131,11 @@ private:
|
||||
friend class MachineFunction;
|
||||
|
||||
public:
|
||||
MachineInstr(const MachineInstr &) = delete;
|
||||
MachineInstr &operator=(const MachineInstr &) = delete;
|
||||
// Use MachineFunction::DeleteMachineInstr() instead.
|
||||
~MachineInstr() = delete;
|
||||
|
||||
const MachineBasicBlock* getParent() const { return Parent; }
|
||||
MachineBasicBlock* getParent() { return Parent; }
|
||||
|
||||
@ -178,7 +186,6 @@ public:
|
||||
Flags &= ~((uint8_t)Flag);
|
||||
}
|
||||
|
||||
|
||||
/// Return true if MI is in a bundle (but not the first MI in a bundle).
|
||||
///
|
||||
/// A bundle looks like this before it's finalized:
|
||||
@ -263,7 +270,6 @@ public:
|
||||
/// earlier.
|
||||
///
|
||||
/// If this method returns, the caller should try to recover from the error.
|
||||
///
|
||||
void emitError(StringRef Msg) const;
|
||||
|
||||
/// Returns the target instruction descriptor of this MachineInstr.
|
||||
@ -273,7 +279,6 @@ public:
|
||||
unsigned getOpcode() const { return MCID->Opcode; }
|
||||
|
||||
/// Access to explicit operands of the instruction.
|
||||
///
|
||||
unsigned getNumOperands() const { return NumOperands; }
|
||||
|
||||
const MachineOperand& getOperand(unsigned i) const {
|
||||
@ -289,8 +294,8 @@ public:
|
||||
unsigned getNumExplicitOperands() const;
|
||||
|
||||
/// iterator/begin/end - Iterate over all operands of a machine instruction.
|
||||
typedef MachineOperand *mop_iterator;
|
||||
typedef const MachineOperand *const_mop_iterator;
|
||||
using mop_iterator = MachineOperand *;
|
||||
using const_mop_iterator = const MachineOperand *;
|
||||
|
||||
mop_iterator operands_begin() { return Operands; }
|
||||
mop_iterator operands_end() { return Operands + NumOperands; }
|
||||
@ -713,7 +718,6 @@ public:
|
||||
return hasProperty(MCID::ExtraDefRegAllocReq, Type);
|
||||
}
|
||||
|
||||
|
||||
enum MICheckType {
|
||||
CheckDefs, // Check all operands for equality
|
||||
CheckKillDead, // Check all operands including kill / dead markers
|
||||
@ -767,6 +771,7 @@ public:
|
||||
|
||||
/// Returns true if the MachineInstr represents a label.
|
||||
bool isLabel() const { return isEHLabel() || isGCLabel(); }
|
||||
|
||||
bool isCFIInstruction() const {
|
||||
return getOpcode() == TargetOpcode::CFI_INSTRUCTION;
|
||||
}
|
||||
@ -775,6 +780,7 @@ public:
|
||||
bool isPosition() const { return isLabel() || isCFIInstruction(); }
|
||||
|
||||
bool isDebugValue() const { return getOpcode() == TargetOpcode::DBG_VALUE; }
|
||||
|
||||
/// A DBG_VALUE is indirect iff the first operand is a register and
|
||||
/// the second operand is an immediate.
|
||||
bool isIndirectDebugValue() const {
|
||||
@ -787,29 +793,38 @@ public:
|
||||
bool isKill() const { return getOpcode() == TargetOpcode::KILL; }
|
||||
bool isImplicitDef() const { return getOpcode()==TargetOpcode::IMPLICIT_DEF; }
|
||||
bool isInlineAsm() const { return getOpcode() == TargetOpcode::INLINEASM; }
|
||||
|
||||
bool isMSInlineAsm() const {
|
||||
return getOpcode() == TargetOpcode::INLINEASM && getInlineAsmDialect();
|
||||
}
|
||||
|
||||
bool isStackAligningInlineAsm() const;
|
||||
InlineAsm::AsmDialect getInlineAsmDialect() const;
|
||||
|
||||
bool isInsertSubreg() const {
|
||||
return getOpcode() == TargetOpcode::INSERT_SUBREG;
|
||||
}
|
||||
|
||||
bool isSubregToReg() const {
|
||||
return getOpcode() == TargetOpcode::SUBREG_TO_REG;
|
||||
}
|
||||
|
||||
bool isRegSequence() const {
|
||||
return getOpcode() == TargetOpcode::REG_SEQUENCE;
|
||||
}
|
||||
|
||||
bool isBundle() const {
|
||||
return getOpcode() == TargetOpcode::BUNDLE;
|
||||
}
|
||||
|
||||
bool isCopy() const {
|
||||
return getOpcode() == TargetOpcode::COPY;
|
||||
}
|
||||
|
||||
bool isFullCopy() const {
|
||||
return isCopy() && !getOperand(0).getSubReg() && !getOperand(1).getSubReg();
|
||||
}
|
||||
|
||||
bool isExtractSubreg() const {
|
||||
return getOpcode() == TargetOpcode::EXTRACT_SUBREG;
|
||||
}
|
||||
@ -978,7 +993,6 @@ public:
|
||||
///
|
||||
/// The flag operand is an immediate that can be decoded with methods like
|
||||
/// InlineAsm::hasRegClassConstraint().
|
||||
///
|
||||
int findInlineAsmFlagIdx(unsigned OpIdx, unsigned *GroupNo = nullptr) const;
|
||||
|
||||
/// Compute the static register class constraint for operand OpIdx.
|
||||
@ -987,7 +1001,6 @@ public:
|
||||
///
|
||||
/// Returns NULL if the static register class constraint cannot be
|
||||
/// determined.
|
||||
///
|
||||
const TargetRegisterClass*
|
||||
getRegClassConstraint(unsigned OpIdx,
|
||||
const TargetInstrInfo *TII,
|
||||
@ -1328,6 +1341,6 @@ inline raw_ostream& operator<<(raw_ostream &OS, const MachineInstr &MI) {
|
||||
return OS;
|
||||
}
|
||||
|
||||
} // End llvm namespace
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
#endif // LLVM_CODEGEN_MACHINEINSTR_H
|
||||
|
@ -15,34 +15,37 @@
|
||||
#define LLVM_CODEGEN_MACHINEINSTRBUNDLEITERATOR_H
|
||||
|
||||
#include "llvm/ADT/ilist.h"
|
||||
#include "llvm/ADT/simple_ilist.h"
|
||||
#include <cassert>
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
template <class T, bool IsReverse> struct MachineInstrBundleIteratorTraits;
|
||||
template <class T> struct MachineInstrBundleIteratorTraits<T, false> {
|
||||
typedef simple_ilist<T, ilist_sentinel_tracking<true>> list_type;
|
||||
typedef typename list_type::iterator instr_iterator;
|
||||
typedef typename list_type::iterator nonconst_instr_iterator;
|
||||
typedef typename list_type::const_iterator const_instr_iterator;
|
||||
using list_type = simple_ilist<T, ilist_sentinel_tracking<true>>;
|
||||
using instr_iterator = typename list_type::iterator;
|
||||
using nonconst_instr_iterator = typename list_type::iterator;
|
||||
using const_instr_iterator = typename list_type::const_iterator;
|
||||
};
|
||||
template <class T> struct MachineInstrBundleIteratorTraits<T, true> {
|
||||
typedef simple_ilist<T, ilist_sentinel_tracking<true>> list_type;
|
||||
typedef typename list_type::reverse_iterator instr_iterator;
|
||||
typedef typename list_type::reverse_iterator nonconst_instr_iterator;
|
||||
typedef typename list_type::const_reverse_iterator const_instr_iterator;
|
||||
using list_type = simple_ilist<T, ilist_sentinel_tracking<true>>;
|
||||
using instr_iterator = typename list_type::reverse_iterator;
|
||||
using nonconst_instr_iterator = typename list_type::reverse_iterator;
|
||||
using const_instr_iterator = typename list_type::const_reverse_iterator;
|
||||
};
|
||||
template <class T> struct MachineInstrBundleIteratorTraits<const T, false> {
|
||||
typedef simple_ilist<T, ilist_sentinel_tracking<true>> list_type;
|
||||
typedef typename list_type::const_iterator instr_iterator;
|
||||
typedef typename list_type::iterator nonconst_instr_iterator;
|
||||
typedef typename list_type::const_iterator const_instr_iterator;
|
||||
using list_type = simple_ilist<T, ilist_sentinel_tracking<true>>;
|
||||
using instr_iterator = typename list_type::const_iterator;
|
||||
using nonconst_instr_iterator = typename list_type::iterator;
|
||||
using const_instr_iterator = typename list_type::const_iterator;
|
||||
};
|
||||
template <class T> struct MachineInstrBundleIteratorTraits<const T, true> {
|
||||
typedef simple_ilist<T, ilist_sentinel_tracking<true>> list_type;
|
||||
typedef typename list_type::const_reverse_iterator instr_iterator;
|
||||
typedef typename list_type::reverse_iterator nonconst_instr_iterator;
|
||||
typedef typename list_type::const_reverse_iterator const_instr_iterator;
|
||||
using list_type = simple_ilist<T, ilist_sentinel_tracking<true>>;
|
||||
using instr_iterator = typename list_type::const_reverse_iterator;
|
||||
using nonconst_instr_iterator = typename list_type::reverse_iterator;
|
||||
using const_instr_iterator = typename list_type::const_reverse_iterator;
|
||||
};
|
||||
|
||||
template <bool IsReverse> struct MachineInstrBundleIteratorHelper;
|
||||
@ -104,27 +107,27 @@ template <> struct MachineInstrBundleIteratorHelper<true> {
|
||||
/// inside bundles (i.e. walk top level MIs only).
|
||||
template <typename Ty, bool IsReverse = false>
|
||||
class MachineInstrBundleIterator : MachineInstrBundleIteratorHelper<IsReverse> {
|
||||
typedef MachineInstrBundleIteratorTraits<Ty, IsReverse> Traits;
|
||||
typedef typename Traits::instr_iterator instr_iterator;
|
||||
using Traits = MachineInstrBundleIteratorTraits<Ty, IsReverse>;
|
||||
using instr_iterator = typename Traits::instr_iterator;
|
||||
|
||||
instr_iterator MII;
|
||||
|
||||
public:
|
||||
typedef typename instr_iterator::value_type value_type;
|
||||
typedef typename instr_iterator::difference_type difference_type;
|
||||
typedef typename instr_iterator::pointer pointer;
|
||||
typedef typename instr_iterator::reference reference;
|
||||
typedef std::bidirectional_iterator_tag iterator_category;
|
||||
|
||||
typedef typename instr_iterator::const_pointer const_pointer;
|
||||
typedef typename instr_iterator::const_reference const_reference;
|
||||
using value_type = typename instr_iterator::value_type;
|
||||
using difference_type = typename instr_iterator::difference_type;
|
||||
using pointer = typename instr_iterator::pointer;
|
||||
using reference = typename instr_iterator::reference;
|
||||
using const_pointer = typename instr_iterator::const_pointer;
|
||||
using const_reference = typename instr_iterator::const_reference;
|
||||
using iterator_category = std::bidirectional_iterator_tag;
|
||||
|
||||
private:
|
||||
typedef typename Traits::nonconst_instr_iterator nonconst_instr_iterator;
|
||||
typedef typename Traits::const_instr_iterator const_instr_iterator;
|
||||
typedef MachineInstrBundleIterator<
|
||||
typename nonconst_instr_iterator::value_type, IsReverse>
|
||||
nonconst_iterator;
|
||||
typedef MachineInstrBundleIterator<Ty, !IsReverse> reverse_iterator;
|
||||
using nonconst_instr_iterator = typename Traits::nonconst_instr_iterator;
|
||||
using const_instr_iterator = typename Traits::const_instr_iterator;
|
||||
using nonconst_iterator =
|
||||
MachineInstrBundleIterator<typename nonconst_instr_iterator::value_type,
|
||||
IsReverse>;
|
||||
using reverse_iterator = MachineInstrBundleIterator<Ty, !IsReverse>;
|
||||
|
||||
public:
|
||||
MachineInstrBundleIterator(instr_iterator MI) : MII(MI) {
|
||||
@ -138,12 +141,14 @@ public:
|
||||
"MachineInstrBundleIterator with a "
|
||||
"bundled MI");
|
||||
}
|
||||
|
||||
MachineInstrBundleIterator(pointer MI) : MII(MI) {
|
||||
// FIXME: This conversion should be explicit.
|
||||
assert((!MI || !MI->isBundledWithPred()) && "It's not legal to initialize "
|
||||
"MachineInstrBundleIterator "
|
||||
"with a bundled MI");
|
||||
}
|
||||
|
||||
// Template allows conversion from const to nonconst.
|
||||
template <class OtherTy>
|
||||
MachineInstrBundleIterator(
|
||||
@ -151,6 +156,7 @@ public:
|
||||
typename std::enable_if<std::is_convertible<OtherTy *, Ty *>::value,
|
||||
void *>::type = nullptr)
|
||||
: MII(I.getInstrIterator()) {}
|
||||
|
||||
MachineInstrBundleIterator() : MII(nullptr) {}
|
||||
|
||||
/// Explicit conversion between forward/reverse iterators.
|
||||
@ -280,4 +286,4 @@ public:
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
#endif // LLVM_CODEGEN_MACHINEINSTRBUNDLEITERATOR_H
|
||||
|
@ -33,6 +33,8 @@
|
||||
#include "llvm/Analysis/LoopInfo.h"
|
||||
#include "llvm/CodeGen/MachineBasicBlock.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/IR/DebugLoc.h"
|
||||
#include "llvm/Pass.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
@ -71,6 +73,7 @@ public:
|
||||
|
||||
private:
|
||||
friend class LoopInfoBase<MachineBasicBlock, MachineLoop>;
|
||||
|
||||
explicit MachineLoop(MachineBasicBlock *MBB)
|
||||
: LoopBase<MachineBasicBlock, MachineLoop>(MBB) {}
|
||||
};
|
||||
@ -79,11 +82,9 @@ private:
|
||||
extern template class LoopInfoBase<MachineBasicBlock, MachineLoop>;
|
||||
|
||||
class MachineLoopInfo : public MachineFunctionPass {
|
||||
LoopInfoBase<MachineBasicBlock, MachineLoop> LI;
|
||||
friend class LoopBase<MachineBasicBlock, MachineLoop>;
|
||||
|
||||
void operator=(const MachineLoopInfo &) = delete;
|
||||
MachineLoopInfo(const MachineLoopInfo &) = delete;
|
||||
LoopInfoBase<MachineBasicBlock, MachineLoop> LI;
|
||||
|
||||
public:
|
||||
static char ID; // Pass identification, replacement for typeid
|
||||
@ -91,6 +92,8 @@ public:
|
||||
MachineLoopInfo() : MachineFunctionPass(ID) {
|
||||
initializeMachineLoopInfoPass(*PassRegistry::getPassRegistry());
|
||||
}
|
||||
MachineLoopInfo(const MachineLoopInfo &) = delete;
|
||||
MachineLoopInfo &operator=(const MachineLoopInfo &) = delete;
|
||||
|
||||
LoopInfoBase<MachineBasicBlock, MachineLoop>& getBase() { return LI; }
|
||||
|
||||
@ -103,7 +106,7 @@ public:
|
||||
bool SpeculativePreheader = false) const;
|
||||
|
||||
/// The iterator interface to the top-level loops in the current function.
|
||||
typedef LoopInfoBase<MachineBasicBlock, MachineLoop>::iterator iterator;
|
||||
using iterator = LoopInfoBase<MachineBasicBlock, MachineLoop>::iterator;
|
||||
inline iterator begin() const { return LI.begin(); }
|
||||
inline iterator end() const { return LI.end(); }
|
||||
bool empty() const { return LI.empty(); }
|
||||
@ -166,11 +169,10 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Allow clients to walk the list of nested loops...
|
||||
template <> struct GraphTraits<const MachineLoop*> {
|
||||
typedef const MachineLoop *NodeRef;
|
||||
typedef MachineLoopInfo::iterator ChildIteratorType;
|
||||
using NodeRef = const MachineLoop *;
|
||||
using ChildIteratorType = MachineLoopInfo::iterator;
|
||||
|
||||
static NodeRef getEntryNode(const MachineLoop *L) { return L; }
|
||||
static ChildIteratorType child_begin(NodeRef N) { return N->begin(); }
|
||||
@ -178,14 +180,14 @@ template <> struct GraphTraits<const MachineLoop*> {
|
||||
};
|
||||
|
||||
template <> struct GraphTraits<MachineLoop*> {
|
||||
typedef MachineLoop *NodeRef;
|
||||
typedef MachineLoopInfo::iterator ChildIteratorType;
|
||||
using NodeRef = MachineLoop *;
|
||||
using ChildIteratorType = MachineLoopInfo::iterator;
|
||||
|
||||
static NodeRef getEntryNode(MachineLoop *L) { return L; }
|
||||
static ChildIteratorType child_begin(NodeRef N) { return N->begin(); }
|
||||
static ChildIteratorType child_end(NodeRef N) { return N->end(); }
|
||||
};
|
||||
|
||||
} // End llvm namespace
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
#endif // LLVM_CODEGEN_MACHINELOOPINFO_H
|
||||
|
@ -31,35 +31,26 @@
|
||||
#ifndef LLVM_CODEGEN_MACHINEMODULEINFO_H
|
||||
#define LLVM_CODEGEN_MACHINEMODULEINFO_H
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/PointerIntPair.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/IR/DebugLoc.h"
|
||||
#include "llvm/IR/ValueHandle.h"
|
||||
#include "llvm/MC/MCContext.h"
|
||||
#include "llvm/MC/MCSymbol.h"
|
||||
#include "llvm/MC/MachineLocation.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Forward declarations.
|
||||
class BlockAddress;
|
||||
class BasicBlock;
|
||||
class CallInst;
|
||||
class Constant;
|
||||
class GlobalVariable;
|
||||
class LandingPadInst;
|
||||
class MDNode;
|
||||
class MMIAddrLabelMap;
|
||||
class MachineBasicBlock;
|
||||
class Function;
|
||||
class MachineFunction;
|
||||
class MachineFunctionInitializer;
|
||||
class MMIAddrLabelMap;
|
||||
class Module;
|
||||
class PointerType;
|
||||
class StructType;
|
||||
class TargetMachine;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// This class can be derived from and used by targets to hold private
|
||||
@ -69,11 +60,12 @@ class StructType;
|
||||
///
|
||||
class MachineModuleInfoImpl {
|
||||
public:
|
||||
typedef PointerIntPair<MCSymbol*, 1, bool> StubValueTy;
|
||||
virtual ~MachineModuleInfoImpl();
|
||||
typedef std::vector<std::pair<MCSymbol*, StubValueTy> > SymbolListTy;
|
||||
protected:
|
||||
using StubValueTy = PointerIntPair<MCSymbol *, 1, bool>;
|
||||
using SymbolListTy = std::vector<std::pair<MCSymbol *, StubValueTy>>;
|
||||
|
||||
virtual ~MachineModuleInfoImpl();
|
||||
|
||||
protected:
|
||||
/// Return the entries from a DenseMap in a deterministic sorted orer.
|
||||
/// Clears the map.
|
||||
static SymbolListTy getSortedStubs(DenseMap<MCSymbol*, StubValueTy>&);
|
||||
@ -252,6 +244,6 @@ public:
|
||||
/// which will link in MSVCRT's floating-point support.
|
||||
void computeUsesVAFloatArgument(const CallInst &I, MachineModuleInfo &MMI);
|
||||
|
||||
} // End llvm namespace
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
#endif // LLVM_CODEGEN_MACHINEMODULEINFO_H
|
||||
|
@ -133,6 +133,10 @@ namespace llvm {
|
||||
// instruction and update the MachineFunctionInfo with that information.
|
||||
extern char &ShrinkWrapID;
|
||||
|
||||
/// LiveRangeShrink pass. Move instruction close to its definition to shrink
|
||||
/// the definition's live range.
|
||||
extern char &LiveRangeShrinkID;
|
||||
|
||||
/// Greedy register allocator.
|
||||
extern char &RAGreedyID;
|
||||
|
||||
|
@ -22,7 +22,7 @@ namespace llvm {
|
||||
|
||||
class PassConfigImpl;
|
||||
class ScheduleDAGInstrs;
|
||||
class TargetMachine;
|
||||
class LLVMTargetMachine;
|
||||
struct MachineSchedContext;
|
||||
|
||||
// The old pass manager infrastructure is hidden in a legacy namespace now.
|
||||
@ -103,7 +103,7 @@ private:
|
||||
bool AddingMachinePasses;
|
||||
|
||||
protected:
|
||||
TargetMachine *TM;
|
||||
LLVMTargetMachine *TM;
|
||||
PassConfigImpl *Impl; // Internal data structures
|
||||
bool Initialized; // Flagged after all passes are configured.
|
||||
|
||||
@ -120,7 +120,7 @@ protected:
|
||||
bool RequireCodeGenSCCOrder;
|
||||
|
||||
public:
|
||||
TargetPassConfig(TargetMachine *tm, PassManagerBase &pm);
|
||||
TargetPassConfig(LLVMTargetMachine &TM, PassManagerBase &pm);
|
||||
// Dummy constructor.
|
||||
TargetPassConfig();
|
||||
|
||||
|
@ -6,6 +6,10 @@
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Defines constants and basic types describing CodeView debug information.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_DEBUGINFO_CODEVIEW_CODEVIEW_H
|
||||
#define LLVM_DEBUGINFO_CODEVIEW_CODEVIEW_H
|
||||
@ -22,28 +26,28 @@ namespace codeview {
|
||||
/// documentation and headers talk about this as the "leaf" type.
|
||||
enum class TypeRecordKind : uint16_t {
|
||||
#define TYPE_RECORD(lf_ename, value, name) name = value,
|
||||
#include "TypeRecords.def"
|
||||
#include "CodeViewTypes.def"
|
||||
};
|
||||
|
||||
/// Duplicate copy of the above enum, but using the official CV names. Useful
|
||||
/// for reference purposes and when dealing with unknown record types.
|
||||
enum TypeLeafKind : uint16_t {
|
||||
#define CV_TYPE(name, val) name = val,
|
||||
#include "TypeRecords.def"
|
||||
#include "CodeViewTypes.def"
|
||||
};
|
||||
|
||||
/// Distinguishes individual records in the Symbols subsection of a .debug$S
|
||||
/// section. Equivalent to SYM_ENUM_e in cvinfo.h.
|
||||
enum class SymbolRecordKind : uint16_t {
|
||||
#define SYMBOL_RECORD(lf_ename, value, name) name = value,
|
||||
#include "CVSymbolTypes.def"
|
||||
#include "CodeViewSymbols.def"
|
||||
};
|
||||
|
||||
/// Duplicate copy of the above enum, but using the official CV names. Useful
|
||||
/// for reference purposes and when dealing with unknown record types.
|
||||
enum SymbolKind : uint16_t {
|
||||
#define CV_SYMBOL(name, val) name = val,
|
||||
#include "CVSymbolTypes.def"
|
||||
#include "CodeViewSymbols.def"
|
||||
};
|
||||
|
||||
#define CV_DEFINE_ENUM_CLASS_FLAGS_OPERATORS(Class) \
|
||||
@ -280,7 +284,7 @@ CV_DEFINE_ENUM_CLASS_FLAGS_OPERATORS(MethodOptions)
|
||||
/// Equivalent to CV_LABEL_TYPE_e.
|
||||
enum class LabelType : uint16_t {
|
||||
Near = 0x0,
|
||||
Far = 0x4,
|
||||
Far = 0x4,
|
||||
};
|
||||
|
||||
/// Equivalent to CV_modifier_t.
|
||||
|
@ -34,6 +34,17 @@ class SymbolDeserializer : public SymbolVisitorCallbacks {
|
||||
};
|
||||
|
||||
public:
|
||||
template <typename T> static Error deserializeAs(CVSymbol Symbol, T &Record) {
|
||||
SymbolDeserializer S(nullptr);
|
||||
if (auto EC = S.visitSymbolBegin(Symbol))
|
||||
return EC;
|
||||
if (auto EC = S.visitKnownRecord(Symbol, Record))
|
||||
return EC;
|
||||
if (auto EC = S.visitSymbolEnd(Symbol))
|
||||
return EC;
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
explicit SymbolDeserializer(SymbolVisitorDelegate *Delegate)
|
||||
: Delegate(Delegate) {}
|
||||
|
||||
@ -54,7 +65,7 @@ public:
|
||||
return visitKnownRecordImpl(CVR, Record); \
|
||||
}
|
||||
#define SYMBOL_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
|
||||
#include "CVSymbolTypes.def"
|
||||
#include "llvm/DebugInfo/CodeView/CodeViewSymbols.def"
|
||||
|
||||
private:
|
||||
template <typename T> Error visitKnownRecordImpl(CVSymbol &CVR, T &Record) {
|
||||
|
@ -35,8 +35,6 @@ protected:
|
||||
|
||||
public:
|
||||
SymbolRecordKind getKind() const { return Kind; }
|
||||
|
||||
private:
|
||||
SymbolRecordKind Kind;
|
||||
};
|
||||
|
||||
|
@ -29,7 +29,7 @@ public:
|
||||
#define SYMBOL_RECORD(EnumName, EnumVal, Name) \
|
||||
Error visitKnownRecord(CVSymbol &CVR, Name &Record) override;
|
||||
#define SYMBOL_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
|
||||
#include "CVSymbolTypes.def"
|
||||
#include "llvm/DebugInfo/CodeView/CodeViewSymbols.def"
|
||||
|
||||
private:
|
||||
Optional<SymbolKind> Kind;
|
||||
|
@ -45,6 +45,17 @@ class SymbolSerializer : public SymbolVisitorCallbacks {
|
||||
}
|
||||
|
||||
public:
|
||||
template <typename SymType>
|
||||
static CVSymbol writeOneSymbol(SymType &Sym, BumpPtrAllocator &Storage) {
|
||||
CVSymbol Result;
|
||||
Result.Type = static_cast<SymbolKind>(Sym.Kind);
|
||||
SymbolSerializer Serializer(Storage);
|
||||
consumeError(Serializer.visitSymbolBegin(Result));
|
||||
consumeError(Serializer.visitKnownRecord(Result, Sym));
|
||||
consumeError(Serializer.visitSymbolEnd(Result));
|
||||
return Result;
|
||||
}
|
||||
|
||||
explicit SymbolSerializer(BumpPtrAllocator &Storage);
|
||||
|
||||
virtual Error visitSymbolBegin(CVSymbol &Record) override;
|
||||
@ -55,7 +66,7 @@ public:
|
||||
return visitKnownRecordImpl(CVR, Record); \
|
||||
}
|
||||
#define SYMBOL_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
|
||||
#include "CVSymbolTypes.def"
|
||||
#include "llvm/DebugInfo/CodeView/CodeViewSymbols.def"
|
||||
|
||||
private:
|
||||
template <typename RecordKind>
|
||||
|
@ -59,7 +59,7 @@ public:
|
||||
return Error::success(); \
|
||||
}
|
||||
#define SYMBOL_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
|
||||
#include "llvm/DebugInfo/CodeView/CVSymbolTypes.def"
|
||||
#include "llvm/DebugInfo/CodeView/CodeViewSymbols.def"
|
||||
|
||||
private:
|
||||
std::vector<SymbolVisitorCallbacks *> Pipeline;
|
||||
|
@ -39,7 +39,7 @@ public:
|
||||
return Error::success(); \
|
||||
}
|
||||
#define SYMBOL_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
|
||||
#include "CVSymbolTypes.def"
|
||||
#include "llvm/DebugInfo/CodeView/CodeViewSymbols.def"
|
||||
};
|
||||
|
||||
} // end namespace codeview
|
||||
|
@ -39,7 +39,7 @@ public:
|
||||
Error visitKnownMember(CVMemberRecord &CVR, Name##Record &Record) override;
|
||||
#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
|
||||
#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
|
||||
#include "TypeRecords.def"
|
||||
#include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
|
||||
|
||||
private:
|
||||
StringRef getTypeName(TypeIndex Index) const;
|
||||
|
@ -41,6 +41,7 @@ public:
|
||||
TypeDeserializer() = default;
|
||||
|
||||
template <typename T> static Error deserializeAs(CVType &CVT, T &Record) {
|
||||
Record.Kind = static_cast<TypeRecordKind>(CVT.kind());
|
||||
MappingInfo I(CVT.content());
|
||||
if (auto EC = I.Mapping.visitTypeBegin(CVT))
|
||||
return EC;
|
||||
@ -75,7 +76,7 @@ public:
|
||||
#define MEMBER_RECORD(EnumName, EnumVal, Name)
|
||||
#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
|
||||
#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
|
||||
#include "TypeRecords.def"
|
||||
#include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
|
||||
|
||||
private:
|
||||
template <typename RecordType>
|
||||
@ -127,7 +128,7 @@ public:
|
||||
}
|
||||
#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
|
||||
#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
|
||||
#include "TypeRecords.def"
|
||||
#include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
|
||||
|
||||
private:
|
||||
template <typename RecordType>
|
||||
|
@ -58,7 +58,7 @@ public:
|
||||
Error visitKnownMember(CVMemberRecord &CVR, Name##Record &Record) override;
|
||||
#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
|
||||
#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
|
||||
#include "TypeRecords.def"
|
||||
#include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
|
||||
|
||||
private:
|
||||
void printMemberAttributes(MemberAttributes Attrs);
|
||||
|
@ -123,13 +123,13 @@ protected:
|
||||
public:
|
||||
TypeRecordKind getKind() const { return Kind; }
|
||||
|
||||
private:
|
||||
TypeRecordKind Kind;
|
||||
};
|
||||
|
||||
// LF_MODIFIER
|
||||
class ModifierRecord : public TypeRecord {
|
||||
public:
|
||||
ModifierRecord() = default;
|
||||
explicit ModifierRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
|
||||
ModifierRecord(TypeIndex ModifiedType, ModifierOptions Modifiers)
|
||||
: TypeRecord(TypeRecordKind::Modifier), ModifiedType(ModifiedType),
|
||||
@ -145,6 +145,7 @@ public:
|
||||
// LF_PROCEDURE
|
||||
class ProcedureRecord : public TypeRecord {
|
||||
public:
|
||||
ProcedureRecord() = default;
|
||||
explicit ProcedureRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
|
||||
ProcedureRecord(TypeIndex ReturnType, CallingConvention CallConv,
|
||||
FunctionOptions Options, uint16_t ParameterCount,
|
||||
@ -169,6 +170,7 @@ public:
|
||||
// LF_MFUNCTION
|
||||
class MemberFunctionRecord : public TypeRecord {
|
||||
public:
|
||||
MemberFunctionRecord() = default;
|
||||
explicit MemberFunctionRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
|
||||
|
||||
MemberFunctionRecord(TypeIndex ReturnType, TypeIndex ClassType,
|
||||
@ -203,6 +205,7 @@ public:
|
||||
// LF_LABEL
|
||||
class LabelRecord : public TypeRecord {
|
||||
public:
|
||||
LabelRecord() = default;
|
||||
explicit LabelRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
|
||||
|
||||
LabelRecord(LabelType Mode) : TypeRecord(TypeRecordKind::Label), Mode(Mode) {}
|
||||
@ -213,6 +216,7 @@ public:
|
||||
// LF_MFUNC_ID
|
||||
class MemberFuncIdRecord : public TypeRecord {
|
||||
public:
|
||||
MemberFuncIdRecord() = default;
|
||||
explicit MemberFuncIdRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
|
||||
MemberFuncIdRecord(TypeIndex ClassType, TypeIndex FunctionType,
|
||||
StringRef Name)
|
||||
@ -230,6 +234,7 @@ public:
|
||||
// LF_ARGLIST
|
||||
class ArgListRecord : public TypeRecord {
|
||||
public:
|
||||
ArgListRecord() = default;
|
||||
explicit ArgListRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
|
||||
|
||||
ArgListRecord(TypeRecordKind Kind, ArrayRef<TypeIndex> Indices)
|
||||
@ -243,6 +248,7 @@ public:
|
||||
// LF_SUBSTR_LIST
|
||||
class StringListRecord : public TypeRecord {
|
||||
public:
|
||||
StringListRecord() = default;
|
||||
explicit StringListRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
|
||||
|
||||
StringListRecord(TypeRecordKind Kind, ArrayRef<TypeIndex> Indices)
|
||||
@ -267,6 +273,7 @@ public:
|
||||
static const uint32_t PointerSizeShift = 13;
|
||||
static const uint32_t PointerSizeMask = 0xFF;
|
||||
|
||||
PointerRecord() = default;
|
||||
explicit PointerRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
|
||||
|
||||
PointerRecord(TypeIndex ReferentType, uint32_t Attrs)
|
||||
@ -341,6 +348,7 @@ private:
|
||||
// LF_NESTTYPE
|
||||
class NestedTypeRecord : public TypeRecord {
|
||||
public:
|
||||
NestedTypeRecord() = default;
|
||||
explicit NestedTypeRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
|
||||
NestedTypeRecord(TypeIndex Type, StringRef Name)
|
||||
: TypeRecord(TypeRecordKind::NestedType), Type(Type), Name(Name) {}
|
||||
@ -355,6 +363,7 @@ public:
|
||||
// LF_FIELDLIST
|
||||
class FieldListRecord : public TypeRecord {
|
||||
public:
|
||||
FieldListRecord() = default;
|
||||
explicit FieldListRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
|
||||
explicit FieldListRecord(ArrayRef<uint8_t> Data)
|
||||
: TypeRecord(TypeRecordKind::FieldList), Data(Data) {}
|
||||
@ -365,6 +374,7 @@ public:
|
||||
// LF_ARRAY
|
||||
class ArrayRecord : public TypeRecord {
|
||||
public:
|
||||
ArrayRecord() = default;
|
||||
explicit ArrayRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
|
||||
ArrayRecord(TypeIndex ElementType, TypeIndex IndexType, uint64_t Size,
|
||||
StringRef Name)
|
||||
@ -384,6 +394,7 @@ public:
|
||||
|
||||
class TagRecord : public TypeRecord {
|
||||
protected:
|
||||
TagRecord() = default;
|
||||
explicit TagRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
|
||||
TagRecord(TypeRecordKind Kind, uint16_t MemberCount, ClassOptions Options,
|
||||
TypeIndex FieldList, StringRef Name, StringRef UniqueName)
|
||||
@ -416,6 +427,7 @@ public:
|
||||
// LF_CLASS, LF_STRUCTURE, LF_INTERFACE
|
||||
class ClassRecord : public TagRecord {
|
||||
public:
|
||||
ClassRecord() = default;
|
||||
explicit ClassRecord(TypeRecordKind Kind) : TagRecord(Kind) {}
|
||||
ClassRecord(TypeRecordKind Kind, uint16_t MemberCount, ClassOptions Options,
|
||||
TypeIndex FieldList, TypeIndex DerivationList,
|
||||
@ -447,6 +459,7 @@ public:
|
||||
|
||||
// LF_UNION
|
||||
struct UnionRecord : public TagRecord {
|
||||
UnionRecord() = default;
|
||||
explicit UnionRecord(TypeRecordKind Kind) : TagRecord(Kind) {}
|
||||
UnionRecord(uint16_t MemberCount, ClassOptions Options, TypeIndex FieldList,
|
||||
uint64_t Size, StringRef Name, StringRef UniqueName)
|
||||
@ -468,6 +481,7 @@ struct UnionRecord : public TagRecord {
|
||||
// LF_ENUM
|
||||
class EnumRecord : public TagRecord {
|
||||
public:
|
||||
EnumRecord() = default;
|
||||
explicit EnumRecord(TypeRecordKind Kind) : TagRecord(Kind) {}
|
||||
EnumRecord(uint16_t MemberCount, ClassOptions Options, TypeIndex FieldList,
|
||||
StringRef Name, StringRef UniqueName, TypeIndex UnderlyingType)
|
||||
@ -482,6 +496,7 @@ public:
|
||||
// LF_BITFIELD
|
||||
class BitFieldRecord : public TypeRecord {
|
||||
public:
|
||||
BitFieldRecord() = default;
|
||||
explicit BitFieldRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
|
||||
BitFieldRecord(TypeIndex Type, uint8_t BitSize, uint8_t BitOffset)
|
||||
: TypeRecord(TypeRecordKind::BitField), Type(Type), BitSize(BitSize),
|
||||
@ -498,6 +513,7 @@ public:
|
||||
// LF_VTSHAPE
|
||||
class VFTableShapeRecord : public TypeRecord {
|
||||
public:
|
||||
VFTableShapeRecord() = default;
|
||||
explicit VFTableShapeRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
|
||||
explicit VFTableShapeRecord(ArrayRef<VFTableSlotKind> Slots)
|
||||
: TypeRecord(TypeRecordKind::VFTableShape), SlotsRef(Slots) {}
|
||||
@ -518,6 +534,7 @@ public:
|
||||
// LF_TYPESERVER2
|
||||
class TypeServer2Record : public TypeRecord {
|
||||
public:
|
||||
TypeServer2Record() = default;
|
||||
explicit TypeServer2Record(TypeRecordKind Kind) : TypeRecord(Kind) {}
|
||||
TypeServer2Record(StringRef Guid, uint32_t Age, StringRef Name)
|
||||
: TypeRecord(TypeRecordKind::TypeServer2), Guid(Guid), Age(Age),
|
||||
@ -537,6 +554,7 @@ public:
|
||||
// LF_STRING_ID
|
||||
class StringIdRecord : public TypeRecord {
|
||||
public:
|
||||
StringIdRecord() = default;
|
||||
explicit StringIdRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
|
||||
StringIdRecord(TypeIndex Id, StringRef String)
|
||||
: TypeRecord(TypeRecordKind::StringId), Id(Id), String(String) {}
|
||||
@ -551,6 +569,7 @@ public:
|
||||
// LF_FUNC_ID
|
||||
class FuncIdRecord : public TypeRecord {
|
||||
public:
|
||||
FuncIdRecord() = default;
|
||||
explicit FuncIdRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
|
||||
FuncIdRecord(TypeIndex ParentScope, TypeIndex FunctionType, StringRef Name)
|
||||
: TypeRecord(TypeRecordKind::FuncId), ParentScope(ParentScope),
|
||||
@ -570,6 +589,7 @@ public:
|
||||
// LF_UDT_SRC_LINE
|
||||
class UdtSourceLineRecord : public TypeRecord {
|
||||
public:
|
||||
UdtSourceLineRecord() = default;
|
||||
explicit UdtSourceLineRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
|
||||
UdtSourceLineRecord(TypeIndex UDT, TypeIndex SourceFile, uint32_t LineNumber)
|
||||
: TypeRecord(TypeRecordKind::UdtSourceLine), UDT(UDT),
|
||||
@ -587,6 +607,7 @@ public:
|
||||
// LF_UDT_MOD_SRC_LINE
|
||||
class UdtModSourceLineRecord : public TypeRecord {
|
||||
public:
|
||||
UdtModSourceLineRecord() = default;
|
||||
explicit UdtModSourceLineRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
|
||||
UdtModSourceLineRecord(TypeIndex UDT, TypeIndex SourceFile,
|
||||
uint32_t LineNumber, uint16_t Module)
|
||||
@ -607,6 +628,7 @@ public:
|
||||
// LF_BUILDINFO
|
||||
class BuildInfoRecord : public TypeRecord {
|
||||
public:
|
||||
BuildInfoRecord() = default;
|
||||
explicit BuildInfoRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
|
||||
BuildInfoRecord(ArrayRef<TypeIndex> ArgIndices)
|
||||
: TypeRecord(TypeRecordKind::BuildInfo),
|
||||
@ -619,6 +641,7 @@ public:
|
||||
// LF_VFTABLE
|
||||
class VFTableRecord : public TypeRecord {
|
||||
public:
|
||||
VFTableRecord() = default;
|
||||
explicit VFTableRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
|
||||
VFTableRecord(TypeIndex CompleteClass, TypeIndex OverriddenVFTable,
|
||||
uint32_t VFPtrOffset, StringRef Name,
|
||||
@ -646,7 +669,7 @@ public:
|
||||
// LF_ONEMETHOD
|
||||
class OneMethodRecord : public TypeRecord {
|
||||
public:
|
||||
OneMethodRecord() : TypeRecord(TypeRecordKind::OneMethod) {}
|
||||
OneMethodRecord() = default;
|
||||
explicit OneMethodRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
|
||||
OneMethodRecord(TypeIndex Type, MemberAttributes Attrs, int32_t VFTableOffset,
|
||||
StringRef Name)
|
||||
@ -678,6 +701,7 @@ public:
|
||||
// LF_METHODLIST
|
||||
class MethodOverloadListRecord : public TypeRecord {
|
||||
public:
|
||||
MethodOverloadListRecord() = default;
|
||||
explicit MethodOverloadListRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
|
||||
MethodOverloadListRecord(ArrayRef<OneMethodRecord> Methods)
|
||||
: TypeRecord(TypeRecordKind::MethodOverloadList), Methods(Methods) {}
|
||||
@ -689,6 +713,7 @@ public:
|
||||
/// For method overload sets. LF_METHOD
|
||||
class OverloadedMethodRecord : public TypeRecord {
|
||||
public:
|
||||
OverloadedMethodRecord() = default;
|
||||
explicit OverloadedMethodRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
|
||||
OverloadedMethodRecord(uint16_t NumOverloads, TypeIndex MethodList,
|
||||
StringRef Name)
|
||||
@ -706,6 +731,7 @@ public:
|
||||
// LF_MEMBER
|
||||
class DataMemberRecord : public TypeRecord {
|
||||
public:
|
||||
DataMemberRecord() = default;
|
||||
explicit DataMemberRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
|
||||
DataMemberRecord(MemberAttributes Attrs, TypeIndex Type, uint64_t Offset,
|
||||
StringRef Name)
|
||||
@ -730,6 +756,7 @@ public:
|
||||
// LF_STMEMBER
|
||||
class StaticDataMemberRecord : public TypeRecord {
|
||||
public:
|
||||
StaticDataMemberRecord() = default;
|
||||
explicit StaticDataMemberRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
|
||||
StaticDataMemberRecord(MemberAttributes Attrs, TypeIndex Type, StringRef Name)
|
||||
: TypeRecord(TypeRecordKind::StaticDataMember), Attrs(Attrs), Type(Type),
|
||||
@ -750,6 +777,7 @@ public:
|
||||
// LF_ENUMERATE
|
||||
class EnumeratorRecord : public TypeRecord {
|
||||
public:
|
||||
EnumeratorRecord() = default;
|
||||
explicit EnumeratorRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
|
||||
EnumeratorRecord(MemberAttributes Attrs, APSInt Value, StringRef Name)
|
||||
: TypeRecord(TypeRecordKind::Enumerator), Attrs(Attrs),
|
||||
@ -770,6 +798,7 @@ public:
|
||||
// LF_VFUNCTAB
|
||||
class VFPtrRecord : public TypeRecord {
|
||||
public:
|
||||
VFPtrRecord() = default;
|
||||
explicit VFPtrRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
|
||||
VFPtrRecord(TypeIndex Type)
|
||||
: TypeRecord(TypeRecordKind::VFPtr), Type(Type) {}
|
||||
@ -782,6 +811,7 @@ public:
|
||||
// LF_BCLASS, LF_BINTERFACE
|
||||
class BaseClassRecord : public TypeRecord {
|
||||
public:
|
||||
BaseClassRecord() = default;
|
||||
explicit BaseClassRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
|
||||
BaseClassRecord(MemberAttributes Attrs, TypeIndex Type, uint64_t Offset)
|
||||
: TypeRecord(TypeRecordKind::BaseClass), Attrs(Attrs), Type(Type),
|
||||
@ -802,6 +832,7 @@ public:
|
||||
// LF_VBCLASS, LF_IVBCLASS
|
||||
class VirtualBaseClassRecord : public TypeRecord {
|
||||
public:
|
||||
VirtualBaseClassRecord() = default;
|
||||
explicit VirtualBaseClassRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
|
||||
VirtualBaseClassRecord(TypeRecordKind Kind, MemberAttributes Attrs,
|
||||
TypeIndex BaseType, TypeIndex VBPtrType,
|
||||
@ -831,6 +862,7 @@ public:
|
||||
/// together. The first will end in an LF_INDEX record that points to the next.
|
||||
class ListContinuationRecord : public TypeRecord {
|
||||
public:
|
||||
ListContinuationRecord() = default;
|
||||
explicit ListContinuationRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
|
||||
ListContinuationRecord(TypeIndex ContinuationIndex)
|
||||
: TypeRecord(TypeRecordKind::ListContinuation),
|
||||
|
@ -37,7 +37,7 @@ public:
|
||||
Error visitKnownMember(CVMemberRecord &CVR, Name##Record &Record) override;
|
||||
#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
|
||||
#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
|
||||
#include "TypeRecords.def"
|
||||
#include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
|
||||
|
||||
private:
|
||||
Optional<TypeLeafKind> TypeKind;
|
||||
|
@ -106,7 +106,7 @@ public:
|
||||
return visitKnownMemberImpl<Name##Record>(CVR, Record); \
|
||||
}
|
||||
#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
|
||||
#include "llvm/DebugInfo/CodeView/TypeRecords.def"
|
||||
#include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
|
||||
|
||||
private:
|
||||
template <typename RecordKind>
|
||||
|
@ -13,8 +13,8 @@
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/DebugInfo/CodeView/CodeView.h"
|
||||
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
|
||||
#include "llvm/DebugInfo/CodeView/TypeSerializer.h"
|
||||
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
|
||||
#include "llvm/DebugInfo/CodeView/TypeSerializer.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include <algorithm>
|
||||
|
@ -94,7 +94,7 @@ public:
|
||||
}
|
||||
#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
|
||||
#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
|
||||
#include "llvm/DebugInfo/CodeView/TypeRecords.def"
|
||||
#include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
|
||||
|
||||
private:
|
||||
template <typename T> Error visitKnownRecordImpl(CVType &CVR, T &Record) {
|
||||
|
@ -58,7 +58,11 @@ public:
|
||||
|
||||
#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
|
||||
#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
|
||||
#include "TypeRecords.def"
|
||||
#include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
|
||||
#undef TYPE_RECORD
|
||||
#undef TYPE_RECORD_ALIAS
|
||||
#undef MEMBER_RECORD
|
||||
#undef MEMBER_RECORD_ALIAS
|
||||
};
|
||||
|
||||
} // end namespace codeview
|
||||
|
@ -146,6 +146,14 @@ enum DIDumpType {
|
||||
DIDT_TUIndex,
|
||||
};
|
||||
|
||||
/// Container for dump options that control which debug information will be
|
||||
/// dumped.
|
||||
struct DIDumpOptions {
|
||||
DIDumpType DumpType = DIDT_All;
|
||||
bool DumpEH = false;
|
||||
bool SummarizeTypes = false;
|
||||
};
|
||||
|
||||
class DIContext {
|
||||
public:
|
||||
enum DIContextKind {
|
||||
@ -158,8 +166,7 @@ public:
|
||||
|
||||
DIContextKind getKind() const { return Kind; }
|
||||
|
||||
virtual void dump(raw_ostream &OS, DIDumpType DumpType = DIDT_All,
|
||||
bool DumpEH = false, bool SummarizeTypes = false) = 0;
|
||||
virtual void dump(raw_ostream &OS, DIDumpOptions DumpOpts) = 0;
|
||||
|
||||
virtual bool verify(raw_ostream &OS, DIDumpType DumpType = DIDT_All) {
|
||||
// No verifier? Just say things went well.
|
||||
|
@ -105,8 +105,7 @@ public:
|
||||
return DICtx->getKind() == CK_DWARF;
|
||||
}
|
||||
|
||||
void dump(raw_ostream &OS, DIDumpType DumpType = DIDT_All,
|
||||
bool DumpEH = false, bool SummarizeTypes = false) override;
|
||||
void dump(raw_ostream &OS, DIDumpOptions DumpOpts) override;
|
||||
|
||||
bool verify(raw_ostream &OS, DIDumpType DumpType = DIDT_All) override;
|
||||
|
||||
|
@ -12,7 +12,6 @@
|
||||
|
||||
#include "llvm/ADT/BitmaskEnum.h"
|
||||
#include "llvm/DebugInfo/CodeView/CodeView.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace llvm {
|
||||
|
@ -38,7 +38,7 @@ public:
|
||||
#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
|
||||
#define MEMBER_RECORD(EnumName, EnumVal, Name)
|
||||
#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
|
||||
#include "llvm/DebugInfo/CodeView/TypeRecords.def"
|
||||
#include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
|
||||
|
||||
private:
|
||||
template <typename RecordKind>
|
||||
|
@ -41,8 +41,7 @@ namespace pdb {
|
||||
return DICtx->getKind() == CK_PDB;
|
||||
}
|
||||
|
||||
void dump(raw_ostream &OS, DIDumpType DumpType = DIDT_All,
|
||||
bool DumpEH = false, bool SummarizeTypes = false) override;
|
||||
void dump(raw_ostream &OS, DIDumpOptions DIDumpOpts) override;
|
||||
|
||||
DILineInfo getLineInfoForAddress(
|
||||
uint64_t Address,
|
||||
|
@ -228,34 +228,31 @@ public:
|
||||
bool operator==(const AttributeSet &O) { return SetNode == O.SetNode; }
|
||||
bool operator!=(const AttributeSet &O) { return !(*this == O); }
|
||||
|
||||
/// Add an argument attribute. Because
|
||||
/// attribute sets are immutable, this returns a new set.
|
||||
AttributeSet addAttribute(LLVMContext &C,
|
||||
Attribute::AttrKind Kind) const;
|
||||
/// Add an argument attribute. Returns a new set because attribute sets are
|
||||
/// immutable.
|
||||
AttributeSet addAttribute(LLVMContext &C, Attribute::AttrKind Kind) const;
|
||||
|
||||
/// Add a target-dependent attribute. Because
|
||||
/// attribute sets are immutable, this returns a new set.
|
||||
/// Add a target-dependent attribute. Returns a new set because attribute sets
|
||||
/// are immutable.
|
||||
AttributeSet addAttribute(LLVMContext &C, StringRef Kind,
|
||||
StringRef Value = StringRef()) const;
|
||||
|
||||
/// Add attributes to the attribute set. Because
|
||||
/// attribute sets are immutable, this returns a new set.
|
||||
/// Add attributes to the attribute set. Returns a new set because attribute
|
||||
/// sets are immutable.
|
||||
AttributeSet addAttributes(LLVMContext &C, AttributeSet AS) const;
|
||||
|
||||
/// Remove the specified attribute from this set. Because
|
||||
/// attribute sets are immutable, this returns a new set.
|
||||
AttributeSet removeAttribute(LLVMContext &C,
|
||||
Attribute::AttrKind Kind) const;
|
||||
/// Remove the specified attribute from this set. Returns a new set because
|
||||
/// attribute sets are immutable.
|
||||
AttributeSet removeAttribute(LLVMContext &C, Attribute::AttrKind Kind) const;
|
||||
|
||||
/// Remove the specified attribute from this set. Because
|
||||
/// attribute sets are immutable, this returns a new set.
|
||||
AttributeSet removeAttribute(LLVMContext &C,
|
||||
StringRef Kind) const;
|
||||
/// Remove the specified attribute from this set. Returns a new set because
|
||||
/// attribute sets are immutable.
|
||||
AttributeSet removeAttribute(LLVMContext &C, StringRef Kind) const;
|
||||
|
||||
/// Remove the specified attributes from this set. Because
|
||||
/// attribute sets are immutable, this returns a new set.
|
||||
/// Remove the specified attributes from this set. Returns a new set because
|
||||
/// attribute sets are immutable.
|
||||
AttributeSet removeAttributes(LLVMContext &C,
|
||||
const AttrBuilder &AttrsToRemove) const;
|
||||
const AttrBuilder &AttrsToRemove) const;
|
||||
|
||||
/// Return the number of attributes in this set.
|
||||
unsigned getNumAttributes() const;
|
||||
@ -377,6 +374,25 @@ public:
|
||||
static AttributeList get(LLVMContext &C, unsigned Index,
|
||||
const AttrBuilder &B);
|
||||
|
||||
/// \brief Add an attribute to the attribute set at the given index.
|
||||
/// Returns a new list because attribute lists are immutable.
|
||||
AttributeList addAttribute(LLVMContext &C, unsigned Index,
|
||||
Attribute::AttrKind Kind) const;
|
||||
|
||||
/// \brief Add an attribute to the attribute set at the given index.
|
||||
/// Returns a new list because attribute lists are immutable.
|
||||
AttributeList addAttribute(LLVMContext &C, unsigned Index, StringRef Kind,
|
||||
StringRef Value = StringRef()) const;
|
||||
|
||||
/// Add an attribute to the attribute set at the given index.
|
||||
/// Returns a new list because attribute lists are immutable.
|
||||
AttributeList addAttribute(LLVMContext &C, unsigned Index, Attribute A) const;
|
||||
|
||||
/// \brief Add attributes to the attribute set at the given index.
|
||||
/// Returns a new list because attribute lists are immutable.
|
||||
AttributeList addAttributes(LLVMContext &C, unsigned Index,
|
||||
const AttrBuilder &B) const;
|
||||
|
||||
/// Add an argument attribute to the list. Returns a new list because
|
||||
/// attribute lists are immutable.
|
||||
AttributeList addParamAttribute(LLVMContext &C, unsigned ArgNo,
|
||||
@ -384,66 +400,112 @@ public:
|
||||
return addAttribute(C, ArgNo + FirstArgIndex, Kind);
|
||||
}
|
||||
|
||||
/// \brief Add an attribute to the attribute set at the given index. Because
|
||||
/// attribute sets are immutable, this returns a new set.
|
||||
AttributeList addAttribute(LLVMContext &C, unsigned Index,
|
||||
Attribute::AttrKind Kind) const;
|
||||
/// Add an argument attribute to the list. Returns a new list because
|
||||
/// attribute lists are immutable.
|
||||
AttributeList addParamAttribute(LLVMContext &C, unsigned ArgNo,
|
||||
StringRef Kind,
|
||||
StringRef Value = StringRef()) const {
|
||||
return addAttribute(C, ArgNo + FirstArgIndex, Kind, Value);
|
||||
}
|
||||
|
||||
/// \brief Add an attribute to the attribute set at the given index. Because
|
||||
/// attribute sets are immutable, this returns a new set.
|
||||
AttributeList addAttribute(LLVMContext &C, unsigned Index, StringRef Kind,
|
||||
StringRef Value = StringRef()) const;
|
||||
/// Add an attribute to the attribute list at the given arg indices. Returns a
|
||||
/// new list because attribute lists are immutable.
|
||||
AttributeList addParamAttribute(LLVMContext &C, ArrayRef<unsigned> ArgNos,
|
||||
Attribute A) const;
|
||||
|
||||
/// Add an attribute to the attribute set at the given indices. Because
|
||||
/// attribute sets are immutable, this returns a new set.
|
||||
AttributeList addAttribute(LLVMContext &C, ArrayRef<unsigned> Indices,
|
||||
Attribute A) const;
|
||||
|
||||
/// \brief Add attributes to the attribute set at the given index. Because
|
||||
/// attribute sets are immutable, this returns a new set.
|
||||
AttributeList addAttributes(LLVMContext &C, unsigned Index,
|
||||
const AttrBuilder &B) const;
|
||||
/// Add an argument attribute to the list. Returns a new list because
|
||||
/// attribute lists are immutable.
|
||||
AttributeList addParamAttributes(LLVMContext &C, unsigned ArgNo,
|
||||
const AttrBuilder &B) const {
|
||||
return addAttributes(C, ArgNo + FirstArgIndex, B);
|
||||
}
|
||||
|
||||
/// \brief Remove the specified attribute at the specified index from this
|
||||
/// attribute list. Because attribute lists are immutable, this returns the
|
||||
/// new list.
|
||||
/// attribute list. Returns a new list because attribute lists are immutable.
|
||||
AttributeList removeAttribute(LLVMContext &C, unsigned Index,
|
||||
Attribute::AttrKind Kind) const;
|
||||
|
||||
/// \brief Remove the specified attribute at the specified index from this
|
||||
/// attribute list. Because attribute lists are immutable, this returns the
|
||||
/// new list.
|
||||
/// attribute list. Returns a new list because attribute lists are immutable.
|
||||
AttributeList removeAttribute(LLVMContext &C, unsigned Index,
|
||||
StringRef Kind) const;
|
||||
|
||||
/// \brief Remove the specified attributes at the specified index from this
|
||||
/// attribute list. Because attribute lists are immutable, this returns the
|
||||
/// new list.
|
||||
/// attribute list. Returns a new list because attribute lists are immutable.
|
||||
AttributeList removeAttributes(LLVMContext &C, unsigned Index,
|
||||
const AttrBuilder &AttrsToRemove) const;
|
||||
|
||||
/// \brief Remove all attributes at the specified index from this
|
||||
/// attribute list. Because attribute lists are immutable, this returns the
|
||||
/// new list.
|
||||
/// attribute list. Returns a new list because attribute lists are immutable.
|
||||
AttributeList removeAttributes(LLVMContext &C, unsigned Index) const;
|
||||
|
||||
/// \brief Add the dereferenceable attribute to the attribute set at the given
|
||||
/// index. Because attribute sets are immutable, this returns a new set.
|
||||
/// \brief Remove the specified attribute at the specified arg index from this
|
||||
/// attribute list. Returns a new list because attribute lists are immutable.
|
||||
AttributeList removeParamAttribute(LLVMContext &C, unsigned ArgNo,
|
||||
Attribute::AttrKind Kind) const {
|
||||
return removeAttribute(C, ArgNo + FirstArgIndex, Kind);
|
||||
}
|
||||
|
||||
/// \brief Remove the specified attribute at the specified arg index from this
|
||||
/// attribute list. Returns a new list because attribute lists are immutable.
|
||||
AttributeList removeParamAttribute(LLVMContext &C, unsigned ArgNo,
|
||||
StringRef Kind) const {
|
||||
return removeAttribute(C, ArgNo + FirstArgIndex, Kind);
|
||||
}
|
||||
|
||||
/// \brief Remove the specified attribute at the specified arg index from this
|
||||
/// attribute list. Returns a new list because attribute lists are immutable.
|
||||
AttributeList removeParamAttributes(LLVMContext &C, unsigned ArgNo,
|
||||
const AttrBuilder &AttrsToRemove) const {
|
||||
return removeAttributes(C, ArgNo + FirstArgIndex, AttrsToRemove);
|
||||
}
|
||||
|
||||
/// \brief Remove all attributes at the specified arg index from this
|
||||
/// attribute list. Returns a new list because attribute lists are immutable.
|
||||
AttributeList removeParamAttributes(LLVMContext &C, unsigned ArgNo) const {
|
||||
return removeAttributes(C, ArgNo + FirstArgIndex);
|
||||
}
|
||||
|
||||
/// \Brief Add the dereferenceable attribute to the attribute set at the given
|
||||
/// index. Returns a new list because attribute lists are immutable.
|
||||
AttributeList addDereferenceableAttr(LLVMContext &C, unsigned Index,
|
||||
uint64_t Bytes) const;
|
||||
|
||||
/// \Brief Add the dereferenceable attribute to the attribute set at the given
|
||||
/// arg index. Returns a new list because attribute lists are immutable.
|
||||
AttributeList addDereferenceableParamAttr(LLVMContext &C, unsigned ArgNo,
|
||||
uint64_t Bytes) const {
|
||||
return addDereferenceableAttr(C, ArgNo + FirstArgIndex, Bytes);
|
||||
}
|
||||
|
||||
/// \brief Add the dereferenceable_or_null attribute to the attribute set at
|
||||
/// the given index. Because attribute sets are immutable, this returns a new
|
||||
/// set.
|
||||
/// the given index. Returns a new list because attribute lists are immutable.
|
||||
AttributeList addDereferenceableOrNullAttr(LLVMContext &C, unsigned Index,
|
||||
uint64_t Bytes) const;
|
||||
|
||||
/// \brief Add the dereferenceable_or_null attribute to the attribute set at
|
||||
/// the given arg index. Returns a new list because attribute lists are
|
||||
/// immutable.
|
||||
AttributeList addDereferenceableOrNullParamAttr(LLVMContext &C,
|
||||
unsigned ArgNo,
|
||||
uint64_t Bytes) const {
|
||||
return addDereferenceableOrNullAttr(C, ArgNo + FirstArgIndex, Bytes);
|
||||
}
|
||||
|
||||
/// Add the allocsize attribute to the attribute set at the given index.
|
||||
/// Because attribute sets are immutable, this returns a new set.
|
||||
/// Returns a new list because attribute lists are immutable.
|
||||
AttributeList addAllocSizeAttr(LLVMContext &C, unsigned Index,
|
||||
unsigned ElemSizeArg,
|
||||
const Optional<unsigned> &NumElemsArg);
|
||||
|
||||
/// Add the allocsize attribute to the attribute set at the given arg index.
|
||||
/// Returns a new list because attribute lists are immutable.
|
||||
AttributeList addAllocSizeParamAttr(LLVMContext &C, unsigned ArgNo,
|
||||
unsigned ElemSizeArg,
|
||||
const Optional<unsigned> &NumElemsArg) {
|
||||
return addAllocSizeAttr(C, ArgNo + FirstArgIndex, ElemSizeArg, NumElemsArg);
|
||||
}
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// AttributeList Accessors
|
||||
//===--------------------------------------------------------------------===//
|
||||
@ -473,6 +535,21 @@ public:
|
||||
/// \brief Return true if attribute exists at the given index.
|
||||
bool hasAttributes(unsigned Index) const;
|
||||
|
||||
/// \brief Return true if the attribute exists for the given argument
|
||||
bool hasParamAttr(unsigned ArgNo, Attribute::AttrKind Kind) const {
|
||||
return hasAttribute(ArgNo + FirstArgIndex, Kind);
|
||||
}
|
||||
|
||||
/// \brief Return true if the attribute exists for the given argument
|
||||
bool hasParamAttr(unsigned ArgNo, StringRef Kind) const {
|
||||
return hasAttribute(ArgNo + FirstArgIndex, Kind);
|
||||
}
|
||||
|
||||
/// \brief Return true if attributes exists for the given argument
|
||||
bool hasParamAttrs(unsigned ArgNo) const {
|
||||
return hasAttributes(ArgNo + FirstArgIndex);
|
||||
}
|
||||
|
||||
/// \brief Equivalent to hasAttribute(AttributeList::FunctionIndex, Kind) but
|
||||
/// may be faster.
|
||||
bool hasFnAttribute(Attribute::AttrKind Kind) const;
|
||||
@ -496,6 +573,16 @@ public:
|
||||
/// \brief Return the attribute object that exists at the given index.
|
||||
Attribute getAttribute(unsigned Index, StringRef Kind) const;
|
||||
|
||||
/// \brief Return the attribute object that exists at the arg index.
|
||||
Attribute getParamAttr(unsigned ArgNo, Attribute::AttrKind Kind) const {
|
||||
return getAttribute(ArgNo + FirstArgIndex, Kind);
|
||||
}
|
||||
|
||||
/// \brief Return the attribute object that exists at the given index.
|
||||
Attribute getParamAttr(unsigned ArgNo, StringRef Kind) const {
|
||||
return getAttribute(ArgNo + FirstArgIndex, Kind);
|
||||
}
|
||||
|
||||
/// \brief Return the alignment of the return value.
|
||||
unsigned getRetAlignment() const;
|
||||
|
||||
@ -508,10 +595,22 @@ public:
|
||||
/// \brief Get the number of dereferenceable bytes (or zero if unknown).
|
||||
uint64_t getDereferenceableBytes(unsigned Index) const;
|
||||
|
||||
/// \brief Get the number of dereferenceable bytes (or zero if unknown) of an
|
||||
/// arg.
|
||||
uint64_t getParamDereferenceableBytes(unsigned ArgNo) const {
|
||||
return getDereferenceableBytes(ArgNo + FirstArgIndex);
|
||||
}
|
||||
|
||||
/// \brief Get the number of dereferenceable_or_null bytes (or zero if
|
||||
/// unknown).
|
||||
uint64_t getDereferenceableOrNullBytes(unsigned Index) const;
|
||||
|
||||
/// \brief Get the number of dereferenceable_or_null bytes (or zero if
|
||||
/// unknown) of an arg.
|
||||
uint64_t getParamDereferenceableOrNullBytes(unsigned ArgNo) const {
|
||||
return getDereferenceableOrNullBytes(ArgNo + FirstArgIndex);
|
||||
}
|
||||
|
||||
/// Get the allocsize argument numbers (or pair(0, 0) if unknown).
|
||||
std::pair<unsigned, Optional<unsigned>>
|
||||
getAllocSizeArgs(unsigned Index) const;
|
||||
|
@ -214,10 +214,6 @@ public:
|
||||
addAttribute(AttributeList::FunctionIndex, Attr);
|
||||
}
|
||||
|
||||
void addParamAttr(unsigned ArgNo, Attribute::AttrKind Kind) {
|
||||
addAttribute(ArgNo + AttributeList::FirstArgIndex, Kind);
|
||||
}
|
||||
|
||||
/// @brief Remove function attributes from this function.
|
||||
void removeFnAttr(Attribute::AttrKind Kind) {
|
||||
removeAttribute(AttributeList::FunctionIndex, Kind);
|
||||
@ -229,10 +225,6 @@ public:
|
||||
getContext(), AttributeList::FunctionIndex, Kind));
|
||||
}
|
||||
|
||||
void removeParamAttr(unsigned ArgNo, Attribute::AttrKind Kind) {
|
||||
removeAttribute(ArgNo + AttributeList::FirstArgIndex, Kind);
|
||||
}
|
||||
|
||||
/// \brief Set the entry count for this function.
|
||||
///
|
||||
/// Entry count is the number of times this function was executed based on
|
||||
@ -299,6 +291,15 @@ public:
|
||||
/// @brief adds the attributes to the list of attributes.
|
||||
void addAttributes(unsigned i, const AttrBuilder &Attrs);
|
||||
|
||||
/// @brief adds the attribute to the list of attributes for the given arg.
|
||||
void addParamAttr(unsigned ArgNo, Attribute::AttrKind Kind);
|
||||
|
||||
/// @brief adds the attribute to the list of attributes for the given arg.
|
||||
void addParamAttr(unsigned ArgNo, Attribute Attr);
|
||||
|
||||
/// @brief adds the attributes to the list of attributes for the given arg.
|
||||
void addParamAttrs(unsigned ArgNo, const AttrBuilder &Attrs);
|
||||
|
||||
/// @brief removes the attribute from the list of attributes.
|
||||
void removeAttribute(unsigned i, Attribute::AttrKind Kind);
|
||||
|
||||
@ -308,6 +309,15 @@ public:
|
||||
/// @brief removes the attributes from the list of attributes.
|
||||
void removeAttributes(unsigned i, const AttrBuilder &Attrs);
|
||||
|
||||
/// @brief removes the attribute from the list of attributes.
|
||||
void removeParamAttr(unsigned ArgNo, Attribute::AttrKind Kind);
|
||||
|
||||
/// @brief removes the attribute from the list of attributes.
|
||||
void removeParamAttr(unsigned ArgNo, StringRef Kind);
|
||||
|
||||
/// @brief removes the attribute from the list of attributes.
|
||||
void removeParamAttrs(unsigned ArgNo, const AttrBuilder &Attrs);
|
||||
|
||||
/// @brief check if an attributes is in the list of attributes.
|
||||
bool hasAttribute(unsigned i, Attribute::AttrKind Kind) const {
|
||||
return getAttributes().hasAttribute(i, Kind);
|
||||
@ -329,10 +339,18 @@ public:
|
||||
/// @brief adds the dereferenceable attribute to the list of attributes.
|
||||
void addDereferenceableAttr(unsigned i, uint64_t Bytes);
|
||||
|
||||
/// @brief adds the dereferenceable attribute to the list of attributes for
|
||||
/// the given arg.
|
||||
void addDereferenceableParamAttr(unsigned ArgNo, uint64_t Bytes);
|
||||
|
||||
/// @brief adds the dereferenceable_or_null attribute to the list of
|
||||
/// attributes.
|
||||
void addDereferenceableOrNullAttr(unsigned i, uint64_t Bytes);
|
||||
|
||||
/// @brief adds the dereferenceable_or_null attribute to the list of
|
||||
/// attributes for the given arg.
|
||||
void addDereferenceableOrNullParamAttr(unsigned ArgNo, uint64_t Bytes);
|
||||
|
||||
/// @brief Extract the alignment for a call or parameter (0=unknown).
|
||||
unsigned getParamAlignment(unsigned ArgNo) const {
|
||||
return AttributeSets.getParamAlignment(ArgNo);
|
||||
@ -345,6 +363,12 @@ public:
|
||||
return AttributeSets.getDereferenceableBytes(i);
|
||||
}
|
||||
|
||||
/// @brief Extract the number of dereferenceable bytes for a parameter.
|
||||
/// @param ArgNo Index of an argument, with 0 being the first function arg.
|
||||
uint64_t getParamDereferenceableBytes(unsigned ArgNo) const {
|
||||
return AttributeSets.getParamDereferenceableBytes(ArgNo);
|
||||
}
|
||||
|
||||
/// @brief Extract the number of dereferenceable_or_null bytes for a call or
|
||||
/// parameter (0=unknown).
|
||||
/// @param i AttributeList index, referring to a return value or argument.
|
||||
@ -352,6 +376,13 @@ public:
|
||||
return AttributeSets.getDereferenceableOrNullBytes(i);
|
||||
}
|
||||
|
||||
/// @brief Extract the number of dereferenceable_or_null bytes for a
|
||||
/// parameter.
|
||||
/// @param ArgNo AttributeList ArgNo, referring to an argument.
|
||||
uint64_t getParamDereferenceableOrNullBytes(unsigned ArgNo) const {
|
||||
return AttributeSets.getParamDereferenceableOrNullBytes(ArgNo);
|
||||
}
|
||||
|
||||
/// @brief Determine if the function does not access memory.
|
||||
bool doesNotAccessMemory() const {
|
||||
return hasFnAttribute(Attribute::ReadNone);
|
||||
|
@ -1660,6 +1660,9 @@ public:
|
||||
/// Adds the attribute to the indicated argument
|
||||
void addParamAttr(unsigned ArgNo, Attribute::AttrKind Kind);
|
||||
|
||||
/// Adds the attribute to the indicated argument
|
||||
void addParamAttr(unsigned ArgNo, Attribute Attr);
|
||||
|
||||
/// removes the attribute from the list of attributes.
|
||||
void removeAttribute(unsigned i, Attribute::AttrKind Kind);
|
||||
|
||||
@ -1669,6 +1672,9 @@ public:
|
||||
/// Removes the attribute from the given argument
|
||||
void removeParamAttr(unsigned ArgNo, Attribute::AttrKind Kind);
|
||||
|
||||
/// Removes the attribute from the given argument
|
||||
void removeParamAttr(unsigned ArgNo, StringRef Kind);
|
||||
|
||||
/// adds the dereferenceable attribute to the list of attributes.
|
||||
void addDereferenceableAttr(unsigned i, uint64_t Bytes);
|
||||
|
||||
@ -1704,6 +1710,18 @@ public:
|
||||
return getAttributes().getAttribute(i, Kind);
|
||||
}
|
||||
|
||||
/// Get the attribute of a given kind from a given arg
|
||||
Attribute getParamAttr(unsigned ArgNo, Attribute::AttrKind Kind) const {
|
||||
assert(ArgNo < getNumArgOperands() && "Out of bounds");
|
||||
return getAttributes().getParamAttr(ArgNo, Kind);
|
||||
}
|
||||
|
||||
/// Get the attribute of a given kind from a given arg
|
||||
Attribute getParamAttr(unsigned ArgNo, StringRef Kind) const {
|
||||
assert(ArgNo < getNumArgOperands() && "Out of bounds");
|
||||
return getAttributes().getParamAttr(ArgNo, Kind);
|
||||
}
|
||||
|
||||
/// Return true if the data operand at index \p i has the attribute \p
|
||||
/// A.
|
||||
///
|
||||
|
@ -188,6 +188,7 @@ void initializeLintPass(PassRegistry&);
|
||||
void initializeLiveDebugValuesPass(PassRegistry&);
|
||||
void initializeLiveDebugVariablesPass(PassRegistry&);
|
||||
void initializeLiveIntervalsPass(PassRegistry&);
|
||||
void initializeLiveRangeShrinkPass(PassRegistry&);
|
||||
void initializeLiveRegMatrixPass(PassRegistry&);
|
||||
void initializeLiveStacksPass(PassRegistry&);
|
||||
void initializeLiveVariablesPass(PassRegistry&);
|
||||
|
@ -30,11 +30,18 @@
|
||||
#define LLVM_INCLUDE_LLVM_OBJECT_RESFILE_H
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/Object/Binary.h"
|
||||
#include "llvm/Object/Error.h"
|
||||
#include "llvm/Support/BinaryByteStream.h"
|
||||
#include "llvm/Support/BinaryStreamReader.h"
|
||||
#include "llvm/Support/COFF.h"
|
||||
#include "llvm/Support/ConvertUTF.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include "llvm/Support/ScopedPrinter.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace llvm {
|
||||
namespace object {
|
||||
@ -44,23 +51,44 @@ class WindowsResource;
|
||||
class ResourceEntryRef {
|
||||
public:
|
||||
Error moveNext(bool &End);
|
||||
bool checkTypeString() const { return IsStringType; }
|
||||
ArrayRef<UTF16> getTypeString() const { return Type; }
|
||||
uint16_t getTypeID() const { return TypeID; }
|
||||
bool checkNameString() const { return IsStringName; }
|
||||
ArrayRef<UTF16> getNameString() const { return Name; }
|
||||
uint16_t getNameID() const { return NameID; }
|
||||
uint16_t getLanguage() const { return Suffix->Language; }
|
||||
|
||||
private:
|
||||
friend class WindowsResource;
|
||||
|
||||
ResourceEntryRef(BinaryStreamRef Ref, const WindowsResource *Owner,
|
||||
Error &Err);
|
||||
|
||||
Error loadNext();
|
||||
|
||||
struct HeaderSuffix {
|
||||
support::ulittle32_t DataVersion;
|
||||
support::ulittle16_t MemoryFlags;
|
||||
support::ulittle16_t Language;
|
||||
support::ulittle32_t Version;
|
||||
support::ulittle32_t Characteristics;
|
||||
};
|
||||
|
||||
BinaryStreamReader Reader;
|
||||
BinaryStreamRef HeaderBytes;
|
||||
BinaryStreamRef DataBytes;
|
||||
bool IsStringType;
|
||||
ArrayRef<UTF16> Type;
|
||||
uint16_t TypeID;
|
||||
bool IsStringName;
|
||||
ArrayRef<UTF16> Name;
|
||||
uint16_t NameID;
|
||||
const HeaderSuffix *Suffix = nullptr;
|
||||
ArrayRef<uint8_t> Data;
|
||||
const WindowsResource *OwningRes = nullptr;
|
||||
};
|
||||
|
||||
class WindowsResource : public Binary {
|
||||
public:
|
||||
~WindowsResource() override;
|
||||
Expected<ResourceEntryRef> getHeadEntry();
|
||||
|
||||
static bool classof(const Binary *V) { return V->isWinRes(); }
|
||||
@ -76,6 +104,36 @@ private:
|
||||
BinaryByteStream BBS;
|
||||
};
|
||||
|
||||
class WindowsResourceParser {
|
||||
public:
|
||||
WindowsResourceParser();
|
||||
|
||||
Error parse(WindowsResource *WR);
|
||||
|
||||
void printTree() const;
|
||||
|
||||
private:
|
||||
class TreeNode {
|
||||
public:
|
||||
TreeNode() = default;
|
||||
explicit TreeNode(ArrayRef<UTF16> Ref);
|
||||
void addEntry(const ResourceEntryRef &Entry);
|
||||
void print(ScopedPrinter &Writer, StringRef Name) const;
|
||||
|
||||
private:
|
||||
TreeNode &addTypeNode(const ResourceEntryRef &Entry);
|
||||
TreeNode &addNameNode(const ResourceEntryRef &Entry);
|
||||
TreeNode &addLanguageNode(const ResourceEntryRef &Entry);
|
||||
TreeNode &addChild(uint32_t ID);
|
||||
TreeNode &addChild(ArrayRef<UTF16> NameRef);
|
||||
std::vector<UTF16> Name;
|
||||
std::map<uint32_t, std::unique_ptr<TreeNode>> IDChildren;
|
||||
std::map<std::string, std::unique_ptr<TreeNode>> StringChildren;
|
||||
};
|
||||
|
||||
TreeNode Root;
|
||||
};
|
||||
|
||||
} // namespace object
|
||||
} // namespace llvm
|
||||
|
||||
|
91
include/llvm/ObjectYAML/CodeViewYAMLDebugSections.h
Normal file
91
include/llvm/ObjectYAML/CodeViewYAMLDebugSections.h
Normal file
@ -0,0 +1,91 @@
|
||||
//===- CodeViewYAMLDebugSections.h - CodeView YAMLIO debug sections -------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines classes for handling the YAML representation of CodeView
|
||||
// Debug Info.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_OBJECTYAML_CODEVIEWYAMLDEBUGSECTIONS_H
|
||||
#define LLVM_OBJECTYAML_CODEVIEWYAMLDEBUGSECTIONS_H
|
||||
|
||||
#include "llvm/DebugInfo/CodeView/CodeView.h"
|
||||
#include "llvm/DebugInfo/CodeView/DebugSubsection.h"
|
||||
#include "llvm/ObjectYAML/YAML.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace CodeViewYAML {
|
||||
namespace detail {
|
||||
struct C13FragmentBase;
|
||||
}
|
||||
|
||||
struct SourceLineEntry {
|
||||
uint32_t Offset;
|
||||
uint32_t LineStart;
|
||||
uint32_t EndDelta;
|
||||
bool IsStatement;
|
||||
};
|
||||
|
||||
struct SourceColumnEntry {
|
||||
uint16_t StartColumn;
|
||||
uint16_t EndColumn;
|
||||
};
|
||||
|
||||
struct SourceLineBlock {
|
||||
StringRef FileName;
|
||||
std::vector<SourceLineEntry> Lines;
|
||||
std::vector<SourceColumnEntry> Columns;
|
||||
};
|
||||
|
||||
struct HexFormattedString {
|
||||
std::vector<uint8_t> Bytes;
|
||||
};
|
||||
|
||||
struct SourceFileChecksumEntry {
|
||||
StringRef FileName;
|
||||
codeview::FileChecksumKind Kind;
|
||||
HexFormattedString ChecksumBytes;
|
||||
};
|
||||
|
||||
struct SourceLineInfo {
|
||||
uint32_t RelocOffset;
|
||||
uint32_t RelocSegment;
|
||||
codeview::LineFlags Flags;
|
||||
uint32_t CodeSize;
|
||||
|
||||
std::vector<SourceLineBlock> Blocks;
|
||||
};
|
||||
|
||||
struct InlineeSite {
|
||||
uint32_t Inlinee;
|
||||
StringRef FileName;
|
||||
uint32_t SourceLineNum;
|
||||
std::vector<StringRef> ExtraFiles;
|
||||
};
|
||||
|
||||
struct InlineeInfo {
|
||||
bool HasExtraFiles;
|
||||
std::vector<InlineeSite> Sites;
|
||||
};
|
||||
|
||||
struct SourceFileInfo {
|
||||
std::vector<SourceFileChecksumEntry> FileChecksums;
|
||||
std::vector<SourceLineInfo> LineFragments;
|
||||
std::vector<InlineeInfo> Inlinees;
|
||||
};
|
||||
|
||||
struct C13DebugSection {
|
||||
std::vector<detail::C13FragmentBase> Fragments;
|
||||
};
|
||||
} // namespace CodeViewYAML
|
||||
} // namespace llvm
|
||||
|
||||
LLVM_YAML_DECLARE_MAPPING_TRAITS(CodeViewYAML::SourceFileInfo)
|
||||
|
||||
#endif
|
41
include/llvm/ObjectYAML/CodeViewYAMLSymbols.h
Normal file
41
include/llvm/ObjectYAML/CodeViewYAMLSymbols.h
Normal file
@ -0,0 +1,41 @@
|
||||
//===- CodeViewYAMLSymbols.h - CodeView YAMLIO Symbol implementation ------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines classes for handling the YAML representation of CodeView
|
||||
// Debug Info.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_OBJECTYAML_CODEVIEWYAMLSYMBOLS_H
|
||||
#define LLVM_OBJECTYAML_CODEVIEWYAMLSYMBOLS_H
|
||||
|
||||
#include "llvm/DebugInfo/CodeView/CodeView.h"
|
||||
#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
|
||||
#include "llvm/ObjectYAML/YAML.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace CodeViewYAML {
|
||||
namespace detail {
|
||||
struct SymbolRecordBase;
|
||||
}
|
||||
|
||||
struct SymbolRecord {
|
||||
std::shared_ptr<detail::SymbolRecordBase> Symbol;
|
||||
|
||||
codeview::CVSymbol toCodeViewSymbol(BumpPtrAllocator &Allocator) const;
|
||||
static Expected<SymbolRecord> fromCodeViewSymbol(codeview::CVSymbol Symbol);
|
||||
};
|
||||
|
||||
} // namespace CodeViewYAML
|
||||
} // namespace llvm
|
||||
|
||||
LLVM_YAML_DECLARE_MAPPING_TRAITS(CodeViewYAML::SymbolRecord)
|
||||
LLVM_YAML_IS_SEQUENCE_VECTOR(CodeViewYAML::SymbolRecord)
|
||||
|
||||
#endif
|
48
include/llvm/ObjectYAML/CodeViewYAMLTypes.h
Normal file
48
include/llvm/ObjectYAML/CodeViewYAMLTypes.h
Normal file
@ -0,0 +1,48 @@
|
||||
//===- CodeViewYAMLTypes.h - CodeView YAMLIO Type Record implementation ---===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines classes for handling the YAML representation of CodeView
|
||||
// Debug Info.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_OBJECTYAML_CODEVIEWYAMLTYPES_H
|
||||
#define LLVM_OBJECTYAML_CODEVIEWYAMLTYPES_H
|
||||
|
||||
#include "llvm/DebugInfo/CodeView/CodeView.h"
|
||||
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
|
||||
#include "llvm/ObjectYAML/YAML.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace CodeViewYAML {
|
||||
namespace detail {
|
||||
struct LeafRecordBase;
|
||||
struct MemberRecordBase;
|
||||
}
|
||||
|
||||
struct MemberRecord {
|
||||
std::shared_ptr<detail::MemberRecordBase> Member;
|
||||
};
|
||||
|
||||
struct LeafRecord {
|
||||
std::shared_ptr<detail::LeafRecordBase> Leaf;
|
||||
|
||||
codeview::CVType toCodeViewRecord(BumpPtrAllocator &Allocator) const;
|
||||
static Expected<LeafRecord> fromCodeViewRecord(codeview::CVType Type);
|
||||
};
|
||||
} // namespace CodeViewYAML
|
||||
} // namespace llvm
|
||||
|
||||
LLVM_YAML_DECLARE_MAPPING_TRAITS(CodeViewYAML::LeafRecord)
|
||||
LLVM_YAML_DECLARE_MAPPING_TRAITS(CodeViewYAML::MemberRecord)
|
||||
|
||||
LLVM_YAML_IS_SEQUENCE_VECTOR(CodeViewYAML::LeafRecord)
|
||||
LLVM_YAML_IS_SEQUENCE_VECTOR(CodeViewYAML::MemberRecord)
|
||||
|
||||
#endif
|
@ -192,6 +192,39 @@ public:
|
||||
buildFunctionSimplificationPipeline(OptimizationLevel Level,
|
||||
bool DebugLogging = false);
|
||||
|
||||
/// Construct the core LLVM module canonicalization and simplification
|
||||
/// pipeline.
|
||||
///
|
||||
/// This pipeline focuses on canonicalizing and simplifying the entire module
|
||||
/// of IR. Much like the function simplification pipeline above, it is
|
||||
/// suitable to run repeatedly over the IR and is not expected to destroy
|
||||
/// important information. It does, however, perform inlining and other
|
||||
/// heuristic based simplifications that are not strictly reversible.
|
||||
///
|
||||
/// Note that \p Level cannot be `O0` here. The pipelines produced are
|
||||
/// only intended for use when attempting to optimize code. If frontends
|
||||
/// require some transformations for semantic reasons, they should explicitly
|
||||
/// build them.
|
||||
ModulePassManager
|
||||
buildModuleSimplificationPipeline(OptimizationLevel Level,
|
||||
bool DebugLogging = false);
|
||||
|
||||
/// Construct the core LLVM module optimization pipeline.
|
||||
///
|
||||
/// This pipeline focuses on optimizing the execution speed of the IR. It
|
||||
/// uses cost modeling and thresholds to balance code growth against runtime
|
||||
/// improvements. It includes vectorization and other information destroying
|
||||
/// transformations. It also cannot generally be run repeatedly on a module
|
||||
/// without potentially seriously regressing either runtime performance of
|
||||
/// the code or serious code size growth.
|
||||
///
|
||||
/// Note that \p Level cannot be `O0` here. The pipelines produced are
|
||||
/// only intended for use when attempting to optimize code. If frontends
|
||||
/// require some transformations for semantic reasons, they should explicitly
|
||||
/// build them.
|
||||
ModulePassManager buildModuleOptimizationPipeline(OptimizationLevel Level,
|
||||
bool DebugLogging = false);
|
||||
|
||||
/// Build a per-module default optimization pipeline.
|
||||
///
|
||||
/// This provides a good default optimization pipeline for per-module
|
||||
@ -206,6 +239,36 @@ public:
|
||||
ModulePassManager buildPerModuleDefaultPipeline(OptimizationLevel Level,
|
||||
bool DebugLogging = false);
|
||||
|
||||
/// Build a pre-link, ThinLTO-targeting default optimization pipeline to
|
||||
/// a pass manager.
|
||||
///
|
||||
/// This adds the pre-link optimizations tuned to prepare a module for
|
||||
/// a ThinLTO run. It works to minimize the IR which needs to be analyzed
|
||||
/// without making irreversible decisions which could be made better during
|
||||
/// the LTO run.
|
||||
///
|
||||
/// Note that \p Level cannot be `O0` here. The pipelines produced are
|
||||
/// only intended for use when attempting to optimize code. If frontends
|
||||
/// require some transformations for semantic reasons, they should explicitly
|
||||
/// build them.
|
||||
ModulePassManager
|
||||
buildThinLTOPreLinkDefaultPipeline(OptimizationLevel Level,
|
||||
bool DebugLogging = false);
|
||||
|
||||
/// Build an ThinLTO default optimization pipeline to a pass manager.
|
||||
///
|
||||
/// This provides a good default optimization pipeline for link-time
|
||||
/// optimization and code generation. It is particularly tuned to fit well
|
||||
/// when IR coming into the LTO phase was first run through \c
|
||||
/// addPreLinkLTODefaultPipeline, and the two coordinate closely.
|
||||
///
|
||||
/// Note that \p Level cannot be `O0` here. The pipelines produced are
|
||||
/// only intended for use when attempting to optimize code. If frontends
|
||||
/// require some transformations for semantic reasons, they should explicitly
|
||||
/// build them.
|
||||
ModulePassManager buildThinLTODefaultPipeline(OptimizationLevel Level,
|
||||
bool DebugLogging = false);
|
||||
|
||||
/// Build a pre-link, LTO-targeting default optimization pipeline to a pass
|
||||
/// manager.
|
||||
///
|
||||
|
@ -206,7 +206,7 @@ ARM_CPU_NAME("cortex-a5", AK_ARMV7A, FK_NEON_VFPV4, false,
|
||||
ARM_CPU_NAME("cortex-a7", AK_ARMV7A, FK_NEON_VFPV4, false,
|
||||
(ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM |
|
||||
ARM::AEK_HWDIVTHUMB))
|
||||
ARM_CPU_NAME("cortex-a8", AK_ARMV7A, FK_NEON, true, ARM::AEK_SEC)
|
||||
ARM_CPU_NAME("cortex-a8", AK_ARMV7A, FK_NEON, false, ARM::AEK_SEC)
|
||||
ARM_CPU_NAME("cortex-a9", AK_ARMV7A, FK_NEON_FP16, false, (ARM::AEK_SEC | ARM::AEK_MP))
|
||||
ARM_CPU_NAME("cortex-a12", AK_ARMV7A, FK_NEON_VFPV4, false,
|
||||
(ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM |
|
||||
@ -236,7 +236,7 @@ ARM_CPU_NAME("cortex-m23", AK_ARMV8MBaseline, FK_NONE, false, ARM::AEK_NONE)
|
||||
ARM_CPU_NAME("cortex-m33", AK_ARMV8MMainline, FK_FPV5_SP_D16, false, ARM::AEK_DSP)
|
||||
ARM_CPU_NAME("cortex-a32", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC)
|
||||
ARM_CPU_NAME("cortex-a35", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC)
|
||||
ARM_CPU_NAME("cortex-a53", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, true, ARM::AEK_CRC)
|
||||
ARM_CPU_NAME("cortex-a53", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC)
|
||||
ARM_CPU_NAME("cortex-a57", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC)
|
||||
ARM_CPU_NAME("cortex-a72", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC)
|
||||
ARM_CPU_NAME("cortex-a73", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC)
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/Support/BinaryStreamArray.h"
|
||||
#include "llvm/Support/BinaryStreamRef.h"
|
||||
#include "llvm/Support/ConvertUTF.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include "llvm/Support/type_traits.h"
|
||||
@ -104,6 +105,13 @@ public:
|
||||
/// returns an appropriate error code.
|
||||
Error readCString(StringRef &Dest);
|
||||
|
||||
/// Similar to readCString, however read a null-terminated UTF16 string
|
||||
/// instead.
|
||||
///
|
||||
/// \returns a success error code if the data was successfully read, otherwise
|
||||
/// returns an appropriate error code.
|
||||
Error readWideString(ArrayRef<UTF16> &Dest);
|
||||
|
||||
/// Read a \p Length byte string into \p Dest. Whether a copy occurs depends
|
||||
/// on the implementation of the underlying stream. Updates the stream's
|
||||
/// offset to point after the newly read data.
|
||||
|
@ -1606,6 +1606,44 @@ template <typename T> struct StdMapStringCustomMappingTraitsImpl {
|
||||
} \
|
||||
}
|
||||
|
||||
#define LLVM_YAML_DECLARE_MAPPING_TRAITS(Type) \
|
||||
namespace llvm { \
|
||||
namespace yaml { \
|
||||
template <> struct MappingTraits<Type> { \
|
||||
static void mapping(IO &IO, Type &Obj); \
|
||||
}; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define LLVM_YAML_DECLARE_ENUM_TRAITS(Type) \
|
||||
namespace llvm { \
|
||||
namespace yaml { \
|
||||
template <> struct ScalarEnumerationTraits<Type> { \
|
||||
static void enumeration(IO &io, Type &Value); \
|
||||
}; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define LLVM_YAML_DECLARE_BITSET_TRAITS(Type) \
|
||||
namespace llvm { \
|
||||
namespace yaml { \
|
||||
template <> struct ScalarBitSetTraits<Type> { \
|
||||
static void bitset(IO &IO, Type &Options); \
|
||||
}; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define LLVM_YAML_DECLARE_SCALAR_TRAITS(Type, MustQuote) \
|
||||
namespace llvm { \
|
||||
namespace yaml { \
|
||||
template <> struct ScalarTraits<Type> { \
|
||||
static void output(const Type &Value, void *ctx, llvm::raw_ostream &Out); \
|
||||
static StringRef input(StringRef Scalar, void *ctxt, Type &Value); \
|
||||
static bool mustQuote(StringRef) { return MustQuote; } \
|
||||
}; \
|
||||
} \
|
||||
}
|
||||
|
||||
/// Utility for declaring that a std::vector of a particular type
|
||||
/// should be considered a YAML document list.
|
||||
#define LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(_type) \
|
||||
|
@ -1237,7 +1237,6 @@ class RecordVal {
|
||||
|
||||
public:
|
||||
RecordVal(Init *N, RecTy *T, bool P);
|
||||
RecordVal(StringRef N, RecTy *T, bool P);
|
||||
|
||||
StringRef getName() const;
|
||||
Init *getNameInit() const { return Name; }
|
||||
@ -1340,7 +1339,6 @@ public:
|
||||
}
|
||||
|
||||
void setName(Init *Name); // Also updates RecordKeeper.
|
||||
void setName(StringRef Name); // Also updates RecordKeeper.
|
||||
|
||||
ArrayRef<SMLoc> getLoc() const { return Locs; }
|
||||
|
||||
@ -1378,13 +1376,11 @@ public:
|
||||
}
|
||||
|
||||
RecordVal *getValue(const Init *Name) {
|
||||
for (RecordVal &Val : Values)
|
||||
if (Val.Name == Name) return &Val;
|
||||
return nullptr;
|
||||
return const_cast<RecordVal *>(static_cast<const Record *>(this)->getValue(Name));
|
||||
}
|
||||
|
||||
RecordVal *getValue(StringRef Name) {
|
||||
return getValue(StringInit::get(Name));
|
||||
return const_cast<RecordVal *>(static_cast<const Record *>(this)->getValue(Name));
|
||||
}
|
||||
|
||||
void addTemplateArg(Init *Name) {
|
||||
@ -1492,7 +1488,7 @@ public:
|
||||
/// its value as a string, throwing an exception if the field does not exist
|
||||
/// or if the value is not a string.
|
||||
///
|
||||
std::string getValueAsString(StringRef FieldName) const;
|
||||
StringRef getValueAsString(StringRef FieldName) const;
|
||||
|
||||
/// This method looks up the specified field and returns
|
||||
/// its value as a BitsInit, throwing an exception if the field does not exist
|
||||
@ -1522,7 +1518,7 @@ public:
|
||||
/// returns its value as a vector of strings, throwing an exception if the
|
||||
/// field does not exist or if the value is not the right type.
|
||||
///
|
||||
std::vector<std::string> getValueAsListOfStrings(StringRef FieldName) const;
|
||||
std::vector<StringRef> getValueAsListOfStrings(StringRef FieldName) const;
|
||||
|
||||
/// This method looks up the specified field and returns its
|
||||
/// value as a Record, throwing an exception if the field does not exist or if
|
||||
|
@ -1143,6 +1143,16 @@ public:
|
||||
return OptSize ? MaxStoresPerMemcpyOptSize : MaxStoresPerMemcpy;
|
||||
}
|
||||
|
||||
/// Get maximum # of load operations permitted for memcmp
|
||||
///
|
||||
/// This function returns the maximum number of load operations permitted
|
||||
/// to replace a call to memcmp. The value is set by the target at the
|
||||
/// performance threshold for such a replacement. If OptSize is true,
|
||||
/// return the limit for functions that have OptSize attribute.
|
||||
unsigned getMaxExpandSizeMemcmp(bool OptSize) const {
|
||||
return OptSize ? MaxLoadsPerMemcmpOptSize : MaxLoadsPerMemcmp;
|
||||
}
|
||||
|
||||
/// \brief Get maximum # of store operations permitted for llvm.memmove
|
||||
///
|
||||
/// This function returns the maximum number of store operations permitted
|
||||
@ -2330,6 +2340,8 @@ protected:
|
||||
/// Maximum number of store operations that may be substituted for a call to
|
||||
/// memcpy, used for functions with OptSize attribute.
|
||||
unsigned MaxStoresPerMemcpyOptSize;
|
||||
unsigned MaxLoadsPerMemcmp;
|
||||
unsigned MaxLoadsPerMemcmpOptSize;
|
||||
|
||||
/// \brief Specify maximum bytes of store instructions per memmove call.
|
||||
///
|
||||
|
@ -299,6 +299,12 @@ public:
|
||||
bool addPassesToEmitMC(PassManagerBase &PM, MCContext *&Ctx,
|
||||
raw_pwrite_stream &OS,
|
||||
bool DisableVerify = true) override;
|
||||
|
||||
/// Returns true if the target is expected to pass all machine verifier
|
||||
/// checks. This is a stopgap measure to fix targets one by one. We will
|
||||
/// remove this at some point and always enable the verifier when
|
||||
/// EXPENSIVE_CHECKS is enabled.
|
||||
virtual bool isMachineVerifierClean() const { return true; }
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
41
include/llvm/Transforms/IPO/ThinLTOBitcodeWriter.h
Normal file
41
include/llvm/Transforms/IPO/ThinLTOBitcodeWriter.h
Normal file
@ -0,0 +1,41 @@
|
||||
//===- ThinLTOBitcodeWriter.h - Bitcode writing pass for ThinLTO ----------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This pass prepares a module containing type metadata for ThinLTO by splitting
|
||||
// it into regular and thin LTO parts if possible, and writing both parts to
|
||||
// a multi-module bitcode file. Modules that do not contain type metadata are
|
||||
// written unmodified as a single module.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_TRANSFORMS_IPO_THINLTOBITCODEWRITER_H
|
||||
#define LLVM_TRANSFORMS_IPO_THINLTOBITCODEWRITER_H
|
||||
|
||||
#include <llvm/IR/PassManager.h>
|
||||
#include <llvm/Support/raw_ostream.h>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class ThinLTOBitcodeWriterPass
|
||||
: public PassInfoMixin<ThinLTOBitcodeWriterPass> {
|
||||
raw_ostream &OS;
|
||||
raw_ostream *ThinLinkOS;
|
||||
|
||||
public:
|
||||
// Writes bitcode to OS. Also write thin link file to ThinLinkOS, if
|
||||
// it's not nullptr.
|
||||
ThinLTOBitcodeWriterPass(raw_ostream &OS, raw_ostream *ThinLinkOS)
|
||||
: OS(OS), ThinLinkOS(ThinLinkOS) {}
|
||||
|
||||
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM);
|
||||
};
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
@ -68,24 +68,6 @@ public:
|
||||
class ValueTable {
|
||||
DenseMap<Value *, uint32_t> valueNumbering;
|
||||
DenseMap<Expression, uint32_t> expressionNumbering;
|
||||
|
||||
// Expressions is the vector of Expression. ExprIdx is the mapping from
|
||||
// value number to the index of Expression in Expressions. We use it
|
||||
// instead of a DenseMap because filling such mapping is faster than
|
||||
// filling a DenseMap and the compile time is a little better.
|
||||
uint32_t nextExprNumber;
|
||||
std::vector<Expression> Expressions;
|
||||
std::vector<uint32_t> ExprIdx;
|
||||
// Value number to PHINode mapping. Used for phi-translate in scalarpre.
|
||||
DenseMap<uint32_t, PHINode *> NumberingPhi;
|
||||
// Cache for phi-translate in scalarpre.
|
||||
typedef DenseMap<std::pair<uint32_t, const BasicBlock *>, uint32_t>
|
||||
PhiTranslateMap;
|
||||
PhiTranslateMap PhiTranslateTable;
|
||||
// Map the block to reversed postorder traversal number. It is used to
|
||||
// find back edge easily.
|
||||
DenseMap<const BasicBlock *, uint32_t> BlockRPONumber;
|
||||
|
||||
AliasAnalysis *AA;
|
||||
MemoryDependenceResults *MD;
|
||||
DominatorTree *DT;
|
||||
@ -97,10 +79,6 @@ public:
|
||||
Value *LHS, Value *RHS);
|
||||
Expression createExtractvalueExpr(ExtractValueInst *EI);
|
||||
uint32_t lookupOrAddCall(CallInst *C);
|
||||
uint32_t phiTranslateImpl(const BasicBlock *BB, const BasicBlock *PhiBlock,
|
||||
uint32_t Num, GVN &Gvn);
|
||||
std::pair<uint32_t, bool> assignExpNewValueNum(Expression &exp);
|
||||
bool areAllValsInBB(uint32_t num, const BasicBlock *BB, GVN &Gvn);
|
||||
|
||||
public:
|
||||
ValueTable();
|
||||
@ -109,12 +87,9 @@ public:
|
||||
~ValueTable();
|
||||
|
||||
uint32_t lookupOrAdd(Value *V);
|
||||
uint32_t lookup(Value *V, bool Verify = true) const;
|
||||
uint32_t lookup(Value *V) const;
|
||||
uint32_t lookupOrAddCmp(unsigned Opcode, CmpInst::Predicate Pred,
|
||||
Value *LHS, Value *RHS);
|
||||
uint32_t phiTranslate(const BasicBlock *BB, const BasicBlock *PhiBlock,
|
||||
uint32_t Num, GVN &Gvn);
|
||||
void assignBlockRPONumber(Function &F);
|
||||
bool exists(Value *V) const;
|
||||
void add(Value *V, uint32_t num);
|
||||
void clear();
|
||||
|
@ -25,6 +25,7 @@ template <typename T> class ArrayRef;
|
||||
class BranchProbabilityInfo;
|
||||
class DominatorTree;
|
||||
class Function;
|
||||
class Instruction;
|
||||
class Loop;
|
||||
class Module;
|
||||
class RegionNode;
|
||||
@ -103,7 +104,17 @@ template <typename T> class ArrayRef;
|
||||
/// a code sequence, that sequence is modified, including changing these
|
||||
/// sets, before extraction occurs. These modifications won't have any
|
||||
/// significant impact on the cost however.
|
||||
void findInputsOutputs(ValueSet &Inputs, ValueSet &Outputs) const;
|
||||
void findInputsOutputs(ValueSet &Inputs, ValueSet &Outputs,
|
||||
const ValueSet &Allocas) const;
|
||||
/// Find the set of allocas whose life ranges are contained within the
|
||||
/// outlined region.
|
||||
///
|
||||
/// Allocas which have life_time markers contained in the outlined region
|
||||
/// should be pushed to the outlined function. The address bitcasts that
|
||||
/// are used by the lifetime markers are also candidates for shrink-
|
||||
/// wrapping. The instructions that need to be sinked are collected in
|
||||
/// 'Allocas'.
|
||||
void findAllocas(ValueSet &Allocas) const;
|
||||
|
||||
private:
|
||||
void severSplitPHINodes(BasicBlock *&Header);
|
||||
|
@ -95,8 +95,8 @@ module LLVM_DebugInfo_CodeView {
|
||||
module * { export * }
|
||||
|
||||
// These are intended for (repeated) textual inclusion.
|
||||
textual header "DebugInfo/CodeView/TypeRecords.def"
|
||||
textual header "DebugInfo/CodeView/CVSymbolTypes.def"
|
||||
textual header "DebugInfo/CodeView/CodeViewTypes.def"
|
||||
textual header "DebugInfo/CodeView/CodeViewSymbols.def"
|
||||
}
|
||||
|
||||
module LLVM_ExecutionEngine {
|
||||
|
@ -210,6 +210,11 @@ template <typename CFLAA> class CFLGraphBuilder {
|
||||
|
||||
void addDerefEdge(Value *From, Value *To, bool IsRead) {
|
||||
assert(From != nullptr && To != nullptr);
|
||||
// FIXME: This is subtly broken, due to how we model some instructions
|
||||
// (e.g. extractvalue, extractelement) as loads. Since those take
|
||||
// non-pointer operands, we'll entirely skip adding edges for those.
|
||||
//
|
||||
// addAssignEdge seems to have a similar issue with insertvalue, etc.
|
||||
if (!From->getType()->isPointerTy() || !To->getType()->isPointerTy())
|
||||
return;
|
||||
addNode(From);
|
||||
@ -540,6 +545,7 @@ template <typename CFLAA> class CFLGraphBuilder {
|
||||
case Instruction::ExtractValue: {
|
||||
auto *Ptr = CE->getOperand(0);
|
||||
addLoadEdge(Ptr, CE);
|
||||
break;
|
||||
}
|
||||
case Instruction::ShuffleVector: {
|
||||
auto *From1 = CE->getOperand(0);
|
||||
|
@ -1739,6 +1739,7 @@ Constant *ConstantFoldScalarCall(StringRef Name, unsigned IntrinsicID, Type *Ty,
|
||||
if ((Name == "round" && TLI->has(LibFunc_round)) ||
|
||||
(Name == "roundf" && TLI->has(LibFunc_roundf)))
|
||||
return ConstantFoldFP(round, V, Ty);
|
||||
break;
|
||||
case 's':
|
||||
if ((Name == "sin" && TLI->has(LibFunc_sin)) ||
|
||||
(Name == "sinf" && TLI->has(LibFunc_sinf)))
|
||||
@ -1807,6 +1808,7 @@ Constant *ConstantFoldScalarCall(StringRef Name, unsigned IntrinsicID, Type *Ty,
|
||||
dyn_cast_or_null<ConstantFP>(Op->getAggregateElement(0U)))
|
||||
return ConstantFoldSSEConvertToInt(FPOp->getValueAPF(),
|
||||
/*roundTowardZero=*/false, Ty);
|
||||
LLVM_FALLTHROUGH;
|
||||
case Intrinsic::x86_sse_cvttss2si:
|
||||
case Intrinsic::x86_sse_cvttss2si64:
|
||||
case Intrinsic::x86_sse2_cvttsd2si:
|
||||
|
@ -27,8 +27,10 @@ EHPersonality llvm::classifyEHPersonality(const Value *Pers) {
|
||||
return StringSwitch<EHPersonality>(F->getName())
|
||||
.Case("__gnat_eh_personality", EHPersonality::GNU_Ada)
|
||||
.Case("__gxx_personality_v0", EHPersonality::GNU_CXX)
|
||||
.Case("__gxx_personality_seh0",EHPersonality::GNU_CXX)
|
||||
.Case("__gxx_personality_sj0", EHPersonality::GNU_CXX_SjLj)
|
||||
.Case("__gcc_personality_v0", EHPersonality::GNU_C)
|
||||
.Case("__gcc_personality_seh0",EHPersonality::GNU_C)
|
||||
.Case("__gcc_personality_sj0", EHPersonality::GNU_C_SjLj)
|
||||
.Case("__objc_personality_v0", EHPersonality::GNU_ObjC)
|
||||
.Case("_except_handler3", EHPersonality::MSVC_X86SEH)
|
||||
|
@ -103,13 +103,8 @@ static bool ValueDominatesPHI(Value *V, PHINode *P, const DominatorTree *DT) {
|
||||
return false;
|
||||
|
||||
// If we have a DominatorTree then do a precise test.
|
||||
if (DT) {
|
||||
if (!DT->isReachableFromEntry(P->getParent()))
|
||||
return true;
|
||||
if (!DT->isReachableFromEntry(I->getParent()))
|
||||
return false;
|
||||
if (DT)
|
||||
return DT->dominates(I, P);
|
||||
}
|
||||
|
||||
// Otherwise, if the instruction is in the entry block and is not an invoke,
|
||||
// then it obviously dominates all phi nodes.
|
||||
|
@ -691,6 +691,7 @@ MemDepResult MemoryDependenceResults::getSimplePointerDependencyFrom(
|
||||
// load query, we can safely ignore it (scan past it).
|
||||
if (isLoad)
|
||||
continue;
|
||||
LLVM_FALLTHROUGH;
|
||||
default:
|
||||
// Otherwise, there is a potential dependence. Return a clobber.
|
||||
return MemDepResult::getClobber(Inst);
|
||||
|
@ -8182,6 +8182,7 @@ bool ScalarEvolution::isKnownPredicateViaNoOverflow(ICmpInst::Predicate Pred,
|
||||
|
||||
case ICmpInst::ICMP_SGE:
|
||||
std::swap(LHS, RHS);
|
||||
LLVM_FALLTHROUGH;
|
||||
case ICmpInst::ICMP_SLE:
|
||||
// X s<= (X + C)<nsw> if C >= 0
|
||||
if (MatchBinaryAddToConst(RHS, LHS, C, SCEV::FlagNSW) && C.isNonNegative())
|
||||
@ -8195,6 +8196,7 @@ bool ScalarEvolution::isKnownPredicateViaNoOverflow(ICmpInst::Predicate Pred,
|
||||
|
||||
case ICmpInst::ICMP_SGT:
|
||||
std::swap(LHS, RHS);
|
||||
LLVM_FALLTHROUGH;
|
||||
case ICmpInst::ICMP_SLT:
|
||||
// X s< (X + C)<nsw> if C > 0
|
||||
if (MatchBinaryAddToConst(RHS, LHS, C, SCEV::FlagNSW) &&
|
||||
@ -8552,6 +8554,7 @@ bool ScalarEvolution::isImpliedCond(ICmpInst::Predicate Pred, const SCEV *LHS,
|
||||
if (isImpliedCondOperands(Pred, LHS, RHS, V,
|
||||
getConstant(SharperMin)))
|
||||
return true;
|
||||
LLVM_FALLTHROUGH;
|
||||
|
||||
case ICmpInst::ICMP_SGT:
|
||||
case ICmpInst::ICMP_UGT:
|
||||
@ -8566,6 +8569,7 @@ bool ScalarEvolution::isImpliedCond(ICmpInst::Predicate Pred, const SCEV *LHS,
|
||||
|
||||
if (isImpliedCondOperands(Pred, LHS, RHS, V, getConstant(Min)))
|
||||
return true;
|
||||
LLVM_FALLTHROUGH;
|
||||
|
||||
default:
|
||||
// No change
|
||||
|
@ -215,6 +215,10 @@ bool TargetTransformInfo::enableAggressiveInterleaving(bool LoopHasReductions) c
|
||||
return TTIImpl->enableAggressiveInterleaving(LoopHasReductions);
|
||||
}
|
||||
|
||||
bool TargetTransformInfo::expandMemCmp(Instruction *I, unsigned &MaxLoadSize) const {
|
||||
return TTIImpl->expandMemCmp(I, MaxLoadSize);
|
||||
}
|
||||
|
||||
bool TargetTransformInfo::enableInterleavedAccessVectorization() const {
|
||||
return TTIImpl->enableInterleavedAccessVectorization();
|
||||
}
|
||||
|
@ -172,6 +172,18 @@ bool llvm::haveNoCommonBitsSet(const Value *LHS, const Value *RHS,
|
||||
}
|
||||
|
||||
|
||||
bool llvm::isOnlyUsedInZeroEqualityComparison(const Instruction *CxtI) {
|
||||
for (const User *U : CxtI->users()) {
|
||||
if (const ICmpInst *IC = dyn_cast<ICmpInst>(U))
|
||||
if (IC->isEquality())
|
||||
if (Constant *C = dyn_cast<Constant>(IC->getOperand(1)))
|
||||
if (C->isNullValue())
|
||||
continue;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool isKnownToBeAPowerOfTwo(const Value *V, bool OrZero, unsigned Depth,
|
||||
const Query &Q);
|
||||
|
||||
@ -2327,6 +2339,7 @@ bool llvm::ComputeMultiple(Value *V, unsigned Base, Value *&Multiple,
|
||||
case Instruction::SExt:
|
||||
if (!LookThroughSExt) return false;
|
||||
// otherwise fall through to ZExt
|
||||
LLVM_FALLTHROUGH;
|
||||
case Instruction::ZExt:
|
||||
return ComputeMultiple(I->getOperand(0), Base, Multiple,
|
||||
LookThroughSExt, Depth+1);
|
||||
|
@ -378,18 +378,10 @@ private:
|
||||
ModuleToSummariesForIndex->count(ModulePath);
|
||||
}
|
||||
|
||||
bool hasValueId(GlobalValue::GUID ValGUID) {
|
||||
const auto &VMI = GUIDToValueIdMap.find(ValGUID);
|
||||
return VMI != GUIDToValueIdMap.end();
|
||||
}
|
||||
void assignValueId(GlobalValue::GUID ValGUID) {
|
||||
unsigned &ValueId = GUIDToValueIdMap[ValGUID];
|
||||
if (ValueId == 0)
|
||||
ValueId = ++GlobalValueId;
|
||||
}
|
||||
unsigned getValueId(GlobalValue::GUID ValGUID) {
|
||||
Optional<unsigned> getValueId(GlobalValue::GUID ValGUID) {
|
||||
auto VMI = GUIDToValueIdMap.find(ValGUID);
|
||||
assert(VMI != GUIDToValueIdMap.end());
|
||||
if (VMI == GUIDToValueIdMap.end())
|
||||
return None;
|
||||
return VMI->second;
|
||||
}
|
||||
std::map<GlobalValue::GUID, unsigned> &valueIds() { return GUIDToValueIdMap; }
|
||||
@ -3413,12 +3405,6 @@ void IndexBitcodeWriter::writeCombinedGlobalValueSummary() {
|
||||
Stream.EnterSubblock(bitc::GLOBALVAL_SUMMARY_BLOCK_ID, 3);
|
||||
Stream.EmitRecord(bitc::FS_VERSION, ArrayRef<uint64_t>{INDEX_VERSION});
|
||||
|
||||
// Create value IDs for undefined references.
|
||||
forEachSummary([&](GVInfo I) {
|
||||
for (auto &RI : I.second->refs())
|
||||
assignValueId(RI.getGUID());
|
||||
});
|
||||
|
||||
for (const auto &GVI : valueIds()) {
|
||||
Stream.EmitRecord(bitc::FS_VALUE_GUID,
|
||||
ArrayRef<uint64_t>{GVI.second, GVI.first});
|
||||
@ -3492,9 +3478,9 @@ void IndexBitcodeWriter::writeCombinedGlobalValueSummary() {
|
||||
GlobalValueSummary *S = I.second;
|
||||
assert(S);
|
||||
|
||||
assert(hasValueId(I.first));
|
||||
unsigned ValueId = getValueId(I.first);
|
||||
SummaryToValueIdMap[S] = ValueId;
|
||||
auto ValueId = getValueId(I.first);
|
||||
assert(ValueId);
|
||||
SummaryToValueIdMap[S] = *ValueId;
|
||||
|
||||
if (auto *AS = dyn_cast<AliasSummary>(S)) {
|
||||
// Will process aliases as a post-pass because the reader wants all
|
||||
@ -3504,11 +3490,14 @@ void IndexBitcodeWriter::writeCombinedGlobalValueSummary() {
|
||||
}
|
||||
|
||||
if (auto *VS = dyn_cast<GlobalVarSummary>(S)) {
|
||||
NameVals.push_back(ValueId);
|
||||
NameVals.push_back(*ValueId);
|
||||
NameVals.push_back(Index.getModuleId(VS->modulePath()));
|
||||
NameVals.push_back(getEncodedGVSummaryFlags(VS->flags()));
|
||||
for (auto &RI : VS->refs()) {
|
||||
NameVals.push_back(getValueId(RI.getGUID()));
|
||||
auto RefValueId = getValueId(RI.getGUID());
|
||||
if (!RefValueId)
|
||||
continue;
|
||||
NameVals.push_back(*RefValueId);
|
||||
}
|
||||
|
||||
// Emit the finished record.
|
||||
@ -3522,15 +3511,22 @@ void IndexBitcodeWriter::writeCombinedGlobalValueSummary() {
|
||||
auto *FS = cast<FunctionSummary>(S);
|
||||
writeFunctionTypeMetadataRecords(Stream, FS);
|
||||
|
||||
NameVals.push_back(ValueId);
|
||||
NameVals.push_back(*ValueId);
|
||||
NameVals.push_back(Index.getModuleId(FS->modulePath()));
|
||||
NameVals.push_back(getEncodedGVSummaryFlags(FS->flags()));
|
||||
NameVals.push_back(FS->instCount());
|
||||
NameVals.push_back(FS->refs().size());
|
||||
// Fill in below
|
||||
NameVals.push_back(0);
|
||||
|
||||
unsigned Count = 0;
|
||||
for (auto &RI : FS->refs()) {
|
||||
NameVals.push_back(getValueId(RI.getGUID()));
|
||||
auto RefValueId = getValueId(RI.getGUID());
|
||||
if (!RefValueId)
|
||||
continue;
|
||||
NameVals.push_back(*RefValueId);
|
||||
Count++;
|
||||
}
|
||||
NameVals[4] = Count;
|
||||
|
||||
bool HasProfileData = false;
|
||||
for (auto &EI : FS->calls()) {
|
||||
@ -3543,15 +3539,19 @@ void IndexBitcodeWriter::writeCombinedGlobalValueSummary() {
|
||||
// If this GUID doesn't have a value id, it doesn't have a function
|
||||
// summary and we don't need to record any calls to it.
|
||||
GlobalValue::GUID GUID = EI.first.getGUID();
|
||||
if (!hasValueId(GUID)) {
|
||||
auto CallValueId = getValueId(GUID);
|
||||
if (!CallValueId) {
|
||||
// For SamplePGO, the indirect call targets for local functions will
|
||||
// have its original name annotated in profile. We try to find the
|
||||
// corresponding PGOFuncName as the GUID.
|
||||
GUID = Index.getGUIDFromOriginalID(GUID);
|
||||
if (GUID == 0 || !hasValueId(GUID))
|
||||
if (GUID == 0)
|
||||
continue;
|
||||
CallValueId = getValueId(GUID);
|
||||
if (!CallValueId)
|
||||
continue;
|
||||
}
|
||||
NameVals.push_back(getValueId(GUID));
|
||||
NameVals.push_back(*CallValueId);
|
||||
if (HasProfileData)
|
||||
NameVals.push_back(static_cast<uint8_t>(EI.second.Hotness));
|
||||
}
|
||||
|
@ -165,7 +165,7 @@ void AggressiveAntiDepBreaker::StartBlock(MachineBasicBlock *BB) {
|
||||
for (const MCPhysReg *I = MF.getRegInfo().getCalleeSavedRegs(); *I;
|
||||
++I) {
|
||||
unsigned Reg = *I;
|
||||
if (!IsReturnBlock && !(Pristine.test(Reg) || BB->isLiveIn(Reg)))
|
||||
if (!IsReturnBlock && !Pristine.test(Reg))
|
||||
continue;
|
||||
for (MCRegAliasIterator AI(Reg, TRI, true); AI.isValid(); ++AI) {
|
||||
unsigned AliasReg = *AI;
|
||||
|
@ -949,6 +949,19 @@ void AsmPrinter::emitFrameAlloc(const MachineInstr &MI) {
|
||||
MCConstantExpr::create(FrameOffset, OutContext));
|
||||
}
|
||||
|
||||
static bool needFuncLabelsForEHOrDebugInfo(const MachineFunction &MF,
|
||||
MachineModuleInfo *MMI) {
|
||||
if (!MF.getLandingPads().empty() || MF.hasEHFunclets() || MMI->hasDebugInfo())
|
||||
return true;
|
||||
|
||||
// We might emit an EH table that uses function begin and end labels even if
|
||||
// we don't have any landingpads.
|
||||
if (!MF.getFunction()->hasPersonalityFn())
|
||||
return false;
|
||||
return !isNoOpWithoutInvoke(
|
||||
classifyEHPersonality(MF.getFunction()->getPersonalityFn()));
|
||||
}
|
||||
|
||||
/// EmitFunctionBody - This method emits the body and trailer for a
|
||||
/// function.
|
||||
void AsmPrinter::EmitFunctionBody() {
|
||||
@ -1076,8 +1089,8 @@ void AsmPrinter::EmitFunctionBody() {
|
||||
// Emit target-specific gunk after the function body.
|
||||
EmitFunctionBodyEnd();
|
||||
|
||||
if (!MF->getLandingPads().empty() || MMI->hasDebugInfo() ||
|
||||
MF->hasEHFunclets() || MAI->hasDotTypeDotSizeDirective()) {
|
||||
if (needFuncLabelsForEHOrDebugInfo(*MF, MMI) ||
|
||||
MAI->hasDotTypeDotSizeDirective()) {
|
||||
// Create a symbol for the end of function.
|
||||
CurrentFnEnd = createTempSymbol("func_end");
|
||||
OutStreamer->EmitLabel(CurrentFnEnd);
|
||||
@ -1402,8 +1415,7 @@ void AsmPrinter::SetupMachineFunction(MachineFunction &MF) {
|
||||
CurrentFnBegin = nullptr;
|
||||
CurExceptionSym = nullptr;
|
||||
bool NeedsLocalForSize = MAI->needsLocalForSize();
|
||||
if (!MF.getLandingPads().empty() || MMI->hasDebugInfo() ||
|
||||
MF.hasEHFunclets() || NeedsLocalForSize) {
|
||||
if (needFuncLabelsForEHOrDebugInfo(MF, MMI) || NeedsLocalForSize) {
|
||||
CurrentFnBegin = createTempSymbol("func_begin");
|
||||
if (NeedsLocalForSize)
|
||||
CurrentFnSymForSize = CurrentFnBegin;
|
||||
|
@ -309,7 +309,7 @@ computeCallSiteTable(SmallVectorImpl<CallSiteEntry> &CallSites,
|
||||
// If some instruction between the previous try-range and the end of the
|
||||
// function may throw, create a call-site entry with no landing pad for the
|
||||
// region following the try-range.
|
||||
if (SawPotentiallyThrowing && !IsSJLJ && LastLabel != nullptr) {
|
||||
if (SawPotentiallyThrowing && !IsSJLJ) {
|
||||
CallSiteEntry Site = { LastLabel, nullptr, nullptr, 0 };
|
||||
CallSites.push_back(Site);
|
||||
}
|
||||
|
@ -49,6 +49,7 @@ add_llvm_library(LLVMCodeGen
|
||||
LivePhysRegs.cpp
|
||||
LiveRangeCalc.cpp
|
||||
LiveRangeEdit.cpp
|
||||
LiveRangeShrink.cpp
|
||||
LiveRegMatrix.cpp
|
||||
LiveRegUnits.cpp
|
||||
LiveStackAnalysis.cpp
|
||||
|
@ -43,6 +43,7 @@ void llvm::initializeCodeGen(PassRegistry &Registry) {
|
||||
initializeLiveDebugValuesPass(Registry);
|
||||
initializeLiveDebugVariablesPass(Registry);
|
||||
initializeLiveIntervalsPass(Registry);
|
||||
initializeLiveRangeShrinkPass(Registry);
|
||||
initializeLiveStacksPass(Registry);
|
||||
initializeLiveVariablesPass(Registry);
|
||||
initializeLocalStackSlotPassPass(Registry);
|
||||
|
@ -24,12 +24,13 @@
|
||||
#include "llvm/Analysis/CFG.h"
|
||||
#include "llvm/Analysis/InstructionSimplify.h"
|
||||
#include "llvm/Analysis/LoopInfo.h"
|
||||
#include "llvm/Analysis/MemoryBuiltins.h"
|
||||
#include "llvm/Analysis/ProfileSummaryInfo.h"
|
||||
#include "llvm/Analysis/TargetLibraryInfo.h"
|
||||
#include "llvm/Analysis/TargetTransformInfo.h"
|
||||
#include "llvm/Analysis/ValueTracking.h"
|
||||
#include "llvm/Analysis/MemoryBuiltins.h"
|
||||
#include "llvm/CodeGen/Analysis.h"
|
||||
#include "llvm/CodeGen/Passes.h"
|
||||
#include "llvm/IR/CallSite.h"
|
||||
#include "llvm/IR/Constants.h"
|
||||
#include "llvm/IR/DataLayout.h"
|
||||
@ -60,6 +61,7 @@
|
||||
#include "llvm/Transforms/Utils/Local.h"
|
||||
#include "llvm/Transforms/Utils/SimplifyLibCalls.h"
|
||||
#include "llvm/Transforms/Utils/ValueMapper.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::PatternMatch;
|
||||
|
||||
@ -84,6 +86,12 @@ STATISTIC(NumDbgValueMoved, "Number of debug value instructions moved");
|
||||
STATISTIC(NumSelectsExpanded, "Number of selects turned into branches");
|
||||
STATISTIC(NumStoreExtractExposed, "Number of store(extractelement) exposed");
|
||||
|
||||
STATISTIC(NumMemCmpCalls, "Number of memcmp calls");
|
||||
STATISTIC(NumMemCmpNotConstant, "Number of memcmp calls without constant size");
|
||||
STATISTIC(NumMemCmpGreaterThanMax,
|
||||
"Number of memcmp calls with size greater than max size");
|
||||
STATISTIC(NumMemCmpInlined, "Number of inlined memcmp calls");
|
||||
|
||||
static cl::opt<bool> DisableBranchOpts(
|
||||
"disable-cgp-branch-opts", cl::Hidden, cl::init(false),
|
||||
cl::desc("Disable branch optimizations in CodeGenPrepare"));
|
||||
@ -144,6 +152,11 @@ EnableTypePromotionMerge("cgp-type-promotion-merge", cl::Hidden,
|
||||
cl::desc("Enable merging of redundant sexts when one is dominating"
|
||||
" the other."), cl::init(true));
|
||||
|
||||
static cl::opt<unsigned> MemCmpNumLoadsPerBlock(
|
||||
"memcmp-num-loads-per-block", cl::Hidden, cl::init(1),
|
||||
cl::desc("The number of loads per basic block for inline expansion of "
|
||||
"memcmp that is only being compared against zero."));
|
||||
|
||||
namespace {
|
||||
typedef SmallPtrSet<Instruction *, 16> SetOfInstrs;
|
||||
typedef PointerIntPair<Type *, 1, bool> TypeIsSExt;
|
||||
@ -1629,6 +1642,593 @@ static bool despeculateCountZeros(IntrinsicInst *CountZeros,
|
||||
return true;
|
||||
}
|
||||
|
||||
// This class provides helper functions to expand a memcmp library call into an
|
||||
// inline expansion.
|
||||
class MemCmpExpansion {
|
||||
struct ResultBlock {
|
||||
BasicBlock *BB;
|
||||
PHINode *PhiSrc1;
|
||||
PHINode *PhiSrc2;
|
||||
ResultBlock();
|
||||
};
|
||||
|
||||
CallInst *CI;
|
||||
ResultBlock ResBlock;
|
||||
unsigned MaxLoadSize;
|
||||
unsigned NumBlocks;
|
||||
unsigned NumBlocksNonOneByte;
|
||||
unsigned NumLoadsPerBlock;
|
||||
std::vector<BasicBlock *> LoadCmpBlocks;
|
||||
BasicBlock *EndBlock;
|
||||
PHINode *PhiRes;
|
||||
bool IsUsedForZeroCmp;
|
||||
int calculateNumBlocks(unsigned Size);
|
||||
void createLoadCmpBlocks();
|
||||
void createResultBlock();
|
||||
void setupResultBlockPHINodes();
|
||||
void setupEndBlockPHINodes();
|
||||
void emitLoadCompareBlock(unsigned Index, int LoadSize, int GEPIndex,
|
||||
bool IsLittleEndian);
|
||||
void emitLoadCompareBlockMultipleLoads(unsigned Index, unsigned Size,
|
||||
unsigned &NumBytesProcessed);
|
||||
void emitLoadCompareByteBlock(unsigned Index, int GEPIndex);
|
||||
void emitMemCmpResultBlock(bool IsLittleEndian);
|
||||
Value *getMemCmpExpansionZeroCase(unsigned Size, bool IsLittleEndian);
|
||||
unsigned getLoadSize(unsigned Size);
|
||||
unsigned getNumLoads(unsigned Size);
|
||||
|
||||
public:
|
||||
MemCmpExpansion(CallInst *CI, unsigned MaxLoadSize,
|
||||
unsigned NumLoadsPerBlock);
|
||||
Value *getMemCmpExpansion(bool IsLittleEndian);
|
||||
};
|
||||
|
||||
MemCmpExpansion::ResultBlock::ResultBlock()
|
||||
: BB(nullptr), PhiSrc1(nullptr), PhiSrc2(nullptr) {}
|
||||
|
||||
// Initialize the basic block structure required for expansion of memcmp call
|
||||
// with given maximum load size and memcmp size parameter.
|
||||
// This structure includes:
|
||||
// 1. A list of load compare blocks - LoadCmpBlocks.
|
||||
// 2. An EndBlock, split from original instruction point, which is the block to
|
||||
// return from.
|
||||
// 3. ResultBlock, block to branch to for early exit when a
|
||||
// LoadCmpBlock finds a difference.
|
||||
MemCmpExpansion::MemCmpExpansion(CallInst *CI, unsigned MaxLoadSize,
|
||||
unsigned NumLoadsPerBlock)
|
||||
: CI(CI), MaxLoadSize(MaxLoadSize), NumLoadsPerBlock(NumLoadsPerBlock) {
|
||||
|
||||
IRBuilder<> Builder(CI->getContext());
|
||||
|
||||
BasicBlock *StartBlock = CI->getParent();
|
||||
EndBlock = StartBlock->splitBasicBlock(CI, "endblock");
|
||||
setupEndBlockPHINodes();
|
||||
IsUsedForZeroCmp = isOnlyUsedInZeroEqualityComparison(CI);
|
||||
|
||||
ConstantInt *SizeCast = dyn_cast<ConstantInt>(CI->getArgOperand(2));
|
||||
uint64_t Size = SizeCast->getZExtValue();
|
||||
|
||||
// Calculate how many load compare blocks are required for an expansion of
|
||||
// given Size.
|
||||
NumBlocks = calculateNumBlocks(Size);
|
||||
createResultBlock();
|
||||
|
||||
// If return value of memcmp is not used in a zero equality, we need to
|
||||
// calculate which source was larger. The calculation requires the
|
||||
// two loaded source values of each load compare block.
|
||||
// These will be saved in the phi nodes created by setupResultBlockPHINodes.
|
||||
if (!IsUsedForZeroCmp)
|
||||
setupResultBlockPHINodes();
|
||||
|
||||
// Create the number of required load compare basic blocks.
|
||||
createLoadCmpBlocks();
|
||||
|
||||
// Update the terminator added by splitBasicBlock to branch to the first
|
||||
// LoadCmpBlock.
|
||||
Builder.SetCurrentDebugLocation(CI->getDebugLoc());
|
||||
StartBlock->getTerminator()->setSuccessor(0, LoadCmpBlocks[0]);
|
||||
}
|
||||
|
||||
void MemCmpExpansion::createLoadCmpBlocks() {
|
||||
for (unsigned i = 0; i < NumBlocks; i++) {
|
||||
BasicBlock *BB = BasicBlock::Create(CI->getContext(), "loadbb",
|
||||
EndBlock->getParent(), EndBlock);
|
||||
LoadCmpBlocks.push_back(BB);
|
||||
}
|
||||
}
|
||||
|
||||
void MemCmpExpansion::createResultBlock() {
|
||||
ResBlock.BB = BasicBlock::Create(CI->getContext(), "res_block",
|
||||
EndBlock->getParent(), EndBlock);
|
||||
}
|
||||
|
||||
// This function creates the IR instructions for loading and comparing 1 byte.
|
||||
// It loads 1 byte from each source of the memcmp paramters with the given
|
||||
// GEPIndex. It then subtracts the two loaded values and adds this result to the
|
||||
// final phi node for selecting the memcmp result.
|
||||
void MemCmpExpansion::emitLoadCompareByteBlock(unsigned Index, int GEPIndex) {
|
||||
IRBuilder<> Builder(CI->getContext());
|
||||
|
||||
Value *Source1 = CI->getArgOperand(0);
|
||||
Value *Source2 = CI->getArgOperand(1);
|
||||
|
||||
Builder.SetInsertPoint(LoadCmpBlocks[Index]);
|
||||
Type *LoadSizeType = Type::getInt8Ty(CI->getContext());
|
||||
// Cast source to LoadSizeType*
|
||||
if (Source1->getType() != LoadSizeType)
|
||||
Source1 = Builder.CreateBitCast(Source1, LoadSizeType->getPointerTo());
|
||||
if (Source2->getType() != LoadSizeType)
|
||||
Source2 = Builder.CreateBitCast(Source2, LoadSizeType->getPointerTo());
|
||||
|
||||
// Get the base address using the GEPIndex
|
||||
if (GEPIndex != 0) {
|
||||
Source1 = Builder.CreateGEP(LoadSizeType, Source1,
|
||||
ConstantInt::get(LoadSizeType, GEPIndex));
|
||||
Source2 = Builder.CreateGEP(LoadSizeType, Source2,
|
||||
ConstantInt::get(LoadSizeType, GEPIndex));
|
||||
}
|
||||
|
||||
Value *LoadSrc1 = Builder.CreateLoad(LoadSizeType, Source1);
|
||||
Value *LoadSrc2 = Builder.CreateLoad(LoadSizeType, Source2);
|
||||
|
||||
LoadSrc1 = Builder.CreateZExt(LoadSrc1, Type::getInt32Ty(CI->getContext()));
|
||||
LoadSrc2 = Builder.CreateZExt(LoadSrc2, Type::getInt32Ty(CI->getContext()));
|
||||
Value *Diff = Builder.CreateSub(LoadSrc1, LoadSrc2);
|
||||
|
||||
PhiRes->addIncoming(Diff, LoadCmpBlocks[Index]);
|
||||
|
||||
if (Index < (LoadCmpBlocks.size() - 1)) {
|
||||
// Early exit branch if difference found to EndBlock, otherwise continue to
|
||||
// next LoadCmpBlock
|
||||
|
||||
Value *Cmp = Builder.CreateICmp(ICmpInst::ICMP_NE, Diff,
|
||||
ConstantInt::get(Diff->getType(), 0));
|
||||
BranchInst *CmpBr =
|
||||
BranchInst::Create(EndBlock, LoadCmpBlocks[Index + 1], Cmp);
|
||||
Builder.Insert(CmpBr);
|
||||
} else {
|
||||
// The last block has an unconditional branch to EndBlock
|
||||
BranchInst *CmpBr = BranchInst::Create(EndBlock);
|
||||
Builder.Insert(CmpBr);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned MemCmpExpansion::getNumLoads(unsigned Size) {
|
||||
return (Size / MaxLoadSize) + countPopulation(Size % MaxLoadSize);
|
||||
}
|
||||
|
||||
unsigned MemCmpExpansion::getLoadSize(unsigned Size) {
|
||||
return MinAlign(PowerOf2Floor(Size), MaxLoadSize);
|
||||
}
|
||||
|
||||
void MemCmpExpansion::emitLoadCompareBlockMultipleLoads(
|
||||
unsigned Index, unsigned Size, unsigned &NumBytesProcessed) {
|
||||
|
||||
IRBuilder<> Builder(CI->getContext());
|
||||
|
||||
std::vector<Value *> XorList, OrList;
|
||||
Value *Diff;
|
||||
|
||||
unsigned RemainingBytes = Size - NumBytesProcessed;
|
||||
unsigned NumLoadsRemaining = getNumLoads(RemainingBytes);
|
||||
unsigned NumLoads = std::min(NumLoadsRemaining, NumLoadsPerBlock);
|
||||
|
||||
Builder.SetInsertPoint(LoadCmpBlocks[Index]);
|
||||
|
||||
for (unsigned i = 0; i < NumLoads; ++i) {
|
||||
unsigned LoadSize = getLoadSize(RemainingBytes);
|
||||
unsigned GEPIndex = NumBytesProcessed / LoadSize;
|
||||
NumBytesProcessed += LoadSize;
|
||||
RemainingBytes -= LoadSize;
|
||||
|
||||
Type *LoadSizeType = IntegerType::get(CI->getContext(), LoadSize * 8);
|
||||
Type *MaxLoadType = IntegerType::get(CI->getContext(), MaxLoadSize * 8);
|
||||
|
||||
Value *Source1 = CI->getArgOperand(0);
|
||||
Value *Source2 = CI->getArgOperand(1);
|
||||
|
||||
// Cast source to LoadSizeType*
|
||||
if (Source1->getType() != LoadSizeType)
|
||||
Source1 = Builder.CreateBitCast(Source1, LoadSizeType->getPointerTo());
|
||||
if (Source2->getType() != LoadSizeType)
|
||||
Source2 = Builder.CreateBitCast(Source2, LoadSizeType->getPointerTo());
|
||||
|
||||
// Get the base address using the GEPIndex
|
||||
if (GEPIndex != 0) {
|
||||
Source1 = Builder.CreateGEP(LoadSizeType, Source1,
|
||||
ConstantInt::get(LoadSizeType, GEPIndex));
|
||||
Source2 = Builder.CreateGEP(LoadSizeType, Source2,
|
||||
ConstantInt::get(LoadSizeType, GEPIndex));
|
||||
}
|
||||
|
||||
// Load LoadSizeType from the base address
|
||||
Value *LoadSrc1 = Builder.CreateLoad(LoadSizeType, Source1);
|
||||
Value *LoadSrc2 = Builder.CreateLoad(LoadSizeType, Source2);
|
||||
if (LoadSizeType != MaxLoadType) {
|
||||
LoadSrc1 = Builder.CreateZExtOrTrunc(LoadSrc1, MaxLoadType);
|
||||
LoadSrc2 = Builder.CreateZExtOrTrunc(LoadSrc2, MaxLoadType);
|
||||
}
|
||||
Diff = Builder.CreateXor(LoadSrc1, LoadSrc2);
|
||||
Diff = Builder.CreateZExtOrTrunc(Diff, MaxLoadType);
|
||||
XorList.push_back(Diff);
|
||||
}
|
||||
|
||||
auto pairWiseOr = [&](std::vector<Value *> &InList) -> std::vector<Value *> {
|
||||
std::vector<Value *> OutList;
|
||||
for (unsigned i = 0; i < InList.size() - 1; i = i + 2) {
|
||||
Value *Or = Builder.CreateOr(InList[i], InList[i + 1]);
|
||||
OutList.push_back(Or);
|
||||
}
|
||||
if (InList.size() % 2 != 0)
|
||||
OutList.push_back(InList.back());
|
||||
return OutList;
|
||||
};
|
||||
|
||||
// Pair wise OR the XOR results
|
||||
OrList = pairWiseOr(XorList);
|
||||
|
||||
// Pair wise OR the OR results until one result left
|
||||
while (OrList.size() != 1) {
|
||||
OrList = pairWiseOr(OrList);
|
||||
}
|
||||
|
||||
Value *Cmp = Builder.CreateICmp(ICmpInst::ICMP_NE, OrList[0],
|
||||
ConstantInt::get(Diff->getType(), 0));
|
||||
BasicBlock *NextBB = (Index == (LoadCmpBlocks.size() - 1))
|
||||
? EndBlock
|
||||
: LoadCmpBlocks[Index + 1];
|
||||
// Early exit branch if difference found to ResultBlock, otherwise continue to
|
||||
// next LoadCmpBlock or EndBlock.
|
||||
BranchInst *CmpBr = BranchInst::Create(ResBlock.BB, NextBB, Cmp);
|
||||
Builder.Insert(CmpBr);
|
||||
|
||||
// Add a phi edge for the last LoadCmpBlock to Endblock with a value of 0
|
||||
// since early exit to ResultBlock was not taken (no difference was found in
|
||||
// any of the bytes)
|
||||
if (Index == LoadCmpBlocks.size() - 1) {
|
||||
Value *Zero = ConstantInt::get(Type::getInt32Ty(CI->getContext()), 0);
|
||||
PhiRes->addIncoming(Zero, LoadCmpBlocks[Index]);
|
||||
}
|
||||
}
|
||||
|
||||
// This function creates the IR intructions for loading and comparing using the
|
||||
// given LoadSize. It loads the number of bytes specified by LoadSize from each
|
||||
// source of the memcmp parameters. It then does a subtract to see if there was
|
||||
// a difference in the loaded values. If a difference is found, it branches
|
||||
// with an early exit to the ResultBlock for calculating which source was
|
||||
// larger. Otherwise, it falls through to the either the next LoadCmpBlock or
|
||||
// the EndBlock if this is the last LoadCmpBlock. Loading 1 byte is handled with
|
||||
// a special case through emitLoadCompareByteBlock. The special handling can
|
||||
// simply subtract the loaded values and add it to the result phi node.
|
||||
void MemCmpExpansion::emitLoadCompareBlock(unsigned Index, int LoadSize,
|
||||
int GEPIndex, bool IsLittleEndian) {
|
||||
if (LoadSize == 1) {
|
||||
MemCmpExpansion::emitLoadCompareByteBlock(Index, GEPIndex);
|
||||
return;
|
||||
}
|
||||
|
||||
IRBuilder<> Builder(CI->getContext());
|
||||
|
||||
Type *LoadSizeType = IntegerType::get(CI->getContext(), LoadSize * 8);
|
||||
Type *MaxLoadType = IntegerType::get(CI->getContext(), MaxLoadSize * 8);
|
||||
|
||||
Value *Source1 = CI->getArgOperand(0);
|
||||
Value *Source2 = CI->getArgOperand(1);
|
||||
|
||||
Builder.SetInsertPoint(LoadCmpBlocks[Index]);
|
||||
// Cast source to LoadSizeType*
|
||||
if (Source1->getType() != LoadSizeType)
|
||||
Source1 = Builder.CreateBitCast(Source1, LoadSizeType->getPointerTo());
|
||||
if (Source2->getType() != LoadSizeType)
|
||||
Source2 = Builder.CreateBitCast(Source2, LoadSizeType->getPointerTo());
|
||||
|
||||
// Get the base address using the GEPIndex
|
||||
if (GEPIndex != 0) {
|
||||
Source1 = Builder.CreateGEP(LoadSizeType, Source1,
|
||||
ConstantInt::get(LoadSizeType, GEPIndex));
|
||||
Source2 = Builder.CreateGEP(LoadSizeType, Source2,
|
||||
ConstantInt::get(LoadSizeType, GEPIndex));
|
||||
}
|
||||
|
||||
// Load LoadSizeType from the base address
|
||||
Value *LoadSrc1 = Builder.CreateLoad(LoadSizeType, Source1);
|
||||
Value *LoadSrc2 = Builder.CreateLoad(LoadSizeType, Source2);
|
||||
|
||||
if (IsLittleEndian) {
|
||||
Function *F = LoadCmpBlocks[Index]->getParent();
|
||||
|
||||
Function *Bswap = Intrinsic::getDeclaration(F->getParent(),
|
||||
Intrinsic::bswap, LoadSizeType);
|
||||
LoadSrc1 = Builder.CreateCall(Bswap, LoadSrc1);
|
||||
LoadSrc2 = Builder.CreateCall(Bswap, LoadSrc2);
|
||||
}
|
||||
|
||||
if (LoadSizeType != MaxLoadType) {
|
||||
LoadSrc1 = Builder.CreateZExtOrTrunc(LoadSrc1, MaxLoadType);
|
||||
LoadSrc2 = Builder.CreateZExtOrTrunc(LoadSrc2, MaxLoadType);
|
||||
}
|
||||
|
||||
// Add the loaded values to the phi nodes for calculating memcmp result only
|
||||
// if result is not used in a zero equality.
|
||||
if (!IsUsedForZeroCmp) {
|
||||
ResBlock.PhiSrc1->addIncoming(LoadSrc1, LoadCmpBlocks[Index]);
|
||||
ResBlock.PhiSrc2->addIncoming(LoadSrc2, LoadCmpBlocks[Index]);
|
||||
}
|
||||
|
||||
Value *Diff = Builder.CreateSub(LoadSrc1, LoadSrc2);
|
||||
|
||||
Value *Cmp = Builder.CreateICmp(ICmpInst::ICMP_NE, Diff,
|
||||
ConstantInt::get(Diff->getType(), 0));
|
||||
BasicBlock *NextBB = (Index == (LoadCmpBlocks.size() - 1))
|
||||
? EndBlock
|
||||
: LoadCmpBlocks[Index + 1];
|
||||
// Early exit branch if difference found to ResultBlock, otherwise continue to
|
||||
// next LoadCmpBlock or EndBlock.
|
||||
BranchInst *CmpBr = BranchInst::Create(ResBlock.BB, NextBB, Cmp);
|
||||
Builder.Insert(CmpBr);
|
||||
|
||||
// Add a phi edge for the last LoadCmpBlock to Endblock with a value of 0
|
||||
// since early exit to ResultBlock was not taken (no difference was found in
|
||||
// any of the bytes)
|
||||
if (Index == LoadCmpBlocks.size() - 1) {
|
||||
Value *Zero = ConstantInt::get(Type::getInt32Ty(CI->getContext()), 0);
|
||||
PhiRes->addIncoming(Zero, LoadCmpBlocks[Index]);
|
||||
}
|
||||
}
|
||||
|
||||
// This function populates the ResultBlock with a sequence to calculate the
|
||||
// memcmp result. It compares the two loaded source values and returns -1 if
|
||||
// src1 < src2 and 1 if src1 > src2.
|
||||
void MemCmpExpansion::emitMemCmpResultBlock(bool IsLittleEndian) {
|
||||
IRBuilder<> Builder(CI->getContext());
|
||||
|
||||
// Special case: if memcmp result is used in a zero equality, result does not
|
||||
// need to be calculated and can simply return 1.
|
||||
if (IsUsedForZeroCmp) {
|
||||
BasicBlock::iterator InsertPt = ResBlock.BB->getFirstInsertionPt();
|
||||
Builder.SetInsertPoint(ResBlock.BB, InsertPt);
|
||||
Value *Res = ConstantInt::get(Type::getInt32Ty(CI->getContext()), 1);
|
||||
PhiRes->addIncoming(Res, ResBlock.BB);
|
||||
BranchInst *NewBr = BranchInst::Create(EndBlock);
|
||||
Builder.Insert(NewBr);
|
||||
return;
|
||||
}
|
||||
BasicBlock::iterator InsertPt = ResBlock.BB->getFirstInsertionPt();
|
||||
Builder.SetInsertPoint(ResBlock.BB, InsertPt);
|
||||
|
||||
Value *Cmp = Builder.CreateICmp(ICmpInst::ICMP_ULT, ResBlock.PhiSrc1,
|
||||
ResBlock.PhiSrc2);
|
||||
|
||||
Value *Res =
|
||||
Builder.CreateSelect(Cmp, ConstantInt::get(Builder.getInt32Ty(), -1),
|
||||
ConstantInt::get(Builder.getInt32Ty(), 1));
|
||||
|
||||
BranchInst *NewBr = BranchInst::Create(EndBlock);
|
||||
Builder.Insert(NewBr);
|
||||
PhiRes->addIncoming(Res, ResBlock.BB);
|
||||
}
|
||||
|
||||
int MemCmpExpansion::calculateNumBlocks(unsigned Size) {
|
||||
int NumBlocks = 0;
|
||||
bool haveOneByteLoad = false;
|
||||
unsigned RemainingSize = Size;
|
||||
unsigned LoadSize = MaxLoadSize;
|
||||
while (RemainingSize) {
|
||||
if (LoadSize == 1)
|
||||
haveOneByteLoad = true;
|
||||
NumBlocks += RemainingSize / LoadSize;
|
||||
RemainingSize = RemainingSize % LoadSize;
|
||||
LoadSize = LoadSize / 2;
|
||||
}
|
||||
NumBlocksNonOneByte = haveOneByteLoad ? (NumBlocks - 1) : NumBlocks;
|
||||
|
||||
if (IsUsedForZeroCmp)
|
||||
NumBlocks = NumBlocks / NumLoadsPerBlock +
|
||||
(NumBlocks % NumLoadsPerBlock != 0 ? 1 : 0);
|
||||
|
||||
return NumBlocks;
|
||||
}
|
||||
|
||||
void MemCmpExpansion::setupResultBlockPHINodes() {
|
||||
IRBuilder<> Builder(CI->getContext());
|
||||
Type *MaxLoadType = IntegerType::get(CI->getContext(), MaxLoadSize * 8);
|
||||
Builder.SetInsertPoint(ResBlock.BB);
|
||||
ResBlock.PhiSrc1 =
|
||||
Builder.CreatePHI(MaxLoadType, NumBlocksNonOneByte, "phi.src1");
|
||||
ResBlock.PhiSrc2 =
|
||||
Builder.CreatePHI(MaxLoadType, NumBlocksNonOneByte, "phi.src2");
|
||||
}
|
||||
|
||||
void MemCmpExpansion::setupEndBlockPHINodes() {
|
||||
IRBuilder<> Builder(CI->getContext());
|
||||
|
||||
Builder.SetInsertPoint(&EndBlock->front());
|
||||
PhiRes = Builder.CreatePHI(Type::getInt32Ty(CI->getContext()), 2, "phi.res");
|
||||
}
|
||||
|
||||
Value *MemCmpExpansion::getMemCmpExpansionZeroCase(unsigned Size,
|
||||
bool IsLittleEndian) {
|
||||
unsigned NumBytesProcessed = 0;
|
||||
// This loop populates each of the LoadCmpBlocks with IR sequence to handle
|
||||
// multiple loads per block
|
||||
for (unsigned i = 0; i < NumBlocks; ++i) {
|
||||
emitLoadCompareBlockMultipleLoads(i, Size, NumBytesProcessed);
|
||||
}
|
||||
|
||||
emitMemCmpResultBlock(IsLittleEndian);
|
||||
return PhiRes;
|
||||
}
|
||||
|
||||
// This function expands the memcmp call into an inline expansion and returns
|
||||
// the memcmp result.
|
||||
Value *MemCmpExpansion::getMemCmpExpansion(bool IsLittleEndian) {
|
||||
|
||||
ConstantInt *SizeCast = dyn_cast<ConstantInt>(CI->getArgOperand(2));
|
||||
uint64_t Size = SizeCast->getZExtValue();
|
||||
|
||||
int LoadSize = MaxLoadSize;
|
||||
int NumBytesToBeProcessed = Size;
|
||||
|
||||
if (IsUsedForZeroCmp) {
|
||||
return getMemCmpExpansionZeroCase(Size, IsLittleEndian);
|
||||
}
|
||||
|
||||
unsigned Index = 0;
|
||||
// This loop calls emitLoadCompareBlock for comparing SizeVal bytes of the two
|
||||
// memcmp source. It starts with loading using the maximum load size set by
|
||||
// the target. It processes any remaining bytes using a load size which is the
|
||||
// next smallest power of 2.
|
||||
while (NumBytesToBeProcessed) {
|
||||
// Calculate how many blocks we can create with the current load size
|
||||
int NumBlocks = NumBytesToBeProcessed / LoadSize;
|
||||
int GEPIndex = (Size - NumBytesToBeProcessed) / LoadSize;
|
||||
NumBytesToBeProcessed = NumBytesToBeProcessed % LoadSize;
|
||||
|
||||
// For each NumBlocks, populate the instruction sequence for loading and
|
||||
// comparing LoadSize bytes
|
||||
while (NumBlocks--) {
|
||||
emitLoadCompareBlock(Index, LoadSize, GEPIndex, IsLittleEndian);
|
||||
Index++;
|
||||
GEPIndex++;
|
||||
}
|
||||
// Get the next LoadSize to use
|
||||
LoadSize = LoadSize / 2;
|
||||
}
|
||||
|
||||
emitMemCmpResultBlock(IsLittleEndian);
|
||||
return PhiRes;
|
||||
}
|
||||
|
||||
// This function checks to see if an expansion of memcmp can be generated.
|
||||
// It checks for constant compare size that is less than the max inline size.
|
||||
// If an expansion cannot occur, returns false to leave as a library call.
|
||||
// Otherwise, the library call is replaced wtih new IR instruction sequence.
|
||||
/// We want to transform:
|
||||
/// %call = call signext i32 @memcmp(i8* %0, i8* %1, i64 15)
|
||||
/// To:
|
||||
/// loadbb:
|
||||
/// %0 = bitcast i32* %buffer2 to i8*
|
||||
/// %1 = bitcast i32* %buffer1 to i8*
|
||||
/// %2 = bitcast i8* %1 to i64*
|
||||
/// %3 = bitcast i8* %0 to i64*
|
||||
/// %4 = load i64, i64* %2
|
||||
/// %5 = load i64, i64* %3
|
||||
/// %6 = call i64 @llvm.bswap.i64(i64 %4)
|
||||
/// %7 = call i64 @llvm.bswap.i64(i64 %5)
|
||||
/// %8 = sub i64 %6, %7
|
||||
/// %9 = icmp ne i64 %8, 0
|
||||
/// br i1 %9, label %res_block, label %loadbb1
|
||||
/// res_block: ; preds = %loadbb2,
|
||||
/// %loadbb1, %loadbb
|
||||
/// %phi.src1 = phi i64 [ %6, %loadbb ], [ %22, %loadbb1 ], [ %36, %loadbb2 ]
|
||||
/// %phi.src2 = phi i64 [ %7, %loadbb ], [ %23, %loadbb1 ], [ %37, %loadbb2 ]
|
||||
/// %10 = icmp ult i64 %phi.src1, %phi.src2
|
||||
/// %11 = select i1 %10, i32 -1, i32 1
|
||||
/// br label %endblock
|
||||
/// loadbb1: ; preds = %loadbb
|
||||
/// %12 = bitcast i32* %buffer2 to i8*
|
||||
/// %13 = bitcast i32* %buffer1 to i8*
|
||||
/// %14 = bitcast i8* %13 to i32*
|
||||
/// %15 = bitcast i8* %12 to i32*
|
||||
/// %16 = getelementptr i32, i32* %14, i32 2
|
||||
/// %17 = getelementptr i32, i32* %15, i32 2
|
||||
/// %18 = load i32, i32* %16
|
||||
/// %19 = load i32, i32* %17
|
||||
/// %20 = call i32 @llvm.bswap.i32(i32 %18)
|
||||
/// %21 = call i32 @llvm.bswap.i32(i32 %19)
|
||||
/// %22 = zext i32 %20 to i64
|
||||
/// %23 = zext i32 %21 to i64
|
||||
/// %24 = sub i64 %22, %23
|
||||
/// %25 = icmp ne i64 %24, 0
|
||||
/// br i1 %25, label %res_block, label %loadbb2
|
||||
/// loadbb2: ; preds = %loadbb1
|
||||
/// %26 = bitcast i32* %buffer2 to i8*
|
||||
/// %27 = bitcast i32* %buffer1 to i8*
|
||||
/// %28 = bitcast i8* %27 to i16*
|
||||
/// %29 = bitcast i8* %26 to i16*
|
||||
/// %30 = getelementptr i16, i16* %28, i16 6
|
||||
/// %31 = getelementptr i16, i16* %29, i16 6
|
||||
/// %32 = load i16, i16* %30
|
||||
/// %33 = load i16, i16* %31
|
||||
/// %34 = call i16 @llvm.bswap.i16(i16 %32)
|
||||
/// %35 = call i16 @llvm.bswap.i16(i16 %33)
|
||||
/// %36 = zext i16 %34 to i64
|
||||
/// %37 = zext i16 %35 to i64
|
||||
/// %38 = sub i64 %36, %37
|
||||
/// %39 = icmp ne i64 %38, 0
|
||||
/// br i1 %39, label %res_block, label %loadbb3
|
||||
/// loadbb3: ; preds = %loadbb2
|
||||
/// %40 = bitcast i32* %buffer2 to i8*
|
||||
/// %41 = bitcast i32* %buffer1 to i8*
|
||||
/// %42 = getelementptr i8, i8* %41, i8 14
|
||||
/// %43 = getelementptr i8, i8* %40, i8 14
|
||||
/// %44 = load i8, i8* %42
|
||||
/// %45 = load i8, i8* %43
|
||||
/// %46 = zext i8 %44 to i32
|
||||
/// %47 = zext i8 %45 to i32
|
||||
/// %48 = sub i32 %46, %47
|
||||
/// br label %endblock
|
||||
/// endblock: ; preds = %res_block,
|
||||
/// %loadbb3
|
||||
/// %phi.res = phi i32 [ %48, %loadbb3 ], [ %11, %res_block ]
|
||||
/// ret i32 %phi.res
|
||||
static bool expandMemCmp(CallInst *CI, const TargetTransformInfo *TTI,
|
||||
const TargetLowering *TLI, const DataLayout *DL) {
|
||||
NumMemCmpCalls++;
|
||||
IRBuilder<> Builder(CI->getContext());
|
||||
|
||||
// TTI call to check if target would like to expand memcmp and get the
|
||||
// MaxLoadSize
|
||||
unsigned MaxLoadSize;
|
||||
if (!TTI->expandMemCmp(CI, MaxLoadSize))
|
||||
return false;
|
||||
|
||||
// Early exit from expansion if -Oz
|
||||
if (CI->getParent()->getParent()->optForMinSize()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Early exit from expansion if size is not a constant
|
||||
ConstantInt *SizeCast = dyn_cast<ConstantInt>(CI->getArgOperand(2));
|
||||
if (!SizeCast) {
|
||||
NumMemCmpNotConstant++;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Early exit from expansion if size greater than max bytes to load
|
||||
uint64_t SizeVal = SizeCast->getZExtValue();
|
||||
|
||||
unsigned NumLoads = 0;
|
||||
unsigned RemainingSize = SizeVal;
|
||||
unsigned LoadSize = MaxLoadSize;
|
||||
while (RemainingSize) {
|
||||
NumLoads += RemainingSize / LoadSize;
|
||||
RemainingSize = RemainingSize % LoadSize;
|
||||
LoadSize = LoadSize / 2;
|
||||
}
|
||||
|
||||
if (NumLoads >
|
||||
TLI->getMaxExpandSizeMemcmp(CI->getParent()->getParent()->optForSize())) {
|
||||
NumMemCmpGreaterThanMax++;
|
||||
return false;
|
||||
}
|
||||
|
||||
NumMemCmpInlined++;
|
||||
|
||||
// MemCmpHelper object, creates and sets up basic blocks required for
|
||||
// expanding memcmp with size SizeVal
|
||||
unsigned NumLoadsPerBlock = MemCmpNumLoadsPerBlock;
|
||||
MemCmpExpansion MemCmpHelper(CI, MaxLoadSize, NumLoadsPerBlock);
|
||||
|
||||
Value *Res = MemCmpHelper.getMemCmpExpansion(DL->isLittleEndian());
|
||||
|
||||
// Replace call with result of expansion and erarse call.
|
||||
CI->replaceAllUsesWith(Res);
|
||||
CI->eraseFromParent();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CodeGenPrepare::optimizeCallInst(CallInst *CI, bool& ModifiedDT) {
|
||||
BasicBlock *BB = CI->getParent();
|
||||
|
||||
@ -1780,6 +2380,15 @@ bool CodeGenPrepare::optimizeCallInst(CallInst *CI, bool& ModifiedDT) {
|
||||
CI->eraseFromParent();
|
||||
return true;
|
||||
}
|
||||
|
||||
LibFunc Func;
|
||||
if (TLInfo->getLibFunc(*CI->getCalledFunction(), Func) &&
|
||||
Func == LibFunc_memcmp) {
|
||||
if (expandMemCmp(CI, TTI, TLI, DL)) {
|
||||
ModifiedDT = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -4927,6 +5536,7 @@ bool CodeGenPrepare::optimizeSwitchInst(SwitchInst *SI) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
namespace {
|
||||
/// \brief Helper class to promote a scalar operation to a vector one.
|
||||
/// This class is used to move downward extractelement transition.
|
||||
|
@ -74,7 +74,7 @@ void CriticalAntiDepBreaker::StartBlock(MachineBasicBlock *BB) {
|
||||
for (const MCPhysReg *I = MF.getRegInfo().getCalleeSavedRegs(); *I;
|
||||
++I) {
|
||||
unsigned Reg = *I;
|
||||
if (!IsReturnBlock && !(Pristine.test(Reg) || BB->isLiveIn(Reg)))
|
||||
if (!IsReturnBlock && !Pristine.test(Reg))
|
||||
continue;
|
||||
for (MCRegAliasIterator AI(*I, TRI, true); AI.isValid(); ++AI) {
|
||||
unsigned Reg = *AI;
|
||||
|
@ -98,12 +98,10 @@ bool Localizer::runOnMachineFunction(MachineFunction &MF) {
|
||||
// Create the localized instruction.
|
||||
MachineInstr *LocalizedMI = MF.CloneMachineInstr(&MI);
|
||||
LocalizedInstrs.insert(LocalizedMI);
|
||||
// Move it at the right place.
|
||||
MachineInstr &MIUse = *MOUse.getParent();
|
||||
if (MIUse.getParent() == InsertMBB)
|
||||
InsertMBB->insert(MIUse, LocalizedMI);
|
||||
else
|
||||
InsertMBB->insert(InsertMBB->getFirstNonPHI(), LocalizedMI);
|
||||
// Don't try to be smart for the insertion point.
|
||||
// There is no guarantee that the first seen use is the first
|
||||
// use in the block.
|
||||
InsertMBB->insert(InsertMBB->getFirstNonPHI(), LocalizedMI);
|
||||
|
||||
// Set a new register for the definition.
|
||||
unsigned NewReg =
|
||||
|
@ -607,8 +607,20 @@ MachineInstr *ImplicitNullChecks::insertFaultingInstr(
|
||||
.addMBB(HandlerMBB)
|
||||
.addImm(MI->getOpcode());
|
||||
|
||||
for (auto &MO : MI->uses())
|
||||
MIB.add(MO);
|
||||
for (auto &MO : MI->uses()) {
|
||||
if (MO.isReg()) {
|
||||
MachineOperand NewMO = MO;
|
||||
if (MO.isUse()) {
|
||||
NewMO.setIsKill(false);
|
||||
} else {
|
||||
assert(MO.isDef() && "Expected def or use");
|
||||
NewMO.setIsDead(false);
|
||||
}
|
||||
MIB.add(NewMO);
|
||||
} else {
|
||||
MIB.add(MO);
|
||||
}
|
||||
}
|
||||
|
||||
MIB.setMemRefs(MI->memoperands_begin(), MI->memoperands_end());
|
||||
|
||||
|
231
lib/CodeGen/LiveRangeShrink.cpp
Normal file
231
lib/CodeGen/LiveRangeShrink.cpp
Normal file
@ -0,0 +1,231 @@
|
||||
//===-- LiveRangeShrink.cpp - Move instructions to shrink live range ------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
///===---------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// This pass moves instructions close to the definition of its operands to
|
||||
/// shrink live range of the def instruction. The code motion is limited within
|
||||
/// the basic block. The moved instruction should have 1 def, and more than one
|
||||
/// uses, all of which are the only use of the def.
|
||||
///
|
||||
///===---------------------------------------------------------------------===//
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
||||
#include "llvm/CodeGen/Passes.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
|
||||
#define DEBUG_TYPE "lrshrink"
|
||||
|
||||
STATISTIC(NumInstrsHoistedToShrinkLiveRange,
|
||||
"Number of insructions hoisted to shrink live range.");
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
class LiveRangeShrink : public MachineFunctionPass {
|
||||
public:
|
||||
static char ID;
|
||||
|
||||
LiveRangeShrink() : MachineFunctionPass(ID) {
|
||||
initializeLiveRangeShrinkPass(*PassRegistry::getPassRegistry());
|
||||
}
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
||||
AU.setPreservesCFG();
|
||||
MachineFunctionPass::getAnalysisUsage(AU);
|
||||
}
|
||||
|
||||
StringRef getPassName() const override { return "Live Range Shrink"; }
|
||||
|
||||
bool runOnMachineFunction(MachineFunction &MF) override;
|
||||
};
|
||||
} // End anonymous namespace.
|
||||
|
||||
char LiveRangeShrink::ID = 0;
|
||||
char &llvm::LiveRangeShrinkID = LiveRangeShrink::ID;
|
||||
|
||||
INITIALIZE_PASS(LiveRangeShrink, "lrshrink", "Live Range Shrink Pass", false,
|
||||
false)
|
||||
namespace {
|
||||
typedef DenseMap<MachineInstr *, unsigned> InstOrderMap;
|
||||
|
||||
/// Returns \p New if it's dominated by \p Old, otherwise return \p Old.
|
||||
/// \p M maintains a map from instruction to its dominating order that satisfies
|
||||
/// M[A] > M[B] guarantees that A is dominated by B.
|
||||
/// If \p New is not in \p M, return \p Old. Otherwise if \p Old is null, return
|
||||
/// \p New.
|
||||
MachineInstr *FindDominatedInstruction(MachineInstr &New, MachineInstr *Old,
|
||||
const InstOrderMap &M) {
|
||||
auto NewIter = M.find(&New);
|
||||
if (NewIter == M.end())
|
||||
return Old;
|
||||
if (Old == nullptr)
|
||||
return &New;
|
||||
unsigned OrderOld = M.find(Old)->second;
|
||||
unsigned OrderNew = NewIter->second;
|
||||
if (OrderOld != OrderNew)
|
||||
return OrderOld < OrderNew ? &New : Old;
|
||||
// OrderOld == OrderNew, we need to iterate down from Old to see if it
|
||||
// can reach New, if yes, New is dominated by Old.
|
||||
for (MachineInstr *I = Old->getNextNode(); M.find(I)->second == OrderNew;
|
||||
I = I->getNextNode())
|
||||
if (I == &New)
|
||||
return &New;
|
||||
return Old;
|
||||
}
|
||||
|
||||
/// Builds Instruction to its dominating order number map \p M by traversing
|
||||
/// from instruction \p Start.
|
||||
void BuildInstOrderMap(MachineBasicBlock::iterator Start, InstOrderMap &M) {
|
||||
M.clear();
|
||||
unsigned i = 0;
|
||||
for (MachineInstr &I : make_range(Start, Start->getParent()->end()))
|
||||
M[&I] = i++;
|
||||
}
|
||||
} // end anonymous namespace
|
||||
|
||||
bool LiveRangeShrink::runOnMachineFunction(MachineFunction &MF) {
|
||||
if (skipFunction(*MF.getFunction()))
|
||||
return false;
|
||||
|
||||
MachineRegisterInfo &MRI = MF.getRegInfo();
|
||||
|
||||
DEBUG(dbgs() << "**** Analysing " << MF.getName() << '\n');
|
||||
|
||||
InstOrderMap IOM;
|
||||
// Map from register to instruction order (value of IOM) where the
|
||||
// register is used last. When moving instructions up, we need to
|
||||
// make sure all its defs (including dead def) will not cross its
|
||||
// last use when moving up.
|
||||
DenseMap<unsigned, std::pair<unsigned, MachineInstr *>> UseMap;
|
||||
|
||||
for (MachineBasicBlock &MBB : MF) {
|
||||
if (MBB.empty())
|
||||
continue;
|
||||
bool SawStore = false;
|
||||
BuildInstOrderMap(MBB.begin(), IOM);
|
||||
UseMap.clear();
|
||||
|
||||
for (MachineBasicBlock::iterator Next = MBB.begin(); Next != MBB.end();) {
|
||||
MachineInstr &MI = *Next;
|
||||
++Next;
|
||||
if (MI.isPHI() || MI.isDebugValue())
|
||||
continue;
|
||||
if (MI.mayStore())
|
||||
SawStore = true;
|
||||
|
||||
unsigned CurrentOrder = IOM[&MI];
|
||||
unsigned Barrier = 0;
|
||||
MachineInstr *BarrierMI = nullptr;
|
||||
for (const MachineOperand &MO : MI.operands()) {
|
||||
if (!MO.isReg() || MO.isDebug())
|
||||
continue;
|
||||
if (MO.isUse())
|
||||
UseMap[MO.getReg()] = std::make_pair(CurrentOrder, &MI);
|
||||
else if (MO.isDead() && UseMap.count(MO.getReg()))
|
||||
// Barrier is the last instruction where MO get used. MI should not
|
||||
// be moved above Barrier.
|
||||
if (Barrier < UseMap[MO.getReg()].first) {
|
||||
Barrier = UseMap[MO.getReg()].first;
|
||||
BarrierMI = UseMap[MO.getReg()].second;
|
||||
}
|
||||
}
|
||||
|
||||
if (!MI.isSafeToMove(nullptr, SawStore)) {
|
||||
// If MI has side effects, it should become a barrier for code motion.
|
||||
// IOM is rebuild from the next instruction to prevent later
|
||||
// instructions from being moved before this MI.
|
||||
if (MI.hasUnmodeledSideEffects() && Next != MBB.end()) {
|
||||
BuildInstOrderMap(Next, IOM);
|
||||
SawStore = false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
const MachineOperand *DefMO = nullptr;
|
||||
MachineInstr *Insert = nullptr;
|
||||
|
||||
// Number of live-ranges that will be shortened. We do not count
|
||||
// live-ranges that are defined by a COPY as it could be coalesced later.
|
||||
unsigned NumEligibleUse = 0;
|
||||
|
||||
for (const MachineOperand &MO : MI.operands()) {
|
||||
if (!MO.isReg() || MO.isDead() || MO.isDebug())
|
||||
continue;
|
||||
unsigned Reg = MO.getReg();
|
||||
// Do not move the instruction if it def/uses a physical register,
|
||||
// unless it is a constant physical register or a noreg.
|
||||
if (!TargetRegisterInfo::isVirtualRegister(Reg)) {
|
||||
if (!Reg || MRI.isConstantPhysReg(Reg))
|
||||
continue;
|
||||
Insert = nullptr;
|
||||
break;
|
||||
}
|
||||
if (MO.isDef()) {
|
||||
// Do not move if there is more than one def.
|
||||
if (DefMO) {
|
||||
Insert = nullptr;
|
||||
break;
|
||||
}
|
||||
DefMO = &MO;
|
||||
} else if (MRI.hasOneNonDBGUse(Reg) && MRI.hasOneDef(Reg) && DefMO &&
|
||||
MRI.getRegClass(DefMO->getReg()) ==
|
||||
MRI.getRegClass(MO.getReg())) {
|
||||
// The heuristic does not handle different register classes yet
|
||||
// (registers of different sizes, looser/tighter constraints). This
|
||||
// is because it needs more accurate model to handle register
|
||||
// pressure correctly.
|
||||
MachineInstr &DefInstr = *MRI.def_instr_begin(Reg);
|
||||
if (!DefInstr.isCopy())
|
||||
NumEligibleUse++;
|
||||
Insert = FindDominatedInstruction(DefInstr, Insert, IOM);
|
||||
} else {
|
||||
Insert = nullptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If Barrier equals IOM[I], traverse forward to find if BarrierMI is
|
||||
// after Insert, if yes, then we should not hoist.
|
||||
for (MachineInstr *I = Insert; I && IOM[I] == Barrier;
|
||||
I = I->getNextNode())
|
||||
if (I == BarrierMI) {
|
||||
Insert = nullptr;
|
||||
break;
|
||||
}
|
||||
// Move the instruction when # of shrunk live range > 1.
|
||||
if (DefMO && Insert && NumEligibleUse > 1 && Barrier <= IOM[Insert]) {
|
||||
MachineBasicBlock::iterator I = std::next(Insert->getIterator());
|
||||
// Skip all the PHI and debug instructions.
|
||||
while (I != MBB.end() && (I->isPHI() || I->isDebugValue()))
|
||||
I = std::next(I);
|
||||
if (I == MI.getIterator())
|
||||
continue;
|
||||
|
||||
// Update the dominator order to be the same as the insertion point.
|
||||
// We do this to maintain a non-decreasing order without need to update
|
||||
// all instruction orders after the insertion point.
|
||||
unsigned NewOrder = IOM[&*I];
|
||||
IOM[&MI] = NewOrder;
|
||||
NumInstrsHoistedToShrinkLiveRange++;
|
||||
|
||||
// Find MI's debug value following MI.
|
||||
MachineBasicBlock::iterator EndIter = std::next(MI.getIterator());
|
||||
if (MI.getOperand(0).isReg())
|
||||
for (; EndIter != MBB.end() && EndIter->isDebugValue() &&
|
||||
EndIter->getOperand(0).isReg() &&
|
||||
EndIter->getOperand(0).getReg() == MI.getOperand(0).getReg();
|
||||
++EndIter, ++Next)
|
||||
IOM[&*EndIter] = NewOrder;
|
||||
MBB.splice(I, &MBB, MI.getIterator(), EndIter);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
@ -332,8 +332,6 @@ bool MIRParserImpl::initializeMachineFunction(MachineFunction &MF) {
|
||||
MF.setAlignment(YamlMF.Alignment);
|
||||
MF.setExposesReturnsTwice(YamlMF.ExposesReturnsTwice);
|
||||
|
||||
if (YamlMF.NoVRegs)
|
||||
MF.getProperties().set(MachineFunctionProperties::Property::NoVRegs);
|
||||
if (YamlMF.Legalized)
|
||||
MF.getProperties().set(MachineFunctionProperties::Property::Legalized);
|
||||
if (YamlMF.RegBankSelected)
|
||||
|
@ -183,8 +183,6 @@ void MIRPrinter::print(const MachineFunction &MF) {
|
||||
YamlMF.Alignment = MF.getAlignment();
|
||||
YamlMF.ExposesReturnsTwice = MF.exposesReturnsTwice();
|
||||
|
||||
YamlMF.NoVRegs = MF.getProperties().hasProperty(
|
||||
MachineFunctionProperties::Property::NoVRegs);
|
||||
YamlMF.Legalized = MF.getProperties().hasProperty(
|
||||
MachineFunctionProperties::Property::Legalized);
|
||||
YamlMF.RegBankSelected = MF.getProperties().hasProperty(
|
||||
|
@ -350,6 +350,13 @@ void MachineBasicBlock::removeLiveIn(MCPhysReg Reg, LaneBitmask LaneMask) {
|
||||
LiveIns.erase(I);
|
||||
}
|
||||
|
||||
MachineBasicBlock::livein_iterator
|
||||
MachineBasicBlock::removeLiveIn(MachineBasicBlock::livein_iterator I) {
|
||||
// Get non-const version of iterator.
|
||||
LiveInVector::iterator LI = LiveIns.begin() + (I - LiveIns.begin());
|
||||
return LiveIns.erase(LI);
|
||||
}
|
||||
|
||||
bool MachineBasicBlock::isLiveIn(MCPhysReg Reg, LaneBitmask LaneMask) const {
|
||||
livein_iterator I = find_if(
|
||||
LiveIns, [Reg](const RegisterMaskPair &LI) { return LI.PhysReg == Reg; });
|
||||
|
@ -1,4 +1,4 @@
|
||||
//===-- lib/CodeGen/MachineInstr.cpp --------------------------------------===//
|
||||
//===- lib/CodeGen/MachineInstr.cpp ---------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -11,21 +11,34 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/CodeGen/MachineInstr.h"
|
||||
#include "llvm/ADT/APFloat.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/ADT/Hashing.h"
|
||||
#include "llvm/ADT/None.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/Analysis/AliasAnalysis.h"
|
||||
#include "llvm/CodeGen/MachineConstantPool.h"
|
||||
#include "llvm/Analysis/MemoryLocation.h"
|
||||
#include "llvm/CodeGen/GlobalISel/RegisterBank.h"
|
||||
#include "llvm/CodeGen/MachineBasicBlock.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
#include "llvm/CodeGen/MachineInstr.h"
|
||||
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
||||
#include "llvm/CodeGen/MachineInstrBundle.h"
|
||||
#include "llvm/CodeGen/MachineMemOperand.h"
|
||||
#include "llvm/CodeGen/MachineModuleInfo.h"
|
||||
#include "llvm/CodeGen/MachineOperand.h"
|
||||
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
||||
#include "llvm/CodeGen/PseudoSourceValue.h"
|
||||
#include "llvm/IR/Constants.h"
|
||||
#include "llvm/IR/DebugInfo.h"
|
||||
#include "llvm/IR/DebugInfoMetadata.h"
|
||||
#include "llvm/IR/DebugLoc.h"
|
||||
#include "llvm/IR/DerivedTypes.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/IR/InlineAsm.h"
|
||||
#include "llvm/IR/InstrTypes.h"
|
||||
#include "llvm/IR/Intrinsics.h"
|
||||
#include "llvm/IR/LLVMContext.h"
|
||||
#include "llvm/IR/Metadata.h"
|
||||
@ -35,9 +48,13 @@
|
||||
#include "llvm/IR/Value.h"
|
||||
#include "llvm/MC/MCInstrDesc.h"
|
||||
#include "llvm/MC/MCSymbol.h"
|
||||
#include "llvm/MC/MCRegisterInfo.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/LowLevelTypeImpl.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Target/TargetInstrInfo.h"
|
||||
@ -45,6 +62,14 @@
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
#include "llvm/Target/TargetRegisterInfo.h"
|
||||
#include "llvm/Target/TargetSubtargetInfo.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <iterator>
|
||||
#include <utility>
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
static cl::opt<bool> PrintWholeRegMask(
|
||||
@ -256,7 +281,7 @@ bool MachineOperand::isIdenticalTo(const MachineOperand &Other) const {
|
||||
case MachineOperand::MO_GlobalAddress:
|
||||
return getGlobal() == Other.getGlobal() && getOffset() == Other.getOffset();
|
||||
case MachineOperand::MO_ExternalSymbol:
|
||||
return !strcmp(getSymbolName(), Other.getSymbolName()) &&
|
||||
return strcmp(getSymbolName(), Other.getSymbolName()) == 0 &&
|
||||
getOffset() == Other.getOffset();
|
||||
case MachineOperand::MO_BlockAddress:
|
||||
return getBlockAddress() == Other.getBlockAddress() &&
|
||||
@ -723,9 +748,7 @@ void MachineInstr::addImplicitDefUseOperands(MachineFunction &MF) {
|
||||
/// the MCInstrDesc.
|
||||
MachineInstr::MachineInstr(MachineFunction &MF, const MCInstrDesc &tid,
|
||||
DebugLoc dl, bool NoImp)
|
||||
: MCID(&tid), Parent(nullptr), Operands(nullptr), NumOperands(0), Flags(0),
|
||||
AsmPrinterFlags(0), NumMemRefs(0), MemRefs(nullptr),
|
||||
debugLoc(std::move(dl)) {
|
||||
: MCID(&tid), debugLoc(std::move(dl)) {
|
||||
assert(debugLoc.hasTrivialDestructor() && "Expected trivial destructor");
|
||||
|
||||
// Reserve space for the expected number of operands.
|
||||
@ -742,9 +765,8 @@ MachineInstr::MachineInstr(MachineFunction &MF, const MCInstrDesc &tid,
|
||||
/// MachineInstr ctor - Copies MachineInstr arg exactly
|
||||
///
|
||||
MachineInstr::MachineInstr(MachineFunction &MF, const MachineInstr &MI)
|
||||
: MCID(&MI.getDesc()), Parent(nullptr), Operands(nullptr), NumOperands(0),
|
||||
Flags(0), AsmPrinterFlags(0), NumMemRefs(MI.NumMemRefs),
|
||||
MemRefs(MI.MemRefs), debugLoc(MI.getDebugLoc()) {
|
||||
: MCID(&MI.getDesc()), NumMemRefs(MI.NumMemRefs), MemRefs(MI.MemRefs),
|
||||
debugLoc(MI.getDebugLoc()) {
|
||||
assert(debugLoc.hasTrivialDestructor() && "Expected trivial destructor");
|
||||
|
||||
CapOperands = OperandCapacity::get(MI.getNumOperands());
|
||||
@ -1633,8 +1655,8 @@ bool MachineInstr::mayAlias(AliasAnalysis *AA, MachineInstr &Other,
|
||||
// memory objects. It can save compile time, and possibly catch some
|
||||
// corner cases not currently covered.
|
||||
|
||||
assert ((MMOa->getOffset() >= 0) && "Negative MachineMemOperand offset");
|
||||
assert ((MMOb->getOffset() >= 0) && "Negative MachineMemOperand offset");
|
||||
assert((MMOa->getOffset() >= 0) && "Negative MachineMemOperand offset");
|
||||
assert((MMOb->getOffset() >= 0) && "Negative MachineMemOperand offset");
|
||||
|
||||
int64_t MinOffset = std::min(MMOa->getOffset(), MMOb->getOffset());
|
||||
int64_t Overlapa = MMOa->getSize() + MMOa->getOffset() - MinOffset;
|
||||
@ -1667,7 +1689,7 @@ bool MachineInstr::hasOrderedMemoryRef() const {
|
||||
return true;
|
||||
|
||||
// Check if any of our memory operands are ordered.
|
||||
return any_of(memoperands(), [](const MachineMemOperand *MMO) {
|
||||
return llvm::any_of(memoperands(), [](const MachineMemOperand *MMO) {
|
||||
return !MMO->isUnordered();
|
||||
});
|
||||
}
|
||||
@ -1841,7 +1863,6 @@ void MachineInstr::print(raw_ostream &OS, ModuleSlotTracker &MST,
|
||||
return;
|
||||
|
||||
// Print the rest of the operands.
|
||||
bool OmittedAnyCallClobbers = false;
|
||||
bool FirstOp = true;
|
||||
unsigned AsmDescOp = ~0u;
|
||||
unsigned AsmOpCount = 0;
|
||||
@ -1878,31 +1899,6 @@ void MachineInstr::print(raw_ostream &OS, ModuleSlotTracker &MST,
|
||||
if (MO.isReg() && TargetRegisterInfo::isVirtualRegister(MO.getReg()))
|
||||
VirtRegs.push_back(MO.getReg());
|
||||
|
||||
// Omit call-clobbered registers which aren't used anywhere. This makes
|
||||
// call instructions much less noisy on targets where calls clobber lots
|
||||
// of registers. Don't rely on MO.isDead() because we may be called before
|
||||
// LiveVariables is run, or we may be looking at a non-allocatable reg.
|
||||
if (MRI && isCall() &&
|
||||
MO.isReg() && MO.isImplicit() && MO.isDef()) {
|
||||
unsigned Reg = MO.getReg();
|
||||
if (TargetRegisterInfo::isPhysicalRegister(Reg)) {
|
||||
if (MRI->use_empty(Reg)) {
|
||||
bool HasAliasLive = false;
|
||||
for (MCRegAliasIterator AI(Reg, TRI, true); AI.isValid(); ++AI) {
|
||||
unsigned AliasReg = *AI;
|
||||
if (!MRI->use_empty(AliasReg)) {
|
||||
HasAliasLive = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!HasAliasLive) {
|
||||
OmittedAnyCallClobbers = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (FirstOp) FirstOp = false; else OS << ",";
|
||||
OS << " ";
|
||||
if (i < getDesc().NumOperands) {
|
||||
@ -1984,12 +1980,6 @@ void MachineInstr::print(raw_ostream &OS, ModuleSlotTracker &MST,
|
||||
MO.print(OS, MST, TRI);
|
||||
}
|
||||
|
||||
// Briefly indicate whether any call clobbers were omitted.
|
||||
if (OmittedAnyCallClobbers) {
|
||||
if (!FirstOp) OS << ",";
|
||||
OS << " ...";
|
||||
}
|
||||
|
||||
bool HaveSemi = false;
|
||||
const unsigned PrintableFlags = FrameSetup | FrameDestroy;
|
||||
if (Flags & PrintableFlags) {
|
||||
@ -2255,8 +2245,8 @@ void MachineInstr::setPhysRegsDeadExcept(ArrayRef<unsigned> UsedRegs,
|
||||
unsigned Reg = MO.getReg();
|
||||
if (!TargetRegisterInfo::isPhysicalRegister(Reg)) continue;
|
||||
// If there are no uses, including partial uses, the def is dead.
|
||||
if (none_of(UsedRegs,
|
||||
[&](unsigned Use) { return TRI.regsOverlap(Use, Reg); }))
|
||||
if (llvm::none_of(UsedRegs,
|
||||
[&](unsigned Use) { return TRI.regsOverlap(Use, Reg); }))
|
||||
MO.setIsDead();
|
||||
}
|
||||
|
||||
|
@ -7,27 +7,34 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/CodeGen/MachineModuleInfo.h"
|
||||
#include "llvm/ADT/PointerUnion.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/PostOrderIterator.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/TinyPtrVector.h"
|
||||
#include "llvm/Analysis/EHPersonalities.h"
|
||||
#include "llvm/Analysis/ValueTracking.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
#include "llvm/CodeGen/MachineFunctionInitializer.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/CodeGen/MachineModuleInfo.h"
|
||||
#include "llvm/CodeGen/Passes.h"
|
||||
#include "llvm/IR/Constants.h"
|
||||
#include "llvm/IR/BasicBlock.h"
|
||||
#include "llvm/IR/DerivedTypes.h"
|
||||
#include "llvm/IR/GlobalVariable.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/MC/MCObjectFileInfo.h"
|
||||
#include "llvm/IR/Value.h"
|
||||
#include "llvm/IR/ValueHandle.h"
|
||||
#include "llvm/MC/MCContext.h"
|
||||
#include "llvm/MC/MCSymbol.h"
|
||||
#include "llvm/Support/Dwarf.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Target/TargetLoweringObjectFile.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::dwarf;
|
||||
|
||||
@ -37,14 +44,16 @@ INITIALIZE_PASS(MachineModuleInfo, "machinemoduleinfo",
|
||||
char MachineModuleInfo::ID = 0;
|
||||
|
||||
// Out of line virtual method.
|
||||
MachineModuleInfoImpl::~MachineModuleInfoImpl() {}
|
||||
MachineModuleInfoImpl::~MachineModuleInfoImpl() = default;
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class MMIAddrLabelMapCallbackPtr final : CallbackVH {
|
||||
MMIAddrLabelMap *Map;
|
||||
MMIAddrLabelMap *Map = nullptr;
|
||||
|
||||
public:
|
||||
MMIAddrLabelMapCallbackPtr() : Map(nullptr) {}
|
||||
MMIAddrLabelMapCallbackPtr(Value *V) : CallbackVH(V), Map(nullptr) {}
|
||||
MMIAddrLabelMapCallbackPtr() = default;
|
||||
MMIAddrLabelMapCallbackPtr(Value *V) : CallbackVH(V) {}
|
||||
|
||||
void setPtr(BasicBlock *BB) {
|
||||
ValueHandleBase::operator=(BB);
|
||||
@ -75,11 +84,12 @@ class MMIAddrLabelMap {
|
||||
/// This is a per-function list of symbols whose corresponding BasicBlock got
|
||||
/// deleted. These symbols need to be emitted at some point in the file, so
|
||||
/// AsmPrinter emits them after the function body.
|
||||
DenseMap<AssertingVH<Function>, std::vector<MCSymbol*> >
|
||||
DenseMap<AssertingVH<Function>, std::vector<MCSymbol*>>
|
||||
DeletedAddrLabelsNeedingEmission;
|
||||
public:
|
||||
|
||||
public:
|
||||
MMIAddrLabelMap(MCContext &context) : Context(context) {}
|
||||
|
||||
~MMIAddrLabelMap() {
|
||||
assert(DeletedAddrLabelsNeedingEmission.empty() &&
|
||||
"Some labels for deleted blocks never got emitted");
|
||||
@ -93,7 +103,8 @@ public:
|
||||
void UpdateForDeletedBlock(BasicBlock *BB);
|
||||
void UpdateForRAUWBlock(BasicBlock *Old, BasicBlock *New);
|
||||
};
|
||||
}
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
ArrayRef<MCSymbol *> MMIAddrLabelMap::getAddrLabelSymbolToEmit(BasicBlock *BB) {
|
||||
assert(BB->hasAddressTaken() &&
|
||||
@ -119,7 +130,7 @@ ArrayRef<MCSymbol *> MMIAddrLabelMap::getAddrLabelSymbolToEmit(BasicBlock *BB) {
|
||||
/// If we have any deleted symbols for F, return them.
|
||||
void MMIAddrLabelMap::
|
||||
takeDeletedSymbolsForFunction(Function *F, std::vector<MCSymbol*> &Result) {
|
||||
DenseMap<AssertingVH<Function>, std::vector<MCSymbol*> >::iterator I =
|
||||
DenseMap<AssertingVH<Function>, std::vector<MCSymbol*>>::iterator I =
|
||||
DeletedAddrLabelsNeedingEmission.find(F);
|
||||
|
||||
// If there are no entries for the function, just return.
|
||||
@ -130,7 +141,6 @@ takeDeletedSymbolsForFunction(Function *F, std::vector<MCSymbol*> &Result) {
|
||||
DeletedAddrLabelsNeedingEmission.erase(I);
|
||||
}
|
||||
|
||||
|
||||
void MMIAddrLabelMap::UpdateForDeletedBlock(BasicBlock *BB) {
|
||||
// If the block got deleted, there is no need for the symbol. If the symbol
|
||||
// was already emitted, we can just forget about it, otherwise we need to
|
||||
@ -177,7 +187,6 @@ void MMIAddrLabelMap::UpdateForRAUWBlock(BasicBlock *Old, BasicBlock *New) {
|
||||
OldEntry.Symbols.end());
|
||||
}
|
||||
|
||||
|
||||
void MMIAddrLabelMapCallbackPtr::deleted() {
|
||||
Map->UpdateForDeletedBlock(cast<BasicBlock>(getValPtr()));
|
||||
}
|
||||
@ -186,9 +195,6 @@ void MMIAddrLabelMapCallbackPtr::allUsesReplacedWith(Value *V2) {
|
||||
Map->UpdateForRAUWBlock(cast<BasicBlock>(getValPtr()), cast<BasicBlock>(V2));
|
||||
}
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
MachineModuleInfo::MachineModuleInfo(const TargetMachine *TM)
|
||||
: ImmutablePass(ID), TM(*TM),
|
||||
Context(TM->getMCAsmInfo(), TM->getMCRegisterInfo(),
|
||||
@ -196,11 +202,9 @@ MachineModuleInfo::MachineModuleInfo(const TargetMachine *TM)
|
||||
initializeMachineModuleInfoPass(*PassRegistry::getPassRegistry());
|
||||
}
|
||||
|
||||
MachineModuleInfo::~MachineModuleInfo() {
|
||||
}
|
||||
MachineModuleInfo::~MachineModuleInfo() = default;
|
||||
|
||||
bool MachineModuleInfo::doInitialization(Module &M) {
|
||||
|
||||
ObjFileMMI = nullptr;
|
||||
CurCallSite = 0;
|
||||
DbgInfoAvailable = UsesVAFloatArgument = UsesMorestackAddr = false;
|
||||
@ -211,7 +215,6 @@ bool MachineModuleInfo::doInitialization(Module &M) {
|
||||
}
|
||||
|
||||
bool MachineModuleInfo::doFinalization(Module &M) {
|
||||
|
||||
Personalities.clear();
|
||||
|
||||
delete AddrLabelSymbols;
|
||||
@ -290,10 +293,12 @@ void MachineModuleInfo::deleteMachineFunctionFor(Function &F) {
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
/// This pass frees the MachineFunction object associated with a Function.
|
||||
class FreeMachineFunction : public FunctionPass {
|
||||
public:
|
||||
static char ID;
|
||||
|
||||
FreeMachineFunction() : FunctionPass(ID) {}
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
||||
@ -311,14 +316,14 @@ public:
|
||||
return "Free MachineFunction";
|
||||
}
|
||||
};
|
||||
char FreeMachineFunction::ID;
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
namespace llvm {
|
||||
FunctionPass *createFreeMachineFunctionPass() {
|
||||
char FreeMachineFunction::ID;
|
||||
|
||||
FunctionPass *llvm::createFreeMachineFunctionPass() {
|
||||
return new FreeMachineFunction();
|
||||
}
|
||||
} // end namespace llvm
|
||||
|
||||
//===- MMI building helpers -----------------------------------------------===//
|
||||
|
||||
|
@ -280,6 +280,7 @@ namespace {
|
||||
SDValue visitSELECT_CC(SDNode *N);
|
||||
SDValue visitSETCC(SDNode *N);
|
||||
SDValue visitSETCCE(SDNode *N);
|
||||
SDValue visitSETCCCARRY(SDNode *N);
|
||||
SDValue visitSIGN_EXTEND(SDNode *N);
|
||||
SDValue visitZERO_EXTEND(SDNode *N);
|
||||
SDValue visitANY_EXTEND(SDNode *N);
|
||||
@ -1457,6 +1458,7 @@ SDValue DAGCombiner::visit(SDNode *N) {
|
||||
case ISD::SELECT_CC: return visitSELECT_CC(N);
|
||||
case ISD::SETCC: return visitSETCC(N);
|
||||
case ISD::SETCCE: return visitSETCCE(N);
|
||||
case ISD::SETCCCARRY: return visitSETCCCARRY(N);
|
||||
case ISD::SIGN_EXTEND: return visitSIGN_EXTEND(N);
|
||||
case ISD::ZERO_EXTEND: return visitZERO_EXTEND(N);
|
||||
case ISD::ANY_EXTEND: return visitANY_EXTEND(N);
|
||||
@ -1958,7 +1960,7 @@ SDValue DAGCombiner::visitADD(SDNode *N) {
|
||||
|
||||
// fold (a+b) -> (a|b) iff a and b share no bits.
|
||||
if ((!LegalOperations || TLI.isOperationLegal(ISD::OR, VT)) &&
|
||||
VT.isInteger() && DAG.haveNoCommonBitsSet(N0, N1))
|
||||
DAG.haveNoCommonBitsSet(N0, N1))
|
||||
return DAG.getNode(ISD::OR, DL, VT, N0, N1);
|
||||
|
||||
if (SDValue Combined = visitADDLike(N0, N1, N))
|
||||
@ -1970,6 +1972,44 @@ SDValue DAGCombiner::visitADD(SDNode *N) {
|
||||
return SDValue();
|
||||
}
|
||||
|
||||
static SDValue getAsCarry(const TargetLowering &TLI, SDValue V) {
|
||||
bool Masked = false;
|
||||
|
||||
// First, peel away TRUNCATE/ZERO_EXTEND/AND nodes due to legalization.
|
||||
while (true) {
|
||||
if (V.getOpcode() == ISD::TRUNCATE || V.getOpcode() == ISD::ZERO_EXTEND) {
|
||||
V = V.getOperand(0);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (V.getOpcode() == ISD::AND && isOneConstant(V.getOperand(1))) {
|
||||
Masked = true;
|
||||
V = V.getOperand(0);
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// If this is not a carry, return.
|
||||
if (V.getResNo() != 1)
|
||||
return SDValue();
|
||||
|
||||
if (V.getOpcode() != ISD::ADDCARRY && V.getOpcode() != ISD::SUBCARRY &&
|
||||
V.getOpcode() != ISD::UADDO && V.getOpcode() != ISD::USUBO)
|
||||
return SDValue();
|
||||
|
||||
// If the result is masked, then no matter what kind of bool it is we can
|
||||
// return. If it isn't, then we need to make sure the bool type is either 0 or
|
||||
// 1 and not other values.
|
||||
if (Masked ||
|
||||
TLI.getBooleanContents(V.getValueType()) ==
|
||||
TargetLoweringBase::ZeroOrOneBooleanContent)
|
||||
return V;
|
||||
|
||||
return SDValue();
|
||||
}
|
||||
|
||||
SDValue DAGCombiner::visitADDLike(SDValue N0, SDValue N1, SDNode *LocReference) {
|
||||
EVT VT = N0.getValueType();
|
||||
SDLoc DL(LocReference);
|
||||
@ -2017,6 +2057,13 @@ SDValue DAGCombiner::visitADDLike(SDValue N0, SDValue N1, SDNode *LocReference)
|
||||
return DAG.getNode(ISD::ADDCARRY, DL, N1->getVTList(),
|
||||
N0, N1.getOperand(0), N1.getOperand(2));
|
||||
|
||||
// (add X, Carry) -> (addcarry X, 0, Carry)
|
||||
if (TLI.isOperationLegalOrCustom(ISD::ADDCARRY, VT))
|
||||
if (SDValue Carry = getAsCarry(TLI, N1))
|
||||
return DAG.getNode(ISD::ADDCARRY, DL,
|
||||
DAG.getVTList(VT, Carry.getValueType()), N0,
|
||||
DAG.getConstant(0, DL, VT), Carry);
|
||||
|
||||
return SDValue();
|
||||
}
|
||||
|
||||
@ -2090,6 +2137,8 @@ SDValue DAGCombiner::visitUADDO(SDNode *N) {
|
||||
}
|
||||
|
||||
SDValue DAGCombiner::visitUADDOLike(SDValue N0, SDValue N1, SDNode *N) {
|
||||
auto VT = N0.getValueType();
|
||||
|
||||
// (uaddo X, (addcarry Y, 0, Carry)) -> (addcarry X, Y, Carry)
|
||||
// If Y + 1 cannot overflow.
|
||||
if (N1.getOpcode() == ISD::ADDCARRY && isNullConstant(N1.getOperand(1))) {
|
||||
@ -2100,6 +2149,12 @@ SDValue DAGCombiner::visitUADDOLike(SDValue N0, SDValue N1, SDNode *N) {
|
||||
N1.getOperand(2));
|
||||
}
|
||||
|
||||
// (uaddo X, Carry) -> (addcarry X, 0, Carry)
|
||||
if (TLI.isOperationLegalOrCustom(ISD::ADDCARRY, VT))
|
||||
if (SDValue Carry = getAsCarry(TLI, N1))
|
||||
return DAG.getNode(ISD::ADDCARRY, SDLoc(N), N->getVTList(), N0,
|
||||
DAG.getConstant(0, SDLoc(N), VT), Carry);
|
||||
|
||||
return SDValue();
|
||||
}
|
||||
|
||||
@ -2167,6 +2222,41 @@ SDValue DAGCombiner::visitADDCARRYLike(SDValue N0, SDValue N1, SDValue CarryIn,
|
||||
return DAG.getNode(ISD::ADDCARRY, SDLoc(N), N->getVTList(),
|
||||
N0.getOperand(0), N0.getOperand(1), CarryIn);
|
||||
|
||||
/**
|
||||
* When one of the addcarry argument is itself a carry, we may be facing
|
||||
* a diamond carry propagation. In which case we try to transform the DAG
|
||||
* to ensure linear carry propagation if that is possible.
|
||||
*
|
||||
* We are trying to get:
|
||||
* (addcarry X, 0, (addcarry A, B, Z):Carry)
|
||||
*/
|
||||
if (auto Y = getAsCarry(TLI, N1)) {
|
||||
/**
|
||||
* (uaddo A, B)
|
||||
* / \
|
||||
* Carry Sum
|
||||
* | \
|
||||
* | (addcarry *, 0, Z)
|
||||
* | /
|
||||
* \ Carry
|
||||
* | /
|
||||
* (addcarry X, *, *)
|
||||
*/
|
||||
if (Y.getOpcode() == ISD::UADDO &&
|
||||
CarryIn.getResNo() == 1 &&
|
||||
CarryIn.getOpcode() == ISD::ADDCARRY &&
|
||||
isNullConstant(CarryIn.getOperand(1)) &&
|
||||
CarryIn.getOperand(0) == Y.getValue(0)) {
|
||||
auto NewY = DAG.getNode(ISD::ADDCARRY, SDLoc(N), Y->getVTList(),
|
||||
Y.getOperand(0), Y.getOperand(1),
|
||||
CarryIn.getOperand(2));
|
||||
AddToWorklist(NewY.getNode());
|
||||
return DAG.getNode(ISD::ADDCARRY, SDLoc(N), N->getVTList(), N0,
|
||||
DAG.getConstant(0, SDLoc(N), N0.getValueType()),
|
||||
NewY.getValue(1));
|
||||
}
|
||||
}
|
||||
|
||||
return SDValue();
|
||||
}
|
||||
|
||||
@ -6754,6 +6844,19 @@ SDValue DAGCombiner::visitSETCCE(SDNode *N) {
|
||||
return SDValue();
|
||||
}
|
||||
|
||||
SDValue DAGCombiner::visitSETCCCARRY(SDNode *N) {
|
||||
SDValue LHS = N->getOperand(0);
|
||||
SDValue RHS = N->getOperand(1);
|
||||
SDValue Carry = N->getOperand(2);
|
||||
SDValue Cond = N->getOperand(3);
|
||||
|
||||
// If Carry is false, fold to a regular SETCC.
|
||||
if (isNullConstant(Carry))
|
||||
return DAG.getNode(ISD::SETCC, SDLoc(N), N->getVTList(), LHS, RHS, Cond);
|
||||
|
||||
return SDValue();
|
||||
}
|
||||
|
||||
/// Try to fold a sext/zext/aext dag node into a ConstantSDNode or
|
||||
/// a build_vector of constants.
|
||||
/// This function is called by the DAGCombiner when visiting sext/zext/aext
|
||||
@ -7124,12 +7227,11 @@ SDValue DAGCombiner::visitSIGN_EXTEND(SDNode *N) {
|
||||
SDValue ExtLoad = DAG.getExtLoad(ISD::SEXTLOAD, DL, VT, LN0->getChain(),
|
||||
LN0->getBasePtr(), N0.getValueType(),
|
||||
LN0->getMemOperand());
|
||||
CombineTo(N, ExtLoad);
|
||||
SDValue Trunc = DAG.getNode(ISD::TRUNCATE, SDLoc(N0),
|
||||
N0.getValueType(), ExtLoad);
|
||||
CombineTo(N0.getNode(), Trunc, ExtLoad.getValue(1));
|
||||
ExtendSetCCUses(SetCCs, Trunc, ExtLoad, DL, ISD::SIGN_EXTEND);
|
||||
return SDValue(N, 0); // Return N so it doesn't get rechecked!
|
||||
CombineTo(N0.getNode(), Trunc, ExtLoad.getValue(1));
|
||||
return CombineTo(N, ExtLoad); // Return N so it doesn't get rechecked!
|
||||
}
|
||||
}
|
||||
|
||||
@ -7185,10 +7287,9 @@ SDValue DAGCombiner::visitSIGN_EXTEND(SDNode *N) {
|
||||
SDValue Trunc = DAG.getNode(ISD::TRUNCATE,
|
||||
SDLoc(N0.getOperand(0)),
|
||||
N0.getOperand(0).getValueType(), ExtLoad);
|
||||
CombineTo(N, And);
|
||||
CombineTo(N0.getOperand(0).getNode(), Trunc, ExtLoad.getValue(1));
|
||||
ExtendSetCCUses(SetCCs, Trunc, ExtLoad, DL, ISD::SIGN_EXTEND);
|
||||
return SDValue(N, 0); // Return N so it doesn't get rechecked!
|
||||
CombineTo(N0.getOperand(0).getNode(), Trunc, ExtLoad.getValue(1));
|
||||
return CombineTo(N, And); // Return N so it doesn't get rechecked!
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -7427,12 +7528,9 @@ SDValue DAGCombiner::visitZERO_EXTEND(SDNode *N) {
|
||||
|
||||
SDValue Trunc = DAG.getNode(ISD::TRUNCATE, SDLoc(N0),
|
||||
N0.getValueType(), ExtLoad);
|
||||
ExtendSetCCUses(SetCCs, Trunc, ExtLoad, SDLoc(N), ISD::ZERO_EXTEND);
|
||||
CombineTo(N0.getNode(), Trunc, ExtLoad.getValue(1));
|
||||
|
||||
ExtendSetCCUses(SetCCs, Trunc, ExtLoad, SDLoc(N),
|
||||
ISD::ZERO_EXTEND);
|
||||
CombineTo(N, ExtLoad);
|
||||
return SDValue(N, 0); // Return N so it doesn't get rechecked!
|
||||
return CombineTo(N, ExtLoad); // Return N so it doesn't get rechecked!
|
||||
}
|
||||
}
|
||||
|
||||
@ -7482,11 +7580,9 @@ SDValue DAGCombiner::visitZERO_EXTEND(SDNode *N) {
|
||||
SDValue Trunc = DAG.getNode(ISD::TRUNCATE,
|
||||
SDLoc(N0.getOperand(0)),
|
||||
N0.getOperand(0).getValueType(), ExtLoad);
|
||||
CombineTo(N, And);
|
||||
ExtendSetCCUses(SetCCs, Trunc, ExtLoad, DL, ISD::ZERO_EXTEND);
|
||||
CombineTo(N0.getOperand(0).getNode(), Trunc, ExtLoad.getValue(1));
|
||||
ExtendSetCCUses(SetCCs, Trunc, ExtLoad, DL,
|
||||
ISD::ZERO_EXTEND);
|
||||
return SDValue(N, 0); // Return N so it doesn't get rechecked!
|
||||
return CombineTo(N, And); // Return N so it doesn't get rechecked!
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -12777,10 +12873,10 @@ bool DAGCombiner::MergeConsecutiveStores(StoreSDNode *St) {
|
||||
}
|
||||
|
||||
// If we have load/store pair instructions and we only have two values,
|
||||
// don't bother.
|
||||
// don't bother merging.
|
||||
unsigned RequiredAlignment;
|
||||
if (LoadNodes.size() == 2 && TLI.hasPairedLoad(MemVT, RequiredAlignment) &&
|
||||
St->getAlignment() >= RequiredAlignment) {
|
||||
StoreNodes[0].MemNode->getAlignment() >= RequiredAlignment) {
|
||||
StoreNodes.erase(StoreNodes.begin(), StoreNodes.begin() + 2);
|
||||
continue;
|
||||
}
|
||||
|
@ -2875,6 +2875,7 @@ bool DAGTypeLegalizer::ExpandIntegerOperand(SDNode *N, unsigned OpNo) {
|
||||
case ISD::SELECT_CC: Res = ExpandIntOp_SELECT_CC(N); break;
|
||||
case ISD::SETCC: Res = ExpandIntOp_SETCC(N); break;
|
||||
case ISD::SETCCE: Res = ExpandIntOp_SETCCE(N); break;
|
||||
case ISD::SETCCCARRY: Res = ExpandIntOp_SETCCCARRY(N); break;
|
||||
case ISD::SINT_TO_FP: Res = ExpandIntOp_SINT_TO_FP(N); break;
|
||||
case ISD::STORE: Res = ExpandIntOp_STORE(cast<StoreSDNode>(N), OpNo); break;
|
||||
case ISD::TRUNCATE: Res = ExpandIntOp_TRUNCATE(N); break;
|
||||
@ -3009,14 +3010,16 @@ void DAGTypeLegalizer::IntegerExpandSetCCOperands(SDValue &NewLHS,
|
||||
return;
|
||||
}
|
||||
|
||||
// Lower with SETCCE if the target supports it.
|
||||
// Lower with SETCCE or SETCCCARRY if the target supports it.
|
||||
EVT HiVT = LHSHi.getValueType();
|
||||
EVT ExpandVT = TLI.getTypeToExpandTo(*DAG.getContext(), HiVT);
|
||||
bool HasSETCCCARRY = TLI.isOperationLegalOrCustom(ISD::SETCCCARRY, ExpandVT);
|
||||
|
||||
// FIXME: Make all targets support this, then remove the other lowering.
|
||||
if (TLI.getOperationAction(
|
||||
ISD::SETCCE,
|
||||
TLI.getTypeToExpandTo(*DAG.getContext(), LHSLo.getValueType())) ==
|
||||
TargetLowering::Custom) {
|
||||
// SETCCE can detect < and >= directly. For > and <=, flip operands and
|
||||
// condition code.
|
||||
if (HasSETCCCARRY ||
|
||||
TLI.getOperationAction(ISD::SETCCE, ExpandVT) == TargetLowering::Custom) {
|
||||
// SETCCE/SETCCCARRY can detect < and >= directly. For > and <=, flip
|
||||
// operands and condition code.
|
||||
bool FlipOperands = false;
|
||||
switch (CCCode) {
|
||||
case ISD::SETGT: CCCode = ISD::SETLT; FlipOperands = true; break;
|
||||
@ -3030,27 +3033,28 @@ void DAGTypeLegalizer::IntegerExpandSetCCOperands(SDValue &NewLHS,
|
||||
std::swap(LHSHi, RHSHi);
|
||||
}
|
||||
// Perform a wide subtraction, feeding the carry from the low part into
|
||||
// SETCCE. The SETCCE operation is essentially looking at the high part of
|
||||
// the result of LHS - RHS. It is negative iff LHS < RHS. It is zero or
|
||||
// positive iff LHS >= RHS.
|
||||
SDVTList VTList = DAG.getVTList(LHSLo.getValueType(), MVT::Glue);
|
||||
SDValue LowCmp = DAG.getNode(ISD::SUBC, dl, VTList, LHSLo, RHSLo);
|
||||
SDValue Res =
|
||||
DAG.getNode(ISD::SETCCE, dl, getSetCCResultType(LHSLo.getValueType()),
|
||||
LHSHi, RHSHi, LowCmp.getValue(1), DAG.getCondCode(CCCode));
|
||||
// SETCCE/SETCCCARRY. The SETCCE/SETCCCARRY operation is essentially
|
||||
// looking at the high part of the result of LHS - RHS. It is negative
|
||||
// iff LHS < RHS. It is zero or positive iff LHS >= RHS.
|
||||
EVT LoVT = LHSLo.getValueType();
|
||||
SDVTList VTList = DAG.getVTList(
|
||||
LoVT, HasSETCCCARRY ? getSetCCResultType(LoVT) : MVT::Glue);
|
||||
SDValue LowCmp = DAG.getNode(HasSETCCCARRY ? ISD::USUBO : ISD::SUBC, dl,
|
||||
VTList, LHSLo, RHSLo);
|
||||
SDValue Res = DAG.getNode(HasSETCCCARRY ? ISD::SETCCCARRY : ISD::SETCCE, dl,
|
||||
getSetCCResultType(HiVT), LHSHi, RHSHi,
|
||||
LowCmp.getValue(1), DAG.getCondCode(CCCode));
|
||||
NewLHS = Res;
|
||||
NewRHS = SDValue();
|
||||
return;
|
||||
}
|
||||
|
||||
NewLHS = TLI.SimplifySetCC(getSetCCResultType(LHSHi.getValueType()),
|
||||
LHSHi, RHSHi, ISD::SETEQ, false,
|
||||
DagCombineInfo, dl);
|
||||
NewLHS = TLI.SimplifySetCC(getSetCCResultType(HiVT), LHSHi, RHSHi, ISD::SETEQ,
|
||||
false, DagCombineInfo, dl);
|
||||
if (!NewLHS.getNode())
|
||||
NewLHS = DAG.getSetCC(dl, getSetCCResultType(LHSHi.getValueType()),
|
||||
LHSHi, RHSHi, ISD::SETEQ);
|
||||
NewLHS = DAG.getSelect(dl, LoCmp.getValueType(),
|
||||
NewLHS, LoCmp, HiCmp);
|
||||
NewLHS =
|
||||
DAG.getSetCC(dl, getSetCCResultType(HiVT), LHSHi, RHSHi, ISD::SETEQ);
|
||||
NewLHS = DAG.getSelect(dl, LoCmp.getValueType(), NewLHS, LoCmp, HiCmp);
|
||||
NewRHS = SDValue();
|
||||
}
|
||||
|
||||
@ -3103,8 +3107,8 @@ SDValue DAGTypeLegalizer::ExpandIntOp_SETCC(SDNode *N) {
|
||||
}
|
||||
|
||||
// Otherwise, update N to have the operands specified.
|
||||
return SDValue(DAG.UpdateNodeOperands(N, NewLHS, NewRHS,
|
||||
DAG.getCondCode(CCCode)), 0);
|
||||
return SDValue(
|
||||
DAG.UpdateNodeOperands(N, NewLHS, NewRHS, DAG.getCondCode(CCCode)), 0);
|
||||
}
|
||||
|
||||
SDValue DAGTypeLegalizer::ExpandIntOp_SETCCE(SDNode *N) {
|
||||
@ -3125,6 +3129,24 @@ SDValue DAGTypeLegalizer::ExpandIntOp_SETCCE(SDNode *N) {
|
||||
LowCmp.getValue(1), Cond);
|
||||
}
|
||||
|
||||
SDValue DAGTypeLegalizer::ExpandIntOp_SETCCCARRY(SDNode *N) {
|
||||
SDValue LHS = N->getOperand(0);
|
||||
SDValue RHS = N->getOperand(1);
|
||||
SDValue Carry = N->getOperand(2);
|
||||
SDValue Cond = N->getOperand(3);
|
||||
SDLoc dl = SDLoc(N);
|
||||
|
||||
SDValue LHSLo, LHSHi, RHSLo, RHSHi;
|
||||
GetExpandedInteger(LHS, LHSLo, LHSHi);
|
||||
GetExpandedInteger(RHS, RHSLo, RHSHi);
|
||||
|
||||
// Expand to a SUBE for the low part and a smaller SETCCCARRY for the high.
|
||||
SDVTList VTList = DAG.getVTList(LHSLo.getValueType(), Carry.getValueType());
|
||||
SDValue LowCmp = DAG.getNode(ISD::SUBCARRY, dl, VTList, LHSLo, RHSLo, Carry);
|
||||
return DAG.getNode(ISD::SETCCCARRY, dl, N->getValueType(0), LHSHi, RHSHi,
|
||||
LowCmp.getValue(1), Cond);
|
||||
}
|
||||
|
||||
SDValue DAGTypeLegalizer::ExpandIntOp_Shift(SDNode *N) {
|
||||
// The value being shifted is legal, but the shift amount is too big.
|
||||
// It follows that either the result of the shift is undefined, or the
|
||||
|
@ -381,6 +381,7 @@ private:
|
||||
SDValue ExpandIntOp_SELECT_CC(SDNode *N);
|
||||
SDValue ExpandIntOp_SETCC(SDNode *N);
|
||||
SDValue ExpandIntOp_SETCCE(SDNode *N);
|
||||
SDValue ExpandIntOp_SETCCCARRY(SDNode *N);
|
||||
SDValue ExpandIntOp_Shift(SDNode *N);
|
||||
SDValue ExpandIntOp_SINT_TO_FP(SDNode *N);
|
||||
SDValue ExpandIntOp_STORE(StoreSDNode *N, unsigned OpNo);
|
||||
|
@ -226,6 +226,7 @@ private:
|
||||
void UnscheduleNodeBottomUp(SUnit*);
|
||||
void RestoreHazardCheckerBottomUp();
|
||||
void BacktrackBottomUp(SUnit*, SUnit*);
|
||||
SUnit *TryUnfoldSU(SUnit *);
|
||||
SUnit *CopyAndMoveSuccessors(SUnit*);
|
||||
void InsertCopiesAndMoveSuccs(SUnit*, unsigned,
|
||||
const TargetRegisterClass*,
|
||||
@ -780,7 +781,7 @@ void ScheduleDAGRRList::ScheduleNodeBottomUp(SUnit *SU) {
|
||||
}
|
||||
|
||||
/// CapturePred - This does the opposite of ReleasePred. Since SU is being
|
||||
/// unscheduled, incrcease the succ left count of its predecessors. Remove
|
||||
/// unscheduled, increase the succ left count of its predecessors. Remove
|
||||
/// them from AvailableQueue if necessary.
|
||||
void ScheduleDAGRRList::CapturePred(SDep *PredEdge) {
|
||||
SUnit *PredSU = PredEdge->getSUnit();
|
||||
@ -934,6 +935,146 @@ static bool isOperandOf(const SUnit *SU, SDNode *N) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// TryUnfold - Attempt to unfold
|
||||
SUnit *ScheduleDAGRRList::TryUnfoldSU(SUnit *SU) {
|
||||
SDNode *N = SU->getNode();
|
||||
// Use while over if to ease fall through.
|
||||
SmallVector<SDNode *, 2> NewNodes;
|
||||
if (!TII->unfoldMemoryOperand(*DAG, N, NewNodes))
|
||||
return nullptr;
|
||||
|
||||
// unfolding an x86 DEC64m operation results in store, dec, load which
|
||||
// can't be handled here so quit
|
||||
if (NewNodes.size() == 3)
|
||||
return nullptr;
|
||||
|
||||
assert(NewNodes.size() == 2 && "Expected a load folding node!");
|
||||
|
||||
N = NewNodes[1];
|
||||
SDNode *LoadNode = NewNodes[0];
|
||||
unsigned NumVals = N->getNumValues();
|
||||
unsigned OldNumVals = SU->getNode()->getNumValues();
|
||||
|
||||
// LoadNode may already exist. This can happen when there is another
|
||||
// load from the same location and producing the same type of value
|
||||
// but it has different alignment or volatileness.
|
||||
bool isNewLoad = true;
|
||||
SUnit *LoadSU;
|
||||
if (LoadNode->getNodeId() != -1) {
|
||||
LoadSU = &SUnits[LoadNode->getNodeId()];
|
||||
// If LoadSU has already been scheduled, we should clone it but
|
||||
// this would negate the benefit to unfolding so just return SU.
|
||||
if (LoadSU->isScheduled)
|
||||
return SU;
|
||||
isNewLoad = false;
|
||||
} else {
|
||||
LoadSU = CreateNewSUnit(LoadNode);
|
||||
LoadNode->setNodeId(LoadSU->NodeNum);
|
||||
|
||||
InitNumRegDefsLeft(LoadSU);
|
||||
computeLatency(LoadSU);
|
||||
}
|
||||
|
||||
DEBUG(dbgs() << "Unfolding SU #" << SU->NodeNum << "\n");
|
||||
|
||||
// Now that we are committed to unfolding replace DAG Uses.
|
||||
for (unsigned i = 0; i != NumVals; ++i)
|
||||
DAG->ReplaceAllUsesOfValueWith(SDValue(SU->getNode(), i), SDValue(N, i));
|
||||
DAG->ReplaceAllUsesOfValueWith(SDValue(SU->getNode(), OldNumVals - 1),
|
||||
SDValue(LoadNode, 1));
|
||||
|
||||
SUnit *NewSU = CreateNewSUnit(N);
|
||||
assert(N->getNodeId() == -1 && "Node already inserted!");
|
||||
N->setNodeId(NewSU->NodeNum);
|
||||
|
||||
const MCInstrDesc &MCID = TII->get(N->getMachineOpcode());
|
||||
for (unsigned i = 0; i != MCID.getNumOperands(); ++i) {
|
||||
if (MCID.getOperandConstraint(i, MCOI::TIED_TO) != -1) {
|
||||
NewSU->isTwoAddress = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (MCID.isCommutable())
|
||||
NewSU->isCommutable = true;
|
||||
|
||||
InitNumRegDefsLeft(NewSU);
|
||||
computeLatency(NewSU);
|
||||
|
||||
// Record all the edges to and from the old SU, by category.
|
||||
SmallVector<SDep, 4> ChainPreds;
|
||||
SmallVector<SDep, 4> ChainSuccs;
|
||||
SmallVector<SDep, 4> LoadPreds;
|
||||
SmallVector<SDep, 4> NodePreds;
|
||||
SmallVector<SDep, 4> NodeSuccs;
|
||||
for (SDep &Pred : SU->Preds) {
|
||||
if (Pred.isCtrl())
|
||||
ChainPreds.push_back(Pred);
|
||||
else if (isOperandOf(Pred.getSUnit(), LoadNode))
|
||||
LoadPreds.push_back(Pred);
|
||||
else
|
||||
NodePreds.push_back(Pred);
|
||||
}
|
||||
for (SDep &Succ : SU->Succs) {
|
||||
if (Succ.isCtrl())
|
||||
ChainSuccs.push_back(Succ);
|
||||
else
|
||||
NodeSuccs.push_back(Succ);
|
||||
}
|
||||
|
||||
// Now assign edges to the newly-created nodes.
|
||||
for (const SDep &Pred : ChainPreds) {
|
||||
RemovePred(SU, Pred);
|
||||
if (isNewLoad)
|
||||
AddPred(LoadSU, Pred);
|
||||
}
|
||||
for (const SDep &Pred : LoadPreds) {
|
||||
RemovePred(SU, Pred);
|
||||
if (isNewLoad)
|
||||
AddPred(LoadSU, Pred);
|
||||
}
|
||||
for (const SDep &Pred : NodePreds) {
|
||||
RemovePred(SU, Pred);
|
||||
AddPred(NewSU, Pred);
|
||||
}
|
||||
for (SDep D : NodeSuccs) {
|
||||
SUnit *SuccDep = D.getSUnit();
|
||||
D.setSUnit(SU);
|
||||
RemovePred(SuccDep, D);
|
||||
D.setSUnit(NewSU);
|
||||
AddPred(SuccDep, D);
|
||||
// Balance register pressure.
|
||||
if (AvailableQueue->tracksRegPressure() && SuccDep->isScheduled &&
|
||||
!D.isCtrl() && NewSU->NumRegDefsLeft > 0)
|
||||
--NewSU->NumRegDefsLeft;
|
||||
}
|
||||
for (SDep D : ChainSuccs) {
|
||||
SUnit *SuccDep = D.getSUnit();
|
||||
D.setSUnit(SU);
|
||||
RemovePred(SuccDep, D);
|
||||
if (isNewLoad) {
|
||||
D.setSUnit(LoadSU);
|
||||
AddPred(SuccDep, D);
|
||||
}
|
||||
}
|
||||
|
||||
// Add a data dependency to reflect that NewSU reads the value defined
|
||||
// by LoadSU.
|
||||
SDep D(LoadSU, SDep::Data, 0);
|
||||
D.setLatency(LoadSU->Latency);
|
||||
AddPred(NewSU, D);
|
||||
|
||||
if (isNewLoad)
|
||||
AvailableQueue->addNode(LoadSU);
|
||||
AvailableQueue->addNode(NewSU);
|
||||
|
||||
++NumUnfolds;
|
||||
|
||||
if (NewSU->NumSuccsLeft == 0)
|
||||
NewSU->isAvailable = true;
|
||||
|
||||
return NewSU;
|
||||
}
|
||||
|
||||
/// CopyAndMoveSuccessors - Clone the specified node and move its scheduled
|
||||
/// successors to the newly created node.
|
||||
SUnit *ScheduleDAGRRList::CopyAndMoveSuccessors(SUnit *SU) {
|
||||
@ -959,135 +1100,16 @@ SUnit *ScheduleDAGRRList::CopyAndMoveSuccessors(SUnit *SU) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// If possible unfold instruction.
|
||||
if (TryUnfold) {
|
||||
SmallVector<SDNode*, 2> NewNodes;
|
||||
if (!TII->unfoldMemoryOperand(*DAG, N, NewNodes))
|
||||
SUnit *UnfoldSU = TryUnfoldSU(SU);
|
||||
if (!UnfoldSU)
|
||||
return nullptr;
|
||||
|
||||
// unfolding an x86 DEC64m operation results in store, dec, load which
|
||||
// can't be handled here so quit
|
||||
if (NewNodes.size() == 3)
|
||||
return nullptr;
|
||||
|
||||
DEBUG(dbgs() << "Unfolding SU #" << SU->NodeNum << "\n");
|
||||
assert(NewNodes.size() == 2 && "Expected a load folding node!");
|
||||
|
||||
N = NewNodes[1];
|
||||
SDNode *LoadNode = NewNodes[0];
|
||||
unsigned NumVals = N->getNumValues();
|
||||
unsigned OldNumVals = SU->getNode()->getNumValues();
|
||||
for (unsigned i = 0; i != NumVals; ++i)
|
||||
DAG->ReplaceAllUsesOfValueWith(SDValue(SU->getNode(), i), SDValue(N, i));
|
||||
DAG->ReplaceAllUsesOfValueWith(SDValue(SU->getNode(), OldNumVals-1),
|
||||
SDValue(LoadNode, 1));
|
||||
|
||||
// LoadNode may already exist. This can happen when there is another
|
||||
// load from the same location and producing the same type of value
|
||||
// but it has different alignment or volatileness.
|
||||
bool isNewLoad = true;
|
||||
SUnit *LoadSU;
|
||||
if (LoadNode->getNodeId() != -1) {
|
||||
LoadSU = &SUnits[LoadNode->getNodeId()];
|
||||
isNewLoad = false;
|
||||
} else {
|
||||
LoadSU = CreateNewSUnit(LoadNode);
|
||||
LoadNode->setNodeId(LoadSU->NodeNum);
|
||||
|
||||
InitNumRegDefsLeft(LoadSU);
|
||||
computeLatency(LoadSU);
|
||||
}
|
||||
|
||||
SUnit *NewSU = CreateNewSUnit(N);
|
||||
assert(N->getNodeId() == -1 && "Node already inserted!");
|
||||
N->setNodeId(NewSU->NodeNum);
|
||||
|
||||
const MCInstrDesc &MCID = TII->get(N->getMachineOpcode());
|
||||
for (unsigned i = 0; i != MCID.getNumOperands(); ++i) {
|
||||
if (MCID.getOperandConstraint(i, MCOI::TIED_TO) != -1) {
|
||||
NewSU->isTwoAddress = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (MCID.isCommutable())
|
||||
NewSU->isCommutable = true;
|
||||
|
||||
InitNumRegDefsLeft(NewSU);
|
||||
computeLatency(NewSU);
|
||||
|
||||
// Record all the edges to and from the old SU, by category.
|
||||
SmallVector<SDep, 4> ChainPreds;
|
||||
SmallVector<SDep, 4> ChainSuccs;
|
||||
SmallVector<SDep, 4> LoadPreds;
|
||||
SmallVector<SDep, 4> NodePreds;
|
||||
SmallVector<SDep, 4> NodeSuccs;
|
||||
for (SDep &Pred : SU->Preds) {
|
||||
if (Pred.isCtrl())
|
||||
ChainPreds.push_back(Pred);
|
||||
else if (isOperandOf(Pred.getSUnit(), LoadNode))
|
||||
LoadPreds.push_back(Pred);
|
||||
else
|
||||
NodePreds.push_back(Pred);
|
||||
}
|
||||
for (SDep &Succ : SU->Succs) {
|
||||
if (Succ.isCtrl())
|
||||
ChainSuccs.push_back(Succ);
|
||||
else
|
||||
NodeSuccs.push_back(Succ);
|
||||
}
|
||||
|
||||
// Now assign edges to the newly-created nodes.
|
||||
for (const SDep &Pred : ChainPreds) {
|
||||
RemovePred(SU, Pred);
|
||||
if (isNewLoad)
|
||||
AddPred(LoadSU, Pred);
|
||||
}
|
||||
for (const SDep &Pred : LoadPreds) {
|
||||
RemovePred(SU, Pred);
|
||||
if (isNewLoad)
|
||||
AddPred(LoadSU, Pred);
|
||||
}
|
||||
for (const SDep &Pred : NodePreds) {
|
||||
RemovePred(SU, Pred);
|
||||
AddPred(NewSU, Pred);
|
||||
}
|
||||
for (SDep D : NodeSuccs) {
|
||||
SUnit *SuccDep = D.getSUnit();
|
||||
D.setSUnit(SU);
|
||||
RemovePred(SuccDep, D);
|
||||
D.setSUnit(NewSU);
|
||||
AddPred(SuccDep, D);
|
||||
// Balance register pressure.
|
||||
if (AvailableQueue->tracksRegPressure() && SuccDep->isScheduled
|
||||
&& !D.isCtrl() && NewSU->NumRegDefsLeft > 0)
|
||||
--NewSU->NumRegDefsLeft;
|
||||
}
|
||||
for (SDep D : ChainSuccs) {
|
||||
SUnit *SuccDep = D.getSUnit();
|
||||
D.setSUnit(SU);
|
||||
RemovePred(SuccDep, D);
|
||||
if (isNewLoad) {
|
||||
D.setSUnit(LoadSU);
|
||||
AddPred(SuccDep, D);
|
||||
}
|
||||
}
|
||||
|
||||
// Add a data dependency to reflect that NewSU reads the value defined
|
||||
// by LoadSU.
|
||||
SDep D(LoadSU, SDep::Data, 0);
|
||||
D.setLatency(LoadSU->Latency);
|
||||
AddPred(NewSU, D);
|
||||
|
||||
if (isNewLoad)
|
||||
AvailableQueue->addNode(LoadSU);
|
||||
AvailableQueue->addNode(NewSU);
|
||||
|
||||
++NumUnfolds;
|
||||
|
||||
if (NewSU->NumSuccsLeft == 0) {
|
||||
NewSU->isAvailable = true;
|
||||
return NewSU;
|
||||
}
|
||||
SU = NewSU;
|
||||
SU = UnfoldSU;
|
||||
N = SU->getNode();
|
||||
// If this can be scheduled don't bother duplicating and just return
|
||||
if (SU->NumSuccsLeft == 0)
|
||||
return SU;
|
||||
}
|
||||
|
||||
DEBUG(dbgs() << " Duplicating SU #" << SU->NodeNum << "\n");
|
||||
|
@ -214,6 +214,7 @@ std::string SDNode::getOperationName(const SelectionDAG *G) const {
|
||||
case ISD::FPOWI: return "fpowi";
|
||||
case ISD::SETCC: return "setcc";
|
||||
case ISD::SETCCE: return "setcce";
|
||||
case ISD::SETCCCARRY: return "setcccarry";
|
||||
case ISD::SELECT: return "select";
|
||||
case ISD::VSELECT: return "vselect";
|
||||
case ISD::SELECT_CC: return "select_cc";
|
||||
|
@ -842,9 +842,10 @@ TargetLoweringBase::TargetLoweringBase(const TargetMachine &tm) : TM(tm) {
|
||||
initActions();
|
||||
|
||||
// Perform these initializations only once.
|
||||
MaxStoresPerMemset = MaxStoresPerMemcpy = MaxStoresPerMemmove = 8;
|
||||
MaxStoresPerMemsetOptSize = MaxStoresPerMemcpyOptSize
|
||||
= MaxStoresPerMemmoveOptSize = 4;
|
||||
MaxStoresPerMemset = MaxStoresPerMemcpy = MaxStoresPerMemmove =
|
||||
MaxLoadsPerMemcmp = 8;
|
||||
MaxStoresPerMemsetOptSize = MaxStoresPerMemcpyOptSize =
|
||||
MaxStoresPerMemmoveOptSize = MaxLoadsPerMemcmpOptSize = 4;
|
||||
UseUnderscoreSetJmp = false;
|
||||
UseUnderscoreLongJmp = false;
|
||||
HasMultipleConditionRegisters = false;
|
||||
@ -926,6 +927,7 @@ void TargetLoweringBase::initActions() {
|
||||
// ADDCARRY operations default to expand
|
||||
setOperationAction(ISD::ADDCARRY, VT, Expand);
|
||||
setOperationAction(ISD::SUBCARRY, VT, Expand);
|
||||
setOperationAction(ISD::SETCCCARRY, VT, Expand);
|
||||
|
||||
// These default to Expand so they will be expanded to CTLZ/CTTZ by default.
|
||||
setOperationAction(ISD::CTLZ_ZERO_UNDEF, VT, Expand);
|
||||
|
@ -261,9 +261,9 @@ TargetPassConfig::~TargetPassConfig() {
|
||||
|
||||
// Out of line constructor provides default values for pass options and
|
||||
// registers all common codegen passes.
|
||||
TargetPassConfig::TargetPassConfig(TargetMachine *tm, PassManagerBase &pm)
|
||||
TargetPassConfig::TargetPassConfig(LLVMTargetMachine &TM, PassManagerBase &pm)
|
||||
: ImmutablePass(ID), PM(&pm), Started(true), Stopped(false),
|
||||
AddingMachinePasses(false), TM(tm), Impl(nullptr), Initialized(false),
|
||||
AddingMachinePasses(false), TM(&TM), Impl(nullptr), Initialized(false),
|
||||
DisableVerify(false), EnableTailMerge(true),
|
||||
RequireCodeGenSCCOrder(false) {
|
||||
|
||||
@ -282,9 +282,9 @@ TargetPassConfig::TargetPassConfig(TargetMachine *tm, PassManagerBase &pm)
|
||||
substitutePass(&PostRAMachineLICMID, &MachineLICMID);
|
||||
|
||||
if (StringRef(PrintMachineInstrs.getValue()).equals(""))
|
||||
TM->Options.PrintMachineCode = true;
|
||||
TM.Options.PrintMachineCode = true;
|
||||
|
||||
if (TM->Options.EnableIPRA)
|
||||
if (TM.Options.EnableIPRA)
|
||||
setRequiresCodeGenSCCOrder();
|
||||
}
|
||||
|
||||
@ -310,7 +310,7 @@ void TargetPassConfig::insertPass(AnalysisID TargetPassID,
|
||||
///
|
||||
/// Targets may override this to extend TargetPassConfig.
|
||||
TargetPassConfig *LLVMTargetMachine::createPassConfig(PassManagerBase &PM) {
|
||||
return new TargetPassConfig(this, PM);
|
||||
return new TargetPassConfig(*this, PM);
|
||||
}
|
||||
|
||||
TargetPassConfig::TargetPassConfig()
|
||||
@ -430,7 +430,12 @@ void TargetPassConfig::addPrintPass(const std::string &Banner) {
|
||||
}
|
||||
|
||||
void TargetPassConfig::addVerifyPass(const std::string &Banner) {
|
||||
if (VerifyMachineCode)
|
||||
bool Verify = VerifyMachineCode;
|
||||
#ifdef EXPENSIVE_CHECKS
|
||||
if (VerifyMachineCode == cl::BOU_UNSET)
|
||||
Verify = TM->isMachineVerifierClean();
|
||||
#endif
|
||||
if (Verify)
|
||||
PM->add(createMachineVerifierPass(Banner));
|
||||
}
|
||||
|
||||
|
@ -46,7 +46,7 @@ Error CVSymbolVisitor::visitSymbolRecord(CVSymbol &Record) {
|
||||
}
|
||||
#define SYMBOL_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \
|
||||
SYMBOL_RECORD(EnumVal, EnumVal, AliasName)
|
||||
#include "llvm/DebugInfo/CodeView/CVSymbolTypes.def"
|
||||
#include "llvm/DebugInfo/CodeView/CodeViewSymbols.def"
|
||||
}
|
||||
|
||||
if (auto EC = Callbacks.visitSymbolEnd(Record))
|
||||
|
@ -71,7 +71,7 @@ static Error visitMemberRecord(CVMemberRecord &Record,
|
||||
MEMBER_RECORD(EnumVal, EnumVal, AliasName)
|
||||
#define TYPE_RECORD(EnumName, EnumVal, Name)
|
||||
#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
|
||||
#include "llvm/DebugInfo/CodeView/TypeRecords.def"
|
||||
#include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
|
||||
}
|
||||
|
||||
if (auto EC = Callbacks.visitMemberEnd(Record))
|
||||
@ -155,7 +155,7 @@ Error CVTypeVisitor::finishVisitation(CVType &Record) {
|
||||
TYPE_RECORD(EnumVal, EnumVal, AliasName)
|
||||
#define MEMBER_RECORD(EnumName, EnumVal, Name)
|
||||
#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
|
||||
#include "llvm/DebugInfo/CodeView/TypeRecords.def"
|
||||
#include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
|
||||
}
|
||||
|
||||
if (auto EC = Callbacks.visitTypeEnd(Record))
|
||||
|
@ -20,13 +20,13 @@ using namespace codeview;
|
||||
|
||||
static const EnumEntry<SymbolKind> SymbolTypeNames[] = {
|
||||
#define CV_SYMBOL(enum, val) {#enum, enum},
|
||||
#include "llvm/DebugInfo/CodeView/CVSymbolTypes.def"
|
||||
#include "llvm/DebugInfo/CodeView/CodeViewSymbols.def"
|
||||
#undef CV_SYMBOL
|
||||
};
|
||||
|
||||
static const EnumEntry<TypeLeafKind> TypeLeafNames[] = {
|
||||
#define CV_TYPE(name, val) {#name, name},
|
||||
#include "llvm/DebugInfo/CodeView/TypeRecords.def"
|
||||
#include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
|
||||
#undef CV_TYPE
|
||||
};
|
||||
|
||||
|
@ -41,7 +41,7 @@ public:
|
||||
#define SYMBOL_RECORD(EnumName, EnumVal, Name) \
|
||||
Error visitKnownRecord(CVSymbol &CVR, Name &Record) override;
|
||||
#define SYMBOL_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
|
||||
#include "llvm/DebugInfo/CodeView/CVSymbolTypes.def"
|
||||
#include "llvm/DebugInfo/CodeView/CodeViewSymbols.def"
|
||||
|
||||
Error visitSymbolBegin(CVSymbol &Record) override;
|
||||
Error visitSymbolEnd(CVSymbol &Record) override;
|
||||
|
@ -26,7 +26,7 @@ using namespace llvm::codeview;
|
||||
|
||||
static const EnumEntry<TypeLeafKind> LeafTypeNames[] = {
|
||||
#define CV_TYPE(enum, val) {#enum, enum},
|
||||
#include "llvm/DebugInfo/CodeView/TypeRecords.def"
|
||||
#include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
|
||||
};
|
||||
|
||||
#define ENUM_ENTRY(enum_class, enum) \
|
||||
@ -155,7 +155,7 @@ static StringRef getLeafTypeName(TypeLeafKind LT) {
|
||||
#define TYPE_RECORD(ename, value, name) \
|
||||
case ename: \
|
||||
return #name;
|
||||
#include "llvm/DebugInfo/CodeView/TypeRecords.def"
|
||||
#include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -84,8 +84,12 @@ static void dumpAccelSection(raw_ostream &OS, StringRef Name,
|
||||
Accel.dump(OS);
|
||||
}
|
||||
|
||||
void DWARFContext::dump(raw_ostream &OS, DIDumpType DumpType, bool DumpEH,
|
||||
bool SummarizeTypes) {
|
||||
void DWARFContext::dump(raw_ostream &OS, DIDumpOptions DumpOpts){
|
||||
|
||||
DIDumpType DumpType = DumpOpts.DumpType;
|
||||
bool DumpEH = DumpOpts.DumpEH;
|
||||
bool SummarizeTypes = DumpOpts.SummarizeTypes;
|
||||
|
||||
if (DumpType == DIDT_All || DumpType == DIDT_Abbrev) {
|
||||
OS << ".debug_abbrev contents:\n";
|
||||
getDebugAbbrev()->dump(OS);
|
||||
|
@ -79,6 +79,7 @@ Error InfoStream::reload() {
|
||||
break;
|
||||
case uint32_t(PdbRaw_FeatureSig::MinimalDebugInfo):
|
||||
Features |= PdbFeatureMinimalDebugInfo;
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
@ -29,8 +29,7 @@ PDBContext::PDBContext(const COFFObjectFile &Object,
|
||||
Session->setLoadAddress(ImageBase.get());
|
||||
}
|
||||
|
||||
void PDBContext::dump(raw_ostream &OS, DIDumpType DumpType, bool DumpEH,
|
||||
bool SummarizeTypes) {}
|
||||
void PDBContext::dump(raw_ostream &OS, DIDumpOptions DumpOpts){}
|
||||
|
||||
DILineInfo PDBContext::getLineInfoForAddress(uint64_t Address,
|
||||
DILineInfoSpecifier Specifier) {
|
||||
|
@ -4,11 +4,11 @@ RUN: sancov -covered-functions LLVMFuzzer-NullDerefTest* %t_workdir/*.sancov | F
|
||||
RUN: env ASAN_OPTIONS=coverage_dir='"%t_workdir"' LLVMFuzzer-DSOTest -dump_coverage=1 -runs=0 2>&1 | FileCheck %s --check-prefix=DSO
|
||||
RUN: env ASAN_OPTIONS=coverage_dir='"%t_workdir"' not LLVMFuzzer-NullDerefTest -dump_coverage=0 2>&1 | FileCheck %s --check-prefix=NOCOV
|
||||
|
||||
CHECK: SanitizerCoverage: {{.*}}LLVMFuzzer-NullDerefTest.{{.*}}.sancov {{.*}} PCs written
|
||||
CHECK: SanitizerCoverage: {{.*}}LLVMFuzzer-NullDerefTest.{{.*}}.sancov: {{.*}} PCs written
|
||||
SANCOV: LLVMFuzzerTestOneInput
|
||||
|
||||
DSO: SanitizerCoverage: {{.*}}LLVMFuzzer-DSOTest.{{.*}}.sancov {{.*}} PCs written
|
||||
DSO-DAG: SanitizerCoverage: {{.*}}LLVMFuzzer-DSO1.{{.*}}.sancov {{.*}} PCs written
|
||||
DSO-DAG: SanitizerCoverage: {{.*}}LLVMFuzzer-DSO2.{{.*}}.sancov {{.*}} PCs written
|
||||
DSO: SanitizerCoverage: {{.*}}LLVMFuzzer-DSOTest.{{.*}}.sancov: {{.*}} PCs written
|
||||
DSO-DAG: SanitizerCoverage: {{.*}}LLVMFuzzer-DSO1.{{.*}}.sancov: {{.*}} PCs written
|
||||
DSO-DAG: SanitizerCoverage: {{.*}}LLVMFuzzer-DSO2.{{.*}}.sancov: {{.*}} PCs written
|
||||
|
||||
NOCOV-NOT: SanitizerCoverage: {{.*}} PCs written
|
||||
|
@ -1006,6 +1006,10 @@ AttributeList AttributeList::get(LLVMContext &C,
|
||||
for (AttributeList List : Attrs)
|
||||
MaxSize = std::max(MaxSize, List.getNumAttrSets());
|
||||
|
||||
// If every list was empty, there is no point in merging the lists.
|
||||
if (MaxSize == 0)
|
||||
return AttributeList();
|
||||
|
||||
SmallVector<AttributeSet, 8> NewAttrSets(MaxSize);
|
||||
for (unsigned I = 0; I < MaxSize; ++I) {
|
||||
AttrBuilder CurBuilder;
|
||||
@ -1033,24 +1037,11 @@ AttributeList AttributeList::addAttribute(LLVMContext &C, unsigned Index,
|
||||
return addAttributes(C, Index, B);
|
||||
}
|
||||
|
||||
AttributeList AttributeList::addAttribute(LLVMContext &C,
|
||||
ArrayRef<unsigned> Indices,
|
||||
AttributeList AttributeList::addAttribute(LLVMContext &C, unsigned Index,
|
||||
Attribute A) const {
|
||||
assert(std::is_sorted(Indices.begin(), Indices.end()));
|
||||
|
||||
SmallVector<AttributeSet, 4> AttrSets(this->begin(), this->end());
|
||||
unsigned MaxIndex = attrIdxToArrayIdx(Indices.back());
|
||||
if (MaxIndex >= AttrSets.size())
|
||||
AttrSets.resize(MaxIndex + 1);
|
||||
|
||||
for (unsigned Index : Indices) {
|
||||
Index = attrIdxToArrayIdx(Index);
|
||||
AttrBuilder B(AttrSets[Index]);
|
||||
B.addAttribute(A);
|
||||
AttrSets[Index] = AttributeSet::get(C, B);
|
||||
}
|
||||
|
||||
return getImpl(C, AttrSets);
|
||||
AttrBuilder B;
|
||||
B.addAttribute(A);
|
||||
return addAttributes(C, Index, B);
|
||||
}
|
||||
|
||||
AttributeList AttributeList::addAttributes(LLVMContext &C, unsigned Index,
|
||||
@ -1082,6 +1073,26 @@ AttributeList AttributeList::addAttributes(LLVMContext &C, unsigned Index,
|
||||
return getImpl(C, AttrSets);
|
||||
}
|
||||
|
||||
AttributeList AttributeList::addParamAttribute(LLVMContext &C,
|
||||
ArrayRef<unsigned> ArgNos,
|
||||
Attribute A) const {
|
||||
assert(std::is_sorted(ArgNos.begin(), ArgNos.end()));
|
||||
|
||||
SmallVector<AttributeSet, 4> AttrSets(this->begin(), this->end());
|
||||
unsigned MaxIndex = attrIdxToArrayIdx(ArgNos.back() + FirstArgIndex);
|
||||
if (MaxIndex >= AttrSets.size())
|
||||
AttrSets.resize(MaxIndex + 1);
|
||||
|
||||
for (unsigned ArgNo : ArgNos) {
|
||||
unsigned Index = attrIdxToArrayIdx(ArgNo + FirstArgIndex);
|
||||
AttrBuilder B(AttrSets[Index]);
|
||||
B.addAttribute(A);
|
||||
AttrSets[Index] = AttributeSet::get(C, B);
|
||||
}
|
||||
|
||||
return getImpl(C, AttrSets);
|
||||
}
|
||||
|
||||
AttributeList AttributeList::removeAttribute(LLVMContext &C, unsigned Index,
|
||||
Attribute::AttrKind Kind) const {
|
||||
if (!hasAttribute(Index, Kind)) return *this;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user