1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-12-31 12:13:10 +00:00

Vendor import of llvm trunk r321414:

https://llvm.org/svn/llvm-project/llvm/trunk@321414
This commit is contained in:
Dimitry Andric 2017-12-24 01:00:08 +00:00
parent 044eb2f6af
commit c7dac04c34
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/vendor/llvm/dist/; revision=327122
svn path=/vendor/llvm/llvm-trunk-r321414/; revision=327123; tag=vendor/llvm/llvm-trunk-r321414
423 changed files with 14393 additions and 10359 deletions

View File

@ -288,3 +288,31 @@ standard stack probe emission.
The MSVC environment does not emit code for VLAs currently.
Windows on ARM64
----------------
Stack Probe Emission
^^^^^^^^^^^^^^^^^^^^
The reference implementation (Microsoft Visual Studio 2017) emits stack probes
in the following fashion:
.. code-block:: gas
mov x15, #constant
bl __chkstk
sub sp, sp, x15, lsl #4
However, this has the limitation of 256 MiB (±128MiB). In order to accommodate
larger binaries, LLVM supports the use of ``-mcode-model=large`` to allow a 8GiB
(±4GiB) range via a slight deviation. It will generate an indirect jump as
follows:
.. code-block:: gas
mov x15, #constant
adrp x16, __chkstk
add x16, x16, :lo12:__chkstk
blr x16
sub sp, sp, x15, lsl #4

View File

@ -692,6 +692,50 @@ The syntax is:
EH_LABEL <mcsymbol Ltmp1>
CFIIndex Operands
^^^^^^^^^^^^^^^^^
A CFI Index operand is holding an index into a per-function side-table,
``MachineFunction::getFrameInstructions()``, which references all the frame
instructions in a ``MachineFunction``. A ``CFI_INSTRUCTION`` may look like it
contains multiple operands, but the only operand it contains is the CFI Index.
The other operands are tracked by the ``MCCFIInstruction`` object.
The syntax is:
.. code-block:: text
CFI_INSTRUCTION offset %w30, -16
which may be emitted later in the MC layer as:
.. code-block:: text
.cfi_offset w30, -16
IntrinsicID Operands
^^^^^^^^^^^^^^^^^^^^
An Intrinsic ID operand contains a generic intrinsic ID or a target-specific ID.
The syntax for the ``returnaddress`` intrinsic is:
.. code-block:: text
%x0 = COPY intrinsic(@llvm.returnaddress)
Predicate Operands
^^^^^^^^^^^^^^^^^^
A Predicate operand contains an IR predicate from ``CmpInst::Predicate``, like
``ICMP_EQ``, etc.
For an int eq predicate ``ICMP_EQ``, the syntax is:
.. code-block:: text
%2:gpr(s32) = G_ICMP intpred(eq), %0, %1
.. TODO: Describe the parsers default behaviour when optional YAML attributes
are missing.
.. TODO: Describe the syntax for the bundled instructions.
@ -702,7 +746,6 @@ The syntax is:
.. TODO: Describe the syntax of the stack object machine operands and their
YAML definitions.
.. TODO: Describe the syntax of the block address machine operands.
.. TODO: Describe the syntax of the CFI index machine operands.
.. TODO: Describe the syntax of the metadata machine operands, and the
instructions debug location attribute.
.. TODO: Describe the syntax of the register live out machine operands.

View File

@ -197,7 +197,7 @@ expressions:
if (DblTy)
return DblTy;
DblTy = DBuilder->createBasicType("double", 64, 64, dwarf::DW_ATE_float);
DblTy = DBuilder->createBasicType("double", 64, dwarf::DW_ATE_float);
return DblTy;
}
@ -208,7 +208,8 @@ And then later on in ``main`` when we're constructing our module:
DBuilder = new DIBuilder(*TheModule);
KSDbgInfo.TheCU = DBuilder->createCompileUnit(
dwarf::DW_LANG_C, "fib.ks", ".", "Kaleidoscope Compiler", 0, "", 0);
dwarf::DW_LANG_C, DBuilder->createFile("fib.ks", "."),
"Kaleidoscope Compiler", 0, "", 0);
There are a couple of things to note here. First, while we're producing a
compile unit for a language called Kaleidoscope we used the language

View File

@ -14,3 +14,4 @@ add_subdirectory(Chapter5)
add_subdirectory(Chapter6)
add_subdirectory(Chapter7)
add_subdirectory(Chapter8)
add_subdirectory(Chapter9)

View File

@ -823,7 +823,7 @@ DIType *DebugInfo::getDoubleTy() {
if (DblTy)
return DblTy;
DblTy = DBuilder->createBasicType("double", 64, 64, dwarf::DW_ATE_float);
DblTy = DBuilder->createBasicType("double", 64, dwarf::DW_ATE_float);
return DblTy;
}
@ -1436,7 +1436,8 @@ int main() {
// Currently down as "fib.ks" as a filename since we're redirecting stdin
// but we'd like actual source locations.
KSDbgInfo.TheCU = DBuilder->createCompileUnit(
dwarf::DW_LANG_C, "fib.ks", ".", "Kaleidoscope Compiler", 0, "", 0);
dwarf::DW_LANG_C, DBuilder->createFile("fib.ks", "."),
"Kaleidoscope Compiler", 0, "", 0);
// Run the main "interpreter loop" now.
MainLoop();

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

@ -51,7 +51,7 @@ add_llvm_library(LLVMCodeGen
LiveRangeShrink.cpp
LiveRegMatrix.cpp
LiveRegUnits.cpp
LiveStackAnalysis.cpp
LiveStacks.cpp
LiveVariables.cpp
LLVMTargetMachine.cpp
LocalStackSlotAllocation.cpp

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

@ -164,7 +164,7 @@ synthesize the various copy insertion/inspection methods in TargetInstrInfo.
Stack coloring improvements:
1. Do proper LiveStackAnalysis on all stack objects including those which are
1. Do proper LiveStacks analysis on all stack objects including those which are
not spill slots.
2. Reorder objects to fill in gaps between objects.
e.g. 4, 1, <gap>, 4, 1, 1, 1, <gap>, 4 => 4, 1, 1, 1, 1, 4, 4

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

@ -19,4 +19,4 @@
type = Library
name = Passes
parent = Libraries
required_libraries = Analysis CodeGen Core IPO InstCombine Scalar Support TransformUtils Vectorize Instrumentation
required_libraries = Analysis CodeGen Core IPO InstCombine Scalar Support Target TransformUtils Vectorize Instrumentation

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

Some files were not shown because too many files have changed in this diff Show More