Mark files not in r294123 as dead.
This commit is contained in:
parent
c411cea556
commit
1bf9ae99e4
|
@ -1,149 +0,0 @@
|
|||
//===- LoopPassManager.h - Loop pass management -----------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// \file
|
||||
///
|
||||
/// This header provides classes for managing passes over loops in LLVM IR.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ANALYSIS_LOOPPASSMANAGER_H
|
||||
#define LLVM_ANALYSIS_LOOPPASSMANAGER_H
|
||||
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/Analysis/AliasAnalysis.h"
|
||||
#include "llvm/Analysis/LoopInfo.h"
|
||||
#include "llvm/Analysis/ScalarEvolution.h"
|
||||
#include "llvm/Analysis/TargetLibraryInfo.h"
|
||||
#include "llvm/IR/Dominators.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
extern template class PassManager<Loop>;
|
||||
/// \brief The loop pass manager.
|
||||
///
|
||||
/// See the documentation for the PassManager template for details. It runs a
|
||||
/// sequency of loop passes over each loop that the manager is run over. This
|
||||
/// typedef serves as a convenient way to refer to this construct.
|
||||
typedef PassManager<Loop> LoopPassManager;
|
||||
|
||||
extern template class AnalysisManager<Loop>;
|
||||
/// \brief The loop analysis manager.
|
||||
///
|
||||
/// See the documentation for the AnalysisManager template for detail
|
||||
/// documentation. This typedef serves as a convenient way to refer to this
|
||||
/// construct in the adaptors and proxies used to integrate this into the larger
|
||||
/// pass manager infrastructure.
|
||||
typedef AnalysisManager<Loop> LoopAnalysisManager;
|
||||
|
||||
/// A proxy from a \c LoopAnalysisManager to a \c Function.
|
||||
typedef InnerAnalysisManagerProxy<LoopAnalysisManager, Function>
|
||||
LoopAnalysisManagerFunctionProxy;
|
||||
|
||||
/// Specialization of the invalidate method for the \c
|
||||
/// LoopAnalysisManagerFunctionProxy's result.
|
||||
template <>
|
||||
bool LoopAnalysisManagerFunctionProxy::Result::invalidate(
|
||||
Function &F, const PreservedAnalyses &PA,
|
||||
FunctionAnalysisManager::Invalidator &Inv);
|
||||
|
||||
// Ensure the \c LoopAnalysisManagerFunctionProxy is provided as an extern
|
||||
// template.
|
||||
extern template class InnerAnalysisManagerProxy<LoopAnalysisManager, Function>;
|
||||
|
||||
extern template class OuterAnalysisManagerProxy<FunctionAnalysisManager, Loop>;
|
||||
/// A proxy from a \c FunctionAnalysisManager to a \c Loop.
|
||||
typedef OuterAnalysisManagerProxy<FunctionAnalysisManager, Loop>
|
||||
FunctionAnalysisManagerLoopProxy;
|
||||
|
||||
/// Returns the minimum set of Analyses that all loop passes must preserve.
|
||||
PreservedAnalyses getLoopPassPreservedAnalyses();
|
||||
|
||||
/// \brief Adaptor that maps from a function to its loops.
|
||||
///
|
||||
/// Designed to allow composition of a LoopPass(Manager) and a
|
||||
/// FunctionPassManager. Note that if this pass is constructed with a \c
|
||||
/// FunctionAnalysisManager it will run the \c LoopAnalysisManagerFunctionProxy
|
||||
/// analysis prior to running the loop passes over the function to enable a \c
|
||||
/// LoopAnalysisManager to be used within this run safely.
|
||||
template <typename LoopPassT>
|
||||
class FunctionToLoopPassAdaptor
|
||||
: public PassInfoMixin<FunctionToLoopPassAdaptor<LoopPassT>> {
|
||||
public:
|
||||
explicit FunctionToLoopPassAdaptor(LoopPassT Pass)
|
||||
: Pass(std::move(Pass)) {}
|
||||
|
||||
/// \brief Runs the loop passes across every loop in the function.
|
||||
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM) {
|
||||
// Setup the loop analysis manager from its proxy.
|
||||
LoopAnalysisManager &LAM =
|
||||
AM.getResult<LoopAnalysisManagerFunctionProxy>(F).getManager();
|
||||
// Get the loop structure for this function
|
||||
LoopInfo &LI = AM.getResult<LoopAnalysis>(F);
|
||||
|
||||
// Also precompute all of the function analyses used by loop passes.
|
||||
// FIXME: These should be handed into the loop passes when the loop pass
|
||||
// management layer is reworked to follow the design of CGSCC.
|
||||
(void)AM.getResult<AAManager>(F);
|
||||
(void)AM.getResult<DominatorTreeAnalysis>(F);
|
||||
(void)AM.getResult<ScalarEvolutionAnalysis>(F);
|
||||
(void)AM.getResult<TargetLibraryAnalysis>(F);
|
||||
|
||||
PreservedAnalyses PA = PreservedAnalyses::all();
|
||||
|
||||
// We want to visit the loops in reverse post-order. We'll build the stack
|
||||
// of loops to visit in Loops by first walking the loops in pre-order.
|
||||
SmallVector<Loop *, 2> Loops;
|
||||
SmallVector<Loop *, 2> WorkList(LI.begin(), LI.end());
|
||||
while (!WorkList.empty()) {
|
||||
Loop *L = WorkList.pop_back_val();
|
||||
WorkList.insert(WorkList.end(), L->begin(), L->end());
|
||||
Loops.push_back(L);
|
||||
}
|
||||
|
||||
// Now pop each element off of the stack to visit the loops in reverse
|
||||
// post-order.
|
||||
for (auto *L : reverse(Loops)) {
|
||||
PreservedAnalyses PassPA = Pass.run(*L, LAM);
|
||||
// FIXME: We should verify the set of analyses relevant to Loop passes
|
||||
// are preserved.
|
||||
|
||||
// We know that the loop pass couldn't have invalidated any other loop's
|
||||
// analyses (that's the contract of a loop pass), so directly handle the
|
||||
// loop analysis manager's invalidation here.
|
||||
LAM.invalidate(*L, PassPA);
|
||||
|
||||
// Then intersect the preserved set so that invalidation of module
|
||||
// analyses will eventually occur when the module pass completes.
|
||||
PA.intersect(std::move(PassPA));
|
||||
}
|
||||
|
||||
// By definition we preserve the proxy. We also preserve all analyses on
|
||||
// Loops. This precludes *any* invalidation of loop analyses by the proxy,
|
||||
// but that's OK because we've taken care to invalidate analyses in the
|
||||
// loop analysis manager incrementally above.
|
||||
PA.preserveSet<AllAnalysesOn<Loop>>();
|
||||
PA.preserve<LoopAnalysisManagerFunctionProxy>();
|
||||
return PA;
|
||||
}
|
||||
|
||||
private:
|
||||
LoopPassT Pass;
|
||||
};
|
||||
|
||||
/// \brief A function to deduce a loop pass type and wrap it in the templated
|
||||
/// adaptor.
|
||||
template <typename LoopPassT>
|
||||
FunctionToLoopPassAdaptor<LoopPassT>
|
||||
createFunctionToLoopPassAdaptor(LoopPassT Pass) {
|
||||
return FunctionToLoopPassAdaptor<LoopPassT>(std::move(Pass));
|
||||
}
|
||||
}
|
||||
|
||||
#endif // LLVM_ANALYSIS_LOOPPASSMANAGER_H
|
|
@ -1,108 +0,0 @@
|
|||
//===-- TypeDumper.h - CodeView type info dumper ----------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_DEBUGINFO_CODEVIEW_TYPEDUMPER_H
|
||||
#define LLVM_DEBUGINFO_CODEVIEW_TYPEDUMPER_H
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/StringSet.h"
|
||||
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
|
||||
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
|
||||
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
|
||||
|
||||
namespace llvm {
|
||||
class ScopedPrinter;
|
||||
|
||||
namespace codeview {
|
||||
|
||||
/// Dumper for CodeView type streams found in COFF object files and PDB files.
|
||||
class CVTypeDumper : public TypeVisitorCallbacks {
|
||||
public:
|
||||
CVTypeDumper(ScopedPrinter *W, bool PrintRecordBytes)
|
||||
: W(W), PrintRecordBytes(PrintRecordBytes) {}
|
||||
|
||||
StringRef getTypeName(TypeIndex TI);
|
||||
void printTypeIndex(StringRef FieldName, TypeIndex TI);
|
||||
|
||||
/// Dumps one type record. Returns false if there was a type parsing error,
|
||||
/// and true otherwise. This should be called in order, since the dumper
|
||||
/// maintains state about previous records which are necessary for cross
|
||||
/// type references.
|
||||
Error dump(const CVRecord<TypeLeafKind> &Record);
|
||||
|
||||
/// Dumps the type records in Types. Returns false if there was a type stream
|
||||
/// parse error, and true otherwise.
|
||||
Error dump(const CVTypeArray &Types);
|
||||
|
||||
/// Dumps the type records in Data. Returns false if there was a type stream
|
||||
/// parse error, and true otherwise. Use this method instead of the
|
||||
/// CVTypeArray overload when type records are laid out contiguously in
|
||||
/// memory.
|
||||
Error dump(ArrayRef<uint8_t> Data);
|
||||
|
||||
/// Gets the type index for the next type record.
|
||||
unsigned getNextTypeIndex() const {
|
||||
return 0x1000 + CVUDTNames.size();
|
||||
}
|
||||
|
||||
/// Records the name of a type, and reserves its type index.
|
||||
void recordType(StringRef Name) { CVUDTNames.push_back(Name); }
|
||||
|
||||
/// Saves the name in a StringSet and creates a stable StringRef.
|
||||
StringRef saveName(StringRef TypeName) {
|
||||
return TypeNames.insert(TypeName).first->getKey();
|
||||
}
|
||||
|
||||
void setPrinter(ScopedPrinter *P);
|
||||
ScopedPrinter *getPrinter() { return W; }
|
||||
|
||||
/// Action to take on unknown types. By default, they are ignored.
|
||||
Error visitUnknownType(CVType &Record) override;
|
||||
Error visitUnknownMember(CVMemberRecord &Record) override;
|
||||
|
||||
/// Paired begin/end actions for all types. Receives all record data,
|
||||
/// including the fixed-length record prefix.
|
||||
Error visitTypeBegin(CVType &Record) override;
|
||||
Error visitTypeEnd(CVType &Record) override;
|
||||
Error visitMemberBegin(CVMemberRecord &Record) override;
|
||||
Error visitMemberEnd(CVMemberRecord &Record) override;
|
||||
|
||||
#define TYPE_RECORD(EnumName, EnumVal, Name) \
|
||||
Error visitKnownRecord(CVType &CVR, Name##Record &Record) override;
|
||||
#define MEMBER_RECORD(EnumName, EnumVal, Name) \
|
||||
Error visitKnownMember(CVMemberRecord &CVR, Name##Record &Record) override;
|
||||
#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
|
||||
#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
|
||||
#include "TypeRecords.def"
|
||||
|
||||
private:
|
||||
void printMemberAttributes(MemberAttributes Attrs);
|
||||
void printMemberAttributes(MemberAccess Access, MethodKind Kind,
|
||||
MethodOptions Options);
|
||||
|
||||
ScopedPrinter *W;
|
||||
|
||||
bool IsInFieldList = false;
|
||||
bool PrintRecordBytes = false;
|
||||
|
||||
/// Name of the current type. Only valid before visitTypeEnd.
|
||||
StringRef Name;
|
||||
|
||||
/// All user defined type records in .debug$T live in here. Type indices
|
||||
/// greater than 0x1000 are user defined. Subtract 0x1000 from the index to
|
||||
/// index into this vector.
|
||||
SmallVector<StringRef, 10> CVUDTNames;
|
||||
|
||||
StringSet<> TypeNames;
|
||||
};
|
||||
|
||||
} // end namespace codeview
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_DEBUGINFO_CODEVIEW_TYPEDUMPER_H
|
|
@ -1,59 +0,0 @@
|
|||
//===- LoopPassManager.cpp - Loop pass management -------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Analysis/LoopPassManager.h"
|
||||
#include "llvm/Analysis/BasicAliasAnalysis.h"
|
||||
#include "llvm/Analysis/GlobalsModRef.h"
|
||||
#include "llvm/Analysis/LoopInfo.h"
|
||||
#include "llvm/Analysis/ScalarEvolution.h"
|
||||
#include "llvm/Analysis/ScalarEvolutionAliasAnalysis.h"
|
||||
#include "llvm/IR/Dominators.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
// Explicit template instantiations and specialization defininitions for core
|
||||
// template typedefs.
|
||||
namespace llvm {
|
||||
template class PassManager<Loop>;
|
||||
template class AnalysisManager<Loop>;
|
||||
template class InnerAnalysisManagerProxy<LoopAnalysisManager, Function>;
|
||||
template class OuterAnalysisManagerProxy<FunctionAnalysisManager, Loop>;
|
||||
|
||||
template <>
|
||||
bool LoopAnalysisManagerFunctionProxy::Result::invalidate(
|
||||
Function &F, const PreservedAnalyses &PA,
|
||||
FunctionAnalysisManager::Invalidator &Inv) {
|
||||
// If this proxy isn't marked as preserved, the set of Function objects in
|
||||
// the module may have changed. We therefore can't call
|
||||
// InnerAM->invalidate(), because any pointers to Functions it has may be
|
||||
// stale.
|
||||
auto PAC = PA.getChecker<LoopAnalysisManagerFunctionProxy>();
|
||||
if (!PAC.preserved() && !PAC.preservedSet<AllAnalysesOn<Loop>>())
|
||||
InnerAM->clear();
|
||||
|
||||
// FIXME: Proper suppor for invalidation isn't yet implemented for the LPM.
|
||||
|
||||
// Return false to indicate that this result is still a valid proxy.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
PreservedAnalyses llvm::getLoopPassPreservedAnalyses() {
|
||||
PreservedAnalyses PA;
|
||||
PA.preserve<DominatorTreeAnalysis>();
|
||||
PA.preserve<LoopAnalysis>();
|
||||
PA.preserve<ScalarEvolutionAnalysis>();
|
||||
// TODO: What we really want to do here is preserve an AA category, but that
|
||||
// concept doesn't exist yet.
|
||||
PA.preserve<AAManager>();
|
||||
PA.preserve<BasicAA>();
|
||||
PA.preserve<GlobalsAA>();
|
||||
PA.preserve<SCEVAA>();
|
||||
return PA;
|
||||
}
|
|
@ -1,772 +0,0 @@
|
|||
//===-- TypeDumper.cpp - CodeView type info dumper --------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/DebugInfo/CodeView/TypeDumper.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
|
||||
#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
|
||||
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
|
||||
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
|
||||
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
|
||||
#include "llvm/DebugInfo/MSF/ByteStream.h"
|
||||
#include "llvm/Support/ScopedPrinter.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::codeview;
|
||||
|
||||
/// The names here all end in "*". If the simple type is a pointer type, we
|
||||
/// return the whole name. Otherwise we lop off the last character in our
|
||||
/// StringRef.
|
||||
static const EnumEntry<SimpleTypeKind> SimpleTypeNames[] = {
|
||||
{"void*", SimpleTypeKind::Void},
|
||||
{"<not translated>*", SimpleTypeKind::NotTranslated},
|
||||
{"HRESULT*", SimpleTypeKind::HResult},
|
||||
{"signed char*", SimpleTypeKind::SignedCharacter},
|
||||
{"unsigned char*", SimpleTypeKind::UnsignedCharacter},
|
||||
{"char*", SimpleTypeKind::NarrowCharacter},
|
||||
{"wchar_t*", SimpleTypeKind::WideCharacter},
|
||||
{"char16_t*", SimpleTypeKind::Character16},
|
||||
{"char32_t*", SimpleTypeKind::Character32},
|
||||
{"__int8*", SimpleTypeKind::SByte},
|
||||
{"unsigned __int8*", SimpleTypeKind::Byte},
|
||||
{"short*", SimpleTypeKind::Int16Short},
|
||||
{"unsigned short*", SimpleTypeKind::UInt16Short},
|
||||
{"__int16*", SimpleTypeKind::Int16},
|
||||
{"unsigned __int16*", SimpleTypeKind::UInt16},
|
||||
{"long*", SimpleTypeKind::Int32Long},
|
||||
{"unsigned long*", SimpleTypeKind::UInt32Long},
|
||||
{"int*", SimpleTypeKind::Int32},
|
||||
{"unsigned*", SimpleTypeKind::UInt32},
|
||||
{"__int64*", SimpleTypeKind::Int64Quad},
|
||||
{"unsigned __int64*", SimpleTypeKind::UInt64Quad},
|
||||
{"__int64*", SimpleTypeKind::Int64},
|
||||
{"unsigned __int64*", SimpleTypeKind::UInt64},
|
||||
{"__int128*", SimpleTypeKind::Int128},
|
||||
{"unsigned __int128*", SimpleTypeKind::UInt128},
|
||||
{"__half*", SimpleTypeKind::Float16},
|
||||
{"float*", SimpleTypeKind::Float32},
|
||||
{"float*", SimpleTypeKind::Float32PartialPrecision},
|
||||
{"__float48*", SimpleTypeKind::Float48},
|
||||
{"double*", SimpleTypeKind::Float64},
|
||||
{"long double*", SimpleTypeKind::Float80},
|
||||
{"__float128*", SimpleTypeKind::Float128},
|
||||
{"_Complex float*", SimpleTypeKind::Complex32},
|
||||
{"_Complex double*", SimpleTypeKind::Complex64},
|
||||
{"_Complex long double*", SimpleTypeKind::Complex80},
|
||||
{"_Complex __float128*", SimpleTypeKind::Complex128},
|
||||
{"bool*", SimpleTypeKind::Boolean8},
|
||||
{"__bool16*", SimpleTypeKind::Boolean16},
|
||||
{"__bool32*", SimpleTypeKind::Boolean32},
|
||||
{"__bool64*", SimpleTypeKind::Boolean64},
|
||||
};
|
||||
|
||||
static const EnumEntry<TypeLeafKind> LeafTypeNames[] = {
|
||||
#define CV_TYPE(enum, val) {#enum, enum},
|
||||
#include "llvm/DebugInfo/CodeView/TypeRecords.def"
|
||||
};
|
||||
|
||||
#define ENUM_ENTRY(enum_class, enum) \
|
||||
{ #enum, std::underlying_type < enum_class > ::type(enum_class::enum) }
|
||||
|
||||
static const EnumEntry<uint16_t> ClassOptionNames[] = {
|
||||
ENUM_ENTRY(ClassOptions, Packed),
|
||||
ENUM_ENTRY(ClassOptions, HasConstructorOrDestructor),
|
||||
ENUM_ENTRY(ClassOptions, HasOverloadedOperator),
|
||||
ENUM_ENTRY(ClassOptions, Nested),
|
||||
ENUM_ENTRY(ClassOptions, ContainsNestedClass),
|
||||
ENUM_ENTRY(ClassOptions, HasOverloadedAssignmentOperator),
|
||||
ENUM_ENTRY(ClassOptions, HasConversionOperator),
|
||||
ENUM_ENTRY(ClassOptions, ForwardReference),
|
||||
ENUM_ENTRY(ClassOptions, Scoped),
|
||||
ENUM_ENTRY(ClassOptions, HasUniqueName),
|
||||
ENUM_ENTRY(ClassOptions, Sealed),
|
||||
ENUM_ENTRY(ClassOptions, Intrinsic),
|
||||
};
|
||||
|
||||
static const EnumEntry<uint8_t> MemberAccessNames[] = {
|
||||
ENUM_ENTRY(MemberAccess, None),
|
||||
ENUM_ENTRY(MemberAccess, Private),
|
||||
ENUM_ENTRY(MemberAccess, Protected),
|
||||
ENUM_ENTRY(MemberAccess, Public),
|
||||
};
|
||||
|
||||
static const EnumEntry<uint16_t> MethodOptionNames[] = {
|
||||
ENUM_ENTRY(MethodOptions, Pseudo),
|
||||
ENUM_ENTRY(MethodOptions, NoInherit),
|
||||
ENUM_ENTRY(MethodOptions, NoConstruct),
|
||||
ENUM_ENTRY(MethodOptions, CompilerGenerated),
|
||||
ENUM_ENTRY(MethodOptions, Sealed),
|
||||
};
|
||||
|
||||
static const EnumEntry<uint16_t> MemberKindNames[] = {
|
||||
ENUM_ENTRY(MethodKind, Vanilla),
|
||||
ENUM_ENTRY(MethodKind, Virtual),
|
||||
ENUM_ENTRY(MethodKind, Static),
|
||||
ENUM_ENTRY(MethodKind, Friend),
|
||||
ENUM_ENTRY(MethodKind, IntroducingVirtual),
|
||||
ENUM_ENTRY(MethodKind, PureVirtual),
|
||||
ENUM_ENTRY(MethodKind, PureIntroducingVirtual),
|
||||
};
|
||||
|
||||
static const EnumEntry<uint8_t> PtrKindNames[] = {
|
||||
ENUM_ENTRY(PointerKind, Near16),
|
||||
ENUM_ENTRY(PointerKind, Far16),
|
||||
ENUM_ENTRY(PointerKind, Huge16),
|
||||
ENUM_ENTRY(PointerKind, BasedOnSegment),
|
||||
ENUM_ENTRY(PointerKind, BasedOnValue),
|
||||
ENUM_ENTRY(PointerKind, BasedOnSegmentValue),
|
||||
ENUM_ENTRY(PointerKind, BasedOnAddress),
|
||||
ENUM_ENTRY(PointerKind, BasedOnSegmentAddress),
|
||||
ENUM_ENTRY(PointerKind, BasedOnType),
|
||||
ENUM_ENTRY(PointerKind, BasedOnSelf),
|
||||
ENUM_ENTRY(PointerKind, Near32),
|
||||
ENUM_ENTRY(PointerKind, Far32),
|
||||
ENUM_ENTRY(PointerKind, Near64),
|
||||
};
|
||||
|
||||
static const EnumEntry<uint8_t> PtrModeNames[] = {
|
||||
ENUM_ENTRY(PointerMode, Pointer),
|
||||
ENUM_ENTRY(PointerMode, LValueReference),
|
||||
ENUM_ENTRY(PointerMode, PointerToDataMember),
|
||||
ENUM_ENTRY(PointerMode, PointerToMemberFunction),
|
||||
ENUM_ENTRY(PointerMode, RValueReference),
|
||||
};
|
||||
|
||||
static const EnumEntry<uint16_t> PtrMemberRepNames[] = {
|
||||
ENUM_ENTRY(PointerToMemberRepresentation, Unknown),
|
||||
ENUM_ENTRY(PointerToMemberRepresentation, SingleInheritanceData),
|
||||
ENUM_ENTRY(PointerToMemberRepresentation, MultipleInheritanceData),
|
||||
ENUM_ENTRY(PointerToMemberRepresentation, VirtualInheritanceData),
|
||||
ENUM_ENTRY(PointerToMemberRepresentation, GeneralData),
|
||||
ENUM_ENTRY(PointerToMemberRepresentation, SingleInheritanceFunction),
|
||||
ENUM_ENTRY(PointerToMemberRepresentation, MultipleInheritanceFunction),
|
||||
ENUM_ENTRY(PointerToMemberRepresentation, VirtualInheritanceFunction),
|
||||
ENUM_ENTRY(PointerToMemberRepresentation, GeneralFunction),
|
||||
};
|
||||
|
||||
static const EnumEntry<uint16_t> TypeModifierNames[] = {
|
||||
ENUM_ENTRY(ModifierOptions, Const),
|
||||
ENUM_ENTRY(ModifierOptions, Volatile),
|
||||
ENUM_ENTRY(ModifierOptions, Unaligned),
|
||||
};
|
||||
|
||||
static const EnumEntry<uint8_t> CallingConventions[] = {
|
||||
ENUM_ENTRY(CallingConvention, NearC),
|
||||
ENUM_ENTRY(CallingConvention, FarC),
|
||||
ENUM_ENTRY(CallingConvention, NearPascal),
|
||||
ENUM_ENTRY(CallingConvention, FarPascal),
|
||||
ENUM_ENTRY(CallingConvention, NearFast),
|
||||
ENUM_ENTRY(CallingConvention, FarFast),
|
||||
ENUM_ENTRY(CallingConvention, NearStdCall),
|
||||
ENUM_ENTRY(CallingConvention, FarStdCall),
|
||||
ENUM_ENTRY(CallingConvention, NearSysCall),
|
||||
ENUM_ENTRY(CallingConvention, FarSysCall),
|
||||
ENUM_ENTRY(CallingConvention, ThisCall),
|
||||
ENUM_ENTRY(CallingConvention, MipsCall),
|
||||
ENUM_ENTRY(CallingConvention, Generic),
|
||||
ENUM_ENTRY(CallingConvention, AlphaCall),
|
||||
ENUM_ENTRY(CallingConvention, PpcCall),
|
||||
ENUM_ENTRY(CallingConvention, SHCall),
|
||||
ENUM_ENTRY(CallingConvention, ArmCall),
|
||||
ENUM_ENTRY(CallingConvention, AM33Call),
|
||||
ENUM_ENTRY(CallingConvention, TriCall),
|
||||
ENUM_ENTRY(CallingConvention, SH5Call),
|
||||
ENUM_ENTRY(CallingConvention, M32RCall),
|
||||
ENUM_ENTRY(CallingConvention, ClrCall),
|
||||
ENUM_ENTRY(CallingConvention, Inline),
|
||||
ENUM_ENTRY(CallingConvention, NearVector),
|
||||
};
|
||||
|
||||
static const EnumEntry<uint8_t> FunctionOptionEnum[] = {
|
||||
ENUM_ENTRY(FunctionOptions, CxxReturnUdt),
|
||||
ENUM_ENTRY(FunctionOptions, Constructor),
|
||||
ENUM_ENTRY(FunctionOptions, ConstructorWithVirtualBases),
|
||||
};
|
||||
|
||||
#undef ENUM_ENTRY
|
||||
|
||||
static StringRef getLeafTypeName(TypeLeafKind LT) {
|
||||
switch (LT) {
|
||||
#define TYPE_RECORD(ename, value, name) \
|
||||
case ename: \
|
||||
return #name;
|
||||
#include "llvm/DebugInfo/CodeView/TypeRecords.def"
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return "UnknownLeaf";
|
||||
}
|
||||
|
||||
Error CVTypeDumper::visitTypeBegin(CVRecord<TypeLeafKind> &Record) {
|
||||
assert(!IsInFieldList);
|
||||
// Reset Name to the empty string. If the visitor sets it, we know it.
|
||||
Name = "";
|
||||
|
||||
W->startLine() << getLeafTypeName(Record.Type);
|
||||
W->getOStream() << " (" << HexNumber(getNextTypeIndex()) << ")";
|
||||
W->getOStream() << " {\n";
|
||||
W->indent();
|
||||
W->printEnum("TypeLeafKind", unsigned(Record.Type),
|
||||
makeArrayRef(LeafTypeNames));
|
||||
if (Record.Type == LF_FIELDLIST) {
|
||||
// Record that we're in a field list so that members do not get assigned
|
||||
// type indices.
|
||||
IsInFieldList = true;
|
||||
}
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error CVTypeDumper::visitTypeEnd(CVRecord<TypeLeafKind> &Record) {
|
||||
if (Record.Type == LF_FIELDLIST) {
|
||||
assert(IsInFieldList);
|
||||
IsInFieldList = false;
|
||||
}
|
||||
assert(!IsInFieldList);
|
||||
|
||||
// Record every type that is not a field list member, even if Name is empty.
|
||||
// CVUDTNames is indexed by type index, and must have one entry for every
|
||||
// type. Field list members are not recorded, and are only referenced by
|
||||
// their containing field list record.
|
||||
recordType(Name);
|
||||
|
||||
if (PrintRecordBytes)
|
||||
W->printBinaryBlock("LeafData", getBytesAsCharacters(Record.content()));
|
||||
|
||||
W->unindent();
|
||||
W->startLine() << "}\n";
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error CVTypeDumper::visitMemberBegin(CVMemberRecord &Record) {
|
||||
assert(IsInFieldList);
|
||||
// Reset Name to the empty string. If the visitor sets it, we know it.
|
||||
Name = "";
|
||||
|
||||
W->startLine() << getLeafTypeName(Record.Kind);
|
||||
W->getOStream() << " {\n";
|
||||
W->indent();
|
||||
W->printEnum("TypeLeafKind", unsigned(Record.Kind),
|
||||
makeArrayRef(LeafTypeNames));
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error CVTypeDumper::visitMemberEnd(CVMemberRecord &Record) {
|
||||
assert(IsInFieldList);
|
||||
if (PrintRecordBytes)
|
||||
W->printBinaryBlock("LeafData", getBytesAsCharacters(Record.Data));
|
||||
|
||||
W->unindent();
|
||||
W->startLine() << "}\n";
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error CVTypeDumper::visitKnownRecord(CVRecord<TypeLeafKind> &CVR,
|
||||
FieldListRecord &FieldList) {
|
||||
CVTypeVisitor Visitor(*this);
|
||||
if (auto EC = Visitor.visitFieldListMemberStream(FieldList.Data))
|
||||
return EC;
|
||||
|
||||
Name = "<field list>";
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error CVTypeDumper::visitKnownRecord(CVRecord<TypeLeafKind> &CVR,
|
||||
StringIdRecord &String) {
|
||||
printTypeIndex("Id", String.getId());
|
||||
W->printString("StringData", String.getString());
|
||||
// Put this in CVUDTNames so it gets printed with LF_UDT_SRC_LINE.
|
||||
Name = String.getString();
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error CVTypeDumper::visitKnownRecord(CVRecord<TypeLeafKind> &CVR,
|
||||
ArgListRecord &Args) {
|
||||
auto Indices = Args.getIndices();
|
||||
uint32_t Size = Indices.size();
|
||||
W->printNumber("NumArgs", Size);
|
||||
ListScope Arguments(*W, "Arguments");
|
||||
SmallString<256> TypeName("(");
|
||||
for (uint32_t I = 0; I < Size; ++I) {
|
||||
printTypeIndex("ArgType", Indices[I]);
|
||||
StringRef ArgTypeName = getTypeName(Indices[I]);
|
||||
TypeName.append(ArgTypeName);
|
||||
if (I + 1 != Size)
|
||||
TypeName.append(", ");
|
||||
}
|
||||
TypeName.push_back(')');
|
||||
Name = saveName(TypeName);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error CVTypeDumper::visitKnownRecord(CVRecord<TypeLeafKind> &CVR,
|
||||
ClassRecord &Class) {
|
||||
uint16_t Props = static_cast<uint16_t>(Class.getOptions());
|
||||
W->printNumber("MemberCount", Class.getMemberCount());
|
||||
W->printFlags("Properties", Props, makeArrayRef(ClassOptionNames));
|
||||
printTypeIndex("FieldList", Class.getFieldList());
|
||||
printTypeIndex("DerivedFrom", Class.getDerivationList());
|
||||
printTypeIndex("VShape", Class.getVTableShape());
|
||||
W->printNumber("SizeOf", Class.getSize());
|
||||
W->printString("Name", Class.getName());
|
||||
if (Props & uint16_t(ClassOptions::HasUniqueName))
|
||||
W->printString("LinkageName", Class.getUniqueName());
|
||||
Name = Class.getName();
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error CVTypeDumper::visitKnownRecord(CVRecord<TypeLeafKind> &CVR,
|
||||
UnionRecord &Union) {
|
||||
uint16_t Props = static_cast<uint16_t>(Union.getOptions());
|
||||
W->printNumber("MemberCount", Union.getMemberCount());
|
||||
W->printFlags("Properties", Props, makeArrayRef(ClassOptionNames));
|
||||
printTypeIndex("FieldList", Union.getFieldList());
|
||||
W->printNumber("SizeOf", Union.getSize());
|
||||
W->printString("Name", Union.getName());
|
||||
if (Props & uint16_t(ClassOptions::HasUniqueName))
|
||||
W->printString("LinkageName", Union.getUniqueName());
|
||||
Name = Union.getName();
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error CVTypeDumper::visitKnownRecord(CVRecord<TypeLeafKind> &CVR,
|
||||
EnumRecord &Enum) {
|
||||
uint16_t Props = static_cast<uint16_t>(Enum.getOptions());
|
||||
W->printNumber("NumEnumerators", Enum.getMemberCount());
|
||||
W->printFlags("Properties", uint16_t(Enum.getOptions()),
|
||||
makeArrayRef(ClassOptionNames));
|
||||
printTypeIndex("UnderlyingType", Enum.getUnderlyingType());
|
||||
printTypeIndex("FieldListType", Enum.getFieldList());
|
||||
W->printString("Name", Enum.getName());
|
||||
if (Props & uint16_t(ClassOptions::HasUniqueName))
|
||||
W->printString("LinkageName", Enum.getUniqueName());
|
||||
Name = Enum.getName();
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error CVTypeDumper::visitKnownRecord(CVRecord<TypeLeafKind> &CVR,
|
||||
ArrayRecord &AT) {
|
||||
printTypeIndex("ElementType", AT.getElementType());
|
||||
printTypeIndex("IndexType", AT.getIndexType());
|
||||
W->printNumber("SizeOf", AT.getSize());
|
||||
W->printString("Name", AT.getName());
|
||||
Name = AT.getName();
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error CVTypeDumper::visitKnownRecord(CVRecord<TypeLeafKind> &CVR,
|
||||
VFTableRecord &VFT) {
|
||||
printTypeIndex("CompleteClass", VFT.getCompleteClass());
|
||||
printTypeIndex("OverriddenVFTable", VFT.getOverriddenVTable());
|
||||
W->printHex("VFPtrOffset", VFT.getVFPtrOffset());
|
||||
W->printString("VFTableName", VFT.getName());
|
||||
for (auto N : VFT.getMethodNames())
|
||||
W->printString("MethodName", N);
|
||||
Name = VFT.getName();
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error CVTypeDumper::visitKnownRecord(CVRecord<TypeLeafKind> &CVR,
|
||||
MemberFuncIdRecord &Id) {
|
||||
printTypeIndex("ClassType", Id.getClassType());
|
||||
printTypeIndex("FunctionType", Id.getFunctionType());
|
||||
W->printString("Name", Id.getName());
|
||||
Name = Id.getName();
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error CVTypeDumper::visitKnownRecord(CVRecord<TypeLeafKind> &CVR,
|
||||
ProcedureRecord &Proc) {
|
||||
printTypeIndex("ReturnType", Proc.getReturnType());
|
||||
W->printEnum("CallingConvention", uint8_t(Proc.getCallConv()),
|
||||
makeArrayRef(CallingConventions));
|
||||
W->printFlags("FunctionOptions", uint8_t(Proc.getOptions()),
|
||||
makeArrayRef(FunctionOptionEnum));
|
||||
W->printNumber("NumParameters", Proc.getParameterCount());
|
||||
printTypeIndex("ArgListType", Proc.getArgumentList());
|
||||
|
||||
StringRef ReturnTypeName = getTypeName(Proc.getReturnType());
|
||||
StringRef ArgListTypeName = getTypeName(Proc.getArgumentList());
|
||||
SmallString<256> TypeName(ReturnTypeName);
|
||||
TypeName.push_back(' ');
|
||||
TypeName.append(ArgListTypeName);
|
||||
Name = saveName(TypeName);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error CVTypeDumper::visitKnownRecord(CVRecord<TypeLeafKind> &CVR,
|
||||
MemberFunctionRecord &MF) {
|
||||
printTypeIndex("ReturnType", MF.getReturnType());
|
||||
printTypeIndex("ClassType", MF.getClassType());
|
||||
printTypeIndex("ThisType", MF.getThisType());
|
||||
W->printEnum("CallingConvention", uint8_t(MF.getCallConv()),
|
||||
makeArrayRef(CallingConventions));
|
||||
W->printFlags("FunctionOptions", uint8_t(MF.getOptions()),
|
||||
makeArrayRef(FunctionOptionEnum));
|
||||
W->printNumber("NumParameters", MF.getParameterCount());
|
||||
printTypeIndex("ArgListType", MF.getArgumentList());
|
||||
W->printNumber("ThisAdjustment", MF.getThisPointerAdjustment());
|
||||
|
||||
StringRef ReturnTypeName = getTypeName(MF.getReturnType());
|
||||
StringRef ClassTypeName = getTypeName(MF.getClassType());
|
||||
StringRef ArgListTypeName = getTypeName(MF.getArgumentList());
|
||||
SmallString<256> TypeName(ReturnTypeName);
|
||||
TypeName.push_back(' ');
|
||||
TypeName.append(ClassTypeName);
|
||||
TypeName.append("::");
|
||||
TypeName.append(ArgListTypeName);
|
||||
Name = saveName(TypeName);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error CVTypeDumper::visitKnownRecord(CVRecord<TypeLeafKind> &CVR,
|
||||
MethodOverloadListRecord &MethodList) {
|
||||
for (auto &M : MethodList.getMethods()) {
|
||||
ListScope S(*W, "Method");
|
||||
printMemberAttributes(M.getAccess(), M.getMethodKind(), M.getOptions());
|
||||
printTypeIndex("Type", M.getType());
|
||||
if (M.isIntroducingVirtual())
|
||||
W->printHex("VFTableOffset", M.getVFTableOffset());
|
||||
}
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error CVTypeDumper::visitKnownRecord(CVRecord<TypeLeafKind> &CVR,
|
||||
FuncIdRecord &Func) {
|
||||
printTypeIndex("ParentScope", Func.getParentScope());
|
||||
printTypeIndex("FunctionType", Func.getFunctionType());
|
||||
W->printString("Name", Func.getName());
|
||||
Name = Func.getName();
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error CVTypeDumper::visitKnownRecord(CVRecord<TypeLeafKind> &CVR,
|
||||
TypeServer2Record &TS) {
|
||||
W->printBinary("Signature", TS.getGuid());
|
||||
W->printNumber("Age", TS.getAge());
|
||||
W->printString("Name", TS.getName());
|
||||
Name = TS.getName();
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error CVTypeDumper::visitKnownRecord(CVRecord<TypeLeafKind> &CVR,
|
||||
PointerRecord &Ptr) {
|
||||
printTypeIndex("PointeeType", Ptr.getReferentType());
|
||||
W->printHex("PointerAttributes", uint32_t(Ptr.getOptions()));
|
||||
W->printEnum("PtrType", unsigned(Ptr.getPointerKind()),
|
||||
makeArrayRef(PtrKindNames));
|
||||
W->printEnum("PtrMode", unsigned(Ptr.getMode()), makeArrayRef(PtrModeNames));
|
||||
|
||||
W->printNumber("IsFlat", Ptr.isFlat());
|
||||
W->printNumber("IsConst", Ptr.isConst());
|
||||
W->printNumber("IsVolatile", Ptr.isVolatile());
|
||||
W->printNumber("IsUnaligned", Ptr.isUnaligned());
|
||||
W->printNumber("SizeOf", Ptr.getSize());
|
||||
|
||||
if (Ptr.isPointerToMember()) {
|
||||
const MemberPointerInfo &MI = Ptr.getMemberInfo();
|
||||
|
||||
printTypeIndex("ClassType", MI.getContainingType());
|
||||
W->printEnum("Representation", uint16_t(MI.getRepresentation()),
|
||||
makeArrayRef(PtrMemberRepNames));
|
||||
|
||||
StringRef PointeeName = getTypeName(Ptr.getReferentType());
|
||||
StringRef ClassName = getTypeName(MI.getContainingType());
|
||||
SmallString<256> TypeName(PointeeName);
|
||||
TypeName.push_back(' ');
|
||||
TypeName.append(ClassName);
|
||||
TypeName.append("::*");
|
||||
Name = saveName(TypeName);
|
||||
} else {
|
||||
SmallString<256> TypeName;
|
||||
if (Ptr.isConst())
|
||||
TypeName.append("const ");
|
||||
if (Ptr.isVolatile())
|
||||
TypeName.append("volatile ");
|
||||
if (Ptr.isUnaligned())
|
||||
TypeName.append("__unaligned ");
|
||||
|
||||
TypeName.append(getTypeName(Ptr.getReferentType()));
|
||||
|
||||
if (Ptr.getMode() == PointerMode::LValueReference)
|
||||
TypeName.append("&");
|
||||
else if (Ptr.getMode() == PointerMode::RValueReference)
|
||||
TypeName.append("&&");
|
||||
else if (Ptr.getMode() == PointerMode::Pointer)
|
||||
TypeName.append("*");
|
||||
|
||||
if (!TypeName.empty())
|
||||
Name = saveName(TypeName);
|
||||
}
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error CVTypeDumper::visitKnownRecord(CVRecord<TypeLeafKind> &CVR,
|
||||
ModifierRecord &Mod) {
|
||||
uint16_t Mods = static_cast<uint16_t>(Mod.getModifiers());
|
||||
printTypeIndex("ModifiedType", Mod.getModifiedType());
|
||||
W->printFlags("Modifiers", Mods, makeArrayRef(TypeModifierNames));
|
||||
|
||||
StringRef ModifiedName = getTypeName(Mod.getModifiedType());
|
||||
SmallString<256> TypeName;
|
||||
if (Mods & uint16_t(ModifierOptions::Const))
|
||||
TypeName.append("const ");
|
||||
if (Mods & uint16_t(ModifierOptions::Volatile))
|
||||
TypeName.append("volatile ");
|
||||
if (Mods & uint16_t(ModifierOptions::Unaligned))
|
||||
TypeName.append("__unaligned ");
|
||||
TypeName.append(ModifiedName);
|
||||
Name = saveName(TypeName);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error CVTypeDumper::visitKnownRecord(CVRecord<TypeLeafKind> &CVR,
|
||||
BitFieldRecord &BitField) {
|
||||
printTypeIndex("Type", BitField.getType());
|
||||
W->printNumber("BitSize", BitField.getBitSize());
|
||||
W->printNumber("BitOffset", BitField.getBitOffset());
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error CVTypeDumper::visitKnownRecord(CVRecord<TypeLeafKind> &CVR,
|
||||
VFTableShapeRecord &Shape) {
|
||||
W->printNumber("VFEntryCount", Shape.getEntryCount());
|
||||
Name = saveName("<vftable " + utostr(Shape.getEntryCount()) + " methods>");
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error CVTypeDumper::visitKnownRecord(CVRecord<TypeLeafKind> &CVR,
|
||||
UdtSourceLineRecord &Line) {
|
||||
printTypeIndex("UDT", Line.getUDT());
|
||||
printTypeIndex("SourceFile", Line.getSourceFile());
|
||||
W->printNumber("LineNumber", Line.getLineNumber());
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error CVTypeDumper::visitKnownRecord(CVRecord<TypeLeafKind> &CVR,
|
||||
UdtModSourceLineRecord &Line) {
|
||||
printTypeIndex("UDT", Line.getUDT());
|
||||
printTypeIndex("SourceFile", Line.getSourceFile());
|
||||
W->printNumber("LineNumber", Line.getLineNumber());
|
||||
W->printNumber("Module", Line.getModule());
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error CVTypeDumper::visitKnownRecord(CVRecord<TypeLeafKind> &CVR,
|
||||
BuildInfoRecord &Args) {
|
||||
W->printNumber("NumArgs", static_cast<uint32_t>(Args.getArgs().size()));
|
||||
|
||||
ListScope Arguments(*W, "Arguments");
|
||||
for (auto Arg : Args.getArgs()) {
|
||||
printTypeIndex("ArgType", Arg);
|
||||
}
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
void CVTypeDumper::printMemberAttributes(MemberAttributes Attrs) {
|
||||
return printMemberAttributes(Attrs.getAccess(), Attrs.getMethodKind(),
|
||||
Attrs.getFlags());
|
||||
}
|
||||
|
||||
void CVTypeDumper::printMemberAttributes(MemberAccess Access, MethodKind Kind,
|
||||
MethodOptions Options) {
|
||||
W->printEnum("AccessSpecifier", uint8_t(Access),
|
||||
makeArrayRef(MemberAccessNames));
|
||||
// Data members will be vanilla. Don't try to print a method kind for them.
|
||||
if (Kind != MethodKind::Vanilla)
|
||||
W->printEnum("MethodKind", unsigned(Kind), makeArrayRef(MemberKindNames));
|
||||
if (Options != MethodOptions::None) {
|
||||
W->printFlags("MethodOptions", unsigned(Options),
|
||||
makeArrayRef(MethodOptionNames));
|
||||
}
|
||||
}
|
||||
|
||||
Error CVTypeDumper::visitUnknownMember(CVMemberRecord &Record) {
|
||||
W->printHex("UnknownMember", unsigned(Record.Kind));
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error CVTypeDumper::visitUnknownType(CVRecord<TypeLeafKind> &Record) {
|
||||
W->printEnum("Kind", uint16_t(Record.kind()), makeArrayRef(LeafTypeNames));
|
||||
W->printNumber("Length", uint32_t(Record.content().size()));
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error CVTypeDumper::visitKnownMember(CVMemberRecord &CVR,
|
||||
NestedTypeRecord &Nested) {
|
||||
printTypeIndex("Type", Nested.getNestedType());
|
||||
W->printString("Name", Nested.getName());
|
||||
Name = Nested.getName();
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error CVTypeDumper::visitKnownMember(CVMemberRecord &CVR,
|
||||
OneMethodRecord &Method) {
|
||||
MethodKind K = Method.getMethodKind();
|
||||
printMemberAttributes(Method.getAccess(), K, Method.getOptions());
|
||||
printTypeIndex("Type", Method.getType());
|
||||
// If virtual, then read the vftable offset.
|
||||
if (Method.isIntroducingVirtual())
|
||||
W->printHex("VFTableOffset", Method.getVFTableOffset());
|
||||
W->printString("Name", Method.getName());
|
||||
Name = Method.getName();
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error CVTypeDumper::visitKnownMember(CVMemberRecord &CVR,
|
||||
OverloadedMethodRecord &Method) {
|
||||
W->printHex("MethodCount", Method.getNumOverloads());
|
||||
printTypeIndex("MethodListIndex", Method.getMethodList());
|
||||
W->printString("Name", Method.getName());
|
||||
Name = Method.getName();
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error CVTypeDumper::visitKnownMember(CVMemberRecord &CVR,
|
||||
DataMemberRecord &Field) {
|
||||
printMemberAttributes(Field.getAccess(), MethodKind::Vanilla,
|
||||
MethodOptions::None);
|
||||
printTypeIndex("Type", Field.getType());
|
||||
W->printHex("FieldOffset", Field.getFieldOffset());
|
||||
W->printString("Name", Field.getName());
|
||||
Name = Field.getName();
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error CVTypeDumper::visitKnownMember(CVMemberRecord &CVR,
|
||||
StaticDataMemberRecord &Field) {
|
||||
printMemberAttributes(Field.getAccess(), MethodKind::Vanilla,
|
||||
MethodOptions::None);
|
||||
printTypeIndex("Type", Field.getType());
|
||||
W->printString("Name", Field.getName());
|
||||
Name = Field.getName();
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error CVTypeDumper::visitKnownMember(CVMemberRecord &CVR,
|
||||
VFPtrRecord &VFTable) {
|
||||
printTypeIndex("Type", VFTable.getType());
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error CVTypeDumper::visitKnownMember(CVMemberRecord &CVR,
|
||||
EnumeratorRecord &Enum) {
|
||||
printMemberAttributes(Enum.getAccess(), MethodKind::Vanilla,
|
||||
MethodOptions::None);
|
||||
W->printNumber("EnumValue", Enum.getValue());
|
||||
W->printString("Name", Enum.getName());
|
||||
Name = Enum.getName();
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error CVTypeDumper::visitKnownMember(CVMemberRecord &CVR,
|
||||
BaseClassRecord &Base) {
|
||||
printMemberAttributes(Base.getAccess(), MethodKind::Vanilla,
|
||||
MethodOptions::None);
|
||||
printTypeIndex("BaseType", Base.getBaseType());
|
||||
W->printHex("BaseOffset", Base.getBaseOffset());
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error CVTypeDumper::visitKnownMember(CVMemberRecord &CVR,
|
||||
VirtualBaseClassRecord &Base) {
|
||||
printMemberAttributes(Base.getAccess(), MethodKind::Vanilla,
|
||||
MethodOptions::None);
|
||||
printTypeIndex("BaseType", Base.getBaseType());
|
||||
printTypeIndex("VBPtrType", Base.getVBPtrType());
|
||||
W->printHex("VBPtrOffset", Base.getVBPtrOffset());
|
||||
W->printHex("VBTableIndex", Base.getVTableIndex());
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error CVTypeDumper::visitKnownMember(CVMemberRecord &CVR,
|
||||
ListContinuationRecord &Cont) {
|
||||
printTypeIndex("ContinuationIndex", Cont.getContinuationIndex());
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
StringRef CVTypeDumper::getTypeName(TypeIndex TI) {
|
||||
if (TI.isNoneType())
|
||||
return "<no type>";
|
||||
|
||||
if (TI.isSimple()) {
|
||||
// This is a simple type.
|
||||
for (const auto &SimpleTypeName : SimpleTypeNames) {
|
||||
if (SimpleTypeName.Value == TI.getSimpleKind()) {
|
||||
if (TI.getSimpleMode() == SimpleTypeMode::Direct)
|
||||
return SimpleTypeName.Name.drop_back(1);
|
||||
// Otherwise, this is a pointer type. We gloss over the distinction
|
||||
// between near, far, 64, 32, etc, and just give a pointer type.
|
||||
return SimpleTypeName.Name;
|
||||
}
|
||||
}
|
||||
return "<unknown simple type>";
|
||||
}
|
||||
|
||||
// User-defined type.
|
||||
StringRef UDTName;
|
||||
unsigned UDTIndex = TI.getIndex() - 0x1000;
|
||||
if (UDTIndex < CVUDTNames.size())
|
||||
return CVUDTNames[UDTIndex];
|
||||
|
||||
return "<unknown UDT>";
|
||||
}
|
||||
|
||||
void CVTypeDumper::printTypeIndex(StringRef FieldName, TypeIndex TI) {
|
||||
StringRef TypeName;
|
||||
if (!TI.isNoneType())
|
||||
TypeName = getTypeName(TI);
|
||||
if (!TypeName.empty())
|
||||
W->printHex(FieldName, TypeName, TI.getIndex());
|
||||
else
|
||||
W->printHex(FieldName, TI.getIndex());
|
||||
}
|
||||
|
||||
Error CVTypeDumper::dump(const CVRecord<TypeLeafKind> &Record) {
|
||||
assert(W && "printer should not be null");
|
||||
TypeDeserializer Deserializer;
|
||||
TypeVisitorCallbackPipeline Pipeline;
|
||||
Pipeline.addCallbackToPipeline(Deserializer);
|
||||
Pipeline.addCallbackToPipeline(*this);
|
||||
|
||||
CVTypeVisitor Visitor(Pipeline);
|
||||
|
||||
CVRecord<TypeLeafKind> RecordCopy = Record;
|
||||
if (auto EC = Visitor.visitTypeRecord(RecordCopy))
|
||||
return EC;
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error CVTypeDumper::dump(const CVTypeArray &Types) {
|
||||
assert(W && "printer should not be null");
|
||||
TypeDeserializer Deserializer;
|
||||
TypeVisitorCallbackPipeline Pipeline;
|
||||
Pipeline.addCallbackToPipeline(Deserializer);
|
||||
Pipeline.addCallbackToPipeline(*this);
|
||||
|
||||
CVTypeVisitor Visitor(Pipeline);
|
||||
|
||||
if (auto EC = Visitor.visitTypeStream(Types))
|
||||
return EC;
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error CVTypeDumper::dump(ArrayRef<uint8_t> Data) {
|
||||
msf::ByteStream Stream(Data);
|
||||
CVTypeArray Types;
|
||||
msf::StreamReader Reader(Stream);
|
||||
if (auto EC = Reader.readArray(Types, Reader.getLength()))
|
||||
return EC;
|
||||
|
||||
return dump(Types);
|
||||
}
|
||||
|
||||
void CVTypeDumper::setPrinter(ScopedPrinter *P) {
|
||||
static ScopedPrinter NullP(llvm::nulls());
|
||||
W = P ? P : &NullP;
|
||||
}
|
|
@ -1,86 +0,0 @@
|
|||
; RUN: opt < %s -mtriple=aarch64 -interleaved-access -S | FileCheck %s
|
||||
|
||||
; CHECK-LABEL: @extract_user_basic(
|
||||
; CHECK: %ldN = call { <4 x i32>, <4 x i32> } @llvm.aarch64.neon.ld2.v4i32.p0v4i32
|
||||
; CHECK: %[[R:.+]] = extractvalue { <4 x i32>, <4 x i32> } %ldN, 0
|
||||
; CHECK: extractelement <4 x i32> %[[R]], i64 1
|
||||
define void @extract_user_basic(<8 x i32>* %A, i1 %C) {
|
||||
entry:
|
||||
%L = load <8 x i32>, <8 x i32>* %A, align 8
|
||||
%S = shufflevector <8 x i32> %L, <8 x i32> undef, <4 x i32> <i32 0, i32 2, i32 4, i32 6>
|
||||
br i1 %C, label %if.then, label %if.merge
|
||||
|
||||
if.then:
|
||||
%E = extractelement <8 x i32> %L, i32 2
|
||||
br label %if.merge
|
||||
|
||||
if.merge:
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK-LABEL: @extract_user_multi(
|
||||
; CHECK: %ldN = call { <4 x i32>, <4 x i32> } @llvm.aarch64.neon.ld2.v4i32.p0v4i32
|
||||
; CHECK: %[[R:.+]] = extractvalue { <4 x i32>, <4 x i32> } %ldN, 0
|
||||
; CHECK: extractelement <4 x i32> %[[R]], i64 0
|
||||
; CHECK: extractelement <4 x i32> %[[R]], i64 1
|
||||
define void @extract_user_multi(<8 x i32>* %A, i1 %C) {
|
||||
entry:
|
||||
%L = load <8 x i32>, <8 x i32>* %A, align 8
|
||||
%S = shufflevector <8 x i32> %L, <8 x i32> undef, <4 x i32> <i32 0, i32 2, i32 4, i32 6>
|
||||
br i1 %C, label %if.then, label %if.merge
|
||||
|
||||
if.then:
|
||||
%E1 = extractelement <8 x i32> %L, i32 0
|
||||
br label %if.merge
|
||||
|
||||
if.merge:
|
||||
%E2 = extractelement <8 x i32> %L, i32 2
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK-LABEL: @extract_user_multi_no_dom(
|
||||
; CHECK-NOT: %ldN = call { <4 x i32>, <4 x i32> } @llvm.aarch64.neon.ld2.v4i32.p0v4i32
|
||||
define void @extract_user_multi_no_dom(<8 x i32>* %A, i1 %C) {
|
||||
entry:
|
||||
%L = load <8 x i32>, <8 x i32>* %A, align 8
|
||||
%E1 = extractelement <8 x i32> %L, i32 0
|
||||
br i1 %C, label %if.then, label %if.merge
|
||||
|
||||
if.then:
|
||||
%S = shufflevector <8 x i32> %L, <8 x i32> undef, <4 x i32> <i32 0, i32 2, i32 4, i32 6>
|
||||
%E2 = extractelement <8 x i32> %L, i32 2
|
||||
br label %if.merge
|
||||
|
||||
if.merge:
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK-LABEL: @extract_user_wrong_const_index(
|
||||
; CHECK-NOT: %ldN = call { <4 x i32>, <4 x i32> } @llvm.aarch64.neon.ld2.v4i32.p0v4i32
|
||||
define void @extract_user_wrong_const_index(<8 x i32>* %A) {
|
||||
entry:
|
||||
%L = load <8 x i32>, <8 x i32>* %A, align 8
|
||||
%S = shufflevector <8 x i32> %L, <8 x i32> undef, <4 x i32> <i32 0, i32 2, i32 4, i32 6>
|
||||
%E = extractelement <8 x i32> %L, i32 1
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK-LABEL: @extract_user_undef_index(
|
||||
; CHECK-NOT: %ldN = call { <4 x i32>, <4 x i32> } @llvm.aarch64.neon.ld2.v4i32.p0v4i32
|
||||
define void @extract_user_undef_index(<8 x i32>* %A) {
|
||||
entry:
|
||||
%L = load <8 x i32>, <8 x i32>* %A, align 8
|
||||
%S = shufflevector <8 x i32> %L, <8 x i32> undef, <4 x i32> <i32 0, i32 2, i32 4, i32 6>
|
||||
%E = extractelement <8 x i32> %L, i32 undef
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK-LABEL: @extract_user_var_index(
|
||||
; CHECK-NOT: %ldN = call { <4 x i32>, <4 x i32> } @llvm.aarch64.neon.ld2.v4i32.p0v4i32
|
||||
define void @extract_user_var_index(<8 x i32>* %A, i32 %I) {
|
||||
entry:
|
||||
%L = load <8 x i32>, <8 x i32>* %A, align 8
|
||||
%S = shufflevector <8 x i32> %L, <8 x i32> undef, <4 x i32> <i32 0, i32 2, i32 4, i32 6>
|
||||
%E = extractelement <8 x i32> %L, i32 %I
|
||||
ret void
|
||||
}
|
|
@ -1,393 +0,0 @@
|
|||
; RUN: llc -mtriple=aarch64 -lower-interleaved-accesses=true < %s | FileCheck %s -check-prefix=NEON
|
||||
; RUN: llc -mtriple=aarch64 -lower-interleaved-accesses=true -mattr=-neon < %s | FileCheck %s -check-prefix=NONEON
|
||||
|
||||
; NEON-LABEL: load_factor2:
|
||||
; NEON: ld2 { v0.8b, v1.8b }, [x0]
|
||||
; NONEON-LABEL: load_factor2:
|
||||
; NONEON-NOT: ld2
|
||||
define <8 x i8> @load_factor2(<16 x i8>* %ptr) {
|
||||
%wide.vec = load <16 x i8>, <16 x i8>* %ptr, align 4
|
||||
%strided.v0 = shufflevector <16 x i8> %wide.vec, <16 x i8> undef, <8 x i32> <i32 0, i32 2, i32 4, i32 6, i32 8, i32 10, i32 12, i32 14>
|
||||
%strided.v1 = shufflevector <16 x i8> %wide.vec, <16 x i8> undef, <8 x i32> <i32 1, i32 3, i32 5, i32 7, i32 9, i32 11, i32 13, i32 15>
|
||||
%add = add nsw <8 x i8> %strided.v0, %strided.v1
|
||||
ret <8 x i8> %add
|
||||
}
|
||||
|
||||
; NEON-LABEL: load_factor3:
|
||||
; NEON: ld3 { v0.4s, v1.4s, v2.4s }, [x0]
|
||||
; NONEON-LABEL: load_factor3:
|
||||
; NONEON-NOT: ld3
|
||||
define <4 x i32> @load_factor3(i32* %ptr) {
|
||||
%base = bitcast i32* %ptr to <12 x i32>*
|
||||
%wide.vec = load <12 x i32>, <12 x i32>* %base, align 4
|
||||
%strided.v2 = shufflevector <12 x i32> %wide.vec, <12 x i32> undef, <4 x i32> <i32 2, i32 5, i32 8, i32 11>
|
||||
%strided.v1 = shufflevector <12 x i32> %wide.vec, <12 x i32> undef, <4 x i32> <i32 1, i32 4, i32 7, i32 10>
|
||||
%add = add nsw <4 x i32> %strided.v2, %strided.v1
|
||||
ret <4 x i32> %add
|
||||
}
|
||||
|
||||
; NEON-LABEL: load_factor4:
|
||||
; NEON: ld4 { v0.4s, v1.4s, v2.4s, v3.4s }, [x0]
|
||||
; NONEON-LABEL: load_factor4:
|
||||
; NONEON-NOT: ld4
|
||||
define <4 x i32> @load_factor4(i32* %ptr) {
|
||||
%base = bitcast i32* %ptr to <16 x i32>*
|
||||
%wide.vec = load <16 x i32>, <16 x i32>* %base, align 4
|
||||
%strided.v0 = shufflevector <16 x i32> %wide.vec, <16 x i32> undef, <4 x i32> <i32 0, i32 4, i32 8, i32 12>
|
||||
%strided.v2 = shufflevector <16 x i32> %wide.vec, <16 x i32> undef, <4 x i32> <i32 2, i32 6, i32 10, i32 14>
|
||||
%add = add nsw <4 x i32> %strided.v0, %strided.v2
|
||||
ret <4 x i32> %add
|
||||
}
|
||||
|
||||
; NEON-LABEL: store_factor2:
|
||||
; NEON: st2 { v0.8b, v1.8b }, [x0]
|
||||
; NONEON-LABEL: store_factor2:
|
||||
; NONEON-NOT: st2
|
||||
define void @store_factor2(<16 x i8>* %ptr, <8 x i8> %v0, <8 x i8> %v1) {
|
||||
%interleaved.vec = shufflevector <8 x i8> %v0, <8 x i8> %v1, <16 x i32> <i32 0, i32 8, i32 1, i32 9, i32 2, i32 10, i32 3, i32 11, i32 4, i32 12, i32 5, i32 13, i32 6, i32 14, i32 7, i32 15>
|
||||
store <16 x i8> %interleaved.vec, <16 x i8>* %ptr, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; NEON-LABEL: store_factor3:
|
||||
; NEON: st3 { v0.4s, v1.4s, v2.4s }, [x0]
|
||||
; NONEON-LABEL: store_factor3:
|
||||
; NONEON-NOT: st3
|
||||
define void @store_factor3(i32* %ptr, <4 x i32> %v0, <4 x i32> %v1, <4 x i32> %v2) {
|
||||
%base = bitcast i32* %ptr to <12 x i32>*
|
||||
%v0_v1 = shufflevector <4 x i32> %v0, <4 x i32> %v1, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
|
||||
%v2_u = shufflevector <4 x i32> %v2, <4 x i32> undef, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 undef, i32 undef, i32 undef, i32 undef>
|
||||
%interleaved.vec = shufflevector <8 x i32> %v0_v1, <8 x i32> %v2_u, <12 x i32> <i32 0, i32 4, i32 8, i32 1, i32 5, i32 9, i32 2, i32 6, i32 10, i32 3, i32 7, i32 11>
|
||||
store <12 x i32> %interleaved.vec, <12 x i32>* %base, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; NEON-LABEL: store_factor4:
|
||||
; NEON: st4 { v0.4s, v1.4s, v2.4s, v3.4s }, [x0]
|
||||
; NONEON-LABEL: store_factor4:
|
||||
; NONEON-NOT: st4
|
||||
define void @store_factor4(i32* %ptr, <4 x i32> %v0, <4 x i32> %v1, <4 x i32> %v2, <4 x i32> %v3) {
|
||||
%base = bitcast i32* %ptr to <16 x i32>*
|
||||
%v0_v1 = shufflevector <4 x i32> %v0, <4 x i32> %v1, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
|
||||
%v2_v3 = shufflevector <4 x i32> %v2, <4 x i32> %v3, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
|
||||
%interleaved.vec = shufflevector <8 x i32> %v0_v1, <8 x i32> %v2_v3, <16 x i32> <i32 0, i32 4, i32 8, i32 12, i32 1, i32 5, i32 9, i32 13, i32 2, i32 6, i32 10, i32 14, i32 3, i32 7, i32 11, i32 15>
|
||||
store <16 x i32> %interleaved.vec, <16 x i32>* %base, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; The following cases test that interleaved access of pointer vectors can be
|
||||
; matched to ldN/stN instruction.
|
||||
|
||||
; NEON-LABEL: load_ptrvec_factor2:
|
||||
; NEON: ld2 { v0.2d, v1.2d }, [x0]
|
||||
; NONEON-LABEL: load_ptrvec_factor2:
|
||||
; NONEON-NOT: ld2
|
||||
define <2 x i32*> @load_ptrvec_factor2(i32** %ptr) {
|
||||
%base = bitcast i32** %ptr to <4 x i32*>*
|
||||
%wide.vec = load <4 x i32*>, <4 x i32*>* %base, align 4
|
||||
%strided.v0 = shufflevector <4 x i32*> %wide.vec, <4 x i32*> undef, <2 x i32> <i32 0, i32 2>
|
||||
ret <2 x i32*> %strided.v0
|
||||
}
|
||||
|
||||
; NEON-LABEL: load_ptrvec_factor3:
|
||||
; NEON: ld3 { v0.2d, v1.2d, v2.2d }, [x0]
|
||||
; NONEON-LABEL: load_ptrvec_factor3:
|
||||
; NONEON-NOT: ld3
|
||||
define void @load_ptrvec_factor3(i32** %ptr, <2 x i32*>* %ptr1, <2 x i32*>* %ptr2) {
|
||||
%base = bitcast i32** %ptr to <6 x i32*>*
|
||||
%wide.vec = load <6 x i32*>, <6 x i32*>* %base, align 4
|
||||
%strided.v2 = shufflevector <6 x i32*> %wide.vec, <6 x i32*> undef, <2 x i32> <i32 2, i32 5>
|
||||
store <2 x i32*> %strided.v2, <2 x i32*>* %ptr1
|
||||
%strided.v1 = shufflevector <6 x i32*> %wide.vec, <6 x i32*> undef, <2 x i32> <i32 1, i32 4>
|
||||
store <2 x i32*> %strided.v1, <2 x i32*>* %ptr2
|
||||
ret void
|
||||
}
|
||||
|
||||
; NEON-LABEL: load_ptrvec_factor4:
|
||||
; NEON: ld4 { v0.2d, v1.2d, v2.2d, v3.2d }, [x0]
|
||||
; NONEON-LABEL: load_ptrvec_factor4:
|
||||
; NONEON-NOT: ld4
|
||||
define void @load_ptrvec_factor4(i32** %ptr, <2 x i32*>* %ptr1, <2 x i32*>* %ptr2) {
|
||||
%base = bitcast i32** %ptr to <8 x i32*>*
|
||||
%wide.vec = load <8 x i32*>, <8 x i32*>* %base, align 4
|
||||
%strided.v1 = shufflevector <8 x i32*> %wide.vec, <8 x i32*> undef, <2 x i32> <i32 1, i32 5>
|
||||
%strided.v3 = shufflevector <8 x i32*> %wide.vec, <8 x i32*> undef, <2 x i32> <i32 3, i32 7>
|
||||
store <2 x i32*> %strided.v1, <2 x i32*>* %ptr1
|
||||
store <2 x i32*> %strided.v3, <2 x i32*>* %ptr2
|
||||
ret void
|
||||
}
|
||||
|
||||
; NEON-LABEL: store_ptrvec_factor2:
|
||||
; NEON: st2 { v0.2d, v1.2d }, [x0]
|
||||
; NONEON-LABEL: store_ptrvec_factor2:
|
||||
; NONEON-NOT: st2
|
||||
define void @store_ptrvec_factor2(i32** %ptr, <2 x i32*> %v0, <2 x i32*> %v1) {
|
||||
%base = bitcast i32** %ptr to <4 x i32*>*
|
||||
%interleaved.vec = shufflevector <2 x i32*> %v0, <2 x i32*> %v1, <4 x i32> <i32 0, i32 2, i32 1, i32 3>
|
||||
store <4 x i32*> %interleaved.vec, <4 x i32*>* %base, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; NEON-LABEL: store_ptrvec_factor3:
|
||||
; NEON: st3 { v0.2d, v1.2d, v2.2d }, [x0]
|
||||
; NONEON-LABEL: store_ptrvec_factor3:
|
||||
; NONEON-NOT: st3
|
||||
define void @store_ptrvec_factor3(i32** %ptr, <2 x i32*> %v0, <2 x i32*> %v1, <2 x i32*> %v2) {
|
||||
%base = bitcast i32** %ptr to <6 x i32*>*
|
||||
%v0_v1 = shufflevector <2 x i32*> %v0, <2 x i32*> %v1, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
|
||||
%v2_u = shufflevector <2 x i32*> %v2, <2 x i32*> undef, <4 x i32> <i32 0, i32 1, i32 undef, i32 undef>
|
||||
%interleaved.vec = shufflevector <4 x i32*> %v0_v1, <4 x i32*> %v2_u, <6 x i32> <i32 0, i32 2, i32 4, i32 1, i32 3, i32 5>
|
||||
store <6 x i32*> %interleaved.vec, <6 x i32*>* %base, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; NEON-LABEL: store_ptrvec_factor4:
|
||||
; NEON: st4 { v0.2d, v1.2d, v2.2d, v3.2d }, [x0]
|
||||
; NONEON-LABEL: store_ptrvec_factor4:
|
||||
; NONEON-NOT: st4
|
||||
define void @store_ptrvec_factor4(i32* %ptr, <2 x i32*> %v0, <2 x i32*> %v1, <2 x i32*> %v2, <2 x i32*> %v3) {
|
||||
%base = bitcast i32* %ptr to <8 x i32*>*
|
||||
%v0_v1 = shufflevector <2 x i32*> %v0, <2 x i32*> %v1, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
|
||||
%v2_v3 = shufflevector <2 x i32*> %v2, <2 x i32*> %v3, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
|
||||
%interleaved.vec = shufflevector <4 x i32*> %v0_v1, <4 x i32*> %v2_v3, <8 x i32> <i32 0, i32 2, i32 4, i32 6, i32 1, i32 3, i32 5, i32 7>
|
||||
store <8 x i32*> %interleaved.vec, <8 x i32*>* %base, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; Following cases check that shuffle maskes with undef indices can be matched
|
||||
; into ldN/stN instruction.
|
||||
|
||||
; NEON-LABEL: load_undef_mask_factor2:
|
||||
; NEON: ld2 { v0.4s, v1.4s }, [x0]
|
||||
; NONEON-LABEL: load_undef_mask_factor2:
|
||||
; NONEON-NOT: ld2
|
||||
define <4 x i32> @load_undef_mask_factor2(i32* %ptr) {
|
||||
%base = bitcast i32* %ptr to <8 x i32>*
|
||||
%wide.vec = load <8 x i32>, <8 x i32>* %base, align 4
|
||||
%strided.v0 = shufflevector <8 x i32> %wide.vec, <8 x i32> undef, <4 x i32> <i32 undef, i32 2, i32 undef, i32 6>
|
||||
%strided.v1 = shufflevector <8 x i32> %wide.vec, <8 x i32> undef, <4 x i32> <i32 undef, i32 3, i32 undef, i32 7>
|
||||
%add = add nsw <4 x i32> %strided.v0, %strided.v1
|
||||
ret <4 x i32> %add
|
||||
}
|
||||
|
||||
; NEON-LABEL: load_undef_mask_factor3:
|
||||
; NEON: ld3 { v0.4s, v1.4s, v2.4s }, [x0]
|
||||
; NONEON-LABEL: load_undef_mask_factor3:
|
||||
; NONEON-NOT: ld3
|
||||
define <4 x i32> @load_undef_mask_factor3(i32* %ptr) {
|
||||
%base = bitcast i32* %ptr to <12 x i32>*
|
||||
%wide.vec = load <12 x i32>, <12 x i32>* %base, align 4
|
||||
%strided.v2 = shufflevector <12 x i32> %wide.vec, <12 x i32> undef, <4 x i32> <i32 2, i32 undef, i32 undef, i32 undef>
|
||||
%strided.v1 = shufflevector <12 x i32> %wide.vec, <12 x i32> undef, <4 x i32> <i32 1, i32 4, i32 7, i32 10>
|
||||
%add = add nsw <4 x i32> %strided.v2, %strided.v1
|
||||
ret <4 x i32> %add
|
||||
}
|
||||
|
||||
; NEON-LABEL: load_undef_mask_factor4:
|
||||
; NEON: ld4 { v0.4s, v1.4s, v2.4s, v3.4s }, [x0]
|
||||
; NONEON-LABEL: load_undef_mask_factor4:
|
||||
; NONEON-NOT: ld4
|
||||
define <4 x i32> @load_undef_mask_factor4(i32* %ptr) {
|
||||
%base = bitcast i32* %ptr to <16 x i32>*
|
||||
%wide.vec = load <16 x i32>, <16 x i32>* %base, align 4
|
||||
%strided.v0 = shufflevector <16 x i32> %wide.vec, <16 x i32> undef, <4 x i32> <i32 0, i32 4, i32 undef, i32 undef>
|
||||
%strided.v2 = shufflevector <16 x i32> %wide.vec, <16 x i32> undef, <4 x i32> <i32 2, i32 6, i32 undef, i32 undef>
|
||||
%add = add nsw <4 x i32> %strided.v0, %strided.v2
|
||||
ret <4 x i32> %add
|
||||
}
|
||||
|
||||
; NEON-LABEL: store_undef_mask_factor2:
|
||||
; NEON: st2 { v0.4s, v1.4s }, [x0]
|
||||
; NONEON-LABEL: store_undef_mask_factor2:
|
||||
; NONEON-NOT: st2
|
||||
define void @store_undef_mask_factor2(i32* %ptr, <4 x i32> %v0, <4 x i32> %v1) {
|
||||
%base = bitcast i32* %ptr to <8 x i32>*
|
||||
%interleaved.vec = shufflevector <4 x i32> %v0, <4 x i32> %v1, <8 x i32> <i32 undef, i32 undef, i32 undef, i32 undef, i32 2, i32 6, i32 3, i32 7>
|
||||
store <8 x i32> %interleaved.vec, <8 x i32>* %base, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; NEON-LABEL: store_undef_mask_factor3:
|
||||
; NEON: st3 { v0.4s, v1.4s, v2.4s }, [x0]
|
||||
; NONEON-LABEL: store_undef_mask_factor3:
|
||||
; NONEON-NOT: st3
|
||||
define void @store_undef_mask_factor3(i32* %ptr, <4 x i32> %v0, <4 x i32> %v1, <4 x i32> %v2) {
|
||||
%base = bitcast i32* %ptr to <12 x i32>*
|
||||
%v0_v1 = shufflevector <4 x i32> %v0, <4 x i32> %v1, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
|
||||
%v2_u = shufflevector <4 x i32> %v2, <4 x i32> undef, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 undef, i32 undef, i32 undef, i32 undef>
|
||||
%interleaved.vec = shufflevector <8 x i32> %v0_v1, <8 x i32> %v2_u, <12 x i32> <i32 0, i32 4, i32 undef, i32 1, i32 undef, i32 9, i32 2, i32 6, i32 10, i32 3, i32 7, i32 11>
|
||||
store <12 x i32> %interleaved.vec, <12 x i32>* %base, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; NEON-LABEL: store_undef_mask_factor4:
|
||||
; NEON: st4 { v0.4s, v1.4s, v2.4s, v3.4s }, [x0]
|
||||
; NONEON-LABEL: store_undef_mask_factor4:
|
||||
; NONEON-NOT: st4
|
||||
define void @store_undef_mask_factor4(i32* %ptr, <4 x i32> %v0, <4 x i32> %v1, <4 x i32> %v2, <4 x i32> %v3) {
|
||||
%base = bitcast i32* %ptr to <16 x i32>*
|
||||
%v0_v1 = shufflevector <4 x i32> %v0, <4 x i32> %v1, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
|
||||
%v2_v3 = shufflevector <4 x i32> %v2, <4 x i32> %v3, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
|
||||
%interleaved.vec = shufflevector <8 x i32> %v0_v1, <8 x i32> %v2_v3, <16 x i32> <i32 0, i32 4, i32 8, i32 undef, i32 undef, i32 5, i32 9, i32 13, i32 2, i32 6, i32 10, i32 14, i32 3, i32 7, i32 11, i32 15>
|
||||
store <16 x i32> %interleaved.vec, <16 x i32>* %base, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; Check that we do something sane with illegal types.
|
||||
|
||||
; NEON-LABEL: load_illegal_factor2:
|
||||
; NEON: BB#0:
|
||||
; NEON-NEXT: ldr q[[V:[0-9]+]], [x0]
|
||||
; NEON-NEXT: uzp1 v0.4s, v[[V]].4s, v{{.*}}.4s
|
||||
; NEON-NEXT: ret
|
||||
; NONEON-LABEL: load_illegal_factor2:
|
||||
; NONEON: BB#0:
|
||||
; NONEON-NEXT: ldr s0, [x0]
|
||||
; NONEON-NEXT: ldr s1, [x0, #8]
|
||||
; NONEON-NEXT: ret
|
||||
define <3 x float> @load_illegal_factor2(<3 x float>* %p) nounwind {
|
||||
%tmp1 = load <3 x float>, <3 x float>* %p, align 16
|
||||
%tmp2 = shufflevector <3 x float> %tmp1, <3 x float> undef, <3 x i32> <i32 0, i32 2, i32 undef>
|
||||
ret <3 x float> %tmp2
|
||||
}
|
||||
|
||||
; NEON-LABEL: store_illegal_factor2:
|
||||
; NEON: BB#0:
|
||||
; NEON-NEXT: uzp1 v0.4s, v0.4s, v{{.*}}.4s
|
||||
; NEON-NEXT: st1 { v0.d }[0], [x0]
|
||||
; NEON-NEXT: ret
|
||||
; NONEON-LABEL: store_illegal_factor2:
|
||||
; NONEON: BB#0:
|
||||
; NONEON-NEXT: fmov w[[ELT2:[0-9]+]], s2
|
||||
; NONEON-NEXT: fmov w[[RES:[0-9]+]], s0
|
||||
; NONEON-NEXT: bfi x[[RES]], x[[ELT2]], #32, #32
|
||||
; NONEON-NEXT: str x[[RES]], [x0]
|
||||
; NONEON-NEXT: ret
|
||||
define void @store_illegal_factor2(<3 x float>* %p, <3 x float> %v) nounwind {
|
||||
%tmp1 = shufflevector <3 x float> %v, <3 x float> undef, <3 x i32> <i32 0, i32 2, i32 undef>
|
||||
store <3 x float> %tmp1, <3 x float>* %p, align 16
|
||||
ret void
|
||||
}
|
||||
|
||||
; NEON-LABEL: load_factor2_with_extract_user:
|
||||
; NEON: ld2 { v0.4s, v1.4s }, [x0]
|
||||
; NEON: mov w0, v0.s[1]
|
||||
; NONEON-LABEL: load_factor2_with_extract_user:
|
||||
; NONEON-NOT: ld2
|
||||
define i32 @load_factor2_with_extract_user(<8 x i32>* %a) {
|
||||
%1 = load <8 x i32>, <8 x i32>* %a, align 8
|
||||
%2 = shufflevector <8 x i32> %1, <8 x i32> undef, <4 x i32> <i32 0, i32 2, i32 4, i32 6>
|
||||
%3 = extractelement <8 x i32> %1, i32 2
|
||||
ret i32 %3
|
||||
}
|
||||
|
||||
; NEON-LABEL: store_general_mask_factor4:
|
||||
; NEON: st4 { v{{[0-9]+}}.{{[0-9]+}}s, v{{[0-9]+}}.{{[0-9]+}}s, v{{[0-9]+}}.{{[0-9]+}}s, v{{[0-9]+}}.{{[0-9]+}}s }, [x0]
|
||||
; NONEON-LABEL: store_general_mask_factor4:
|
||||
; NONEON-NOT: st4
|
||||
define void @store_general_mask_factor4(i32* %ptr, <32 x i32> %v0, <32 x i32> %v1) {
|
||||
%base = bitcast i32* %ptr to <8 x i32>*
|
||||
%i.vec = shufflevector <32 x i32> %v0, <32 x i32> %v1, <8 x i32> <i32 4, i32 16, i32 32, i32 8, i32 5, i32 17, i32 33, i32 9>
|
||||
store <8 x i32> %i.vec, <8 x i32>* %base, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; NEON-LABEL: store_general_mask_factor4_undefbeg:
|
||||
; NEON: st4 { v{{[0-9]+}}.{{[0-9]+}}s, v{{[0-9]+}}.{{[0-9]+}}s, v{{[0-9]+}}.{{[0-9]+}}s, v{{[0-9]+}}.{{[0-9]+}}s }, [x0]
|
||||
; NONEON-LABEL: store_general_mask_factor4_undefbeg:
|
||||
; NONEON-NOT: st4
|
||||
define void @store_general_mask_factor4_undefbeg(i32* %ptr, <32 x i32> %v0, <32 x i32> %v1) {
|
||||
%base = bitcast i32* %ptr to <8 x i32>*
|
||||
%i.vec = shufflevector <32 x i32> %v0, <32 x i32> %v1, <8 x i32> <i32 undef, i32 16, i32 32, i32 8, i32 5, i32 17, i32 33, i32 9>
|
||||
store <8 x i32> %i.vec, <8 x i32>* %base, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; NEON-LABEL: store_general_mask_factor4_undefend:
|
||||
; NEON: st4 { v{{[0-9]+}}.{{[0-9]+}}s, v{{[0-9]+}}.{{[0-9]+}}s, v{{[0-9]+}}.{{[0-9]+}}s, v{{[0-9]+}}.{{[0-9]+}}s }, [x0]
|
||||
; NONEON-LABEL: store_general_mask_factor4_undefend:
|
||||
; NONEON-NOT: st4
|
||||
define void @store_general_mask_factor4_undefend(i32* %ptr, <32 x i32> %v0, <32 x i32> %v1) {
|
||||
%base = bitcast i32* %ptr to <8 x i32>*
|
||||
%i.vec = shufflevector <32 x i32> %v0, <32 x i32> %v1, <8 x i32> <i32 4, i32 16, i32 32, i32 8, i32 5, i32 17, i32 33, i32 undef>
|
||||
store <8 x i32> %i.vec, <8 x i32>* %base, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; NEON-LABEL: store_general_mask_factor4_undefmid:
|
||||
; NEON: st4 { v{{[0-9]+}}.{{[0-9]+}}s, v{{[0-9]+}}.{{[0-9]+}}s, v{{[0-9]+}}.{{[0-9]+}}s, v{{[0-9]+}}.{{[0-9]+}}s }, [x0]
|
||||
; NONEON-LABEL: store_general_mask_factor4_undefmid:
|
||||
; NONEON-NOT: st4
|
||||
define void @store_general_mask_factor4_undefmid(i32* %ptr, <32 x i32> %v0, <32 x i32> %v1) {
|
||||
%base = bitcast i32* %ptr to <8 x i32>*
|
||||
%i.vec = shufflevector <32 x i32> %v0, <32 x i32> %v1, <8 x i32> <i32 4, i32 undef, i32 32, i32 8, i32 5, i32 17, i32 undef, i32 9>
|
||||
store <8 x i32> %i.vec, <8 x i32>* %base, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; NEON-LABEL: store_general_mask_factor4_undefmulti:
|
||||
; NEON: st4 { v{{[0-9]+}}.{{[0-9]+}}s, v{{[0-9]+}}.{{[0-9]+}}s, v{{[0-9]+}}.{{[0-9]+}}s, v{{[0-9]+}}.{{[0-9]+}}s }, [x0]
|
||||
; NONEON-LABEL: store_general_mask_factor4_undefmulti:
|
||||
; NONEON-NOT: st4
|
||||
define void @store_general_mask_factor4_undefmulti(i32* %ptr, <32 x i32> %v0, <32 x i32> %v1) {
|
||||
%base = bitcast i32* %ptr to <8 x i32>*
|
||||
%i.vec = shufflevector <32 x i32> %v0, <32 x i32> %v1, <8 x i32> <i32 4, i32 undef, i32 undef, i32 8, i32 undef, i32 undef, i32 undef, i32 9>
|
||||
store <8 x i32> %i.vec, <8 x i32>* %base, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; NEON-LABEL: store_general_mask_factor3:
|
||||
; NEON: st3 { v{{[0-9]+}}.{{[0-9]+}}s, v{{[0-9]+}}.{{[0-9]+}}s, v{{[0-9]+}}.{{[0-9]+}}s }, [x0]
|
||||
; NONEON-LABEL: store_general_mask_factor3:
|
||||
; NONEON-NOT: st3
|
||||
define void @store_general_mask_factor3(i32* %ptr, <32 x i32> %v0, <32 x i32> %v1) {
|
||||
%base = bitcast i32* %ptr to <12 x i32>*
|
||||
%i.vec = shufflevector <32 x i32> %v0, <32 x i32> %v1, <12 x i32> <i32 4, i32 32, i32 16, i32 5, i32 33, i32 17, i32 6, i32 34, i32 18, i32 7, i32 35, i32 19>
|
||||
store <12 x i32> %i.vec, <12 x i32>* %base, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; NEON-LABEL: store_general_mask_factor3_undefmultimid:
|
||||
; NEON: st3 { v{{[0-9]+}}.{{[0-9]+}}s, v{{[0-9]+}}.{{[0-9]+}}s, v{{[0-9]+}}.{{[0-9]+}}s }, [x0]
|
||||
; NONEON-LABEL: store_general_mask_factor3_undefmultimid:
|
||||
; NONEON-NOT: st3
|
||||
define void @store_general_mask_factor3_undefmultimid(i32* %ptr, <32 x i32> %v0, <32 x i32> %v1) {
|
||||
%base = bitcast i32* %ptr to <12 x i32>*
|
||||
%i.vec = shufflevector <32 x i32> %v0, <32 x i32> %v1, <12 x i32> <i32 4, i32 32, i32 16, i32 undef, i32 33, i32 17, i32 undef, i32 34, i32 18, i32 7, i32 35, i32 19>
|
||||
store <12 x i32> %i.vec, <12 x i32>* %base, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; NEON-LABEL: store_general_mask_factor3_undef_fail:
|
||||
; NEON-NOT: st3
|
||||
; NONEON-LABEL: store_general_mask_factor3_undef_fail:
|
||||
; NONEON-NOT: st3
|
||||
define void @store_general_mask_factor3_undef_fail(i32* %ptr, <32 x i32> %v0, <32 x i32> %v1) {
|
||||
%base = bitcast i32* %ptr to <12 x i32>*
|
||||
%i.vec = shufflevector <32 x i32> %v0, <32 x i32> %v1, <12 x i32> <i32 4, i32 32, i32 16, i32 undef, i32 33, i32 17, i32 undef, i32 34, i32 18, i32 8, i32 35, i32 19>
|
||||
store <12 x i32> %i.vec, <12 x i32>* %base, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; NEON-LABEL: store_general_mask_factor3_undeflane:
|
||||
; NEON: st3 { v{{[0-9]+}}.{{[0-9]+}}s, v{{[0-9]+}}.{{[0-9]+}}s, v{{[0-9]+}}.{{[0-9]+}}s }, [x0]
|
||||
; NONEON-LABEL: store_general_mask_factor3_undeflane:
|
||||
; NONEON-NOT: st3
|
||||
define void @store_general_mask_factor3_undeflane(i32* %ptr, <32 x i32> %v0, <32 x i32> %v1) {
|
||||
%base = bitcast i32* %ptr to <12 x i32>*
|
||||
%i.vec = shufflevector <32 x i32> %v0, <32 x i32> %v1, <12 x i32> <i32 undef, i32 32, i32 16, i32 undef, i32 33, i32 17, i32 undef, i32 34, i32 18, i32 undef, i32 35, i32 19>
|
||||
store <12 x i32> %i.vec, <12 x i32>* %base, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; NEON-LABEL: store_general_mask_factor3_negativestart:
|
||||
; NEON-NOT: st3
|
||||
; NONEON-LABEL: store_general_mask_factor3_negativestart:
|
||||
; NONEON-NOT: st3
|
||||
define void @store_general_mask_factor3_negativestart(i32* %ptr, <32 x i32> %v0, <32 x i32> %v1) {
|
||||
%base = bitcast i32* %ptr to <12 x i32>*
|
||||
%i.vec = shufflevector <32 x i32> %v0, <32 x i32> %v1, <12 x i32> <i32 undef, i32 32, i32 16, i32 undef, i32 33, i32 17, i32 undef, i32 34, i32 18, i32 2, i32 35, i32 19>
|
||||
store <12 x i32> %i.vec, <12 x i32>* %base, align 4
|
||||
ret void
|
||||
}
|
||||
|
|
@ -1,133 +0,0 @@
|
|||
# RUN: llc -run-pass=aarch64-ldst-opt %s -o - 2>&1 | FileCheck %s
|
||||
--- |
|
||||
target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
|
||||
target triple = "aarch64--linux-gnu"
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define i16 @promote-load-from-store(i32* %dst, i32 %x) #0 {
|
||||
store i32 %x, i32* %dst
|
||||
%dst16 = bitcast i32* %dst to i16*
|
||||
%dst1 = getelementptr inbounds i16, i16* %dst16, i32 1
|
||||
%x16 = load i16, i16* %dst1
|
||||
ret i16 %x16
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define void @store-pair(i32* %dst, i32 %x, i32 %y) #0 {
|
||||
%dst01 = bitcast i32* %dst to i32*
|
||||
%dst1 = getelementptr inbounds i32, i32* %dst, i32 1
|
||||
store i32 %x, i32* %dst01
|
||||
store i32 %x, i32* %dst1
|
||||
ret void
|
||||
}
|
||||
|
||||
attributes #0 = { nounwind }
|
||||
|
||||
...
|
||||
---
|
||||
name: promote-load-from-store
|
||||
alignment: 2
|
||||
exposesReturnsTwice: false
|
||||
tracksRegLiveness: true
|
||||
liveins:
|
||||
- { reg: '%x0' }
|
||||
- { reg: '%w1' }
|
||||
frameInfo:
|
||||
isFrameAddressTaken: false
|
||||
isReturnAddressTaken: false
|
||||
hasStackMap: false
|
||||
hasPatchPoint: false
|
||||
stackSize: 0
|
||||
offsetAdjustment: 0
|
||||
maxAlignment: 0
|
||||
adjustsStack: false
|
||||
hasCalls: false
|
||||
maxCallFrameSize: 0
|
||||
hasOpaqueSPAdjustment: false
|
||||
hasVAStart: false
|
||||
hasMustTailInVarArgFunc: false
|
||||
body: |
|
||||
bb.0 (%ir-block.0):
|
||||
liveins: %w1, %x0, %lr
|
||||
|
||||
STRWui killed %w1, %x0, 0 :: (store 4 into %ir.dst)
|
||||
CFI_INSTRUCTION 0
|
||||
CFI_INSTRUCTION 0
|
||||
CFI_INSTRUCTION 0
|
||||
CFI_INSTRUCTION 0
|
||||
CFI_INSTRUCTION 0
|
||||
CFI_INSTRUCTION 0
|
||||
CFI_INSTRUCTION 0
|
||||
CFI_INSTRUCTION 0
|
||||
CFI_INSTRUCTION 0
|
||||
CFI_INSTRUCTION 0
|
||||
CFI_INSTRUCTION 0
|
||||
CFI_INSTRUCTION 0
|
||||
CFI_INSTRUCTION 0
|
||||
CFI_INSTRUCTION 0
|
||||
CFI_INSTRUCTION 0
|
||||
CFI_INSTRUCTION 0
|
||||
CFI_INSTRUCTION 0
|
||||
CFI_INSTRUCTION 0
|
||||
CFI_INSTRUCTION 0
|
||||
CFI_INSTRUCTION 0
|
||||
%w0 = LDRHHui killed %x0, 1 :: (load 2 from %ir.dst1)
|
||||
RET %lr, implicit %w0
|
||||
|
||||
...
|
||||
# CHECK-LABEL: name: promote-load-from-store
|
||||
# CHECK: STRWui %w1
|
||||
# CHECK: UBFMWri %w1
|
||||
---
|
||||
name: store-pair
|
||||
alignment: 2
|
||||
exposesReturnsTwice: false
|
||||
tracksRegLiveness: true
|
||||
liveins:
|
||||
- { reg: '%x0' }
|
||||
- { reg: '%w1' }
|
||||
frameInfo:
|
||||
isFrameAddressTaken: false
|
||||
isReturnAddressTaken: false
|
||||
hasStackMap: false
|
||||
hasPatchPoint: false
|
||||
stackSize: 0
|
||||
offsetAdjustment: 0
|
||||
maxAlignment: 0
|
||||
adjustsStack: false
|
||||
hasCalls: false
|
||||
maxCallFrameSize: 0
|
||||
hasOpaqueSPAdjustment: false
|
||||
hasVAStart: false
|
||||
hasMustTailInVarArgFunc: false
|
||||
body: |
|
||||
bb.0 (%ir-block.0):
|
||||
liveins: %w1, %x0, %lr
|
||||
|
||||
STRWui %w1, %x0, 0 :: (store 4 into %ir.dst01)
|
||||
CFI_INSTRUCTION 0
|
||||
CFI_INSTRUCTION 0
|
||||
CFI_INSTRUCTION 0
|
||||
CFI_INSTRUCTION 0
|
||||
CFI_INSTRUCTION 0
|
||||
CFI_INSTRUCTION 0
|
||||
CFI_INSTRUCTION 0
|
||||
CFI_INSTRUCTION 0
|
||||
CFI_INSTRUCTION 0
|
||||
CFI_INSTRUCTION 0
|
||||
CFI_INSTRUCTION 0
|
||||
CFI_INSTRUCTION 0
|
||||
CFI_INSTRUCTION 0
|
||||
CFI_INSTRUCTION 0
|
||||
CFI_INSTRUCTION 0
|
||||
CFI_INSTRUCTION 0
|
||||
CFI_INSTRUCTION 0
|
||||
CFI_INSTRUCTION 0
|
||||
CFI_INSTRUCTION 0
|
||||
CFI_INSTRUCTION 0
|
||||
STRWui killed %w1, killed %x0, 1 :: (store 4 into %ir.dst1)
|
||||
RET %lr
|
||||
|
||||
...
|
||||
# CHECK-LABEL: name: store-pair
|
||||
# CHECK: STPWi
|
|
@ -1,26 +0,0 @@
|
|||
; RUN: llc -mtriple=amdgcn--amdhsa -mcpu=kaveri -mattr=+flat-for-global < %s | FileCheck -check-prefix=HSA -check-prefix=HSA-DEFAULT -check-prefix=ALL %s
|
||||
; RUN: llc -mtriple=amdgcn--amdhsa -mcpu=kaveri -mattr=-flat-for-global < %s | FileCheck -check-prefix=HSA -check-prefix=HSA-NODEFAULT -check-prefix=ALL %s
|
||||
; RUN: llc -mtriple=amdgcn-- -mcpu=kaveri -mattr=-flat-for-global < %s | FileCheck -check-prefix=NOHSA-DEFAULT -check-prefix=ALL %s
|
||||
; RUN: llc -mtriple=amdgcn-- -mcpu=kaveri -mattr=+flat-for-global < %s | FileCheck -check-prefix=NOHSA-NODEFAULT -check-prefix=ALL %s
|
||||
|
||||
|
||||
; There are no stack objects even though flat is used by default, so
|
||||
; flat_scratch_init should be disabled.
|
||||
|
||||
; ALL-LABEL: {{^}}test:
|
||||
; HSA: .amd_kernel_code_t
|
||||
; HSA: enable_sgpr_flat_scratch_init = 0
|
||||
; HSA: .end_amd_kernel_code_t
|
||||
|
||||
; ALL-NOT: flat_scr
|
||||
|
||||
; HSA-DEFAULT: flat_store_dword
|
||||
; HSA-NODEFAULT: buffer_store_dword
|
||||
|
||||
; NOHSA-DEFAULT: buffer_store_dword
|
||||
; NOHSA-NODEFAULT: flat_store_dword
|
||||
define void @test(i32 addrspace(1)* %out) {
|
||||
entry:
|
||||
store i32 0, i32 addrspace(1)* %out
|
||||
ret void
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
; RUN: llc -march=amdgcn -mcpu=SI -verify-machineinstrs < %s | FileCheck -check-prefix=SI %s
|
||||
; RUN: llc -march=amdgcn -mcpu=tonga -verify-machineinstrs < %s | FileCheck -check-prefix=SI %s
|
||||
|
||||
declare float @llvm.convert.from.fp16.f32(i16) nounwind readnone
|
||||
declare double @llvm.convert.from.fp16.f64(i16) nounwind readnone
|
||||
|
||||
; SI-LABEL: {{^}}test_convert_fp16_to_fp32:
|
||||
; SI: buffer_load_ushort [[VAL:v[0-9]+]]
|
||||
; SI: v_cvt_f32_f16_e32 [[RESULT:v[0-9]+]], [[VAL]]
|
||||
; SI: buffer_store_dword [[RESULT]]
|
||||
define void @test_convert_fp16_to_fp32(float addrspace(1)* noalias %out, i16 addrspace(1)* noalias %in) nounwind {
|
||||
%val = load i16, i16 addrspace(1)* %in, align 2
|
||||
%cvt = call float @llvm.convert.from.fp16.f32(i16 %val) nounwind readnone
|
||||
store float %cvt, float addrspace(1)* %out, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
|
||||
; SI-LABEL: {{^}}test_convert_fp16_to_fp64:
|
||||
; SI: buffer_load_ushort [[VAL:v[0-9]+]]
|
||||
; SI: v_cvt_f32_f16_e32 [[RESULT32:v[0-9]+]], [[VAL]]
|
||||
; SI: v_cvt_f64_f32_e32 [[RESULT:v\[[0-9]+:[0-9]+\]]], [[RESULT32]]
|
||||
; SI: buffer_store_dwordx2 [[RESULT]]
|
||||
define void @test_convert_fp16_to_fp64(double addrspace(1)* noalias %out, i16 addrspace(1)* noalias %in) nounwind {
|
||||
%val = load i16, i16 addrspace(1)* %in, align 2
|
||||
%cvt = call double @llvm.convert.from.fp16.f64(i16 %val) nounwind readnone
|
||||
store double %cvt, double addrspace(1)* %out, align 4
|
||||
ret void
|
||||
}
|
|
@ -1,86 +0,0 @@
|
|||
; RUN: opt < %s -mtriple=arm-eabi -mattr=+neon -interleaved-access -S | FileCheck %s
|
||||
|
||||
; CHECK-LABEL: @extract_user_basic(
|
||||
; CHECK: %vldN = call { <4 x i32>, <4 x i32> } @llvm.arm.neon.vld2.v4i32.p0i8
|
||||
; CHECK: %[[R:.+]] = extractvalue { <4 x i32>, <4 x i32> } %vldN, 0
|
||||
; CHECK: extractelement <4 x i32> %[[R]], i64 1
|
||||
define void @extract_user_basic(<8 x i32>* %A, i1 %C) {
|
||||
entry:
|
||||
%L = load <8 x i32>, <8 x i32>* %A, align 8
|
||||
%S = shufflevector <8 x i32> %L, <8 x i32> undef, <4 x i32> <i32 0, i32 2, i32 4, i32 6>
|
||||
br i1 %C, label %if.then, label %if.merge
|
||||
|
||||
if.then:
|
||||
%E = extractelement <8 x i32> %L, i32 2
|
||||
br label %if.merge
|
||||
|
||||
if.merge:
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK-LABEL: @extract_user_multi(
|
||||
; CHECK: %vldN = call { <4 x i32>, <4 x i32> } @llvm.arm.neon.vld2.v4i32.p0i8
|
||||
; CHECK: %[[R:.+]] = extractvalue { <4 x i32>, <4 x i32> } %vldN, 0
|
||||
; CHECK: extractelement <4 x i32> %[[R]], i64 0
|
||||
; CHECK: extractelement <4 x i32> %[[R]], i64 1
|
||||
define void @extract_user_multi(<8 x i32>* %A, i1 %C) {
|
||||
entry:
|
||||
%L = load <8 x i32>, <8 x i32>* %A, align 8
|
||||
%S = shufflevector <8 x i32> %L, <8 x i32> undef, <4 x i32> <i32 0, i32 2, i32 4, i32 6>
|
||||
br i1 %C, label %if.then, label %if.merge
|
||||
|
||||
if.then:
|
||||
%E1 = extractelement <8 x i32> %L, i32 0
|
||||
br label %if.merge
|
||||
|
||||
if.merge:
|
||||
%E2 = extractelement <8 x i32> %L, i32 2
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK-LABEL: @extract_user_multi_no_dom(
|
||||
; CHECK-NOT: %vldN = call { <4 x i32>, <4 x i32> } @llvm.arm.neon.vld2.v4i32.p0i8
|
||||
define void @extract_user_multi_no_dom(<8 x i32>* %A, i1 %C) {
|
||||
entry:
|
||||
%L = load <8 x i32>, <8 x i32>* %A, align 8
|
||||
%E1 = extractelement <8 x i32> %L, i32 0
|
||||
br i1 %C, label %if.then, label %if.merge
|
||||
|
||||
if.then:
|
||||
%S = shufflevector <8 x i32> %L, <8 x i32> undef, <4 x i32> <i32 0, i32 2, i32 4, i32 6>
|
||||
%E2 = extractelement <8 x i32> %L, i32 2
|
||||
br label %if.merge
|
||||
|
||||
if.merge:
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK-LABEL: @extract_user_wrong_const_index(
|
||||
; CHECK-NOT: %vldN = call { <4 x i32>, <4 x i32> } @llvm.arm.neon.vld2.v4i32.p0i8
|
||||
define void @extract_user_wrong_const_index(<8 x i32>* %A) {
|
||||
entry:
|
||||
%L = load <8 x i32>, <8 x i32>* %A, align 8
|
||||
%S = shufflevector <8 x i32> %L, <8 x i32> undef, <4 x i32> <i32 0, i32 2, i32 4, i32 6>
|
||||
%E = extractelement <8 x i32> %L, i32 1
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK-LABEL: @extract_user_undef_index(
|
||||
; CHECK-NOT: %vldN = call { <4 x i32>, <4 x i32> } @llvm.arm.neon.vld2.v4i32.p0i8
|
||||
define void @extract_user_undef_index(<8 x i32>* %A) {
|
||||
entry:
|
||||
%L = load <8 x i32>, <8 x i32>* %A, align 8
|
||||
%S = shufflevector <8 x i32> %L, <8 x i32> undef, <4 x i32> <i32 0, i32 2, i32 4, i32 6>
|
||||
%E = extractelement <8 x i32> %L, i32 undef
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK-LABEL: @extract_user_var_index(
|
||||
; CHECK-NOT: %vldN = call { <4 x i32>, <4 x i32> } @llvm.arm.neon.vld2.v4i32.p0i8
|
||||
define void @extract_user_var_index(<8 x i32>* %A, i32 %I) {
|
||||
entry:
|
||||
%L = load <8 x i32>, <8 x i32>* %A, align 8
|
||||
%S = shufflevector <8 x i32> %L, <8 x i32> undef, <4 x i32> <i32 0, i32 2, i32 4, i32 6>
|
||||
%E = extractelement <8 x i32> %L, i32 %I
|
||||
ret void
|
||||
}
|
|
@ -1,462 +0,0 @@
|
|||
; RUN: llc -mtriple=arm-eabi -mattr=+neon -lower-interleaved-accesses=true < %s | FileCheck %s -check-prefix=NEON
|
||||
; RUN: llc -mtriple=arm-eabi -mattr=-neon -lower-interleaved-accesses=true < %s | FileCheck %s -check-prefix=NONEON
|
||||
|
||||
; NEON-LABEL: load_factor2:
|
||||
; NEON: vld2.8 {d16, d17}, [r0]
|
||||
; NONEON-LABEL: load_factor2:
|
||||
; NONEON-NOT: vld2
|
||||
define <8 x i8> @load_factor2(<16 x i8>* %ptr) {
|
||||
%wide.vec = load <16 x i8>, <16 x i8>* %ptr, align 4
|
||||
%strided.v0 = shufflevector <16 x i8> %wide.vec, <16 x i8> undef, <8 x i32> <i32 0, i32 2, i32 4, i32 6, i32 8, i32 10, i32 12, i32 14>
|
||||
%strided.v1 = shufflevector <16 x i8> %wide.vec, <16 x i8> undef, <8 x i32> <i32 1, i32 3, i32 5, i32 7, i32 9, i32 11, i32 13, i32 15>
|
||||
%add = add nsw <8 x i8> %strided.v0, %strided.v1
|
||||
ret <8 x i8> %add
|
||||
}
|
||||
|
||||
; NEON-LABEL: load_factor3:
|
||||
; NEON: vld3.32 {d16, d17, d18}, [r0]
|
||||
; NONEON-LABEL: load_factor3:
|
||||
; NONEON-NOT: vld3
|
||||
define <2 x i32> @load_factor3(i32* %ptr) {
|
||||
%base = bitcast i32* %ptr to <6 x i32>*
|
||||
%wide.vec = load <6 x i32>, <6 x i32>* %base, align 4
|
||||
%strided.v2 = shufflevector <6 x i32> %wide.vec, <6 x i32> undef, <2 x i32> <i32 2, i32 5>
|
||||
%strided.v1 = shufflevector <6 x i32> %wide.vec, <6 x i32> undef, <2 x i32> <i32 1, i32 4>
|
||||
%add = add nsw <2 x i32> %strided.v2, %strided.v1
|
||||
ret <2 x i32> %add
|
||||
}
|
||||
|
||||
; NEON-LABEL: load_factor4:
|
||||
; NEON: vld4.32 {d16, d18, d20, d22}, [r0]!
|
||||
; NEON: vld4.32 {d17, d19, d21, d23}, [r0]
|
||||
; NONEON-LABEL: load_factor4:
|
||||
; NONEON-NOT: vld4
|
||||
define <4 x i32> @load_factor4(i32* %ptr) {
|
||||
%base = bitcast i32* %ptr to <16 x i32>*
|
||||
%wide.vec = load <16 x i32>, <16 x i32>* %base, align 4
|
||||
%strided.v0 = shufflevector <16 x i32> %wide.vec, <16 x i32> undef, <4 x i32> <i32 0, i32 4, i32 8, i32 12>
|
||||
%strided.v2 = shufflevector <16 x i32> %wide.vec, <16 x i32> undef, <4 x i32> <i32 2, i32 6, i32 10, i32 14>
|
||||
%add = add nsw <4 x i32> %strided.v0, %strided.v2
|
||||
ret <4 x i32> %add
|
||||
}
|
||||
|
||||
; NEON-LABEL: store_factor2:
|
||||
; NEON: vst2.8 {d16, d17}, [r0]
|
||||
; NONEON-LABEL: store_factor2:
|
||||
; NONEON-NOT: vst2
|
||||
define void @store_factor2(<16 x i8>* %ptr, <8 x i8> %v0, <8 x i8> %v1) {
|
||||
%interleaved.vec = shufflevector <8 x i8> %v0, <8 x i8> %v1, <16 x i32> <i32 0, i32 8, i32 1, i32 9, i32 2, i32 10, i32 3, i32 11, i32 4, i32 12, i32 5, i32 13, i32 6, i32 14, i32 7, i32 15>
|
||||
store <16 x i8> %interleaved.vec, <16 x i8>* %ptr, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; NEON-LABEL: store_factor3:
|
||||
; NEON: vst3.32 {d16, d18, d20}, [r0]!
|
||||
; NEON: vst3.32 {d17, d19, d21}, [r0]
|
||||
; NONEON-LABEL: store_factor3:
|
||||
; NONEON-NOT: vst3.32
|
||||
define void @store_factor3(i32* %ptr, <4 x i32> %v0, <4 x i32> %v1, <4 x i32> %v2) {
|
||||
%base = bitcast i32* %ptr to <12 x i32>*
|
||||
%v0_v1 = shufflevector <4 x i32> %v0, <4 x i32> %v1, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
|
||||
%v2_u = shufflevector <4 x i32> %v2, <4 x i32> undef, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 undef, i32 undef, i32 undef, i32 undef>
|
||||
%interleaved.vec = shufflevector <8 x i32> %v0_v1, <8 x i32> %v2_u, <12 x i32> <i32 0, i32 4, i32 8, i32 1, i32 5, i32 9, i32 2, i32 6, i32 10, i32 3, i32 7, i32 11>
|
||||
store <12 x i32> %interleaved.vec, <12 x i32>* %base, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; NEON-LABEL: store_factor4:
|
||||
; NEON: vst4.32 {d16, d18, d20, d22}, [r0]!
|
||||
; NEON: vst4.32 {d17, d19, d21, d23}, [r0]
|
||||
; NONEON-LABEL: store_factor4:
|
||||
; NONEON-NOT: vst4
|
||||
define void @store_factor4(i32* %ptr, <4 x i32> %v0, <4 x i32> %v1, <4 x i32> %v2, <4 x i32> %v3) {
|
||||
%base = bitcast i32* %ptr to <16 x i32>*
|
||||
%v0_v1 = shufflevector <4 x i32> %v0, <4 x i32> %v1, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
|
||||
%v2_v3 = shufflevector <4 x i32> %v2, <4 x i32> %v3, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
|
||||
%interleaved.vec = shufflevector <8 x i32> %v0_v1, <8 x i32> %v2_v3, <16 x i32> <i32 0, i32 4, i32 8, i32 12, i32 1, i32 5, i32 9, i32 13, i32 2, i32 6, i32 10, i32 14, i32 3, i32 7, i32 11, i32 15>
|
||||
store <16 x i32> %interleaved.vec, <16 x i32>* %base, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; The following cases test that interleaved access of pointer vectors can be
|
||||
; matched to ldN/stN instruction.
|
||||
|
||||
; NEON-LABEL: load_ptrvec_factor2:
|
||||
; NEON: vld2.32 {d16, d17}, [r0]
|
||||
; NONEON-LABEL: load_ptrvec_factor2:
|
||||
; NONEON-NOT: vld2
|
||||
define <2 x i32*> @load_ptrvec_factor2(i32** %ptr) {
|
||||
%base = bitcast i32** %ptr to <4 x i32*>*
|
||||
%wide.vec = load <4 x i32*>, <4 x i32*>* %base, align 4
|
||||
%strided.v0 = shufflevector <4 x i32*> %wide.vec, <4 x i32*> undef, <2 x i32> <i32 0, i32 2>
|
||||
ret <2 x i32*> %strided.v0
|
||||
}
|
||||
|
||||
; NEON-LABEL: load_ptrvec_factor3:
|
||||
; NEON: vld3.32 {d16, d17, d18}, [r0]
|
||||
; NONEON-LABEL: load_ptrvec_factor3:
|
||||
; NONEON-NOT: vld3
|
||||
define void @load_ptrvec_factor3(i32** %ptr, <2 x i32*>* %ptr1, <2 x i32*>* %ptr2) {
|
||||
%base = bitcast i32** %ptr to <6 x i32*>*
|
||||
%wide.vec = load <6 x i32*>, <6 x i32*>* %base, align 4
|
||||
%strided.v2 = shufflevector <6 x i32*> %wide.vec, <6 x i32*> undef, <2 x i32> <i32 2, i32 5>
|
||||
store <2 x i32*> %strided.v2, <2 x i32*>* %ptr1
|
||||
%strided.v1 = shufflevector <6 x i32*> %wide.vec, <6 x i32*> undef, <2 x i32> <i32 1, i32 4>
|
||||
store <2 x i32*> %strided.v1, <2 x i32*>* %ptr2
|
||||
ret void
|
||||
}
|
||||
|
||||
; NEON-LABEL: load_ptrvec_factor4:
|
||||
; NEON: vld4.32 {d16, d17, d18, d19}, [r0]
|
||||
; NONEON-LABEL: load_ptrvec_factor4:
|
||||
; NONEON-NOT: vld4
|
||||
define void @load_ptrvec_factor4(i32** %ptr, <2 x i32*>* %ptr1, <2 x i32*>* %ptr2) {
|
||||
%base = bitcast i32** %ptr to <8 x i32*>*
|
||||
%wide.vec = load <8 x i32*>, <8 x i32*>* %base, align 4
|
||||
%strided.v1 = shufflevector <8 x i32*> %wide.vec, <8 x i32*> undef, <2 x i32> <i32 1, i32 5>
|
||||
%strided.v3 = shufflevector <8 x i32*> %wide.vec, <8 x i32*> undef, <2 x i32> <i32 3, i32 7>
|
||||
store <2 x i32*> %strided.v1, <2 x i32*>* %ptr1
|
||||
store <2 x i32*> %strided.v3, <2 x i32*>* %ptr2
|
||||
ret void
|
||||
}
|
||||
|
||||
; NEON-LABEL: store_ptrvec_factor2:
|
||||
; NEON: vst2.32 {d16, d17}, [r0]
|
||||
; NONEON-LABEL: store_ptrvec_factor2:
|
||||
; NONEON-NOT: vst2
|
||||
define void @store_ptrvec_factor2(i32** %ptr, <2 x i32*> %v0, <2 x i32*> %v1) {
|
||||
%base = bitcast i32** %ptr to <4 x i32*>*
|
||||
%interleaved.vec = shufflevector <2 x i32*> %v0, <2 x i32*> %v1, <4 x i32> <i32 0, i32 2, i32 1, i32 3>
|
||||
store <4 x i32*> %interleaved.vec, <4 x i32*>* %base, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; NEON-LABEL: store_ptrvec_factor3:
|
||||
; NEON: vst3.32 {d16, d17, d18}, [r0]
|
||||
; NONEON-LABEL: store_ptrvec_factor3:
|
||||
; NONEON-NOT: vst3
|
||||
define void @store_ptrvec_factor3(i32** %ptr, <2 x i32*> %v0, <2 x i32*> %v1, <2 x i32*> %v2) {
|
||||
%base = bitcast i32** %ptr to <6 x i32*>*
|
||||
%v0_v1 = shufflevector <2 x i32*> %v0, <2 x i32*> %v1, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
|
||||
%v2_u = shufflevector <2 x i32*> %v2, <2 x i32*> undef, <4 x i32> <i32 0, i32 1, i32 undef, i32 undef>
|
||||
%interleaved.vec = shufflevector <4 x i32*> %v0_v1, <4 x i32*> %v2_u, <6 x i32> <i32 0, i32 2, i32 4, i32 1, i32 3, i32 5>
|
||||
store <6 x i32*> %interleaved.vec, <6 x i32*>* %base, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; NEON-LABEL: store_ptrvec_factor4:
|
||||
; NEON: vst4.32 {d16, d17, d18, d19}, [r0]
|
||||
; NONEON-LABEL: store_ptrvec_factor4:
|
||||
; NONEON-NOT: vst4
|
||||
define void @store_ptrvec_factor4(i32* %ptr, <2 x i32*> %v0, <2 x i32*> %v1, <2 x i32*> %v2, <2 x i32*> %v3) {
|
||||
%base = bitcast i32* %ptr to <8 x i32*>*
|
||||
%v0_v1 = shufflevector <2 x i32*> %v0, <2 x i32*> %v1, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
|
||||
%v2_v3 = shufflevector <2 x i32*> %v2, <2 x i32*> %v3, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
|
||||
%interleaved.vec = shufflevector <4 x i32*> %v0_v1, <4 x i32*> %v2_v3, <8 x i32> <i32 0, i32 2, i32 4, i32 6, i32 1, i32 3, i32 5, i32 7>
|
||||
store <8 x i32*> %interleaved.vec, <8 x i32*>* %base, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; Following cases check that shuffle maskes with undef indices can be matched
|
||||
; into ldN/stN instruction.
|
||||
|
||||
; NEON-LABEL: load_undef_mask_factor2:
|
||||
; NEON: vld2.32 {d16, d17, d18, d19}, [r0]
|
||||
; NONEON-LABEL: load_undef_mask_factor2:
|
||||
; NONEON-NOT: vld2
|
||||
define <4 x i32> @load_undef_mask_factor2(i32* %ptr) {
|
||||
%base = bitcast i32* %ptr to <8 x i32>*
|
||||
%wide.vec = load <8 x i32>, <8 x i32>* %base, align 4
|
||||
%strided.v0 = shufflevector <8 x i32> %wide.vec, <8 x i32> undef, <4 x i32> <i32 undef, i32 2, i32 undef, i32 6>
|
||||
%strided.v1 = shufflevector <8 x i32> %wide.vec, <8 x i32> undef, <4 x i32> <i32 undef, i32 3, i32 undef, i32 7>
|
||||
%add = add nsw <4 x i32> %strided.v0, %strided.v1
|
||||
ret <4 x i32> %add
|
||||
}
|
||||
|
||||
; NEON-LABEL: load_undef_mask_factor3:
|
||||
; NEON: vld3.32 {d16, d18, d20}, [r0]!
|
||||
; NEON: vld3.32 {d17, d19, d21}, [r0]
|
||||
; NONEON-LABEL: load_undef_mask_factor3:
|
||||
; NONEON-NOT: vld3
|
||||
define <4 x i32> @load_undef_mask_factor3(i32* %ptr) {
|
||||
%base = bitcast i32* %ptr to <12 x i32>*
|
||||
%wide.vec = load <12 x i32>, <12 x i32>* %base, align 4
|
||||
%strided.v2 = shufflevector <12 x i32> %wide.vec, <12 x i32> undef, <4 x i32> <i32 2, i32 undef, i32 undef, i32 undef>
|
||||
%strided.v1 = shufflevector <12 x i32> %wide.vec, <12 x i32> undef, <4 x i32> <i32 1, i32 4, i32 7, i32 10>
|
||||
%add = add nsw <4 x i32> %strided.v2, %strided.v1
|
||||
ret <4 x i32> %add
|
||||
}
|
||||
|
||||
; NEON-LABEL: load_undef_mask_factor4:
|
||||
; NEON: vld4.32 {d16, d18, d20, d22}, [r0]!
|
||||
; NEON: vld4.32 {d17, d19, d21, d23}, [r0]
|
||||
; NONEON-LABEL: load_undef_mask_factor4:
|
||||
; NONEON-NOT: vld4
|
||||
define <4 x i32> @load_undef_mask_factor4(i32* %ptr) {
|
||||
%base = bitcast i32* %ptr to <16 x i32>*
|
||||
%wide.vec = load <16 x i32>, <16 x i32>* %base, align 4
|
||||
%strided.v0 = shufflevector <16 x i32> %wide.vec, <16 x i32> undef, <4 x i32> <i32 0, i32 4, i32 undef, i32 undef>
|
||||
%strided.v2 = shufflevector <16 x i32> %wide.vec, <16 x i32> undef, <4 x i32> <i32 2, i32 6, i32 undef, i32 undef>
|
||||
%add = add nsw <4 x i32> %strided.v0, %strided.v2
|
||||
ret <4 x i32> %add
|
||||
}
|
||||
|
||||
; NEON-LABEL: store_undef_mask_factor2:
|
||||
; NEON: vst2.32 {d16, d17, d18, d19}, [r0]
|
||||
; NONEON-LABEL: store_undef_mask_factor2:
|
||||
; NONEON-NOT: vst2
|
||||
define void @store_undef_mask_factor2(i32* %ptr, <4 x i32> %v0, <4 x i32> %v1) {
|
||||
%base = bitcast i32* %ptr to <8 x i32>*
|
||||
%interleaved.vec = shufflevector <4 x i32> %v0, <4 x i32> %v1, <8 x i32> <i32 undef, i32 undef, i32 undef, i32 undef, i32 2, i32 6, i32 3, i32 7>
|
||||
store <8 x i32> %interleaved.vec, <8 x i32>* %base, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; NEON-LABEL: store_undef_mask_factor3:
|
||||
; NEON: vst3.32 {d16, d18, d20}, [r0]!
|
||||
; NEON: vst3.32 {d17, d19, d21}, [r0]
|
||||
; NONEON-LABEL: store_undef_mask_factor3:
|
||||
; NONEON-NOT: vst3
|
||||
define void @store_undef_mask_factor3(i32* %ptr, <4 x i32> %v0, <4 x i32> %v1, <4 x i32> %v2) {
|
||||
%base = bitcast i32* %ptr to <12 x i32>*
|
||||
%v0_v1 = shufflevector <4 x i32> %v0, <4 x i32> %v1, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
|
||||
%v2_u = shufflevector <4 x i32> %v2, <4 x i32> undef, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 undef, i32 undef, i32 undef, i32 undef>
|
||||
%interleaved.vec = shufflevector <8 x i32> %v0_v1, <8 x i32> %v2_u, <12 x i32> <i32 0, i32 4, i32 undef, i32 1, i32 undef, i32 9, i32 2, i32 6, i32 10, i32 3, i32 7, i32 11>
|
||||
store <12 x i32> %interleaved.vec, <12 x i32>* %base, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; NEON-LABEL: store_undef_mask_factor4:
|
||||
; NEON: vst4.32 {d16, d18, d20, d22}, [r0]!
|
||||
; NEON: vst4.32 {d17, d19, d21, d23}, [r0]
|
||||
; NONEON-LABEL: store_undef_mask_factor4:
|
||||
; NONEON-NOT: vst4
|
||||
define void @store_undef_mask_factor4(i32* %ptr, <4 x i32> %v0, <4 x i32> %v1, <4 x i32> %v2, <4 x i32> %v3) {
|
||||
%base = bitcast i32* %ptr to <16 x i32>*
|
||||
%v0_v1 = shufflevector <4 x i32> %v0, <4 x i32> %v1, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
|
||||
%v2_v3 = shufflevector <4 x i32> %v2, <4 x i32> %v3, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
|
||||
%interleaved.vec = shufflevector <8 x i32> %v0_v1, <8 x i32> %v2_v3, <16 x i32> <i32 0, i32 4, i32 8, i32 undef, i32 undef, i32 5, i32 9, i32 13, i32 2, i32 6, i32 10, i32 14, i32 3, i32 7, i32 11, i32 15>
|
||||
store <16 x i32> %interleaved.vec, <16 x i32>* %base, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; The following test cases check that address spaces are properly handled
|
||||
|
||||
; NEON-LABEL: load_address_space
|
||||
; NEON: vld3.32
|
||||
; NONEON-LABEL: load_address_space
|
||||
; NONEON-NOT: vld3
|
||||
define void @load_address_space(<4 x i32> addrspace(1)* %A, <2 x i32>* %B) {
|
||||
%tmp = load <4 x i32>, <4 x i32> addrspace(1)* %A
|
||||
%interleaved = shufflevector <4 x i32> %tmp, <4 x i32> undef, <2 x i32> <i32 0, i32 3>
|
||||
store <2 x i32> %interleaved, <2 x i32>* %B
|
||||
ret void
|
||||
}
|
||||
|
||||
; NEON-LABEL: store_address_space
|
||||
; NEON: vst2.32
|
||||
; NONEON-LABEL: store_address_space
|
||||
; NONEON-NOT: vst2
|
||||
define void @store_address_space(<2 x i32>* %A, <2 x i32>* %B, <4 x i32> addrspace(1)* %C) {
|
||||
%tmp0 = load <2 x i32>, <2 x i32>* %A
|
||||
%tmp1 = load <2 x i32>, <2 x i32>* %B
|
||||
%interleaved = shufflevector <2 x i32> %tmp0, <2 x i32> %tmp1, <4 x i32> <i32 0, i32 2, i32 1, i32 3>
|
||||
store <4 x i32> %interleaved, <4 x i32> addrspace(1)* %C
|
||||
ret void
|
||||
}
|
||||
|
||||
; Check that we do something sane with illegal types.
|
||||
|
||||
; NEON-LABEL: load_illegal_factor2:
|
||||
; NEON: BB#0:
|
||||
; NEON-NEXT: vld1.64 {d16, d17}, [r0:128]
|
||||
; NEON-NEXT: vuzp.32 q8, {{.*}}
|
||||
; NEON-NEXT: vmov r0, r1, d16
|
||||
; NEON-NEXT: vmov r2, r3, {{.*}}
|
||||
; NEON-NEXT: mov pc, lr
|
||||
; NONEON-LABEL: load_illegal_factor2:
|
||||
; NONEON: BB#0:
|
||||
; NONEON-NEXT: ldr [[ELT0:r[0-9]+]], [r0]
|
||||
; NONEON-NEXT: ldr r1, [r0, #8]
|
||||
; NONEON-NEXT: mov r0, [[ELT0]]
|
||||
; NONEON-NEXT: mov pc, lr
|
||||
define <3 x float> @load_illegal_factor2(<3 x float>* %p) nounwind {
|
||||
%tmp1 = load <3 x float>, <3 x float>* %p, align 16
|
||||
%tmp2 = shufflevector <3 x float> %tmp1, <3 x float> undef, <3 x i32> <i32 0, i32 2, i32 undef>
|
||||
ret <3 x float> %tmp2
|
||||
}
|
||||
|
||||
; This lowering isn't great, but it's at least correct.
|
||||
|
||||
; NEON-LABEL: store_illegal_factor2:
|
||||
; NEON: BB#0:
|
||||
; NEON-NEXT: vldr d17, [sp]
|
||||
; NEON-NEXT: vmov d16, r2, r3
|
||||
; NEON-NEXT: vuzp.32 q8, {{.*}}
|
||||
; NEON-NEXT: vstr d16, [r0]
|
||||
; NEON-NEXT: mov pc, lr
|
||||
; NONEON-LABEL: store_illegal_factor2:
|
||||
; NONEON: BB#0:
|
||||
; NONEON-NEXT: stm r0, {r1, r3}
|
||||
; NONEON-NEXT: mov pc, lr
|
||||
define void @store_illegal_factor2(<3 x float>* %p, <3 x float> %v) nounwind {
|
||||
%tmp1 = shufflevector <3 x float> %v, <3 x float> undef, <3 x i32> <i32 0, i32 2, i32 undef>
|
||||
store <3 x float> %tmp1, <3 x float>* %p, align 16
|
||||
ret void
|
||||
}
|
||||
|
||||
; NEON-LABEL: load_factor2_with_extract_user:
|
||||
; NEON: vld2.32 {d16, d17, d18, d19}, [r0:64]
|
||||
; NEON: vmov.32 r0, d16[1]
|
||||
; NONEON-LABEL: load_factor2_with_extract_user:
|
||||
; NONEON-NOT: vld2
|
||||
define i32 @load_factor2_with_extract_user(<8 x i32>* %a) {
|
||||
%1 = load <8 x i32>, <8 x i32>* %a, align 8
|
||||
%2 = shufflevector <8 x i32> %1, <8 x i32> undef, <4 x i32> <i32 0, i32 2, i32 4, i32 6>
|
||||
%3 = extractelement <8 x i32> %1, i32 2
|
||||
ret i32 %3
|
||||
}
|
||||
|
||||
; NEON-LABEL: store_general_mask_factor4:
|
||||
; NEON: vst4.32 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r0]
|
||||
; NONEON-LABEL: store_general_mask_factor4:
|
||||
; NONEON-NOT: vst4.32
|
||||
define void @store_general_mask_factor4(i32* %ptr, <32 x i32> %v0, <32 x i32> %v1) {
|
||||
%base = bitcast i32* %ptr to <8 x i32>*
|
||||
%i.vec = shufflevector <32 x i32> %v0, <32 x i32> %v1, <8 x i32> <i32 4, i32 16, i32 32, i32 8, i32 5, i32 17, i32 33, i32 9>
|
||||
store <8 x i32> %i.vec, <8 x i32>* %base, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; NEON-LABEL: store_general_mask_factor4_undefbeg:
|
||||
; NEON: vst4.32 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r0]
|
||||
; NONEON-LABEL: store_general_mask_factor4_undefbeg:
|
||||
; NONEON-NOT: vst4.32
|
||||
define void @store_general_mask_factor4_undefbeg(i32* %ptr, <32 x i32> %v0, <32 x i32> %v1) {
|
||||
%base = bitcast i32* %ptr to <8 x i32>*
|
||||
%i.vec = shufflevector <32 x i32> %v0, <32 x i32> %v1, <8 x i32> <i32 undef, i32 16, i32 32, i32 8, i32 5, i32 17, i32 33, i32 9>
|
||||
store <8 x i32> %i.vec, <8 x i32>* %base, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; NEON-LABEL: store_general_mask_factor4_undefend:
|
||||
; NEON: vst4.32 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r0]
|
||||
; NONEON-LABEL: store_general_mask_factor4_undefend:
|
||||
; NONEON-NOT: vst4.32
|
||||
define void @store_general_mask_factor4_undefend(i32* %ptr, <32 x i32> %v0, <32 x i32> %v1) {
|
||||
%base = bitcast i32* %ptr to <8 x i32>*
|
||||
%i.vec = shufflevector <32 x i32> %v0, <32 x i32> %v1, <8 x i32> <i32 4, i32 16, i32 32, i32 8, i32 5, i32 17, i32 33, i32 undef>
|
||||
store <8 x i32> %i.vec, <8 x i32>* %base, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; NEON-LABEL: store_general_mask_factor4_undefmid:
|
||||
; NEON: vst4.32 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r0]
|
||||
; NONEON-LABEL: store_general_mask_factor4_undefmid:
|
||||
; NONEON-NOT: vst4.32
|
||||
define void @store_general_mask_factor4_undefmid(i32* %ptr, <32 x i32> %v0, <32 x i32> %v1) {
|
||||
%base = bitcast i32* %ptr to <8 x i32>*
|
||||
%i.vec = shufflevector <32 x i32> %v0, <32 x i32> %v1, <8 x i32> <i32 4, i32 undef, i32 32, i32 8, i32 5, i32 17, i32 undef, i32 9>
|
||||
store <8 x i32> %i.vec, <8 x i32>* %base, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; NEON-LABEL: store_general_mask_factor4_undefmulti:
|
||||
; NEON: vst4.32 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r0]
|
||||
; NONEON-LABEL: store_general_mask_factor4_undefmulti:
|
||||
; NONEON-NOT: vst4.32
|
||||
define void @store_general_mask_factor4_undefmulti(i32* %ptr, <32 x i32> %v0, <32 x i32> %v1) {
|
||||
%base = bitcast i32* %ptr to <8 x i32>*
|
||||
%i.vec = shufflevector <32 x i32> %v0, <32 x i32> %v1, <8 x i32> <i32 4, i32 undef, i32 undef, i32 8, i32 undef, i32 undef, i32 undef, i32 9>
|
||||
store <8 x i32> %i.vec, <8 x i32>* %base, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; NEON-LABEL: store_general_mask_factor3:
|
||||
; NEON: vst3.32 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r0]
|
||||
; NONEON-LABEL: store_general_mask_factor3:
|
||||
; NONEON-NOT: vst3.32
|
||||
define void @store_general_mask_factor3(i32* %ptr, <32 x i32> %v0, <32 x i32> %v1) {
|
||||
%base = bitcast i32* %ptr to <12 x i32>*
|
||||
%i.vec = shufflevector <32 x i32> %v0, <32 x i32> %v1, <12 x i32> <i32 4, i32 32, i32 16, i32 5, i32 33, i32 17, i32 6, i32 34, i32 18, i32 7, i32 35, i32 19>
|
||||
store <12 x i32> %i.vec, <12 x i32>* %base, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; NEON-LABEL: store_general_mask_factor3_undefmultimid:
|
||||
; NEON: vst3.32 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r0]
|
||||
; NONEON-LABEL: store_general_mask_factor3_undefmultimid:
|
||||
; NONEON-NOT: vst3.32
|
||||
define void @store_general_mask_factor3_undefmultimid(i32* %ptr, <32 x i32> %v0, <32 x i32> %v1) {
|
||||
%base = bitcast i32* %ptr to <12 x i32>*
|
||||
%i.vec = shufflevector <32 x i32> %v0, <32 x i32> %v1, <12 x i32> <i32 4, i32 32, i32 16, i32 undef, i32 33, i32 17, i32 undef, i32 34, i32 18, i32 7, i32 35, i32 19>
|
||||
store <12 x i32> %i.vec, <12 x i32>* %base, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; NEON-LABEL: store_general_mask_factor3_undef_fail:
|
||||
; NEON-NOT: vst3.32
|
||||
; NONEON-LABEL: store_general_mask_factor3_undef_fail:
|
||||
; NONEON-NOT: vst3.32
|
||||
define void @store_general_mask_factor3_undef_fail(i32* %ptr, <32 x i32> %v0, <32 x i32> %v1) {
|
||||
%base = bitcast i32* %ptr to <12 x i32>*
|
||||
%i.vec = shufflevector <32 x i32> %v0, <32 x i32> %v1, <12 x i32> <i32 4, i32 32, i32 16, i32 undef, i32 33, i32 17, i32 undef, i32 34, i32 18, i32 8, i32 35, i32 19>
|
||||
store <12 x i32> %i.vec, <12 x i32>* %base, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; NEON-LABEL: store_general_mask_factor3_undeflane:
|
||||
; NEON: vst3.32 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r0]
|
||||
; NONEON-LABEL: store_general_mask_factor3_undeflane:
|
||||
; NONEON-NOT: vst3.32
|
||||
define void @store_general_mask_factor3_undeflane(i32* %ptr, <32 x i32> %v0, <32 x i32> %v1) {
|
||||
%base = bitcast i32* %ptr to <12 x i32>*
|
||||
%i.vec = shufflevector <32 x i32> %v0, <32 x i32> %v1, <12 x i32> <i32 undef, i32 32, i32 16, i32 undef, i32 33, i32 17, i32 undef, i32 34, i32 18, i32 undef, i32 35, i32 19>
|
||||
store <12 x i32> %i.vec, <12 x i32>* %base, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; NEON-LABEL: store_general_mask_factor3_endstart_fail:
|
||||
; NEON-NOT: vst3.32
|
||||
; NONEON-LABEL: store_general_mask_factor3_endstart_fail:
|
||||
; NONEON-NOT: vst3.32
|
||||
define void @store_general_mask_factor3_endstart_fail(i32* %ptr, <32 x i32> %v0, <32 x i32> %v1) {
|
||||
%base = bitcast i32* %ptr to <12 x i32>*
|
||||
%i.vec = shufflevector <32 x i32> %v0, <32 x i32> %v1, <12 x i32> <i32 undef, i32 32, i32 16, i32 undef, i32 33, i32 17, i32 undef, i32 34, i32 18, i32 2, i32 35, i32 19>
|
||||
store <12 x i32> %i.vec, <12 x i32>* %base, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; NEON-LABEL: store_general_mask_factor3_endstart_pass:
|
||||
; NEON: vst3.32 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r0]
|
||||
; NONEON-LABEL: store_general_mask_factor3_endstart_pass:
|
||||
; NONEON-NOT: vst3.32
|
||||
define void @store_general_mask_factor3_endstart_pass(i32* %ptr, <32 x i32> %v0, <32 x i32> %v1) {
|
||||
%base = bitcast i32* %ptr to <12 x i32>*
|
||||
%i.vec = shufflevector <32 x i32> %v0, <32 x i32> %v1, <12 x i32> <i32 undef, i32 32, i32 16, i32 undef, i32 33, i32 17, i32 undef, i32 34, i32 18, i32 7, i32 35, i32 19>
|
||||
store <12 x i32> %i.vec, <12 x i32>* %base, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; NEON-LABEL: store_general_mask_factor3_midstart_fail:
|
||||
; NEON-NOT: vst3.32
|
||||
; NONEON-LABEL: store_general_mask_factor3_midstart_fail:
|
||||
; NONEON-NOT: vst3.32
|
||||
define void @store_general_mask_factor3_midstart_fail(i32* %ptr, <32 x i32> %v0, <32 x i32> %v1) {
|
||||
%base = bitcast i32* %ptr to <12 x i32>*
|
||||
%i.vec = shufflevector <32 x i32> %v0, <32 x i32> %v1, <12 x i32> <i32 undef, i32 32, i32 16, i32 0, i32 33, i32 17, i32 undef, i32 34, i32 18, i32 undef, i32 35, i32 19>
|
||||
store <12 x i32> %i.vec, <12 x i32>* %base, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; NEON-LABEL: store_general_mask_factor3_midstart_pass:
|
||||
; NEON: vst3.32 {d{{[0-9]+}}, d{{[0-9]+}}, d{{[0-9]+}}}, [r0]
|
||||
; NONEON-LABEL: store_general_mask_factor3_midstart_pass:
|
||||
; NONEON-NOT: vst3.32
|
||||
define void @store_general_mask_factor3_midstart_pass(i32* %ptr, <32 x i32> %v0, <32 x i32> %v1) {
|
||||
%base = bitcast i32* %ptr to <12 x i32>*
|
||||
%i.vec = shufflevector <32 x i32> %v0, <32 x i32> %v1, <12 x i32> <i32 undef, i32 32, i32 16, i32 1, i32 33, i32 17, i32 undef, i32 34, i32 18, i32 undef, i32 35, i32 19>
|
||||
store <12 x i32> %i.vec, <12 x i32>* %base, align 4
|
||||
ret void
|
||||
}
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
; RUN: llc < %s -mcpu=atom -march=x86-64 | FileCheck %s
|
||||
|
||||
target triple = "x86_64-unknown-linux-gnu"
|
||||
|
||||
; Additional tests for 64-bit divide bypass
|
||||
|
||||
define i64 @Test_get_quotient(i64 %a, i64 %b) nounwind {
|
||||
; CHECK-LABEL: Test_get_quotient:
|
||||
; CHECK: movq %rdi, %rax
|
||||
; CHECK: orq %rsi, %rax
|
||||
; CHECK-NEXT: testq $-65536, %rax
|
||||
; CHECK-NEXT: je
|
||||
; CHECK: idivq
|
||||
; CHECK: ret
|
||||
; CHECK: divw
|
||||
; CHECK: ret
|
||||
%result = sdiv i64 %a, %b
|
||||
ret i64 %result
|
||||
}
|
||||
|
||||
define i64 @Test_get_remainder(i64 %a, i64 %b) nounwind {
|
||||
; CHECK-LABEL: Test_get_remainder:
|
||||
; CHECK: movq %rdi, %rax
|
||||
; CHECK: orq %rsi, %rax
|
||||
; CHECK-NEXT: testq $-65536, %rax
|
||||
; CHECK-NEXT: je
|
||||
; CHECK: idivq
|
||||
; CHECK: ret
|
||||
; CHECK: divw
|
||||
; CHECK: ret
|
||||
%result = srem i64 %a, %b
|
||||
ret i64 %result
|
||||
}
|
||||
|
||||
define i64 @Test_get_quotient_and_remainder(i64 %a, i64 %b) nounwind {
|
||||
; CHECK-LABEL: Test_get_quotient_and_remainder:
|
||||
; CHECK: movq %rdi, %rax
|
||||
; CHECK: orq %rsi, %rax
|
||||
; CHECK-NEXT: testq $-65536, %rax
|
||||
; CHECK-NEXT: je
|
||||
; CHECK: idivq
|
||||
; CHECK: divw
|
||||
; CHECK: addq
|
||||
; CHECK: ret
|
||||
; CHECK-NOT: idivq
|
||||
; CHECK-NOT: divw
|
||||
%resultdiv = sdiv i64 %a, %b
|
||||
%resultrem = srem i64 %a, %b
|
||||
%result = add i64 %resultdiv, %resultrem
|
||||
ret i64 %result
|
||||
}
|
|
@ -1,112 +0,0 @@
|
|||
; RUN: llc < %s -mcpu=atom -mtriple=i686-linux | FileCheck %s
|
||||
|
||||
define i32 @Test_get_quotient(i32 %a, i32 %b) nounwind {
|
||||
; CHECK-LABEL: Test_get_quotient:
|
||||
; CHECK: orl %ecx, %edx
|
||||
; CHECK-NEXT: testl $-256, %edx
|
||||
; CHECK-NEXT: je
|
||||
; CHECK: idivl
|
||||
; CHECK: ret
|
||||
; CHECK: divb
|
||||
; CHECK: ret
|
||||
%result = sdiv i32 %a, %b
|
||||
ret i32 %result
|
||||
}
|
||||
|
||||
define i32 @Test_get_remainder(i32 %a, i32 %b) nounwind {
|
||||
; CHECK-LABEL: Test_get_remainder:
|
||||
; CHECK: orl %ecx, %edx
|
||||
; CHECK-NEXT: testl $-256, %edx
|
||||
; CHECK-NEXT: je
|
||||
; CHECK: idivl
|
||||
; CHECK: ret
|
||||
; CHECK: divb
|
||||
; CHECK: ret
|
||||
%result = srem i32 %a, %b
|
||||
ret i32 %result
|
||||
}
|
||||
|
||||
define i32 @Test_get_quotient_and_remainder(i32 %a, i32 %b) nounwind {
|
||||
; CHECK-LABEL: Test_get_quotient_and_remainder:
|
||||
; CHECK: orl %ecx, %edx
|
||||
; CHECK-NEXT: testl $-256, %edx
|
||||
; CHECK-NEXT: je
|
||||
; CHECK: idivl
|
||||
; CHECK: divb
|
||||
; CHECK: addl
|
||||
; CHECK: ret
|
||||
; CHECK-NOT: idivl
|
||||
; CHECK-NOT: divb
|
||||
%resultdiv = sdiv i32 %a, %b
|
||||
%resultrem = srem i32 %a, %b
|
||||
%result = add i32 %resultdiv, %resultrem
|
||||
ret i32 %result
|
||||
}
|
||||
|
||||
define i32 @Test_use_div_and_idiv(i32 %a, i32 %b) nounwind {
|
||||
; CHECK-LABEL: Test_use_div_and_idiv:
|
||||
; CHECK: idivl
|
||||
; CHECK: divb
|
||||
; CHECK: divl
|
||||
; CHECK: divb
|
||||
; CHECK: addl
|
||||
; CHECK: ret
|
||||
%resultidiv = sdiv i32 %a, %b
|
||||
%resultdiv = udiv i32 %a, %b
|
||||
%result = add i32 %resultidiv, %resultdiv
|
||||
ret i32 %result
|
||||
}
|
||||
|
||||
define i32 @Test_use_div_imm_imm() nounwind {
|
||||
; CHECK-LABEL: Test_use_div_imm_imm:
|
||||
; CHECK: movl $64
|
||||
%resultdiv = sdiv i32 256, 4
|
||||
ret i32 %resultdiv
|
||||
}
|
||||
|
||||
define i32 @Test_use_div_reg_imm(i32 %a) nounwind {
|
||||
; CHECK-LABEL: Test_use_div_reg_imm:
|
||||
; CHECK-NOT: test
|
||||
; CHECK-NOT: idiv
|
||||
; CHECK-NOT: divb
|
||||
%resultdiv = sdiv i32 %a, 33
|
||||
ret i32 %resultdiv
|
||||
}
|
||||
|
||||
define i32 @Test_use_rem_reg_imm(i32 %a) nounwind {
|
||||
; CHECK-LABEL: Test_use_rem_reg_imm:
|
||||
; CHECK-NOT: test
|
||||
; CHECK-NOT: idiv
|
||||
; CHECK-NOT: divb
|
||||
%resultrem = srem i32 %a, 33
|
||||
ret i32 %resultrem
|
||||
}
|
||||
|
||||
define i32 @Test_use_divrem_reg_imm(i32 %a) nounwind {
|
||||
; CHECK-LABEL: Test_use_divrem_reg_imm:
|
||||
; CHECK-NOT: test
|
||||
; CHECK-NOT: idiv
|
||||
; CHECK-NOT: divb
|
||||
%resultdiv = sdiv i32 %a, 33
|
||||
%resultrem = srem i32 %a, 33
|
||||
%result = add i32 %resultdiv, %resultrem
|
||||
ret i32 %result
|
||||
}
|
||||
|
||||
define i32 @Test_use_div_imm_reg(i32 %a) nounwind {
|
||||
; CHECK-LABEL: Test_use_div_imm_reg:
|
||||
; CHECK: test
|
||||
; CHECK: idiv
|
||||
; CHECK: divb
|
||||
%resultdiv = sdiv i32 4, %a
|
||||
ret i32 %resultdiv
|
||||
}
|
||||
|
||||
define i32 @Test_use_rem_imm_reg(i32 %a) nounwind {
|
||||
; CHECK-LABEL: Test_use_rem_imm_reg:
|
||||
; CHECK: test
|
||||
; CHECK: idiv
|
||||
; CHECK: divb
|
||||
%resultdiv = sdiv i32 4, %a
|
||||
ret i32 %resultdiv
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
; RUN: llc -mtriple=x86_64-unknown-linux-gnu -mattr=+idivl-to-divb < %s | FileCheck -check-prefix=DIV32 %s
|
||||
; RUN: llc -mtriple=x86_64-unknown-linux-gnu -mattr=+idivq-to-divw < %s | FileCheck -check-prefix=DIV64 %s
|
||||
|
||||
define i32 @div32(i32 %a, i32 %b) {
|
||||
entry:
|
||||
; DIV32-LABEL: div32:
|
||||
; DIV32: orl %{{.*}}, [[REG:%[a-z]+]]
|
||||
; DIV32: testl $-256, [[REG]]
|
||||
; DIV32: divb
|
||||
; DIV64-LABEL: div32:
|
||||
; DIV64-NOT: divb
|
||||
%div = sdiv i32 %a, %b
|
||||
ret i32 %div
|
||||
}
|
||||
|
||||
define i64 @div64(i64 %a, i64 %b) {
|
||||
entry:
|
||||
; DIV32-LABEL: div64:
|
||||
; DIV32-NOT: divw
|
||||
; DIV64-LABEL: div64:
|
||||
; DIV64: orq %{{.*}}, [[REG:%[a-z]+]]
|
||||
; DIV64: testq $-65536, [[REG]]
|
||||
; DIV64: divw
|
||||
%div = sdiv i64 %a, %b
|
||||
ret i64 %div
|
||||
}
|
||||
|
||||
; Verify that no extra code is generated when optimizing for size.
|
||||
|
||||
define i32 @div32_optsize(i32 %a, i32 %b) optsize {
|
||||
; DIV32-LABEL: div32_optsize:
|
||||
; DIV32-NOT: divb
|
||||
%div = sdiv i32 %a, %b
|
||||
ret i32 %div
|
||||
}
|
||||
|
||||
define i32 @div32_minsize(i32 %a, i32 %b) minsize {
|
||||
; DIV32-LABEL: div32_minsize:
|
||||
; DIV32-NOT: divb
|
||||
%div = sdiv i32 %a, %b
|
||||
ret i32 %div
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
; RUN: sed 's/^;.*$//' %s \
|
||||
; RUN: | FileCheck --strict-whitespace --match-full-lines %s
|
||||
|
||||
bla1
|
||||
bla2
|
||||
bla3
|
||||
bla4
|
||||
bla5
|
||||
|
||||
; CHECK-LABEL:bla1
|
||||
; CHECK-NEXT:bla2
|
||||
; CHECK-NEXT: bla3
|
||||
; CHECK-NEXT:bla4
|
||||
; CHECK-NEXT: bla5
|
|
@ -1,38 +0,0 @@
|
|||
# RUN: llvm-mc %s -triple=mips64-unknown-linux -disassemble -mcpu=mips4 | FileCheck %s
|
||||
# XFAIL: *
|
||||
0x46 0x2f 0x79 0x32 # CHECK: c.eq.d $fcc1, $f15, $f15
|
||||
0x46 0x11 0xc5 0x32 # CHECK: c.eq.s $fcc5, $f24, $f17
|
||||
0x46 0x35 0x5c 0x30 # CHECK: c.f.d $fcc4, $f11, $f21
|
||||
0x46 0x07 0xf4 0x30 # CHECK: c.f.s $fcc4, $f30, $f7
|
||||
0x46 0x21 0x94 0x3e # CHECK: c.le.d $fcc4, $f18, $f1
|
||||
0x46 0x04 0xc6 0x3e # CHECK: c.le.s $fcc6, $f24, $f4
|
||||
0x46 0x23 0x4b 0x3c # CHECK: c.lt.d $fcc3, $f9, $f3
|
||||
0x46 0x0e 0x8a 0x3c # CHECK: c.lt.s $fcc2, $f17, $f14
|
||||
0x46 0x30 0xad 0x3d # CHECK: c.nge.d $fcc5, $f21, $f16
|
||||
0x46 0x08 0x5b 0x3d # CHECK: c.nge.s $fcc3, $f11, $f8
|
||||
0x46 0x17 0xfa 0x3b # CHECK: c.ngl.s $fcc2, $f31, $f23
|
||||
0x46 0x17 0x92 0x39 # CHECK: c.ngle.s $fcc2, $f18, $f23
|
||||
0x46 0x27 0xc4 0x3f # CHECK: c.ngt.d $fcc4, $f24, $f7
|
||||
0x46 0x0d 0x45 0x3f # CHECK: c.ngt.s $fcc5, $f8, $f13
|
||||
0x46 0x3f 0x82 0x36 # CHECK: c.ole.d $fcc2, $f16, $f31
|
||||
0x46 0x14 0x3b 0x36 # CHECK: c.ole.s $fcc3, $f7, $f20
|
||||
0x46 0x3c 0x9c 0x34 # CHECK: c.olt.d $fcc4, $f19, $f28
|
||||
0x46 0x07 0xa6 0x34 # CHECK: c.olt.s $fcc6, $f20, $f7
|
||||
0x46 0x27 0xfc 0x3a # CHECK: c.seq.d $fcc4, $f31, $f7
|
||||
0x46 0x19 0x0f 0x3a # CHECK: c.seq.s $fcc7, $f1, $f25
|
||||
0x46 0x39 0x6c 0x33 # CHECK: c.ueq.d $fcc4, $f13, $f25
|
||||
0x46 0x1e 0x1e 0x33 # CHECK: c.ueq.s $fcc6, $f3, $f30
|
||||
0x46 0x32 0xcf 0x37 # CHECK: c.ule.d $fcc7, $f25, $f18
|
||||
0x46 0x1e 0xaf 0x37 # CHECK: c.ule.s $fcc7, $f21, $f30
|
||||
0x46 0x31 0x36 0x35 # CHECK: c.ult.d $fcc6, $f6, $f17
|
||||
0x46 0x0a 0xc7 0x35 # CHECK: c.ult.s $fcc7, $f24, $f10
|
||||
0x46 0x38 0xbe 0x31 # CHECK: c.un.d $fcc6, $f23, $f24
|
||||
0x46 0x04 0xf1 0x31 # CHECK: c.un.s $fcc1, $f30, $f4
|
||||
0x4e 0x74 0xd4 0xa1 # CHECK: madd.d $f18, $f19, $f26, $f20
|
||||
0x4f 0xf9 0x98 0x60 # CHECK: madd.s $f1, $f31, $f19, $f25
|
||||
0x4c 0x32 0xfa 0xa9 # CHECK: msub.d $f10, $f1, $f31, $f18
|
||||
0x4e 0x70 0x53 0x28 # CHECK: msub.s $f12, $f19, $f10, $f16
|
||||
0x4d 0x33 0x74 0xb1 # CHECK: nmadd.d $f18, $f9, $f14, $f19
|
||||
0x4c 0xac 0xc8 0x30 # CHECK: nmadd.s $f0, $f5, $f25, $f12
|
||||
0x4d 0x1e 0x87 0xb9 # CHECK: nmsub.d $f30, $f8, $f16, $f30
|
||||
0x4f 0x04 0x98 0x78 # CHECK: nmsub.s $f1, $f24, $f19, $f4
|
|
@ -1,10 +0,0 @@
|
|||
# Instructions that are invalid and are correctly rejected but use the wrong
|
||||
# error message at the moment.
|
||||
#
|
||||
# RUN: not llvm-mc %s -triple=mips-unknown-linux -show-encoding -mcpu=mips3 \
|
||||
# RUN: 2>%t1
|
||||
# RUN: FileCheck %s < %t1
|
||||
|
||||
.set noat
|
||||
bc1fl $fcc7,27 # CHECK: :[[@LINE]]:{{[0-9]+}}: error: invalid operand for instruction
|
||||
bc1tl $fcc7,27 # CHECK: :[[@LINE]]:{{[0-9]+}}: error: invalid operand for instruction
|
|
@ -1,3 +0,0 @@
|
|||
; RUN: not llvm-xray extract %S/Inputs/elf64-badentrysizes.bin 2>&1 | FileCheck %s
|
||||
; CHECK: llvm-xray: Cannot extract instrumentation map from '{{.*}}elf64-badentrysizes.bin'.
|
||||
; CHECK-NEXT: Instrumentation map entries not evenly divisible by size of an XRay sled entry in ELF64.
|
|
@ -1,90 +0,0 @@
|
|||
//===- BuiltinDumper.cpp ---------------------------------------- *- C++ *-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "BuiltinDumper.h"
|
||||
#include "LinePrinter.h"
|
||||
#include "llvm-pdbdump.h"
|
||||
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::pdb;
|
||||
|
||||
BuiltinDumper::BuiltinDumper(LinePrinter &P)
|
||||
: PDBSymDumper(false), Printer(P) {}
|
||||
|
||||
void BuiltinDumper::start(const PDBSymbolTypeBuiltin &Symbol) {
|
||||
WithColor(Printer, PDB_ColorItem::Type).get() << getTypeName(Symbol);
|
||||
}
|
||||
|
||||
StringRef BuiltinDumper::getTypeName(const PDBSymbolTypeBuiltin &Symbol) {
|
||||
PDB_BuiltinType Type = Symbol.getBuiltinType();
|
||||
switch (Type) {
|
||||
case PDB_BuiltinType::Float:
|
||||
if (Symbol.getLength() == 4)
|
||||
return "float";
|
||||
return "double";
|
||||
case PDB_BuiltinType::UInt:
|
||||
switch (Symbol.getLength()) {
|
||||
case 8:
|
||||
return "unsigned __int64";
|
||||
case 4:
|
||||
return "unsigned int";
|
||||
case 2:
|
||||
return "unsigned short";
|
||||
case 1:
|
||||
return "unsigned char";
|
||||
default:
|
||||
return "unsigned";
|
||||
}
|
||||
case PDB_BuiltinType::Int:
|
||||
switch (Symbol.getLength()) {
|
||||
case 8:
|
||||
return "__int64";
|
||||
case 4:
|
||||
return "int";
|
||||
case 2:
|
||||
return "short";
|
||||
case 1:
|
||||
return "char";
|
||||
default:
|
||||
return "int";
|
||||
}
|
||||
case PDB_BuiltinType::Char:
|
||||
return "char";
|
||||
case PDB_BuiltinType::WCharT:
|
||||
return "wchar_t";
|
||||
case PDB_BuiltinType::Void:
|
||||
return "void";
|
||||
case PDB_BuiltinType::Long:
|
||||
return "long";
|
||||
case PDB_BuiltinType::ULong:
|
||||
return "unsigned long";
|
||||
case PDB_BuiltinType::Bool:
|
||||
return "bool";
|
||||
case PDB_BuiltinType::Currency:
|
||||
return "CURRENCY";
|
||||
case PDB_BuiltinType::Date:
|
||||
return "DATE";
|
||||
case PDB_BuiltinType::Variant:
|
||||
return "VARIANT";
|
||||
case PDB_BuiltinType::Complex:
|
||||
return "complex";
|
||||
case PDB_BuiltinType::Bitfield:
|
||||
return "bitfield";
|
||||
case PDB_BuiltinType::BSTR:
|
||||
return "BSTR";
|
||||
case PDB_BuiltinType::HResult:
|
||||
return "HRESULT";
|
||||
case PDB_BuiltinType::BCD:
|
||||
return "HRESULT";
|
||||
default:
|
||||
return "void";
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
//===- BuiltinDumper.h ---------------------------------------- *- C++ --*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_TOOLS_LLVMPDBDUMP_BUILTINDUMPER_H
|
||||
#define LLVM_TOOLS_LLVMPDBDUMP_BUILTINDUMPER_H
|
||||
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace pdb {
|
||||
|
||||
class LinePrinter;
|
||||
|
||||
class BuiltinDumper : public PDBSymDumper {
|
||||
public:
|
||||
BuiltinDumper(LinePrinter &P);
|
||||
|
||||
void start(const PDBSymbolTypeBuiltin &Symbol);
|
||||
|
||||
private:
|
||||
StringRef getTypeName(const PDBSymbolTypeBuiltin &Symbol);
|
||||
|
||||
LinePrinter &Printer;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,191 +0,0 @@
|
|||
//===- ClassDefinitionDumper.cpp --------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "ClassDefinitionDumper.h"
|
||||
#include "EnumDumper.h"
|
||||
#include "FunctionDumper.h"
|
||||
#include "LinePrinter.h"
|
||||
#include "llvm-pdbdump.h"
|
||||
#include "TypedefDumper.h"
|
||||
#include "VariableDumper.h"
|
||||
|
||||
#include "llvm/DebugInfo/PDB/IPDBSession.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBExtras.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h"
|
||||
#include "llvm/Support/Format.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::pdb;
|
||||
|
||||
ClassDefinitionDumper::ClassDefinitionDumper(LinePrinter &P)
|
||||
: PDBSymDumper(true), Printer(P) {}
|
||||
|
||||
void ClassDefinitionDumper::start(const PDBSymbolTypeUDT &Class) {
|
||||
std::string Name = Class.getName();
|
||||
WithColor(Printer, PDB_ColorItem::Keyword).get() << Class.getUdtKind() << " ";
|
||||
WithColor(Printer, PDB_ColorItem::Type).get() << Class.getName();
|
||||
|
||||
auto Bases = Class.findAllChildren<PDBSymbolTypeBaseClass>();
|
||||
if (Bases->getChildCount() > 0) {
|
||||
Printer.Indent();
|
||||
Printer.NewLine();
|
||||
Printer << ":";
|
||||
uint32_t BaseIndex = 0;
|
||||
while (auto Base = Bases->getNext()) {
|
||||
Printer << " ";
|
||||
WithColor(Printer, PDB_ColorItem::Keyword).get() << Base->getAccess();
|
||||
if (Base->isVirtualBaseClass())
|
||||
WithColor(Printer, PDB_ColorItem::Keyword).get() << " virtual";
|
||||
WithColor(Printer, PDB_ColorItem::Type).get() << " " << Base->getName();
|
||||
if (++BaseIndex < Bases->getChildCount()) {
|
||||
Printer.NewLine();
|
||||
Printer << ",";
|
||||
}
|
||||
}
|
||||
Printer.Unindent();
|
||||
}
|
||||
|
||||
Printer << " {";
|
||||
auto Children = Class.findAllChildren();
|
||||
if (Children->getChildCount() == 0) {
|
||||
Printer << "}";
|
||||
return;
|
||||
}
|
||||
|
||||
// Try to dump symbols organized by member access level. Public members
|
||||
// first, then protected, then private. This might be slow, so it's worth
|
||||
// reconsidering the value of this if performance of large PDBs is a problem.
|
||||
// NOTE: Access level of nested types is not recorded in the PDB, so we have
|
||||
// a special case for them.
|
||||
SymbolGroupByAccess Groups;
|
||||
Groups.insert(std::make_pair(0, SymbolGroup()));
|
||||
Groups.insert(std::make_pair((int)PDB_MemberAccess::Private, SymbolGroup()));
|
||||
Groups.insert(
|
||||
std::make_pair((int)PDB_MemberAccess::Protected, SymbolGroup()));
|
||||
Groups.insert(std::make_pair((int)PDB_MemberAccess::Public, SymbolGroup()));
|
||||
|
||||
while (auto Child = Children->getNext()) {
|
||||
PDB_MemberAccess Access = Child->getRawSymbol().getAccess();
|
||||
if (isa<PDBSymbolTypeBaseClass>(*Child))
|
||||
continue;
|
||||
|
||||
auto &AccessGroup = Groups.find((int)Access)->second;
|
||||
|
||||
if (auto Func = dyn_cast<PDBSymbolFunc>(Child.get())) {
|
||||
if (Func->isCompilerGenerated() && opts::pretty::ExcludeCompilerGenerated)
|
||||
continue;
|
||||
if (Func->getLength() == 0 && !Func->isPureVirtual() &&
|
||||
!Func->isIntroVirtualFunction())
|
||||
continue;
|
||||
Child.release();
|
||||
AccessGroup.Functions.push_back(std::unique_ptr<PDBSymbolFunc>(Func));
|
||||
} else if (auto Data = dyn_cast<PDBSymbolData>(Child.get())) {
|
||||
Child.release();
|
||||
AccessGroup.Data.push_back(std::unique_ptr<PDBSymbolData>(Data));
|
||||
} else {
|
||||
AccessGroup.Unknown.push_back(std::move(Child));
|
||||
}
|
||||
}
|
||||
|
||||
int Count = 0;
|
||||
Count += dumpAccessGroup((PDB_MemberAccess)0, Groups[0]);
|
||||
Count += dumpAccessGroup(PDB_MemberAccess::Public,
|
||||
Groups[(int)PDB_MemberAccess::Public]);
|
||||
Count += dumpAccessGroup(PDB_MemberAccess::Protected,
|
||||
Groups[(int)PDB_MemberAccess::Protected]);
|
||||
Count += dumpAccessGroup(PDB_MemberAccess::Private,
|
||||
Groups[(int)PDB_MemberAccess::Private]);
|
||||
if (Count > 0)
|
||||
Printer.NewLine();
|
||||
Printer << "}";
|
||||
}
|
||||
|
||||
int ClassDefinitionDumper::dumpAccessGroup(PDB_MemberAccess Access,
|
||||
const SymbolGroup &Group) {
|
||||
if (Group.Functions.empty() && Group.Data.empty() && Group.Unknown.empty())
|
||||
return 0;
|
||||
|
||||
int Count = 0;
|
||||
if (Access == PDB_MemberAccess::Private) {
|
||||
Printer.NewLine();
|
||||
WithColor(Printer, PDB_ColorItem::Keyword).get() << "private";
|
||||
Printer << ":";
|
||||
} else if (Access == PDB_MemberAccess::Protected) {
|
||||
Printer.NewLine();
|
||||
WithColor(Printer, PDB_ColorItem::Keyword).get() << "protected";
|
||||
Printer << ":";
|
||||
} else if (Access == PDB_MemberAccess::Public) {
|
||||
Printer.NewLine();
|
||||
WithColor(Printer, PDB_ColorItem::Keyword).get() << "public";
|
||||
Printer << ":";
|
||||
}
|
||||
Printer.Indent();
|
||||
for (auto iter = Group.Functions.begin(), end = Group.Functions.end();
|
||||
iter != end; ++iter) {
|
||||
++Count;
|
||||
(*iter)->dump(*this);
|
||||
}
|
||||
for (auto iter = Group.Data.begin(), end = Group.Data.end(); iter != end;
|
||||
++iter) {
|
||||
++Count;
|
||||
(*iter)->dump(*this);
|
||||
}
|
||||
for (auto iter = Group.Unknown.begin(), end = Group.Unknown.end();
|
||||
iter != end; ++iter) {
|
||||
++Count;
|
||||
(*iter)->dump(*this);
|
||||
}
|
||||
Printer.Unindent();
|
||||
return Count;
|
||||
}
|
||||
|
||||
void ClassDefinitionDumper::dump(const PDBSymbolTypeBaseClass &Symbol) {}
|
||||
|
||||
void ClassDefinitionDumper::dump(const PDBSymbolData &Symbol) {
|
||||
VariableDumper Dumper(Printer);
|
||||
Dumper.start(Symbol);
|
||||
}
|
||||
|
||||
void ClassDefinitionDumper::dump(const PDBSymbolFunc &Symbol) {
|
||||
if (Printer.IsSymbolExcluded(Symbol.getName()))
|
||||
return;
|
||||
|
||||
Printer.NewLine();
|
||||
FunctionDumper Dumper(Printer);
|
||||
Dumper.start(Symbol, FunctionDumper::PointerType::None);
|
||||
}
|
||||
|
||||
void ClassDefinitionDumper::dump(const PDBSymbolTypeVTable &Symbol) {}
|
||||
|
||||
void ClassDefinitionDumper::dump(const PDBSymbolTypeEnum &Symbol) {
|
||||
if (Printer.IsTypeExcluded(Symbol.getName()))
|
||||
return;
|
||||
|
||||
Printer.NewLine();
|
||||
EnumDumper Dumper(Printer);
|
||||
Dumper.start(Symbol);
|
||||
}
|
||||
|
||||
void ClassDefinitionDumper::dump(const PDBSymbolTypeTypedef &Symbol) {
|
||||
if (Printer.IsTypeExcluded(Symbol.getName()))
|
||||
return;
|
||||
|
||||
Printer.NewLine();
|
||||
TypedefDumper Dumper(Printer);
|
||||
Dumper.start(Symbol);
|
||||
}
|
||||
|
||||
void ClassDefinitionDumper::dump(const PDBSymbolTypeUDT &Symbol) {}
|
|
@ -1,63 +0,0 @@
|
|||
//===- ClassDefinitionDumper.h - --------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_TOOLS_LLVMPDBDUMP_CLASSDEFINITIONDUMPER_H
|
||||
#define LLVM_TOOLS_LLVMPDBDUMP_CLASSDEFINITIONDUMPER_H
|
||||
|
||||
#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
|
||||
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace llvm {
|
||||
namespace pdb {
|
||||
|
||||
class LinePrinter;
|
||||
|
||||
class ClassDefinitionDumper : public PDBSymDumper {
|
||||
public:
|
||||
ClassDefinitionDumper(LinePrinter &P);
|
||||
|
||||
void start(const PDBSymbolTypeUDT &Exe);
|
||||
|
||||
void dump(const PDBSymbolTypeBaseClass &Symbol) override;
|
||||
void dump(const PDBSymbolData &Symbol) override;
|
||||
void dump(const PDBSymbolTypeEnum &Symbol) override;
|
||||
void dump(const PDBSymbolFunc &Symbol) override;
|
||||
void dump(const PDBSymbolTypeTypedef &Symbol) override;
|
||||
void dump(const PDBSymbolTypeUDT &Symbol) override;
|
||||
void dump(const PDBSymbolTypeVTable &Symbol) override;
|
||||
|
||||
private:
|
||||
LinePrinter &Printer;
|
||||
|
||||
struct SymbolGroup {
|
||||
SymbolGroup() {}
|
||||
SymbolGroup(SymbolGroup &&Other) {
|
||||
Functions = std::move(Other.Functions);
|
||||
Data = std::move(Other.Data);
|
||||
Unknown = std::move(Other.Unknown);
|
||||
}
|
||||
|
||||
std::list<std::unique_ptr<PDBSymbolFunc>> Functions;
|
||||
std::list<std::unique_ptr<PDBSymbolData>> Data;
|
||||
std::list<std::unique_ptr<PDBSymbol>> Unknown;
|
||||
SymbolGroup(const SymbolGroup &other) = delete;
|
||||
SymbolGroup &operator=(const SymbolGroup &other) = delete;
|
||||
};
|
||||
typedef std::unordered_map<int, SymbolGroup> SymbolGroupByAccess;
|
||||
|
||||
int dumpAccessGroup(PDB_MemberAccess Access, const SymbolGroup &Group);
|
||||
};
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -1,195 +0,0 @@
|
|||
//===- CompilandDumper.cpp - llvm-pdbdump compiland symbol dumper *- C++ *-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "CompilandDumper.h"
|
||||
#include "LinePrinter.h"
|
||||
#include "llvm-pdbdump.h"
|
||||
|
||||
#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h"
|
||||
#include "llvm/DebugInfo/PDB/IPDBLineNumber.h"
|
||||
#include "llvm/DebugInfo/PDB/IPDBSession.h"
|
||||
#include "llvm/DebugInfo/PDB/IPDBSourceFile.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBExtras.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbol.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugEnd.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugStart.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolLabel.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolThunk.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolUnknown.h"
|
||||
#include "llvm/Support/Format.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
#include "FunctionDumper.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::pdb;
|
||||
|
||||
CompilandDumper::CompilandDumper(LinePrinter &P)
|
||||
: PDBSymDumper(true), Printer(P) {}
|
||||
|
||||
void CompilandDumper::dump(const PDBSymbolCompilandDetails &Symbol) {}
|
||||
|
||||
void CompilandDumper::dump(const PDBSymbolCompilandEnv &Symbol) {}
|
||||
|
||||
void CompilandDumper::start(const PDBSymbolCompiland &Symbol,
|
||||
CompilandDumpFlags opts) {
|
||||
std::string FullName = Symbol.getName();
|
||||
if (Printer.IsCompilandExcluded(FullName))
|
||||
return;
|
||||
|
||||
Printer.NewLine();
|
||||
WithColor(Printer, PDB_ColorItem::Path).get() << FullName;
|
||||
|
||||
if (opts & Flags::Lines) {
|
||||
const IPDBSession &Session = Symbol.getSession();
|
||||
auto Files = Session.getSourceFilesForCompiland(Symbol);
|
||||
Printer.Indent();
|
||||
while (auto File = Files->getNext()) {
|
||||
Printer.NewLine();
|
||||
WithColor(Printer, PDB_ColorItem::Path).get() << File->getFileName();
|
||||
|
||||
auto Lines = Session.findLineNumbers(Symbol, *File);
|
||||
Printer.Indent();
|
||||
while (auto Line = Lines->getNext()) {
|
||||
Printer.NewLine();
|
||||
uint32_t LineStart = Line->getLineNumber();
|
||||
uint32_t LineEnd = Line->getLineNumberEnd();
|
||||
|
||||
Printer << "Line ";
|
||||
PDB_ColorItem StatementColor = Line->isStatement()
|
||||
? PDB_ColorItem::Keyword
|
||||
: PDB_ColorItem::LiteralValue;
|
||||
WithColor(Printer, StatementColor).get() << LineStart;
|
||||
if (LineStart != LineEnd)
|
||||
WithColor(Printer, StatementColor).get() << " - " << LineEnd;
|
||||
|
||||
uint32_t ColumnStart = Line->getColumnNumber();
|
||||
uint32_t ColumnEnd = Line->getColumnNumberEnd();
|
||||
if (ColumnStart != 0 || ColumnEnd != 0) {
|
||||
Printer << ", Column: ";
|
||||
WithColor(Printer, StatementColor).get() << ColumnStart;
|
||||
if (ColumnEnd != ColumnStart)
|
||||
WithColor(Printer, StatementColor).get() << " - " << ColumnEnd;
|
||||
}
|
||||
|
||||
Printer << ", Address: ";
|
||||
if (Line->getLength() > 0) {
|
||||
uint64_t AddrStart = Line->getVirtualAddress();
|
||||
uint64_t AddrEnd = AddrStart + Line->getLength() - 1;
|
||||
WithColor(Printer, PDB_ColorItem::Address).get()
|
||||
<< "[" << format_hex(AddrStart, 10) << " - "
|
||||
<< format_hex(AddrEnd, 10) << "]";
|
||||
Printer << " (" << Line->getLength() << " bytes)";
|
||||
} else {
|
||||
uint64_t AddrStart = Line->getVirtualAddress();
|
||||
WithColor(Printer, PDB_ColorItem::Address).get()
|
||||
<< "[" << format_hex(AddrStart, 10) << "] ";
|
||||
Printer << "(0 bytes)";
|
||||
}
|
||||
}
|
||||
Printer.Unindent();
|
||||
}
|
||||
Printer.Unindent();
|
||||
}
|
||||
|
||||
if (opts & Flags::Children) {
|
||||
auto ChildrenEnum = Symbol.findAllChildren();
|
||||
Printer.Indent();
|
||||
while (auto Child = ChildrenEnum->getNext())
|
||||
Child->dump(*this);
|
||||
Printer.Unindent();
|
||||
}
|
||||
}
|
||||
|
||||
void CompilandDumper::dump(const PDBSymbolData &Symbol) {
|
||||
if (Printer.IsSymbolExcluded(Symbol.getName()))
|
||||
return;
|
||||
|
||||
Printer.NewLine();
|
||||
|
||||
switch (auto LocType = Symbol.getLocationType()) {
|
||||
case PDB_LocType::Static:
|
||||
Printer << "data: ";
|
||||
WithColor(Printer, PDB_ColorItem::Address).get()
|
||||
<< "[" << format_hex(Symbol.getVirtualAddress(), 10) << "]";
|
||||
break;
|
||||
case PDB_LocType::Constant:
|
||||
Printer << "constant: ";
|
||||
WithColor(Printer, PDB_ColorItem::LiteralValue).get()
|
||||
<< "[" << Symbol.getValue() << "]";
|
||||
break;
|
||||
default:
|
||||
Printer << "data(unexpected type=" << LocType << ")";
|
||||
}
|
||||
|
||||
Printer << " ";
|
||||
WithColor(Printer, PDB_ColorItem::Identifier).get() << Symbol.getName();
|
||||
}
|
||||
|
||||
void CompilandDumper::dump(const PDBSymbolFunc &Symbol) {
|
||||
if (Symbol.getLength() == 0)
|
||||
return;
|
||||
if (Printer.IsSymbolExcluded(Symbol.getName()))
|
||||
return;
|
||||
|
||||
Printer.NewLine();
|
||||
FunctionDumper Dumper(Printer);
|
||||
Dumper.start(Symbol, FunctionDumper::PointerType::None);
|
||||
}
|
||||
|
||||
void CompilandDumper::dump(const PDBSymbolLabel &Symbol) {
|
||||
if (Printer.IsSymbolExcluded(Symbol.getName()))
|
||||
return;
|
||||
|
||||
Printer.NewLine();
|
||||
Printer << "label ";
|
||||
WithColor(Printer, PDB_ColorItem::Address).get()
|
||||
<< "[" << format_hex(Symbol.getVirtualAddress(), 10) << "] ";
|
||||
WithColor(Printer, PDB_ColorItem::Identifier).get() << Symbol.getName();
|
||||
}
|
||||
|
||||
void CompilandDumper::dump(const PDBSymbolThunk &Symbol) {
|
||||
if (Printer.IsSymbolExcluded(Symbol.getName()))
|
||||
return;
|
||||
|
||||
Printer.NewLine();
|
||||
Printer << "thunk ";
|
||||
codeview::ThunkOrdinal Ordinal = Symbol.getThunkOrdinal();
|
||||
uint64_t VA = Symbol.getVirtualAddress();
|
||||
if (Ordinal == codeview::ThunkOrdinal::TrampIncremental) {
|
||||
uint64_t Target = Symbol.getTargetVirtualAddress();
|
||||
WithColor(Printer, PDB_ColorItem::Address).get() << format_hex(VA, 10);
|
||||
Printer << " -> ";
|
||||
WithColor(Printer, PDB_ColorItem::Address).get() << format_hex(Target, 10);
|
||||
} else {
|
||||
WithColor(Printer, PDB_ColorItem::Address).get()
|
||||
<< "[" << format_hex(VA, 10) << " - "
|
||||
<< format_hex(VA + Symbol.getLength(), 10) << "]";
|
||||
}
|
||||
Printer << " (";
|
||||
WithColor(Printer, PDB_ColorItem::Register).get() << Ordinal;
|
||||
Printer << ") ";
|
||||
std::string Name = Symbol.getName();
|
||||
if (!Name.empty())
|
||||
WithColor(Printer, PDB_ColorItem::Identifier).get() << Name;
|
||||
}
|
||||
|
||||
void CompilandDumper::dump(const PDBSymbolTypeTypedef &Symbol) {}
|
||||
|
||||
void CompilandDumper::dump(const PDBSymbolUnknown &Symbol) {
|
||||
Printer.NewLine();
|
||||
Printer << "unknown (" << Symbol.getSymTag() << ")";
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
//===- CompilandDumper.h - llvm-pdbdump compiland symbol dumper *- C++ --*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_TOOLS_LLVMPDBDUMP_COMPILANDDUMPER_H
|
||||
#define LLVM_TOOLS_LLVMPDBDUMP_COMPILANDDUMPER_H
|
||||
|
||||
#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace pdb {
|
||||
|
||||
class LinePrinter;
|
||||
|
||||
typedef int CompilandDumpFlags;
|
||||
class CompilandDumper : public PDBSymDumper {
|
||||
public:
|
||||
enum Flags { None = 0x0, Children = 0x1, Symbols = 0x2, Lines = 0x4 };
|
||||
|
||||
CompilandDumper(LinePrinter &P);
|
||||
|
||||
void start(const PDBSymbolCompiland &Symbol, CompilandDumpFlags flags);
|
||||
|
||||
void dump(const PDBSymbolCompilandDetails &Symbol) override;
|
||||
void dump(const PDBSymbolCompilandEnv &Symbol) override;
|
||||
void dump(const PDBSymbolData &Symbol) override;
|
||||
void dump(const PDBSymbolFunc &Symbol) override;
|
||||
void dump(const PDBSymbolLabel &Symbol) override;
|
||||
void dump(const PDBSymbolThunk &Symbol) override;
|
||||
void dump(const PDBSymbolTypeTypedef &Symbol) override;
|
||||
void dump(const PDBSymbolUnknown &Symbol) override;
|
||||
|
||||
private:
|
||||
LinePrinter &Printer;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,53 +0,0 @@
|
|||
//===- EnumDumper.cpp -------------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "EnumDumper.h"
|
||||
|
||||
#include "BuiltinDumper.h"
|
||||
#include "LinePrinter.h"
|
||||
#include "llvm-pdbdump.h"
|
||||
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::pdb;
|
||||
|
||||
EnumDumper::EnumDumper(LinePrinter &P) : PDBSymDumper(true), Printer(P) {}
|
||||
|
||||
void EnumDumper::start(const PDBSymbolTypeEnum &Symbol) {
|
||||
WithColor(Printer, PDB_ColorItem::Keyword).get() << "enum ";
|
||||
WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName();
|
||||
if (!opts::pretty::NoEnumDefs) {
|
||||
auto BuiltinType = Symbol.getUnderlyingType();
|
||||
if (BuiltinType->getBuiltinType() != PDB_BuiltinType::Int ||
|
||||
BuiltinType->getLength() != 4) {
|
||||
Printer << " : ";
|
||||
BuiltinDumper Dumper(Printer);
|
||||
Dumper.start(*BuiltinType);
|
||||
}
|
||||
Printer << " {";
|
||||
Printer.Indent();
|
||||
auto EnumValues = Symbol.findAllChildren<PDBSymbolData>();
|
||||
while (auto EnumValue = EnumValues->getNext()) {
|
||||
if (EnumValue->getDataKind() != PDB_DataKind::Constant)
|
||||
continue;
|
||||
Printer.NewLine();
|
||||
WithColor(Printer, PDB_ColorItem::Identifier).get()
|
||||
<< EnumValue->getName();
|
||||
Printer << " = ";
|
||||
WithColor(Printer, PDB_ColorItem::LiteralValue).get()
|
||||
<< EnumValue->getValue();
|
||||
}
|
||||
Printer.Unindent();
|
||||
Printer.NewLine();
|
||||
Printer << "}";
|
||||
}
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
//===- EnumDumper.h - -------------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_TOOLS_LLVMPDBDUMP_ENUMDUMPER_H
|
||||
#define LLVM_TOOLS_LLVMPDBDUMP_ENUMDUMPER_H
|
||||
|
||||
#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace pdb {
|
||||
|
||||
class LinePrinter;
|
||||
|
||||
class EnumDumper : public PDBSymDumper {
|
||||
public:
|
||||
EnumDumper(LinePrinter &P);
|
||||
|
||||
void start(const PDBSymbolTypeEnum &Symbol);
|
||||
|
||||
private:
|
||||
LinePrinter &Printer;
|
||||
};
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -1,41 +0,0 @@
|
|||
//===- ExternalSymbolDumper.cpp -------------------------------- *- C++ *-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "ExternalSymbolDumper.h"
|
||||
#include "LinePrinter.h"
|
||||
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolExe.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolPublicSymbol.h"
|
||||
#include "llvm/Support/Format.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::pdb;
|
||||
|
||||
ExternalSymbolDumper::ExternalSymbolDumper(LinePrinter &P)
|
||||
: PDBSymDumper(true), Printer(P) {}
|
||||
|
||||
void ExternalSymbolDumper::start(const PDBSymbolExe &Symbol) {
|
||||
auto Vars = Symbol.findAllChildren<PDBSymbolPublicSymbol>();
|
||||
while (auto Var = Vars->getNext())
|
||||
Var->dump(*this);
|
||||
}
|
||||
|
||||
void ExternalSymbolDumper::dump(const PDBSymbolPublicSymbol &Symbol) {
|
||||
std::string LinkageName = Symbol.getName();
|
||||
if (Printer.IsSymbolExcluded(LinkageName))
|
||||
return;
|
||||
|
||||
Printer.NewLine();
|
||||
uint64_t Addr = Symbol.getVirtualAddress();
|
||||
|
||||
Printer << "[";
|
||||
WithColor(Printer, PDB_ColorItem::Address).get() << format_hex(Addr, 10);
|
||||
Printer << "] ";
|
||||
WithColor(Printer, PDB_ColorItem::Identifier).get() << LinkageName;
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
//===- ExternalSymbolDumper.h --------------------------------- *- C++ --*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_TOOLS_LLVMPDBDUMP_EXTERNALSYMBOLDUMPER_H
|
||||
#define LLVM_TOOLS_LLVMPDBDUMP_EXTERNALSYMBOLDUMPER_H
|
||||
|
||||
#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace pdb {
|
||||
|
||||
class LinePrinter;
|
||||
|
||||
class ExternalSymbolDumper : public PDBSymDumper {
|
||||
public:
|
||||
ExternalSymbolDumper(LinePrinter &P);
|
||||
|
||||
void start(const PDBSymbolExe &Symbol);
|
||||
|
||||
void dump(const PDBSymbolPublicSymbol &Symbol) override;
|
||||
|
||||
private:
|
||||
LinePrinter &Printer;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,257 +0,0 @@
|
|||
//===- FunctionDumper.cpp ------------------------------------ *- C++ *-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "FunctionDumper.h"
|
||||
#include "BuiltinDumper.h"
|
||||
#include "LinePrinter.h"
|
||||
#include "llvm-pdbdump.h"
|
||||
|
||||
#include "llvm/DebugInfo/PDB/IPDBSession.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBExtras.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugEnd.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugStart.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolTypeArray.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionArg.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
|
||||
#include "llvm/Support/Format.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::codeview;
|
||||
using namespace llvm::pdb;
|
||||
|
||||
namespace {
|
||||
template <class T>
|
||||
void dumpClassParentWithScopeOperator(const T &Symbol, LinePrinter &Printer,
|
||||
FunctionDumper &Dumper) {
|
||||
uint32_t ClassParentId = Symbol.getClassParentId();
|
||||
auto ClassParent =
|
||||
Symbol.getSession().template getConcreteSymbolById<PDBSymbolTypeUDT>(
|
||||
ClassParentId);
|
||||
if (!ClassParent)
|
||||
return;
|
||||
|
||||
WithColor(Printer, PDB_ColorItem::Type).get() << ClassParent->getName();
|
||||
Printer << "::";
|
||||
}
|
||||
}
|
||||
|
||||
FunctionDumper::FunctionDumper(LinePrinter &P)
|
||||
: PDBSymDumper(true), Printer(P) {}
|
||||
|
||||
void FunctionDumper::start(const PDBSymbolTypeFunctionSig &Symbol,
|
||||
const char *Name, PointerType Pointer) {
|
||||
auto ReturnType = Symbol.getReturnType();
|
||||
ReturnType->dump(*this);
|
||||
Printer << " ";
|
||||
uint32_t ClassParentId = Symbol.getClassParentId();
|
||||
auto ClassParent =
|
||||
Symbol.getSession().getConcreteSymbolById<PDBSymbolTypeUDT>(
|
||||
ClassParentId);
|
||||
|
||||
PDB_CallingConv CC = Symbol.getCallingConvention();
|
||||
bool ShouldDumpCallingConvention = true;
|
||||
if ((ClassParent && CC == CallingConvention::ThisCall) ||
|
||||
(!ClassParent && CC == CallingConvention::NearStdCall)) {
|
||||
ShouldDumpCallingConvention = false;
|
||||
}
|
||||
|
||||
if (Pointer == PointerType::None) {
|
||||
if (ShouldDumpCallingConvention)
|
||||
WithColor(Printer, PDB_ColorItem::Keyword).get() << CC << " ";
|
||||
if (ClassParent) {
|
||||
Printer << "(";
|
||||
WithColor(Printer, PDB_ColorItem::Identifier).get()
|
||||
<< ClassParent->getName();
|
||||
Printer << "::)";
|
||||
}
|
||||
} else {
|
||||
Printer << "(";
|
||||
if (ShouldDumpCallingConvention)
|
||||
WithColor(Printer, PDB_ColorItem::Keyword).get() << CC << " ";
|
||||
if (ClassParent) {
|
||||
WithColor(Printer, PDB_ColorItem::Identifier).get()
|
||||
<< ClassParent->getName();
|
||||
Printer << "::";
|
||||
}
|
||||
if (Pointer == PointerType::Reference)
|
||||
Printer << "&";
|
||||
else
|
||||
Printer << "*";
|
||||
if (Name)
|
||||
WithColor(Printer, PDB_ColorItem::Identifier).get() << Name;
|
||||
Printer << ")";
|
||||
}
|
||||
|
||||
Printer << "(";
|
||||
if (auto ChildEnum = Symbol.getArguments()) {
|
||||
uint32_t Index = 0;
|
||||
while (auto Arg = ChildEnum->getNext()) {
|
||||
Arg->dump(*this);
|
||||
if (++Index < ChildEnum->getChildCount())
|
||||
Printer << ", ";
|
||||
}
|
||||
}
|
||||
Printer << ")";
|
||||
|
||||
if (Symbol.isConstType())
|
||||
WithColor(Printer, PDB_ColorItem::Keyword).get() << " const";
|
||||
if (Symbol.isVolatileType())
|
||||
WithColor(Printer, PDB_ColorItem::Keyword).get() << " volatile";
|
||||
}
|
||||
|
||||
void FunctionDumper::start(const PDBSymbolFunc &Symbol, PointerType Pointer) {
|
||||
uint64_t FuncStart = Symbol.getVirtualAddress();
|
||||
uint64_t FuncEnd = FuncStart + Symbol.getLength();
|
||||
|
||||
Printer << "func [";
|
||||
WithColor(Printer, PDB_ColorItem::Address).get() << format_hex(FuncStart, 10);
|
||||
if (auto DebugStart = Symbol.findOneChild<PDBSymbolFuncDebugStart>()) {
|
||||
uint64_t Prologue = DebugStart->getVirtualAddress() - FuncStart;
|
||||
WithColor(Printer, PDB_ColorItem::Offset).get() << "+" << Prologue;
|
||||
}
|
||||
Printer << " - ";
|
||||
WithColor(Printer, PDB_ColorItem::Address).get() << format_hex(FuncEnd, 10);
|
||||
if (auto DebugEnd = Symbol.findOneChild<PDBSymbolFuncDebugEnd>()) {
|
||||
uint64_t Epilogue = FuncEnd - DebugEnd->getVirtualAddress();
|
||||
WithColor(Printer, PDB_ColorItem::Offset).get() << "-" << Epilogue;
|
||||
}
|
||||
Printer << "] (";
|
||||
|
||||
if (Symbol.hasFramePointer()) {
|
||||
WithColor(Printer, PDB_ColorItem::Register).get()
|
||||
<< Symbol.getLocalBasePointerRegisterId();
|
||||
} else {
|
||||
WithColor(Printer, PDB_ColorItem::Register).get() << "FPO";
|
||||
}
|
||||
Printer << ") ";
|
||||
|
||||
if (Symbol.isVirtual() || Symbol.isPureVirtual())
|
||||
WithColor(Printer, PDB_ColorItem::Keyword).get() << "virtual ";
|
||||
|
||||
auto Signature = Symbol.getSignature();
|
||||
if (!Signature) {
|
||||
WithColor(Printer, PDB_ColorItem::Identifier).get() << Symbol.getName();
|
||||
if (Pointer == PointerType::Pointer)
|
||||
Printer << "*";
|
||||
else if (Pointer == FunctionDumper::PointerType::Reference)
|
||||
Printer << "&";
|
||||
return;
|
||||
}
|
||||
|
||||
auto ReturnType = Signature->getReturnType();
|
||||
ReturnType->dump(*this);
|
||||
Printer << " ";
|
||||
|
||||
auto ClassParent = Symbol.getClassParent();
|
||||
CallingConvention CC = Signature->getCallingConvention();
|
||||
if (Pointer != FunctionDumper::PointerType::None)
|
||||
Printer << "(";
|
||||
|
||||
if ((ClassParent && CC != CallingConvention::ThisCall) ||
|
||||
(!ClassParent && CC != CallingConvention::NearStdCall)) {
|
||||
WithColor(Printer, PDB_ColorItem::Keyword).get()
|
||||
<< Signature->getCallingConvention() << " ";
|
||||
}
|
||||
WithColor(Printer, PDB_ColorItem::Identifier).get() << Symbol.getName();
|
||||
if (Pointer != FunctionDumper::PointerType::None) {
|
||||
if (Pointer == PointerType::Pointer)
|
||||
Printer << "*";
|
||||
else if (Pointer == FunctionDumper::PointerType::Reference)
|
||||
Printer << "&";
|
||||
Printer << ")";
|
||||
}
|
||||
|
||||
Printer << "(";
|
||||
if (auto Arguments = Symbol.getArguments()) {
|
||||
uint32_t Index = 0;
|
||||
while (auto Arg = Arguments->getNext()) {
|
||||
auto ArgType = Arg->getType();
|
||||
ArgType->dump(*this);
|
||||
WithColor(Printer, PDB_ColorItem::Identifier).get() << " "
|
||||
<< Arg->getName();
|
||||
if (++Index < Arguments->getChildCount())
|
||||
Printer << ", ";
|
||||
}
|
||||
}
|
||||
Printer << ")";
|
||||
if (Symbol.isConstType())
|
||||
WithColor(Printer, PDB_ColorItem::Keyword).get() << " const";
|
||||
if (Symbol.isVolatileType())
|
||||
WithColor(Printer, PDB_ColorItem::Keyword).get() << " volatile";
|
||||
if (Symbol.isPureVirtual())
|
||||
Printer << " = 0";
|
||||
}
|
||||
|
||||
void FunctionDumper::dump(const PDBSymbolTypeArray &Symbol) {
|
||||
uint32_t ElementTypeId = Symbol.getTypeId();
|
||||
auto ElementType = Symbol.getSession().getSymbolById(ElementTypeId);
|
||||
if (!ElementType)
|
||||
return;
|
||||
|
||||
ElementType->dump(*this);
|
||||
Printer << "[";
|
||||
WithColor(Printer, PDB_ColorItem::LiteralValue).get() << Symbol.getLength();
|
||||
Printer << "]";
|
||||
}
|
||||
|
||||
void FunctionDumper::dump(const PDBSymbolTypeBuiltin &Symbol) {
|
||||
BuiltinDumper Dumper(Printer);
|
||||
Dumper.start(Symbol);
|
||||
}
|
||||
|
||||
void FunctionDumper::dump(const PDBSymbolTypeEnum &Symbol) {
|
||||
dumpClassParentWithScopeOperator(Symbol, Printer, *this);
|
||||
WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName();
|
||||
}
|
||||
|
||||
void FunctionDumper::dump(const PDBSymbolTypeFunctionArg &Symbol) {
|
||||
// PDBSymbolTypeFunctionArg is just a shim over the real argument. Just drill
|
||||
// through to the real thing and dump it.
|
||||
uint32_t TypeId = Symbol.getTypeId();
|
||||
auto Type = Symbol.getSession().getSymbolById(TypeId);
|
||||
if (!Type)
|
||||
return;
|
||||
Type->dump(*this);
|
||||
}
|
||||
|
||||
void FunctionDumper::dump(const PDBSymbolTypeTypedef &Symbol) {
|
||||
dumpClassParentWithScopeOperator(Symbol, Printer, *this);
|
||||
WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName();
|
||||
}
|
||||
|
||||
void FunctionDumper::dump(const PDBSymbolTypePointer &Symbol) {
|
||||
uint32_t PointeeId = Symbol.getTypeId();
|
||||
auto PointeeType = Symbol.getSession().getSymbolById(PointeeId);
|
||||
if (!PointeeType)
|
||||
return;
|
||||
|
||||
if (auto FuncSig = dyn_cast<PDBSymbolTypeFunctionSig>(PointeeType.get())) {
|
||||
FunctionDumper NestedDumper(Printer);
|
||||
PointerType Pointer =
|
||||
Symbol.isReference() ? PointerType::Reference : PointerType::Pointer;
|
||||
NestedDumper.start(*FuncSig, nullptr, Pointer);
|
||||
} else {
|
||||
if (Symbol.isConstType())
|
||||
WithColor(Printer, PDB_ColorItem::Keyword).get() << "const ";
|
||||
if (Symbol.isVolatileType())
|
||||
WithColor(Printer, PDB_ColorItem::Keyword).get() << "volatile ";
|
||||
PointeeType->dump(*this);
|
||||
Printer << (Symbol.isReference() ? "&" : "*");
|
||||
}
|
||||
}
|
||||
|
||||
void FunctionDumper::dump(const PDBSymbolTypeUDT &Symbol) {
|
||||
WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName();
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
//===- FunctionDumper.h --------------------------------------- *- C++ --*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_TOOLS_LLVMPDBDUMP_FUNCTIONDUMPER_H
|
||||
#define LLVM_TOOLS_LLVMPDBDUMP_FUNCTIONDUMPER_H
|
||||
|
||||
#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace pdb {
|
||||
class LinePrinter;
|
||||
|
||||
class FunctionDumper : public PDBSymDumper {
|
||||
public:
|
||||
FunctionDumper(LinePrinter &P);
|
||||
|
||||
enum class PointerType { None, Pointer, Reference };
|
||||
|
||||
void start(const PDBSymbolTypeFunctionSig &Symbol, const char *Name,
|
||||
PointerType Pointer);
|
||||
void start(const PDBSymbolFunc &Symbol, PointerType Pointer);
|
||||
|
||||
void dump(const PDBSymbolTypeArray &Symbol) override;
|
||||
void dump(const PDBSymbolTypeBuiltin &Symbol) override;
|
||||
void dump(const PDBSymbolTypeEnum &Symbol) override;
|
||||
void dump(const PDBSymbolTypeFunctionArg &Symbol) override;
|
||||
void dump(const PDBSymbolTypePointer &Symbol) override;
|
||||
void dump(const PDBSymbolTypeTypedef &Symbol) override;
|
||||
void dump(const PDBSymbolTypeUDT &Symbol) override;
|
||||
|
||||
private:
|
||||
LinePrinter &Printer;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,98 +0,0 @@
|
|||
//===- TypeDumper.cpp - PDBSymDumper implementation for types *----- C++ *-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "TypeDumper.h"
|
||||
|
||||
#include "BuiltinDumper.h"
|
||||
#include "ClassDefinitionDumper.h"
|
||||
#include "EnumDumper.h"
|
||||
#include "LinePrinter.h"
|
||||
#include "llvm-pdbdump.h"
|
||||
#include "TypedefDumper.h"
|
||||
|
||||
#include "llvm/DebugInfo/PDB/IPDBSession.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolExe.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::pdb;
|
||||
|
||||
TypeDumper::TypeDumper(LinePrinter &P) : PDBSymDumper(true), Printer(P) {}
|
||||
|
||||
void TypeDumper::start(const PDBSymbolExe &Exe) {
|
||||
auto Enums = Exe.findAllChildren<PDBSymbolTypeEnum>();
|
||||
Printer.NewLine();
|
||||
WithColor(Printer, PDB_ColorItem::Identifier).get() << "Enums";
|
||||
Printer << ": (" << Enums->getChildCount() << " items)";
|
||||
Printer.Indent();
|
||||
while (auto Enum = Enums->getNext())
|
||||
Enum->dump(*this);
|
||||
Printer.Unindent();
|
||||
|
||||
auto Typedefs = Exe.findAllChildren<PDBSymbolTypeTypedef>();
|
||||
Printer.NewLine();
|
||||
WithColor(Printer, PDB_ColorItem::Identifier).get() << "Typedefs";
|
||||
Printer << ": (" << Typedefs->getChildCount() << " items)";
|
||||
Printer.Indent();
|
||||
while (auto Typedef = Typedefs->getNext())
|
||||
Typedef->dump(*this);
|
||||
Printer.Unindent();
|
||||
|
||||
auto Classes = Exe.findAllChildren<PDBSymbolTypeUDT>();
|
||||
Printer.NewLine();
|
||||
WithColor(Printer, PDB_ColorItem::Identifier).get() << "Classes";
|
||||
Printer << ": (" << Classes->getChildCount() << " items)";
|
||||
Printer.Indent();
|
||||
while (auto Class = Classes->getNext())
|
||||
Class->dump(*this);
|
||||
Printer.Unindent();
|
||||
}
|
||||
|
||||
void TypeDumper::dump(const PDBSymbolTypeEnum &Symbol) {
|
||||
if (Symbol.getUnmodifiedTypeId() != 0)
|
||||
return;
|
||||
if (Printer.IsTypeExcluded(Symbol.getName()))
|
||||
return;
|
||||
// Dump member enums when dumping their class definition.
|
||||
if (nullptr != Symbol.getClassParent())
|
||||
return;
|
||||
|
||||
Printer.NewLine();
|
||||
EnumDumper Dumper(Printer);
|
||||
Dumper.start(Symbol);
|
||||
}
|
||||
|
||||
void TypeDumper::dump(const PDBSymbolTypeTypedef &Symbol) {
|
||||
if (Printer.IsTypeExcluded(Symbol.getName()))
|
||||
return;
|
||||
|
||||
Printer.NewLine();
|
||||
TypedefDumper Dumper(Printer);
|
||||
Dumper.start(Symbol);
|
||||
}
|
||||
|
||||
void TypeDumper::dump(const PDBSymbolTypeUDT &Symbol) {
|
||||
if (Symbol.getUnmodifiedTypeId() != 0)
|
||||
return;
|
||||
if (Printer.IsTypeExcluded(Symbol.getName()))
|
||||
return;
|
||||
|
||||
Printer.NewLine();
|
||||
|
||||
if (opts::pretty::NoClassDefs) {
|
||||
WithColor(Printer, PDB_ColorItem::Keyword).get() << "class ";
|
||||
WithColor(Printer, PDB_ColorItem::Identifier).get() << Symbol.getName();
|
||||
} else {
|
||||
ClassDefinitionDumper Dumper(Printer);
|
||||
Dumper.start(Symbol);
|
||||
}
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
//===- TypeDumper.h - PDBSymDumper implementation for types *- C++ ------*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_TOOLS_LLVMPDBDUMP_TYPEDUMPER_H
|
||||
#define LLVM_TOOLS_LLVMPDBDUMP_TYPEDUMPER_H
|
||||
|
||||
#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace pdb {
|
||||
class LinePrinter;
|
||||
|
||||
class TypeDumper : public PDBSymDumper {
|
||||
public:
|
||||
TypeDumper(LinePrinter &P);
|
||||
|
||||
void start(const PDBSymbolExe &Exe);
|
||||
|
||||
void dump(const PDBSymbolTypeEnum &Symbol) override;
|
||||
void dump(const PDBSymbolTypeTypedef &Symbol) override;
|
||||
void dump(const PDBSymbolTypeUDT &Symbol) override;
|
||||
|
||||
private:
|
||||
LinePrinter &Printer;
|
||||
};
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -1,80 +0,0 @@
|
|||
//===- TypedefDumper.cpp - PDBSymDumper impl for typedefs -------- * C++ *-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "TypedefDumper.h"
|
||||
|
||||
#include "BuiltinDumper.h"
|
||||
#include "FunctionDumper.h"
|
||||
#include "LinePrinter.h"
|
||||
#include "llvm-pdbdump.h"
|
||||
|
||||
#include "llvm/DebugInfo/PDB/IPDBSession.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBExtras.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::pdb;
|
||||
|
||||
TypedefDumper::TypedefDumper(LinePrinter &P) : PDBSymDumper(true), Printer(P) {}
|
||||
|
||||
void TypedefDumper::start(const PDBSymbolTypeTypedef &Symbol) {
|
||||
WithColor(Printer, PDB_ColorItem::Keyword).get() << "typedef ";
|
||||
uint32_t TargetId = Symbol.getTypeId();
|
||||
if (auto TypeSymbol = Symbol.getSession().getSymbolById(TargetId))
|
||||
TypeSymbol->dump(*this);
|
||||
WithColor(Printer, PDB_ColorItem::Identifier).get() << " "
|
||||
<< Symbol.getName();
|
||||
}
|
||||
|
||||
void TypedefDumper::dump(const PDBSymbolTypeArray &Symbol) {}
|
||||
|
||||
void TypedefDumper::dump(const PDBSymbolTypeBuiltin &Symbol) {
|
||||
BuiltinDumper Dumper(Printer);
|
||||
Dumper.start(Symbol);
|
||||
}
|
||||
|
||||
void TypedefDumper::dump(const PDBSymbolTypeEnum &Symbol) {
|
||||
WithColor(Printer, PDB_ColorItem::Keyword).get() << "enum ";
|
||||
WithColor(Printer, PDB_ColorItem::Type).get() << " " << Symbol.getName();
|
||||
}
|
||||
|
||||
void TypedefDumper::dump(const PDBSymbolTypePointer &Symbol) {
|
||||
if (Symbol.isConstType())
|
||||
WithColor(Printer, PDB_ColorItem::Keyword).get() << "const ";
|
||||
if (Symbol.isVolatileType())
|
||||
WithColor(Printer, PDB_ColorItem::Keyword).get() << "volatile ";
|
||||
uint32_t PointeeId = Symbol.getTypeId();
|
||||
auto PointeeType = Symbol.getSession().getSymbolById(PointeeId);
|
||||
if (!PointeeType)
|
||||
return;
|
||||
if (auto FuncSig = dyn_cast<PDBSymbolTypeFunctionSig>(PointeeType.get())) {
|
||||
FunctionDumper::PointerType Pointer = FunctionDumper::PointerType::Pointer;
|
||||
if (Symbol.isReference())
|
||||
Pointer = FunctionDumper::PointerType::Reference;
|
||||
FunctionDumper NestedDumper(Printer);
|
||||
NestedDumper.start(*FuncSig, nullptr, Pointer);
|
||||
} else {
|
||||
PointeeType->dump(*this);
|
||||
Printer << ((Symbol.isReference()) ? "&" : "*");
|
||||
}
|
||||
}
|
||||
|
||||
void TypedefDumper::dump(const PDBSymbolTypeFunctionSig &Symbol) {
|
||||
FunctionDumper Dumper(Printer);
|
||||
Dumper.start(Symbol, nullptr, FunctionDumper::PointerType::None);
|
||||
}
|
||||
|
||||
void TypedefDumper::dump(const PDBSymbolTypeUDT &Symbol) {
|
||||
WithColor(Printer, PDB_ColorItem::Keyword).get() << "class ";
|
||||
WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName();
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
//===- TypedefDumper.h - llvm-pdbdump typedef dumper ---------*- C++ ----*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_TOOLS_LLVMPDBDUMP_TYPEDEFDUMPER_H
|
||||
#define LLVM_TOOLS_LLVMPDBDUMP_TYPEDEFDUMPER_H
|
||||
|
||||
#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace pdb {
|
||||
|
||||
class LinePrinter;
|
||||
|
||||
class TypedefDumper : public PDBSymDumper {
|
||||
public:
|
||||
TypedefDumper(LinePrinter &P);
|
||||
|
||||
void start(const PDBSymbolTypeTypedef &Symbol);
|
||||
|
||||
void dump(const PDBSymbolTypeArray &Symbol) override;
|
||||
void dump(const PDBSymbolTypeBuiltin &Symbol) override;
|
||||
void dump(const PDBSymbolTypeEnum &Symbol) override;
|
||||
void dump(const PDBSymbolTypeFunctionSig &Symbol) override;
|
||||
void dump(const PDBSymbolTypePointer &Symbol) override;
|
||||
void dump(const PDBSymbolTypeUDT &Symbol) override;
|
||||
|
||||
private:
|
||||
LinePrinter &Printer;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,171 +0,0 @@
|
|||
//===- VariableDumper.cpp - -------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "VariableDumper.h"
|
||||
|
||||
#include "BuiltinDumper.h"
|
||||
#include "LinePrinter.h"
|
||||
#include "llvm-pdbdump.h"
|
||||
#include "FunctionDumper.h"
|
||||
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolTypeArray.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
|
||||
|
||||
#include "llvm/Support/Format.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::pdb;
|
||||
|
||||
VariableDumper::VariableDumper(LinePrinter &P)
|
||||
: PDBSymDumper(true), Printer(P) {}
|
||||
|
||||
void VariableDumper::start(const PDBSymbolData &Var) {
|
||||
if (Var.isCompilerGenerated() && opts::pretty::ExcludeCompilerGenerated)
|
||||
return;
|
||||
if (Printer.IsSymbolExcluded(Var.getName()))
|
||||
return;
|
||||
|
||||
auto VarType = Var.getType();
|
||||
|
||||
switch (auto LocType = Var.getLocationType()) {
|
||||
case PDB_LocType::Static:
|
||||
Printer.NewLine();
|
||||
Printer << "data [";
|
||||
WithColor(Printer, PDB_ColorItem::Address).get()
|
||||
<< format_hex(Var.getVirtualAddress(), 10);
|
||||
Printer << "] ";
|
||||
WithColor(Printer, PDB_ColorItem::Keyword).get() << "static ";
|
||||
dumpSymbolTypeAndName(*VarType, Var.getName());
|
||||
break;
|
||||
case PDB_LocType::Constant:
|
||||
if (isa<PDBSymbolTypeEnum>(*VarType))
|
||||
break;
|
||||
Printer.NewLine();
|
||||
Printer << "data ";
|
||||
WithColor(Printer, PDB_ColorItem::Keyword).get() << "const ";
|
||||
dumpSymbolTypeAndName(*VarType, Var.getName());
|
||||
Printer << " = ";
|
||||
WithColor(Printer, PDB_ColorItem::LiteralValue).get() << Var.getValue();
|
||||
break;
|
||||
case PDB_LocType::ThisRel:
|
||||
Printer.NewLine();
|
||||
Printer << "data ";
|
||||
WithColor(Printer, PDB_ColorItem::Offset).get()
|
||||
<< "+" << format_hex(Var.getOffset(), 4) << " ";
|
||||
dumpSymbolTypeAndName(*VarType, Var.getName());
|
||||
break;
|
||||
case PDB_LocType::BitField:
|
||||
Printer.NewLine();
|
||||
Printer << "data ";
|
||||
WithColor(Printer, PDB_ColorItem::Offset).get()
|
||||
<< "+" << format_hex(Var.getOffset(), 4) << " ";
|
||||
dumpSymbolTypeAndName(*VarType, Var.getName());
|
||||
Printer << " : ";
|
||||
WithColor(Printer, PDB_ColorItem::LiteralValue).get() << Var.getLength();
|
||||
break;
|
||||
default:
|
||||
Printer.NewLine();
|
||||
Printer << "data ";
|
||||
Printer << "unknown(" << LocType << ") ";
|
||||
WithColor(Printer, PDB_ColorItem::Identifier).get() << Var.getName();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void VariableDumper::dump(const PDBSymbolTypeBuiltin &Symbol) {
|
||||
BuiltinDumper Dumper(Printer);
|
||||
Dumper.start(Symbol);
|
||||
}
|
||||
|
||||
void VariableDumper::dump(const PDBSymbolTypeEnum &Symbol) {
|
||||
WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName();
|
||||
}
|
||||
|
||||
void VariableDumper::dump(const PDBSymbolTypeFunctionSig &Symbol) {}
|
||||
|
||||
void VariableDumper::dump(const PDBSymbolTypePointer &Symbol) {
|
||||
auto PointeeType = Symbol.getPointeeType();
|
||||
if (!PointeeType)
|
||||
return;
|
||||
|
||||
if (auto Func = dyn_cast<PDBSymbolFunc>(PointeeType.get())) {
|
||||
FunctionDumper NestedDumper(Printer);
|
||||
FunctionDumper::PointerType Pointer =
|
||||
Symbol.isReference() ? FunctionDumper::PointerType::Reference
|
||||
: FunctionDumper::PointerType::Pointer;
|
||||
NestedDumper.start(*Func, Pointer);
|
||||
} else {
|
||||
if (Symbol.isConstType())
|
||||
WithColor(Printer, PDB_ColorItem::Keyword).get() << "const ";
|
||||
if (Symbol.isVolatileType())
|
||||
WithColor(Printer, PDB_ColorItem::Keyword).get() << "volatile ";
|
||||
PointeeType->dump(*this);
|
||||
Printer << (Symbol.isReference() ? "&" : "*");
|
||||
}
|
||||
}
|
||||
|
||||
void VariableDumper::dump(const PDBSymbolTypeTypedef &Symbol) {
|
||||
WithColor(Printer, PDB_ColorItem::Keyword).get() << "typedef ";
|
||||
WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName();
|
||||
}
|
||||
|
||||
void VariableDumper::dump(const PDBSymbolTypeUDT &Symbol) {
|
||||
WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName();
|
||||
}
|
||||
|
||||
void VariableDumper::dumpSymbolTypeAndName(const PDBSymbol &Type,
|
||||
StringRef Name) {
|
||||
if (auto *ArrayType = dyn_cast<PDBSymbolTypeArray>(&Type)) {
|
||||
std::string IndexSpec;
|
||||
raw_string_ostream IndexStream(IndexSpec);
|
||||
std::unique_ptr<PDBSymbol> ElementType = ArrayType->getElementType();
|
||||
while (auto NestedArray = dyn_cast<PDBSymbolTypeArray>(ElementType.get())) {
|
||||
IndexStream << "[";
|
||||
IndexStream << NestedArray->getCount();
|
||||
IndexStream << "]";
|
||||
ElementType = NestedArray->getElementType();
|
||||
}
|
||||
IndexStream << "[" << ArrayType->getCount() << "]";
|
||||
ElementType->dump(*this);
|
||||
WithColor(Printer, PDB_ColorItem::Identifier).get() << " " << Name;
|
||||
Printer << IndexStream.str();
|
||||
} else {
|
||||
if (!tryDumpFunctionPointer(Type, Name)) {
|
||||
Type.dump(*this);
|
||||
WithColor(Printer, PDB_ColorItem::Identifier).get() << " " << Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool VariableDumper::tryDumpFunctionPointer(const PDBSymbol &Type,
|
||||
StringRef Name) {
|
||||
// Function pointers come across as pointers to function signatures. But the
|
||||
// signature carries no name, so we have to handle this case separately.
|
||||
if (auto *PointerType = dyn_cast<PDBSymbolTypePointer>(&Type)) {
|
||||
auto PointeeType = PointerType->getPointeeType();
|
||||
if (auto *FunctionSig =
|
||||
dyn_cast<PDBSymbolTypeFunctionSig>(PointeeType.get())) {
|
||||
FunctionDumper Dumper(Printer);
|
||||
FunctionDumper::PointerType PT = FunctionDumper::PointerType::Pointer;
|
||||
if (PointerType->isReference())
|
||||
PT = FunctionDumper::PointerType::Reference;
|
||||
std::string NameStr(Name.begin(), Name.end());
|
||||
Dumper.start(*FunctionSig, NameStr.c_str(), PT);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
//===- VariableDumper.h - PDBSymDumper implementation for types -*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_TOOLS_LLVMPDBDUMP_VARIABLEDUMPER_H
|
||||
#define LLVM_TOOLS_LLVMPDBDUMP_VARIABLEDUMPER_H
|
||||
|
||||
#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class StringRef;
|
||||
|
||||
namespace pdb {
|
||||
|
||||
class LinePrinter;
|
||||
|
||||
class VariableDumper : public PDBSymDumper {
|
||||
public:
|
||||
VariableDumper(LinePrinter &P);
|
||||
|
||||
void start(const PDBSymbolData &Var);
|
||||
|
||||
void dump(const PDBSymbolTypeBuiltin &Symbol) override;
|
||||
void dump(const PDBSymbolTypeEnum &Symbol) override;
|
||||
void dump(const PDBSymbolTypeFunctionSig &Symbol) override;
|
||||
void dump(const PDBSymbolTypePointer &Symbol) override;
|
||||
void dump(const PDBSymbolTypeTypedef &Symbol) override;
|
||||
void dump(const PDBSymbolTypeUDT &Symbol) override;
|
||||
|
||||
private:
|
||||
void dumpSymbolTypeAndName(const PDBSymbol &Type, StringRef Name);
|
||||
bool tryDumpFunctionPointer(const PDBSymbol &Type, StringRef Name);
|
||||
|
||||
LinePrinter &Printer;
|
||||
};
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -1,209 +0,0 @@
|
|||
//===- llvm/unittest/Analysis/LoopPassManagerTest.cpp - LPM tests ---------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Analysis/AliasAnalysis.h"
|
||||
#include "llvm/Analysis/AssumptionCache.h"
|
||||
#include "llvm/Analysis/LoopPassManager.h"
|
||||
#include "llvm/Analysis/ScalarEvolution.h"
|
||||
#include "llvm/Analysis/TargetLibraryInfo.h"
|
||||
#include "llvm/AsmParser/Parser.h"
|
||||
#include "llvm/IR/Dominators.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/IR/LLVMContext.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
#include "llvm/Support/SourceMgr.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
|
||||
class TestLoopAnalysis : public AnalysisInfoMixin<TestLoopAnalysis> {
|
||||
friend AnalysisInfoMixin<TestLoopAnalysis>;
|
||||
static AnalysisKey Key;
|
||||
|
||||
int &Runs;
|
||||
|
||||
public:
|
||||
struct Result {
|
||||
Result(int Count) : BlockCount(Count) {}
|
||||
int BlockCount;
|
||||
};
|
||||
|
||||
TestLoopAnalysis(int &Runs) : Runs(Runs) {}
|
||||
|
||||
/// \brief Run the analysis pass over the loop and return a result.
|
||||
Result run(Loop &L, LoopAnalysisManager &AM) {
|
||||
++Runs;
|
||||
int Count = 0;
|
||||
|
||||
for (auto I = L.block_begin(), E = L.block_end(); I != E; ++I)
|
||||
++Count;
|
||||
return Result(Count);
|
||||
}
|
||||
};
|
||||
|
||||
AnalysisKey TestLoopAnalysis::Key;
|
||||
|
||||
class TestLoopPass {
|
||||
std::vector<StringRef> &VisitedLoops;
|
||||
int &AnalyzedBlockCount;
|
||||
bool OnlyUseCachedResults;
|
||||
|
||||
public:
|
||||
TestLoopPass(std::vector<StringRef> &VisitedLoops, int &AnalyzedBlockCount,
|
||||
bool OnlyUseCachedResults = false)
|
||||
: VisitedLoops(VisitedLoops), AnalyzedBlockCount(AnalyzedBlockCount),
|
||||
OnlyUseCachedResults(OnlyUseCachedResults) {}
|
||||
|
||||
PreservedAnalyses run(Loop &L, LoopAnalysisManager &AM) {
|
||||
VisitedLoops.push_back(L.getName());
|
||||
|
||||
if (OnlyUseCachedResults) {
|
||||
// Hack to force the use of the cached interface.
|
||||
if (auto *AR = AM.getCachedResult<TestLoopAnalysis>(L))
|
||||
AnalyzedBlockCount += AR->BlockCount;
|
||||
} else {
|
||||
// Typical path just runs the analysis as needed.
|
||||
auto &AR = AM.getResult<TestLoopAnalysis>(L);
|
||||
AnalyzedBlockCount += AR.BlockCount;
|
||||
}
|
||||
|
||||
return PreservedAnalyses::all();
|
||||
}
|
||||
|
||||
static StringRef name() { return "TestLoopPass"; }
|
||||
};
|
||||
|
||||
// A test loop pass that invalidates the analysis for loops with the given name.
|
||||
class TestLoopInvalidatingPass {
|
||||
StringRef Name;
|
||||
|
||||
public:
|
||||
TestLoopInvalidatingPass(StringRef LoopName) : Name(LoopName) {}
|
||||
|
||||
PreservedAnalyses run(Loop &L, LoopAnalysisManager &AM) {
|
||||
return L.getName() == Name ? getLoopPassPreservedAnalyses()
|
||||
: PreservedAnalyses::all();
|
||||
}
|
||||
|
||||
static StringRef name() { return "TestLoopInvalidatingPass"; }
|
||||
};
|
||||
|
||||
std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) {
|
||||
SMDiagnostic Err;
|
||||
return parseAssemblyString(IR, Err, C);
|
||||
}
|
||||
|
||||
class LoopPassManagerTest : public ::testing::Test {
|
||||
protected:
|
||||
LLVMContext Context;
|
||||
std::unique_ptr<Module> M;
|
||||
|
||||
public:
|
||||
LoopPassManagerTest()
|
||||
: M(parseIR(Context, "define void @f() {\n"
|
||||
"entry:\n"
|
||||
" br label %loop.0\n"
|
||||
"loop.0:\n"
|
||||
" br i1 undef, label %loop.0.0, label %end\n"
|
||||
"loop.0.0:\n"
|
||||
" br i1 undef, label %loop.0.0, label %loop.0.1\n"
|
||||
"loop.0.1:\n"
|
||||
" br i1 undef, label %loop.0.1, label %loop.0\n"
|
||||
"end:\n"
|
||||
" ret void\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"define void @g() {\n"
|
||||
"entry:\n"
|
||||
" br label %loop.g.0\n"
|
||||
"loop.g.0:\n"
|
||||
" br i1 undef, label %loop.g.0, label %end\n"
|
||||
"end:\n"
|
||||
" ret void\n"
|
||||
"}\n")) {}
|
||||
};
|
||||
|
||||
#define EXPECT_N_ELEMENTS_EQ(N, EXPECTED, ACTUAL) \
|
||||
do { \
|
||||
EXPECT_EQ(N##UL, ACTUAL.size()); \
|
||||
for (int I = 0; I < N; ++I) \
|
||||
EXPECT_TRUE(EXPECTED[I] == ACTUAL[I]) << "Element " << I << " is " \
|
||||
<< ACTUAL[I] << ". Expected " \
|
||||
<< EXPECTED[I] << "."; \
|
||||
} while (0)
|
||||
|
||||
TEST_F(LoopPassManagerTest, Basic) {
|
||||
LoopAnalysisManager LAM(true);
|
||||
int LoopAnalysisRuns = 0;
|
||||
LAM.registerPass([&] { return TestLoopAnalysis(LoopAnalysisRuns); });
|
||||
|
||||
FunctionAnalysisManager FAM(true);
|
||||
// We need DominatorTreeAnalysis for LoopAnalysis.
|
||||
FAM.registerPass([&] { return DominatorTreeAnalysis(); });
|
||||
FAM.registerPass([&] { return LoopAnalysis(); });
|
||||
// We also allow loop passes to assume a set of other analyses and so need
|
||||
// those.
|
||||
FAM.registerPass([&] { return AAManager(); });
|
||||
FAM.registerPass([&] { return TargetLibraryAnalysis(); });
|
||||
FAM.registerPass([&] { return ScalarEvolutionAnalysis(); });
|
||||
FAM.registerPass([&] { return AssumptionAnalysis(); });
|
||||
FAM.registerPass([&] { return LoopAnalysisManagerFunctionProxy(LAM); });
|
||||
LAM.registerPass([&] { return FunctionAnalysisManagerLoopProxy(FAM); });
|
||||
|
||||
ModuleAnalysisManager MAM(true);
|
||||
MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); });
|
||||
FAM.registerPass([&] { return ModuleAnalysisManagerFunctionProxy(MAM); });
|
||||
|
||||
ModulePassManager MPM(true);
|
||||
FunctionPassManager FPM(true);
|
||||
|
||||
// Visit all of the loops.
|
||||
std::vector<StringRef> VisitedLoops1;
|
||||
int AnalyzedBlockCount1 = 0;
|
||||
{
|
||||
LoopPassManager LPM;
|
||||
LPM.addPass(TestLoopPass(VisitedLoops1, AnalyzedBlockCount1));
|
||||
|
||||
FPM.addPass(createFunctionToLoopPassAdaptor(std::move(LPM)));
|
||||
}
|
||||
|
||||
// Only use cached analyses.
|
||||
std::vector<StringRef> VisitedLoops2;
|
||||
int AnalyzedBlockCount2 = 0;
|
||||
{
|
||||
LoopPassManager LPM;
|
||||
LPM.addPass(TestLoopInvalidatingPass("loop.g.0"));
|
||||
LPM.addPass(TestLoopPass(VisitedLoops2, AnalyzedBlockCount2,
|
||||
/*OnlyUseCachedResults=*/true));
|
||||
|
||||
FPM.addPass(createFunctionToLoopPassAdaptor(std::move(LPM)));
|
||||
}
|
||||
|
||||
MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
|
||||
MPM.run(*M, MAM);
|
||||
|
||||
StringRef ExpectedLoops[] = {"loop.0.0", "loop.0.1", "loop.0", "loop.g.0"};
|
||||
|
||||
// Validate the counters and order of loops visited.
|
||||
// loop.0 has 3 blocks whereas loop.0.0, loop.0.1, and loop.g.0 each have 1.
|
||||
EXPECT_N_ELEMENTS_EQ(4, ExpectedLoops, VisitedLoops1);
|
||||
EXPECT_EQ(6, AnalyzedBlockCount1);
|
||||
|
||||
EXPECT_N_ELEMENTS_EQ(4, ExpectedLoops, VisitedLoops2);
|
||||
// The block from loop.g.0 won't be counted, since it wasn't cached.
|
||||
EXPECT_EQ(5, AnalyzedBlockCount2);
|
||||
|
||||
// The first LPM runs the loop analysis for all four loops, the second uses
|
||||
// cached results for everything.
|
||||
EXPECT_EQ(4, LoopAnalysisRuns);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue