Merge llvm trunk r321414 to contrib/llvm.

This commit is contained in:
dim 2017-12-24 01:04:58 +00:00
commit ca8935c57d
219 changed files with 4753 additions and 2615 deletions

View File

@ -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.
*

View File

@ -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);

View File

@ -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();

View File

@ -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,

View File

@ -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);

View File

@ -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.

View File

@ -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.

View File

@ -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);
}

View File

@ -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; }

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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")

View 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

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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;

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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

View File

@ -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();
};

View File

@ -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)

View File

@ -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

View File

@ -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;

View File

@ -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; } \
}; \
} \
}

View File

@ -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.

View File

@ -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.
//

View File

@ -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();

View File

@ -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);

View File

@ -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 * } }

View File

@ -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

View File

@ -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";
}
}

View File

@ -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

View File

@ -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();
}

View File

@ -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

View File

@ -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

View File

@ -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) {

View File

@ -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,

View File

@ -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));
}

View File

@ -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);

View File

@ -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")));
}

View File

@ -4368,6 +4368,7 @@ static Optional<BinaryOp> MatchBinaryOp(Value *V, DominatorTree &DT) {
default:
break;
}
break;
}
default:

View File

@ -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);
}

View File

@ -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.

View File

@ -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)

View File

@ -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.

View File

@ -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)

View File

@ -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");
}

View File

@ -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"

View File

@ -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.

View File

@ -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"

View File

@ -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);

View File

@ -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

View File

@ -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;
}
}

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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

View File

@ -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;

View File

@ -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;
}

View File

@ -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);

View File

@ -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:

View File

@ -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:

View File

@ -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

View File

@ -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) {

View File

@ -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);
}
//===----------------------------------------------------------------------===//

View File

@ -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"

View File

@ -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() {

View File

@ -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"

View File

@ -83,6 +83,7 @@ bool DWARFAcceleratorTable::validateForms() {
!FormValue.isFormClass(DWARFFormValue::FC_Flag)) ||
FormValue.getForm() == dwarf::DW_FORM_sdata)
return false;
break;
default:
break;
}

View File

@ -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())) {

View File

@ -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);
}

View File

@ -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

View File

@ -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);
}

View File

@ -1674,6 +1674,7 @@ static ICmpInst::Predicate evaluateICmpRelation(Constant *V1, Constant *V2,
}
}
}
break;
}
default:
break;

View File

@ -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;
}

View File

@ -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)) {

View File

@ -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;
}

View File

@ -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)

View File

@ -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.

View File

@ -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"

View File

@ -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

View File

@ -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;

View File

@ -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
}

View File

@ -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;
}

View File

@ -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");

View File

@ -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() {

View File

@ -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;
}

View File

@ -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:

View File

@ -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"));

View File

@ -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;

View File

@ -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 {

View File

@ -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