Merge llvm trunk r321414 to contrib/llvm.
This commit is contained in:
commit
ca8935c57d
@ -757,17 +757,17 @@ extern void thinlto_codegen_add_cross_referenced_symbol(thinlto_code_gen_t cg,
|
||||
* @ingroup LLVMCTLTO
|
||||
*
|
||||
* These entry points control the ThinLTO cache. The cache is intended to
|
||||
* support incremental build, and thus needs to be persistent accross build.
|
||||
* The client enabled the cache by supplying a path to an existing directory.
|
||||
* support incremental builds, and thus needs to be persistent across builds.
|
||||
* The client enables the cache by supplying a path to an existing directory.
|
||||
* The code generator will use this to store objects files that may be reused
|
||||
* during a subsequent build.
|
||||
* To avoid filling the disk space, a few knobs are provided:
|
||||
* - The pruning interval limit the frequency at which the garbage collector
|
||||
* will try to scan the cache directory to prune it from expired entries.
|
||||
* Setting to -1 disable the pruning (default).
|
||||
* - The pruning interval limits the frequency at which the garbage collector
|
||||
* will try to scan the cache directory to prune expired entries.
|
||||
* Setting to a negative number disables the pruning.
|
||||
* - The pruning expiration time indicates to the garbage collector how old an
|
||||
* entry needs to be to be removed.
|
||||
* - Finally, the garbage collector can be instructed to prune the cache till
|
||||
* - Finally, the garbage collector can be instructed to prune the cache until
|
||||
* the occupied space goes below a threshold.
|
||||
* @{
|
||||
*/
|
||||
@ -782,7 +782,7 @@ extern void thinlto_codegen_set_cache_dir(thinlto_code_gen_t cg,
|
||||
const char *cache_dir);
|
||||
|
||||
/**
|
||||
* Sets the cache pruning interval (in seconds). A negative value disable the
|
||||
* Sets the cache pruning interval (in seconds). A negative value disables the
|
||||
* pruning. An unspecified default value will be applied, and a value of 0 will
|
||||
* be ignored.
|
||||
*
|
||||
|
@ -95,46 +95,81 @@ enum AliasResult {
|
||||
///
|
||||
/// This is no access at all, a modification, a reference, or both
|
||||
/// a modification and a reference. These are specifically structured such that
|
||||
/// they form a two bit matrix and bit-tests for 'mod' or 'ref'
|
||||
/// they form a three bit matrix and bit-tests for 'mod' or 'ref' or 'must'
|
||||
/// work with any of the possible values.
|
||||
|
||||
enum class ModRefInfo {
|
||||
/// Must is provided for completeness, but no routines will return only
|
||||
/// Must today. See definition of Must below.
|
||||
Must = 0,
|
||||
/// The access may reference the value stored in memory,
|
||||
/// a mustAlias relation was found, and no mayAlias or partialAlias found.
|
||||
MustRef = 1,
|
||||
/// The access may modify the value stored in memory,
|
||||
/// a mustAlias relation was found, and no mayAlias or partialAlias found.
|
||||
MustMod = 2,
|
||||
/// The access may reference, modify or both the value stored in memory,
|
||||
/// a mustAlias relation was found, and no mayAlias or partialAlias found.
|
||||
MustModRef = MustRef | MustMod,
|
||||
/// The access neither references nor modifies the value stored in memory.
|
||||
NoModRef = 0,
|
||||
NoModRef = 4,
|
||||
/// The access may reference the value stored in memory.
|
||||
Ref = 1,
|
||||
Ref = NoModRef | MustRef,
|
||||
/// The access may modify the value stored in memory.
|
||||
Mod = 2,
|
||||
Mod = NoModRef | MustMod,
|
||||
/// The access may reference and may modify the value stored in memory.
|
||||
ModRef = Ref | Mod,
|
||||
|
||||
/// About Must:
|
||||
/// Must is set in a best effort manner.
|
||||
/// We usually do not try our best to infer Must, instead it is merely
|
||||
/// another piece of "free" information that is presented when available.
|
||||
/// Must set means there was certainly a MustAlias found. For calls,
|
||||
/// where multiple arguments are checked (argmemonly), this translates to
|
||||
/// only MustAlias or NoAlias was found.
|
||||
/// Must is not set for RAR accesses, even if the two locations must
|
||||
/// alias. The reason is that two read accesses translate to an early return
|
||||
/// of NoModRef. An additional alias check to set Must may be
|
||||
/// expensive. Other cases may also not set Must(e.g. callCapturesBefore).
|
||||
/// We refer to Must being *set* when the most significant bit is *cleared*.
|
||||
/// Conversely we *clear* Must information by *setting* the Must bit to 1.
|
||||
};
|
||||
|
||||
LLVM_NODISCARD inline bool isNoModRef(const ModRefInfo MRI) {
|
||||
return MRI == ModRefInfo::NoModRef;
|
||||
return (static_cast<int>(MRI) & static_cast<int>(ModRefInfo::MustModRef)) ==
|
||||
static_cast<int>(ModRefInfo::Must);
|
||||
}
|
||||
LLVM_NODISCARD inline bool isModOrRefSet(const ModRefInfo MRI) {
|
||||
return static_cast<int>(MRI) & static_cast<int>(ModRefInfo::ModRef);
|
||||
return static_cast<int>(MRI) & static_cast<int>(ModRefInfo::MustModRef);
|
||||
}
|
||||
LLVM_NODISCARD inline bool isModAndRefSet(const ModRefInfo MRI) {
|
||||
return (static_cast<int>(MRI) & static_cast<int>(ModRefInfo::ModRef)) ==
|
||||
static_cast<int>(ModRefInfo::ModRef);
|
||||
return (static_cast<int>(MRI) & static_cast<int>(ModRefInfo::MustModRef)) ==
|
||||
static_cast<int>(ModRefInfo::MustModRef);
|
||||
}
|
||||
LLVM_NODISCARD inline bool isModSet(const ModRefInfo MRI) {
|
||||
return static_cast<int>(MRI) & static_cast<int>(ModRefInfo::Mod);
|
||||
return static_cast<int>(MRI) & static_cast<int>(ModRefInfo::MustMod);
|
||||
}
|
||||
LLVM_NODISCARD inline bool isRefSet(const ModRefInfo MRI) {
|
||||
return static_cast<int>(MRI) & static_cast<int>(ModRefInfo::Ref);
|
||||
return static_cast<int>(MRI) & static_cast<int>(ModRefInfo::MustRef);
|
||||
}
|
||||
LLVM_NODISCARD inline bool isMustSet(const ModRefInfo MRI) {
|
||||
return !(static_cast<int>(MRI) & static_cast<int>(ModRefInfo::NoModRef));
|
||||
}
|
||||
|
||||
LLVM_NODISCARD inline ModRefInfo setMod(const ModRefInfo MRI) {
|
||||
return ModRefInfo(static_cast<int>(MRI) | static_cast<int>(ModRefInfo::Mod));
|
||||
return ModRefInfo(static_cast<int>(MRI) |
|
||||
static_cast<int>(ModRefInfo::MustMod));
|
||||
}
|
||||
LLVM_NODISCARD inline ModRefInfo setRef(const ModRefInfo MRI) {
|
||||
return ModRefInfo(static_cast<int>(MRI) | static_cast<int>(ModRefInfo::Ref));
|
||||
return ModRefInfo(static_cast<int>(MRI) |
|
||||
static_cast<int>(ModRefInfo::MustRef));
|
||||
}
|
||||
LLVM_NODISCARD inline ModRefInfo setMust(const ModRefInfo MRI) {
|
||||
return ModRefInfo(static_cast<int>(MRI) &
|
||||
static_cast<int>(ModRefInfo::MustModRef));
|
||||
}
|
||||
LLVM_NODISCARD inline ModRefInfo setModAndRef(const ModRefInfo MRI) {
|
||||
return ModRefInfo(static_cast<int>(MRI) |
|
||||
static_cast<int>(ModRefInfo::ModRef));
|
||||
static_cast<int>(ModRefInfo::MustModRef));
|
||||
}
|
||||
LLVM_NODISCARD inline ModRefInfo clearMod(const ModRefInfo MRI) {
|
||||
return ModRefInfo(static_cast<int>(MRI) & static_cast<int>(ModRefInfo::Ref));
|
||||
@ -142,6 +177,10 @@ LLVM_NODISCARD inline ModRefInfo clearMod(const ModRefInfo MRI) {
|
||||
LLVM_NODISCARD inline ModRefInfo clearRef(const ModRefInfo MRI) {
|
||||
return ModRefInfo(static_cast<int>(MRI) & static_cast<int>(ModRefInfo::Mod));
|
||||
}
|
||||
LLVM_NODISCARD inline ModRefInfo clearMust(const ModRefInfo MRI) {
|
||||
return ModRefInfo(static_cast<int>(MRI) |
|
||||
static_cast<int>(ModRefInfo::NoModRef));
|
||||
}
|
||||
LLVM_NODISCARD inline ModRefInfo unionModRef(const ModRefInfo MRI1,
|
||||
const ModRefInfo MRI2) {
|
||||
return ModRefInfo(static_cast<int>(MRI1) | static_cast<int>(MRI2));
|
||||
@ -160,11 +199,11 @@ enum FunctionModRefLocation {
|
||||
/// Base case is no access to memory.
|
||||
FMRL_Nowhere = 0,
|
||||
/// Access to memory via argument pointers.
|
||||
FMRL_ArgumentPointees = 4,
|
||||
FMRL_ArgumentPointees = 8,
|
||||
/// Memory that is inaccessible via LLVM IR.
|
||||
FMRL_InaccessibleMem = 8,
|
||||
FMRL_InaccessibleMem = 16,
|
||||
/// Access to any memory.
|
||||
FMRL_Anywhere = 16 | FMRL_InaccessibleMem | FMRL_ArgumentPointees
|
||||
FMRL_Anywhere = 32 | FMRL_InaccessibleMem | FMRL_ArgumentPointees
|
||||
};
|
||||
|
||||
/// Summary of how a function affects memory in the program.
|
||||
@ -344,7 +383,7 @@ class AAResults {
|
||||
/// result's bits are set to indicate the allowed aliasing ModRef kinds. Note
|
||||
/// that these bits do not necessarily account for the overall behavior of
|
||||
/// the function, but rather only provide additional per-argument
|
||||
/// information.
|
||||
/// information. This never sets ModRefInfo::Must.
|
||||
ModRefInfo getArgModRefInfo(ImmutableCallSite CS, unsigned ArgIdx);
|
||||
|
||||
/// Return the behavior of the given call site.
|
||||
@ -624,6 +663,8 @@ class AAResults {
|
||||
/// or reads the specified memory location \p MemLoc before instruction \p I
|
||||
/// in a BasicBlock. An ordered basic block \p OBB can be used to speed up
|
||||
/// instruction ordering queries inside the BasicBlock containing \p I.
|
||||
/// Early exits in callCapturesBefore may lead to ModRefInfo::Must not being
|
||||
/// set.
|
||||
ModRefInfo callCapturesBefore(const Instruction *I,
|
||||
const MemoryLocation &MemLoc, DominatorTree *DT,
|
||||
OrderedBasicBlock *OBB = nullptr);
|
||||
|
@ -35,19 +35,23 @@ class AAEvaluator : public PassInfoMixin<AAEvaluator> {
|
||||
int64_t FunctionCount;
|
||||
int64_t NoAliasCount, MayAliasCount, PartialAliasCount, MustAliasCount;
|
||||
int64_t NoModRefCount, ModCount, RefCount, ModRefCount;
|
||||
int64_t MustCount, MustRefCount, MustModCount, MustModRefCount;
|
||||
|
||||
public:
|
||||
AAEvaluator()
|
||||
: FunctionCount(), NoAliasCount(), MayAliasCount(), PartialAliasCount(),
|
||||
MustAliasCount(), NoModRefCount(), ModCount(), RefCount(),
|
||||
ModRefCount() {}
|
||||
ModRefCount(), MustCount(), MustRefCount(), MustModCount(),
|
||||
MustModRefCount() {}
|
||||
AAEvaluator(AAEvaluator &&Arg)
|
||||
: FunctionCount(Arg.FunctionCount), NoAliasCount(Arg.NoAliasCount),
|
||||
MayAliasCount(Arg.MayAliasCount),
|
||||
PartialAliasCount(Arg.PartialAliasCount),
|
||||
MustAliasCount(Arg.MustAliasCount), NoModRefCount(Arg.NoModRefCount),
|
||||
ModCount(Arg.ModCount), RefCount(Arg.RefCount),
|
||||
ModRefCount(Arg.ModRefCount) {
|
||||
ModRefCount(Arg.ModRefCount), MustCount(Arg.MustCount),
|
||||
MustRefCount(Arg.MustRefCount), MustModCount(Arg.MustModCount),
|
||||
MustModRefCount(Arg.MustModRefCount) {
|
||||
Arg.FunctionCount = 0;
|
||||
}
|
||||
~AAEvaluator();
|
||||
|
@ -667,21 +667,6 @@ int64_t getPtrStride(PredicatedScalarEvolution &PSE, Value *Ptr, const Loop *Lp,
|
||||
const ValueToValueMap &StridesMap = ValueToValueMap(),
|
||||
bool Assume = false, bool ShouldCheckWrap = true);
|
||||
|
||||
/// \brief Attempt to sort the 'loads' in \p VL and return the sorted values in
|
||||
/// \p Sorted.
|
||||
///
|
||||
/// Returns 'false' if sorting is not legal or feasible, otherwise returns
|
||||
/// 'true'. If \p Mask is not null, it also returns the \p Mask which is the
|
||||
/// shuffle mask for actual memory access order.
|
||||
///
|
||||
/// For example, for a given VL of memory accesses in program order, a[i+2],
|
||||
/// a[i+0], a[i+1] and a[i+3], this function will sort the VL and save the
|
||||
/// sorted value in 'Sorted' as a[i+0], a[i+1], a[i+2], a[i+3] and saves the
|
||||
/// mask for actual memory accesses in program order in 'Mask' as <2,0,1,3>
|
||||
bool sortLoadAccesses(ArrayRef<Value *> VL, const DataLayout &DL,
|
||||
ScalarEvolution &SE, SmallVectorImpl<Value *> &Sorted,
|
||||
SmallVectorImpl<unsigned> *Mask = nullptr);
|
||||
|
||||
/// \brief Returns true if the memory operations \p A and \p B are consecutive.
|
||||
/// This is a simple API that does not depend on the analysis pass.
|
||||
bool isConsecutiveAccess(Value *A, Value *B, const DataLayout &DL,
|
||||
|
@ -407,6 +407,12 @@ class MemoryDependenceResults {
|
||||
void getNonLocalPointerDependency(Instruction *QueryInst,
|
||||
SmallVectorImpl<NonLocalDepResult> &Result);
|
||||
|
||||
/// Perform a dependency query specifically for QueryInst's access to Loc.
|
||||
/// The other comments for getNonLocalPointerDependency apply here as well.
|
||||
void getNonLocalPointerDependencyFrom(Instruction *QueryInst,
|
||||
const MemoryLocation &Loc, bool isLoad,
|
||||
SmallVectorImpl<NonLocalDepResult> &Result);
|
||||
|
||||
/// Removes an instruction from the dependence analysis, updating the
|
||||
/// dependence of instructions that previously depended on it.
|
||||
void removeInstruction(Instruction *InstToRemove);
|
||||
|
@ -92,12 +92,12 @@ class ProfileSummaryInfo {
|
||||
bool hasHugeWorkingSetSize();
|
||||
/// \brief Returns true if \p F has hot function entry.
|
||||
bool isFunctionEntryHot(const Function *F);
|
||||
/// Returns true if \p F has hot function entry or hot call edge.
|
||||
bool isFunctionHotInCallGraph(const Function *F);
|
||||
/// Returns true if \p F contains hot code.
|
||||
bool isFunctionHotInCallGraph(const Function *F, BlockFrequencyInfo &BFI);
|
||||
/// \brief Returns true if \p F has cold function entry.
|
||||
bool isFunctionEntryCold(const Function *F);
|
||||
/// Returns true if \p F has cold function entry or cold call edge.
|
||||
bool isFunctionColdInCallGraph(const Function *F);
|
||||
/// Returns true if \p F contains only cold code.
|
||||
bool isFunctionColdInCallGraph(const Function *F, BlockFrequencyInfo &BFI);
|
||||
/// \brief Returns true if \p F is a hot function.
|
||||
bool isHotCount(uint64_t C);
|
||||
/// \brief Returns true if count \p C is considered cold.
|
||||
|
@ -47,7 +47,7 @@ namespace llvm {
|
||||
ScalarEvolution &SE;
|
||||
const DataLayout &DL;
|
||||
|
||||
// New instructions receive a name to identifies them with the current pass.
|
||||
// New instructions receive a name to identify them with the current pass.
|
||||
const char* IVName;
|
||||
|
||||
// InsertedExpressions caches Values for reuse, so must track RAUW.
|
||||
|
@ -646,6 +646,9 @@ class TargetTransformInfo {
|
||||
/// \brief Additional properties of an operand's values.
|
||||
enum OperandValueProperties { OP_None = 0, OP_PowerOf2 = 1 };
|
||||
|
||||
/// \return True if target can execute instructions out of order.
|
||||
bool isOutOfOrder() const;
|
||||
|
||||
/// \return The number of scalar or vector registers that the target has.
|
||||
/// If 'Vectors' is true, it returns the number of vector registers. If it is
|
||||
/// set to false, it returns the number of scalar registers.
|
||||
@ -1018,6 +1021,7 @@ class TargetTransformInfo::Concept {
|
||||
Type *Ty) = 0;
|
||||
virtual int getIntImmCost(Intrinsic::ID IID, unsigned Idx, const APInt &Imm,
|
||||
Type *Ty) = 0;
|
||||
virtual bool isOutOfOrder() const = 0;
|
||||
virtual unsigned getNumberOfRegisters(bool Vector) = 0;
|
||||
virtual unsigned getRegisterBitWidth(bool Vector) const = 0;
|
||||
virtual unsigned getMinVectorRegisterBitWidth() = 0;
|
||||
@ -1295,6 +1299,9 @@ class TargetTransformInfo::Model final : public TargetTransformInfo::Concept {
|
||||
Type *Ty) override {
|
||||
return Impl.getIntImmCost(IID, Idx, Imm, Ty);
|
||||
}
|
||||
bool isOutOfOrder() const override {
|
||||
return Impl.isOutOfOrder();
|
||||
}
|
||||
unsigned getNumberOfRegisters(bool Vector) override {
|
||||
return Impl.getNumberOfRegisters(Vector);
|
||||
}
|
||||
|
@ -337,6 +337,8 @@ class TargetTransformInfoImplBase {
|
||||
return TTI::TCC_Free;
|
||||
}
|
||||
|
||||
bool isOutOfOrder() const { return false; }
|
||||
|
||||
unsigned getNumberOfRegisters(bool Vector) { return 8; }
|
||||
|
||||
unsigned getRegisterBitWidth(bool Vector) const { return 32; }
|
||||
|
@ -208,7 +208,7 @@ const unsigned WASM_SYMBOL_VISIBILITY_HIDDEN = 0x4;
|
||||
#define WASM_RELOC(name, value) name = value,
|
||||
|
||||
enum : unsigned {
|
||||
#include "WasmRelocs/WebAssembly.def"
|
||||
#include "WasmRelocs.def"
|
||||
};
|
||||
|
||||
#undef WASM_RELOC
|
||||
|
@ -302,9 +302,13 @@ class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase<T> {
|
||||
}
|
||||
|
||||
unsigned getFPOpCost(Type *Ty) {
|
||||
// By default, FP instructions are no more expensive since they are
|
||||
// implemented in HW. Target specific TTI can override this.
|
||||
return TargetTransformInfo::TCC_Basic;
|
||||
// Check whether FADD is available, as a proxy for floating-point in
|
||||
// general.
|
||||
const TargetLoweringBase *TLI = getTLI();
|
||||
EVT VT = TLI->getValueType(DL, Ty);
|
||||
if (TLI->isOperationLegalOrCustomOrPromote(ISD::FADD, VT))
|
||||
return TargetTransformInfo::TCC_Basic;
|
||||
return TargetTransformInfo::TCC_Expensive;
|
||||
}
|
||||
|
||||
unsigned getOperationCost(unsigned Opcode, Type *Ty, Type *OpTy) {
|
||||
@ -398,6 +402,10 @@ class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase<T> {
|
||||
return BaseT::getInstructionLatency(I);
|
||||
}
|
||||
|
||||
bool isOutOfOrder() const {
|
||||
return getST()->getSchedModel().isOutOfOrder();
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
/// \name Vector TTI Implementations
|
||||
|
@ -282,10 +282,6 @@ enum {
|
||||
/// Provides the logic to select generic machine instructions.
|
||||
class InstructionSelector {
|
||||
public:
|
||||
using I64ImmediatePredicateFn = bool (*)(int64_t);
|
||||
using APIntImmediatePredicateFn = bool (*)(const APInt &);
|
||||
using APFloatImmediatePredicateFn = bool (*)(const APFloat &);
|
||||
|
||||
virtual ~InstructionSelector() = default;
|
||||
|
||||
/// Select the (possibly generic) instruction \p I to only use target-specific
|
||||
@ -319,9 +315,6 @@ class InstructionSelector {
|
||||
struct MatcherInfoTy {
|
||||
const LLT *TypeObjects;
|
||||
const PredicateBitset *FeatureBitsets;
|
||||
const I64ImmediatePredicateFn *I64ImmPredicateFns;
|
||||
const APIntImmediatePredicateFn *APIntImmPredicateFns;
|
||||
const APFloatImmediatePredicateFn *APFloatImmPredicateFns;
|
||||
const ComplexMatcherMemFn *ComplexPredicates;
|
||||
};
|
||||
|
||||
@ -340,6 +333,16 @@ class InstructionSelector {
|
||||
const RegisterBankInfo &RBI, const PredicateBitset &AvailableFeatures,
|
||||
CodeGenCoverage &CoverageInfo) const;
|
||||
|
||||
virtual bool testImmPredicate_I64(unsigned, int64_t) const {
|
||||
llvm_unreachable("Subclasses must override this to use tablegen");
|
||||
}
|
||||
virtual bool testImmPredicate_APInt(unsigned, const APInt &) const {
|
||||
llvm_unreachable("Subclasses must override this to use tablegen");
|
||||
}
|
||||
virtual bool testImmPredicate_APFloat(unsigned, const APFloat &) const {
|
||||
llvm_unreachable("Subclasses must override this to use tablegen");
|
||||
}
|
||||
|
||||
/// Constrain a register operand of an instruction \p I to a specified
|
||||
/// register class. This could involve inserting COPYs before (for uses) or
|
||||
/// after (for defs) and may replace the operand of \p I.
|
||||
|
@ -181,7 +181,7 @@ bool InstructionSelector::executeMatchTable(
|
||||
else
|
||||
llvm_unreachable("Expected Imm or CImm operand");
|
||||
|
||||
if (!MatcherInfo.I64ImmPredicateFns[Predicate](Value))
|
||||
if (!testImmPredicate_I64(Predicate, Value))
|
||||
if (handleReject() == RejectAndGiveUp)
|
||||
return false;
|
||||
break;
|
||||
@ -202,7 +202,7 @@ bool InstructionSelector::executeMatchTable(
|
||||
else
|
||||
llvm_unreachable("Expected Imm or CImm operand");
|
||||
|
||||
if (!MatcherInfo.APIntImmPredicateFns[Predicate](Value))
|
||||
if (!testImmPredicate_APInt(Predicate, Value))
|
||||
if (handleReject() == RejectAndGiveUp)
|
||||
return false;
|
||||
break;
|
||||
@ -221,7 +221,7 @@ bool InstructionSelector::executeMatchTable(
|
||||
assert(Predicate > GIPFP_APFloat_Invalid && "Expected a valid predicate");
|
||||
APFloat Value = State.MIs[InsnID]->getOperand(1).getFPImm()->getValueAPF();
|
||||
|
||||
if (!MatcherInfo.APFloatImmPredicateFns[Predicate](Value))
|
||||
if (!testImmPredicate_APFloat(Predicate, Value))
|
||||
if (handleReject() == RejectAndGiveUp)
|
||||
return false;
|
||||
break;
|
||||
|
@ -1,4 +1,4 @@
|
||||
//===- LiveStackAnalysis.h - Live Stack Slot Analysis -----------*- C++ -*-===//
|
||||
//===- LiveStacks.h - Live Stack Slot Analysis ------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -13,8 +13,8 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_LIVESTACKANALYSIS_H
|
||||
#define LLVM_CODEGEN_LIVESTACKANALYSIS_H
|
||||
#ifndef LLVM_CODEGEN_LIVESTACKS_H
|
||||
#define LLVM_CODEGEN_LIVESTACKS_H
|
||||
|
||||
#include "llvm/CodeGen/LiveInterval.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
@ -100,4 +100,4 @@ class LiveStacks : public MachineFunctionPass {
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_LIVESTACK_ANALYSIS_H
|
||||
#endif
|
@ -29,6 +29,7 @@ class GlobalValue;
|
||||
class MachineBasicBlock;
|
||||
class MachineInstr;
|
||||
class MachineRegisterInfo;
|
||||
class MCCFIInstruction;
|
||||
class MDNode;
|
||||
class ModuleSlotTracker;
|
||||
class TargetMachine;
|
||||
@ -250,6 +251,12 @@ class MachineOperand {
|
||||
static void printStackObjectReference(raw_ostream &OS, unsigned FrameIndex,
|
||||
bool IsFixed, StringRef Name);
|
||||
|
||||
/// Print the offset with explicit +/- signs.
|
||||
static void printOperandOffset(raw_ostream &OS, int64_t Offset);
|
||||
|
||||
/// Print an IRSlotNumber.
|
||||
static void printIRSlotNumber(raw_ostream &OS, int Slot);
|
||||
|
||||
/// Print the MachineOperand to \p os.
|
||||
/// Providing a valid \p TRI and \p IntrinsicInfo results in a more
|
||||
/// target-specific printing. If \p TRI and \p IntrinsicInfo are null, the
|
||||
|
@ -165,6 +165,8 @@ HANDLE_LIBCALL(SINCOS_F64, nullptr)
|
||||
HANDLE_LIBCALL(SINCOS_F80, nullptr)
|
||||
HANDLE_LIBCALL(SINCOS_F128, nullptr)
|
||||
HANDLE_LIBCALL(SINCOS_PPCF128, nullptr)
|
||||
HANDLE_LIBCALL(SINCOS_STRET_F32, nullptr)
|
||||
HANDLE_LIBCALL(SINCOS_STRET_F64, nullptr)
|
||||
HANDLE_LIBCALL(POW_F32, "powf")
|
||||
HANDLE_LIBCALL(POW_F64, "pow")
|
||||
HANDLE_LIBCALL(POW_F80, "powl")
|
||||
@ -334,6 +336,7 @@ HANDLE_LIBCALL(O_PPCF128, "__gcc_qunord")
|
||||
HANDLE_LIBCALL(MEMCPY, "memcpy")
|
||||
HANDLE_LIBCALL(MEMMOVE, "memmove")
|
||||
HANDLE_LIBCALL(MEMSET, "memset")
|
||||
HANDLE_LIBCALL(BZERO, nullptr)
|
||||
|
||||
// Element-wise unordered-atomic memory of different sizes
|
||||
HANDLE_LIBCALL(MEMCPY_ELEMENT_UNORDERED_ATOMIC_1, "__llvm_memcpy_element_unordered_atomic_1")
|
||||
|
34
contrib/llvm/include/llvm/CodeGen/SDNodeProperties.td
Normal file
34
contrib/llvm/include/llvm/CodeGen/SDNodeProperties.td
Normal file
@ -0,0 +1,34 @@
|
||||
//===- SDNodeProperties.td - Common code for DAG isels ---*- tablegen -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
class SDNodeProperty;
|
||||
|
||||
// Selection DAG Pattern Operations
|
||||
class SDPatternOperator {
|
||||
list<SDNodeProperty> Properties = [];
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Selection DAG Node Properties.
|
||||
//
|
||||
// Note: These are hard coded into tblgen.
|
||||
//
|
||||
def SDNPCommutative : SDNodeProperty; // X op Y == Y op X
|
||||
def SDNPAssociative : SDNodeProperty; // (X op Y) op Z == X op (Y op Z)
|
||||
def SDNPHasChain : SDNodeProperty; // R/W chain operand and result
|
||||
def SDNPOutGlue : SDNodeProperty; // Write a flag result
|
||||
def SDNPInGlue : SDNodeProperty; // Read a flag operand
|
||||
def SDNPOptInGlue : SDNodeProperty; // Optionally read a flag operand
|
||||
def SDNPMayStore : SDNodeProperty; // May write to memory, sets 'mayStore'.
|
||||
def SDNPMayLoad : SDNodeProperty; // May read memory, sets 'mayLoad'.
|
||||
def SDNPSideEffect : SDNodeProperty; // Sets 'HasUnmodelledSideEffects'.
|
||||
def SDNPMemOperand : SDNodeProperty; // Touches memory, has assoc MemOperand
|
||||
def SDNPVariadic : SDNodeProperty; // Node has variable arguments.
|
||||
def SDNPWantRoot : SDNodeProperty; // ComplexPattern gets the root of match
|
||||
def SDNPWantParent : SDNodeProperty; // ComplexPattern gets the parent
|
@ -189,8 +189,8 @@ class SDValue {
|
||||
inline bool isUndef() const;
|
||||
inline unsigned getMachineOpcode() const;
|
||||
inline const DebugLoc &getDebugLoc() const;
|
||||
inline void dump() const;
|
||||
inline void dumpr() const;
|
||||
inline void dump(const SelectionDAG *G = nullptr) const;
|
||||
inline void dumpr(const SelectionDAG *G = nullptr) const;
|
||||
|
||||
/// Return true if this operand (which must be a chain) reaches the
|
||||
/// specified operand without crossing any side-effecting instructions.
|
||||
@ -1089,12 +1089,12 @@ inline const DebugLoc &SDValue::getDebugLoc() const {
|
||||
return Node->getDebugLoc();
|
||||
}
|
||||
|
||||
inline void SDValue::dump() const {
|
||||
return Node->dump();
|
||||
inline void SDValue::dump(const SelectionDAG *G) const {
|
||||
return Node->dump(G);
|
||||
}
|
||||
|
||||
inline void SDValue::dumpr() const {
|
||||
return Node->dumpr();
|
||||
inline void SDValue::dumpr(const SelectionDAG *G) const {
|
||||
return Node->dumpr(G);
|
||||
}
|
||||
|
||||
// Define inline functions from the SDUse class.
|
||||
|
@ -824,8 +824,8 @@ class TargetLoweringBase {
|
||||
/// also combined within this function. Currently, the minimum size check is
|
||||
/// performed in findJumpTable() in SelectionDAGBuiler and
|
||||
/// getEstimatedNumberOfCaseClusters() in BasicTTIImpl.
|
||||
bool isSuitableForJumpTable(const SwitchInst *SI, uint64_t NumCases,
|
||||
uint64_t Range) const {
|
||||
virtual bool isSuitableForJumpTable(const SwitchInst *SI, uint64_t NumCases,
|
||||
uint64_t Range) const {
|
||||
const bool OptForSize = SI->getParent()->getParent()->optForSize();
|
||||
const unsigned MinDensity = getMinimumJumpTableDensity(OptForSize);
|
||||
const unsigned MaxJumpTableSize =
|
||||
@ -1276,7 +1276,7 @@ class TargetLoweringBase {
|
||||
}
|
||||
|
||||
/// Return lower limit for number of blocks in a jump table.
|
||||
unsigned getMinimumJumpTableEntries() const;
|
||||
virtual unsigned getMinimumJumpTableEntries() const;
|
||||
|
||||
/// Return lower limit of the density in a jump table.
|
||||
unsigned getMinimumJumpTableDensity(bool OptForSize) const;
|
||||
@ -2429,7 +2429,7 @@ class TargetLoweringBase {
|
||||
PromoteToType;
|
||||
|
||||
/// Stores the name each libcall.
|
||||
const char *LibcallRoutineNames[RTLIB::UNKNOWN_LIBCALL];
|
||||
const char *LibcallRoutineNames[RTLIB::UNKNOWN_LIBCALL + 1];
|
||||
|
||||
/// The ISD::CondCode that should be used to test the result of each of the
|
||||
/// comparison libcall against zero.
|
||||
@ -2438,6 +2438,9 @@ class TargetLoweringBase {
|
||||
/// Stores the CallingConv that should be used for each libcall.
|
||||
CallingConv::ID LibcallCallingConvs[RTLIB::UNKNOWN_LIBCALL];
|
||||
|
||||
/// Set default libcall names and calling conventions.
|
||||
void InitLibcalls(const Triple &TT);
|
||||
|
||||
protected:
|
||||
/// Return true if the extension represented by \p I is free.
|
||||
/// \pre \p I is a sign, zero, or fp extension and
|
||||
|
@ -165,6 +165,29 @@ struct BaseAddress {
|
||||
uint64_t SectionIndex;
|
||||
};
|
||||
|
||||
/// Represents a unit's contribution to the string offsets table.
|
||||
struct StrOffsetsContributionDescriptor {
|
||||
uint64_t Base = 0;
|
||||
uint64_t Size = 0;
|
||||
/// Format and version.
|
||||
DWARFFormParams FormParams = {0, 0, dwarf::DwarfFormat::DWARF32};
|
||||
|
||||
StrOffsetsContributionDescriptor(uint64_t Base, uint64_t Size,
|
||||
uint8_t Version, dwarf::DwarfFormat Format)
|
||||
: Base(Base), Size(Size), FormParams({Version, 0, Format}) {}
|
||||
|
||||
uint8_t getVersion() const { return FormParams.Version; }
|
||||
dwarf::DwarfFormat getFormat() const { return FormParams.Format; }
|
||||
uint8_t getDwarfOffsetByteSize() const {
|
||||
return FormParams.getDwarfOffsetByteSize();
|
||||
}
|
||||
/// Determine whether a contribution to the string offsets table is
|
||||
/// consistent with the relevant section size and that its length is
|
||||
/// a multiple of the size of one of its entries.
|
||||
Optional<StrOffsetsContributionDescriptor>
|
||||
validateContributionSize(DWARFDataExtractor &DA);
|
||||
};
|
||||
|
||||
class DWARFUnit {
|
||||
DWARFContext &Context;
|
||||
/// Section containing this DWARFUnit.
|
||||
@ -176,7 +199,6 @@ class DWARFUnit {
|
||||
const DWARFSection &LineSection;
|
||||
StringRef StringSection;
|
||||
const DWARFSection &StringOffsetSection;
|
||||
uint64_t StringOffsetSectionBase = 0;
|
||||
const DWARFSection *AddrOffsetSection;
|
||||
uint32_t AddrOffsetSectionBase = 0;
|
||||
bool isLittleEndian;
|
||||
@ -185,6 +207,9 @@ class DWARFUnit {
|
||||
|
||||
// Version, address size, and DWARF format.
|
||||
DWARFFormParams FormParams;
|
||||
/// Start, length, and DWARF format of the unit's contribution to the string
|
||||
/// offsets table (DWARF v5).
|
||||
Optional<StrOffsetsContributionDescriptor> StringOffsetsTableContribution;
|
||||
|
||||
uint32_t Offset;
|
||||
uint32_t Length;
|
||||
@ -195,10 +220,40 @@ class DWARFUnit {
|
||||
/// The compile unit debug information entry items.
|
||||
std::vector<DWARFDebugInfoEntry> DieArray;
|
||||
|
||||
/// Map from range's start address to end address and corresponding DIE.
|
||||
/// IntervalMap does not support range removal, as a result, we use the
|
||||
/// std::map::upper_bound for address range lookup.
|
||||
std::map<uint64_t, std::pair<uint64_t, DWARFDie>> AddrDieMap;
|
||||
/// The vector of inlined subroutine DIEs that we can map directly to from
|
||||
/// their subprogram below.
|
||||
std::vector<DWARFDie> InlinedSubroutineDIEs;
|
||||
|
||||
/// A type representing a subprogram DIE and a map (built using a sorted
|
||||
/// vector) into that subprogram's inlined subroutine DIEs.
|
||||
struct SubprogramDIEAddrInfo {
|
||||
DWARFDie SubprogramDIE;
|
||||
|
||||
uint64_t SubprogramBasePC;
|
||||
|
||||
/// A vector sorted to allow mapping from a relative PC to the inlined
|
||||
/// subroutine DIE with the most specific address range covering that PC.
|
||||
///
|
||||
/// The PCs are relative to the `SubprogramBasePC`.
|
||||
///
|
||||
/// The vector is sorted in ascending order of the first int which
|
||||
/// represents the relative PC for an interval in the map. The second int
|
||||
/// represents the index into the `InlinedSubroutineDIEs` vector of the DIE
|
||||
/// that interval maps to. An index of '-1` indicates an empty mapping. The
|
||||
/// interval covered is from the `.first` relative PC to the next entry's
|
||||
/// `.first` relative PC.
|
||||
std::vector<std::pair<uint32_t, int32_t>> InlinedSubroutineDIEAddrMap;
|
||||
};
|
||||
|
||||
/// Vector of the subprogram DIEs and their subroutine address maps.
|
||||
std::vector<SubprogramDIEAddrInfo> SubprogramDIEAddrInfos;
|
||||
|
||||
/// A vector sorted to allow mapping from a PC to the subprogram DIE (and
|
||||
/// associated addr map) index. Subprograms with overlapping PC ranges aren't
|
||||
/// supported here. Nothing will crash, but the mapping may be inaccurate.
|
||||
/// This vector may also contain "empty" ranges marked by an address with
|
||||
/// a DIE index of '-1'.
|
||||
std::vector<std::pair<uint64_t, int64_t>> SubprogramDIEAddrMap;
|
||||
|
||||
using die_iterator_range =
|
||||
iterator_range<std::vector<DWARFDebugInfoEntry>::iterator>;
|
||||
@ -219,6 +274,21 @@ class DWARFUnit {
|
||||
/// Size in bytes of the unit header.
|
||||
virtual uint32_t getHeaderSize() const { return getVersion() <= 4 ? 11 : 12; }
|
||||
|
||||
/// Find the unit's contribution to the string offsets table and determine its
|
||||
/// length and form. The given offset is expected to be derived from the unit
|
||||
/// DIE's DW_AT_str_offsets_base attribute.
|
||||
Optional<StrOffsetsContributionDescriptor>
|
||||
determineStringOffsetsTableContribution(DWARFDataExtractor &DA,
|
||||
uint64_t Offset);
|
||||
|
||||
/// Find the unit's contribution to the string offsets table and determine its
|
||||
/// length and form. The given offset is expected to be 0 in a dwo file or,
|
||||
/// in a dwp file, the start of the unit's contribution to the string offsets
|
||||
/// table section (as determined by the index table).
|
||||
Optional<StrOffsetsContributionDescriptor>
|
||||
determineStringOffsetsTableContributionDWO(DWARFDataExtractor &DA,
|
||||
uint64_t Offset);
|
||||
|
||||
public:
|
||||
DWARFUnit(DWARFContext &Context, const DWARFSection &Section,
|
||||
const DWARFDebugAbbrev *DA, const DWARFSection *RS, StringRef SS,
|
||||
@ -242,9 +312,6 @@ class DWARFUnit {
|
||||
AddrOffsetSectionBase = Base;
|
||||
}
|
||||
|
||||
/// Recursively update address to Die map.
|
||||
void updateAddressDieMap(DWARFDie Die);
|
||||
|
||||
void setRangesSection(const DWARFSection *RS, uint32_t Base) {
|
||||
RangeSection = RS;
|
||||
RangeSectionBase = Base;
|
||||
@ -272,6 +339,10 @@ class DWARFUnit {
|
||||
uint32_t getNextUnitOffset() const { return Offset + Length + 4; }
|
||||
uint32_t getLength() const { return Length; }
|
||||
|
||||
const Optional<StrOffsetsContributionDescriptor> &
|
||||
getStringOffsetsTableContribution() const {
|
||||
return StringOffsetsTableContribution;
|
||||
}
|
||||
const DWARFFormParams &getFormParams() const { return FormParams; }
|
||||
uint16_t getVersion() const { return FormParams.Version; }
|
||||
dwarf::DwarfFormat getFormat() const { return FormParams.Format; }
|
||||
@ -281,6 +352,16 @@ class DWARFUnit {
|
||||
return FormParams.getDwarfOffsetByteSize();
|
||||
}
|
||||
|
||||
uint8_t getDwarfStringOffsetsByteSize() const {
|
||||
assert(StringOffsetsTableContribution);
|
||||
return StringOffsetsTableContribution->getDwarfOffsetByteSize();
|
||||
}
|
||||
|
||||
uint64_t getStringOffsetsBase() const {
|
||||
assert(StringOffsetsTableContribution);
|
||||
return StringOffsetsTableContribution->Base;
|
||||
}
|
||||
|
||||
const DWARFAbbreviationDeclarationSet *getAbbreviations() const;
|
||||
|
||||
uint8_t getUnitType() const { return UnitType; }
|
||||
@ -426,6 +507,9 @@ class DWARFUnit {
|
||||
/// parseDWO - Parses .dwo file for current compile unit. Returns true if
|
||||
/// it was actually constructed.
|
||||
bool parseDWO();
|
||||
|
||||
void buildSubprogramDIEAddrMap();
|
||||
void buildInlinedSubroutineDIEAddrMap(SubprogramDIEAddrInfo &SPInfo);
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
@ -16,6 +16,7 @@
|
||||
#ifndef LLVM_FUZZMUTATE_IRMUTATOR_H
|
||||
#define LLVM_FUZZMUTATE_IRMUTATOR_H
|
||||
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/FuzzMutate/OpDescriptor.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
|
||||
@ -74,7 +75,8 @@ class IRMutator {
|
||||
class InjectorIRStrategy : public IRMutationStrategy {
|
||||
std::vector<fuzzerop::OpDescriptor> Operations;
|
||||
|
||||
fuzzerop::OpDescriptor chooseOperation(Value *Src, RandomIRBuilder &IB);
|
||||
Optional<fuzzerop::OpDescriptor> chooseOperation(Value *Src,
|
||||
RandomIRBuilder &IB);
|
||||
|
||||
public:
|
||||
InjectorIRStrategy(std::vector<fuzzerop::OpDescriptor> &&Operations)
|
||||
|
@ -248,6 +248,12 @@ class Function : public GlobalObject, public ilist_node<Function> {
|
||||
/// pgo data.
|
||||
Optional<uint64_t> getEntryCount() const;
|
||||
|
||||
/// Return true if the function is annotated with profile data.
|
||||
///
|
||||
/// Presence of entry counts from a profile run implies the function has
|
||||
/// profile annotations.
|
||||
bool hasProfileData() const { return getEntryCount().hasValue(); }
|
||||
|
||||
/// Returns the set of GUIDs that needs to be imported to the function for
|
||||
/// sample PGO, to enable the same inlines as the profiled optimized binary.
|
||||
DenseSet<GlobalValue::GUID> getImportGUIDs() const;
|
||||
|
@ -12,6 +12,7 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
include "llvm/CodeGen/ValueTypes.td"
|
||||
include "llvm/CodeGen/SDNodeProperties.td"
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Properties we keep track of for intrinsics.
|
||||
@ -264,16 +265,17 @@ def llvm_vararg_ty : LLVMType<isVoid>; // this means vararg here
|
||||
// intrinsic.
|
||||
// * Properties can be set to describe the behavior of the intrinsic.
|
||||
//
|
||||
class SDPatternOperator;
|
||||
class Intrinsic<list<LLVMType> ret_types,
|
||||
list<LLVMType> param_types = [],
|
||||
list<IntrinsicProperty> properties = [],
|
||||
string name = ""> : SDPatternOperator {
|
||||
list<IntrinsicProperty> intr_properties = [],
|
||||
string name = "",
|
||||
list<SDNodeProperty> sd_properties = []> : SDPatternOperator {
|
||||
string LLVMName = name;
|
||||
string TargetPrefix = ""; // Set to a prefix for target-specific intrinsics.
|
||||
list<LLVMType> RetTypes = ret_types;
|
||||
list<LLVMType> ParamTypes = param_types;
|
||||
list<IntrinsicProperty> IntrProperties = properties;
|
||||
list<IntrinsicProperty> IntrProperties = intr_properties;
|
||||
let Properties = sd_properties;
|
||||
|
||||
bit isTarget = 0;
|
||||
}
|
||||
|
@ -148,10 +148,14 @@ class ThinLTOCodeGenerator {
|
||||
/// incremental build.
|
||||
void setCacheDir(std::string Path) { CacheOptions.Path = std::move(Path); }
|
||||
|
||||
/// Cache policy: interval (seconds) between two prune of the cache. Set to a
|
||||
/// negative value (default) to disable pruning. A value of 0 will be ignored.
|
||||
/// Cache policy: interval (seconds) between two prunes of the cache. Set to a
|
||||
/// negative value to disable pruning. A value of 0 will be ignored.
|
||||
void setCachePruningInterval(int Interval) {
|
||||
if (Interval)
|
||||
if (Interval == 0)
|
||||
return;
|
||||
if(Interval < 0)
|
||||
CacheOptions.Policy.Interval.reset();
|
||||
else
|
||||
CacheOptions.Policy.Interval = std::chrono::seconds(Interval);
|
||||
}
|
||||
|
||||
|
@ -165,7 +165,8 @@ class MCAsmInfo {
|
||||
const char *ZeroDirective;
|
||||
|
||||
/// This directive allows emission of an ascii string with the standard C
|
||||
/// escape characters embedded into it. Defaults to "\t.ascii\t"
|
||||
/// escape characters embedded into it. If a target doesn't support this, it
|
||||
/// can be set to null. Defaults to "\t.ascii\t"
|
||||
const char *AsciiDirective;
|
||||
|
||||
/// If not null, this allows for special handling of zero terminated strings
|
||||
|
@ -95,6 +95,17 @@ class MCTargetStreamer {
|
||||
virtual void prettyPrintAsm(MCInstPrinter &InstPrinter, raw_ostream &OS,
|
||||
const MCInst &Inst, const MCSubtargetInfo &STI);
|
||||
|
||||
virtual void emitDwarfFileDirective(StringRef Directive);
|
||||
|
||||
/// Update streamer for a new active section.
|
||||
///
|
||||
/// This is called by PopSection and SwitchSection, if the current
|
||||
/// section changes.
|
||||
virtual void changeSection(const MCSection *CurSection, MCSection *Section,
|
||||
const MCExpr *SubSection, raw_ostream &OS);
|
||||
|
||||
virtual void emitValue(const MCExpr *Value);
|
||||
|
||||
virtual void finish();
|
||||
};
|
||||
|
||||
|
@ -43,9 +43,9 @@ class WasmSymbol {
|
||||
};
|
||||
|
||||
WasmSymbol(StringRef Name, SymbolType Type, uint32_t Section,
|
||||
uint32_t ElementIndex, uint32_t ImportIndex = 0)
|
||||
uint32_t ElementIndex, uint32_t FunctionType = 0)
|
||||
: Name(Name), Type(Type), Section(Section), ElementIndex(ElementIndex),
|
||||
ImportIndex(ImportIndex) {}
|
||||
FunctionType(FunctionType) {}
|
||||
|
||||
StringRef Name;
|
||||
SymbolType Type;
|
||||
@ -55,8 +55,18 @@ class WasmSymbol {
|
||||
// Index into either the function or global index space.
|
||||
uint32_t ElementIndex;
|
||||
|
||||
// For imports, the index into the import table
|
||||
uint32_t ImportIndex;
|
||||
// For function, the type index
|
||||
uint32_t FunctionType;
|
||||
|
||||
// Symbols can be both exported and imported (in the case of the weakly
|
||||
// defined symbol). In this the import index is stored as AltIndex.
|
||||
uint32_t AltIndex = 0;
|
||||
bool HasAltIndex = false;
|
||||
|
||||
void setAltIndex(uint32_t Index) {
|
||||
HasAltIndex = true;
|
||||
AltIndex = Index;
|
||||
}
|
||||
|
||||
bool isFunction() const {
|
||||
return Type == WasmSymbol::SymbolType::FUNCTION_IMPORT ||
|
||||
@ -91,8 +101,7 @@ class WasmSymbol {
|
||||
|
||||
void print(raw_ostream &Out) const {
|
||||
Out << "Name=" << Name << ", Type=" << static_cast<int>(Type)
|
||||
<< ", Flags=" << Flags << " ElemIndex=" << ElementIndex
|
||||
<< ", ImportIndex=" << ImportIndex;
|
||||
<< ", Flags=" << Flags << " ElemIndex=" << ElementIndex;
|
||||
}
|
||||
|
||||
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
||||
|
@ -27,8 +27,9 @@ template <typename T> class Expected;
|
||||
struct CachePruningPolicy {
|
||||
/// The pruning interval. This is intended to be used to avoid scanning the
|
||||
/// directory too often. It does not impact the decision of which file to
|
||||
/// prune. A value of 0 forces the scan to occur.
|
||||
std::chrono::seconds Interval = std::chrono::seconds(1200);
|
||||
/// prune. A value of 0 forces the scan to occur. A value of None disables
|
||||
/// pruning.
|
||||
llvm::Optional<std::chrono::seconds> Interval = std::chrono::seconds(1200);
|
||||
|
||||
/// The expiration for a file. When a file hasn't been accessed for Expiration
|
||||
/// seconds, it is removed from the cache. A value of 0 disables the
|
||||
|
@ -15,6 +15,7 @@
|
||||
#define LLVM_SUPPORT_MEMORYBUFFER_H
|
||||
|
||||
#include "llvm-c/Types.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/Twine.h"
|
||||
#include "llvm/Support/CBindingWrapping.h"
|
||||
@ -47,6 +48,9 @@ class MemoryBuffer {
|
||||
|
||||
void init(const char *BufStart, const char *BufEnd,
|
||||
bool RequiresNullTerminator);
|
||||
|
||||
static constexpr bool Writable = false;
|
||||
|
||||
public:
|
||||
MemoryBuffer(const MemoryBuffer &) = delete;
|
||||
MemoryBuffer &operator=(const MemoryBuffer &) = delete;
|
||||
@ -119,12 +123,6 @@ class MemoryBuffer {
|
||||
static std::unique_ptr<MemoryBuffer>
|
||||
getNewMemBuffer(size_t Size, StringRef BufferName = "");
|
||||
|
||||
/// Allocate a new MemoryBuffer of the specified size that is not initialized.
|
||||
/// Note that the caller should initialize the memory allocated by this
|
||||
/// method. The memory is owned by the MemoryBuffer object.
|
||||
static std::unique_ptr<MemoryBuffer>
|
||||
getNewUninitMemBuffer(size_t Size, const Twine &BufferName = "");
|
||||
|
||||
/// Read all of stdin into a file buffer, and return it.
|
||||
static ErrorOr<std::unique_ptr<MemoryBuffer>> getSTDIN();
|
||||
|
||||
@ -156,6 +154,62 @@ class MemoryBuffer {
|
||||
MemoryBufferRef getMemBufferRef() const;
|
||||
};
|
||||
|
||||
/// This class is an extension of MemoryBuffer, which allows writing to the
|
||||
/// underlying contents. It only supports creation methods that are guaranteed
|
||||
/// to produce a writable buffer. For example, mapping a file read-only is not
|
||||
/// supported.
|
||||
class WritableMemoryBuffer : public MemoryBuffer {
|
||||
protected:
|
||||
WritableMemoryBuffer() = default;
|
||||
|
||||
static constexpr bool Writable = true;
|
||||
|
||||
public:
|
||||
using MemoryBuffer::getBuffer;
|
||||
using MemoryBuffer::getBufferEnd;
|
||||
using MemoryBuffer::getBufferStart;
|
||||
|
||||
// const_cast is well-defined here, because the underlying buffer is
|
||||
// guaranteed to have been initialized with a mutable buffer.
|
||||
char *getBufferStart() {
|
||||
return const_cast<char *>(MemoryBuffer::getBufferStart());
|
||||
}
|
||||
char *getBufferEnd() {
|
||||
return const_cast<char *>(MemoryBuffer::getBufferEnd());
|
||||
}
|
||||
MutableArrayRef<char> getBuffer() {
|
||||
return {getBufferStart(), getBufferEnd()};
|
||||
}
|
||||
|
||||
static ErrorOr<std::unique_ptr<WritableMemoryBuffer>>
|
||||
getFile(const Twine &Filename, int64_t FileSize = -1,
|
||||
bool IsVolatile = false);
|
||||
|
||||
/// Map a subrange of the specified file as a WritableMemoryBuffer.
|
||||
static ErrorOr<std::unique_ptr<WritableMemoryBuffer>>
|
||||
getFileSlice(const Twine &Filename, uint64_t MapSize, uint64_t Offset,
|
||||
bool IsVolatile = false);
|
||||
|
||||
/// Allocate a new MemoryBuffer of the specified size that is not initialized.
|
||||
/// Note that the caller should initialize the memory allocated by this
|
||||
/// method. The memory is owned by the MemoryBuffer object.
|
||||
static std::unique_ptr<WritableMemoryBuffer>
|
||||
getNewUninitMemBuffer(size_t Size, const Twine &BufferName = "");
|
||||
|
||||
private:
|
||||
// Hide these base class factory function so one can't write
|
||||
// WritableMemoryBuffer::getXXX()
|
||||
// and be surprised that he got a read-only Buffer.
|
||||
using MemoryBuffer::getFileAsStream;
|
||||
using MemoryBuffer::getFileOrSTDIN;
|
||||
using MemoryBuffer::getMemBuffer;
|
||||
using MemoryBuffer::getMemBufferCopy;
|
||||
using MemoryBuffer::getNewMemBuffer;
|
||||
using MemoryBuffer::getOpenFile;
|
||||
using MemoryBuffer::getOpenFileSlice;
|
||||
using MemoryBuffer::getSTDIN;
|
||||
};
|
||||
|
||||
class MemoryBufferRef {
|
||||
StringRef Buffer;
|
||||
StringRef Identifier;
|
||||
|
@ -549,9 +549,9 @@ inline QuotingType needsQuotes(StringRef S) {
|
||||
// range.
|
||||
if (C <= 0x1F)
|
||||
return QuotingType::Double;
|
||||
// C1 control block (0x80 - 0x9F) is excluded from the allowed character
|
||||
// range.
|
||||
if (C >= 0x80 && C <= 0x9F)
|
||||
|
||||
// Always double quote UTF-8.
|
||||
if ((C & 0x80) != 0)
|
||||
return QuotingType::Double;
|
||||
|
||||
// The character is not safe, at least simple quoting needed.
|
||||
@ -1725,7 +1725,7 @@ template <typename T> struct StdMapStringCustomMappingTraitsImpl {
|
||||
template <> struct ScalarTraits<Type> { \
|
||||
static void output(const Type &Value, void *ctx, raw_ostream &Out); \
|
||||
static StringRef input(StringRef Scalar, void *ctxt, Type &Value); \
|
||||
static QuotingType mustQuote(StringRef) { return MustQuote; } \
|
||||
static QuotingType mustQuote(StringRef) { return MustQuote; } \
|
||||
}; \
|
||||
} \
|
||||
}
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class Function;
|
||||
class GlobalValue;
|
||||
class MachineModuleInfo;
|
||||
class Mangler;
|
||||
@ -38,6 +39,7 @@ class PassManagerBuilder;
|
||||
class Target;
|
||||
class TargetIntrinsicInfo;
|
||||
class TargetIRAnalysis;
|
||||
class TargetTransformInfo;
|
||||
class TargetLoweringObjectFile;
|
||||
class TargetPassConfig;
|
||||
class TargetSubtargetInfo;
|
||||
@ -204,7 +206,13 @@ class TargetMachine {
|
||||
/// This is used to construct the new pass manager's target IR analysis pass,
|
||||
/// set up appropriately for this target machine. Even the old pass manager
|
||||
/// uses this to answer queries about the IR.
|
||||
virtual TargetIRAnalysis getTargetIRAnalysis();
|
||||
TargetIRAnalysis getTargetIRAnalysis();
|
||||
|
||||
/// \brief Return a TargetTransformInfo for a given function.
|
||||
///
|
||||
/// The returned TargetTransformInfo is specialized to the subtarget
|
||||
/// corresponding to \p F.
|
||||
virtual TargetTransformInfo getTargetTransformInfo(const Function &F);
|
||||
|
||||
/// Allow the target to modify the pass manager, e.g. by calling
|
||||
/// PassManagerBuilder::addExtension.
|
||||
@ -280,11 +288,11 @@ class LLVMTargetMachine : public TargetMachine {
|
||||
void initAsmInfo();
|
||||
|
||||
public:
|
||||
/// \brief Get a TargetIRAnalysis implementation for the target.
|
||||
/// \brief Get a TargetTransformInfo implementation for the target.
|
||||
///
|
||||
/// This analysis will produce a TTI result which uses the common code
|
||||
/// generator to answer queries about the IR.
|
||||
TargetIRAnalysis getTargetIRAnalysis() override;
|
||||
/// The TTI returned uses the common code generator to answer queries about
|
||||
/// the IR.
|
||||
TargetTransformInfo getTargetTransformInfo(const Function &F) override;
|
||||
|
||||
/// Create a pass configuration object to be used by addPassToEmitX methods
|
||||
/// for generating a pipeline of CodeGen passes.
|
||||
|
@ -285,32 +285,6 @@ class SDCallSeqStart<list<SDTypeConstraint> constraints> :
|
||||
class SDCallSeqEnd<list<SDTypeConstraint> constraints> :
|
||||
SDTypeProfile<0, 2, constraints>;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Selection DAG Node Properties.
|
||||
//
|
||||
// Note: These are hard coded into tblgen.
|
||||
//
|
||||
class SDNodeProperty;
|
||||
def SDNPCommutative : SDNodeProperty; // X op Y == Y op X
|
||||
def SDNPAssociative : SDNodeProperty; // (X op Y) op Z == X op (Y op Z)
|
||||
def SDNPHasChain : SDNodeProperty; // R/W chain operand and result
|
||||
def SDNPOutGlue : SDNodeProperty; // Write a flag result
|
||||
def SDNPInGlue : SDNodeProperty; // Read a flag operand
|
||||
def SDNPOptInGlue : SDNodeProperty; // Optionally read a flag operand
|
||||
def SDNPMayStore : SDNodeProperty; // May write to memory, sets 'mayStore'.
|
||||
def SDNPMayLoad : SDNodeProperty; // May read memory, sets 'mayLoad'.
|
||||
def SDNPSideEffect : SDNodeProperty; // Sets 'HasUnmodelledSideEffects'.
|
||||
def SDNPMemOperand : SDNodeProperty; // Touches memory, has assoc MemOperand
|
||||
def SDNPVariadic : SDNodeProperty; // Node has variable arguments.
|
||||
def SDNPWantRoot : SDNodeProperty; // ComplexPattern gets the root of match
|
||||
def SDNPWantParent : SDNodeProperty; // ComplexPattern gets the parent
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Selection DAG Pattern Operations
|
||||
class SDPatternOperator {
|
||||
list<SDNodeProperty> Properties = [];
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Selection DAG Node definitions.
|
||||
//
|
||||
|
@ -133,7 +133,7 @@ ModulePass *createAddressSanitizerModulePass(bool CompileKernel = false,
|
||||
FunctionPass *createMemorySanitizerPass(int TrackOrigins = 0,
|
||||
bool Recover = false);
|
||||
|
||||
FunctionPass *createHWAddressSanitizerPass();
|
||||
FunctionPass *createHWAddressSanitizerPass(bool Recover = false);
|
||||
|
||||
// Insert ThreadSanitizer (race detection) instrumentation
|
||||
FunctionPass *createThreadSanitizerPass();
|
||||
|
@ -29,13 +29,23 @@ namespace llvm {
|
||||
bool isLegalToPromote(CallSite CS, Function *Callee,
|
||||
const char **FailureReason = nullptr);
|
||||
|
||||
/// Promote the given indirect call site to unconditionally call \p Callee.
|
||||
///
|
||||
/// This function promotes the given call site, returning the direct call or
|
||||
/// invoke instruction. If the function type of the call site doesn't match that
|
||||
/// of the callee, bitcast instructions are inserted where appropriate. If \p
|
||||
/// RetBitCast is non-null, it will be used to store the return value bitcast,
|
||||
/// if created.
|
||||
Instruction *promoteCall(CallSite CS, Function *Callee,
|
||||
CastInst **RetBitCast = nullptr);
|
||||
|
||||
/// Promote the given indirect call site to conditionally call \p Callee.
|
||||
///
|
||||
/// This function creates an if-then-else structure at the location of the call
|
||||
/// site. The original call site is promoted and moved into the "then" block. A
|
||||
/// clone of the indirect call site is placed in the "else" block and returned.
|
||||
/// If \p BranchWeights is non-null, it will be used to set !prof metadata on
|
||||
/// the new conditional branch.
|
||||
/// site. The original call site is moved into the "else" block. A clone of the
|
||||
/// indirect call site is promoted, placed in the "then" block, and returned. If
|
||||
/// \p BranchWeights is non-null, it will be used to set !prof metadata on the
|
||||
/// new conditional branch.
|
||||
Instruction *promoteCallWithIfThenElse(CallSite CS, Function *Callee,
|
||||
MDNode *BranchWeights = nullptr);
|
||||
|
||||
|
@ -61,7 +61,7 @@ module LLVM_BinaryFormat {
|
||||
textual header "BinaryFormat/ELFRelocs/SystemZ.def"
|
||||
textual header "BinaryFormat/ELFRelocs/x86_64.def"
|
||||
textual header "BinaryFormat/ELFRelocs/WebAssembly.def"
|
||||
textual header "BinaryFormat/WasmRelocs/WebAssembly.def"
|
||||
textual header "BinaryFormat/WasmRelocs.def"
|
||||
}
|
||||
|
||||
module LLVM_Config { requires cplusplus umbrella "Config" module * { export * } }
|
||||
|
@ -133,9 +133,9 @@ ModRefInfo AAResults::getArgModRefInfo(ImmutableCallSite CS, unsigned ArgIdx) {
|
||||
}
|
||||
|
||||
ModRefInfo AAResults::getModRefInfo(Instruction *I, ImmutableCallSite Call) {
|
||||
// We may have two calls
|
||||
// We may have two calls.
|
||||
if (auto CS = ImmutableCallSite(I)) {
|
||||
// Check if the two calls modify the same memory
|
||||
// Check if the two calls modify the same memory.
|
||||
return getModRefInfo(CS, Call);
|
||||
} else if (I->isFenceLike()) {
|
||||
// If this is a fence, just return ModRef.
|
||||
@ -179,6 +179,7 @@ ModRefInfo AAResults::getModRefInfo(ImmutableCallSite CS,
|
||||
|
||||
if (onlyAccessesArgPointees(MRB) || onlyAccessesInaccessibleOrArgMem(MRB)) {
|
||||
bool DoesAlias = false;
|
||||
bool IsMustAlias = true;
|
||||
ModRefInfo AllArgsMask = ModRefInfo::NoModRef;
|
||||
if (doesAccessArgPointees(MRB)) {
|
||||
for (auto AI = CS.arg_begin(), AE = CS.arg_end(); AI != AE; ++AI) {
|
||||
@ -193,6 +194,8 @@ ModRefInfo AAResults::getModRefInfo(ImmutableCallSite CS,
|
||||
DoesAlias = true;
|
||||
AllArgsMask = unionModRef(AllArgsMask, ArgMask);
|
||||
}
|
||||
// Conservatively clear IsMustAlias unless only MustAlias is found.
|
||||
IsMustAlias &= (ArgAlias == MustAlias);
|
||||
}
|
||||
}
|
||||
// Return NoModRef if no alias found with any argument.
|
||||
@ -200,6 +203,8 @@ ModRefInfo AAResults::getModRefInfo(ImmutableCallSite CS,
|
||||
return ModRefInfo::NoModRef;
|
||||
// Logical & between other AA analyses and argument analysis.
|
||||
Result = intersectModRef(Result, AllArgsMask);
|
||||
// If only MustAlias found above, set Must bit.
|
||||
Result = IsMustAlias ? setMust(Result) : clearMust(Result);
|
||||
}
|
||||
|
||||
// If Loc is a constant memory location, the call definitely could not
|
||||
@ -251,6 +256,7 @@ ModRefInfo AAResults::getModRefInfo(ImmutableCallSite CS1,
|
||||
if (onlyAccessesArgPointees(CS2B)) {
|
||||
ModRefInfo R = ModRefInfo::NoModRef;
|
||||
if (doesAccessArgPointees(CS2B)) {
|
||||
bool IsMustAlias = true;
|
||||
for (auto I = CS2.arg_begin(), E = CS2.arg_end(); I != E; ++I) {
|
||||
const Value *Arg = *I;
|
||||
if (!Arg->getType()->isPointerTy())
|
||||
@ -274,10 +280,19 @@ ModRefInfo AAResults::getModRefInfo(ImmutableCallSite CS1,
|
||||
ModRefInfo ModRefCS1 = getModRefInfo(CS1, CS2ArgLoc);
|
||||
ArgMask = intersectModRef(ArgMask, ModRefCS1);
|
||||
|
||||
// Conservatively clear IsMustAlias unless only MustAlias is found.
|
||||
IsMustAlias &= isMustSet(ModRefCS1);
|
||||
|
||||
R = intersectModRef(unionModRef(R, ArgMask), Result);
|
||||
if (R == Result)
|
||||
if (R == Result) {
|
||||
// On early exit, not all args were checked, cannot set Must.
|
||||
if (I + 1 != E)
|
||||
IsMustAlias = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// If Alias found and only MustAlias found above, set Must bit.
|
||||
R = IsMustAlias ? setMust(R) : clearMust(R);
|
||||
}
|
||||
return R;
|
||||
}
|
||||
@ -287,6 +302,7 @@ ModRefInfo AAResults::getModRefInfo(ImmutableCallSite CS1,
|
||||
if (onlyAccessesArgPointees(CS1B)) {
|
||||
ModRefInfo R = ModRefInfo::NoModRef;
|
||||
if (doesAccessArgPointees(CS1B)) {
|
||||
bool IsMustAlias = true;
|
||||
for (auto I = CS1.arg_begin(), E = CS1.arg_end(); I != E; ++I) {
|
||||
const Value *Arg = *I;
|
||||
if (!Arg->getType()->isPointerTy())
|
||||
@ -303,9 +319,18 @@ ModRefInfo AAResults::getModRefInfo(ImmutableCallSite CS1,
|
||||
(isRefSet(ArgModRefCS1) && isModSet(ModRefCS2)))
|
||||
R = intersectModRef(unionModRef(R, ArgModRefCS1), Result);
|
||||
|
||||
if (R == Result)
|
||||
// Conservatively clear IsMustAlias unless only MustAlias is found.
|
||||
IsMustAlias &= isMustSet(ModRefCS2);
|
||||
|
||||
if (R == Result) {
|
||||
// On early exit, not all args were checked, cannot set Must.
|
||||
if (I + 1 != E)
|
||||
IsMustAlias = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// If Alias found and only MustAlias found above, set Must bit.
|
||||
R = IsMustAlias ? setMust(R) : clearMust(R);
|
||||
}
|
||||
return R;
|
||||
}
|
||||
@ -353,9 +378,13 @@ ModRefInfo AAResults::getModRefInfo(const LoadInst *L,
|
||||
|
||||
// If the load address doesn't alias the given address, it doesn't read
|
||||
// or write the specified memory.
|
||||
if (Loc.Ptr && !alias(MemoryLocation::get(L), Loc))
|
||||
return ModRefInfo::NoModRef;
|
||||
|
||||
if (Loc.Ptr) {
|
||||
AliasResult AR = alias(MemoryLocation::get(L), Loc);
|
||||
if (AR == NoAlias)
|
||||
return ModRefInfo::NoModRef;
|
||||
if (AR == MustAlias)
|
||||
return ModRefInfo::MustRef;
|
||||
}
|
||||
// Otherwise, a load just reads.
|
||||
return ModRefInfo::Ref;
|
||||
}
|
||||
@ -367,15 +396,20 @@ ModRefInfo AAResults::getModRefInfo(const StoreInst *S,
|
||||
return ModRefInfo::ModRef;
|
||||
|
||||
if (Loc.Ptr) {
|
||||
AliasResult AR = alias(MemoryLocation::get(S), Loc);
|
||||
// If the store address cannot alias the pointer in question, then the
|
||||
// specified memory cannot be modified by the store.
|
||||
if (!alias(MemoryLocation::get(S), Loc))
|
||||
if (AR == NoAlias)
|
||||
return ModRefInfo::NoModRef;
|
||||
|
||||
// If the pointer is a pointer to constant memory, then it could not have
|
||||
// been modified by this store.
|
||||
if (pointsToConstantMemory(Loc))
|
||||
return ModRefInfo::NoModRef;
|
||||
|
||||
// If the store address aliases the pointer as must alias, set Must.
|
||||
if (AR == MustAlias)
|
||||
return ModRefInfo::MustMod;
|
||||
}
|
||||
|
||||
// Otherwise, a store just writes.
|
||||
@ -393,15 +427,20 @@ ModRefInfo AAResults::getModRefInfo(const FenceInst *S, const MemoryLocation &Lo
|
||||
ModRefInfo AAResults::getModRefInfo(const VAArgInst *V,
|
||||
const MemoryLocation &Loc) {
|
||||
if (Loc.Ptr) {
|
||||
AliasResult AR = alias(MemoryLocation::get(V), Loc);
|
||||
// If the va_arg address cannot alias the pointer in question, then the
|
||||
// specified memory cannot be accessed by the va_arg.
|
||||
if (!alias(MemoryLocation::get(V), Loc))
|
||||
if (AR == NoAlias)
|
||||
return ModRefInfo::NoModRef;
|
||||
|
||||
// If the pointer is a pointer to constant memory, then it could not have
|
||||
// been modified by this va_arg.
|
||||
if (pointsToConstantMemory(Loc))
|
||||
return ModRefInfo::NoModRef;
|
||||
|
||||
// If the va_arg aliases the pointer as must alias, set Must.
|
||||
if (AR == MustAlias)
|
||||
return ModRefInfo::MustModRef;
|
||||
}
|
||||
|
||||
// Otherwise, a va_arg reads and writes.
|
||||
@ -440,9 +479,17 @@ ModRefInfo AAResults::getModRefInfo(const AtomicCmpXchgInst *CX,
|
||||
if (isStrongerThanMonotonic(CX->getSuccessOrdering()))
|
||||
return ModRefInfo::ModRef;
|
||||
|
||||
// If the cmpxchg address does not alias the location, it does not access it.
|
||||
if (Loc.Ptr && !alias(MemoryLocation::get(CX), Loc))
|
||||
return ModRefInfo::NoModRef;
|
||||
if (Loc.Ptr) {
|
||||
AliasResult AR = alias(MemoryLocation::get(CX), Loc);
|
||||
// If the cmpxchg address does not alias the location, it does not access
|
||||
// it.
|
||||
if (AR == NoAlias)
|
||||
return ModRefInfo::NoModRef;
|
||||
|
||||
// If the cmpxchg address aliases the pointer as must alias, set Must.
|
||||
if (AR == MustAlias)
|
||||
return ModRefInfo::MustModRef;
|
||||
}
|
||||
|
||||
return ModRefInfo::ModRef;
|
||||
}
|
||||
@ -453,9 +500,17 @@ ModRefInfo AAResults::getModRefInfo(const AtomicRMWInst *RMW,
|
||||
if (isStrongerThanMonotonic(RMW->getOrdering()))
|
||||
return ModRefInfo::ModRef;
|
||||
|
||||
// If the atomicrmw address does not alias the location, it does not access it.
|
||||
if (Loc.Ptr && !alias(MemoryLocation::get(RMW), Loc))
|
||||
return ModRefInfo::NoModRef;
|
||||
if (Loc.Ptr) {
|
||||
AliasResult AR = alias(MemoryLocation::get(RMW), Loc);
|
||||
// If the atomicrmw address does not alias the location, it does not access
|
||||
// it.
|
||||
if (AR == NoAlias)
|
||||
return ModRefInfo::NoModRef;
|
||||
|
||||
// If the atomicrmw address aliases the pointer as must alias, set Must.
|
||||
if (AR == MustAlias)
|
||||
return ModRefInfo::MustModRef;
|
||||
}
|
||||
|
||||
return ModRefInfo::ModRef;
|
||||
}
|
||||
@ -493,6 +548,8 @@ ModRefInfo AAResults::callCapturesBefore(const Instruction *I,
|
||||
|
||||
unsigned ArgNo = 0;
|
||||
ModRefInfo R = ModRefInfo::NoModRef;
|
||||
bool MustAlias = true;
|
||||
// Set flag only if no May found and all operands processed.
|
||||
for (auto CI = CS.data_operands_begin(), CE = CS.data_operands_end();
|
||||
CI != CE; ++CI, ++ArgNo) {
|
||||
// Only look at the no-capture or byval pointer arguments. If this
|
||||
@ -503,11 +560,14 @@ ModRefInfo AAResults::callCapturesBefore(const Instruction *I,
|
||||
ArgNo < CS.getNumArgOperands() && !CS.isByValArgument(ArgNo)))
|
||||
continue;
|
||||
|
||||
AliasResult AR = alias(MemoryLocation(*CI), MemoryLocation(Object));
|
||||
// If this is a no-capture pointer argument, see if we can tell that it
|
||||
// is impossible to alias the pointer we're checking. If not, we have to
|
||||
// assume that the call could touch the pointer, even though it doesn't
|
||||
// escape.
|
||||
if (isNoAlias(MemoryLocation(*CI), MemoryLocation(Object)))
|
||||
if (AR != MustAlias)
|
||||
MustAlias = false;
|
||||
if (AR == NoAlias)
|
||||
continue;
|
||||
if (CS.doesNotAccessMemory(ArgNo))
|
||||
continue;
|
||||
@ -515,9 +575,10 @@ ModRefInfo AAResults::callCapturesBefore(const Instruction *I,
|
||||
R = ModRefInfo::Ref;
|
||||
continue;
|
||||
}
|
||||
// Not returning MustModRef since we have not seen all the arguments.
|
||||
return ModRefInfo::ModRef;
|
||||
}
|
||||
return R;
|
||||
return MustAlias ? setMust(R) : clearMust(R);
|
||||
}
|
||||
|
||||
/// canBasicBlockModify - Return true if it is possible for execution of the
|
||||
|
@ -31,9 +31,13 @@ static cl::opt<bool> PrintPartialAlias("print-partial-aliases", cl::ReallyHidden
|
||||
static cl::opt<bool> PrintMustAlias("print-must-aliases", cl::ReallyHidden);
|
||||
|
||||
static cl::opt<bool> PrintNoModRef("print-no-modref", cl::ReallyHidden);
|
||||
static cl::opt<bool> PrintMod("print-mod", cl::ReallyHidden);
|
||||
static cl::opt<bool> PrintRef("print-ref", cl::ReallyHidden);
|
||||
static cl::opt<bool> PrintMod("print-mod", cl::ReallyHidden);
|
||||
static cl::opt<bool> PrintModRef("print-modref", cl::ReallyHidden);
|
||||
static cl::opt<bool> PrintMust("print-must", cl::ReallyHidden);
|
||||
static cl::opt<bool> PrintMustRef("print-mustref", cl::ReallyHidden);
|
||||
static cl::opt<bool> PrintMustMod("print-mustmod", cl::ReallyHidden);
|
||||
static cl::opt<bool> PrintMustModRef("print-mustmodref", cl::ReallyHidden);
|
||||
|
||||
static cl::opt<bool> EvalAAMD("evaluate-aa-metadata", cl::ReallyHidden);
|
||||
|
||||
@ -262,6 +266,25 @@ void AAEvaluator::runInternal(Function &F, AAResults &AA) {
|
||||
F.getParent());
|
||||
++ModRefCount;
|
||||
break;
|
||||
case ModRefInfo::Must:
|
||||
PrintModRefResults("Must", PrintMust, I, Pointer, F.getParent());
|
||||
++MustCount;
|
||||
break;
|
||||
case ModRefInfo::MustMod:
|
||||
PrintModRefResults("Just Mod (MustAlias)", PrintMustMod, I, Pointer,
|
||||
F.getParent());
|
||||
++MustModCount;
|
||||
break;
|
||||
case ModRefInfo::MustRef:
|
||||
PrintModRefResults("Just Ref (MustAlias)", PrintMustRef, I, Pointer,
|
||||
F.getParent());
|
||||
++MustRefCount;
|
||||
break;
|
||||
case ModRefInfo::MustModRef:
|
||||
PrintModRefResults("Both ModRef (MustAlias)", PrintMustModRef, I,
|
||||
Pointer, F.getParent());
|
||||
++MustModRefCount;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -288,6 +311,25 @@ void AAEvaluator::runInternal(Function &F, AAResults &AA) {
|
||||
PrintModRefResults("Both ModRef", PrintModRef, *C, *D, F.getParent());
|
||||
++ModRefCount;
|
||||
break;
|
||||
case ModRefInfo::Must:
|
||||
PrintModRefResults("Must", PrintMust, *C, *D, F.getParent());
|
||||
++MustCount;
|
||||
break;
|
||||
case ModRefInfo::MustMod:
|
||||
PrintModRefResults("Just Mod (MustAlias)", PrintMustMod, *C, *D,
|
||||
F.getParent());
|
||||
++MustModCount;
|
||||
break;
|
||||
case ModRefInfo::MustRef:
|
||||
PrintModRefResults("Just Ref (MustAlias)", PrintMustRef, *C, *D,
|
||||
F.getParent());
|
||||
++MustRefCount;
|
||||
break;
|
||||
case ModRefInfo::MustModRef:
|
||||
PrintModRefResults("Both ModRef (MustAlias)", PrintMustModRef, *C, *D,
|
||||
F.getParent());
|
||||
++MustModRefCount;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -325,7 +367,8 @@ AAEvaluator::~AAEvaluator() {
|
||||
}
|
||||
|
||||
// Display the summary for mod/ref analysis
|
||||
int64_t ModRefSum = NoModRefCount + ModCount + RefCount + ModRefCount;
|
||||
int64_t ModRefSum = NoModRefCount + RefCount + ModCount + ModRefCount +
|
||||
MustCount + MustRefCount + MustModCount + MustModRefCount;
|
||||
if (ModRefSum == 0) {
|
||||
errs() << " Alias Analysis Mod/Ref Evaluator Summary: no "
|
||||
"mod/ref!\n";
|
||||
@ -339,10 +382,22 @@ AAEvaluator::~AAEvaluator() {
|
||||
PrintPercent(RefCount, ModRefSum);
|
||||
errs() << " " << ModRefCount << " mod & ref responses ";
|
||||
PrintPercent(ModRefCount, ModRefSum);
|
||||
errs() << " " << MustCount << " must responses ";
|
||||
PrintPercent(MustCount, ModRefSum);
|
||||
errs() << " " << MustModCount << " must mod responses ";
|
||||
PrintPercent(MustModCount, ModRefSum);
|
||||
errs() << " " << MustRefCount << " must ref responses ";
|
||||
PrintPercent(MustRefCount, ModRefSum);
|
||||
errs() << " " << MustModRefCount << " must mod & ref responses ";
|
||||
PrintPercent(MustModRefCount, ModRefSum);
|
||||
errs() << " Alias Analysis Evaluator Mod/Ref Summary: "
|
||||
<< NoModRefCount * 100 / ModRefSum << "%/"
|
||||
<< ModCount * 100 / ModRefSum << "%/" << RefCount * 100 / ModRefSum
|
||||
<< "%/" << ModRefCount * 100 / ModRefSum << "%\n";
|
||||
<< "%/" << ModRefCount * 100 / ModRefSum << "%/"
|
||||
<< MustCount * 100 / ModRefSum << "%/"
|
||||
<< MustRefCount * 100 / ModRefSum << "%/"
|
||||
<< MustModCount * 100 / ModRefSum << "%/"
|
||||
<< MustModRefCount * 100 / ModRefSum << "%\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -781,6 +781,7 @@ ModRefInfo BasicAAResult::getModRefInfo(ImmutableCallSite CS,
|
||||
// Optimistically assume that call doesn't touch Object and check this
|
||||
// assumption in the following loop.
|
||||
ModRefInfo Result = ModRefInfo::NoModRef;
|
||||
bool IsMustAlias = true;
|
||||
|
||||
unsigned OperandNo = 0;
|
||||
for (auto CI = CS.data_operands_begin(), CE = CS.data_operands_end();
|
||||
@ -802,7 +803,8 @@ ModRefInfo BasicAAResult::getModRefInfo(ImmutableCallSite CS,
|
||||
// is impossible to alias the pointer we're checking.
|
||||
AliasResult AR =
|
||||
getBestAAResults().alias(MemoryLocation(*CI), MemoryLocation(Object));
|
||||
|
||||
if (AR != MustAlias)
|
||||
IsMustAlias = false;
|
||||
// Operand doesnt alias 'Object', continue looking for other aliases
|
||||
if (AR == NoAlias)
|
||||
continue;
|
||||
@ -818,13 +820,20 @@ ModRefInfo BasicAAResult::getModRefInfo(ImmutableCallSite CS,
|
||||
continue;
|
||||
}
|
||||
// This operand aliases 'Object' and call reads and writes into it.
|
||||
// Setting ModRef will not yield an early return below, MustAlias is not
|
||||
// used further.
|
||||
Result = ModRefInfo::ModRef;
|
||||
break;
|
||||
}
|
||||
|
||||
// No operand aliases, reset Must bit. Add below if at least one aliases
|
||||
// and all aliases found are MustAlias.
|
||||
if (isNoModRef(Result))
|
||||
IsMustAlias = false;
|
||||
|
||||
// Early return if we improved mod ref information
|
||||
if (!isModAndRefSet(Result))
|
||||
return Result;
|
||||
return IsMustAlias ? setMust(Result) : clearMust(Result);
|
||||
}
|
||||
|
||||
// If the CallSite is to malloc or calloc, we can assume that it doesn't
|
||||
|
@ -82,7 +82,7 @@ PreservedAnalyses CFGOnlyViewerPass::run(Function &F,
|
||||
return PreservedAnalyses::all();
|
||||
}
|
||||
|
||||
static void writeCFGToDotFile(Function &F) {
|
||||
static void writeCFGToDotFile(Function &F, bool CFGOnly = false) {
|
||||
std::string Filename = ("cfg." + F.getName() + ".dot").str();
|
||||
errs() << "Writing '" << Filename << "'...";
|
||||
|
||||
@ -90,7 +90,7 @@ static void writeCFGToDotFile(Function &F) {
|
||||
raw_fd_ostream File(Filename, EC, sys::fs::F_Text);
|
||||
|
||||
if (!EC)
|
||||
WriteGraph(File, (const Function*)&F);
|
||||
WriteGraph(File, (const Function*)&F, CFGOnly);
|
||||
else
|
||||
errs() << " error opening file for writing!";
|
||||
errs() << "\n";
|
||||
@ -134,7 +134,7 @@ namespace {
|
||||
}
|
||||
|
||||
bool runOnFunction(Function &F) override {
|
||||
writeCFGToDotFile(F);
|
||||
writeCFGToDotFile(F, /*CFGOnly=*/true);
|
||||
return false;
|
||||
}
|
||||
void print(raw_ostream &OS, const Module* = nullptr) const override {}
|
||||
@ -152,7 +152,7 @@ INITIALIZE_PASS(CFGOnlyPrinterLegacyPass, "dot-cfg-only",
|
||||
|
||||
PreservedAnalyses CFGOnlyPrinterPass::run(Function &F,
|
||||
FunctionAnalysisManager &AM) {
|
||||
writeCFGToDotFile(F);
|
||||
writeCFGToDotFile(F, /*CFGOnly=*/true);
|
||||
return PreservedAnalyses::all();
|
||||
}
|
||||
|
||||
|
@ -85,12 +85,17 @@ class GlobalsAAResult::FunctionInfo {
|
||||
/// The bit that flags that this function may read any global. This is
|
||||
/// chosen to mix together with ModRefInfo bits.
|
||||
/// FIXME: This assumes ModRefInfo lattice will remain 4 bits!
|
||||
/// It overlaps with ModRefInfo::Must bit!
|
||||
/// FunctionInfo.getModRefInfo() masks out everything except ModRef so
|
||||
/// this remains correct, but the Must info is lost.
|
||||
enum { MayReadAnyGlobal = 4 };
|
||||
|
||||
/// Checks to document the invariants of the bit packing here.
|
||||
static_assert((MayReadAnyGlobal & static_cast<int>(ModRefInfo::ModRef)) == 0,
|
||||
static_assert((MayReadAnyGlobal & static_cast<int>(ModRefInfo::MustModRef)) ==
|
||||
0,
|
||||
"ModRef and the MayReadAnyGlobal flag bits overlap.");
|
||||
static_assert(((MayReadAnyGlobal | static_cast<int>(ModRefInfo::ModRef)) >>
|
||||
static_assert(((MayReadAnyGlobal |
|
||||
static_cast<int>(ModRefInfo::MustModRef)) >>
|
||||
AlignedMapPointerTraits::NumLowBitsAvailable) == 0,
|
||||
"Insufficient low bits to store our flag and ModRef info.");
|
||||
|
||||
@ -125,14 +130,22 @@ class GlobalsAAResult::FunctionInfo {
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// This method clears MayReadAnyGlobal bit added by GlobalsAAResult to return
|
||||
/// the corresponding ModRefInfo. It must align in functionality with
|
||||
/// clearMust().
|
||||
ModRefInfo globalClearMayReadAnyGlobal(int I) const {
|
||||
return ModRefInfo((I & static_cast<int>(ModRefInfo::ModRef)) |
|
||||
static_cast<int>(ModRefInfo::NoModRef));
|
||||
}
|
||||
|
||||
/// Returns the \c ModRefInfo info for this function.
|
||||
ModRefInfo getModRefInfo() const {
|
||||
return ModRefInfo(Info.getInt() & static_cast<int>(ModRefInfo::ModRef));
|
||||
return globalClearMayReadAnyGlobal(Info.getInt());
|
||||
}
|
||||
|
||||
/// Adds new \c ModRefInfo for this function to its state.
|
||||
void addModRefInfo(ModRefInfo NewMRI) {
|
||||
Info.setInt(Info.getInt() | static_cast<int>(NewMRI));
|
||||
Info.setInt(Info.getInt() | static_cast<int>(setMust(NewMRI)));
|
||||
}
|
||||
|
||||
/// Returns whether this function may read any global variable, and we don't
|
||||
|
@ -249,8 +249,6 @@ class CallAnalyzer : public InstVisitor<CallAnalyzer, bool> {
|
||||
bool visitCastInst(CastInst &I);
|
||||
bool visitUnaryInstruction(UnaryInstruction &I);
|
||||
bool visitCmpInst(CmpInst &I);
|
||||
bool visitAnd(BinaryOperator &I);
|
||||
bool visitOr(BinaryOperator &I);
|
||||
bool visitSub(BinaryOperator &I);
|
||||
bool visitBinaryOperator(BinaryOperator &I);
|
||||
bool visitLoad(LoadInst &I);
|
||||
@ -363,6 +361,7 @@ void CallAnalyzer::accumulateSROACost(DenseMap<Value *, int>::iterator CostIt,
|
||||
void CallAnalyzer::disableLoadElimination() {
|
||||
if (EnableLoadElimination) {
|
||||
Cost += LoadEliminationCost;
|
||||
LoadEliminationCost = 0;
|
||||
EnableLoadElimination = false;
|
||||
}
|
||||
}
|
||||
@ -700,6 +699,22 @@ bool CallAnalyzer::visitCastInst(CastInst &I) {
|
||||
// Disable SROA in the face of arbitrary casts we don't whitelist elsewhere.
|
||||
disableSROA(I.getOperand(0));
|
||||
|
||||
// If this is a floating-point cast, and the target says this operation
|
||||
// is expensive, this may eventually become a library call. Treat the cost
|
||||
// as such.
|
||||
switch (I.getOpcode()) {
|
||||
case Instruction::FPTrunc:
|
||||
case Instruction::FPExt:
|
||||
case Instruction::UIToFP:
|
||||
case Instruction::SIToFP:
|
||||
case Instruction::FPToUI:
|
||||
case Instruction::FPToSI:
|
||||
if (TTI.getFPOpCost(I.getType()) == TargetTransformInfo::TCC_Expensive)
|
||||
Cost += InlineConstants::CallPenalty;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return TargetTransformInfo::TCC_Free == TTI.getUserCost(&I);
|
||||
}
|
||||
|
||||
@ -1004,34 +1019,6 @@ bool CallAnalyzer::visitCmpInst(CmpInst &I) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CallAnalyzer::visitOr(BinaryOperator &I) {
|
||||
// This is necessary because the generic simplify instruction only works if
|
||||
// both operands are constants.
|
||||
for (unsigned i = 0; i < 2; ++i) {
|
||||
if (ConstantInt *C = dyn_cast_or_null<ConstantInt>(
|
||||
SimplifiedValues.lookup(I.getOperand(i))))
|
||||
if (C->isAllOnesValue()) {
|
||||
SimplifiedValues[&I] = C;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return Base::visitOr(I);
|
||||
}
|
||||
|
||||
bool CallAnalyzer::visitAnd(BinaryOperator &I) {
|
||||
// This is necessary because the generic simplify instruction only works if
|
||||
// both operands are constants.
|
||||
for (unsigned i = 0; i < 2; ++i) {
|
||||
if (ConstantInt *C = dyn_cast_or_null<ConstantInt>(
|
||||
SimplifiedValues.lookup(I.getOperand(i))))
|
||||
if (C->isZero()) {
|
||||
SimplifiedValues[&I] = C;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return Base::visitAnd(I);
|
||||
}
|
||||
|
||||
bool CallAnalyzer::visitSub(BinaryOperator &I) {
|
||||
// Try to handle a special case: we can fold computing the difference of two
|
||||
// constant-related pointers.
|
||||
@ -1061,23 +1048,38 @@ bool CallAnalyzer::visitSub(BinaryOperator &I) {
|
||||
|
||||
bool CallAnalyzer::visitBinaryOperator(BinaryOperator &I) {
|
||||
Value *LHS = I.getOperand(0), *RHS = I.getOperand(1);
|
||||
auto Evaluate = [&](SmallVectorImpl<Constant *> &COps) {
|
||||
Value *SimpleV = nullptr;
|
||||
if (auto FI = dyn_cast<FPMathOperator>(&I))
|
||||
SimpleV = SimplifyFPBinOp(I.getOpcode(), COps[0], COps[1],
|
||||
FI->getFastMathFlags(), DL);
|
||||
else
|
||||
SimpleV = SimplifyBinOp(I.getOpcode(), COps[0], COps[1], DL);
|
||||
return dyn_cast_or_null<Constant>(SimpleV);
|
||||
};
|
||||
Constant *CLHS = dyn_cast<Constant>(LHS);
|
||||
if (!CLHS)
|
||||
CLHS = SimplifiedValues.lookup(LHS);
|
||||
Constant *CRHS = dyn_cast<Constant>(RHS);
|
||||
if (!CRHS)
|
||||
CRHS = SimplifiedValues.lookup(RHS);
|
||||
|
||||
if (simplifyInstruction(I, Evaluate))
|
||||
Value *SimpleV = nullptr;
|
||||
if (auto FI = dyn_cast<FPMathOperator>(&I))
|
||||
SimpleV = SimplifyFPBinOp(I.getOpcode(), CLHS ? CLHS : LHS,
|
||||
CRHS ? CRHS : RHS, FI->getFastMathFlags(), DL);
|
||||
else
|
||||
SimpleV =
|
||||
SimplifyBinOp(I.getOpcode(), CLHS ? CLHS : LHS, CRHS ? CRHS : RHS, DL);
|
||||
|
||||
if (Constant *C = dyn_cast_or_null<Constant>(SimpleV))
|
||||
SimplifiedValues[&I] = C;
|
||||
|
||||
if (SimpleV)
|
||||
return true;
|
||||
|
||||
// Disable any SROA on arguments to arbitrary, unsimplified binary operators.
|
||||
disableSROA(LHS);
|
||||
disableSROA(RHS);
|
||||
|
||||
// If the instruction is floating point, and the target says this operation
|
||||
// is expensive, this may eventually become a library call. Treat the cost
|
||||
// as such.
|
||||
if (I.getType()->isFloatingPointTy() &&
|
||||
TTI.getFPOpCost(I.getType()) == TargetTransformInfo::TCC_Expensive)
|
||||
Cost += InlineConstants::CallPenalty;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1097,7 +1099,7 @@ bool CallAnalyzer::visitLoad(LoadInst &I) {
|
||||
// by any stores or calls, this load is likely to be redundant and can be
|
||||
// eliminated.
|
||||
if (EnableLoadElimination &&
|
||||
!LoadAddrSet.insert(I.getPointerOperand()).second) {
|
||||
!LoadAddrSet.insert(I.getPointerOperand()).second && I.isUnordered()) {
|
||||
LoadEliminationCost += InlineConstants::InstrCost;
|
||||
return true;
|
||||
}
|
||||
@ -1547,17 +1549,6 @@ bool CallAnalyzer::analyzeBlock(BasicBlock *BB,
|
||||
if (isa<ExtractElementInst>(I) || I->getType()->isVectorTy())
|
||||
++NumVectorInstructions;
|
||||
|
||||
// If the instruction is floating point, and the target says this operation
|
||||
// is expensive or the function has the "use-soft-float" attribute, this may
|
||||
// eventually become a library call. Treat the cost as such.
|
||||
if (I->getType()->isFloatingPointTy()) {
|
||||
// If the function has the "use-soft-float" attribute, mark it as
|
||||
// expensive.
|
||||
if (TTI.getFPOpCost(I->getType()) == TargetTransformInfo::TCC_Expensive ||
|
||||
(F.getFnAttribute("use-soft-float").getValueAsString() == "true"))
|
||||
Cost += InlineConstants::CallPenalty;
|
||||
}
|
||||
|
||||
// If the instruction simplified to a constant, there is no cost to this
|
||||
// instruction. Visit the instructions using our InstVisitor to account for
|
||||
// all of the per-instruction logic. The visit tree returns true if we
|
||||
|
@ -1107,77 +1107,6 @@ static unsigned getAddressSpaceOperand(Value *I) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// TODO:This API can be improved by using the permutation of given width as the
|
||||
// accesses are entered into the map.
|
||||
bool llvm::sortLoadAccesses(ArrayRef<Value *> VL, const DataLayout &DL,
|
||||
ScalarEvolution &SE,
|
||||
SmallVectorImpl<Value *> &Sorted,
|
||||
SmallVectorImpl<unsigned> *Mask) {
|
||||
SmallVector<std::pair<int64_t, Value *>, 4> OffValPairs;
|
||||
OffValPairs.reserve(VL.size());
|
||||
Sorted.reserve(VL.size());
|
||||
|
||||
// Walk over the pointers, and map each of them to an offset relative to
|
||||
// first pointer in the array.
|
||||
Value *Ptr0 = getPointerOperand(VL[0]);
|
||||
const SCEV *Scev0 = SE.getSCEV(Ptr0);
|
||||
Value *Obj0 = GetUnderlyingObject(Ptr0, DL);
|
||||
PointerType *PtrTy = dyn_cast<PointerType>(Ptr0->getType());
|
||||
uint64_t Size = DL.getTypeAllocSize(PtrTy->getElementType());
|
||||
|
||||
for (auto *Val : VL) {
|
||||
// The only kind of access we care about here is load.
|
||||
if (!isa<LoadInst>(Val))
|
||||
return false;
|
||||
|
||||
Value *Ptr = getPointerOperand(Val);
|
||||
assert(Ptr && "Expected value to have a pointer operand.");
|
||||
// If a pointer refers to a different underlying object, bail - the
|
||||
// pointers are by definition incomparable.
|
||||
Value *CurrObj = GetUnderlyingObject(Ptr, DL);
|
||||
if (CurrObj != Obj0)
|
||||
return false;
|
||||
|
||||
const SCEVConstant *Diff =
|
||||
dyn_cast<SCEVConstant>(SE.getMinusSCEV(SE.getSCEV(Ptr), Scev0));
|
||||
// The pointers may not have a constant offset from each other, or SCEV
|
||||
// may just not be smart enough to figure out they do. Regardless,
|
||||
// there's nothing we can do.
|
||||
if (!Diff || static_cast<unsigned>(Diff->getAPInt().abs().getSExtValue()) >
|
||||
(VL.size() - 1) * Size)
|
||||
return false;
|
||||
|
||||
OffValPairs.emplace_back(Diff->getAPInt().getSExtValue(), Val);
|
||||
}
|
||||
SmallVector<unsigned, 4> UseOrder(VL.size());
|
||||
for (unsigned i = 0; i < VL.size(); i++) {
|
||||
UseOrder[i] = i;
|
||||
}
|
||||
|
||||
// Sort the memory accesses and keep the order of their uses in UseOrder.
|
||||
std::sort(UseOrder.begin(), UseOrder.end(),
|
||||
[&OffValPairs](unsigned Left, unsigned Right) {
|
||||
return OffValPairs[Left].first < OffValPairs[Right].first;
|
||||
});
|
||||
|
||||
for (unsigned i = 0; i < VL.size(); i++)
|
||||
Sorted.emplace_back(OffValPairs[UseOrder[i]].second);
|
||||
|
||||
// Sort UseOrder to compute the Mask.
|
||||
if (Mask) {
|
||||
Mask->reserve(VL.size());
|
||||
for (unsigned i = 0; i < VL.size(); i++)
|
||||
Mask->emplace_back(i);
|
||||
std::sort(Mask->begin(), Mask->end(),
|
||||
[&UseOrder](unsigned Left, unsigned Right) {
|
||||
return UseOrder[Left] < UseOrder[Right];
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/// Returns true if the memory operations \p A and \p B are consecutive.
|
||||
bool llvm::isConsecutiveAccess(Value *A, Value *B, const DataLayout &DL,
|
||||
ScalarEvolution &SE, bool CheckType) {
|
||||
|
@ -647,6 +647,7 @@ MemDepResult MemoryDependenceResults::getSimplePointerDependencyFrom(
|
||||
|
||||
// Ok, this store might clobber the query pointer. Check to see if it is
|
||||
// a must alias: in this case, we want to return this as a def.
|
||||
// FIXME: Use ModRefInfo::Must bit from getModRefInfo call above.
|
||||
MemoryLocation StoreLoc = MemoryLocation::get(SI);
|
||||
|
||||
// If we found a pointer, check if it could be the same as our pointer.
|
||||
@ -690,7 +691,7 @@ MemDepResult MemoryDependenceResults::getSimplePointerDependencyFrom(
|
||||
// If necessary, perform additional analysis.
|
||||
if (isModAndRefSet(MR))
|
||||
MR = AA.callCapturesBefore(Inst, MemLoc, &DT, &OBB);
|
||||
switch (MR) {
|
||||
switch (clearMust(MR)) {
|
||||
case ModRefInfo::NoModRef:
|
||||
// If the call has no effect on the queried pointer, just ignore it.
|
||||
continue;
|
||||
@ -919,6 +920,14 @@ void MemoryDependenceResults::getNonLocalPointerDependency(
|
||||
Instruction *QueryInst, SmallVectorImpl<NonLocalDepResult> &Result) {
|
||||
const MemoryLocation Loc = MemoryLocation::get(QueryInst);
|
||||
bool isLoad = isa<LoadInst>(QueryInst);
|
||||
return getNonLocalPointerDependencyFrom(QueryInst, Loc, isLoad, Result);
|
||||
}
|
||||
|
||||
void MemoryDependenceResults::getNonLocalPointerDependencyFrom(
|
||||
Instruction *QueryInst,
|
||||
const MemoryLocation &Loc,
|
||||
bool isLoad,
|
||||
SmallVectorImpl<NonLocalDepResult> &Result) {
|
||||
BasicBlock *FromBB = QueryInst->getParent();
|
||||
assert(FromBB);
|
||||
|
||||
@ -1118,21 +1127,15 @@ bool MemoryDependenceResults::getNonLocalPointerDepFromBB(
|
||||
// If we already have a cache entry for this CacheKey, we may need to do some
|
||||
// work to reconcile the cache entry and the current query.
|
||||
if (!Pair.second) {
|
||||
if (CacheInfo->Size < Loc.Size) {
|
||||
// The query's Size is greater than the cached one. Throw out the
|
||||
// cached data and proceed with the query at the greater size.
|
||||
if (CacheInfo->Size != Loc.Size) {
|
||||
// The query's Size differs from the cached one. Throw out the
|
||||
// cached data and proceed with the query at the new size.
|
||||
CacheInfo->Pair = BBSkipFirstBlockPair();
|
||||
CacheInfo->Size = Loc.Size;
|
||||
for (auto &Entry : CacheInfo->NonLocalDeps)
|
||||
if (Instruction *Inst = Entry.getResult().getInst())
|
||||
RemoveFromReverseMap(ReverseNonLocalPtrDeps, Inst, CacheKey);
|
||||
CacheInfo->NonLocalDeps.clear();
|
||||
} else if (CacheInfo->Size > Loc.Size) {
|
||||
// This query's Size is less than the cached one. Conservatively restart
|
||||
// the query using the greater size.
|
||||
return getNonLocalPointerDepFromBB(
|
||||
QueryInst, Pointer, Loc.getWithNewSize(CacheInfo->Size), isLoad,
|
||||
StartBB, Result, Visited, SkipFirstBlock);
|
||||
}
|
||||
|
||||
// If the query's AATags are inconsistent with the cached one,
|
||||
|
@ -192,8 +192,6 @@ template <> struct DenseMapInfo<MemoryLocOrCall> {
|
||||
}
|
||||
};
|
||||
|
||||
enum class Reorderability { Always, IfNoAlias, Never };
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
/// This does one-way checks to see if Use could theoretically be hoisted above
|
||||
@ -202,22 +200,16 @@ enum class Reorderability { Always, IfNoAlias, Never };
|
||||
/// This assumes that, for the purposes of MemorySSA, Use comes directly after
|
||||
/// MayClobber, with no potentially clobbering operations in between them.
|
||||
/// (Where potentially clobbering ops are memory barriers, aliased stores, etc.)
|
||||
static Reorderability getLoadReorderability(const LoadInst *Use,
|
||||
const LoadInst *MayClobber) {
|
||||
static bool areLoadsReorderable(const LoadInst *Use,
|
||||
const LoadInst *MayClobber) {
|
||||
bool VolatileUse = Use->isVolatile();
|
||||
bool VolatileClobber = MayClobber->isVolatile();
|
||||
// Volatile operations may never be reordered with other volatile operations.
|
||||
if (VolatileUse && VolatileClobber)
|
||||
return Reorderability::Never;
|
||||
|
||||
// The lang ref allows reordering of volatile and non-volatile operations.
|
||||
// Whether an aliasing nonvolatile load and volatile load can be reordered,
|
||||
// though, is ambiguous. Because it may not be best to exploit this ambiguity,
|
||||
// we only allow volatile/non-volatile reordering if the volatile and
|
||||
// non-volatile operations don't alias.
|
||||
Reorderability Result = VolatileUse || VolatileClobber
|
||||
? Reorderability::IfNoAlias
|
||||
: Reorderability::Always;
|
||||
return false;
|
||||
// Otherwise, volatile doesn't matter here. From the language reference:
|
||||
// 'optimizers may change the order of volatile operations relative to
|
||||
// non-volatile operations.'"
|
||||
|
||||
// If a load is seq_cst, it cannot be moved above other loads. If its ordering
|
||||
// is weaker, it can be moved above other loads. We just need to be sure that
|
||||
@ -229,9 +221,7 @@ static Reorderability getLoadReorderability(const LoadInst *Use,
|
||||
bool SeqCstUse = Use->getOrdering() == AtomicOrdering::SequentiallyConsistent;
|
||||
bool MayClobberIsAcquire = isAtLeastOrStrongerThan(MayClobber->getOrdering(),
|
||||
AtomicOrdering::Acquire);
|
||||
if (SeqCstUse || MayClobberIsAcquire)
|
||||
return Reorderability::Never;
|
||||
return Result;
|
||||
return !(SeqCstUse || MayClobberIsAcquire);
|
||||
}
|
||||
|
||||
static bool instructionClobbersQuery(MemoryDef *MD,
|
||||
@ -265,18 +255,9 @@ static bool instructionClobbersQuery(MemoryDef *MD,
|
||||
return isModOrRefSet(I);
|
||||
}
|
||||
|
||||
if (auto *DefLoad = dyn_cast<LoadInst>(DefInst)) {
|
||||
if (auto *UseLoad = dyn_cast<LoadInst>(UseInst)) {
|
||||
switch (getLoadReorderability(UseLoad, DefLoad)) {
|
||||
case Reorderability::Always:
|
||||
return false;
|
||||
case Reorderability::Never:
|
||||
return true;
|
||||
case Reorderability::IfNoAlias:
|
||||
return !AA.isNoAlias(UseLoc, MemoryLocation::get(DefLoad));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (auto *DefLoad = dyn_cast<LoadInst>(DefInst))
|
||||
if (auto *UseLoad = dyn_cast<LoadInst>(UseInst))
|
||||
return !areLoadsReorderable(UseLoad, DefLoad);
|
||||
|
||||
return isModSet(AA.getModRefInfo(DefInst, UseLoc));
|
||||
}
|
||||
|
@ -454,7 +454,7 @@ ModuleSummaryIndex llvm::buildModuleSummaryIndex(
|
||||
std::unique_ptr<BlockFrequencyInfo> BFIPtr;
|
||||
if (GetBFICallback)
|
||||
BFI = GetBFICallback(F);
|
||||
else if (F.getEntryCount().hasValue()) {
|
||||
else if (F.hasProfileData()) {
|
||||
LoopInfo LI{DominatorTree(const_cast<Function &>(F))};
|
||||
BranchProbabilityInfo BPI{F, LI};
|
||||
BFIPtr = llvm::make_unique<BlockFrequencyInfo>(F, BPI, LI);
|
||||
|
@ -115,42 +115,62 @@ bool ProfileSummaryInfo::isFunctionEntryHot(const Function *F) {
|
||||
return FunctionCount && isHotCount(FunctionCount.getValue());
|
||||
}
|
||||
|
||||
/// Returns true if the function's entry or total call edge count is hot.
|
||||
/// Returns true if the function contains hot code. This can include a hot
|
||||
/// function entry count, hot basic block, or (in the case of Sample PGO)
|
||||
/// hot total call edge count.
|
||||
/// If it returns false, it either means it is not hot or it is unknown
|
||||
/// whether it is hot or not (for example, no profile data is available).
|
||||
bool ProfileSummaryInfo::isFunctionHotInCallGraph(const Function *F) {
|
||||
/// (for example, no profile data is available).
|
||||
bool ProfileSummaryInfo::isFunctionHotInCallGraph(const Function *F,
|
||||
BlockFrequencyInfo &BFI) {
|
||||
if (!F || !computeSummary())
|
||||
return false;
|
||||
if (auto FunctionCount = F->getEntryCount())
|
||||
if (isHotCount(FunctionCount.getValue()))
|
||||
return true;
|
||||
|
||||
uint64_t TotalCallCount = 0;
|
||||
if (hasSampleProfile()) {
|
||||
uint64_t TotalCallCount = 0;
|
||||
for (const auto &BB : *F)
|
||||
for (const auto &I : BB)
|
||||
if (isa<CallInst>(I) || isa<InvokeInst>(I))
|
||||
if (auto CallCount = getProfileCount(&I, nullptr))
|
||||
TotalCallCount += CallCount.getValue();
|
||||
if (isHotCount(TotalCallCount))
|
||||
return true;
|
||||
}
|
||||
for (const auto &BB : *F)
|
||||
for (const auto &I : BB)
|
||||
if (isa<CallInst>(I) || isa<InvokeInst>(I))
|
||||
if (auto CallCount = getProfileCount(&I, nullptr))
|
||||
TotalCallCount += CallCount.getValue();
|
||||
return isHotCount(TotalCallCount);
|
||||
if (isHotBB(&BB, &BFI))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Returns true if the function's entry and total call edge count is cold.
|
||||
/// Returns true if the function only contains cold code. This means that
|
||||
/// the function entry and blocks are all cold, and (in the case of Sample PGO)
|
||||
/// the total call edge count is cold.
|
||||
/// If it returns false, it either means it is not cold or it is unknown
|
||||
/// whether it is cold or not (for example, no profile data is available).
|
||||
bool ProfileSummaryInfo::isFunctionColdInCallGraph(const Function *F) {
|
||||
/// (for example, no profile data is available).
|
||||
bool ProfileSummaryInfo::isFunctionColdInCallGraph(const Function *F,
|
||||
BlockFrequencyInfo &BFI) {
|
||||
if (!F || !computeSummary())
|
||||
return false;
|
||||
if (auto FunctionCount = F->getEntryCount())
|
||||
if (!isColdCount(FunctionCount.getValue()))
|
||||
return false;
|
||||
|
||||
uint64_t TotalCallCount = 0;
|
||||
|
||||
if (hasSampleProfile()) {
|
||||
uint64_t TotalCallCount = 0;
|
||||
for (const auto &BB : *F)
|
||||
for (const auto &I : BB)
|
||||
if (isa<CallInst>(I) || isa<InvokeInst>(I))
|
||||
if (auto CallCount = getProfileCount(&I, nullptr))
|
||||
TotalCallCount += CallCount.getValue();
|
||||
if (!isColdCount(TotalCallCount))
|
||||
return false;
|
||||
}
|
||||
for (const auto &BB : *F)
|
||||
for (const auto &I : BB)
|
||||
if (isa<CallInst>(I) || isa<InvokeInst>(I))
|
||||
if (auto CallCount = getProfileCount(&I, nullptr))
|
||||
TotalCallCount += CallCount.getValue();
|
||||
return isColdCount(TotalCallCount);
|
||||
if (!isColdBB(&BB, &BFI))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Returns true if the function's entry is a cold. If it returns false, it
|
||||
@ -231,7 +251,7 @@ bool ProfileSummaryInfo::isColdCallSite(const CallSite &CS,
|
||||
// If there is no profile for the caller, and we know the profile is
|
||||
// accurate, we consider the callsite as cold.
|
||||
return (hasSampleProfile() &&
|
||||
(CS.getCaller()->getEntryCount() || ProfileSampleAccurate ||
|
||||
(CS.getCaller()->hasProfileData() || ProfileSampleAccurate ||
|
||||
CS.getCaller()->hasFnAttribute("profile-sample-accurate")));
|
||||
}
|
||||
|
||||
|
@ -4368,6 +4368,7 @@ static Optional<BinaryOp> MatchBinaryOp(Value *V, DominatorTree &DT) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
|
@ -314,6 +314,10 @@ int TargetTransformInfo::getIntImmCost(Intrinsic::ID IID, unsigned Idx,
|
||||
return Cost;
|
||||
}
|
||||
|
||||
bool TargetTransformInfo::isOutOfOrder() const {
|
||||
return TTIImpl->isOutOfOrder();
|
||||
}
|
||||
|
||||
unsigned TargetTransformInfo::getNumberOfRegisters(bool Vector) const {
|
||||
return TTIImpl->getNumberOfRegisters(Vector);
|
||||
}
|
||||
|
@ -544,21 +544,32 @@ static bool matchAccessTags(const MDNode *A, const MDNode *B,
|
||||
TBAAStructTagNode TagA(A), TagB(B);
|
||||
const MDNode *CommonType = getLeastCommonType(TagA.getAccessType(),
|
||||
TagB.getAccessType());
|
||||
if (GenericTag)
|
||||
*GenericTag = createAccessTag(CommonType);
|
||||
|
||||
// TODO: We need to check if AccessType of TagA encloses AccessType of
|
||||
// TagB to support aggregate AccessType. If yes, return true.
|
||||
|
||||
// Climb the type DAG from base type of A to see if we reach base type of B.
|
||||
uint64_t OffsetA;
|
||||
if (findAccessType(TagA, TagB.getBaseType(), OffsetA))
|
||||
return OffsetA == TagB.getOffset();
|
||||
if (findAccessType(TagA, TagB.getBaseType(), OffsetA)) {
|
||||
bool SameMemberAccess = OffsetA == TagB.getOffset();
|
||||
if (GenericTag)
|
||||
*GenericTag = SameMemberAccess ? TagB.getNode() :
|
||||
createAccessTag(CommonType);
|
||||
return SameMemberAccess;
|
||||
}
|
||||
|
||||
// Climb the type DAG from base type of B to see if we reach base type of A.
|
||||
uint64_t OffsetB;
|
||||
if (findAccessType(TagB, TagA.getBaseType(), OffsetB))
|
||||
return OffsetB == TagA.getOffset();
|
||||
if (findAccessType(TagB, TagA.getBaseType(), OffsetB)) {
|
||||
bool SameMemberAccess = OffsetB == TagA.getOffset();
|
||||
if (GenericTag)
|
||||
*GenericTag = SameMemberAccess ? TagA.getNode() :
|
||||
createAccessTag(CommonType);
|
||||
return SameMemberAccess;
|
||||
}
|
||||
|
||||
if (GenericTag)
|
||||
*GenericTag = createAccessTag(CommonType);
|
||||
|
||||
// If the final access types have different roots, they're part of different
|
||||
// potentially unrelated type systems, so we must be conservative.
|
||||
|
@ -3371,7 +3371,7 @@ void ModuleBitcodeWriterBase::writePerModuleFunctionSummaryRecord(
|
||||
for (auto &RI : FS->refs())
|
||||
NameVals.push_back(VE.getValueID(RI.getValue()));
|
||||
|
||||
bool HasProfileData = F.getEntryCount().hasValue();
|
||||
bool HasProfileData = F.hasProfileData();
|
||||
for (auto &ECI : FS->calls()) {
|
||||
NameVals.push_back(getValueId(ECI.first));
|
||||
if (HasProfileData)
|
||||
|
@ -2033,6 +2033,7 @@ const MCExpr *AsmPrinter::lowerConstant(const Constant *CV) {
|
||||
}
|
||||
}
|
||||
// else fallthrough
|
||||
LLVM_FALLTHROUGH;
|
||||
|
||||
// The MC library also has a right-shift operator, but it isn't consistently
|
||||
// signed or unsigned between different targets.
|
||||
|
@ -352,8 +352,6 @@ bool CodeGenPrepare::runOnFunction(Function &F) {
|
||||
// Clear per function information.
|
||||
InsertedInsts.clear();
|
||||
PromotedInsts.clear();
|
||||
BFI.reset();
|
||||
BPI.reset();
|
||||
|
||||
ModifiedDT = false;
|
||||
if (auto *TPC = getAnalysisIfAvailable<TargetPassConfig>()) {
|
||||
@ -365,14 +363,16 @@ bool CodeGenPrepare::runOnFunction(Function &F) {
|
||||
TLInfo = &getAnalysis<TargetLibraryInfoWrapperPass>().getTLI();
|
||||
TTI = &getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F);
|
||||
LI = &getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
|
||||
BPI.reset(new BranchProbabilityInfo(F, *LI));
|
||||
BFI.reset(new BlockFrequencyInfo(F, *BPI, *LI));
|
||||
OptSize = F.optForSize();
|
||||
|
||||
ProfileSummaryInfo *PSI =
|
||||
getAnalysis<ProfileSummaryInfoWrapperPass>().getPSI();
|
||||
if (ProfileGuidedSectionPrefix) {
|
||||
if (PSI->isFunctionHotInCallGraph(&F))
|
||||
if (PSI->isFunctionHotInCallGraph(&F, *BFI))
|
||||
F.setSectionPrefix(".hot");
|
||||
else if (PSI->isFunctionColdInCallGraph(&F))
|
||||
else if (PSI->isFunctionColdInCallGraph(&F, *BFI))
|
||||
F.setSectionPrefix(".unlikely");
|
||||
}
|
||||
|
||||
@ -652,13 +652,6 @@ bool CodeGenPrepare::isMergingEmptyBlockProfitable(BasicBlock *BB,
|
||||
if (SameIncomingValueBBs.count(Pred))
|
||||
return true;
|
||||
|
||||
if (!BFI) {
|
||||
Function &F = *BB->getParent();
|
||||
LoopInfo LI{DominatorTree(F)};
|
||||
BPI.reset(new BranchProbabilityInfo(F, LI));
|
||||
BFI.reset(new BlockFrequencyInfo(F, *BPI, LI));
|
||||
}
|
||||
|
||||
BlockFrequency PredFreq = BFI->getBlockFreq(Pred);
|
||||
BlockFrequency BBFreq = BFI->getBlockFreq(BB);
|
||||
|
||||
@ -3704,7 +3697,7 @@ bool AddressingModeMatcher::matchOperationAddr(User *AddrInst, unsigned Opcode,
|
||||
} else {
|
||||
uint64_t TypeSize = DL.getTypeAllocSize(GTI.getIndexedType());
|
||||
if (ConstantInt *CI = dyn_cast<ConstantInt>(AddrInst->getOperand(i))) {
|
||||
ConstantOffset += CI->getSExtValue()*TypeSize;
|
||||
ConstantOffset += CI->getSExtValue() * TypeSize;
|
||||
} else if (TypeSize) { // Scales of zero don't do anything.
|
||||
// We only allow one variable index at the moment.
|
||||
if (VariableOperand != -1)
|
||||
|
@ -835,6 +835,9 @@ LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT Ty) {
|
||||
case 64:
|
||||
ZeroTy = Type::getDoubleTy(Ctx);
|
||||
break;
|
||||
case 128:
|
||||
ZeroTy = Type::getFP128Ty(Ctx);
|
||||
break;
|
||||
default:
|
||||
llvm_unreachable("unexpected floating-point type");
|
||||
}
|
||||
|
@ -28,7 +28,7 @@
|
||||
#include "llvm/CodeGen/LiveInterval.h"
|
||||
#include "llvm/CodeGen/LiveIntervals.h"
|
||||
#include "llvm/CodeGen/LiveRangeEdit.h"
|
||||
#include "llvm/CodeGen/LiveStackAnalysis.h"
|
||||
#include "llvm/CodeGen/LiveStacks.h"
|
||||
#include "llvm/CodeGen/MachineBasicBlock.h"
|
||||
#include "llvm/CodeGen/MachineBlockFrequencyInfo.h"
|
||||
#include "llvm/CodeGen/MachineDominators.h"
|
||||
|
@ -81,10 +81,9 @@ LLVMTargetMachine::LLVMTargetMachine(const Target &T,
|
||||
this->OptLevel = OL;
|
||||
}
|
||||
|
||||
TargetIRAnalysis LLVMTargetMachine::getTargetIRAnalysis() {
|
||||
return TargetIRAnalysis([this](const Function &F) {
|
||||
return TargetTransformInfo(BasicTTIImpl(this, F));
|
||||
});
|
||||
TargetTransformInfo
|
||||
LLVMTargetMachine::getTargetTransformInfo(const Function &F) {
|
||||
return TargetTransformInfo(BasicTTIImpl(this, F));
|
||||
}
|
||||
|
||||
/// addPassesToX helper drives creation and initialization of TargetPassConfig.
|
||||
|
@ -1,4 +1,4 @@
|
||||
//===-- LiveStackAnalysis.cpp - Live Stack Slot Analysis ------------------===//
|
||||
//===-- LiveStacks.cpp - Live Stack Slot Analysis -------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -13,7 +13,7 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/CodeGen/LiveStackAnalysis.h"
|
||||
#include "llvm/CodeGen/LiveStacks.h"
|
||||
#include "llvm/CodeGen/LiveIntervals.h"
|
||||
#include "llvm/CodeGen/Passes.h"
|
||||
#include "llvm/CodeGen/TargetRegisterInfo.h"
|
@ -157,18 +157,14 @@ class MIPrinter {
|
||||
void print(const MachineBasicBlock &MBB);
|
||||
|
||||
void print(const MachineInstr &MI);
|
||||
void printIRBlockReference(const BasicBlock &BB);
|
||||
void printIRValueReference(const Value &V);
|
||||
void printStackObjectReference(int FrameIndex);
|
||||
void printOffset(int64_t Offset);
|
||||
void print(const MachineInstr &MI, unsigned OpIdx,
|
||||
const TargetRegisterInfo *TRI, bool ShouldPrintRegisterTies,
|
||||
LLT TypeToPrint, bool PrintDef = true);
|
||||
void print(const LLVMContext &Context, const TargetInstrInfo &TII,
|
||||
const MachineMemOperand &Op);
|
||||
void printSyncScope(const LLVMContext &Context, SyncScope::ID SSID);
|
||||
|
||||
void print(const MCCFIInstruction &CFI, const TargetRegisterInfo *TRI);
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
@ -707,32 +703,6 @@ void MIPrinter::print(const MachineInstr &MI) {
|
||||
}
|
||||
}
|
||||
|
||||
static void printIRSlotNumber(raw_ostream &OS, int Slot) {
|
||||
if (Slot == -1)
|
||||
OS << "<badref>";
|
||||
else
|
||||
OS << Slot;
|
||||
}
|
||||
|
||||
void MIPrinter::printIRBlockReference(const BasicBlock &BB) {
|
||||
OS << "%ir-block.";
|
||||
if (BB.hasName()) {
|
||||
printLLVMNameWithoutPrefix(OS, BB.getName());
|
||||
return;
|
||||
}
|
||||
const Function *F = BB.getParent();
|
||||
int Slot;
|
||||
if (F == MST.getCurrentFunction()) {
|
||||
Slot = MST.getLocalSlot(&BB);
|
||||
} else {
|
||||
ModuleSlotTracker CustomMST(F->getParent(),
|
||||
/*ShouldInitializeAllMetadata=*/false);
|
||||
CustomMST.incorporateFunction(*F);
|
||||
Slot = CustomMST.getLocalSlot(&BB);
|
||||
}
|
||||
printIRSlotNumber(OS, Slot);
|
||||
}
|
||||
|
||||
void MIPrinter::printIRValueReference(const Value &V) {
|
||||
if (isa<GlobalValue>(V)) {
|
||||
V.printAsOperand(OS, /*PrintType=*/false, MST);
|
||||
@ -750,7 +720,7 @@ void MIPrinter::printIRValueReference(const Value &V) {
|
||||
printLLVMNameWithoutPrefix(OS, V.getName());
|
||||
return;
|
||||
}
|
||||
printIRSlotNumber(OS, MST.getLocalSlot(&V));
|
||||
MachineOperand::printIRSlotNumber(OS, MST.getLocalSlot(&V));
|
||||
}
|
||||
|
||||
void MIPrinter::printStackObjectReference(int FrameIndex) {
|
||||
@ -762,16 +732,6 @@ void MIPrinter::printStackObjectReference(int FrameIndex) {
|
||||
Operand.Name);
|
||||
}
|
||||
|
||||
void MIPrinter::printOffset(int64_t Offset) {
|
||||
if (Offset == 0)
|
||||
return;
|
||||
if (Offset < 0) {
|
||||
OS << " - " << -Offset;
|
||||
return;
|
||||
}
|
||||
OS << " + " << Offset;
|
||||
}
|
||||
|
||||
void MIPrinter::print(const MachineInstr &MI, unsigned OpIdx,
|
||||
const TargetRegisterInfo *TRI,
|
||||
bool ShouldPrintRegisterTies, LLT TypeToPrint,
|
||||
@ -787,6 +747,7 @@ void MIPrinter::print(const MachineInstr &MI, unsigned OpIdx,
|
||||
LLVM_FALLTHROUGH;
|
||||
case MachineOperand::MO_Register:
|
||||
case MachineOperand::MO_CImmediate:
|
||||
case MachineOperand::MO_FPImmediate:
|
||||
case MachineOperand::MO_MachineBasicBlock:
|
||||
case MachineOperand::MO_ConstantPoolIndex:
|
||||
case MachineOperand::MO_TargetIndex:
|
||||
@ -795,7 +756,11 @@ void MIPrinter::print(const MachineInstr &MI, unsigned OpIdx,
|
||||
case MachineOperand::MO_GlobalAddress:
|
||||
case MachineOperand::MO_RegisterLiveOut:
|
||||
case MachineOperand::MO_Metadata:
|
||||
case MachineOperand::MO_MCSymbol: {
|
||||
case MachineOperand::MO_MCSymbol:
|
||||
case MachineOperand::MO_CFIIndex:
|
||||
case MachineOperand::MO_IntrinsicID:
|
||||
case MachineOperand::MO_Predicate:
|
||||
case MachineOperand::MO_BlockAddress: {
|
||||
unsigned TiedOperandIdx = 0;
|
||||
if (ShouldPrintRegisterTies && Op.isReg() && Op.isTied() && !Op.isDef())
|
||||
TiedOperandIdx = Op.getParent()->findTiedOperandIdx(OpIdx);
|
||||
@ -804,21 +769,9 @@ void MIPrinter::print(const MachineInstr &MI, unsigned OpIdx,
|
||||
TiedOperandIdx, TRI, TII);
|
||||
break;
|
||||
}
|
||||
case MachineOperand::MO_FPImmediate:
|
||||
Op.getFPImm()->printAsOperand(OS, /*PrintType=*/true, MST);
|
||||
break;
|
||||
case MachineOperand::MO_FrameIndex:
|
||||
printStackObjectReference(Op.getIndex());
|
||||
break;
|
||||
case MachineOperand::MO_BlockAddress:
|
||||
OS << "blockaddress(";
|
||||
Op.getBlockAddress()->getFunction()->printAsOperand(OS, /*PrintType=*/false,
|
||||
MST);
|
||||
OS << ", ";
|
||||
printIRBlockReference(*Op.getBlockAddress()->getBasicBlock());
|
||||
OS << ')';
|
||||
printOffset(Op.getOffset());
|
||||
break;
|
||||
case MachineOperand::MO_RegisterMask: {
|
||||
auto RegMaskInfo = RegisterMaskIds.find(Op.getRegMask());
|
||||
if (RegMaskInfo != RegisterMaskIds.end())
|
||||
@ -827,28 +780,6 @@ void MIPrinter::print(const MachineInstr &MI, unsigned OpIdx,
|
||||
printCustomRegMask(Op.getRegMask(), OS, TRI);
|
||||
break;
|
||||
}
|
||||
case MachineOperand::MO_CFIIndex: {
|
||||
const MachineFunction &MF = *Op.getParent()->getMF();
|
||||
print(MF.getFrameInstructions()[Op.getCFIIndex()], TRI);
|
||||
break;
|
||||
}
|
||||
case MachineOperand::MO_IntrinsicID: {
|
||||
Intrinsic::ID ID = Op.getIntrinsicID();
|
||||
if (ID < Intrinsic::num_intrinsics)
|
||||
OS << "intrinsic(@" << Intrinsic::getName(ID, None) << ')';
|
||||
else {
|
||||
const MachineFunction &MF = *Op.getParent()->getMF();
|
||||
const TargetIntrinsicInfo *TII = MF.getTarget().getIntrinsicInfo();
|
||||
OS << "intrinsic(@" << TII->getName(ID) << ')';
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MachineOperand::MO_Predicate: {
|
||||
auto Pred = static_cast<CmpInst::Predicate>(Op.getPredicate());
|
||||
OS << (CmpInst::isIntPredicate(Pred) ? "int" : "float") << "pred("
|
||||
<< CmpInst::getPredicateName(Pred) << ')';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -938,7 +869,7 @@ void MIPrinter::print(const LLVMContext &Context, const TargetInstrInfo &TII,
|
||||
break;
|
||||
}
|
||||
}
|
||||
printOffset(Op.getOffset());
|
||||
MachineOperand::printOperandOffset(OS, Op.getOffset());
|
||||
if (Op.getBaseAlignment() != Op.getSize())
|
||||
OS << ", align " << Op.getBaseAlignment();
|
||||
auto AAInfo = Op.getAAInfo();
|
||||
@ -978,118 +909,6 @@ void MIPrinter::printSyncScope(const LLVMContext &Context, SyncScope::ID SSID) {
|
||||
}
|
||||
}
|
||||
|
||||
static void printCFIRegister(unsigned DwarfReg, raw_ostream &OS,
|
||||
const TargetRegisterInfo *TRI) {
|
||||
int Reg = TRI->getLLVMRegNum(DwarfReg, true);
|
||||
if (Reg == -1) {
|
||||
OS << "<badreg>";
|
||||
return;
|
||||
}
|
||||
OS << printReg(Reg, TRI);
|
||||
}
|
||||
|
||||
void MIPrinter::print(const MCCFIInstruction &CFI,
|
||||
const TargetRegisterInfo *TRI) {
|
||||
switch (CFI.getOperation()) {
|
||||
case MCCFIInstruction::OpSameValue:
|
||||
OS << "same_value ";
|
||||
if (MCSymbol *Label = CFI.getLabel())
|
||||
MachineOperand::printSymbol(OS, *Label);
|
||||
printCFIRegister(CFI.getRegister(), OS, TRI);
|
||||
break;
|
||||
case MCCFIInstruction::OpRememberState:
|
||||
OS << "remember_state ";
|
||||
if (MCSymbol *Label = CFI.getLabel())
|
||||
MachineOperand::printSymbol(OS, *Label);
|
||||
break;
|
||||
case MCCFIInstruction::OpRestoreState:
|
||||
OS << "restore_state ";
|
||||
if (MCSymbol *Label = CFI.getLabel())
|
||||
MachineOperand::printSymbol(OS, *Label);
|
||||
break;
|
||||
case MCCFIInstruction::OpOffset:
|
||||
OS << "offset ";
|
||||
if (MCSymbol *Label = CFI.getLabel())
|
||||
MachineOperand::printSymbol(OS, *Label);
|
||||
printCFIRegister(CFI.getRegister(), OS, TRI);
|
||||
OS << ", " << CFI.getOffset();
|
||||
break;
|
||||
case MCCFIInstruction::OpDefCfaRegister:
|
||||
OS << "def_cfa_register ";
|
||||
if (MCSymbol *Label = CFI.getLabel())
|
||||
MachineOperand::printSymbol(OS, *Label);
|
||||
printCFIRegister(CFI.getRegister(), OS, TRI);
|
||||
break;
|
||||
case MCCFIInstruction::OpDefCfaOffset:
|
||||
OS << "def_cfa_offset ";
|
||||
if (MCSymbol *Label = CFI.getLabel())
|
||||
MachineOperand::printSymbol(OS, *Label);
|
||||
OS << CFI.getOffset();
|
||||
break;
|
||||
case MCCFIInstruction::OpDefCfa:
|
||||
OS << "def_cfa ";
|
||||
if (MCSymbol *Label = CFI.getLabel())
|
||||
MachineOperand::printSymbol(OS, *Label);
|
||||
printCFIRegister(CFI.getRegister(), OS, TRI);
|
||||
OS << ", " << CFI.getOffset();
|
||||
break;
|
||||
case MCCFIInstruction::OpRelOffset:
|
||||
OS << "rel_offset ";
|
||||
if (MCSymbol *Label = CFI.getLabel())
|
||||
MachineOperand::printSymbol(OS, *Label);
|
||||
printCFIRegister(CFI.getRegister(), OS, TRI);
|
||||
OS << ", " << CFI.getOffset();
|
||||
break;
|
||||
case MCCFIInstruction::OpAdjustCfaOffset:
|
||||
OS << "adjust_cfa_offset ";
|
||||
if (MCSymbol *Label = CFI.getLabel())
|
||||
MachineOperand::printSymbol(OS, *Label);
|
||||
OS << CFI.getOffset();
|
||||
break;
|
||||
case MCCFIInstruction::OpRestore:
|
||||
OS << "restore ";
|
||||
if (MCSymbol *Label = CFI.getLabel())
|
||||
MachineOperand::printSymbol(OS, *Label);
|
||||
printCFIRegister(CFI.getRegister(), OS, TRI);
|
||||
break;
|
||||
case MCCFIInstruction::OpEscape: {
|
||||
OS << "escape ";
|
||||
if (MCSymbol *Label = CFI.getLabel())
|
||||
MachineOperand::printSymbol(OS, *Label);
|
||||
if (!CFI.getValues().empty()) {
|
||||
size_t e = CFI.getValues().size() - 1;
|
||||
for (size_t i = 0; i < e; ++i)
|
||||
OS << format("0x%02x", uint8_t(CFI.getValues()[i])) << ", ";
|
||||
OS << format("0x%02x", uint8_t(CFI.getValues()[e])) << ", ";
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MCCFIInstruction::OpUndefined:
|
||||
OS << "undefined ";
|
||||
if (MCSymbol *Label = CFI.getLabel())
|
||||
MachineOperand::printSymbol(OS, *Label);
|
||||
printCFIRegister(CFI.getRegister(), OS, TRI);
|
||||
break;
|
||||
case MCCFIInstruction::OpRegister:
|
||||
OS << "register ";
|
||||
if (MCSymbol *Label = CFI.getLabel())
|
||||
MachineOperand::printSymbol(OS, *Label);
|
||||
printCFIRegister(CFI.getRegister(), OS, TRI);
|
||||
OS << ", ";
|
||||
printCFIRegister(CFI.getRegister2(), OS, TRI);
|
||||
break;
|
||||
case MCCFIInstruction::OpWindowSave:
|
||||
OS << "window_save ";
|
||||
if (MCSymbol *Label = CFI.getLabel())
|
||||
MachineOperand::printSymbol(OS, *Label);
|
||||
break;
|
||||
default:
|
||||
// TODO: Print the other CFI Operations.
|
||||
OS << "<unserializable cfi operation>";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void llvm::printMIR(raw_ostream &OS, const Module &M) {
|
||||
yaml::Output Out(OS);
|
||||
Out << const_cast<Module &>(M);
|
||||
|
@ -1235,7 +1235,7 @@ void MachineBlockPlacement::precomputeTriangleChains() {
|
||||
// When profile is available, we need to handle the triangle-shape CFG.
|
||||
static BranchProbability getLayoutSuccessorProbThreshold(
|
||||
const MachineBasicBlock *BB) {
|
||||
if (!BB->getParent()->getFunction().getEntryCount())
|
||||
if (!BB->getParent()->getFunction().hasProfileData())
|
||||
return BranchProbability(StaticLikelyProb, 100);
|
||||
if (BB->succ_size() == 2) {
|
||||
const MachineBasicBlock *Succ1 = *BB->succ_begin();
|
||||
@ -2178,7 +2178,7 @@ MachineBlockPlacement::collectLoopBlockSet(const MachineLoop &L) {
|
||||
// will be merged into the first outer loop chain for which this block is not
|
||||
// cold anymore. This needs precise profile data and we only do this when
|
||||
// profile data is available.
|
||||
if (F->getFunction().getEntryCount() || ForceLoopColdBlock) {
|
||||
if (F->getFunction().hasProfileData() || ForceLoopColdBlock) {
|
||||
BlockFrequency LoopFreq(0);
|
||||
for (auto LoopPred : L.getHeader()->predecessors())
|
||||
if (!L.contains(LoopPred))
|
||||
@ -2220,7 +2220,7 @@ void MachineBlockPlacement::buildLoopChains(const MachineLoop &L) {
|
||||
// for better layout.
|
||||
bool RotateLoopWithProfile =
|
||||
ForcePreciseRotationCost ||
|
||||
(PreciseRotationCost && F->getFunction().getEntryCount());
|
||||
(PreciseRotationCost && F->getFunction().hasProfileData());
|
||||
|
||||
// First check to see if there is an obviously preferable top block for the
|
||||
// loop. This will default to the header, but may end up as one of the
|
||||
|
@ -380,16 +380,6 @@ static void tryToGetTargetInfo(const MachineOperand &MO,
|
||||
}
|
||||
}
|
||||
|
||||
static void printOffset(raw_ostream &OS, int64_t Offset) {
|
||||
if (Offset == 0)
|
||||
return;
|
||||
if (Offset < 0) {
|
||||
OS << " - " << -Offset;
|
||||
return;
|
||||
}
|
||||
OS << " + " << Offset;
|
||||
}
|
||||
|
||||
static const char *getTargetIndexName(const MachineFunction &MF, int Index) {
|
||||
const auto *TII = MF.getSubtarget().getInstrInfo();
|
||||
assert(TII && "expected instruction info");
|
||||
@ -412,6 +402,44 @@ static const char *getTargetFlagName(const TargetInstrInfo *TII, unsigned TF) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void printCFIRegister(unsigned DwarfReg, raw_ostream &OS,
|
||||
const TargetRegisterInfo *TRI) {
|
||||
if (!TRI) {
|
||||
OS << "%dwarfreg." << DwarfReg;
|
||||
return;
|
||||
}
|
||||
|
||||
int Reg = TRI->getLLVMRegNum(DwarfReg, true);
|
||||
if (Reg == -1) {
|
||||
OS << "<badreg>";
|
||||
return;
|
||||
}
|
||||
OS << printReg(Reg, TRI);
|
||||
}
|
||||
|
||||
static void printIRBlockReference(raw_ostream &OS, const BasicBlock &BB,
|
||||
ModuleSlotTracker &MST) {
|
||||
OS << "%ir-block.";
|
||||
if (BB.hasName()) {
|
||||
printLLVMNameWithoutPrefix(OS, BB.getName());
|
||||
return;
|
||||
}
|
||||
Optional<int> Slot;
|
||||
if (const Function *F = BB.getParent()) {
|
||||
if (F == MST.getCurrentFunction()) {
|
||||
Slot = MST.getLocalSlot(&BB);
|
||||
} else if (const Module *M = F->getParent()) {
|
||||
ModuleSlotTracker CustomMST(M, /*ShouldInitializeAllMetadata=*/false);
|
||||
CustomMST.incorporateFunction(*F);
|
||||
Slot = CustomMST.getLocalSlot(&BB);
|
||||
}
|
||||
}
|
||||
if (Slot)
|
||||
MachineOperand::printIRSlotNumber(OS, *Slot);
|
||||
else
|
||||
OS << "<unknown>";
|
||||
}
|
||||
|
||||
void MachineOperand::printSubregIdx(raw_ostream &OS, uint64_t Index,
|
||||
const TargetRegisterInfo *TRI) {
|
||||
OS << "%subreg.";
|
||||
@ -490,6 +518,125 @@ void MachineOperand::printStackObjectReference(raw_ostream &OS,
|
||||
OS << '.' << Name;
|
||||
}
|
||||
|
||||
void MachineOperand::printOperandOffset(raw_ostream &OS, int64_t Offset) {
|
||||
if (Offset == 0)
|
||||
return;
|
||||
if (Offset < 0) {
|
||||
OS << " - " << -Offset;
|
||||
return;
|
||||
}
|
||||
OS << " + " << Offset;
|
||||
}
|
||||
|
||||
void MachineOperand::printIRSlotNumber(raw_ostream &OS, int Slot) {
|
||||
if (Slot == -1)
|
||||
OS << "<badref>";
|
||||
else
|
||||
OS << Slot;
|
||||
}
|
||||
|
||||
static void printCFI(raw_ostream &OS, const MCCFIInstruction &CFI,
|
||||
const TargetRegisterInfo *TRI) {
|
||||
switch (CFI.getOperation()) {
|
||||
case MCCFIInstruction::OpSameValue:
|
||||
OS << "same_value ";
|
||||
if (MCSymbol *Label = CFI.getLabel())
|
||||
MachineOperand::printSymbol(OS, *Label);
|
||||
printCFIRegister(CFI.getRegister(), OS, TRI);
|
||||
break;
|
||||
case MCCFIInstruction::OpRememberState:
|
||||
OS << "remember_state ";
|
||||
if (MCSymbol *Label = CFI.getLabel())
|
||||
MachineOperand::printSymbol(OS, *Label);
|
||||
break;
|
||||
case MCCFIInstruction::OpRestoreState:
|
||||
OS << "restore_state ";
|
||||
if (MCSymbol *Label = CFI.getLabel())
|
||||
MachineOperand::printSymbol(OS, *Label);
|
||||
break;
|
||||
case MCCFIInstruction::OpOffset:
|
||||
OS << "offset ";
|
||||
if (MCSymbol *Label = CFI.getLabel())
|
||||
MachineOperand::printSymbol(OS, *Label);
|
||||
printCFIRegister(CFI.getRegister(), OS, TRI);
|
||||
OS << ", " << CFI.getOffset();
|
||||
break;
|
||||
case MCCFIInstruction::OpDefCfaRegister:
|
||||
OS << "def_cfa_register ";
|
||||
if (MCSymbol *Label = CFI.getLabel())
|
||||
MachineOperand::printSymbol(OS, *Label);
|
||||
printCFIRegister(CFI.getRegister(), OS, TRI);
|
||||
break;
|
||||
case MCCFIInstruction::OpDefCfaOffset:
|
||||
OS << "def_cfa_offset ";
|
||||
if (MCSymbol *Label = CFI.getLabel())
|
||||
MachineOperand::printSymbol(OS, *Label);
|
||||
OS << CFI.getOffset();
|
||||
break;
|
||||
case MCCFIInstruction::OpDefCfa:
|
||||
OS << "def_cfa ";
|
||||
if (MCSymbol *Label = CFI.getLabel())
|
||||
MachineOperand::printSymbol(OS, *Label);
|
||||
printCFIRegister(CFI.getRegister(), OS, TRI);
|
||||
OS << ", " << CFI.getOffset();
|
||||
break;
|
||||
case MCCFIInstruction::OpRelOffset:
|
||||
OS << "rel_offset ";
|
||||
if (MCSymbol *Label = CFI.getLabel())
|
||||
MachineOperand::printSymbol(OS, *Label);
|
||||
printCFIRegister(CFI.getRegister(), OS, TRI);
|
||||
OS << ", " << CFI.getOffset();
|
||||
break;
|
||||
case MCCFIInstruction::OpAdjustCfaOffset:
|
||||
OS << "adjust_cfa_offset ";
|
||||
if (MCSymbol *Label = CFI.getLabel())
|
||||
MachineOperand::printSymbol(OS, *Label);
|
||||
OS << CFI.getOffset();
|
||||
break;
|
||||
case MCCFIInstruction::OpRestore:
|
||||
OS << "restore ";
|
||||
if (MCSymbol *Label = CFI.getLabel())
|
||||
MachineOperand::printSymbol(OS, *Label);
|
||||
printCFIRegister(CFI.getRegister(), OS, TRI);
|
||||
break;
|
||||
case MCCFIInstruction::OpEscape: {
|
||||
OS << "escape ";
|
||||
if (MCSymbol *Label = CFI.getLabel())
|
||||
MachineOperand::printSymbol(OS, *Label);
|
||||
if (!CFI.getValues().empty()) {
|
||||
size_t e = CFI.getValues().size() - 1;
|
||||
for (size_t i = 0; i < e; ++i)
|
||||
OS << format("0x%02x", uint8_t(CFI.getValues()[i])) << ", ";
|
||||
OS << format("0x%02x", uint8_t(CFI.getValues()[e])) << ", ";
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MCCFIInstruction::OpUndefined:
|
||||
OS << "undefined ";
|
||||
if (MCSymbol *Label = CFI.getLabel())
|
||||
MachineOperand::printSymbol(OS, *Label);
|
||||
printCFIRegister(CFI.getRegister(), OS, TRI);
|
||||
break;
|
||||
case MCCFIInstruction::OpRegister:
|
||||
OS << "register ";
|
||||
if (MCSymbol *Label = CFI.getLabel())
|
||||
MachineOperand::printSymbol(OS, *Label);
|
||||
printCFIRegister(CFI.getRegister(), OS, TRI);
|
||||
OS << ", ";
|
||||
printCFIRegister(CFI.getRegister2(), OS, TRI);
|
||||
break;
|
||||
case MCCFIInstruction::OpWindowSave:
|
||||
OS << "window_save ";
|
||||
if (MCSymbol *Label = CFI.getLabel())
|
||||
MachineOperand::printSymbol(OS, *Label);
|
||||
break;
|
||||
default:
|
||||
// TODO: Print the other CFI Operations.
|
||||
OS << "<unserializable cfi directive>";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void MachineOperand::print(raw_ostream &OS, const TargetRegisterInfo *TRI,
|
||||
const TargetIntrinsicInfo *IntrinsicInfo) const {
|
||||
tryToGetTargetInfo(*this, TRI, IntrinsicInfo);
|
||||
@ -561,29 +708,7 @@ void MachineOperand::print(raw_ostream &OS, ModuleSlotTracker &MST,
|
||||
getCImm()->printAsOperand(OS, /*PrintType=*/true, MST);
|
||||
break;
|
||||
case MachineOperand::MO_FPImmediate:
|
||||
if (getFPImm()->getType()->isFloatTy()) {
|
||||
OS << getFPImm()->getValueAPF().convertToFloat();
|
||||
} else if (getFPImm()->getType()->isHalfTy()) {
|
||||
APFloat APF = getFPImm()->getValueAPF();
|
||||
bool Unused;
|
||||
APF.convert(APFloat::IEEEsingle(), APFloat::rmNearestTiesToEven, &Unused);
|
||||
OS << "half " << APF.convertToFloat();
|
||||
} else if (getFPImm()->getType()->isFP128Ty()) {
|
||||
APFloat APF = getFPImm()->getValueAPF();
|
||||
SmallString<16> Str;
|
||||
getFPImm()->getValueAPF().toString(Str);
|
||||
OS << "quad " << Str;
|
||||
} else if (getFPImm()->getType()->isX86_FP80Ty()) {
|
||||
APFloat APF = getFPImm()->getValueAPF();
|
||||
OS << "x86_fp80 0xK";
|
||||
APInt API = APF.bitcastToAPInt();
|
||||
OS << format_hex_no_prefix(API.getHiBits(16).getZExtValue(), 4,
|
||||
/*Upper=*/true);
|
||||
OS << format_hex_no_prefix(API.getLoBits(64).getZExtValue(), 16,
|
||||
/*Upper=*/true);
|
||||
} else {
|
||||
OS << getFPImm()->getValueAPF().convertToDouble();
|
||||
}
|
||||
getFPImm()->printAsOperand(OS, /*PrintType=*/true, MST);
|
||||
break;
|
||||
case MachineOperand::MO_MachineBasicBlock:
|
||||
OS << printMBBReference(*getMBB());
|
||||
@ -606,7 +731,7 @@ void MachineOperand::print(raw_ostream &OS, ModuleSlotTracker &MST,
|
||||
}
|
||||
case MachineOperand::MO_ConstantPoolIndex:
|
||||
OS << "%const." << getIndex();
|
||||
printOffset(OS, getOffset());
|
||||
printOperandOffset(OS, getOffset());
|
||||
break;
|
||||
case MachineOperand::MO_TargetIndex: {
|
||||
OS << "target-index(";
|
||||
@ -615,7 +740,7 @@ void MachineOperand::print(raw_ostream &OS, ModuleSlotTracker &MST,
|
||||
if (const auto *TargetIndexName = getTargetIndexName(*MF, getIndex()))
|
||||
Name = TargetIndexName;
|
||||
OS << Name << ')';
|
||||
printOffset(OS, getOffset());
|
||||
printOperandOffset(OS, getOffset());
|
||||
break;
|
||||
}
|
||||
case MachineOperand::MO_JumpTableIndex:
|
||||
@ -623,7 +748,7 @@ void MachineOperand::print(raw_ostream &OS, ModuleSlotTracker &MST,
|
||||
break;
|
||||
case MachineOperand::MO_GlobalAddress:
|
||||
getGlobal()->printAsOperand(OS, /*PrintType=*/false, MST);
|
||||
printOffset(OS, getOffset());
|
||||
printOperandOffset(OS, getOffset());
|
||||
break;
|
||||
case MachineOperand::MO_ExternalSymbol: {
|
||||
StringRef Name = getSymbolName();
|
||||
@ -633,16 +758,19 @@ void MachineOperand::print(raw_ostream &OS, ModuleSlotTracker &MST,
|
||||
} else {
|
||||
printLLVMNameWithoutPrefix(OS, Name);
|
||||
}
|
||||
printOffset(OS, getOffset());
|
||||
printOperandOffset(OS, getOffset());
|
||||
break;
|
||||
}
|
||||
case MachineOperand::MO_BlockAddress:
|
||||
OS << '<';
|
||||
getBlockAddress()->printAsOperand(OS, /*PrintType=*/false, MST);
|
||||
if (getOffset())
|
||||
OS << "+" << getOffset();
|
||||
OS << '>';
|
||||
case MachineOperand::MO_BlockAddress: {
|
||||
OS << "blockaddress(";
|
||||
getBlockAddress()->getFunction()->printAsOperand(OS, /*PrintType=*/false,
|
||||
MST);
|
||||
OS << ", ";
|
||||
printIRBlockReference(OS, *getBlockAddress()->getBasicBlock(), MST);
|
||||
OS << ')';
|
||||
MachineOperand::printOperandOffset(OS, getOffset());
|
||||
break;
|
||||
}
|
||||
case MachineOperand::MO_RegisterMask: {
|
||||
OS << "<regmask";
|
||||
if (TRI) {
|
||||
@ -693,23 +821,27 @@ void MachineOperand::print(raw_ostream &OS, ModuleSlotTracker &MST,
|
||||
case MachineOperand::MO_MCSymbol:
|
||||
printSymbol(OS, *getMCSymbol());
|
||||
break;
|
||||
case MachineOperand::MO_CFIIndex:
|
||||
OS << "<call frame instruction>";
|
||||
case MachineOperand::MO_CFIIndex: {
|
||||
if (const MachineFunction *MF = getMFIfAvailable(*this))
|
||||
printCFI(OS, MF->getFrameInstructions()[getCFIIndex()], TRI);
|
||||
else
|
||||
OS << "<cfi directive>";
|
||||
break;
|
||||
}
|
||||
case MachineOperand::MO_IntrinsicID: {
|
||||
Intrinsic::ID ID = getIntrinsicID();
|
||||
if (ID < Intrinsic::num_intrinsics)
|
||||
OS << "<intrinsic:@" << Intrinsic::getName(ID, None) << '>';
|
||||
OS << "intrinsic(@" << Intrinsic::getName(ID, None) << ')';
|
||||
else if (IntrinsicInfo)
|
||||
OS << "<intrinsic:@" << IntrinsicInfo->getName(ID) << '>';
|
||||
OS << "intrinsic(@" << IntrinsicInfo->getName(ID) << ')';
|
||||
else
|
||||
OS << "<intrinsic:" << ID << '>';
|
||||
OS << "intrinsic(" << ID << ')';
|
||||
break;
|
||||
}
|
||||
case MachineOperand::MO_Predicate: {
|
||||
auto Pred = static_cast<CmpInst::Predicate>(getPredicate());
|
||||
OS << '<' << (CmpInst::isIntPredicate(Pred) ? "intpred" : "floatpred")
|
||||
<< CmpInst::getPredicateName(Pred) << '>';
|
||||
OS << (CmpInst::isIntPredicate(Pred) ? "int" : "float") << "pred("
|
||||
<< CmpInst::getPredicateName(Pred) << ')';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +37,7 @@
|
||||
#include "llvm/CodeGen/GlobalISel/RegisterBank.h"
|
||||
#include "llvm/CodeGen/LiveInterval.h"
|
||||
#include "llvm/CodeGen/LiveIntervals.h"
|
||||
#include "llvm/CodeGen/LiveStackAnalysis.h"
|
||||
#include "llvm/CodeGen/LiveStacks.h"
|
||||
#include "llvm/CodeGen/LiveVariables.h"
|
||||
#include "llvm/CodeGen/MachineBasicBlock.h"
|
||||
#include "llvm/CodeGen/MachineFrameInfo.h"
|
||||
|
@ -21,7 +21,7 @@
|
||||
#include "llvm/CodeGen/LiveIntervals.h"
|
||||
#include "llvm/CodeGen/LiveRangeEdit.h"
|
||||
#include "llvm/CodeGen/LiveRegMatrix.h"
|
||||
#include "llvm/CodeGen/LiveStackAnalysis.h"
|
||||
#include "llvm/CodeGen/LiveStacks.h"
|
||||
#include "llvm/CodeGen/MachineBlockFrequencyInfo.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/CodeGen/MachineInstr.h"
|
||||
|
@ -39,7 +39,7 @@
|
||||
#include "llvm/CodeGen/LiveIntervals.h"
|
||||
#include "llvm/CodeGen/LiveRangeEdit.h"
|
||||
#include "llvm/CodeGen/LiveRegMatrix.h"
|
||||
#include "llvm/CodeGen/LiveStackAnalysis.h"
|
||||
#include "llvm/CodeGen/LiveStacks.h"
|
||||
#include "llvm/CodeGen/MachineBasicBlock.h"
|
||||
#include "llvm/CodeGen/MachineBlockFrequencyInfo.h"
|
||||
#include "llvm/CodeGen/MachineDominators.h"
|
||||
|
@ -45,7 +45,7 @@
|
||||
#include "llvm/CodeGen/LiveInterval.h"
|
||||
#include "llvm/CodeGen/LiveIntervals.h"
|
||||
#include "llvm/CodeGen/LiveRangeEdit.h"
|
||||
#include "llvm/CodeGen/LiveStackAnalysis.h"
|
||||
#include "llvm/CodeGen/LiveStacks.h"
|
||||
#include "llvm/CodeGen/MachineBlockFrequencyInfo.h"
|
||||
#include "llvm/CodeGen/MachineDominators.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
|
@ -3988,10 +3988,12 @@ SDValue DAGCombiner::visitAND(SDNode *N) {
|
||||
if (SDValue RAND = ReassociateOps(ISD::AND, SDLoc(N), N0, N1))
|
||||
return RAND;
|
||||
// fold (and (or x, C), D) -> D if (C & D) == D
|
||||
if (N1C && N0.getOpcode() == ISD::OR)
|
||||
if (ConstantSDNode *ORI = isConstOrConstSplat(N0.getOperand(1)))
|
||||
if (N1C->getAPIntValue().isSubsetOf(ORI->getAPIntValue()))
|
||||
return N1;
|
||||
auto MatchSubset = [](ConstantSDNode *LHS, ConstantSDNode *RHS) {
|
||||
return RHS->getAPIntValue().isSubsetOf(LHS->getAPIntValue());
|
||||
};
|
||||
if (N0.getOpcode() == ISD::OR &&
|
||||
matchBinaryPredicate(N0.getOperand(1), N1, MatchSubset))
|
||||
return N1;
|
||||
// fold (and (any_ext V), c) -> (zero_ext V) if 'and' only clears top bits.
|
||||
if (N1C && N0.getOpcode() == ISD::ANY_EXTEND) {
|
||||
SDValue N0Op0 = N0.getOperand(0);
|
||||
@ -4675,16 +4677,16 @@ SDValue DAGCombiner::visitOR(SDNode *N) {
|
||||
|
||||
// Canonicalize (or (and X, c1), c2) -> (and (or X, c2), c1|c2)
|
||||
// iff (c1 & c2) != 0.
|
||||
if (N1C && N0.getOpcode() == ISD::AND && N0.getNode()->hasOneUse()) {
|
||||
if (ConstantSDNode *C1 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) {
|
||||
if (C1->getAPIntValue().intersects(N1C->getAPIntValue())) {
|
||||
if (SDValue COR =
|
||||
DAG.FoldConstantArithmetic(ISD::OR, SDLoc(N1), VT, N1C, C1))
|
||||
return DAG.getNode(
|
||||
ISD::AND, SDLoc(N), VT,
|
||||
DAG.getNode(ISD::OR, SDLoc(N0), VT, N0.getOperand(0), N1), COR);
|
||||
return SDValue();
|
||||
}
|
||||
auto MatchIntersect = [](ConstantSDNode *LHS, ConstantSDNode *RHS) {
|
||||
return LHS->getAPIntValue().intersects(RHS->getAPIntValue());
|
||||
};
|
||||
if (N0.getOpcode() == ISD::AND && N0.getNode()->hasOneUse() &&
|
||||
matchBinaryPredicate(N0.getOperand(1), N1, MatchIntersect)) {
|
||||
if (SDValue COR = DAG.FoldConstantArithmetic(
|
||||
ISD::OR, SDLoc(N1), VT, N1.getNode(), N0.getOperand(1).getNode())) {
|
||||
SDValue IOR = DAG.getNode(ISD::OR, SDLoc(N0), VT, N0.getOperand(0), N1);
|
||||
AddToWorklist(IOR.getNode());
|
||||
return DAG.getNode(ISD::AND, SDLoc(N), VT, COR, IOR);
|
||||
}
|
||||
}
|
||||
|
||||
@ -5380,21 +5382,6 @@ SDValue DAGCombiner::visitXOR(SDNode *N) {
|
||||
AddToWorklist(NotX.getNode());
|
||||
return DAG.getNode(ISD::AND, SDLoc(N), VT, NotX, N1);
|
||||
}
|
||||
// fold (xor (xor x, c1), c2) -> (xor x, (xor c1, c2))
|
||||
if (N1C && N0.getOpcode() == ISD::XOR) {
|
||||
if (const ConstantSDNode *N00C = getAsNonOpaqueConstant(N0.getOperand(0))) {
|
||||
SDLoc DL(N);
|
||||
return DAG.getNode(ISD::XOR, DL, VT, N0.getOperand(1),
|
||||
DAG.getConstant(N1C->getAPIntValue() ^
|
||||
N00C->getAPIntValue(), DL, VT));
|
||||
}
|
||||
if (const ConstantSDNode *N01C = getAsNonOpaqueConstant(N0.getOperand(1))) {
|
||||
SDLoc DL(N);
|
||||
return DAG.getNode(ISD::XOR, DL, VT, N0.getOperand(0),
|
||||
DAG.getConstant(N1C->getAPIntValue() ^
|
||||
N01C->getAPIntValue(), DL, VT));
|
||||
}
|
||||
}
|
||||
|
||||
// fold Y = sra (X, size(X)-1); xor (add (X, Y), Y) -> (abs X)
|
||||
unsigned OpSizeInBits = VT.getScalarSizeInBits();
|
||||
@ -10201,7 +10188,7 @@ SDValue DAGCombiner::visitFMUL(SDNode *N) {
|
||||
case ISD::SETLT:
|
||||
case ISD::SETLE:
|
||||
std::swap(TrueOpnd, FalseOpnd);
|
||||
// Fall through
|
||||
LLVM_FALLTHROUGH;
|
||||
case ISD::SETOGT:
|
||||
case ISD::SETUGT:
|
||||
case ISD::SETOGE:
|
||||
@ -10555,7 +10542,7 @@ static inline bool CanCombineFCOPYSIGN_EXTEND_ROUND(SDNode *N) {
|
||||
// value in one SSE register, but instruction selection cannot handle
|
||||
// FCOPYSIGN on SSE registers yet.
|
||||
EVT N1VT = N1->getValueType(0);
|
||||
EVT N1Op0VT = N1->getOperand(0)->getValueType(0);
|
||||
EVT N1Op0VT = N1->getOperand(0).getValueType();
|
||||
return (N1VT == N1Op0VT || N1Op0VT != MVT::f128);
|
||||
}
|
||||
return false;
|
||||
@ -13784,30 +13771,30 @@ SDValue DAGCombiner::visitSTORE(SDNode *N) {
|
||||
}
|
||||
}
|
||||
|
||||
if (StoreSDNode *ST1 = dyn_cast<StoreSDNode>(Chain)) {
|
||||
if (ST->isUnindexed() && !ST->isVolatile() && ST1->isUnindexed() &&
|
||||
!ST1->isVolatile() && ST1->getBasePtr() == Ptr &&
|
||||
ST->getMemoryVT() == ST1->getMemoryVT()) {
|
||||
// If this is a store followed by a store with the same value to the same
|
||||
// location, then the store is dead/noop.
|
||||
if (ST1->getValue() == Value) {
|
||||
// The store is dead, remove it.
|
||||
return Chain;
|
||||
}
|
||||
// Deal with elidable overlapping chained stores.
|
||||
if (StoreSDNode *ST1 = dyn_cast<StoreSDNode>(Chain))
|
||||
if (OptLevel != CodeGenOpt::None && ST->isUnindexed() &&
|
||||
ST1->isUnindexed() && !ST1->isVolatile() && ST1->hasOneUse() &&
|
||||
!ST1->getBasePtr().isUndef() && !ST->isVolatile()) {
|
||||
BaseIndexOffset STBasePtr = BaseIndexOffset::match(ST->getBasePtr(), DAG);
|
||||
BaseIndexOffset ST1BasePtr =
|
||||
BaseIndexOffset::match(ST1->getBasePtr(), DAG);
|
||||
unsigned STBytes = ST->getMemoryVT().getStoreSize();
|
||||
unsigned ST1Bytes = ST1->getMemoryVT().getStoreSize();
|
||||
int64_t PtrDiff;
|
||||
// If this is a store who's preceeding store to a subset of the same
|
||||
// memory and no one other node is chained to that store we can
|
||||
// effectively drop the store. Do not remove stores to undef as they may
|
||||
// be used as data sinks.
|
||||
|
||||
// If this is a store who's preceeding store to the same location
|
||||
// and no one other node is chained to that store we can effectively
|
||||
// drop the store. Do not remove stores to undef as they may be used as
|
||||
// data sinks.
|
||||
if (OptLevel != CodeGenOpt::None && ST1->hasOneUse() &&
|
||||
!ST1->getBasePtr().isUndef()) {
|
||||
// ST1 is fully overwritten and can be elided. Combine with it's chain
|
||||
// value.
|
||||
if (((ST->getBasePtr() == ST1->getBasePtr()) &&
|
||||
(ST->getValue() == ST1->getValue())) ||
|
||||
(STBasePtr.equalBaseIndex(ST1BasePtr, DAG, PtrDiff) &&
|
||||
(0 <= PtrDiff) && (PtrDiff + ST1Bytes <= STBytes))) {
|
||||
CombineTo(ST1, ST1->getChain());
|
||||
return SDValue();
|
||||
return SDValue(N, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If this is an FP_ROUND or TRUNC followed by a store, fold this into a
|
||||
// truncating store. We can do this even if this is already a truncstore.
|
||||
@ -15110,7 +15097,7 @@ SDValue DAGCombiner::visitCONCAT_VECTORS(SDNode *N) {
|
||||
|
||||
// Transform: concat_vectors(scalar, undef) -> scalar_to_vector(sclr).
|
||||
if (In->getOpcode() == ISD::BITCAST &&
|
||||
!In->getOperand(0)->getValueType(0).isVector()) {
|
||||
!In->getOperand(0).getValueType().isVector()) {
|
||||
SDValue Scalar = In->getOperand(0);
|
||||
|
||||
// If the bitcast type isn't legal, it might be a trunc of a legal type;
|
||||
@ -15157,7 +15144,7 @@ SDValue DAGCombiner::visitCONCAT_VECTORS(SDNode *N) {
|
||||
bool FoundMinVT = false;
|
||||
for (const SDValue &Op : N->ops())
|
||||
if (ISD::BUILD_VECTOR == Op.getOpcode()) {
|
||||
EVT OpSVT = Op.getOperand(0)->getValueType(0);
|
||||
EVT OpSVT = Op.getOperand(0).getValueType();
|
||||
MinVT = (!FoundMinVT || OpSVT.bitsLE(MinVT)) ? OpSVT : MinVT;
|
||||
FoundMinVT = true;
|
||||
}
|
||||
@ -17418,43 +17405,6 @@ SDValue DAGCombiner::buildSqrtEstimate(SDValue Op, SDNodeFlags Flags) {
|
||||
return buildSqrtEstimateImpl(Op, Flags, false);
|
||||
}
|
||||
|
||||
/// Return true if base is a frame index, which is known not to alias with
|
||||
/// anything but itself. Provides base object and offset as results.
|
||||
static bool findBaseOffset(SDValue Ptr, SDValue &Base, int64_t &Offset,
|
||||
const GlobalValue *&GV, const void *&CV) {
|
||||
// Assume it is a primitive operation.
|
||||
Base = Ptr; Offset = 0; GV = nullptr; CV = nullptr;
|
||||
|
||||
// If it's an adding a simple constant then integrate the offset.
|
||||
if (Base.getOpcode() == ISD::ADD) {
|
||||
if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Base.getOperand(1))) {
|
||||
Base = Base.getOperand(0);
|
||||
Offset += C->getSExtValue();
|
||||
}
|
||||
}
|
||||
|
||||
// Return the underlying GlobalValue, and update the Offset. Return false
|
||||
// for GlobalAddressSDNode since the same GlobalAddress may be represented
|
||||
// by multiple nodes with different offsets.
|
||||
if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Base)) {
|
||||
GV = G->getGlobal();
|
||||
Offset += G->getOffset();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Return the underlying Constant value, and update the Offset. Return false
|
||||
// for ConstantSDNodes since the same constant pool entry may be represented
|
||||
// by multiple nodes with different offsets.
|
||||
if (ConstantPoolSDNode *C = dyn_cast<ConstantPoolSDNode>(Base)) {
|
||||
CV = C->isMachineConstantPoolEntry() ? (const void *)C->getMachineCPVal()
|
||||
: (const void *)C->getConstVal();
|
||||
Offset += C->getOffset();
|
||||
return false;
|
||||
}
|
||||
// If it's any of the following then it can't alias with anything but itself.
|
||||
return isa<FrameIndexSDNode>(Base);
|
||||
}
|
||||
|
||||
/// Return true if there is any possibility that the two addresses overlap.
|
||||
bool DAGCombiner::isAlias(LSBaseSDNode *Op0, LSBaseSDNode *Op1) const {
|
||||
// If they are the same then they must be aliases.
|
||||
@ -17496,39 +17446,18 @@ bool DAGCombiner::isAlias(LSBaseSDNode *Op0, LSBaseSDNode *Op1) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
// FIXME: findBaseOffset and ConstantValue/GlobalValue/FrameIndex analysis
|
||||
// modified to use BaseIndexOffset.
|
||||
bool IsFI0 = isa<FrameIndexSDNode>(BasePtr0.getBase());
|
||||
bool IsFI1 = isa<FrameIndexSDNode>(BasePtr1.getBase());
|
||||
bool IsGV0 = isa<GlobalAddressSDNode>(BasePtr0.getBase());
|
||||
bool IsGV1 = isa<GlobalAddressSDNode>(BasePtr1.getBase());
|
||||
bool IsCV0 = isa<ConstantPoolSDNode>(BasePtr0.getBase());
|
||||
bool IsCV1 = isa<ConstantPoolSDNode>(BasePtr1.getBase());
|
||||
|
||||
// Gather base node and offset information.
|
||||
SDValue Base0, Base1;
|
||||
int64_t Offset0, Offset1;
|
||||
const GlobalValue *GV0, *GV1;
|
||||
const void *CV0, *CV1;
|
||||
bool IsFrameIndex0 = findBaseOffset(Op0->getBasePtr(),
|
||||
Base0, Offset0, GV0, CV0);
|
||||
bool IsFrameIndex1 = findBaseOffset(Op1->getBasePtr(),
|
||||
Base1, Offset1, GV1, CV1);
|
||||
|
||||
// If they have the same base address, then check to see if they overlap.
|
||||
if (Base0 == Base1 || (GV0 && (GV0 == GV1)) || (CV0 && (CV0 == CV1)))
|
||||
return !((Offset0 + NumBytes0) <= Offset1 ||
|
||||
(Offset1 + NumBytes1) <= Offset0);
|
||||
|
||||
// It is possible for different frame indices to alias each other, mostly
|
||||
// when tail call optimization reuses return address slots for arguments.
|
||||
// To catch this case, look up the actual index of frame indices to compute
|
||||
// the real alias relationship.
|
||||
if (IsFrameIndex0 && IsFrameIndex1) {
|
||||
MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo();
|
||||
Offset0 += MFI.getObjectOffset(cast<FrameIndexSDNode>(Base0)->getIndex());
|
||||
Offset1 += MFI.getObjectOffset(cast<FrameIndexSDNode>(Base1)->getIndex());
|
||||
return !((Offset0 + NumBytes0) <= Offset1 ||
|
||||
(Offset1 + NumBytes1) <= Offset0);
|
||||
}
|
||||
|
||||
// Otherwise, if we know what the bases are, and they aren't identical, then
|
||||
// we know they cannot alias.
|
||||
if ((IsFrameIndex0 || CV0 || GV0) && (IsFrameIndex1 || CV1 || GV1))
|
||||
// If of mismatched base types or checkable indices we can check
|
||||
// they do not alias.
|
||||
if ((BasePtr0.getIndex() == BasePtr1.getIndex() || (IsFI0 != IsFI1) ||
|
||||
(IsGV0 != IsGV1) || (IsCV0 != IsCV1)) &&
|
||||
(IsFI0 || IsGV0 || IsCV0) && (IsFI1 || IsGV1 || IsCV1))
|
||||
return false;
|
||||
|
||||
// If we know required SrcValue1 and SrcValue2 have relatively large alignment
|
||||
|
@ -1887,7 +1887,7 @@ SDValue DAGTypeLegalizer::PromoteFloatOp_STORE(SDNode *N, unsigned OpNo) {
|
||||
SDLoc DL(N);
|
||||
|
||||
SDValue Promoted = GetPromotedFloat(Val);
|
||||
EVT VT = ST->getOperand(1)->getValueType(0);
|
||||
EVT VT = ST->getOperand(1).getValueType();
|
||||
EVT IVT = EVT::getIntegerVT(*DAG.getContext(), VT.getSizeInBits());
|
||||
|
||||
SDValue NewVal;
|
||||
|
@ -224,7 +224,7 @@ bool DAGTypeLegalizer::run() {
|
||||
assert(N->getNodeId() == ReadyToProcess &&
|
||||
"Node should be ready if on worklist!");
|
||||
|
||||
DEBUG(dbgs() << "Legalizing node: "; N->dump());
|
||||
DEBUG(dbgs() << "Legalizing node: "; N->dump(&DAG));
|
||||
if (IgnoreNodeResults(N)) {
|
||||
DEBUG(dbgs() << "Ignoring node results\n");
|
||||
goto ScanOperands;
|
||||
@ -296,7 +296,7 @@ bool DAGTypeLegalizer::run() {
|
||||
continue;
|
||||
|
||||
const auto Op = N->getOperand(i);
|
||||
DEBUG(dbgs() << "Analyzing operand: "; Op.dump());
|
||||
DEBUG(dbgs() << "Analyzing operand: "; Op.dump(&DAG));
|
||||
EVT OpVT = Op.getValueType();
|
||||
switch (getTypeAction(OpVT)) {
|
||||
case TargetLowering::TypeLegal:
|
||||
@ -445,7 +445,7 @@ bool DAGTypeLegalizer::run() {
|
||||
if (!isTypeLegal(Node.getValueType(i)) &&
|
||||
!TLI.isTypeLegal(Node.getValueType(i))) {
|
||||
dbgs() << "Result type " << i << " illegal: ";
|
||||
Node.dump();
|
||||
Node.dump(&DAG);
|
||||
Failed = true;
|
||||
}
|
||||
|
||||
@ -455,7 +455,7 @@ bool DAGTypeLegalizer::run() {
|
||||
!isTypeLegal(Node.getOperand(i).getValueType()) &&
|
||||
!TLI.isTypeLegal(Node.getOperand(i).getValueType())) {
|
||||
dbgs() << "Operand type " << i << " illegal: ";
|
||||
Node.getOperand(i).dump();
|
||||
Node.getOperand(i).dump(&DAG);
|
||||
Failed = true;
|
||||
}
|
||||
|
||||
|
@ -331,7 +331,7 @@ SDValue DAGTypeLegalizer::ScalarizeVecRes_VSELECT(SDNode *N) {
|
||||
// At least try the common case where the boolean is generated by a
|
||||
// comparison.
|
||||
if (Cond->getOpcode() == ISD::SETCC) {
|
||||
EVT OpVT = Cond->getOperand(0)->getValueType(0);
|
||||
EVT OpVT = Cond->getOperand(0).getValueType();
|
||||
ScalarBool = TLI.getBooleanContents(OpVT.getScalarType());
|
||||
VecBool = TLI.getBooleanContents(OpVT);
|
||||
} else
|
||||
@ -1548,14 +1548,14 @@ bool DAGTypeLegalizer::SplitVectorOperand(SDNode *N, unsigned OpNo) {
|
||||
break;
|
||||
case ISD::FP_TO_SINT:
|
||||
case ISD::FP_TO_UINT:
|
||||
if (N->getValueType(0).bitsLT(N->getOperand(0)->getValueType(0)))
|
||||
if (N->getValueType(0).bitsLT(N->getOperand(0).getValueType()))
|
||||
Res = SplitVecOp_TruncateHelper(N);
|
||||
else
|
||||
Res = SplitVecOp_UnaryOp(N);
|
||||
break;
|
||||
case ISD::SINT_TO_FP:
|
||||
case ISD::UINT_TO_FP:
|
||||
if (N->getValueType(0).bitsLT(N->getOperand(0)->getValueType(0)))
|
||||
if (N->getValueType(0).bitsLT(N->getOperand(0).getValueType()))
|
||||
Res = SplitVecOp_TruncateHelper(N);
|
||||
else
|
||||
Res = SplitVecOp_UnaryOp(N);
|
||||
|
@ -252,6 +252,7 @@ bool ResourcePriorityQueue::isResourceAvailable(SUnit *SU) {
|
||||
if (!ResourcesModel->canReserveResources(&TII->get(
|
||||
SU->getNode()->getMachineOpcode())))
|
||||
return false;
|
||||
break;
|
||||
case TargetOpcode::EXTRACT_SUBREG:
|
||||
case TargetOpcode::INSERT_SUBREG:
|
||||
case TargetOpcode::SUBREG_TO_REG:
|
||||
|
@ -3750,6 +3750,9 @@ SDValue SelectionDAG::getNode(unsigned Opcode, const SDLoc &DL, EVT VT,
|
||||
case ISD::FP_TO_SINT:
|
||||
case ISD::FP_TO_UINT:
|
||||
case ISD::TRUNCATE:
|
||||
case ISD::ANY_EXTEND:
|
||||
case ISD::ZERO_EXTEND:
|
||||
case ISD::SIGN_EXTEND:
|
||||
case ISD::UINT_TO_FP:
|
||||
case ISD::SINT_TO_FP:
|
||||
case ISD::ABS:
|
||||
|
@ -37,6 +37,23 @@ bool BaseIndexOffset::equalBaseIndex(BaseIndexOffset &Other,
|
||||
return true;
|
||||
}
|
||||
|
||||
// Match Constants
|
||||
if (auto *A = dyn_cast<ConstantPoolSDNode>(Base))
|
||||
if (auto *B = dyn_cast<ConstantPoolSDNode>(Other.Base)) {
|
||||
bool IsMatch =
|
||||
A->isMachineConstantPoolEntry() == B->isMachineConstantPoolEntry();
|
||||
if (IsMatch) {
|
||||
if (A->isMachineConstantPoolEntry())
|
||||
IsMatch = A->getMachineCPVal() == B->getMachineCPVal();
|
||||
else
|
||||
IsMatch = A->getConstVal() == B->getConstVal();
|
||||
}
|
||||
if (IsMatch) {
|
||||
Off += B->getOffset() - A->getOffset();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
const MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo();
|
||||
|
||||
// Match non-equal FrameIndexes - If both frame indices are fixed
|
||||
|
@ -3117,7 +3117,16 @@ void SelectionDAGISel::SelectCodeCommon(SDNode *NodeToMatch,
|
||||
continue;
|
||||
}
|
||||
case OPC_RecordMemRef:
|
||||
MatchedMemRefs.push_back(cast<MemSDNode>(N)->getMemOperand());
|
||||
if (auto *MN = dyn_cast<MemSDNode>(N))
|
||||
MatchedMemRefs.push_back(MN->getMemOperand());
|
||||
else {
|
||||
DEBUG(
|
||||
dbgs() << "Expected MemSDNode ";
|
||||
N->dump(CurDAG);
|
||||
dbgs() << '\n'
|
||||
);
|
||||
}
|
||||
|
||||
continue;
|
||||
|
||||
case OPC_CaptureGlueInput:
|
||||
@ -3563,7 +3572,7 @@ void SelectionDAGISel::SelectCodeCommon(SDNode *NodeToMatch,
|
||||
Ops.push_back(InputGlue);
|
||||
|
||||
// Create the node.
|
||||
SDNode *Res = nullptr;
|
||||
MachineSDNode *Res = nullptr;
|
||||
bool IsMorphNodeTo = Opcode == OPC_MorphNodeTo ||
|
||||
(Opcode >= OPC_MorphNodeTo0 && Opcode <= OPC_MorphNodeTo2);
|
||||
if (!IsMorphNodeTo) {
|
||||
@ -3589,7 +3598,8 @@ void SelectionDAGISel::SelectCodeCommon(SDNode *NodeToMatch,
|
||||
"Chain node replaced during MorphNode");
|
||||
Chain.erase(std::remove(Chain.begin(), Chain.end(), N), Chain.end());
|
||||
});
|
||||
Res = MorphNode(NodeToMatch, TargetOpc, VTList, Ops, EmitNodeInfo);
|
||||
Res = cast<MachineSDNode>(MorphNode(NodeToMatch, TargetOpc, VTList,
|
||||
Ops, EmitNodeInfo));
|
||||
}
|
||||
|
||||
// If the node had chain/glue results, update our notion of the current
|
||||
@ -3645,13 +3655,19 @@ void SelectionDAGISel::SelectCodeCommon(SDNode *NodeToMatch,
|
||||
}
|
||||
}
|
||||
|
||||
cast<MachineSDNode>(Res)
|
||||
->setMemRefs(MemRefs, MemRefs + NumMemRefs);
|
||||
Res->setMemRefs(MemRefs, MemRefs + NumMemRefs);
|
||||
}
|
||||
|
||||
DEBUG(dbgs() << " "
|
||||
<< (IsMorphNodeTo ? "Morphed" : "Created")
|
||||
<< " node: "; Res->dump(CurDAG); dbgs() << "\n");
|
||||
DEBUG(
|
||||
if (!MatchedMemRefs.empty() && Res->memoperands_empty())
|
||||
dbgs() << " Dropping mem operands\n";
|
||||
dbgs() << " "
|
||||
<< (IsMorphNodeTo ? "Morphed" : "Created")
|
||||
<< " node: ";
|
||||
Res->dump(CurDAG);
|
||||
|
||||
dbgs() << '\n';
|
||||
);
|
||||
|
||||
// If this was a MorphNodeTo then we're completely done!
|
||||
if (IsMorphNodeTo) {
|
||||
|
@ -3812,7 +3812,7 @@ SDValue TargetLowering::getVectorElementPointer(SelectionDAG &DAG,
|
||||
|
||||
Index = DAG.getNode(ISD::MUL, dl, IdxVT, Index,
|
||||
DAG.getConstant(EltSize, dl, IdxVT));
|
||||
return DAG.getNode(ISD::ADD, dl, IdxVT, Index, VecPtr);
|
||||
return DAG.getNode(ISD::ADD, dl, IdxVT, VecPtr, Index);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -16,7 +16,7 @@
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include "llvm/CodeGen/LiveInterval.h"
|
||||
#include "llvm/CodeGen/LiveIntervals.h"
|
||||
#include "llvm/CodeGen/LiveStackAnalysis.h"
|
||||
#include "llvm/CodeGen/LiveStacks.h"
|
||||
#include "llvm/CodeGen/MachineBasicBlock.h"
|
||||
#include "llvm/CodeGen/MachineBlockFrequencyInfo.h"
|
||||
#include "llvm/CodeGen/MachineFrameInfo.h"
|
||||
|
@ -89,6 +89,21 @@ static cl::opt<unsigned> OptsizeJumpTableDensity(
|
||||
cl::desc("Minimum density for building a jump table in "
|
||||
"an optsize function"));
|
||||
|
||||
static bool darwinHasSinCos(const Triple &TT) {
|
||||
assert(TT.isOSDarwin() && "should be called with darwin triple");
|
||||
// Don't bother with 32 bit x86.
|
||||
if (TT.getArch() == Triple::x86)
|
||||
return false;
|
||||
// Macos < 10.9 has no sincos_stret.
|
||||
if (TT.isMacOSX())
|
||||
return !TT.isMacOSXVersionLT(10, 9) && TT.isArch64Bit();
|
||||
// iOS < 7.0 has no sincos_stret.
|
||||
if (TT.isiOS())
|
||||
return !TT.isOSVersionLT(7, 0);
|
||||
// Any other darwin such as WatchOS/TvOS is new enough.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Although this default value is arbitrary, it is not random. It is assumed
|
||||
// that a condition that evaluates the same way by a higher percentage than this
|
||||
// is best represented as control flow. Therefore, the default value N should be
|
||||
@ -100,44 +115,56 @@ static cl::opt<int> MinPercentageForPredictableBranch(
|
||||
"or false to assume that the condition is predictable"),
|
||||
cl::Hidden);
|
||||
|
||||
/// InitLibcallNames - Set default libcall names.
|
||||
static void InitLibcallNames(const char **Names, const Triple &TT) {
|
||||
void TargetLoweringBase::InitLibcalls(const Triple &TT) {
|
||||
#define HANDLE_LIBCALL(code, name) \
|
||||
Names[RTLIB::code] = name;
|
||||
setLibcallName(RTLIB::code, name);
|
||||
#include "llvm/CodeGen/RuntimeLibcalls.def"
|
||||
#undef HANDLE_LIBCALL
|
||||
// Initialize calling conventions to their default.
|
||||
for (int LC = 0; LC < RTLIB::UNKNOWN_LIBCALL; ++LC)
|
||||
setLibcallCallingConv((RTLIB::Libcall)LC, CallingConv::C);
|
||||
|
||||
// A few names are different on particular architectures or environments.
|
||||
if (TT.isOSDarwin()) {
|
||||
// For f16/f32 conversions, Darwin uses the standard naming scheme, instead
|
||||
// of the gnueabi-style __gnu_*_ieee.
|
||||
// FIXME: What about other targets?
|
||||
Names[RTLIB::FPEXT_F16_F32] = "__extendhfsf2";
|
||||
Names[RTLIB::FPROUND_F32_F16] = "__truncsfhf2";
|
||||
setLibcallName(RTLIB::FPEXT_F16_F32, "__extendhfsf2");
|
||||
setLibcallName(RTLIB::FPROUND_F32_F16, "__truncsfhf2");
|
||||
|
||||
// Darwin 10 and higher has an optimized __bzero.
|
||||
if (!TT.isMacOSX() || !TT.isMacOSXVersionLT(10, 6) || TT.isArch64Bit()) {
|
||||
setLibcallName(RTLIB::BZERO, TT.isAArch64() ? "bzero" : "__bzero");
|
||||
}
|
||||
|
||||
if (darwinHasSinCos(TT)) {
|
||||
setLibcallName(RTLIB::SINCOS_STRET_F32, "__sincosf_stret");
|
||||
setLibcallName(RTLIB::SINCOS_STRET_F64, "__sincos_stret");
|
||||
if (TT.isWatchABI()) {
|
||||
setLibcallCallingConv(RTLIB::SINCOS_STRET_F32,
|
||||
CallingConv::ARM_AAPCS_VFP);
|
||||
setLibcallCallingConv(RTLIB::SINCOS_STRET_F64,
|
||||
CallingConv::ARM_AAPCS_VFP);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Names[RTLIB::FPEXT_F16_F32] = "__gnu_h2f_ieee";
|
||||
Names[RTLIB::FPROUND_F32_F16] = "__gnu_f2h_ieee";
|
||||
setLibcallName(RTLIB::FPEXT_F16_F32, "__gnu_h2f_ieee");
|
||||
setLibcallName(RTLIB::FPROUND_F32_F16, "__gnu_f2h_ieee");
|
||||
}
|
||||
|
||||
if (TT.isGNUEnvironment() || TT.isOSFuchsia()) {
|
||||
Names[RTLIB::SINCOS_F32] = "sincosf";
|
||||
Names[RTLIB::SINCOS_F64] = "sincos";
|
||||
Names[RTLIB::SINCOS_F80] = "sincosl";
|
||||
Names[RTLIB::SINCOS_F128] = "sincosl";
|
||||
Names[RTLIB::SINCOS_PPCF128] = "sincosl";
|
||||
setLibcallName(RTLIB::SINCOS_F32, "sincosf");
|
||||
setLibcallName(RTLIB::SINCOS_F64, "sincos");
|
||||
setLibcallName(RTLIB::SINCOS_F80, "sincosl");
|
||||
setLibcallName(RTLIB::SINCOS_F128, "sincosl");
|
||||
setLibcallName(RTLIB::SINCOS_PPCF128, "sincosl");
|
||||
}
|
||||
|
||||
if (TT.isOSOpenBSD()) {
|
||||
Names[RTLIB::STACKPROTECTOR_CHECK_FAIL] = nullptr;
|
||||
setLibcallName(RTLIB::STACKPROTECTOR_CHECK_FAIL, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
/// Set default libcall CallingConvs.
|
||||
static void InitLibcallCallingConvs(CallingConv::ID *CCs) {
|
||||
for (int LC = 0; LC < RTLIB::UNKNOWN_LIBCALL; ++LC)
|
||||
CCs[LC] = CallingConv::C;
|
||||
}
|
||||
|
||||
/// getFPEXT - Return the FPEXT_*_* value for the given types, or
|
||||
/// UNKNOWN_LIBCALL if there is none.
|
||||
RTLIB::Libcall RTLIB::getFPEXT(EVT OpVT, EVT RetVT) {
|
||||
@ -524,9 +551,8 @@ TargetLoweringBase::TargetLoweringBase(const TargetMachine &tm) : TM(tm) {
|
||||
|
||||
std::fill(std::begin(LibcallRoutineNames), std::end(LibcallRoutineNames), nullptr);
|
||||
|
||||
InitLibcallNames(LibcallRoutineNames, TM.getTargetTriple());
|
||||
InitLibcalls(TM.getTargetTriple());
|
||||
InitCmpLibcallCCs(CmpLibcallCCs);
|
||||
InitLibcallCallingConvs(LibcallCallingConvs);
|
||||
}
|
||||
|
||||
void TargetLoweringBase::initActions() {
|
||||
|
@ -22,7 +22,7 @@
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include "llvm/CodeGen/LiveInterval.h"
|
||||
#include "llvm/CodeGen/LiveIntervals.h"
|
||||
#include "llvm/CodeGen/LiveStackAnalysis.h"
|
||||
#include "llvm/CodeGen/LiveStacks.h"
|
||||
#include "llvm/CodeGen/MachineBasicBlock.h"
|
||||
#include "llvm/CodeGen/MachineFrameInfo.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
|
@ -83,6 +83,7 @@ bool DWARFAcceleratorTable::validateForms() {
|
||||
!FormValue.isFormClass(DWARFFormValue::FC_Flag)) ||
|
||||
FormValue.getForm() == dwarf::DW_FORM_sdata)
|
||||
return false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -88,70 +88,101 @@ static void dumpUUID(raw_ostream &OS, const ObjectFile &Obj) {
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dumpDWARFv5StringOffsetsSection(raw_ostream &OS, StringRef SectionName,
|
||||
const DWARFObject &Obj,
|
||||
const DWARFSection &StringOffsetsSection,
|
||||
StringRef StringSection, bool LittleEndian) {
|
||||
using ContributionCollection =
|
||||
std::vector<Optional<StrOffsetsContributionDescriptor>>;
|
||||
|
||||
// Collect all the contributions to the string offsets table from all units,
|
||||
// sort them by their starting offsets and remove duplicates.
|
||||
static ContributionCollection
|
||||
collectContributionData(DWARFContext::cu_iterator_range CUs,
|
||||
DWARFContext::tu_section_iterator_range TUSs) {
|
||||
ContributionCollection Contributions;
|
||||
for (const auto &CU : CUs)
|
||||
Contributions.push_back(CU->getStringOffsetsTableContribution());
|
||||
for (const auto &TUS : TUSs)
|
||||
for (const auto &TU : TUS)
|
||||
Contributions.push_back(TU->getStringOffsetsTableContribution());
|
||||
|
||||
// Sort the contributions so that any invalid ones are placed at
|
||||
// the start of the contributions vector. This way they are reported
|
||||
// first.
|
||||
std::sort(Contributions.begin(), Contributions.end(),
|
||||
[](const Optional<StrOffsetsContributionDescriptor> &L,
|
||||
const Optional<StrOffsetsContributionDescriptor> &R) {
|
||||
if (L && R) return L->Base < R->Base;
|
||||
return R.hasValue();
|
||||
});
|
||||
|
||||
// Uniquify contributions, as it is possible that units (specifically
|
||||
// type units in dwo or dwp files) share contributions. We don't want
|
||||
// to report them more than once.
|
||||
Contributions.erase(
|
||||
std::unique(Contributions.begin(), Contributions.end(),
|
||||
[](const Optional<StrOffsetsContributionDescriptor> &L,
|
||||
const Optional<StrOffsetsContributionDescriptor> &R) {
|
||||
if (L && R)
|
||||
return L->Base == R->Base && L->Size == R->Size;
|
||||
return false;
|
||||
}),
|
||||
Contributions.end());
|
||||
return Contributions;
|
||||
}
|
||||
|
||||
static void dumpDWARFv5StringOffsetsSection(
|
||||
raw_ostream &OS, StringRef SectionName, const DWARFObject &Obj,
|
||||
const DWARFSection &StringOffsetsSection, StringRef StringSection,
|
||||
DWARFContext::cu_iterator_range CUs,
|
||||
DWARFContext::tu_section_iterator_range TUSs, bool LittleEndian) {
|
||||
auto Contributions = collectContributionData(CUs, TUSs);
|
||||
DWARFDataExtractor StrOffsetExt(Obj, StringOffsetsSection, LittleEndian, 0);
|
||||
uint32_t Offset = 0;
|
||||
DataExtractor StrData(StringSection, LittleEndian, 0);
|
||||
uint64_t SectionSize = StringOffsetsSection.Data.size();
|
||||
|
||||
while (Offset < SectionSize) {
|
||||
unsigned Version = 0;
|
||||
DwarfFormat Format = DWARF32;
|
||||
unsigned EntrySize = 4;
|
||||
// Perform validation and extract the segment size from the header.
|
||||
if (!StrOffsetExt.isValidOffsetForDataOfSize(Offset, 4)) {
|
||||
OS << "error: invalid contribution to string offsets table in section ."
|
||||
<< SectionName << ".\n";
|
||||
return;
|
||||
}
|
||||
uint32_t ContributionStart = Offset;
|
||||
uint64_t ContributionSize = StrOffsetExt.getU32(&Offset);
|
||||
// A contribution size of 0xffffffff indicates DWARF64, with the actual size
|
||||
// in the following 8 bytes. Otherwise, the DWARF standard mandates that
|
||||
// the contribution size must be at most 0xfffffff0.
|
||||
if (ContributionSize == 0xffffffff) {
|
||||
if (!StrOffsetExt.isValidOffsetForDataOfSize(Offset, 8)) {
|
||||
OS << "error: invalid contribution to string offsets table in section ."
|
||||
<< SectionName << ".\n";
|
||||
return;
|
||||
}
|
||||
Format = DWARF64;
|
||||
EntrySize = 8;
|
||||
ContributionSize = StrOffsetExt.getU64(&Offset);
|
||||
} else if (ContributionSize > 0xfffffff0) {
|
||||
uint32_t Offset = 0;
|
||||
for (auto &Contribution : Contributions) {
|
||||
// Report an ill-formed contribution.
|
||||
if (!Contribution) {
|
||||
OS << "error: invalid contribution to string offsets table in section ."
|
||||
<< SectionName << ".\n";
|
||||
return;
|
||||
}
|
||||
|
||||
// We must ensure that we don't read a partial record at the end, so we
|
||||
// validate for a multiple of EntrySize. Also, we're expecting a version
|
||||
// number and padding, which adds an additional 4 bytes.
|
||||
uint64_t ValidationSize =
|
||||
4 + ((ContributionSize + EntrySize - 1) & (-(uint64_t)EntrySize));
|
||||
if (!StrOffsetExt.isValidOffsetForDataOfSize(Offset, ValidationSize)) {
|
||||
OS << "error: contribution to string offsets table in section ."
|
||||
<< SectionName << " has invalid length.\n";
|
||||
dwarf::DwarfFormat Format = Contribution->getFormat();
|
||||
uint16_t Version = Contribution->getVersion();
|
||||
uint64_t ContributionHeader = Contribution->Base;
|
||||
// In DWARF v5 there is a contribution header that immediately precedes
|
||||
// the string offsets base (the location we have previously retrieved from
|
||||
// the CU DIE's DW_AT_str_offsets attribute). The header is located either
|
||||
// 8 or 16 bytes before the base, depending on the contribution's format.
|
||||
if (Version >= 5)
|
||||
ContributionHeader -= Format == DWARF32 ? 8 : 16;
|
||||
|
||||
// Detect overlapping contributions.
|
||||
if (Offset > ContributionHeader) {
|
||||
OS << "error: overlapping contributions to string offsets table in "
|
||||
"section ."
|
||||
<< SectionName << ".\n";
|
||||
return;
|
||||
}
|
||||
|
||||
Version = StrOffsetExt.getU16(&Offset);
|
||||
Offset += 2;
|
||||
OS << format("0x%8.8x: ", ContributionStart);
|
||||
OS << "Contribution size = " << ContributionSize
|
||||
// Report a gap in the table.
|
||||
if (Offset < ContributionHeader) {
|
||||
OS << format("0x%8.8x: Gap, length = ", Offset);
|
||||
OS << (ContributionHeader - Offset) << "\n";
|
||||
}
|
||||
OS << format("0x%8.8x: ", (uint32_t)ContributionHeader);
|
||||
OS << "Contribution size = " << Contribution->Size
|
||||
<< ", Format = " << (Format == DWARF32 ? "DWARF32" : "DWARF64")
|
||||
<< ", Version = " << Version << "\n";
|
||||
|
||||
uint32_t ContributionBase = Offset;
|
||||
DataExtractor StrData(StringSection, LittleEndian, 0);
|
||||
while (Offset - ContributionBase < ContributionSize) {
|
||||
Offset = Contribution->Base;
|
||||
unsigned EntrySize = Contribution->getDwarfOffsetByteSize();
|
||||
while (Offset - Contribution->Base < Contribution->Size) {
|
||||
OS << format("0x%8.8x: ", Offset);
|
||||
// FIXME: We can only extract strings in DWARF32 format at the moment.
|
||||
// FIXME: We can only extract strings if the offset fits in 32 bits.
|
||||
uint64_t StringOffset =
|
||||
StrOffsetExt.getRelocatedValue(EntrySize, &Offset);
|
||||
if (Format == DWARF32) {
|
||||
// Extract the string if we can and display it. Otherwise just report
|
||||
// the offset.
|
||||
if (StringOffset <= std::numeric_limits<uint32_t>::max()) {
|
||||
uint32_t StringOffset32 = (uint32_t)StringOffset;
|
||||
OS << format("%8.8x ", StringOffset32);
|
||||
const char *S = StrData.getCStr(&StringOffset32);
|
||||
@ -162,6 +193,11 @@ dumpDWARFv5StringOffsetsSection(raw_ostream &OS, StringRef SectionName,
|
||||
OS << "\n";
|
||||
}
|
||||
}
|
||||
// Report a gap at the end of the table.
|
||||
if (Offset < SectionSize) {
|
||||
OS << format("0x%8.8x: Gap, length = ", Offset);
|
||||
OS << (SectionSize - Offset) << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
// Dump a DWARF string offsets section. This may be a DWARF v5 formatted
|
||||
@ -170,17 +206,18 @@ dumpDWARFv5StringOffsetsSection(raw_ostream &OS, StringRef SectionName,
|
||||
// a header containing size and version number. Alternatively, it may be a
|
||||
// monolithic series of string offsets, as generated by the pre-DWARF v5
|
||||
// implementation of split DWARF.
|
||||
static void dumpStringOffsetsSection(raw_ostream &OS, StringRef SectionName,
|
||||
const DWARFObject &Obj,
|
||||
const DWARFSection &StringOffsetsSection,
|
||||
StringRef StringSection, bool LittleEndian,
|
||||
unsigned MaxVersion) {
|
||||
static void dumpStringOffsetsSection(
|
||||
raw_ostream &OS, StringRef SectionName, const DWARFObject &Obj,
|
||||
const DWARFSection &StringOffsetsSection, StringRef StringSection,
|
||||
DWARFContext::cu_iterator_range CUs,
|
||||
DWARFContext::tu_section_iterator_range TUSs, bool LittleEndian,
|
||||
unsigned MaxVersion) {
|
||||
// If we have at least one (compile or type) unit with DWARF v5 or greater,
|
||||
// we assume that the section is formatted like a DWARF v5 string offsets
|
||||
// section.
|
||||
if (MaxVersion >= 5)
|
||||
dumpDWARFv5StringOffsetsSection(OS, SectionName, Obj, StringOffsetsSection,
|
||||
StringSection, LittleEndian);
|
||||
StringSection, CUs, TUSs, LittleEndian);
|
||||
else {
|
||||
DataExtractor strOffsetExt(StringOffsetsSection.Data, LittleEndian, 0);
|
||||
uint32_t offset = 0;
|
||||
@ -468,12 +505,14 @@ void DWARFContext::dump(
|
||||
DObj->getStringOffsetSection().Data))
|
||||
dumpStringOffsetsSection(
|
||||
OS, "debug_str_offsets", *DObj, DObj->getStringOffsetSection(),
|
||||
DObj->getStringSection(), isLittleEndian(), getMaxVersion());
|
||||
DObj->getStringSection(), compile_units(), type_unit_sections(),
|
||||
isLittleEndian(), getMaxVersion());
|
||||
if (shouldDump(ExplicitDWO, ".debug_str_offsets.dwo", DIDT_ID_DebugStrOffsets,
|
||||
DObj->getStringOffsetDWOSection().Data))
|
||||
dumpStringOffsetsSection(
|
||||
OS, "debug_str_offsets.dwo", *DObj, DObj->getStringOffsetDWOSection(),
|
||||
DObj->getStringDWOSection(), isLittleEndian(), getMaxVersion());
|
||||
DObj->getStringDWOSection(), dwo_compile_units(),
|
||||
dwo_type_unit_sections(), isLittleEndian(), getMaxVersion());
|
||||
|
||||
if (shouldDump(Explicit, ".gnu_index", DIDT_ID_GdbIndex,
|
||||
DObj->getGdbIndexSection())) {
|
||||
|
@ -8,6 +8,7 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h"
|
||||
@ -79,8 +80,10 @@ bool DWARFUnit::getAddrOffsetSectionItem(uint32_t Index,
|
||||
|
||||
bool DWARFUnit::getStringOffsetSectionItem(uint32_t Index,
|
||||
uint64_t &Result) const {
|
||||
unsigned ItemSize = getDwarfOffsetByteSize();
|
||||
uint32_t Offset = StringOffsetSectionBase + Index * ItemSize;
|
||||
if (!StringOffsetsTableContribution)
|
||||
return false;
|
||||
unsigned ItemSize = getDwarfStringOffsetsByteSize();
|
||||
uint32_t Offset = getStringOffsetsBase() + Index * ItemSize;
|
||||
if (StringOffsetSection.Data.size() < Offset + ItemSize)
|
||||
return false;
|
||||
DWARFDataExtractor DA(Context.getDWARFObj(), StringOffsetSection,
|
||||
@ -251,15 +254,28 @@ size_t DWARFUnit::extractDIEsIfNeeded(bool CUDieOnly) {
|
||||
RangeSectionBase = toSectionOffset(UnitDie.find(DW_AT_rnglists_base), 0);
|
||||
}
|
||||
|
||||
// In general, we derive the offset of the unit's contibution to the
|
||||
// debug_str_offsets{.dwo} section from the unit DIE's
|
||||
// DW_AT_str_offsets_base attribute. In dwp files we add to it the offset
|
||||
// we get from the index table.
|
||||
StringOffsetSectionBase =
|
||||
toSectionOffset(UnitDie.find(DW_AT_str_offsets_base), 0);
|
||||
// In general, in DWARF v5 and beyond we derive the start of the unit's
|
||||
// contribution to the string offsets table from the unit DIE's
|
||||
// DW_AT_str_offsets_base attribute. Split DWARF units do not use this
|
||||
// attribute, so we assume that there is a contribution to the string
|
||||
// offsets table starting at offset 0 of the debug_str_offsets.dwo section.
|
||||
// In both cases we need to determine the format of the contribution,
|
||||
// which may differ from the unit's format.
|
||||
uint64_t StringOffsetsContributionBase =
|
||||
isDWO ? 0 : toSectionOffset(UnitDie.find(DW_AT_str_offsets_base), 0);
|
||||
if (IndexEntry)
|
||||
if (const auto *C = IndexEntry->getOffset(DW_SECT_STR_OFFSETS))
|
||||
StringOffsetSectionBase += C->Offset;
|
||||
StringOffsetsContributionBase += C->Offset;
|
||||
|
||||
DWARFDataExtractor DA(Context.getDWARFObj(), StringOffsetSection,
|
||||
isLittleEndian, 0);
|
||||
if (isDWO)
|
||||
StringOffsetsTableContribution =
|
||||
determineStringOffsetsTableContributionDWO(
|
||||
DA, StringOffsetsContributionBase);
|
||||
else if (getVersion() >= 5)
|
||||
StringOffsetsTableContribution = determineStringOffsetsTableContribution(
|
||||
DA, StringOffsetsContributionBase);
|
||||
|
||||
// Don't fall back to DW_AT_GNU_ranges_base: it should be ignored for
|
||||
// skeleton CU DIE, so that DWARF users not aware of it are not broken.
|
||||
@ -344,45 +360,378 @@ void DWARFUnit::collectAddressRanges(DWARFAddressRangesVector &CURanges) {
|
||||
clearDIEs(true);
|
||||
}
|
||||
|
||||
void DWARFUnit::updateAddressDieMap(DWARFDie Die) {
|
||||
if (Die.isSubroutineDIE()) {
|
||||
// Populates a map from PC addresses to subprogram DIEs.
|
||||
//
|
||||
// This routine tries to look at the smallest amount of the debug info it can
|
||||
// to locate the DIEs. This is because many subprograms will never end up being
|
||||
// read or needed at all. We want to be as lazy as possible.
|
||||
void DWARFUnit::buildSubprogramDIEAddrMap() {
|
||||
assert(SubprogramDIEAddrMap.empty() && "Must only build this map once!");
|
||||
SmallVector<DWARFDie, 16> Worklist;
|
||||
Worklist.push_back(getUnitDIE());
|
||||
do {
|
||||
DWARFDie Die = Worklist.pop_back_val();
|
||||
|
||||
// Queue up child DIEs to recurse through.
|
||||
// FIXME: This causes us to read a lot more debug info than we really need.
|
||||
// We should look at pruning out DIEs which cannot transitively hold
|
||||
// separate subprograms.
|
||||
for (DWARFDie Child : Die.children())
|
||||
Worklist.push_back(Child);
|
||||
|
||||
// If handling a non-subprogram DIE, nothing else to do.
|
||||
if (!Die.isSubprogramDIE())
|
||||
continue;
|
||||
|
||||
// For subprogram DIEs, store them, and insert relevant markers into the
|
||||
// address map. We don't care about overlap at all here as DWARF doesn't
|
||||
// meaningfully support that, so we simply will insert a range with no DIE
|
||||
// starting from the high PC. In the event there are overlaps, sorting
|
||||
// these may truncate things in surprising ways but still will allow
|
||||
// lookups to proceed.
|
||||
int DIEIndex = SubprogramDIEAddrInfos.size();
|
||||
SubprogramDIEAddrInfos.push_back({Die, (uint64_t)-1, {}});
|
||||
for (const auto &R : Die.getAddressRanges()) {
|
||||
// Ignore 0-sized ranges.
|
||||
if (R.LowPC == R.HighPC)
|
||||
continue;
|
||||
auto B = AddrDieMap.upper_bound(R.LowPC);
|
||||
if (B != AddrDieMap.begin() && R.LowPC < (--B)->second.first) {
|
||||
// The range is a sub-range of existing ranges, we need to split the
|
||||
// existing range.
|
||||
if (R.HighPC < B->second.first)
|
||||
AddrDieMap[R.HighPC] = B->second;
|
||||
if (R.LowPC > B->first)
|
||||
AddrDieMap[B->first].first = R.LowPC;
|
||||
}
|
||||
AddrDieMap[R.LowPC] = std::make_pair(R.HighPC, Die);
|
||||
|
||||
SubprogramDIEAddrMap.push_back({R.LowPC, DIEIndex});
|
||||
SubprogramDIEAddrMap.push_back({R.HighPC, -1});
|
||||
|
||||
if (R.LowPC < SubprogramDIEAddrInfos.back().SubprogramBasePC)
|
||||
SubprogramDIEAddrInfos.back().SubprogramBasePC = R.LowPC;
|
||||
}
|
||||
} while (!Worklist.empty());
|
||||
|
||||
if (SubprogramDIEAddrMap.empty()) {
|
||||
// If we found no ranges, create a no-op map so that lookups remain simple
|
||||
// but never find anything.
|
||||
SubprogramDIEAddrMap.push_back({0, -1});
|
||||
return;
|
||||
}
|
||||
// Parent DIEs are added to the AddrDieMap prior to the Children DIEs to
|
||||
// simplify the logic to update AddrDieMap. The child's range will always
|
||||
// be equal or smaller than the parent's range. With this assumption, when
|
||||
// adding one range into the map, it will at most split a range into 3
|
||||
// sub-ranges.
|
||||
for (DWARFDie Child = Die.getFirstChild(); Child; Child = Child.getSibling())
|
||||
updateAddressDieMap(Child);
|
||||
|
||||
// Next, sort the ranges and remove both exact duplicates and runs with the
|
||||
// same DIE index. We order the ranges so that non-empty ranges are
|
||||
// preferred. Because there may be ties, we also need to use stable sort.
|
||||
std::stable_sort(SubprogramDIEAddrMap.begin(), SubprogramDIEAddrMap.end(),
|
||||
[](const std::pair<uint64_t, int64_t> &LHS,
|
||||
const std::pair<uint64_t, int64_t> &RHS) {
|
||||
if (LHS.first < RHS.first)
|
||||
return true;
|
||||
if (LHS.first > RHS.first)
|
||||
return false;
|
||||
|
||||
// For ranges that start at the same address, keep the one
|
||||
// with a DIE.
|
||||
if (LHS.second != -1 && RHS.second == -1)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
});
|
||||
SubprogramDIEAddrMap.erase(
|
||||
std::unique(SubprogramDIEAddrMap.begin(), SubprogramDIEAddrMap.end(),
|
||||
[](const std::pair<uint64_t, int64_t> &LHS,
|
||||
const std::pair<uint64_t, int64_t> &RHS) {
|
||||
// If the start addresses are exactly the same, we can
|
||||
// remove all but the first one as it is the only one that
|
||||
// will be found and used.
|
||||
//
|
||||
// If the DIE indices are the same, we can "merge" the
|
||||
// ranges by eliminating the second.
|
||||
return LHS.first == RHS.first || LHS.second == RHS.second;
|
||||
}),
|
||||
SubprogramDIEAddrMap.end());
|
||||
|
||||
assert(SubprogramDIEAddrMap.back().second == -1 &&
|
||||
"The last interval must not have a DIE as each DIE's address range is "
|
||||
"bounded.");
|
||||
}
|
||||
|
||||
// Build the second level of mapping from PC to DIE, specifically one that maps
|
||||
// a PC *within* a particular DWARF subprogram into a precise, maximally nested
|
||||
// inlined subroutine DIE (if any exists). We build a separate map for each
|
||||
// subprogram because many subprograms will never get queried for an address
|
||||
// and this allows us to be significantly lazier in reading the DWARF itself.
|
||||
void DWARFUnit::buildInlinedSubroutineDIEAddrMap(
|
||||
SubprogramDIEAddrInfo &SPInfo) {
|
||||
auto &AddrMap = SPInfo.InlinedSubroutineDIEAddrMap;
|
||||
uint64_t BasePC = SPInfo.SubprogramBasePC;
|
||||
|
||||
auto SubroutineAddrMapSorter = [](const std::pair<int, int> &LHS,
|
||||
const std::pair<int, int> &RHS) {
|
||||
if (LHS.first < RHS.first)
|
||||
return true;
|
||||
if (LHS.first > RHS.first)
|
||||
return false;
|
||||
|
||||
// For ranges that start at the same address, keep the
|
||||
// non-empty one.
|
||||
if (LHS.second != -1 && RHS.second == -1)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
};
|
||||
auto SubroutineAddrMapUniquer = [](const std::pair<int, int> &LHS,
|
||||
const std::pair<int, int> &RHS) {
|
||||
// If the start addresses are exactly the same, we can
|
||||
// remove all but the first one as it is the only one that
|
||||
// will be found and used.
|
||||
//
|
||||
// If the DIE indices are the same, we can "merge" the
|
||||
// ranges by eliminating the second.
|
||||
return LHS.first == RHS.first || LHS.second == RHS.second;
|
||||
};
|
||||
|
||||
struct DieAndParentIntervalRange {
|
||||
DWARFDie Die;
|
||||
int ParentIntervalsBeginIdx, ParentIntervalsEndIdx;
|
||||
};
|
||||
|
||||
SmallVector<DieAndParentIntervalRange, 16> Worklist;
|
||||
auto EnqueueChildDIEs = [&](const DWARFDie &Die, int ParentIntervalsBeginIdx,
|
||||
int ParentIntervalsEndIdx) {
|
||||
for (DWARFDie Child : Die.children())
|
||||
Worklist.push_back(
|
||||
{Child, ParentIntervalsBeginIdx, ParentIntervalsEndIdx});
|
||||
};
|
||||
EnqueueChildDIEs(SPInfo.SubprogramDIE, 0, 0);
|
||||
while (!Worklist.empty()) {
|
||||
DWARFDie Die = Worklist.back().Die;
|
||||
int ParentIntervalsBeginIdx = Worklist.back().ParentIntervalsBeginIdx;
|
||||
int ParentIntervalsEndIdx = Worklist.back().ParentIntervalsEndIdx;
|
||||
Worklist.pop_back();
|
||||
|
||||
// If we encounter a nested subprogram, simply ignore it. We map to
|
||||
// (disjoint) subprograms before arriving here and we don't want to examine
|
||||
// any inlined subroutines of an unrelated subpragram.
|
||||
if (Die.getTag() == DW_TAG_subprogram)
|
||||
continue;
|
||||
|
||||
// For non-subroutines, just recurse to keep searching for inlined
|
||||
// subroutines.
|
||||
if (Die.getTag() != DW_TAG_inlined_subroutine) {
|
||||
EnqueueChildDIEs(Die, ParentIntervalsBeginIdx, ParentIntervalsEndIdx);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Capture the inlined subroutine DIE that we will reference from the map.
|
||||
int DIEIndex = InlinedSubroutineDIEs.size();
|
||||
InlinedSubroutineDIEs.push_back(Die);
|
||||
|
||||
int DieIntervalsBeginIdx = AddrMap.size();
|
||||
// First collect the PC ranges for this DIE into our subroutine interval
|
||||
// map.
|
||||
for (auto R : Die.getAddressRanges()) {
|
||||
// Clamp the PCs to be above the base.
|
||||
R.LowPC = std::max(R.LowPC, BasePC);
|
||||
R.HighPC = std::max(R.HighPC, BasePC);
|
||||
// Compute relative PCs from the subprogram base and drop down to an
|
||||
// unsigned 32-bit int to represent them within the data structure. This
|
||||
// lets us cover a 4gb single subprogram. Because subprograms may be
|
||||
// partitioned into distant parts of a binary (think hot/cold
|
||||
// partitioning) we want to preserve as much as we can here without
|
||||
// burning extra memory. Past that, we will simply truncate and lose the
|
||||
// ability to map those PCs to a DIE more precise than the subprogram.
|
||||
const uint32_t MaxRelativePC = std::numeric_limits<uint32_t>::max();
|
||||
uint32_t RelativeLowPC = (R.LowPC - BasePC) > (uint64_t)MaxRelativePC
|
||||
? MaxRelativePC
|
||||
: (uint32_t)(R.LowPC - BasePC);
|
||||
uint32_t RelativeHighPC = (R.HighPC - BasePC) > (uint64_t)MaxRelativePC
|
||||
? MaxRelativePC
|
||||
: (uint32_t)(R.HighPC - BasePC);
|
||||
// Ignore empty or bogus ranges.
|
||||
if (RelativeLowPC >= RelativeHighPC)
|
||||
continue;
|
||||
AddrMap.push_back({RelativeLowPC, DIEIndex});
|
||||
AddrMap.push_back({RelativeHighPC, -1});
|
||||
}
|
||||
|
||||
// If there are no address ranges, there is nothing to do to map into them
|
||||
// and there cannot be any child subroutine DIEs with address ranges of
|
||||
// interest as those would all be required to nest within this DIE's
|
||||
// non-existent ranges, so we can immediately continue to the next DIE in
|
||||
// the worklist.
|
||||
if (DieIntervalsBeginIdx == (int)AddrMap.size())
|
||||
continue;
|
||||
|
||||
// The PCs from this DIE should never overlap, so we can easily sort them
|
||||
// here.
|
||||
std::sort(AddrMap.begin() + DieIntervalsBeginIdx, AddrMap.end(),
|
||||
SubroutineAddrMapSorter);
|
||||
// Remove any dead ranges. These should only come from "empty" ranges that
|
||||
// were clobbered by some other range.
|
||||
AddrMap.erase(std::unique(AddrMap.begin() + DieIntervalsBeginIdx,
|
||||
AddrMap.end(), SubroutineAddrMapUniquer),
|
||||
AddrMap.end());
|
||||
|
||||
// Compute the end index of this DIE's addr map intervals.
|
||||
int DieIntervalsEndIdx = AddrMap.size();
|
||||
|
||||
assert(DieIntervalsBeginIdx != DieIntervalsEndIdx &&
|
||||
"Must not have an empty map for this layer!");
|
||||
assert(AddrMap.back().second == -1 && "Must end with an empty range!");
|
||||
assert(std::is_sorted(AddrMap.begin() + DieIntervalsBeginIdx, AddrMap.end(),
|
||||
less_first()) &&
|
||||
"Failed to sort this DIE's interals!");
|
||||
|
||||
// If we have any parent intervals, walk the newly added ranges and find
|
||||
// the parent ranges they were inserted into. Both of these are sorted and
|
||||
// neither has any overlaps. We need to append new ranges to split up any
|
||||
// parent ranges these new ranges would overlap when we merge them.
|
||||
if (ParentIntervalsBeginIdx != ParentIntervalsEndIdx) {
|
||||
int ParentIntervalIdx = ParentIntervalsBeginIdx;
|
||||
for (int i = DieIntervalsBeginIdx, e = DieIntervalsEndIdx - 1; i < e;
|
||||
++i) {
|
||||
const uint32_t IntervalStart = AddrMap[i].first;
|
||||
const uint32_t IntervalEnd = AddrMap[i + 1].first;
|
||||
const int IntervalDieIdx = AddrMap[i].second;
|
||||
if (IntervalDieIdx == -1) {
|
||||
// For empty intervals, nothing is required. This is a bit surprising
|
||||
// however. If the prior interval overlaps a parent interval and this
|
||||
// would be necessary to mark the end, we will synthesize a new end
|
||||
// that switches back to the parent DIE below. And this interval will
|
||||
// get dropped in favor of one with a DIE attached. However, we'll
|
||||
// still include this and so worst-case, it will still end the prior
|
||||
// interval.
|
||||
continue;
|
||||
}
|
||||
|
||||
// We are walking the new ranges in order, so search forward from the
|
||||
// last point for a parent range that might overlap.
|
||||
auto ParentIntervalsRange =
|
||||
make_range(AddrMap.begin() + ParentIntervalIdx,
|
||||
AddrMap.begin() + ParentIntervalsEndIdx);
|
||||
assert(std::is_sorted(ParentIntervalsRange.begin(),
|
||||
ParentIntervalsRange.end(), less_first()) &&
|
||||
"Unsorted parent intervals can't be searched!");
|
||||
auto PI = std::upper_bound(
|
||||
ParentIntervalsRange.begin(), ParentIntervalsRange.end(),
|
||||
IntervalStart,
|
||||
[](uint32_t LHS, const std::pair<uint32_t, int32_t> &RHS) {
|
||||
return LHS < RHS.first;
|
||||
});
|
||||
if (PI == ParentIntervalsRange.begin() ||
|
||||
PI == ParentIntervalsRange.end())
|
||||
continue;
|
||||
|
||||
ParentIntervalIdx = PI - AddrMap.begin();
|
||||
int32_t &ParentIntervalDieIdx = std::prev(PI)->second;
|
||||
uint32_t &ParentIntervalStart = std::prev(PI)->first;
|
||||
const uint32_t ParentIntervalEnd = PI->first;
|
||||
|
||||
// If the new range starts exactly at the position of the parent range,
|
||||
// we need to adjust the parent range. Note that these collisions can
|
||||
// only happen with the original parent range because we will merge any
|
||||
// adjacent ranges in the child.
|
||||
if (IntervalStart == ParentIntervalStart) {
|
||||
// If there will be a tail, just shift the start of the parent
|
||||
// forward. Note that this cannot change the parent ordering.
|
||||
if (IntervalEnd < ParentIntervalEnd) {
|
||||
ParentIntervalStart = IntervalEnd;
|
||||
continue;
|
||||
}
|
||||
// Otherwise, mark this as becoming empty so we'll remove it and
|
||||
// prefer the child range.
|
||||
ParentIntervalDieIdx = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Finally, if the parent interval will need to remain as a prefix to
|
||||
// this one, insert a new interval to cover any tail.
|
||||
if (IntervalEnd < ParentIntervalEnd)
|
||||
AddrMap.push_back({IntervalEnd, ParentIntervalDieIdx});
|
||||
}
|
||||
}
|
||||
|
||||
// Note that we don't need to re-sort even this DIE's address map intervals
|
||||
// after this. All of the newly added intervals actually fill in *gaps* in
|
||||
// this DIE's address map, and we know that children won't need to lookup
|
||||
// into those gaps.
|
||||
|
||||
// Recurse through its children, giving them the interval map range of this
|
||||
// DIE to use as their parent intervals.
|
||||
EnqueueChildDIEs(Die, DieIntervalsBeginIdx, DieIntervalsEndIdx);
|
||||
}
|
||||
|
||||
if (AddrMap.empty()) {
|
||||
AddrMap.push_back({0, -1});
|
||||
return;
|
||||
}
|
||||
|
||||
// Now that we've added all of the intervals needed, we need to resort and
|
||||
// unique them. Most notably, this will remove all the empty ranges that had
|
||||
// a parent range covering, etc. We only expect a single non-empty interval
|
||||
// at any given start point, so we just use std::sort. This could potentially
|
||||
// produce non-deterministic maps for invalid DWARF.
|
||||
std::sort(AddrMap.begin(), AddrMap.end(), SubroutineAddrMapSorter);
|
||||
AddrMap.erase(
|
||||
std::unique(AddrMap.begin(), AddrMap.end(), SubroutineAddrMapUniquer),
|
||||
AddrMap.end());
|
||||
}
|
||||
|
||||
DWARFDie DWARFUnit::getSubroutineForAddress(uint64_t Address) {
|
||||
extractDIEsIfNeeded(false);
|
||||
if (AddrDieMap.empty())
|
||||
updateAddressDieMap(getUnitDIE());
|
||||
auto R = AddrDieMap.upper_bound(Address);
|
||||
if (R == AddrDieMap.begin())
|
||||
|
||||
// We use a two-level mapping structure to locate subroutines for a given PC
|
||||
// address.
|
||||
//
|
||||
// First, we map the address to a subprogram. This can be done more cheaply
|
||||
// because subprograms cannot nest within each other. It also allows us to
|
||||
// avoid detailed examination of many subprograms, instead only focusing on
|
||||
// the ones which we end up actively querying.
|
||||
if (SubprogramDIEAddrMap.empty())
|
||||
buildSubprogramDIEAddrMap();
|
||||
|
||||
assert(!SubprogramDIEAddrMap.empty() &&
|
||||
"We must always end up with a non-empty map!");
|
||||
|
||||
auto I = std::upper_bound(
|
||||
SubprogramDIEAddrMap.begin(), SubprogramDIEAddrMap.end(), Address,
|
||||
[](uint64_t LHS, const std::pair<uint64_t, int64_t> &RHS) {
|
||||
return LHS < RHS.first;
|
||||
});
|
||||
// If we find the beginning, then the address is before the first subprogram.
|
||||
if (I == SubprogramDIEAddrMap.begin())
|
||||
return DWARFDie();
|
||||
// upper_bound's previous item contains Address.
|
||||
--R;
|
||||
if (Address >= R->second.first)
|
||||
// Back up to the interval containing the address and see if it
|
||||
// has a DIE associated with it.
|
||||
--I;
|
||||
if (I->second == -1)
|
||||
return DWARFDie();
|
||||
return R->second.second;
|
||||
|
||||
auto &SPInfo = SubprogramDIEAddrInfos[I->second];
|
||||
|
||||
// Now that we have the subprogram for this address, we do the second level
|
||||
// mapping by building a map within a subprogram's PC range to any specific
|
||||
// inlined subroutine.
|
||||
if (SPInfo.InlinedSubroutineDIEAddrMap.empty())
|
||||
buildInlinedSubroutineDIEAddrMap(SPInfo);
|
||||
|
||||
// We lookup within the inlined subroutine using a subprogram-relative
|
||||
// address.
|
||||
assert(Address >= SPInfo.SubprogramBasePC &&
|
||||
"Address isn't above the start of the subprogram!");
|
||||
uint32_t RelativeAddr = ((Address - SPInfo.SubprogramBasePC) >
|
||||
(uint64_t)std::numeric_limits<uint32_t>::max())
|
||||
? std::numeric_limits<uint32_t>::max()
|
||||
: (uint32_t)(Address - SPInfo.SubprogramBasePC);
|
||||
|
||||
auto J =
|
||||
std::upper_bound(SPInfo.InlinedSubroutineDIEAddrMap.begin(),
|
||||
SPInfo.InlinedSubroutineDIEAddrMap.end(), RelativeAddr,
|
||||
[](uint32_t LHS, const std::pair<uint32_t, int32_t> &RHS) {
|
||||
return LHS < RHS.first;
|
||||
});
|
||||
// If we find the beginning, the address is before any inlined subroutine so
|
||||
// return the subprogram DIE.
|
||||
if (J == SPInfo.InlinedSubroutineDIEAddrMap.begin())
|
||||
return SPInfo.SubprogramDIE;
|
||||
// Back up `J` and return the inlined subroutine if we have one or the
|
||||
// subprogram if we don't.
|
||||
--J;
|
||||
return J->second == -1 ? SPInfo.SubprogramDIE
|
||||
: InlinedSubroutineDIEs[J->second];
|
||||
}
|
||||
|
||||
void
|
||||
@ -466,3 +815,89 @@ const DWARFAbbreviationDeclarationSet *DWARFUnit::getAbbreviations() const {
|
||||
Abbrevs = Abbrev->getAbbreviationDeclarationSet(AbbrOffset);
|
||||
return Abbrevs;
|
||||
}
|
||||
|
||||
Optional<StrOffsetsContributionDescriptor>
|
||||
StrOffsetsContributionDescriptor::validateContributionSize(
|
||||
DWARFDataExtractor &DA) {
|
||||
uint8_t EntrySize = getDwarfOffsetByteSize();
|
||||
// In order to ensure that we don't read a partial record at the end of
|
||||
// the section we validate for a multiple of the entry size.
|
||||
uint64_t ValidationSize = alignTo(Size, EntrySize);
|
||||
// Guard against overflow.
|
||||
if (ValidationSize >= Size)
|
||||
if (DA.isValidOffsetForDataOfSize((uint32_t)Base, ValidationSize))
|
||||
return *this;
|
||||
return Optional<StrOffsetsContributionDescriptor>();
|
||||
}
|
||||
|
||||
// Look for a DWARF64-formatted contribution to the string offsets table
|
||||
// starting at a given offset and record it in a descriptor.
|
||||
static Optional<StrOffsetsContributionDescriptor>
|
||||
parseDWARF64StringOffsetsTableHeader(DWARFDataExtractor &DA, uint32_t Offset) {
|
||||
if (!DA.isValidOffsetForDataOfSize(Offset, 16))
|
||||
return Optional<StrOffsetsContributionDescriptor>();
|
||||
|
||||
if (DA.getU32(&Offset) != 0xffffffff)
|
||||
return Optional<StrOffsetsContributionDescriptor>();
|
||||
|
||||
uint64_t Size = DA.getU64(&Offset);
|
||||
uint8_t Version = DA.getU16(&Offset);
|
||||
(void)DA.getU16(&Offset); // padding
|
||||
return StrOffsetsContributionDescriptor(Offset, Size, Version, DWARF64);
|
||||
//return Optional<StrOffsetsContributionDescriptor>(Descriptor);
|
||||
}
|
||||
|
||||
// Look for a DWARF32-formatted contribution to the string offsets table
|
||||
// starting at a given offset and record it in a descriptor.
|
||||
static Optional<StrOffsetsContributionDescriptor>
|
||||
parseDWARF32StringOffsetsTableHeader(DWARFDataExtractor &DA, uint32_t Offset) {
|
||||
if (!DA.isValidOffsetForDataOfSize(Offset, 8))
|
||||
return Optional<StrOffsetsContributionDescriptor>();
|
||||
uint32_t ContributionSize = DA.getU32(&Offset);
|
||||
if (ContributionSize >= 0xfffffff0)
|
||||
return Optional<StrOffsetsContributionDescriptor>();
|
||||
uint8_t Version = DA.getU16(&Offset);
|
||||
(void)DA.getU16(&Offset); // padding
|
||||
return StrOffsetsContributionDescriptor(Offset, ContributionSize, Version, DWARF32);
|
||||
//return Optional<StrOffsetsContributionDescriptor>(Descriptor);
|
||||
}
|
||||
|
||||
Optional<StrOffsetsContributionDescriptor>
|
||||
DWARFUnit::determineStringOffsetsTableContribution(DWARFDataExtractor &DA,
|
||||
uint64_t Offset) {
|
||||
Optional<StrOffsetsContributionDescriptor> Descriptor;
|
||||
// Attempt to find a DWARF64 contribution 16 bytes before the base.
|
||||
if (Offset >= 16)
|
||||
Descriptor =
|
||||
parseDWARF64StringOffsetsTableHeader(DA, (uint32_t)Offset - 16);
|
||||
// Try to find a DWARF32 contribution 8 bytes before the base.
|
||||
if (!Descriptor && Offset >= 8)
|
||||
Descriptor = parseDWARF32StringOffsetsTableHeader(DA, (uint32_t)Offset - 8);
|
||||
return Descriptor ? Descriptor->validateContributionSize(DA) : Descriptor;
|
||||
}
|
||||
|
||||
Optional<StrOffsetsContributionDescriptor>
|
||||
DWARFUnit::determineStringOffsetsTableContributionDWO(DWARFDataExtractor &DA,
|
||||
uint64_t Offset) {
|
||||
if (getVersion() >= 5) {
|
||||
// Look for a valid contribution at the given offset.
|
||||
auto Descriptor =
|
||||
parseDWARF64StringOffsetsTableHeader(DA, (uint32_t)Offset);
|
||||
if (!Descriptor)
|
||||
Descriptor = parseDWARF32StringOffsetsTableHeader(DA, (uint32_t)Offset);
|
||||
return Descriptor ? Descriptor->validateContributionSize(DA) : Descriptor;
|
||||
}
|
||||
// Prior to DWARF v5, we derive the contribution size from the
|
||||
// index table (in a package file). In a .dwo file it is simply
|
||||
// the length of the string offsets section.
|
||||
uint64_t Size = 0;
|
||||
if (!IndexEntry)
|
||||
Size = StringOffsetSection.Data.size();
|
||||
else if (const auto *C = IndexEntry->getOffset(DW_SECT_STR_OFFSETS))
|
||||
Size = C->Length;
|
||||
// Return a descriptor with the given offset as base, version 4 and
|
||||
// DWARF32 format.
|
||||
//return Optional<StrOffsetsContributionDescriptor>(
|
||||
//StrOffsetsContributionDescriptor(Offset, Size, 4, DWARF32));
|
||||
return StrOffsetsContributionDescriptor(Offset, Size, 4, DWARF32);
|
||||
}
|
||||
|
@ -8,6 +8,7 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Demangle/Demangle.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
|
||||
// This file exports a single function: llvm::itanium_demangle.
|
||||
// It also has no dependencies on the rest of llvm. It is implemented this way
|
||||
@ -1947,7 +1948,7 @@ static const char *parse_type(const char *first, const char *last, C &db) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// falls through
|
||||
LLVM_FALLTHROUGH;
|
||||
default:
|
||||
// must check for builtin-types before class-enum-types to avoid
|
||||
// ambiguities with operator-names
|
||||
|
@ -8,15 +8,17 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/FuzzMutate/IRMutator.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/Analysis/TargetLibraryInfo.h"
|
||||
#include "llvm/FuzzMutate/Operations.h"
|
||||
#include "llvm/FuzzMutate/Random.h"
|
||||
#include "llvm/FuzzMutate/RandomIRBuilder.h"
|
||||
#include "llvm/IR/BasicBlock.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
#include "llvm/IR/InstIterator.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Transforms/Scalar/DCE.h"
|
||||
|
||||
using namespace llvm;
|
||||
@ -90,14 +92,14 @@ std::vector<fuzzerop::OpDescriptor> InjectorIRStrategy::getDefaultOps() {
|
||||
return Ops;
|
||||
}
|
||||
|
||||
fuzzerop::OpDescriptor
|
||||
Optional<fuzzerop::OpDescriptor>
|
||||
InjectorIRStrategy::chooseOperation(Value *Src, RandomIRBuilder &IB) {
|
||||
auto OpMatchesPred = [&Src](fuzzerop::OpDescriptor &Op) {
|
||||
return Op.SourcePreds[0].matches({}, Src);
|
||||
};
|
||||
auto RS = makeSampler(IB.Rand, make_filter_range(Operations, OpMatchesPred));
|
||||
if (RS.isEmpty())
|
||||
report_fatal_error("No available operations for src type");
|
||||
return None;
|
||||
return *RS;
|
||||
}
|
||||
|
||||
@ -120,10 +122,15 @@ void InjectorIRStrategy::mutate(BasicBlock &BB, RandomIRBuilder &IB) {
|
||||
|
||||
// Choose an operation that's constrained to be valid for the type of the
|
||||
// source, collect any other sources it needs, and then build it.
|
||||
fuzzerop::OpDescriptor OpDesc = chooseOperation(Srcs[0], IB);
|
||||
for (const auto &Pred : makeArrayRef(OpDesc.SourcePreds).slice(1))
|
||||
auto OpDesc = chooseOperation(Srcs[0], IB);
|
||||
// Bail if no operation was found
|
||||
if (!OpDesc)
|
||||
return;
|
||||
|
||||
for (const auto &Pred : makeArrayRef(OpDesc->SourcePreds).slice(1))
|
||||
Srcs.push_back(IB.findOrCreateSource(BB, InstsBefore, Srcs, Pred));
|
||||
if (Value *Op = OpDesc.BuilderFunc(Srcs, Insts[IP])) {
|
||||
|
||||
if (Value *Op = OpDesc->BuilderFunc(Srcs, Insts[IP])) {
|
||||
// Find a sink and wire up the results of the operation.
|
||||
IB.connectToSink(BB, InstsAfter, Op);
|
||||
}
|
||||
|
@ -1674,6 +1674,7 @@ static ICmpInst::Predicate evaluateICmpRelation(Constant *V1, Constant *V2,
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
|
@ -1333,7 +1333,9 @@ Optional<uint64_t> Function::getEntryCount() const {
|
||||
if (MDS->getString().equals("function_entry_count")) {
|
||||
ConstantInt *CI = mdconst::extract<ConstantInt>(MD->getOperand(1));
|
||||
uint64_t Count = CI->getValue().getZExtValue();
|
||||
if (Count == 0)
|
||||
// A value of -1 is used for SamplePGO when there were no samples.
|
||||
// Treat this the same as unknown.
|
||||
if (Count == (uint64_t)-1)
|
||||
return None;
|
||||
return Count;
|
||||
}
|
||||
|
@ -627,9 +627,10 @@ uint64_t Value::getPointerDereferenceableBytes(const DataLayout &DL,
|
||||
CanBeNull = false;
|
||||
if (const Argument *A = dyn_cast<Argument>(this)) {
|
||||
DerefBytes = A->getDereferenceableBytes();
|
||||
if (DerefBytes == 0 && A->hasByValAttr()) {
|
||||
if (DerefBytes == 0 && (A->hasByValAttr() || A->hasStructRetAttr())) {
|
||||
Type *PT = cast<PointerType>(A->getType())->getElementType();
|
||||
DerefBytes = DL.getTypeStoreSize(PT);
|
||||
if (PT->isSized())
|
||||
DerefBytes = DL.getTypeStoreSize(PT);
|
||||
}
|
||||
if (DerefBytes == 0) {
|
||||
DerefBytes = A->getDereferenceableOrNullBytes();
|
||||
@ -655,10 +656,8 @@ uint64_t Value::getPointerDereferenceableBytes(const DataLayout &DL,
|
||||
CanBeNull = true;
|
||||
}
|
||||
} else if (auto *AI = dyn_cast<AllocaInst>(this)) {
|
||||
const ConstantInt *ArraySize = dyn_cast<ConstantInt>(AI->getArraySize());
|
||||
if (ArraySize && AI->getAllocatedType()->isSized()) {
|
||||
DerefBytes = DL.getTypeStoreSize(AI->getAllocatedType()) *
|
||||
ArraySize->getZExtValue();
|
||||
if (!AI->isArrayAllocation()) {
|
||||
DerefBytes = DL.getTypeStoreSize(AI->getAllocatedType());
|
||||
CanBeNull = false;
|
||||
}
|
||||
} else if (auto *GV = dyn_cast<GlobalVariable>(this)) {
|
||||
|
@ -405,9 +405,13 @@ void MCAsmStreamer::emitExplicitComments() {
|
||||
void MCAsmStreamer::ChangeSection(MCSection *Section,
|
||||
const MCExpr *Subsection) {
|
||||
assert(Section && "Cannot switch to a null section!");
|
||||
Section->PrintSwitchToSection(
|
||||
*MAI, getContext().getObjectFileInfo()->getTargetTriple(), OS,
|
||||
Subsection);
|
||||
if (MCTargetStreamer *TS = getTargetStreamer()) {
|
||||
TS->changeSection(getCurrentSectionOnly(), Section, Subsection, OS);
|
||||
} else {
|
||||
Section->PrintSwitchToSection(
|
||||
*MAI, getContext().getObjectFileInfo()->getTargetTriple(), OS,
|
||||
Subsection);
|
||||
}
|
||||
}
|
||||
|
||||
void MCAsmStreamer::EmitLabel(MCSymbol *Symbol, SMLoc Loc) {
|
||||
@ -796,10 +800,15 @@ void MCAsmStreamer::EmitBytes(StringRef Data) {
|
||||
"Cannot emit contents before setting section!");
|
||||
if (Data.empty()) return;
|
||||
|
||||
if (Data.size() == 1) {
|
||||
OS << MAI->getData8bitsDirective();
|
||||
OS << (unsigned)(unsigned char)Data[0];
|
||||
EmitEOL();
|
||||
// If only single byte is provided or no ascii or asciz directives is
|
||||
// supported, emit as vector of 8bits data.
|
||||
if (Data.size() == 1 ||
|
||||
!(MAI->getAscizDirective() || MAI->getAsciiDirective())) {
|
||||
const char *Directive = MAI->getData8bitsDirective();
|
||||
for (const unsigned char C : Data.bytes()) {
|
||||
OS << Directive << (unsigned)C;
|
||||
EmitEOL();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -884,8 +893,12 @@ void MCAsmStreamer::EmitValueImpl(const MCExpr *Value, unsigned Size,
|
||||
|
||||
assert(Directive && "Invalid size for machine code value!");
|
||||
OS << Directive;
|
||||
Value->print(OS, MAI);
|
||||
EmitEOL();
|
||||
if (MCTargetStreamer *TS = getTargetStreamer()) {
|
||||
TS->emitValue(Value);
|
||||
} else {
|
||||
Value->print(OS, MAI);
|
||||
EmitEOL();
|
||||
}
|
||||
}
|
||||
|
||||
void MCAsmStreamer::EmitULEB128Value(const MCExpr *Value) {
|
||||
@ -1097,13 +1110,19 @@ unsigned MCAsmStreamer::EmitDwarfFileDirective(unsigned FileNo,
|
||||
}
|
||||
}
|
||||
|
||||
OS << "\t.file\t" << FileNo << ' ';
|
||||
SmallString<128> Str;
|
||||
raw_svector_ostream OS1(Str);
|
||||
OS1 << "\t.file\t" << FileNo << ' ';
|
||||
if (!Directory.empty()) {
|
||||
PrintQuotedString(Directory, OS);
|
||||
OS << ' ';
|
||||
PrintQuotedString(Directory, OS1);
|
||||
OS1 << ' ';
|
||||
}
|
||||
PrintQuotedString(Filename, OS1);
|
||||
if (MCTargetStreamer *TS = getTargetStreamer()) {
|
||||
TS->emitDwarfFileDirective(OS1.str());
|
||||
} else {
|
||||
EmitRawText(OS1.str());
|
||||
}
|
||||
PrintQuotedString(Filename, OS);
|
||||
EmitEOL();
|
||||
|
||||
return FileNo;
|
||||
}
|
||||
|
@ -49,6 +49,28 @@ void MCTargetStreamer::emitLabel(MCSymbol *Symbol) {}
|
||||
|
||||
void MCTargetStreamer::finish() {}
|
||||
|
||||
void MCTargetStreamer::changeSection(const MCSection *CurSection,
|
||||
MCSection *Section,
|
||||
const MCExpr *Subsection,
|
||||
raw_ostream &OS) {
|
||||
Section->PrintSwitchToSection(
|
||||
*Streamer.getContext().getAsmInfo(),
|
||||
Streamer.getContext().getObjectFileInfo()->getTargetTriple(), OS,
|
||||
Subsection);
|
||||
}
|
||||
|
||||
void MCTargetStreamer::emitDwarfFileDirective(StringRef Directive) {
|
||||
Streamer.EmitRawText(Directive);
|
||||
}
|
||||
|
||||
void MCTargetStreamer::emitValue(const MCExpr *Value) {
|
||||
SmallString<128> Str;
|
||||
raw_svector_ostream OS(Str);
|
||||
|
||||
Value->print(OS, Streamer.getContext().getAsmInfo());
|
||||
Streamer.EmitRawText(OS.str());
|
||||
}
|
||||
|
||||
void MCTargetStreamer::emitAssignment(MCSymbol *Symbol, const MCExpr *Value) {}
|
||||
|
||||
MCStreamer::MCStreamer(MCContext &Ctx)
|
||||
|
@ -553,7 +553,7 @@ uint32_t WasmObjectWriter::getRelocationIndexValue(
|
||||
case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB:
|
||||
case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32:
|
||||
if (!IndirectSymbolIndices.count(RelEntry.Symbol))
|
||||
report_fatal_error("symbol not found table index space: " +
|
||||
report_fatal_error("symbol not found in table index space: " +
|
||||
RelEntry.Symbol->getName());
|
||||
return IndirectSymbolIndices[RelEntry.Symbol];
|
||||
case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
|
||||
@ -562,7 +562,7 @@ uint32_t WasmObjectWriter::getRelocationIndexValue(
|
||||
case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
|
||||
case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32:
|
||||
if (!SymbolIndices.count(RelEntry.Symbol))
|
||||
report_fatal_error("symbol not found function/global index space: " +
|
||||
report_fatal_error("symbol not found in function/global index space: " +
|
||||
RelEntry.Symbol->getName());
|
||||
return SymbolIndices[RelEntry.Symbol];
|
||||
case wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB:
|
||||
@ -994,33 +994,10 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm,
|
||||
SmallVector<WasmExport, 4> Exports;
|
||||
SmallVector<std::pair<StringRef, uint32_t>, 4> SymbolFlags;
|
||||
SmallVector<std::pair<uint16_t, uint32_t>, 2> InitFuncs;
|
||||
SmallPtrSet<const MCSymbolWasm *, 4> IsAddressTaken;
|
||||
unsigned NumFuncImports = 0;
|
||||
SmallVector<WasmDataSegment, 4> DataSegments;
|
||||
uint32_t DataSize = 0;
|
||||
|
||||
// Populate the IsAddressTaken set.
|
||||
for (const WasmRelocationEntry &RelEntry : CodeRelocations) {
|
||||
switch (RelEntry.Type) {
|
||||
case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB:
|
||||
case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
|
||||
IsAddressTaken.insert(RelEntry.Symbol);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (const WasmRelocationEntry &RelEntry : DataRelocations) {
|
||||
switch (RelEntry.Type) {
|
||||
case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32:
|
||||
case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32:
|
||||
IsAddressTaken.insert(RelEntry.Symbol);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// In the special .global_variables section, we've encoded global
|
||||
// variables used by the function. Translate them into the Globals
|
||||
// list.
|
||||
@ -1116,7 +1093,7 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm,
|
||||
continue;
|
||||
|
||||
// If the symbol is not defined in this translation unit, import it.
|
||||
if (!WS.isDefined(/*SetUsed=*/false)) {
|
||||
if (!WS.isDefined(/*SetUsed=*/false) || WS.isVariable()) {
|
||||
WasmImport Import;
|
||||
Import.ModuleName = WS.getModuleName();
|
||||
Import.FieldName = WS.getName();
|
||||
@ -1132,8 +1109,7 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm,
|
||||
Import.IsMutable = false;
|
||||
SymbolIndices[&WS] = NumGlobalImports;
|
||||
|
||||
// If this global is the stack pointer, make it mutable and remember it
|
||||
// so that we can emit metadata for it.
|
||||
// If this global is the stack pointer, make it mutable.
|
||||
if (WS.getName() == "__stack_pointer")
|
||||
Import.IsMutable = true;
|
||||
|
||||
@ -1218,14 +1194,7 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm,
|
||||
}
|
||||
|
||||
DEBUG(dbgs() << " -> function index: " << Index << "\n");
|
||||
|
||||
// If needed, prepare the function to be called indirectly.
|
||||
if (IsAddressTaken.count(&WS) != 0) {
|
||||
IndirectSymbolIndices[&WS] = TableElems.size();
|
||||
DEBUG(dbgs() << " -> adding to table: " << TableElems.size() << "\n");
|
||||
TableElems.push_back(Index);
|
||||
}
|
||||
} else {
|
||||
} else {
|
||||
if (WS.isTemporary() && !WS.getSize())
|
||||
continue;
|
||||
|
||||
@ -1289,7 +1258,6 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm,
|
||||
uint32_t Index = SymbolIndices.find(ResolvedSym)->second;
|
||||
DEBUG(dbgs() << " -> index:" << Index << "\n");
|
||||
|
||||
SymbolIndices[&WS] = Index;
|
||||
WasmExport Export;
|
||||
Export.FieldName = WS.getName();
|
||||
Export.Index = Index;
|
||||
@ -1304,12 +1272,34 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm,
|
||||
SymbolFlags.emplace_back(WS.getName(), wasm::WASM_SYMBOL_BINDING_LOCAL);
|
||||
}
|
||||
|
||||
// Add types for indirect function calls.
|
||||
for (const WasmRelocationEntry &Fixup : CodeRelocations) {
|
||||
if (Fixup.Type != wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB)
|
||||
continue;
|
||||
{
|
||||
auto HandleReloc = [&](const WasmRelocationEntry &Rel) {
|
||||
// Functions referenced by a relocation need to prepared to be called
|
||||
// indirectly.
|
||||
const MCSymbolWasm& WS = *Rel.Symbol;
|
||||
if (WS.isFunction() && IndirectSymbolIndices.count(&WS) == 0) {
|
||||
switch (Rel.Type) {
|
||||
case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32:
|
||||
case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB:
|
||||
case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32:
|
||||
case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB: {
|
||||
uint32_t Index = SymbolIndices.find(&WS)->second;
|
||||
IndirectSymbolIndices[&WS] = TableElems.size();
|
||||
DEBUG(dbgs() << " -> adding to table: " << TableElems.size() << "\n");
|
||||
TableElems.push_back(Index);
|
||||
registerFunctionType(WS);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
registerFunctionType(*Fixup.Symbol);
|
||||
for (const WasmRelocationEntry &RelEntry : CodeRelocations)
|
||||
HandleReloc(RelEntry);
|
||||
for (const WasmRelocationEntry &RelEntry : DataRelocations)
|
||||
HandleReloc(RelEntry);
|
||||
}
|
||||
|
||||
// Translate .init_array section contents into start functions.
|
||||
|
@ -138,6 +138,7 @@ StringRef llvm::object::getELFRelocationTypeName(uint32_t Machine,
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ELF::EM_BPF:
|
||||
switch (Type) {
|
||||
#include "llvm/BinaryFormat/ELFRelocs/BPF.def"
|
||||
|
@ -303,7 +303,6 @@ Error WasmObjectFile::parseNameSection(const uint8_t *Ptr, const uint8_t *End) {
|
||||
|
||||
void WasmObjectFile::populateSymbolTable() {
|
||||
// Add imports to symbol table
|
||||
size_t ImportIndex = 0;
|
||||
size_t GlobalIndex = 0;
|
||||
size_t FunctionIndex = 0;
|
||||
for (const wasm::WasmImport& Import : Imports) {
|
||||
@ -312,7 +311,7 @@ void WasmObjectFile::populateSymbolTable() {
|
||||
assert(Import.Global.Type == wasm::WASM_TYPE_I32);
|
||||
SymbolMap.try_emplace(Import.Field, Symbols.size());
|
||||
Symbols.emplace_back(Import.Field, WasmSymbol::SymbolType::GLOBAL_IMPORT,
|
||||
ImportSection, GlobalIndex++, ImportIndex);
|
||||
ImportSection, GlobalIndex++);
|
||||
DEBUG(dbgs() << "Adding import: " << Symbols.back()
|
||||
<< " sym index:" << Symbols.size() << "\n");
|
||||
break;
|
||||
@ -320,14 +319,13 @@ void WasmObjectFile::populateSymbolTable() {
|
||||
SymbolMap.try_emplace(Import.Field, Symbols.size());
|
||||
Symbols.emplace_back(Import.Field,
|
||||
WasmSymbol::SymbolType::FUNCTION_IMPORT,
|
||||
ImportSection, FunctionIndex++, ImportIndex);
|
||||
ImportSection, FunctionIndex++, Import.SigIndex);
|
||||
DEBUG(dbgs() << "Adding import: " << Symbols.back()
|
||||
<< " sym index:" << Symbols.size() << "\n");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
ImportIndex++;
|
||||
}
|
||||
|
||||
// Add exports to symbol table
|
||||
@ -338,11 +336,22 @@ void WasmObjectFile::populateSymbolTable() {
|
||||
Export.Kind == wasm::WASM_EXTERNAL_FUNCTION
|
||||
? WasmSymbol::SymbolType::FUNCTION_EXPORT
|
||||
: WasmSymbol::SymbolType::GLOBAL_EXPORT;
|
||||
SymbolMap.try_emplace(Export.Name, Symbols.size());
|
||||
Symbols.emplace_back(Export.Name, ExportType,
|
||||
ExportSection, Export.Index);
|
||||
DEBUG(dbgs() << "Adding export: " << Symbols.back()
|
||||
<< " sym index:" << Symbols.size() << "\n");
|
||||
auto Pair = SymbolMap.try_emplace(Export.Name, Symbols.size());
|
||||
if (Pair.second) {
|
||||
Symbols.emplace_back(Export.Name, ExportType,
|
||||
ExportSection, Export.Index);
|
||||
DEBUG(dbgs() << "Adding export: " << Symbols.back()
|
||||
<< " sym index:" << Symbols.size() << "\n");
|
||||
} else {
|
||||
uint32_t SymIndex = Pair.first->second;
|
||||
const WasmSymbol &OldSym = Symbols[SymIndex];
|
||||
WasmSymbol NewSym(Export.Name, ExportType, ExportSection, Export.Index);
|
||||
NewSym.setAltIndex(OldSym.ElementIndex);
|
||||
Symbols[SymIndex] = NewSym;
|
||||
|
||||
DEBUG(dbgs() << "Replacing existing symbol: " << NewSym
|
||||
<< " sym index:" << SymIndex << "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1017,7 +1026,7 @@ void WasmObjectFile::getRelocationTypeName(
|
||||
break;
|
||||
|
||||
switch (Rel.Type) {
|
||||
#include "llvm/BinaryFormat/WasmRelocs/WebAssembly.def"
|
||||
#include "llvm/BinaryFormat/WasmRelocs.def"
|
||||
}
|
||||
|
||||
#undef WASM_RELOC
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "llvm/Object/WindowsResource.h"
|
||||
#include "llvm/Object/COFF.h"
|
||||
#include "llvm/Support/FileOutputBuffer.h"
|
||||
#include "llvm/Support/FormatVariadic.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
#include <ctime>
|
||||
#include <queue>
|
||||
@ -560,10 +561,9 @@ void WindowsResourceCOFFWriter::writeSymbolTable() {
|
||||
|
||||
// Now write a symbol for each relocation.
|
||||
for (unsigned i = 0; i < Data.size(); i++) {
|
||||
char RelocationName[9];
|
||||
sprintf(RelocationName, "$R%06X", DataOffsets[i]);
|
||||
auto RelocationName = formatv("$R{0:X-6}", i & 0xffffff).sstr<COFF::NameSize>();
|
||||
Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset);
|
||||
strncpy(Symbol->Name.ShortName, RelocationName, (size_t)COFF::NameSize);
|
||||
memcpy(Symbol->Name.ShortName, RelocationName.data(), (size_t) COFF::NameSize);
|
||||
Symbol->Value = DataOffsets[i];
|
||||
Symbol->SectionNumber = 2;
|
||||
Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL;
|
||||
|
@ -439,7 +439,7 @@ void ScalarEnumerationTraits<WasmYAML::TableType>::enumeration(
|
||||
void ScalarEnumerationTraits<WasmYAML::RelocType>::enumeration(
|
||||
IO &IO, WasmYAML::RelocType &Type) {
|
||||
#define WASM_RELOC(name, value) IO.enumCase(Type, #name, wasm::name);
|
||||
#include "llvm/BinaryFormat/WasmRelocs/WebAssembly.def"
|
||||
#include "llvm/BinaryFormat/WasmRelocs.def"
|
||||
#undef WASM_RELOC
|
||||
}
|
||||
|
||||
|
@ -2546,12 +2546,12 @@ IEEEFloat::convertFromDecimalString(StringRef str, roundingMode rounding_mode) {
|
||||
}
|
||||
|
||||
bool IEEEFloat::convertFromStringSpecials(StringRef str) {
|
||||
if (str.equals("inf") || str.equals("INFINITY")) {
|
||||
if (str.equals("inf") || str.equals("INFINITY") || str.equals("+Inf")) {
|
||||
makeInf(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (str.equals("-inf") || str.equals("-INFINITY")) {
|
||||
if (str.equals("-inf") || str.equals("-INFINITY") || str.equals("-Inf")) {
|
||||
makeInf(true);
|
||||
return true;
|
||||
}
|
||||
|
@ -165,12 +165,14 @@ bool llvm::pruneCache(StringRef Path, CachePruningPolicy Policy) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!Policy.Interval)
|
||||
return false;
|
||||
if (Policy.Interval != seconds(0)) {
|
||||
// Check whether the time stamp is older than our pruning interval.
|
||||
// If not, do nothing.
|
||||
const auto TimeStampModTime = FileStatus.getLastModificationTime();
|
||||
auto TimeStampAge = CurrentTime - TimeStampModTime;
|
||||
if (TimeStampAge <= Policy.Interval) {
|
||||
if (TimeStampAge <= *Policy.Interval) {
|
||||
DEBUG(dbgs() << "Timestamp file too recent ("
|
||||
<< duration_cast<seconds>(TimeStampAge).count()
|
||||
<< "s old), do not prune.\n");
|
||||
|
@ -80,10 +80,12 @@ void *operator new(size_t N, const NamedBufferAlloc &Alloc) {
|
||||
|
||||
namespace {
|
||||
/// MemoryBufferMem - Named MemoryBuffer pointing to a block of memory.
|
||||
class MemoryBufferMem : public MemoryBuffer {
|
||||
template<typename MB>
|
||||
class MemoryBufferMem : public MB {
|
||||
public:
|
||||
MemoryBufferMem(StringRef InputData, bool RequiresNullTerminator) {
|
||||
init(InputData.begin(), InputData.end(), RequiresNullTerminator);
|
||||
MemoryBuffer::init(InputData.begin(), InputData.end(),
|
||||
RequiresNullTerminator);
|
||||
}
|
||||
|
||||
/// Disable sized deallocation for MemoryBufferMem, because it has
|
||||
@ -95,21 +97,22 @@ class MemoryBufferMem : public MemoryBuffer {
|
||||
return StringRef(reinterpret_cast<const char *>(this + 1));
|
||||
}
|
||||
|
||||
BufferKind getBufferKind() const override {
|
||||
return MemoryBuffer_Malloc;
|
||||
MemoryBuffer::BufferKind getBufferKind() const override {
|
||||
return MemoryBuffer::MemoryBuffer_Malloc;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static ErrorOr<std::unique_ptr<MemoryBuffer>>
|
||||
getFileAux(const Twine &Filename, int64_t FileSize, uint64_t MapSize,
|
||||
template <typename MB>
|
||||
static ErrorOr<std::unique_ptr<MB>>
|
||||
getFileAux(const Twine &Filename, int64_t FileSize, uint64_t MapSize,
|
||||
uint64_t Offset, bool RequiresNullTerminator, bool IsVolatile);
|
||||
|
||||
std::unique_ptr<MemoryBuffer>
|
||||
MemoryBuffer::getMemBuffer(StringRef InputData, StringRef BufferName,
|
||||
bool RequiresNullTerminator) {
|
||||
auto *Ret = new (NamedBufferAlloc(BufferName))
|
||||
MemoryBufferMem(InputData, RequiresNullTerminator);
|
||||
MemoryBufferMem<MemoryBuffer>(InputData, RequiresNullTerminator);
|
||||
return std::unique_ptr<MemoryBuffer>(Ret);
|
||||
}
|
||||
|
||||
@ -119,50 +122,30 @@ MemoryBuffer::getMemBuffer(MemoryBufferRef Ref, bool RequiresNullTerminator) {
|
||||
Ref.getBuffer(), Ref.getBufferIdentifier(), RequiresNullTerminator));
|
||||
}
|
||||
|
||||
std::unique_ptr<MemoryBuffer>
|
||||
MemoryBuffer::getMemBufferCopy(StringRef InputData, const Twine &BufferName) {
|
||||
std::unique_ptr<MemoryBuffer> Buf =
|
||||
getNewUninitMemBuffer(InputData.size(), BufferName);
|
||||
static ErrorOr<std::unique_ptr<WritableMemoryBuffer>>
|
||||
getMemBufferCopyImpl(StringRef InputData, const Twine &BufferName) {
|
||||
auto Buf = WritableMemoryBuffer::getNewUninitMemBuffer(InputData.size(), BufferName);
|
||||
if (!Buf)
|
||||
return nullptr;
|
||||
memcpy(const_cast<char*>(Buf->getBufferStart()), InputData.data(),
|
||||
InputData.size());
|
||||
return Buf;
|
||||
return make_error_code(errc::not_enough_memory);
|
||||
memcpy(Buf->getBufferStart(), InputData.data(), InputData.size());
|
||||
return std::move(Buf);
|
||||
}
|
||||
|
||||
std::unique_ptr<MemoryBuffer>
|
||||
MemoryBuffer::getNewUninitMemBuffer(size_t Size, const Twine &BufferName) {
|
||||
// Allocate space for the MemoryBuffer, the data and the name. It is important
|
||||
// that MemoryBuffer and data are aligned so PointerIntPair works with them.
|
||||
// TODO: Is 16-byte alignment enough? We copy small object files with large
|
||||
// alignment expectations into this buffer.
|
||||
SmallString<256> NameBuf;
|
||||
StringRef NameRef = BufferName.toStringRef(NameBuf);
|
||||
size_t AlignedStringLen =
|
||||
alignTo(sizeof(MemoryBufferMem) + NameRef.size() + 1, 16);
|
||||
size_t RealLen = AlignedStringLen + Size + 1;
|
||||
char *Mem = static_cast<char*>(operator new(RealLen, std::nothrow));
|
||||
if (!Mem)
|
||||
return nullptr;
|
||||
|
||||
// The name is stored after the class itself.
|
||||
CopyStringRef(Mem + sizeof(MemoryBufferMem), NameRef);
|
||||
|
||||
// The buffer begins after the name and must be aligned.
|
||||
char *Buf = Mem + AlignedStringLen;
|
||||
Buf[Size] = 0; // Null terminate buffer.
|
||||
|
||||
auto *Ret = new (Mem) MemoryBufferMem(StringRef(Buf, Size), true);
|
||||
return std::unique_ptr<MemoryBuffer>(Ret);
|
||||
MemoryBuffer::getMemBufferCopy(StringRef InputData, const Twine &BufferName) {
|
||||
auto Buf = getMemBufferCopyImpl(InputData, BufferName);
|
||||
if (Buf)
|
||||
return std::move(*Buf);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<MemoryBuffer>
|
||||
MemoryBuffer::getNewMemBuffer(size_t Size, StringRef BufferName) {
|
||||
std::unique_ptr<MemoryBuffer> SB = getNewUninitMemBuffer(Size, BufferName);
|
||||
auto SB = WritableMemoryBuffer::getNewUninitMemBuffer(Size, BufferName);
|
||||
if (!SB)
|
||||
return nullptr;
|
||||
memset(const_cast<char*>(SB->getBufferStart()), 0, Size);
|
||||
return SB;
|
||||
memset(SB->getBufferStart(), 0, Size);
|
||||
return std::move(SB);
|
||||
}
|
||||
|
||||
ErrorOr<std::unique_ptr<MemoryBuffer>>
|
||||
@ -179,10 +162,10 @@ MemoryBuffer::getFileOrSTDIN(const Twine &Filename, int64_t FileSize,
|
||||
ErrorOr<std::unique_ptr<MemoryBuffer>>
|
||||
MemoryBuffer::getFileSlice(const Twine &FilePath, uint64_t MapSize,
|
||||
uint64_t Offset, bool IsVolatile) {
|
||||
return getFileAux(FilePath, -1, MapSize, Offset, false, IsVolatile);
|
||||
return getFileAux<MemoryBuffer>(FilePath, -1, MapSize, Offset, false,
|
||||
IsVolatile);
|
||||
}
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// MemoryBuffer::getFile implementation.
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -191,7 +174,8 @@ namespace {
|
||||
/// \brief Memory maps a file descriptor using sys::fs::mapped_file_region.
|
||||
///
|
||||
/// This handles converting the offset into a legal offset on the platform.
|
||||
class MemoryBufferMMapFile : public MemoryBuffer {
|
||||
template<typename MB>
|
||||
class MemoryBufferMMapFile : public MB {
|
||||
sys::fs::mapped_file_region MFR;
|
||||
|
||||
static uint64_t getLegalMapOffset(uint64_t Offset) {
|
||||
@ -209,11 +193,13 @@ class MemoryBufferMMapFile : public MemoryBuffer {
|
||||
public:
|
||||
MemoryBufferMMapFile(bool RequiresNullTerminator, int FD, uint64_t Len,
|
||||
uint64_t Offset, std::error_code &EC)
|
||||
: MFR(FD, sys::fs::mapped_file_region::readonly,
|
||||
: MFR(FD,
|
||||
MB::Writable ? sys::fs::mapped_file_region::priv
|
||||
: sys::fs::mapped_file_region::readonly,
|
||||
getLegalMapSize(Len, Offset), getLegalMapOffset(Offset), EC) {
|
||||
if (!EC) {
|
||||
const char *Start = getStart(Len, Offset);
|
||||
init(Start, Start + Len, RequiresNullTerminator);
|
||||
MemoryBuffer::init(Start, Start + Len, RequiresNullTerminator);
|
||||
}
|
||||
}
|
||||
|
||||
@ -226,13 +212,13 @@ class MemoryBufferMMapFile : public MemoryBuffer {
|
||||
return StringRef(reinterpret_cast<const char *>(this + 1));
|
||||
}
|
||||
|
||||
BufferKind getBufferKind() const override {
|
||||
return MemoryBuffer_MMap;
|
||||
MemoryBuffer::BufferKind getBufferKind() const override {
|
||||
return MemoryBuffer::MemoryBuffer_MMap;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static ErrorOr<std::unique_ptr<MemoryBuffer>>
|
||||
static ErrorOr<std::unique_ptr<WritableMemoryBuffer>>
|
||||
getMemoryBufferForStream(int FD, const Twine &BufferName) {
|
||||
const ssize_t ChunkSize = 4096*4;
|
||||
SmallString<ChunkSize> Buffer;
|
||||
@ -246,37 +232,80 @@ getMemoryBufferForStream(int FD, const Twine &BufferName) {
|
||||
Buffer.set_size(Buffer.size() + ReadBytes);
|
||||
} while (ReadBytes != 0);
|
||||
|
||||
return MemoryBuffer::getMemBufferCopy(Buffer, BufferName);
|
||||
return getMemBufferCopyImpl(Buffer, BufferName);
|
||||
}
|
||||
|
||||
|
||||
ErrorOr<std::unique_ptr<MemoryBuffer>>
|
||||
MemoryBuffer::getFile(const Twine &Filename, int64_t FileSize,
|
||||
bool RequiresNullTerminator, bool IsVolatile) {
|
||||
return getFileAux(Filename, FileSize, FileSize, 0,
|
||||
RequiresNullTerminator, IsVolatile);
|
||||
return getFileAux<MemoryBuffer>(Filename, FileSize, FileSize, 0,
|
||||
RequiresNullTerminator, IsVolatile);
|
||||
}
|
||||
|
||||
static ErrorOr<std::unique_ptr<MemoryBuffer>>
|
||||
template <typename MB>
|
||||
static ErrorOr<std::unique_ptr<MB>>
|
||||
getOpenFileImpl(int FD, const Twine &Filename, uint64_t FileSize,
|
||||
uint64_t MapSize, int64_t Offset, bool RequiresNullTerminator,
|
||||
bool IsVolatile);
|
||||
|
||||
static ErrorOr<std::unique_ptr<MemoryBuffer>>
|
||||
template <typename MB>
|
||||
static ErrorOr<std::unique_ptr<MB>>
|
||||
getFileAux(const Twine &Filename, int64_t FileSize, uint64_t MapSize,
|
||||
uint64_t Offset, bool RequiresNullTerminator, bool IsVolatile) {
|
||||
int FD;
|
||||
std::error_code EC = sys::fs::openFileForRead(Filename, FD);
|
||||
|
||||
if (EC)
|
||||
return EC;
|
||||
|
||||
ErrorOr<std::unique_ptr<MemoryBuffer>> Ret =
|
||||
getOpenFileImpl(FD, Filename, FileSize, MapSize, Offset,
|
||||
RequiresNullTerminator, IsVolatile);
|
||||
auto Ret = getOpenFileImpl<MB>(FD, Filename, FileSize, MapSize, Offset,
|
||||
RequiresNullTerminator, IsVolatile);
|
||||
close(FD);
|
||||
return Ret;
|
||||
}
|
||||
|
||||
ErrorOr<std::unique_ptr<WritableMemoryBuffer>>
|
||||
WritableMemoryBuffer::getFile(const Twine &Filename, int64_t FileSize,
|
||||
bool IsVolatile) {
|
||||
return getFileAux<WritableMemoryBuffer>(Filename, FileSize, FileSize, 0,
|
||||
/*RequiresNullTerminator*/ false,
|
||||
IsVolatile);
|
||||
}
|
||||
|
||||
ErrorOr<std::unique_ptr<WritableMemoryBuffer>>
|
||||
WritableMemoryBuffer::getFileSlice(const Twine &Filename, uint64_t MapSize,
|
||||
uint64_t Offset, bool IsVolatile) {
|
||||
return getFileAux<WritableMemoryBuffer>(Filename, -1, MapSize, Offset, false,
|
||||
IsVolatile);
|
||||
}
|
||||
|
||||
std::unique_ptr<WritableMemoryBuffer>
|
||||
WritableMemoryBuffer::getNewUninitMemBuffer(size_t Size, const Twine &BufferName) {
|
||||
using MemBuffer = MemoryBufferMem<WritableMemoryBuffer>;
|
||||
// Allocate space for the MemoryBuffer, the data and the name. It is important
|
||||
// that MemoryBuffer and data are aligned so PointerIntPair works with them.
|
||||
// TODO: Is 16-byte alignment enough? We copy small object files with large
|
||||
// alignment expectations into this buffer.
|
||||
SmallString<256> NameBuf;
|
||||
StringRef NameRef = BufferName.toStringRef(NameBuf);
|
||||
size_t AlignedStringLen = alignTo(sizeof(MemBuffer) + NameRef.size() + 1, 16);
|
||||
size_t RealLen = AlignedStringLen + Size + 1;
|
||||
char *Mem = static_cast<char*>(operator new(RealLen, std::nothrow));
|
||||
if (!Mem)
|
||||
return nullptr;
|
||||
|
||||
// The name is stored after the class itself.
|
||||
CopyStringRef(Mem + sizeof(MemBuffer), NameRef);
|
||||
|
||||
// The buffer begins after the name and must be aligned.
|
||||
char *Buf = Mem + AlignedStringLen;
|
||||
Buf[Size] = 0; // Null terminate buffer.
|
||||
|
||||
auto *Ret = new (Mem) MemBuffer(StringRef(Buf, Size), true);
|
||||
return std::unique_ptr<WritableMemoryBuffer>(Ret);
|
||||
}
|
||||
|
||||
static bool shouldUseMmap(int FD,
|
||||
size_t FileSize,
|
||||
size_t MapSize,
|
||||
@ -332,7 +361,8 @@ static bool shouldUseMmap(int FD,
|
||||
return true;
|
||||
}
|
||||
|
||||
static ErrorOr<std::unique_ptr<MemoryBuffer>>
|
||||
template <typename MB>
|
||||
static ErrorOr<std::unique_ptr<MB>>
|
||||
getOpenFileImpl(int FD, const Twine &Filename, uint64_t FileSize,
|
||||
uint64_t MapSize, int64_t Offset, bool RequiresNullTerminator,
|
||||
bool IsVolatile) {
|
||||
@ -364,22 +394,21 @@ getOpenFileImpl(int FD, const Twine &Filename, uint64_t FileSize,
|
||||
if (shouldUseMmap(FD, FileSize, MapSize, Offset, RequiresNullTerminator,
|
||||
PageSize, IsVolatile)) {
|
||||
std::error_code EC;
|
||||
std::unique_ptr<MemoryBuffer> Result(
|
||||
new (NamedBufferAlloc(Filename))
|
||||
MemoryBufferMMapFile(RequiresNullTerminator, FD, MapSize, Offset, EC));
|
||||
std::unique_ptr<MB> Result(
|
||||
new (NamedBufferAlloc(Filename)) MemoryBufferMMapFile<MB>(
|
||||
RequiresNullTerminator, FD, MapSize, Offset, EC));
|
||||
if (!EC)
|
||||
return std::move(Result);
|
||||
}
|
||||
|
||||
std::unique_ptr<MemoryBuffer> Buf =
|
||||
MemoryBuffer::getNewUninitMemBuffer(MapSize, Filename);
|
||||
auto Buf = WritableMemoryBuffer::getNewUninitMemBuffer(MapSize, Filename);
|
||||
if (!Buf) {
|
||||
// Failed to create a buffer. The only way it can fail is if
|
||||
// new(std::nothrow) returns 0.
|
||||
return make_error_code(errc::not_enough_memory);
|
||||
}
|
||||
|
||||
char *BufPtr = const_cast<char *>(Buf->getBufferStart());
|
||||
char *BufPtr = Buf.get()->getBufferStart();
|
||||
|
||||
size_t BytesLeft = MapSize;
|
||||
#ifndef HAVE_PREAD
|
||||
@ -412,7 +441,7 @@ getOpenFileImpl(int FD, const Twine &Filename, uint64_t FileSize,
|
||||
ErrorOr<std::unique_ptr<MemoryBuffer>>
|
||||
MemoryBuffer::getOpenFile(int FD, const Twine &Filename, uint64_t FileSize,
|
||||
bool RequiresNullTerminator, bool IsVolatile) {
|
||||
return getOpenFileImpl(FD, Filename, FileSize, FileSize, 0,
|
||||
return getOpenFileImpl<MemoryBuffer>(FD, Filename, FileSize, FileSize, 0,
|
||||
RequiresNullTerminator, IsVolatile);
|
||||
}
|
||||
|
||||
@ -420,7 +449,8 @@ ErrorOr<std::unique_ptr<MemoryBuffer>>
|
||||
MemoryBuffer::getOpenFileSlice(int FD, const Twine &Filename, uint64_t MapSize,
|
||||
int64_t Offset, bool IsVolatile) {
|
||||
assert(MapSize != uint64_t(-1));
|
||||
return getOpenFileImpl(FD, Filename, -1, MapSize, Offset, false, IsVolatile);
|
||||
return getOpenFileImpl<MemoryBuffer>(FD, Filename, -1, MapSize, Offset, false,
|
||||
IsVolatile);
|
||||
}
|
||||
|
||||
ErrorOr<std::unique_ptr<MemoryBuffer>> MemoryBuffer::getSTDIN() {
|
||||
|
@ -586,7 +586,7 @@ bool StringRef::getAsDouble(double &Result, bool AllowInexact) const {
|
||||
APFloat::opStatus Status =
|
||||
F.convertFromString(*this, APFloat::rmNearestTiesToEven);
|
||||
if (Status != APFloat::opOK) {
|
||||
if (!AllowInexact || Status != APFloat::opInexact)
|
||||
if (!AllowInexact || !(Status & APFloat::opInexact))
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -537,7 +537,7 @@ StringRef llvm::AArch64::getDefaultCPU(StringRef Arch) {
|
||||
}
|
||||
|
||||
unsigned llvm::AArch64::checkArchVersion(StringRef Arch) {
|
||||
if (Arch[0] == 'v' && std::isdigit(Arch[1]))
|
||||
if (Arch.size() >= 2 && Arch[0] == 'v' && std::isdigit(Arch[1]))
|
||||
return (Arch[1] - 48);
|
||||
return 0;
|
||||
}
|
||||
@ -633,7 +633,7 @@ StringRef llvm::ARM::getCanonicalArchName(StringRef Arch) {
|
||||
// Only match non-marketing names
|
||||
if (offset != StringRef::npos) {
|
||||
// Must start with 'vN'.
|
||||
if (A[0] != 'v' || !std::isdigit(A[1]))
|
||||
if (A.size() >= 2 && (A[0] != 'v' || !std::isdigit(A[1])))
|
||||
return Error;
|
||||
// Can't have an extra 'eb'.
|
||||
if (A.find("eb") != StringRef::npos)
|
||||
@ -739,7 +739,6 @@ ARM::ProfileKind ARM::parseArchProfile(StringRef Arch) {
|
||||
case ARM::ArchKind::ARMV8_2A:
|
||||
case ARM::ArchKind::ARMV8_3A:
|
||||
return ARM::ProfileKind::A;
|
||||
LLVM_FALLTHROUGH;
|
||||
case ARM::ArchKind::ARMV2:
|
||||
case ARM::ArchKind::ARMV2A:
|
||||
case ARM::ArchKind::ARMV3:
|
||||
|
@ -657,7 +657,12 @@ void Output::scalarString(StringRef &S, QuotingType MustQuote) {
|
||||
}
|
||||
i = j + 1;
|
||||
} else if (MustQuote == QuotingType::Double &&
|
||||
!sys::unicode::isPrintable(S[j])) {
|
||||
!sys::unicode::isPrintable(S[j]) && (S[j] & 0x80) == 0) {
|
||||
// If we're double quoting non-printable characters, we prefer printing
|
||||
// them as "\x" + their hex representation. Note that special casing is
|
||||
// needed for UTF-8, where a byte may be part of a UTF-8 sequence and
|
||||
// appear as non-printable, in which case we want to print the correct
|
||||
// unicode character and not its hex representation.
|
||||
output(StringRef(&Base[i], j - i)); // "flush"
|
||||
output(StringLiteral("\\x"));
|
||||
|
||||
|
@ -583,6 +583,20 @@ void AArch64AsmPrinter::EmitInstruction(const MachineInstr *MI) {
|
||||
switch (MI->getOpcode()) {
|
||||
default:
|
||||
break;
|
||||
case AArch64::MOVIv2d_ns:
|
||||
// If the target has <rdar://problem/16473581>, lower this
|
||||
// instruction to movi.16b instead.
|
||||
if (STI->hasZeroCycleZeroingFPWorkaround() &&
|
||||
MI->getOperand(1).getImm() == 0) {
|
||||
MCInst TmpInst;
|
||||
TmpInst.setOpcode(AArch64::MOVIv16b_ns);
|
||||
TmpInst.addOperand(MCOperand::createReg(MI->getOperand(0).getReg()));
|
||||
TmpInst.addOperand(MCOperand::createImm(MI->getOperand(1).getImm()));
|
||||
EmitToStreamer(*OutStreamer, TmpInst);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case AArch64::DBG_VALUE: {
|
||||
if (isVerbose() && OutStreamer->hasRawTextSupport()) {
|
||||
SmallString<128> TmpStr;
|
||||
|
@ -5135,11 +5135,12 @@ bool AArch64FastISel::fastSelectInstruction(const Instruction *I) {
|
||||
return selectAtomicCmpXchg(cast<AtomicCmpXchgInst>(I));
|
||||
}
|
||||
|
||||
// fall-back to target-independent instruction selection.
|
||||
return selectOperator(I, I->getOpcode());
|
||||
// Silence warnings.
|
||||
(void)&CC_AArch64_DarwinPCS_VarArg;
|
||||
(void)&CC_AArch64_Win64_VarArg;
|
||||
|
||||
// fall-back to target-independent instruction selection.
|
||||
return selectOperator(I, I->getOpcode());
|
||||
}
|
||||
|
||||
namespace llvm {
|
||||
|
@ -97,6 +97,7 @@
|
||||
#include "AArch64RegisterInfo.h"
|
||||
#include "AArch64Subtarget.h"
|
||||
#include "AArch64TargetMachine.h"
|
||||
#include "MCTargetDesc/AArch64AddressingModes.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include "llvm/CodeGen/LivePhysRegs.h"
|
||||
@ -335,6 +336,22 @@ bool AArch64FrameLowering::canUseAsPrologue(
|
||||
return findScratchNonCalleeSaveRegister(TmpMBB) != AArch64::NoRegister;
|
||||
}
|
||||
|
||||
static bool windowsRequiresStackProbe(MachineFunction &MF,
|
||||
unsigned StackSizeInBytes) {
|
||||
const AArch64Subtarget &Subtarget = MF.getSubtarget<AArch64Subtarget>();
|
||||
if (!Subtarget.isTargetWindows())
|
||||
return false;
|
||||
const Function &F = MF.getFunction();
|
||||
// TODO: When implementing stack protectors, take that into account
|
||||
// for the probe threshold.
|
||||
unsigned StackProbeSize = 4096;
|
||||
if (F.hasFnAttribute("stack-probe-size"))
|
||||
F.getFnAttribute("stack-probe-size")
|
||||
.getValueAsString()
|
||||
.getAsInteger(0, StackProbeSize);
|
||||
return StackSizeInBytes >= StackProbeSize;
|
||||
}
|
||||
|
||||
bool AArch64FrameLowering::shouldCombineCSRLocalStackBump(
|
||||
MachineFunction &MF, unsigned StackBumpBytes) const {
|
||||
AArch64FunctionInfo *AFI = MF.getInfo<AArch64FunctionInfo>();
|
||||
@ -347,7 +364,7 @@ bool AArch64FrameLowering::shouldCombineCSRLocalStackBump(
|
||||
|
||||
// 512 is the maximum immediate for stp/ldp that will be used for
|
||||
// callee-save save/restores
|
||||
if (StackBumpBytes >= 512)
|
||||
if (StackBumpBytes >= 512 || windowsRequiresStackProbe(MF, StackBumpBytes))
|
||||
return false;
|
||||
|
||||
if (MFI.hasVarSizedObjects())
|
||||
@ -478,7 +495,7 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF,
|
||||
return;
|
||||
|
||||
int NumBytes = (int)MFI.getStackSize();
|
||||
if (!AFI->hasStackFrame()) {
|
||||
if (!AFI->hasStackFrame() && !windowsRequiresStackProbe(MF, NumBytes)) {
|
||||
assert(!HasFP && "unexpected function without stack frame but with FP");
|
||||
|
||||
// All of the stack allocation is for locals.
|
||||
@ -550,6 +567,44 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF,
|
||||
MachineInstr::FrameSetup);
|
||||
}
|
||||
|
||||
if (windowsRequiresStackProbe(MF, NumBytes)) {
|
||||
uint32_t NumWords = NumBytes >> 4;
|
||||
|
||||
BuildMI(MBB, MBBI, DL, TII->get(AArch64::MOVi64imm), AArch64::X15)
|
||||
.addImm(NumWords)
|
||||
.setMIFlags(MachineInstr::FrameSetup);
|
||||
|
||||
switch (MF.getTarget().getCodeModel()) {
|
||||
case CodeModel::Small:
|
||||
case CodeModel::Medium:
|
||||
case CodeModel::Kernel:
|
||||
BuildMI(MBB, MBBI, DL, TII->get(AArch64::BL))
|
||||
.addExternalSymbol("__chkstk")
|
||||
.addReg(AArch64::X15, RegState::Implicit)
|
||||
.setMIFlags(MachineInstr::FrameSetup);
|
||||
break;
|
||||
case CodeModel::Large:
|
||||
BuildMI(MBB, MBBI, DL, TII->get(AArch64::MOVaddrEXT))
|
||||
.addReg(AArch64::X16, RegState::Define)
|
||||
.addExternalSymbol("__chkstk")
|
||||
.addExternalSymbol("__chkstk")
|
||||
.setMIFlags(MachineInstr::FrameSetup);
|
||||
|
||||
BuildMI(MBB, MBBI, DL, TII->get(AArch64::BLR))
|
||||
.addReg(AArch64::X16, RegState::Kill)
|
||||
.addReg(AArch64::X15, RegState::Implicit | RegState::Define)
|
||||
.setMIFlags(MachineInstr::FrameSetup);
|
||||
break;
|
||||
}
|
||||
|
||||
BuildMI(MBB, MBBI, DL, TII->get(AArch64::SUBXrx64), AArch64::SP)
|
||||
.addReg(AArch64::SP, RegState::Kill)
|
||||
.addReg(AArch64::X15, RegState::Kill)
|
||||
.addImm(AArch64_AM::getArithExtendImm(AArch64_AM::UXTX, 4))
|
||||
.setMIFlags(MachineInstr::FrameSetup);
|
||||
NumBytes = 0;
|
||||
}
|
||||
|
||||
// Allocate space for the rest of the frame.
|
||||
if (NumBytes) {
|
||||
const bool NeedsRealignment = RegInfo->needsStackRealignment(MF);
|
||||
@ -1164,18 +1219,32 @@ void AArch64FrameLowering::determineCalleeSaves(MachineFunction &MF,
|
||||
unsigned UnspilledCSGPR = AArch64::NoRegister;
|
||||
unsigned UnspilledCSGPRPaired = AArch64::NoRegister;
|
||||
|
||||
MachineFrameInfo &MFI = MF.getFrameInfo();
|
||||
const MCPhysReg *CSRegs = RegInfo->getCalleeSavedRegs(&MF);
|
||||
|
||||
unsigned BasePointerReg = RegInfo->hasBasePointer(MF)
|
||||
? RegInfo->getBaseRegister()
|
||||
: (unsigned)AArch64::NoRegister;
|
||||
|
||||
unsigned SpillEstimate = SavedRegs.count();
|
||||
for (unsigned i = 0; CSRegs[i]; ++i) {
|
||||
unsigned Reg = CSRegs[i];
|
||||
unsigned PairedReg = CSRegs[i ^ 1];
|
||||
if (Reg == BasePointerReg)
|
||||
SpillEstimate++;
|
||||
if (produceCompactUnwindFrame(MF) && !SavedRegs.test(PairedReg))
|
||||
SpillEstimate++;
|
||||
}
|
||||
SpillEstimate += 2; // Conservatively include FP+LR in the estimate
|
||||
unsigned StackEstimate = MFI.estimateStackSize(MF) + 8 * SpillEstimate;
|
||||
|
||||
// The frame record needs to be created by saving the appropriate registers
|
||||
if (hasFP(MF)) {
|
||||
if (hasFP(MF) || windowsRequiresStackProbe(MF, StackEstimate)) {
|
||||
SavedRegs.set(AArch64::FP);
|
||||
SavedRegs.set(AArch64::LR);
|
||||
}
|
||||
|
||||
unsigned BasePointerReg = AArch64::NoRegister;
|
||||
if (RegInfo->hasBasePointer(MF))
|
||||
BasePointerReg = RegInfo->getBaseRegister();
|
||||
|
||||
unsigned ExtraCSSpill = 0;
|
||||
const MCPhysReg *CSRegs = RegInfo->getCalleeSavedRegs(&MF);
|
||||
// Figure out which callee-saved registers to save/restore.
|
||||
for (unsigned i = 0; CSRegs[i]; ++i) {
|
||||
const unsigned Reg = CSRegs[i];
|
||||
@ -1217,7 +1286,6 @@ void AArch64FrameLowering::determineCalleeSaves(MachineFunction &MF,
|
||||
|
||||
// The CSR spill slots have not been allocated yet, so estimateStackSize
|
||||
// won't include them.
|
||||
MachineFrameInfo &MFI = MF.getFrameInfo();
|
||||
unsigned CFSize = MFI.estimateStackSize(MF) + 8 * NumRegsSpilled;
|
||||
DEBUG(dbgs() << "Estimated stack frame size: " << CFSize << " bytes.\n");
|
||||
unsigned EstimatedStackSizeLimit = estimateRSStackSizeLimit(MF);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user