mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-02-14 01:20:40 +00:00
[llvm-exegesis][NFC] Remove extra llvm::
qualifications.
Summary: Second patch: in the lib. Reviewers: gchatelet Subscribers: nemanjai, tschuett, MaskRay, mgrang, jsji, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D68692 llvm-svn: 374158
This commit is contained in:
parent
99479f2b1a
commit
de4e3c1cf7
@ -16,19 +16,19 @@ namespace exegesis {
|
||||
static unsigned getLoadImmediateOpcode(unsigned RegBitWidth) {
|
||||
switch (RegBitWidth) {
|
||||
case 32:
|
||||
return llvm::AArch64::MOVi32imm;
|
||||
return AArch64::MOVi32imm;
|
||||
case 64:
|
||||
return llvm::AArch64::MOVi64imm;
|
||||
return AArch64::MOVi64imm;
|
||||
}
|
||||
llvm_unreachable("Invalid Value Width");
|
||||
}
|
||||
|
||||
// Generates instruction to load an immediate value into a register.
|
||||
static llvm::MCInst loadImmediate(unsigned Reg, unsigned RegBitWidth,
|
||||
const llvm::APInt &Value) {
|
||||
static MCInst loadImmediate(unsigned Reg, unsigned RegBitWidth,
|
||||
const APInt &Value) {
|
||||
if (Value.getBitWidth() > RegBitWidth)
|
||||
llvm_unreachable("Value must fit in the Register");
|
||||
return llvm::MCInstBuilder(getLoadImmediateOpcode(RegBitWidth))
|
||||
return MCInstBuilder(getLoadImmediateOpcode(RegBitWidth))
|
||||
.addReg(Reg)
|
||||
.addImm(Value.getZExtValue());
|
||||
}
|
||||
@ -42,24 +42,23 @@ public:
|
||||
ExegesisAArch64Target() : ExegesisTarget(AArch64CpuPfmCounters) {}
|
||||
|
||||
private:
|
||||
std::vector<llvm::MCInst> setRegTo(const llvm::MCSubtargetInfo &STI,
|
||||
unsigned Reg,
|
||||
const llvm::APInt &Value) const override {
|
||||
if (llvm::AArch64::GPR32RegClass.contains(Reg))
|
||||
std::vector<MCInst> setRegTo(const MCSubtargetInfo &STI, unsigned Reg,
|
||||
const APInt &Value) const override {
|
||||
if (AArch64::GPR32RegClass.contains(Reg))
|
||||
return {loadImmediate(Reg, 32, Value)};
|
||||
if (llvm::AArch64::GPR64RegClass.contains(Reg))
|
||||
if (AArch64::GPR64RegClass.contains(Reg))
|
||||
return {loadImmediate(Reg, 64, Value)};
|
||||
llvm::errs() << "setRegTo is not implemented, results will be unreliable\n";
|
||||
errs() << "setRegTo is not implemented, results will be unreliable\n";
|
||||
return {};
|
||||
}
|
||||
|
||||
bool matchesArch(llvm::Triple::ArchType Arch) const override {
|
||||
return Arch == llvm::Triple::aarch64 || Arch == llvm::Triple::aarch64_be;
|
||||
bool matchesArch(Triple::ArchType Arch) const override {
|
||||
return Arch == Triple::aarch64 || Arch == Triple::aarch64_be;
|
||||
}
|
||||
|
||||
void addTargetSpecificPasses(llvm::PassManagerBase &PM) const override {
|
||||
void addTargetSpecificPasses(PassManagerBase &PM) const override {
|
||||
// Function return is a pseudo-instruction that needs to be expanded
|
||||
PM.add(llvm::createAArch64ExpandPseudoPass());
|
||||
PM.add(createAArch64ExpandPseudoPass());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -24,11 +24,9 @@ namespace {
|
||||
|
||||
enum EscapeTag { kEscapeCsv, kEscapeHtml, kEscapeHtmlString };
|
||||
|
||||
template <EscapeTag Tag>
|
||||
void writeEscaped(llvm::raw_ostream &OS, const llvm::StringRef S);
|
||||
template <EscapeTag Tag> void writeEscaped(raw_ostream &OS, const StringRef S);
|
||||
|
||||
template <>
|
||||
void writeEscaped<kEscapeCsv>(llvm::raw_ostream &OS, const llvm::StringRef S) {
|
||||
template <> void writeEscaped<kEscapeCsv>(raw_ostream &OS, const StringRef S) {
|
||||
if (std::find(S.begin(), S.end(), kCsvSep) == S.end()) {
|
||||
OS << S;
|
||||
} else {
|
||||
@ -44,8 +42,7 @@ void writeEscaped<kEscapeCsv>(llvm::raw_ostream &OS, const llvm::StringRef S) {
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
void writeEscaped<kEscapeHtml>(llvm::raw_ostream &OS, const llvm::StringRef S) {
|
||||
template <> void writeEscaped<kEscapeHtml>(raw_ostream &OS, const StringRef S) {
|
||||
for (const char C : S) {
|
||||
if (C == '<')
|
||||
OS << "<";
|
||||
@ -59,8 +56,7 @@ void writeEscaped<kEscapeHtml>(llvm::raw_ostream &OS, const llvm::StringRef S) {
|
||||
}
|
||||
|
||||
template <>
|
||||
void writeEscaped<kEscapeHtmlString>(llvm::raw_ostream &OS,
|
||||
const llvm::StringRef S) {
|
||||
void writeEscaped<kEscapeHtmlString>(raw_ostream &OS, const StringRef S) {
|
||||
for (const char C : S) {
|
||||
if (C == '"')
|
||||
OS << "\\\"";
|
||||
@ -73,7 +69,7 @@ void writeEscaped<kEscapeHtmlString>(llvm::raw_ostream &OS,
|
||||
|
||||
template <EscapeTag Tag>
|
||||
static void
|
||||
writeClusterId(llvm::raw_ostream &OS,
|
||||
writeClusterId(raw_ostream &OS,
|
||||
const InstructionBenchmarkClustering::ClusterId &CID) {
|
||||
if (CID.isNoise())
|
||||
writeEscaped<Tag>(OS, "[noise]");
|
||||
@ -84,7 +80,7 @@ writeClusterId(llvm::raw_ostream &OS,
|
||||
}
|
||||
|
||||
template <EscapeTag Tag>
|
||||
static void writeMeasurementValue(llvm::raw_ostream &OS, const double Value) {
|
||||
static void writeMeasurementValue(raw_ostream &OS, const double Value) {
|
||||
// Given Value, if we wanted to serialize it to a string,
|
||||
// how many base-10 digits will we need to store, max?
|
||||
static constexpr auto MaxDigitCount =
|
||||
@ -98,39 +94,36 @@ static void writeMeasurementValue(llvm::raw_ostream &OS, const double Value) {
|
||||
static constexpr StringLiteral SimpleFloatFormat = StringLiteral("{0:F}");
|
||||
|
||||
writeEscaped<Tag>(
|
||||
OS,
|
||||
llvm::formatv(SimpleFloatFormat.data(), Value).sstr<SerializationLen>());
|
||||
OS, formatv(SimpleFloatFormat.data(), Value).sstr<SerializationLen>());
|
||||
}
|
||||
|
||||
template <typename EscapeTag, EscapeTag Tag>
|
||||
void Analysis::writeSnippet(llvm::raw_ostream &OS,
|
||||
llvm::ArrayRef<uint8_t> Bytes,
|
||||
void Analysis::writeSnippet(raw_ostream &OS, ArrayRef<uint8_t> Bytes,
|
||||
const char *Separator) const {
|
||||
llvm::SmallVector<std::string, 3> Lines;
|
||||
SmallVector<std::string, 3> Lines;
|
||||
// Parse the asm snippet and print it.
|
||||
while (!Bytes.empty()) {
|
||||
llvm::MCInst MI;
|
||||
MCInst MI;
|
||||
uint64_t MISize = 0;
|
||||
if (!Disasm_->getInstruction(MI, MISize, Bytes, 0, llvm::nulls(),
|
||||
llvm::nulls())) {
|
||||
writeEscaped<Tag>(OS, llvm::join(Lines, Separator));
|
||||
if (!Disasm_->getInstruction(MI, MISize, Bytes, 0, nulls(), nulls())) {
|
||||
writeEscaped<Tag>(OS, join(Lines, Separator));
|
||||
writeEscaped<Tag>(OS, Separator);
|
||||
writeEscaped<Tag>(OS, "[error decoding asm snippet]");
|
||||
return;
|
||||
}
|
||||
llvm::SmallString<128> InstPrinterStr; // FIXME: magic number.
|
||||
llvm::raw_svector_ostream OSS(InstPrinterStr);
|
||||
SmallString<128> InstPrinterStr; // FIXME: magic number.
|
||||
raw_svector_ostream OSS(InstPrinterStr);
|
||||
InstPrinter_->printInst(&MI, OSS, "", *SubtargetInfo_);
|
||||
Bytes = Bytes.drop_front(MISize);
|
||||
Lines.emplace_back(llvm::StringRef(InstPrinterStr).trim());
|
||||
Lines.emplace_back(StringRef(InstPrinterStr).trim());
|
||||
}
|
||||
writeEscaped<Tag>(OS, llvm::join(Lines, Separator));
|
||||
writeEscaped<Tag>(OS, join(Lines, Separator));
|
||||
}
|
||||
|
||||
// Prints a row representing an instruction, along with scheduling info and
|
||||
// point coordinates (measurements).
|
||||
void Analysis::printInstructionRowCsv(const size_t PointId,
|
||||
llvm::raw_ostream &OS) const {
|
||||
raw_ostream &OS) const {
|
||||
const InstructionBenchmark &Point = Clustering_.getPoints()[PointId];
|
||||
writeClusterId<kEscapeCsv>(OS, Clustering_.getClusterIdForPoint(PointId));
|
||||
OS << kCsvSep;
|
||||
@ -139,12 +132,12 @@ void Analysis::printInstructionRowCsv(const size_t PointId,
|
||||
writeEscaped<kEscapeCsv>(OS, Point.Key.Config);
|
||||
OS << kCsvSep;
|
||||
assert(!Point.Key.Instructions.empty());
|
||||
const llvm::MCInst &MCI = Point.keyInstruction();
|
||||
const MCInst &MCI = Point.keyInstruction();
|
||||
unsigned SchedClassId;
|
||||
std::tie(SchedClassId, std::ignore) = ResolvedSchedClass::resolveSchedClassId(
|
||||
*SubtargetInfo_, *InstrInfo_, MCI);
|
||||
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
||||
const llvm::MCSchedClassDesc *const SCDesc =
|
||||
const MCSchedClassDesc *const SCDesc =
|
||||
SubtargetInfo_->getSchedModel().getSchedClassDesc(SchedClassId);
|
||||
writeEscaped<kEscapeCsv>(OS, SCDesc->Name);
|
||||
#else
|
||||
@ -157,8 +150,7 @@ void Analysis::printInstructionRowCsv(const size_t PointId,
|
||||
OS << "\n";
|
||||
}
|
||||
|
||||
Analysis::Analysis(const llvm::Target &Target,
|
||||
std::unique_ptr<llvm::MCInstrInfo> InstrInfo,
|
||||
Analysis::Analysis(const Target &Target, std::unique_ptr<MCInstrInfo> InstrInfo,
|
||||
const InstructionBenchmarkClustering &Clustering,
|
||||
double AnalysisInconsistencyEpsilon,
|
||||
bool AnalysisDisplayUnstableOpcodes)
|
||||
@ -175,21 +167,20 @@ Analysis::Analysis(const llvm::Target &Target,
|
||||
SubtargetInfo_.reset(Target.createMCSubtargetInfo(FirstPoint.LLVMTriple,
|
||||
FirstPoint.CpuName, ""));
|
||||
InstPrinter_.reset(Target.createMCInstPrinter(
|
||||
llvm::Triple(FirstPoint.LLVMTriple), 0 /*default variant*/, *AsmInfo_,
|
||||
Triple(FirstPoint.LLVMTriple), 0 /*default variant*/, *AsmInfo_,
|
||||
*InstrInfo_, *RegInfo_));
|
||||
|
||||
Context_ = std::make_unique<llvm::MCContext>(AsmInfo_.get(), RegInfo_.get(),
|
||||
&ObjectFileInfo_);
|
||||
Context_ = std::make_unique<MCContext>(AsmInfo_.get(), RegInfo_.get(),
|
||||
&ObjectFileInfo_);
|
||||
Disasm_.reset(Target.createMCDisassembler(*SubtargetInfo_, *Context_));
|
||||
assert(Disasm_ && "cannot create MCDisassembler. missing call to "
|
||||
"InitializeXXXTargetDisassembler ?");
|
||||
}
|
||||
|
||||
template <>
|
||||
llvm::Error
|
||||
Analysis::run<Analysis::PrintClusters>(llvm::raw_ostream &OS) const {
|
||||
Error Analysis::run<Analysis::PrintClusters>(raw_ostream &OS) const {
|
||||
if (Clustering_.getPoints().empty())
|
||||
return llvm::Error::success();
|
||||
return Error::success();
|
||||
|
||||
// Write the header.
|
||||
OS << "cluster_id" << kCsvSep << "opcode_name" << kCsvSep << "config"
|
||||
@ -208,7 +199,7 @@ Analysis::run<Analysis::PrintClusters>(llvm::raw_ostream &OS) const {
|
||||
}
|
||||
OS << "\n\n";
|
||||
}
|
||||
return llvm::Error::success();
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Analysis::ResolvedSchedClassAndPoints::ResolvedSchedClassAndPoints(
|
||||
@ -228,7 +219,7 @@ Analysis::makePointsPerSchedClass() const {
|
||||
assert(!Point.Key.Instructions.empty());
|
||||
// FIXME: we should be using the tuple of classes for instructions in the
|
||||
// snippet as key.
|
||||
const llvm::MCInst &MCI = Point.keyInstruction();
|
||||
const MCInst &MCI = Point.keyInstruction();
|
||||
unsigned SchedClassId;
|
||||
bool WasVariant;
|
||||
std::tie(SchedClassId, WasVariant) =
|
||||
@ -252,9 +243,9 @@ Analysis::makePointsPerSchedClass() const {
|
||||
|
||||
// Uops repeat the same opcode over again. Just show this opcode and show the
|
||||
// whole snippet only on hover.
|
||||
static void writeUopsSnippetHtml(llvm::raw_ostream &OS,
|
||||
const std::vector<llvm::MCInst> &Instructions,
|
||||
const llvm::MCInstrInfo &InstrInfo) {
|
||||
static void writeUopsSnippetHtml(raw_ostream &OS,
|
||||
const std::vector<MCInst> &Instructions,
|
||||
const MCInstrInfo &InstrInfo) {
|
||||
if (Instructions.empty())
|
||||
return;
|
||||
writeEscaped<kEscapeHtml>(OS, InstrInfo.getName(Instructions[0].getOpcode()));
|
||||
@ -264,12 +255,11 @@ static void writeUopsSnippetHtml(llvm::raw_ostream &OS,
|
||||
|
||||
// Latency tries to find a serial path. Just show the opcode path and show the
|
||||
// whole snippet only on hover.
|
||||
static void
|
||||
writeLatencySnippetHtml(llvm::raw_ostream &OS,
|
||||
const std::vector<llvm::MCInst> &Instructions,
|
||||
const llvm::MCInstrInfo &InstrInfo) {
|
||||
static void writeLatencySnippetHtml(raw_ostream &OS,
|
||||
const std::vector<MCInst> &Instructions,
|
||||
const MCInstrInfo &InstrInfo) {
|
||||
bool First = true;
|
||||
for (const llvm::MCInst &Instr : Instructions) {
|
||||
for (const MCInst &Instr : Instructions) {
|
||||
if (First)
|
||||
First = false;
|
||||
else
|
||||
@ -280,7 +270,7 @@ writeLatencySnippetHtml(llvm::raw_ostream &OS,
|
||||
|
||||
void Analysis::printSchedClassClustersHtml(
|
||||
const std::vector<SchedClassCluster> &Clusters,
|
||||
const ResolvedSchedClass &RSC, llvm::raw_ostream &OS) const {
|
||||
const ResolvedSchedClass &RSC, raw_ostream &OS) const {
|
||||
const auto &Points = Clustering_.getPoints();
|
||||
OS << "<table class=\"sched-class-clusters\">";
|
||||
OS << "<tr><th>ClusterId</th><th>Opcode/Config</th>";
|
||||
@ -349,7 +339,7 @@ void Analysis::SchedClassCluster::addPoint(
|
||||
}
|
||||
|
||||
bool Analysis::SchedClassCluster::measurementsMatch(
|
||||
const llvm::MCSubtargetInfo &STI, const ResolvedSchedClass &RSC,
|
||||
const MCSubtargetInfo &STI, const ResolvedSchedClass &RSC,
|
||||
const InstructionBenchmarkClustering &Clustering,
|
||||
const double AnalysisInconsistencyEpsilonSquared_) const {
|
||||
assert(!Clustering.getPoints().empty());
|
||||
@ -374,7 +364,7 @@ bool Analysis::SchedClassCluster::measurementsMatch(
|
||||
}
|
||||
|
||||
void Analysis::printSchedClassDescHtml(const ResolvedSchedClass &RSC,
|
||||
llvm::raw_ostream &OS) const {
|
||||
raw_ostream &OS) const {
|
||||
OS << "<table class=\"sched-class-desc\">";
|
||||
OS << "<tr><th>Valid</th><th>Variant</th><th>NumMicroOps</th><th>Latency</"
|
||||
"th><th>RThroughput</th><th>WriteProcRes</th><th title=\"This is the "
|
||||
@ -499,8 +489,8 @@ tr.bad-cluster td.measurement span.minmax {
|
||||
)";
|
||||
|
||||
template <>
|
||||
llvm::Error Analysis::run<Analysis::PrintSchedClassInconsistencies>(
|
||||
llvm::raw_ostream &OS) const {
|
||||
Error Analysis::run<Analysis::PrintSchedClassInconsistencies>(
|
||||
raw_ostream &OS) const {
|
||||
const auto &FirstPoint = Clustering_.getPoints()[0];
|
||||
// Print the header.
|
||||
OS << "<!DOCTYPE html><html>" << kHtmlHead << "<body>";
|
||||
@ -536,12 +526,12 @@ llvm::Error Analysis::run<Analysis::PrintSchedClassInconsistencies>(
|
||||
|
||||
// Print any scheduling class that has at least one cluster that does not
|
||||
// match the checked-in data.
|
||||
if (llvm::all_of(SchedClassClusters,
|
||||
[this, &RSCAndPoints](const SchedClassCluster &C) {
|
||||
return C.measurementsMatch(
|
||||
*SubtargetInfo_, RSCAndPoints.RSC, Clustering_,
|
||||
AnalysisInconsistencyEpsilonSquared_);
|
||||
}))
|
||||
if (all_of(SchedClassClusters, [this,
|
||||
&RSCAndPoints](const SchedClassCluster &C) {
|
||||
return C.measurementsMatch(*SubtargetInfo_, RSCAndPoints.RSC,
|
||||
Clustering_,
|
||||
AnalysisInconsistencyEpsilonSquared_);
|
||||
}))
|
||||
continue; // Nothing weird.
|
||||
|
||||
OS << "<div class=\"inconsistency\"><p>Sched Class <span "
|
||||
@ -560,7 +550,7 @@ llvm::Error Analysis::run<Analysis::PrintSchedClassInconsistencies>(
|
||||
}
|
||||
|
||||
OS << "</body></html>";
|
||||
return llvm::Error::success();
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
} // namespace exegesis
|
||||
|
@ -36,8 +36,7 @@ namespace exegesis {
|
||||
// A helper class to analyze benchmark results for a target.
|
||||
class Analysis {
|
||||
public:
|
||||
Analysis(const llvm::Target &Target,
|
||||
std::unique_ptr<llvm::MCInstrInfo> InstrInfo,
|
||||
Analysis(const Target &Target, std::unique_ptr<MCInstrInfo> InstrInfo,
|
||||
const InstructionBenchmarkClustering &Clustering,
|
||||
double AnalysisInconsistencyEpsilon,
|
||||
bool AnalysisDisplayUnstableOpcodes);
|
||||
@ -47,7 +46,7 @@ public:
|
||||
// Find potential errors in the scheduling information given measurements.
|
||||
struct PrintSchedClassInconsistencies {};
|
||||
|
||||
template <typename Pass> llvm::Error run(llvm::raw_ostream &OS) const;
|
||||
template <typename Pass> Error run(raw_ostream &OS) const;
|
||||
|
||||
private:
|
||||
using ClusterId = InstructionBenchmarkClustering::ClusterId;
|
||||
@ -69,8 +68,7 @@ private:
|
||||
|
||||
// Returns true if the cluster representative measurements match that of SC.
|
||||
bool
|
||||
measurementsMatch(const llvm::MCSubtargetInfo &STI,
|
||||
const ResolvedSchedClass &SC,
|
||||
measurementsMatch(const MCSubtargetInfo &STI, const ResolvedSchedClass &SC,
|
||||
const InstructionBenchmarkClustering &Clustering,
|
||||
const double AnalysisInconsistencyEpsilonSquared_) const;
|
||||
|
||||
@ -81,14 +79,14 @@ private:
|
||||
SchedClassClusterCentroid Centroid;
|
||||
};
|
||||
|
||||
void printInstructionRowCsv(size_t PointId, llvm::raw_ostream &OS) const;
|
||||
void printInstructionRowCsv(size_t PointId, raw_ostream &OS) const;
|
||||
|
||||
void
|
||||
printSchedClassClustersHtml(const std::vector<SchedClassCluster> &Clusters,
|
||||
const ResolvedSchedClass &SC,
|
||||
llvm::raw_ostream &OS) const;
|
||||
raw_ostream &OS) const;
|
||||
void printSchedClassDescHtml(const ResolvedSchedClass &SC,
|
||||
llvm::raw_ostream &OS) const;
|
||||
raw_ostream &OS) const;
|
||||
|
||||
// A pair of (Sched Class, indices of points that belong to the sched
|
||||
// class).
|
||||
@ -103,18 +101,18 @@ private:
|
||||
std::vector<ResolvedSchedClassAndPoints> makePointsPerSchedClass() const;
|
||||
|
||||
template <typename EscapeTag, EscapeTag Tag>
|
||||
void writeSnippet(llvm::raw_ostream &OS, llvm::ArrayRef<uint8_t> Bytes,
|
||||
void writeSnippet(raw_ostream &OS, ArrayRef<uint8_t> Bytes,
|
||||
const char *Separator) const;
|
||||
|
||||
const InstructionBenchmarkClustering &Clustering_;
|
||||
llvm::MCObjectFileInfo ObjectFileInfo_;
|
||||
std::unique_ptr<llvm::MCContext> Context_;
|
||||
std::unique_ptr<llvm::MCSubtargetInfo> SubtargetInfo_;
|
||||
std::unique_ptr<llvm::MCInstrInfo> InstrInfo_;
|
||||
std::unique_ptr<llvm::MCRegisterInfo> RegInfo_;
|
||||
std::unique_ptr<llvm::MCAsmInfo> AsmInfo_;
|
||||
std::unique_ptr<llvm::MCInstPrinter> InstPrinter_;
|
||||
std::unique_ptr<llvm::MCDisassembler> Disasm_;
|
||||
MCObjectFileInfo ObjectFileInfo_;
|
||||
std::unique_ptr<MCContext> Context_;
|
||||
std::unique_ptr<MCSubtargetInfo> SubtargetInfo_;
|
||||
std::unique_ptr<MCInstrInfo> InstrInfo_;
|
||||
std::unique_ptr<MCRegisterInfo> RegInfo_;
|
||||
std::unique_ptr<MCAsmInfo> AsmInfo_;
|
||||
std::unique_ptr<MCInstPrinter> InstPrinter_;
|
||||
std::unique_ptr<MCDisassembler> Disasm_;
|
||||
const double AnalysisInconsistencyEpsilonSquared_;
|
||||
const bool AnalysisDisplayUnstableOpcodes_;
|
||||
};
|
||||
|
@ -31,11 +31,9 @@ static constexpr const char FunctionID[] = "foo";
|
||||
|
||||
// Fills the given basic block with register setup code, and returns true if
|
||||
// all registers could be setup correctly.
|
||||
static bool
|
||||
generateSnippetSetupCode(const ExegesisTarget &ET,
|
||||
const llvm::MCSubtargetInfo *const MSI,
|
||||
llvm::ArrayRef<RegisterValue> RegisterInitialValues,
|
||||
BasicBlockFiller &BBF) {
|
||||
static bool generateSnippetSetupCode(
|
||||
const ExegesisTarget &ET, const MCSubtargetInfo *const MSI,
|
||||
ArrayRef<RegisterValue> RegisterInitialValues, BasicBlockFiller &BBF) {
|
||||
bool IsSnippetSetupComplete = true;
|
||||
for (const RegisterValue &RV : RegisterInitialValues) {
|
||||
// Load a constant in the register.
|
||||
@ -48,20 +46,20 @@ generateSnippetSetupCode(const ExegesisTarget &ET,
|
||||
}
|
||||
|
||||
// Small utility function to add named passes.
|
||||
static bool addPass(llvm::PassManagerBase &PM, llvm::StringRef PassName,
|
||||
llvm::TargetPassConfig &TPC) {
|
||||
const llvm::PassRegistry *PR = llvm::PassRegistry::getPassRegistry();
|
||||
const llvm::PassInfo *PI = PR->getPassInfo(PassName);
|
||||
static bool addPass(PassManagerBase &PM, StringRef PassName,
|
||||
TargetPassConfig &TPC) {
|
||||
const PassRegistry *PR = PassRegistry::getPassRegistry();
|
||||
const PassInfo *PI = PR->getPassInfo(PassName);
|
||||
if (!PI) {
|
||||
llvm::errs() << " run-pass " << PassName << " is not registered.\n";
|
||||
errs() << " run-pass " << PassName << " is not registered.\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!PI->getNormalCtor()) {
|
||||
llvm::errs() << " cannot create pass: " << PI->getPassName() << "\n";
|
||||
errs() << " cannot create pass: " << PI->getPassName() << "\n";
|
||||
return true;
|
||||
}
|
||||
llvm::Pass *P = PI->getNormalCtor()();
|
||||
Pass *P = PI->getNormalCtor()();
|
||||
std::string Banner = std::string("After ") + std::string(P->getPassName());
|
||||
PM.add(P);
|
||||
TPC.printAndVerify(Banner);
|
||||
@ -69,42 +67,39 @@ static bool addPass(llvm::PassManagerBase &PM, llvm::StringRef PassName,
|
||||
return false;
|
||||
}
|
||||
|
||||
llvm::MachineFunction &
|
||||
createVoidVoidPtrMachineFunction(llvm::StringRef FunctionID,
|
||||
llvm::Module *Module,
|
||||
llvm::MachineModuleInfo *MMI) {
|
||||
llvm::Type *const ReturnType = llvm::Type::getInt32Ty(Module->getContext());
|
||||
llvm::Type *const MemParamType = llvm::PointerType::get(
|
||||
llvm::Type::getInt8Ty(Module->getContext()), 0 /*default address space*/);
|
||||
llvm::FunctionType *FunctionType =
|
||||
llvm::FunctionType::get(ReturnType, {MemParamType}, false);
|
||||
llvm::Function *const F = llvm::Function::Create(
|
||||
FunctionType, llvm::GlobalValue::InternalLinkage, FunctionID, Module);
|
||||
MachineFunction &createVoidVoidPtrMachineFunction(StringRef FunctionID,
|
||||
Module *Module,
|
||||
MachineModuleInfo *MMI) {
|
||||
Type *const ReturnType = Type::getInt32Ty(Module->getContext());
|
||||
Type *const MemParamType = PointerType::get(
|
||||
Type::getInt8Ty(Module->getContext()), 0 /*default address space*/);
|
||||
FunctionType *FunctionType =
|
||||
FunctionType::get(ReturnType, {MemParamType}, false);
|
||||
Function *const F = Function::Create(
|
||||
FunctionType, GlobalValue::InternalLinkage, FunctionID, Module);
|
||||
// Making sure we can create a MachineFunction out of this Function even if it
|
||||
// contains no IR.
|
||||
F->setIsMaterializable(true);
|
||||
return MMI->getOrCreateMachineFunction(*F);
|
||||
}
|
||||
|
||||
BasicBlockFiller::BasicBlockFiller(llvm::MachineFunction &MF,
|
||||
llvm::MachineBasicBlock *MBB,
|
||||
const llvm::MCInstrInfo *MCII)
|
||||
BasicBlockFiller::BasicBlockFiller(MachineFunction &MF, MachineBasicBlock *MBB,
|
||||
const MCInstrInfo *MCII)
|
||||
: MF(MF), MBB(MBB), MCII(MCII) {}
|
||||
|
||||
void BasicBlockFiller::addInstruction(const llvm::MCInst &Inst,
|
||||
const llvm::DebugLoc &DL) {
|
||||
void BasicBlockFiller::addInstruction(const MCInst &Inst, const DebugLoc &DL) {
|
||||
const unsigned Opcode = Inst.getOpcode();
|
||||
const llvm::MCInstrDesc &MCID = MCII->get(Opcode);
|
||||
llvm::MachineInstrBuilder Builder = llvm::BuildMI(MBB, DL, MCID);
|
||||
const MCInstrDesc &MCID = MCII->get(Opcode);
|
||||
MachineInstrBuilder Builder = BuildMI(MBB, DL, MCID);
|
||||
for (unsigned OpIndex = 0, E = Inst.getNumOperands(); OpIndex < E;
|
||||
++OpIndex) {
|
||||
const llvm::MCOperand &Op = Inst.getOperand(OpIndex);
|
||||
const MCOperand &Op = Inst.getOperand(OpIndex);
|
||||
if (Op.isReg()) {
|
||||
const bool IsDef = OpIndex < MCID.getNumDefs();
|
||||
unsigned Flags = 0;
|
||||
const llvm::MCOperandInfo &OpInfo = MCID.operands().begin()[OpIndex];
|
||||
const MCOperandInfo &OpInfo = MCID.operands().begin()[OpIndex];
|
||||
if (IsDef && !OpInfo.isOptionalDef())
|
||||
Flags |= llvm::RegState::Define;
|
||||
Flags |= RegState::Define;
|
||||
Builder.addReg(Op.getReg(), Flags);
|
||||
} else if (Op.isImm()) {
|
||||
Builder.addImm(Op.getImm());
|
||||
@ -116,31 +111,31 @@ void BasicBlockFiller::addInstruction(const llvm::MCInst &Inst,
|
||||
}
|
||||
}
|
||||
|
||||
void BasicBlockFiller::addInstructions(ArrayRef<llvm::MCInst> Insts,
|
||||
const llvm::DebugLoc &DL) {
|
||||
void BasicBlockFiller::addInstructions(ArrayRef<MCInst> Insts,
|
||||
const DebugLoc &DL) {
|
||||
for (const MCInst &Inst : Insts)
|
||||
addInstruction(Inst, DL);
|
||||
}
|
||||
|
||||
void BasicBlockFiller::addReturn(const llvm::DebugLoc &DL) {
|
||||
void BasicBlockFiller::addReturn(const DebugLoc &DL) {
|
||||
// Insert the return code.
|
||||
const llvm::TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
|
||||
const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
|
||||
if (TII->getReturnOpcode() < TII->getNumOpcodes()) {
|
||||
llvm::BuildMI(MBB, DL, TII->get(TII->getReturnOpcode()));
|
||||
BuildMI(MBB, DL, TII->get(TII->getReturnOpcode()));
|
||||
} else {
|
||||
llvm::MachineIRBuilder MIB(MF);
|
||||
MachineIRBuilder MIB(MF);
|
||||
MIB.setMBB(*MBB);
|
||||
MF.getSubtarget().getCallLowering()->lowerReturn(MIB, nullptr, {});
|
||||
}
|
||||
}
|
||||
|
||||
FunctionFiller::FunctionFiller(llvm::MachineFunction &MF,
|
||||
FunctionFiller::FunctionFiller(MachineFunction &MF,
|
||||
std::vector<unsigned> RegistersSetUp)
|
||||
: MF(MF), MCII(MF.getTarget().getMCInstrInfo()), Entry(addBasicBlock()),
|
||||
RegistersSetUp(std::move(RegistersSetUp)) {}
|
||||
|
||||
BasicBlockFiller FunctionFiller::addBasicBlock() {
|
||||
llvm::MachineBasicBlock *MBB = MF.CreateMachineBasicBlock();
|
||||
MachineBasicBlock *MBB = MF.CreateMachineBasicBlock();
|
||||
MF.push_back(MBB);
|
||||
return BasicBlockFiller(MF, MBB, MCII);
|
||||
}
|
||||
@ -149,50 +144,45 @@ ArrayRef<unsigned> FunctionFiller::getRegistersSetUp() const {
|
||||
return RegistersSetUp;
|
||||
}
|
||||
|
||||
static std::unique_ptr<llvm::Module>
|
||||
createModule(const std::unique_ptr<llvm::LLVMContext> &Context,
|
||||
const llvm::DataLayout DL) {
|
||||
auto Module = std::make_unique<llvm::Module>(ModuleID, *Context);
|
||||
Module->setDataLayout(DL);
|
||||
return Module;
|
||||
static std::unique_ptr<Module>
|
||||
createModule(const std::unique_ptr<LLVMContext> &Context, const DataLayout DL) {
|
||||
auto Mod = std::make_unique<Module>(ModuleID, *Context);
|
||||
Mod->setDataLayout(DL);
|
||||
return Mod;
|
||||
}
|
||||
|
||||
llvm::BitVector getFunctionReservedRegs(const llvm::TargetMachine &TM) {
|
||||
std::unique_ptr<llvm::LLVMContext> Context =
|
||||
std::make_unique<llvm::LLVMContext>();
|
||||
std::unique_ptr<llvm::Module> Module =
|
||||
createModule(Context, TM.createDataLayout());
|
||||
BitVector getFunctionReservedRegs(const TargetMachine &TM) {
|
||||
std::unique_ptr<LLVMContext> Context = std::make_unique<LLVMContext>();
|
||||
std::unique_ptr<Module> Module = createModule(Context, TM.createDataLayout());
|
||||
// TODO: This only works for targets implementing LLVMTargetMachine.
|
||||
const LLVMTargetMachine &LLVMTM = static_cast<const LLVMTargetMachine &>(TM);
|
||||
std::unique_ptr<llvm::MachineModuleInfoWrapperPass> MMIWP =
|
||||
std::make_unique<llvm::MachineModuleInfoWrapperPass>(&LLVMTM);
|
||||
llvm::MachineFunction &MF = createVoidVoidPtrMachineFunction(
|
||||
std::unique_ptr<MachineModuleInfoWrapperPass> MMIWP =
|
||||
std::make_unique<MachineModuleInfoWrapperPass>(&LLVMTM);
|
||||
MachineFunction &MF = createVoidVoidPtrMachineFunction(
|
||||
FunctionID, Module.get(), &MMIWP.get()->getMMI());
|
||||
// Saving reserved registers for client.
|
||||
return MF.getSubtarget().getRegisterInfo()->getReservedRegs(MF);
|
||||
}
|
||||
|
||||
void assembleToStream(const ExegesisTarget &ET,
|
||||
std::unique_ptr<llvm::LLVMTargetMachine> TM,
|
||||
llvm::ArrayRef<unsigned> LiveIns,
|
||||
llvm::ArrayRef<RegisterValue> RegisterInitialValues,
|
||||
const FillFunction &Fill,
|
||||
llvm::raw_pwrite_stream &AsmStream) {
|
||||
std::unique_ptr<llvm::LLVMContext> Context =
|
||||
std::make_unique<llvm::LLVMContext>();
|
||||
std::unique_ptr<llvm::Module> Module =
|
||||
std::unique_ptr<LLVMTargetMachine> TM,
|
||||
ArrayRef<unsigned> LiveIns,
|
||||
ArrayRef<RegisterValue> RegisterInitialValues,
|
||||
const FillFunction &Fill, raw_pwrite_stream &AsmStream) {
|
||||
std::unique_ptr<LLVMContext> Context = std::make_unique<LLVMContext>();
|
||||
std::unique_ptr<Module> Module =
|
||||
createModule(Context, TM->createDataLayout());
|
||||
std::unique_ptr<llvm::MachineModuleInfoWrapperPass> MMIWP =
|
||||
std::make_unique<llvm::MachineModuleInfoWrapperPass>(TM.get());
|
||||
llvm::MachineFunction &MF = createVoidVoidPtrMachineFunction(
|
||||
std::unique_ptr<MachineModuleInfoWrapperPass> MMIWP =
|
||||
std::make_unique<MachineModuleInfoWrapperPass>(TM.get());
|
||||
MachineFunction &MF = createVoidVoidPtrMachineFunction(
|
||||
FunctionID, Module.get(), &MMIWP.get()->getMMI());
|
||||
|
||||
// We need to instruct the passes that we're done with SSA and virtual
|
||||
// registers.
|
||||
auto &Properties = MF.getProperties();
|
||||
Properties.set(llvm::MachineFunctionProperties::Property::NoVRegs);
|
||||
Properties.reset(llvm::MachineFunctionProperties::Property::IsSSA);
|
||||
Properties.set(llvm::MachineFunctionProperties::Property::NoPHIs);
|
||||
Properties.set(MachineFunctionProperties::Property::NoVRegs);
|
||||
Properties.reset(MachineFunctionProperties::Property::IsSSA);
|
||||
Properties.set(MachineFunctionProperties::Property::NoPHIs);
|
||||
|
||||
for (const unsigned Reg : LiveIns)
|
||||
MF.getRegInfo().addLiveIn(Reg);
|
||||
@ -212,7 +202,7 @@ void assembleToStream(const ExegesisTarget &ET,
|
||||
// If the snippet setup is not complete, we disable liveliness tracking. This
|
||||
// means that we won't know what values are in the registers.
|
||||
if (!IsSnippetSetupComplete)
|
||||
Properties.reset(llvm::MachineFunctionProperties::Property::TracksLiveness);
|
||||
Properties.reset(MachineFunctionProperties::Property::TracksLiveness);
|
||||
|
||||
Fill(Sink);
|
||||
|
||||
@ -221,13 +211,13 @@ void assembleToStream(const ExegesisTarget &ET,
|
||||
MF.getRegInfo().freezeReservedRegs(MF);
|
||||
|
||||
// We create the pass manager, run the passes to populate AsmBuffer.
|
||||
llvm::MCContext &MCContext = MMIWP->getMMI().getContext();
|
||||
llvm::legacy::PassManager PM;
|
||||
MCContext &MCContext = MMIWP->getMMI().getContext();
|
||||
legacy::PassManager PM;
|
||||
|
||||
llvm::TargetLibraryInfoImpl TLII(llvm::Triple(Module->getTargetTriple()));
|
||||
PM.add(new llvm::TargetLibraryInfoWrapperPass(TLII));
|
||||
TargetLibraryInfoImpl TLII(Triple(Module->getTargetTriple()));
|
||||
PM.add(new TargetLibraryInfoWrapperPass(TLII));
|
||||
|
||||
llvm::TargetPassConfig *TPC = TM->createPassConfig(PM);
|
||||
TargetPassConfig *TPC = TM->createPassConfig(PM);
|
||||
PM.add(TPC);
|
||||
PM.add(MMIWP.release());
|
||||
TPC->printAndVerify("MachineFunctionGenerator::assemble");
|
||||
@ -239,50 +229,49 @@ void assembleToStream(const ExegesisTarget &ET,
|
||||
// - prologepilog: saves and restore callee saved registers.
|
||||
for (const char *PassName : {"machineverifier", "prologepilog"})
|
||||
if (addPass(PM, PassName, *TPC))
|
||||
llvm::report_fatal_error("Unable to add a mandatory pass");
|
||||
report_fatal_error("Unable to add a mandatory pass");
|
||||
TPC->setInitialized();
|
||||
|
||||
// AsmPrinter is responsible for generating the assembly into AsmBuffer.
|
||||
if (TM->addAsmPrinter(PM, AsmStream, nullptr,
|
||||
llvm::TargetMachine::CGFT_ObjectFile, MCContext))
|
||||
llvm::report_fatal_error("Cannot add AsmPrinter passes");
|
||||
if (TM->addAsmPrinter(PM, AsmStream, nullptr, TargetMachine::CGFT_ObjectFile,
|
||||
MCContext))
|
||||
report_fatal_error("Cannot add AsmPrinter passes");
|
||||
|
||||
PM.run(*Module); // Run all the passes
|
||||
}
|
||||
|
||||
llvm::object::OwningBinary<llvm::object::ObjectFile>
|
||||
getObjectFromBuffer(llvm::StringRef InputData) {
|
||||
object::OwningBinary<object::ObjectFile>
|
||||
getObjectFromBuffer(StringRef InputData) {
|
||||
// Storing the generated assembly into a MemoryBuffer that owns the memory.
|
||||
std::unique_ptr<llvm::MemoryBuffer> Buffer =
|
||||
llvm::MemoryBuffer::getMemBufferCopy(InputData);
|
||||
std::unique_ptr<MemoryBuffer> Buffer =
|
||||
MemoryBuffer::getMemBufferCopy(InputData);
|
||||
// Create the ObjectFile from the MemoryBuffer.
|
||||
std::unique_ptr<llvm::object::ObjectFile> Obj = llvm::cantFail(
|
||||
llvm::object::ObjectFile::createObjectFile(Buffer->getMemBufferRef()));
|
||||
std::unique_ptr<object::ObjectFile> Obj =
|
||||
cantFail(object::ObjectFile::createObjectFile(Buffer->getMemBufferRef()));
|
||||
// Returning both the MemoryBuffer and the ObjectFile.
|
||||
return llvm::object::OwningBinary<llvm::object::ObjectFile>(
|
||||
std::move(Obj), std::move(Buffer));
|
||||
return object::OwningBinary<object::ObjectFile>(std::move(Obj),
|
||||
std::move(Buffer));
|
||||
}
|
||||
|
||||
llvm::object::OwningBinary<llvm::object::ObjectFile>
|
||||
getObjectFromFile(llvm::StringRef Filename) {
|
||||
return llvm::cantFail(llvm::object::ObjectFile::createObjectFile(Filename));
|
||||
object::OwningBinary<object::ObjectFile> getObjectFromFile(StringRef Filename) {
|
||||
return cantFail(object::ObjectFile::createObjectFile(Filename));
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// Implementation of this class relies on the fact that a single object with a
|
||||
// single function will be loaded into memory.
|
||||
class TrackingSectionMemoryManager : public llvm::SectionMemoryManager {
|
||||
class TrackingSectionMemoryManager : public SectionMemoryManager {
|
||||
public:
|
||||
explicit TrackingSectionMemoryManager(uintptr_t *CodeSize)
|
||||
: CodeSize(CodeSize) {}
|
||||
|
||||
uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
|
||||
unsigned SectionID,
|
||||
llvm::StringRef SectionName) override {
|
||||
StringRef SectionName) override {
|
||||
*CodeSize = Size;
|
||||
return llvm::SectionMemoryManager::allocateCodeSection(
|
||||
Size, Alignment, SectionID, SectionName);
|
||||
return SectionMemoryManager::allocateCodeSection(Size, Alignment, SectionID,
|
||||
SectionName);
|
||||
}
|
||||
|
||||
private:
|
||||
@ -292,9 +281,9 @@ private:
|
||||
} // namespace
|
||||
|
||||
ExecutableFunction::ExecutableFunction(
|
||||
std::unique_ptr<llvm::LLVMTargetMachine> TM,
|
||||
llvm::object::OwningBinary<llvm::object::ObjectFile> &&ObjectFileHolder)
|
||||
: Context(std::make_unique<llvm::LLVMContext>()) {
|
||||
std::unique_ptr<LLVMTargetMachine> TM,
|
||||
object::OwningBinary<object::ObjectFile> &&ObjectFileHolder)
|
||||
: Context(std::make_unique<LLVMContext>()) {
|
||||
assert(ObjectFileHolder.getBinary() && "cannot create object file");
|
||||
// Initializing the execution engine.
|
||||
// We need to use the JIT EngineKind to be able to add an object file.
|
||||
@ -302,24 +291,23 @@ ExecutableFunction::ExecutableFunction(
|
||||
uintptr_t CodeSize = 0;
|
||||
std::string Error;
|
||||
ExecEngine.reset(
|
||||
llvm::EngineBuilder(createModule(Context, TM->createDataLayout()))
|
||||
EngineBuilder(createModule(Context, TM->createDataLayout()))
|
||||
.setErrorStr(&Error)
|
||||
.setMCPU(TM->getTargetCPU())
|
||||
.setEngineKind(llvm::EngineKind::JIT)
|
||||
.setEngineKind(EngineKind::JIT)
|
||||
.setMCJITMemoryManager(
|
||||
std::make_unique<TrackingSectionMemoryManager>(&CodeSize))
|
||||
.create(TM.release()));
|
||||
if (!ExecEngine)
|
||||
llvm::report_fatal_error(Error);
|
||||
report_fatal_error(Error);
|
||||
// Adding the generated object file containing the assembled function.
|
||||
// The ExecutionEngine makes sure the object file is copied into an
|
||||
// executable page.
|
||||
ExecEngine->addObjectFile(std::move(ObjectFileHolder));
|
||||
// Fetching function bytes.
|
||||
FunctionBytes =
|
||||
llvm::StringRef(reinterpret_cast<const char *>(
|
||||
ExecEngine->getFunctionAddress(FunctionID)),
|
||||
CodeSize);
|
||||
FunctionBytes = StringRef(reinterpret_cast<const char *>(
|
||||
ExecEngine->getFunctionAddress(FunctionID)),
|
||||
CodeSize);
|
||||
}
|
||||
|
||||
} // namespace exegesis
|
||||
|
@ -38,7 +38,7 @@ class ExegesisTarget;
|
||||
|
||||
// Gather the set of reserved registers (depends on function's calling
|
||||
// convention and target machine).
|
||||
llvm::BitVector getFunctionReservedRegs(const llvm::TargetMachine &TM);
|
||||
BitVector getFunctionReservedRegs(const TargetMachine &TM);
|
||||
|
||||
// Helper to fill in a basic block.
|
||||
class BasicBlockFiller {
|
||||
@ -47,8 +47,7 @@ public:
|
||||
const MCInstrInfo *MCII);
|
||||
|
||||
void addInstruction(const MCInst &Inst, const DebugLoc &DL = DebugLoc());
|
||||
void addInstructions(ArrayRef<llvm::MCInst> Insts,
|
||||
const DebugLoc &DL = DebugLoc());
|
||||
void addInstructions(ArrayRef<MCInst> Insts, const DebugLoc &DL = DebugLoc());
|
||||
|
||||
void addReturn(const DebugLoc &DL = DebugLoc());
|
||||
|
||||
@ -88,47 +87,43 @@ using FillFunction = std::function<void(FunctionFiller &)>;
|
||||
// epilogue. Once the MachineFunction is ready, it is assembled for TM to
|
||||
// AsmStream, the temporary function is eventually discarded.
|
||||
void assembleToStream(const ExegesisTarget &ET,
|
||||
std::unique_ptr<llvm::LLVMTargetMachine> TM,
|
||||
llvm::ArrayRef<unsigned> LiveIns,
|
||||
llvm::ArrayRef<RegisterValue> RegisterInitialValues,
|
||||
const FillFunction &Fill,
|
||||
llvm::raw_pwrite_stream &AsmStream);
|
||||
std::unique_ptr<LLVMTargetMachine> TM,
|
||||
ArrayRef<unsigned> LiveIns,
|
||||
ArrayRef<RegisterValue> RegisterInitialValues,
|
||||
const FillFunction &Fill, raw_pwrite_stream &AsmStream);
|
||||
|
||||
// Creates an ObjectFile in the format understood by the host.
|
||||
// Note: the resulting object keeps a copy of Buffer so it can be discarded once
|
||||
// this function returns.
|
||||
llvm::object::OwningBinary<llvm::object::ObjectFile>
|
||||
getObjectFromBuffer(llvm::StringRef Buffer);
|
||||
object::OwningBinary<object::ObjectFile> getObjectFromBuffer(StringRef Buffer);
|
||||
|
||||
// Loads the content of Filename as on ObjectFile and returns it.
|
||||
llvm::object::OwningBinary<llvm::object::ObjectFile>
|
||||
getObjectFromFile(llvm::StringRef Filename);
|
||||
object::OwningBinary<object::ObjectFile> getObjectFromFile(StringRef Filename);
|
||||
|
||||
// Consumes an ObjectFile containing a `void foo(char*)` function and make it
|
||||
// executable.
|
||||
struct ExecutableFunction {
|
||||
explicit ExecutableFunction(
|
||||
std::unique_ptr<llvm::LLVMTargetMachine> TM,
|
||||
llvm::object::OwningBinary<llvm::object::ObjectFile> &&ObjectFileHolder);
|
||||
std::unique_ptr<LLVMTargetMachine> TM,
|
||||
object::OwningBinary<object::ObjectFile> &&ObjectFileHolder);
|
||||
|
||||
// Retrieves the function as an array of bytes.
|
||||
llvm::StringRef getFunctionBytes() const { return FunctionBytes; }
|
||||
StringRef getFunctionBytes() const { return FunctionBytes; }
|
||||
|
||||
// Executes the function.
|
||||
void operator()(char *Memory) const {
|
||||
((void (*)(char *))(intptr_t)FunctionBytes.data())(Memory);
|
||||
}
|
||||
|
||||
std::unique_ptr<llvm::LLVMContext> Context;
|
||||
std::unique_ptr<llvm::ExecutionEngine> ExecEngine;
|
||||
llvm::StringRef FunctionBytes;
|
||||
std::unique_ptr<LLVMContext> Context;
|
||||
std::unique_ptr<ExecutionEngine> ExecEngine;
|
||||
StringRef FunctionBytes;
|
||||
};
|
||||
|
||||
// Creates a void(int8*) MachineFunction.
|
||||
llvm::MachineFunction &
|
||||
createVoidVoidPtrMachineFunction(llvm::StringRef FunctionID,
|
||||
llvm::Module *Module,
|
||||
llvm::MachineModuleInfo *MMI);
|
||||
MachineFunction &createVoidVoidPtrMachineFunction(StringRef FunctionID,
|
||||
Module *Module,
|
||||
MachineModuleInfo *MMI);
|
||||
|
||||
} // namespace exegesis
|
||||
} // namespace llvm
|
||||
|
@ -38,18 +38,18 @@ struct YamlContext {
|
||||
generateOpcodeNameToOpcodeIdxMapping(State.getInstrInfo())),
|
||||
RegNameToRegNo(generateRegNameToRegNoMapping(State.getRegInfo())) {}
|
||||
|
||||
static llvm::StringMap<unsigned>
|
||||
generateOpcodeNameToOpcodeIdxMapping(const llvm::MCInstrInfo &InstrInfo) {
|
||||
llvm::StringMap<unsigned> Map(InstrInfo.getNumOpcodes());
|
||||
static StringMap<unsigned>
|
||||
generateOpcodeNameToOpcodeIdxMapping(const MCInstrInfo &InstrInfo) {
|
||||
StringMap<unsigned> Map(InstrInfo.getNumOpcodes());
|
||||
for (unsigned I = 0, E = InstrInfo.getNumOpcodes(); I < E; ++I)
|
||||
Map[InstrInfo.getName(I)] = I;
|
||||
assert(Map.size() == InstrInfo.getNumOpcodes() && "Size prediction failed");
|
||||
return Map;
|
||||
};
|
||||
|
||||
llvm::StringMap<unsigned>
|
||||
generateRegNameToRegNoMapping(const llvm::MCRegisterInfo &RegInfo) {
|
||||
llvm::StringMap<unsigned> Map(RegInfo.getNumRegs());
|
||||
StringMap<unsigned>
|
||||
generateRegNameToRegNoMapping(const MCRegisterInfo &RegInfo) {
|
||||
StringMap<unsigned> Map(RegInfo.getNumRegs());
|
||||
// Special-case RegNo 0, which would otherwise be spelled as ''.
|
||||
Map[kNoRegister] = 0;
|
||||
for (unsigned I = 1, E = RegInfo.getNumRegs(); I < E; ++I)
|
||||
@ -58,7 +58,7 @@ struct YamlContext {
|
||||
return Map;
|
||||
};
|
||||
|
||||
void serializeMCInst(const llvm::MCInst &MCInst, llvm::raw_ostream &OS) {
|
||||
void serializeMCInst(const MCInst &MCInst, raw_ostream &OS) {
|
||||
OS << getInstrName(MCInst.getOpcode());
|
||||
for (const auto &Op : MCInst) {
|
||||
OS << ' ';
|
||||
@ -66,15 +66,15 @@ struct YamlContext {
|
||||
}
|
||||
}
|
||||
|
||||
void deserializeMCInst(llvm::StringRef String, llvm::MCInst &Value) {
|
||||
llvm::SmallVector<llvm::StringRef, 16> Pieces;
|
||||
void deserializeMCInst(StringRef String, MCInst &Value) {
|
||||
SmallVector<StringRef, 16> Pieces;
|
||||
String.split(Pieces, " ", /* MaxSplit */ -1, /* KeepEmpty */ false);
|
||||
if (Pieces.empty()) {
|
||||
ErrorStream << "Unknown Instruction: '" << String << "'\n";
|
||||
return;
|
||||
}
|
||||
bool ProcessOpcode = true;
|
||||
for (llvm::StringRef Piece : Pieces) {
|
||||
for (StringRef Piece : Pieces) {
|
||||
if (ProcessOpcode)
|
||||
Value.setOpcode(getInstrOpcode(Piece));
|
||||
else
|
||||
@ -85,43 +85,43 @@ struct YamlContext {
|
||||
|
||||
std::string &getLastError() { return ErrorStream.str(); }
|
||||
|
||||
llvm::raw_string_ostream &getErrorStream() { return ErrorStream; }
|
||||
raw_string_ostream &getErrorStream() { return ErrorStream; }
|
||||
|
||||
llvm::StringRef getRegName(unsigned RegNo) {
|
||||
StringRef getRegName(unsigned RegNo) {
|
||||
// Special case: RegNo 0 is NoRegister. We have to deal with it explicitly.
|
||||
if (RegNo == 0)
|
||||
return kNoRegister;
|
||||
const llvm::StringRef RegName = State->getRegInfo().getName(RegNo);
|
||||
const StringRef RegName = State->getRegInfo().getName(RegNo);
|
||||
if (RegName.empty())
|
||||
ErrorStream << "No register with enum value '" << RegNo << "'\n";
|
||||
return RegName;
|
||||
}
|
||||
|
||||
llvm::Optional<unsigned> getRegNo(llvm::StringRef RegName) {
|
||||
Optional<unsigned> getRegNo(StringRef RegName) {
|
||||
auto Iter = RegNameToRegNo.find(RegName);
|
||||
if (Iter != RegNameToRegNo.end())
|
||||
return Iter->second;
|
||||
ErrorStream << "No register with name '" << RegName << "'\n";
|
||||
return llvm::None;
|
||||
return None;
|
||||
}
|
||||
|
||||
private:
|
||||
void serializeIntegerOperand(llvm::raw_ostream &OS, int64_t Value) {
|
||||
void serializeIntegerOperand(raw_ostream &OS, int64_t Value) {
|
||||
OS << kIntegerPrefix;
|
||||
OS.write_hex(llvm::bit_cast<uint64_t>(Value));
|
||||
OS.write_hex(bit_cast<uint64_t>(Value));
|
||||
}
|
||||
|
||||
bool tryDeserializeIntegerOperand(llvm::StringRef String, int64_t &Value) {
|
||||
bool tryDeserializeIntegerOperand(StringRef String, int64_t &Value) {
|
||||
if (!String.consume_front(kIntegerPrefix))
|
||||
return false;
|
||||
return !String.consumeInteger(16, Value);
|
||||
}
|
||||
|
||||
void serializeFPOperand(llvm::raw_ostream &OS, double Value) {
|
||||
OS << kDoublePrefix << llvm::format("%la", Value);
|
||||
void serializeFPOperand(raw_ostream &OS, double Value) {
|
||||
OS << kDoublePrefix << format("%la", Value);
|
||||
}
|
||||
|
||||
bool tryDeserializeFPOperand(llvm::StringRef String, double &Value) {
|
||||
bool tryDeserializeFPOperand(StringRef String, double &Value) {
|
||||
if (!String.consume_front(kDoublePrefix))
|
||||
return false;
|
||||
char *EndPointer = nullptr;
|
||||
@ -129,8 +129,7 @@ private:
|
||||
return EndPointer == String.end();
|
||||
}
|
||||
|
||||
void serializeMCOperand(const llvm::MCOperand &MCOperand,
|
||||
llvm::raw_ostream &OS) {
|
||||
void serializeMCOperand(const MCOperand &MCOperand, raw_ostream &OS) {
|
||||
if (MCOperand.isReg()) {
|
||||
OS << getRegName(MCOperand.getReg());
|
||||
} else if (MCOperand.isImm()) {
|
||||
@ -142,29 +141,29 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
llvm::MCOperand deserializeMCOperand(llvm::StringRef String) {
|
||||
MCOperand deserializeMCOperand(StringRef String) {
|
||||
assert(!String.empty());
|
||||
int64_t IntValue = 0;
|
||||
double DoubleValue = 0;
|
||||
if (tryDeserializeIntegerOperand(String, IntValue))
|
||||
return llvm::MCOperand::createImm(IntValue);
|
||||
return MCOperand::createImm(IntValue);
|
||||
if (tryDeserializeFPOperand(String, DoubleValue))
|
||||
return llvm::MCOperand::createFPImm(DoubleValue);
|
||||
return MCOperand::createFPImm(DoubleValue);
|
||||
if (auto RegNo = getRegNo(String))
|
||||
return llvm::MCOperand::createReg(*RegNo);
|
||||
return MCOperand::createReg(*RegNo);
|
||||
if (String != kInvalidOperand)
|
||||
ErrorStream << "Unknown Operand: '" << String << "'\n";
|
||||
return {};
|
||||
}
|
||||
|
||||
llvm::StringRef getInstrName(unsigned InstrNo) {
|
||||
const llvm::StringRef InstrName = State->getInstrInfo().getName(InstrNo);
|
||||
StringRef getInstrName(unsigned InstrNo) {
|
||||
const StringRef InstrName = State->getInstrInfo().getName(InstrNo);
|
||||
if (InstrName.empty())
|
||||
ErrorStream << "No opcode with enum value '" << InstrNo << "'\n";
|
||||
return InstrName;
|
||||
}
|
||||
|
||||
unsigned getInstrOpcode(llvm::StringRef InstrName) {
|
||||
unsigned getInstrOpcode(StringRef InstrName) {
|
||||
auto Iter = OpcodeNameToOpcodeIdx.find(InstrName);
|
||||
if (Iter != OpcodeNameToOpcodeIdx.end())
|
||||
return Iter->second;
|
||||
@ -172,11 +171,11 @@ private:
|
||||
return 0;
|
||||
}
|
||||
|
||||
const llvm::exegesis::LLVMState *State;
|
||||
const exegesis::LLVMState *State;
|
||||
std::string LastError;
|
||||
llvm::raw_string_ostream ErrorStream;
|
||||
const llvm::StringMap<unsigned> OpcodeNameToOpcodeIdx;
|
||||
const llvm::StringMap<unsigned> RegNameToRegNo;
|
||||
raw_string_ostream ErrorStream;
|
||||
const StringMap<unsigned> OpcodeNameToOpcodeIdx;
|
||||
const StringMap<unsigned> RegNameToRegNo;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
@ -187,19 +186,18 @@ static YamlContext &getTypedContext(void *Ctx) {
|
||||
return *reinterpret_cast<YamlContext *>(Ctx);
|
||||
}
|
||||
|
||||
// std::vector<llvm::MCInst> will be rendered as a list.
|
||||
template <> struct SequenceElementTraits<llvm::MCInst> {
|
||||
// std::vector<MCInst> will be rendered as a list.
|
||||
template <> struct SequenceElementTraits<MCInst> {
|
||||
static const bool flow = false;
|
||||
};
|
||||
|
||||
template <> struct ScalarTraits<llvm::MCInst> {
|
||||
template <> struct ScalarTraits<MCInst> {
|
||||
|
||||
static void output(const llvm::MCInst &Value, void *Ctx,
|
||||
llvm::raw_ostream &Out) {
|
||||
static void output(const MCInst &Value, void *Ctx, raw_ostream &Out) {
|
||||
getTypedContext(Ctx).serializeMCInst(Value, Out);
|
||||
}
|
||||
|
||||
static StringRef input(StringRef Scalar, void *Ctx, llvm::MCInst &Value) {
|
||||
static StringRef input(StringRef Scalar, void *Ctx, MCInst &Value) {
|
||||
YamlContext &Context = getTypedContext(Ctx);
|
||||
Context.deserializeMCInst(Scalar, Value);
|
||||
return Context.getLastError();
|
||||
@ -254,7 +252,7 @@ template <> struct ScalarTraits<exegesis::RegisterValue> {
|
||||
static constexpr const bool kSigned = false;
|
||||
|
||||
static void output(const exegesis::RegisterValue &RV, void *Ctx,
|
||||
llvm::raw_ostream &Out) {
|
||||
raw_ostream &Out) {
|
||||
YamlContext &Context = getTypedContext(Ctx);
|
||||
Out << Context.getRegName(RV.Register) << "=0x"
|
||||
<< RV.Value.toString(kRadix, kSigned);
|
||||
@ -262,15 +260,15 @@ template <> struct ScalarTraits<exegesis::RegisterValue> {
|
||||
|
||||
static StringRef input(StringRef String, void *Ctx,
|
||||
exegesis::RegisterValue &RV) {
|
||||
llvm::SmallVector<llvm::StringRef, 2> Pieces;
|
||||
SmallVector<StringRef, 2> Pieces;
|
||||
String.split(Pieces, "=0x", /* MaxSplit */ -1,
|
||||
/* KeepEmpty */ false);
|
||||
YamlContext &Context = getTypedContext(Ctx);
|
||||
llvm::Optional<unsigned> RegNo;
|
||||
Optional<unsigned> RegNo;
|
||||
if (Pieces.size() == 2 && (RegNo = Context.getRegNo(Pieces[0]))) {
|
||||
RV.Register = *RegNo;
|
||||
const unsigned BitsNeeded = llvm::APInt::getBitsNeeded(Pieces[1], kRadix);
|
||||
RV.Value = llvm::APInt(BitsNeeded, Pieces[1], kRadix);
|
||||
const unsigned BitsNeeded = APInt::getBitsNeeded(Pieces[1], kRadix);
|
||||
RV.Value = APInt(BitsNeeded, Pieces[1], kRadix);
|
||||
} else {
|
||||
Context.getErrorStream()
|
||||
<< "Unknown initial register value: '" << String << "'";
|
||||
@ -333,16 +331,15 @@ struct MappingContextTraits<exegesis::InstructionBenchmark, YamlContext> {
|
||||
|
||||
namespace exegesis {
|
||||
|
||||
llvm::Expected<InstructionBenchmark>
|
||||
InstructionBenchmark::readYaml(const LLVMState &State,
|
||||
llvm::StringRef Filename) {
|
||||
Expected<InstructionBenchmark>
|
||||
InstructionBenchmark::readYaml(const LLVMState &State, StringRef Filename) {
|
||||
if (auto ExpectedMemoryBuffer =
|
||||
llvm::errorOrToExpected(llvm::MemoryBuffer::getFile(Filename))) {
|
||||
llvm::yaml::Input Yin(*ExpectedMemoryBuffer.get());
|
||||
errorOrToExpected(MemoryBuffer::getFile(Filename))) {
|
||||
yaml::Input Yin(*ExpectedMemoryBuffer.get());
|
||||
YamlContext Context(State);
|
||||
InstructionBenchmark Benchmark;
|
||||
if (Yin.setCurrentDocument())
|
||||
llvm::yaml::yamlize(Yin, Benchmark, /*unused*/ true, Context);
|
||||
yaml::yamlize(Yin, Benchmark, /*unused*/ true, Context);
|
||||
if (!Context.getLastError().empty())
|
||||
return make_error<Failure>(Context.getLastError());
|
||||
return Benchmark;
|
||||
@ -351,19 +348,18 @@ InstructionBenchmark::readYaml(const LLVMState &State,
|
||||
}
|
||||
}
|
||||
|
||||
llvm::Expected<std::vector<InstructionBenchmark>>
|
||||
InstructionBenchmark::readYamls(const LLVMState &State,
|
||||
llvm::StringRef Filename) {
|
||||
Expected<std::vector<InstructionBenchmark>>
|
||||
InstructionBenchmark::readYamls(const LLVMState &State, StringRef Filename) {
|
||||
if (auto ExpectedMemoryBuffer =
|
||||
llvm::errorOrToExpected(llvm::MemoryBuffer::getFile(Filename))) {
|
||||
llvm::yaml::Input Yin(*ExpectedMemoryBuffer.get());
|
||||
errorOrToExpected(MemoryBuffer::getFile(Filename))) {
|
||||
yaml::Input Yin(*ExpectedMemoryBuffer.get());
|
||||
YamlContext Context(State);
|
||||
std::vector<InstructionBenchmark> Benchmarks;
|
||||
while (Yin.setCurrentDocument()) {
|
||||
Benchmarks.emplace_back();
|
||||
yamlize(Yin, Benchmarks.back(), /*unused*/ true, Context);
|
||||
if (Yin.error())
|
||||
return llvm::errorCodeToError(Yin.error());
|
||||
return errorCodeToError(Yin.error());
|
||||
if (!Context.getLastError().empty())
|
||||
return make_error<Failure>(Context.getLastError());
|
||||
Yin.nextDocument();
|
||||
@ -374,47 +370,46 @@ InstructionBenchmark::readYamls(const LLVMState &State,
|
||||
}
|
||||
}
|
||||
|
||||
llvm::Error InstructionBenchmark::writeYamlTo(const LLVMState &State,
|
||||
llvm::raw_ostream &OS) {
|
||||
Error InstructionBenchmark::writeYamlTo(const LLVMState &State,
|
||||
raw_ostream &OS) {
|
||||
auto Cleanup = make_scope_exit([&] { OS.flush(); });
|
||||
llvm::yaml::Output Yout(OS, nullptr /*Ctx*/, 200 /*WrapColumn*/);
|
||||
yaml::Output Yout(OS, nullptr /*Ctx*/, 200 /*WrapColumn*/);
|
||||
YamlContext Context(State);
|
||||
Yout.beginDocuments();
|
||||
llvm::yaml::yamlize(Yout, *this, /*unused*/ true, Context);
|
||||
yaml::yamlize(Yout, *this, /*unused*/ true, Context);
|
||||
if (!Context.getLastError().empty())
|
||||
return make_error<Failure>(Context.getLastError());
|
||||
Yout.endDocuments();
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
llvm::Error InstructionBenchmark::readYamlFrom(const LLVMState &State,
|
||||
llvm::StringRef InputContent) {
|
||||
llvm::yaml::Input Yin(InputContent);
|
||||
Error InstructionBenchmark::readYamlFrom(const LLVMState &State,
|
||||
StringRef InputContent) {
|
||||
yaml::Input Yin(InputContent);
|
||||
YamlContext Context(State);
|
||||
if (Yin.setCurrentDocument())
|
||||
llvm::yaml::yamlize(Yin, *this, /*unused*/ true, Context);
|
||||
yaml::yamlize(Yin, *this, /*unused*/ true, Context);
|
||||
if (!Context.getLastError().empty())
|
||||
return make_error<Failure>(Context.getLastError());
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
llvm::Error InstructionBenchmark::writeYaml(const LLVMState &State,
|
||||
const llvm::StringRef Filename) {
|
||||
Error InstructionBenchmark::writeYaml(const LLVMState &State,
|
||||
const StringRef Filename) {
|
||||
if (Filename == "-") {
|
||||
if (auto Err = writeYamlTo(State, llvm::outs()))
|
||||
if (auto Err = writeYamlTo(State, outs()))
|
||||
return Err;
|
||||
} else {
|
||||
int ResultFD = 0;
|
||||
if (auto E = llvm::errorCodeToError(
|
||||
openFileForWrite(Filename, ResultFD, llvm::sys::fs::CD_CreateAlways,
|
||||
llvm::sys::fs::OF_Text))) {
|
||||
if (auto E = errorCodeToError(openFileForWrite(
|
||||
Filename, ResultFD, sys::fs::CD_CreateAlways, sys::fs::OF_Text))) {
|
||||
return E;
|
||||
}
|
||||
llvm::raw_fd_ostream Ostr(ResultFD, true /*shouldClose*/);
|
||||
raw_fd_ostream Ostr(ResultFD, true /*shouldClose*/);
|
||||
if (auto Err = writeYamlTo(State, Ostr))
|
||||
return Err;
|
||||
}
|
||||
return llvm::Error::success();
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
void PerInstructionStats::push(const BenchmarkMeasure &BM) {
|
||||
|
@ -32,7 +32,7 @@ namespace exegesis {
|
||||
|
||||
struct InstructionBenchmarkKey {
|
||||
// The LLVM opcode name.
|
||||
std::vector<llvm::MCInst> Instructions;
|
||||
std::vector<MCInst> Instructions;
|
||||
// The initial values of the registers.
|
||||
std::vector<RegisterValue> RegisterInitialValues;
|
||||
// An opaque configuration, that can be used to separate several benchmarks of
|
||||
@ -62,7 +62,7 @@ struct InstructionBenchmark {
|
||||
std::string CpuName;
|
||||
std::string LLVMTriple;
|
||||
// Which instruction is being benchmarked here?
|
||||
const llvm::MCInst &keyInstruction() const { return Key.Instructions[0]; }
|
||||
const MCInst &keyInstruction() const { return Key.Instructions[0]; }
|
||||
// The number of instructions inside the repeated snippet. For example, if a
|
||||
// snippet of 3 instructions is repeated 4 times, this is 12.
|
||||
int NumRepetitions = 0;
|
||||
@ -75,19 +75,18 @@ struct InstructionBenchmark {
|
||||
std::vector<uint8_t> AssembledSnippet;
|
||||
|
||||
// Read functions.
|
||||
static llvm::Expected<InstructionBenchmark>
|
||||
readYaml(const LLVMState &State, llvm::StringRef Filename);
|
||||
static Expected<InstructionBenchmark> readYaml(const LLVMState &State,
|
||||
StringRef Filename);
|
||||
|
||||
static llvm::Expected<std::vector<InstructionBenchmark>>
|
||||
readYamls(const LLVMState &State, llvm::StringRef Filename);
|
||||
static Expected<std::vector<InstructionBenchmark>>
|
||||
readYamls(const LLVMState &State, StringRef Filename);
|
||||
|
||||
llvm::Error readYamlFrom(const LLVMState &State,
|
||||
llvm::StringRef InputContent);
|
||||
class Error readYamlFrom(const LLVMState &State, StringRef InputContent);
|
||||
|
||||
// Write functions, non-const because of YAML traits.
|
||||
llvm::Error writeYamlTo(const LLVMState &State, llvm::raw_ostream &S);
|
||||
class Error writeYamlTo(const LLVMState &State, raw_ostream &S);
|
||||
|
||||
llvm::Error writeYaml(const LLVMState &State, const llvm::StringRef Filename);
|
||||
class Error writeYaml(const LLVMState &State, const StringRef Filename);
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
@ -35,37 +35,36 @@ namespace {
|
||||
class FunctionExecutorImpl : public BenchmarkRunner::FunctionExecutor {
|
||||
public:
|
||||
FunctionExecutorImpl(const LLVMState &State,
|
||||
llvm::object::OwningBinary<llvm::object::ObjectFile> Obj,
|
||||
object::OwningBinary<object::ObjectFile> Obj,
|
||||
BenchmarkRunner::ScratchSpace *Scratch)
|
||||
: Function(State.createTargetMachine(), std::move(Obj)),
|
||||
Scratch(Scratch) {}
|
||||
|
||||
private:
|
||||
llvm::Expected<int64_t> runAndMeasure(const char *Counters) const override {
|
||||
Expected<int64_t> runAndMeasure(const char *Counters) const override {
|
||||
// We sum counts when there are several counters for a single ProcRes
|
||||
// (e.g. P23 on SandyBridge).
|
||||
int64_t CounterValue = 0;
|
||||
llvm::SmallVector<llvm::StringRef, 2> CounterNames;
|
||||
llvm::StringRef(Counters).split(CounterNames, '+');
|
||||
SmallVector<StringRef, 2> CounterNames;
|
||||
StringRef(Counters).split(CounterNames, '+');
|
||||
char *const ScratchPtr = Scratch->ptr();
|
||||
for (auto &CounterName : CounterNames) {
|
||||
CounterName = CounterName.trim();
|
||||
pfm::PerfEvent PerfEvent(CounterName);
|
||||
if (!PerfEvent.valid())
|
||||
llvm::report_fatal_error(llvm::Twine("invalid perf event '")
|
||||
.concat(CounterName)
|
||||
.concat("'"));
|
||||
report_fatal_error(
|
||||
Twine("invalid perf event '").concat(CounterName).concat("'"));
|
||||
pfm::Counter Counter(PerfEvent);
|
||||
Scratch->clear();
|
||||
{
|
||||
llvm::CrashRecoveryContext CRC;
|
||||
llvm::CrashRecoveryContext::Enable();
|
||||
CrashRecoveryContext CRC;
|
||||
CrashRecoveryContext::Enable();
|
||||
const bool Crashed = !CRC.RunSafely([this, &Counter, ScratchPtr]() {
|
||||
Counter.start();
|
||||
this->Function(ScratchPtr);
|
||||
Counter.stop();
|
||||
});
|
||||
llvm::CrashRecoveryContext::Disable();
|
||||
CrashRecoveryContext::Disable();
|
||||
// FIXME: Better diagnosis.
|
||||
if (Crashed)
|
||||
return make_error<Failure>("snippet crashed while running");
|
||||
@ -91,7 +90,7 @@ InstructionBenchmark BenchmarkRunner::runConfiguration(
|
||||
InstrBenchmark.NumRepetitions = NumRepetitions;
|
||||
InstrBenchmark.Info = BC.Info;
|
||||
|
||||
const std::vector<llvm::MCInst> &Instructions = BC.Key.Instructions;
|
||||
const std::vector<MCInst> &Instructions = BC.Key.Instructions;
|
||||
|
||||
InstrBenchmark.Key = BC.Key;
|
||||
|
||||
@ -100,8 +99,8 @@ InstructionBenchmark BenchmarkRunner::runConfiguration(
|
||||
// that the inside instructions are repeated.
|
||||
constexpr const int kMinInstructionsForSnippet = 16;
|
||||
{
|
||||
llvm::SmallString<0> Buffer;
|
||||
llvm::raw_svector_ostream OS(Buffer);
|
||||
SmallString<0> Buffer;
|
||||
raw_svector_ostream OS(Buffer);
|
||||
assembleToStream(State.getExegesisTarget(), State.createTargetMachine(),
|
||||
BC.LiveIns, BC.Key.RegisterInitialValues,
|
||||
Repetitor.Repeat(Instructions, kMinInstructionsForSnippet),
|
||||
@ -117,19 +116,19 @@ InstructionBenchmark BenchmarkRunner::runConfiguration(
|
||||
const auto Filler =
|
||||
Repetitor.Repeat(Instructions, InstrBenchmark.NumRepetitions);
|
||||
|
||||
llvm::object::OwningBinary<llvm::object::ObjectFile> ObjectFile;
|
||||
object::OwningBinary<object::ObjectFile> ObjectFile;
|
||||
if (DumpObjectToDisk) {
|
||||
auto ObjectFilePath = writeObjectFile(BC, Filler);
|
||||
if (llvm::Error E = ObjectFilePath.takeError()) {
|
||||
InstrBenchmark.Error = llvm::toString(std::move(E));
|
||||
if (Error E = ObjectFilePath.takeError()) {
|
||||
InstrBenchmark.Error = toString(std::move(E));
|
||||
return InstrBenchmark;
|
||||
}
|
||||
llvm::outs() << "Check generated assembly with: /usr/bin/objdump -d "
|
||||
<< *ObjectFilePath << "\n";
|
||||
outs() << "Check generated assembly with: /usr/bin/objdump -d "
|
||||
<< *ObjectFilePath << "\n";
|
||||
ObjectFile = getObjectFromFile(*ObjectFilePath);
|
||||
} else {
|
||||
llvm::SmallString<0> Buffer;
|
||||
llvm::raw_svector_ostream OS(Buffer);
|
||||
SmallString<0> Buffer;
|
||||
raw_svector_ostream OS(Buffer);
|
||||
assembleToStream(State.getExegesisTarget(), State.createTargetMachine(),
|
||||
BC.LiveIns, BC.Key.RegisterInitialValues, Filler, OS);
|
||||
ObjectFile = getObjectFromBuffer(OS.str());
|
||||
@ -138,8 +137,8 @@ InstructionBenchmark BenchmarkRunner::runConfiguration(
|
||||
const FunctionExecutorImpl Executor(State, std::move(ObjectFile),
|
||||
Scratch.get());
|
||||
auto Measurements = runMeasurements(Executor);
|
||||
if (llvm::Error E = Measurements.takeError()) {
|
||||
InstrBenchmark.Error = llvm::toString(std::move(E));
|
||||
if (Error E = Measurements.takeError()) {
|
||||
InstrBenchmark.Error = toString(std::move(E));
|
||||
return InstrBenchmark;
|
||||
}
|
||||
InstrBenchmark.Measurements = std::move(*Measurements);
|
||||
@ -155,15 +154,15 @@ InstructionBenchmark BenchmarkRunner::runConfiguration(
|
||||
return InstrBenchmark;
|
||||
}
|
||||
|
||||
llvm::Expected<std::string>
|
||||
Expected<std::string>
|
||||
BenchmarkRunner::writeObjectFile(const BenchmarkCode &BC,
|
||||
const FillFunction &FillFunction) const {
|
||||
int ResultFD = 0;
|
||||
llvm::SmallString<256> ResultPath;
|
||||
if (llvm::Error E = llvm::errorCodeToError(llvm::sys::fs::createTemporaryFile(
|
||||
"snippet", "o", ResultFD, ResultPath)))
|
||||
SmallString<256> ResultPath;
|
||||
if (Error E = errorCodeToError(
|
||||
sys::fs::createTemporaryFile("snippet", "o", ResultFD, ResultPath)))
|
||||
return std::move(E);
|
||||
llvm::raw_fd_ostream OFS(ResultFD, true /*ShouldClose*/);
|
||||
raw_fd_ostream OFS(ResultFD, true /*ShouldClose*/);
|
||||
assembleToStream(State.getExegesisTarget(), State.createTargetMachine(),
|
||||
BC.LiveIns, BC.Key.RegisterInitialValues, FillFunction, OFS);
|
||||
return ResultPath.str();
|
||||
|
@ -65,8 +65,7 @@ public:
|
||||
class FunctionExecutor {
|
||||
public:
|
||||
virtual ~FunctionExecutor();
|
||||
virtual llvm::Expected<int64_t>
|
||||
runAndMeasure(const char *Counters) const = 0;
|
||||
virtual Expected<int64_t> runAndMeasure(const char *Counters) const = 0;
|
||||
};
|
||||
|
||||
protected:
|
||||
@ -74,12 +73,11 @@ protected:
|
||||
const InstructionBenchmark::ModeE Mode;
|
||||
|
||||
private:
|
||||
virtual llvm::Expected<std::vector<BenchmarkMeasure>>
|
||||
virtual Expected<std::vector<BenchmarkMeasure>>
|
||||
runMeasurements(const FunctionExecutor &Executor) const = 0;
|
||||
|
||||
llvm::Expected<std::string>
|
||||
writeObjectFile(const BenchmarkCode &Configuration,
|
||||
const FillFunction &Fill) const;
|
||||
Expected<std::string> writeObjectFile(const BenchmarkCode &Configuration,
|
||||
const FillFunction &Fill) const;
|
||||
|
||||
const std::unique_ptr<ScratchSpace> Scratch;
|
||||
};
|
||||
|
@ -59,7 +59,7 @@ bool InstructionBenchmarkClustering::areAllNeighbours(
|
||||
ArrayRef<size_t> Pts) const {
|
||||
// First, get the centroid of this group of points. This is O(N).
|
||||
SchedClassClusterCentroid G;
|
||||
llvm::for_each(Pts, [this, &G](size_t P) {
|
||||
for_each(Pts, [this, &G](size_t P) {
|
||||
assert(P < Points_.size());
|
||||
ArrayRef<BenchmarkMeasure> Measurements = Points_[P].Measurements;
|
||||
if (Measurements.empty()) // Error point.
|
||||
@ -73,7 +73,7 @@ bool InstructionBenchmarkClustering::areAllNeighbours(
|
||||
AnalysisClusteringEpsilonSquared_ / 4.0;
|
||||
|
||||
// And now check that every point is a neighbour of the centroid. Also O(N).
|
||||
return llvm::all_of(
|
||||
return all_of(
|
||||
Pts, [this, &Centroid, AnalysisClusteringEpsilonHalvedSquared](size_t P) {
|
||||
assert(P < Points_.size());
|
||||
const auto &PMeasurements = Points_[P].Measurements;
|
||||
@ -91,7 +91,7 @@ InstructionBenchmarkClustering::InstructionBenchmarkClustering(
|
||||
AnalysisClusteringEpsilonSquared_(AnalysisClusteringEpsilonSquared),
|
||||
NoiseCluster_(ClusterId::noise()), ErrorCluster_(ClusterId::error()) {}
|
||||
|
||||
llvm::Error InstructionBenchmarkClustering::validateAndSetup() {
|
||||
Error InstructionBenchmarkClustering::validateAndSetup() {
|
||||
ClusterIdForPoint_.resize(Points_.size());
|
||||
// Mark erroneous measurements out.
|
||||
// All points must have the same number of dimensions, in the same order.
|
||||
@ -106,15 +106,14 @@ llvm::Error InstructionBenchmarkClustering::validateAndSetup() {
|
||||
const auto *CurMeasurement = &Point.Measurements;
|
||||
if (LastMeasurement) {
|
||||
if (LastMeasurement->size() != CurMeasurement->size()) {
|
||||
return llvm::make_error<llvm::StringError>(
|
||||
"inconsistent measurement dimensions",
|
||||
llvm::inconvertibleErrorCode());
|
||||
return make_error<StringError>("inconsistent measurement dimensions",
|
||||
inconvertibleErrorCode());
|
||||
}
|
||||
for (size_t I = 0, E = LastMeasurement->size(); I < E; ++I) {
|
||||
if (LastMeasurement->at(I).Key != CurMeasurement->at(I).Key) {
|
||||
return llvm::make_error<llvm::StringError>(
|
||||
return make_error<StringError>(
|
||||
"inconsistent measurement dimensions keys",
|
||||
llvm::inconvertibleErrorCode());
|
||||
inconvertibleErrorCode());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -123,7 +122,7 @@ llvm::Error InstructionBenchmarkClustering::validateAndSetup() {
|
||||
if (LastMeasurement) {
|
||||
NumDimensions_ = LastMeasurement->size();
|
||||
}
|
||||
return llvm::Error::success();
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
void InstructionBenchmarkClustering::clusterizeDbScan(const size_t MinPts) {
|
||||
@ -146,7 +145,7 @@ void InstructionBenchmarkClustering::clusterizeDbScan(const size_t MinPts) {
|
||||
CurrentCluster.PointIndices.push_back(P);
|
||||
|
||||
// Process P's neighbors.
|
||||
llvm::SetVector<size_t, std::deque<size_t>> ToProcess;
|
||||
SetVector<size_t, std::deque<size_t>> ToProcess;
|
||||
ToProcess.insert(Neighbors.begin(), Neighbors.end());
|
||||
while (!ToProcess.empty()) {
|
||||
// Retrieve a point from the set.
|
||||
@ -185,14 +184,14 @@ void InstructionBenchmarkClustering::clusterizeDbScan(const size_t MinPts) {
|
||||
|
||||
void InstructionBenchmarkClustering::clusterizeNaive(unsigned NumOpcodes) {
|
||||
// Given an instruction Opcode, which are the benchmarks of this instruction?
|
||||
std::vector<llvm::SmallVector<size_t, 1>> OpcodeToPoints;
|
||||
std::vector<SmallVector<size_t, 1>> OpcodeToPoints;
|
||||
OpcodeToPoints.resize(NumOpcodes);
|
||||
size_t NumOpcodesSeen = 0;
|
||||
for (size_t P = 0, NumPoints = Points_.size(); P < NumPoints; ++P) {
|
||||
const InstructionBenchmark &Point = Points_[P];
|
||||
const unsigned Opcode = Point.keyInstruction().getOpcode();
|
||||
assert(Opcode < NumOpcodes && "NumOpcodes is incorrect (too small)");
|
||||
llvm::SmallVectorImpl<size_t> &PointsOfOpcode = OpcodeToPoints[Opcode];
|
||||
SmallVectorImpl<size_t> &PointsOfOpcode = OpcodeToPoints[Opcode];
|
||||
if (PointsOfOpcode.empty()) // If we previously have not seen any points of
|
||||
++NumOpcodesSeen; // this opcode, then naturally this is the new opcode.
|
||||
PointsOfOpcode.emplace_back(P);
|
||||
@ -204,16 +203,16 @@ void InstructionBenchmarkClustering::clusterizeNaive(unsigned NumOpcodes) {
|
||||
"can't see more opcodes than there are total points");
|
||||
|
||||
Clusters_.reserve(NumOpcodesSeen); // One cluster per opcode.
|
||||
for (ArrayRef<size_t> PointsOfOpcode : llvm::make_filter_range(
|
||||
OpcodeToPoints, [](ArrayRef<size_t> PointsOfOpcode) {
|
||||
return !PointsOfOpcode.empty(); // Ignore opcodes with no points.
|
||||
})) {
|
||||
for (ArrayRef<size_t> PointsOfOpcode :
|
||||
make_filter_range(OpcodeToPoints, [](ArrayRef<size_t> PointsOfOpcode) {
|
||||
return !PointsOfOpcode.empty(); // Ignore opcodes with no points.
|
||||
})) {
|
||||
// Create a new cluster.
|
||||
Clusters_.emplace_back(ClusterId::makeValid(
|
||||
Clusters_.size(), /*IsUnstable=*/!areAllNeighbours(PointsOfOpcode)));
|
||||
Cluster &CurrentCluster = Clusters_.back();
|
||||
// Mark points as belonging to the new cluster.
|
||||
llvm::for_each(PointsOfOpcode, [this, &CurrentCluster](size_t P) {
|
||||
for_each(PointsOfOpcode, [this, &CurrentCluster](size_t P) {
|
||||
ClusterIdForPoint_[P] = CurrentCluster.Id;
|
||||
});
|
||||
// And add all the points of this opcode to the new cluster.
|
||||
@ -250,8 +249,7 @@ void InstructionBenchmarkClustering::stabilize(unsigned NumOpcodes) {
|
||||
bool operator<(const OpcodeAndConfig &O) const { return Tie() < O.Tie(); }
|
||||
bool operator!=(const OpcodeAndConfig &O) const { return Tie() != O.Tie(); }
|
||||
};
|
||||
std::map<OpcodeAndConfig, llvm::SmallSet<ClusterId, 1>>
|
||||
OpcodeConfigToClusterIDs;
|
||||
std::map<OpcodeAndConfig, SmallSet<ClusterId, 1>> OpcodeConfigToClusterIDs;
|
||||
// Populate OpcodeConfigToClusterIDs and UnstableOpcodes data structures.
|
||||
assert(ClusterIdForPoint_.size() == Points_.size() && "size mismatch");
|
||||
for (const auto &Point : zip(Points_, ClusterIdForPoint_)) {
|
||||
@ -259,14 +257,12 @@ void InstructionBenchmarkClustering::stabilize(unsigned NumOpcodes) {
|
||||
if (!ClusterIdOfPoint.isValid())
|
||||
continue; // Only process fully valid clusters.
|
||||
const OpcodeAndConfig Key(std::get<0>(Point));
|
||||
llvm::SmallSet<ClusterId, 1> &ClusterIDsOfOpcode =
|
||||
OpcodeConfigToClusterIDs[Key];
|
||||
SmallSet<ClusterId, 1> &ClusterIDsOfOpcode = OpcodeConfigToClusterIDs[Key];
|
||||
ClusterIDsOfOpcode.insert(ClusterIdOfPoint);
|
||||
}
|
||||
|
||||
for (const auto &OpcodeConfigToClusterID : OpcodeConfigToClusterIDs) {
|
||||
const llvm::SmallSet<ClusterId, 1> &ClusterIDs =
|
||||
OpcodeConfigToClusterID.second;
|
||||
const SmallSet<ClusterId, 1> &ClusterIDs = OpcodeConfigToClusterID.second;
|
||||
const OpcodeAndConfig &Key = OpcodeConfigToClusterID.first;
|
||||
// We only care about unstable instructions.
|
||||
if (ClusterIDs.size() < 2)
|
||||
@ -317,11 +313,10 @@ void InstructionBenchmarkClustering::stabilize(unsigned NumOpcodes) {
|
||||
}
|
||||
}
|
||||
|
||||
llvm::Expected<InstructionBenchmarkClustering>
|
||||
InstructionBenchmarkClustering::create(
|
||||
Expected<InstructionBenchmarkClustering> InstructionBenchmarkClustering::create(
|
||||
const std::vector<InstructionBenchmark> &Points, const ModeE Mode,
|
||||
const size_t DbscanMinPts, const double AnalysisClusteringEpsilon,
|
||||
llvm::Optional<unsigned> NumOpcodes) {
|
||||
Optional<unsigned> NumOpcodes) {
|
||||
InstructionBenchmarkClustering Clustering(
|
||||
Points, AnalysisClusteringEpsilon * AnalysisClusteringEpsilon);
|
||||
if (auto Error = Clustering.validateAndSetup()) {
|
||||
@ -338,7 +333,7 @@ InstructionBenchmarkClustering::create(
|
||||
Clustering.stabilize(NumOpcodes.getValue());
|
||||
} else /*if(Mode == ModeE::Naive)*/ {
|
||||
if (!NumOpcodes.hasValue())
|
||||
llvm::report_fatal_error(
|
||||
report_fatal_error(
|
||||
"'naive' clustering mode requires opcode count to be specified");
|
||||
Clustering.clusterizeNaive(NumOpcodes.getValue());
|
||||
}
|
||||
@ -352,13 +347,13 @@ void SchedClassClusterCentroid::addPoint(ArrayRef<BenchmarkMeasure> Point) {
|
||||
assert(Representative.size() == Point.size() &&
|
||||
"All points should have identical dimensions.");
|
||||
|
||||
for (const auto &I : llvm::zip(Representative, Point))
|
||||
for (const auto &I : zip(Representative, Point))
|
||||
std::get<0>(I).push(std::get<1>(I));
|
||||
}
|
||||
|
||||
std::vector<BenchmarkMeasure> SchedClassClusterCentroid::getAsPoint() const {
|
||||
std::vector<BenchmarkMeasure> ClusterCenterPoint(Representative.size());
|
||||
for (const auto &I : llvm::zip(ClusterCenterPoint, Representative))
|
||||
for (const auto &I : zip(ClusterCenterPoint, Representative))
|
||||
std::get<0>(I).PerInstructionValue = std::get<1>(I).avg();
|
||||
return ClusterCenterPoint;
|
||||
}
|
||||
@ -369,7 +364,7 @@ bool SchedClassClusterCentroid::validate(
|
||||
switch (Mode) {
|
||||
case InstructionBenchmark::Latency:
|
||||
if (NumMeasurements != 1) {
|
||||
llvm::errs()
|
||||
errs()
|
||||
<< "invalid number of measurements in latency mode: expected 1, got "
|
||||
<< NumMeasurements << "\n";
|
||||
return false;
|
||||
@ -380,9 +375,9 @@ bool SchedClassClusterCentroid::validate(
|
||||
break;
|
||||
case InstructionBenchmark::InverseThroughput:
|
||||
if (NumMeasurements != 1) {
|
||||
llvm::errs() << "invalid number of measurements in inverse throughput "
|
||||
"mode: expected 1, got "
|
||||
<< NumMeasurements << "\n";
|
||||
errs() << "invalid number of measurements in inverse throughput "
|
||||
"mode: expected 1, got "
|
||||
<< NumMeasurements << "\n";
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
@ -29,10 +29,10 @@ public:
|
||||
|
||||
// Clusters `Points` using DBSCAN with the given parameters. See the cc file
|
||||
// for more explanations on the algorithm.
|
||||
static llvm::Expected<InstructionBenchmarkClustering>
|
||||
static Expected<InstructionBenchmarkClustering>
|
||||
create(const std::vector<InstructionBenchmark> &Points, ModeE Mode,
|
||||
size_t DbscanMinPts, double AnalysisClusteringEpsilon,
|
||||
llvm::Optional<unsigned> NumOpcodes = llvm::None);
|
||||
Optional<unsigned> NumOpcodes = None);
|
||||
|
||||
class ClusterId {
|
||||
public:
|
||||
@ -123,7 +123,7 @@ private:
|
||||
const std::vector<InstructionBenchmark> &Points,
|
||||
double AnalysisClusteringEpsilonSquared);
|
||||
|
||||
llvm::Error validateAndSetup();
|
||||
Error validateAndSetup();
|
||||
|
||||
void clusterizeDbScan(size_t MinPts);
|
||||
void clusterizeNaive(unsigned NumOpcodes);
|
||||
|
@ -32,32 +32,30 @@ unsigned InstructionTemplate::getOpcode() const {
|
||||
return Instr.Description->getOpcode();
|
||||
}
|
||||
|
||||
llvm::MCOperand &InstructionTemplate::getValueFor(const Variable &Var) {
|
||||
MCOperand &InstructionTemplate::getValueFor(const Variable &Var) {
|
||||
return VariableValues[Var.getIndex()];
|
||||
}
|
||||
|
||||
const llvm::MCOperand &
|
||||
InstructionTemplate::getValueFor(const Variable &Var) const {
|
||||
const MCOperand &InstructionTemplate::getValueFor(const Variable &Var) const {
|
||||
return VariableValues[Var.getIndex()];
|
||||
}
|
||||
|
||||
llvm::MCOperand &InstructionTemplate::getValueFor(const Operand &Op) {
|
||||
MCOperand &InstructionTemplate::getValueFor(const Operand &Op) {
|
||||
return getValueFor(Instr.Variables[Op.getVariableIndex()]);
|
||||
}
|
||||
|
||||
const llvm::MCOperand &
|
||||
InstructionTemplate::getValueFor(const Operand &Op) const {
|
||||
const MCOperand &InstructionTemplate::getValueFor(const Operand &Op) const {
|
||||
return getValueFor(Instr.Variables[Op.getVariableIndex()]);
|
||||
}
|
||||
|
||||
bool InstructionTemplate::hasImmediateVariables() const {
|
||||
return llvm::any_of(Instr.Variables, [this](const Variable &Var) {
|
||||
return any_of(Instr.Variables, [this](const Variable &Var) {
|
||||
return Instr.getPrimaryOperand(Var).isImmediate();
|
||||
});
|
||||
}
|
||||
|
||||
llvm::MCInst InstructionTemplate::build() const {
|
||||
llvm::MCInst Result;
|
||||
MCInst InstructionTemplate::build() const {
|
||||
MCInst Result;
|
||||
Result.setOpcode(Instr.Description->Opcode);
|
||||
for (const auto &Op : Instr.Operands)
|
||||
if (Op.isExplicit())
|
||||
@ -66,10 +64,10 @@ llvm::MCInst InstructionTemplate::build() const {
|
||||
}
|
||||
|
||||
bool isEnumValue(ExecutionMode Execution) {
|
||||
return llvm::isPowerOf2_32(static_cast<uint32_t>(Execution));
|
||||
return isPowerOf2_32(static_cast<uint32_t>(Execution));
|
||||
}
|
||||
|
||||
llvm::StringRef getName(ExecutionMode Bit) {
|
||||
StringRef getName(ExecutionMode Bit) {
|
||||
assert(isEnumValue(Bit) && "Bit must be a power of two");
|
||||
switch (Bit) {
|
||||
case ExecutionMode::UNKNOWN:
|
||||
@ -92,7 +90,7 @@ llvm::StringRef getName(ExecutionMode Bit) {
|
||||
llvm_unreachable("Missing enum case");
|
||||
}
|
||||
|
||||
llvm::ArrayRef<ExecutionMode> getAllExecutionBits() {
|
||||
ArrayRef<ExecutionMode> getAllExecutionBits() {
|
||||
static const ExecutionMode kAllExecutionModeBits[] = {
|
||||
ExecutionMode::ALWAYS_SERIAL_IMPLICIT_REGS_ALIAS,
|
||||
ExecutionMode::ALWAYS_SERIAL_TIED_REGS_ALIAS,
|
||||
@ -102,12 +100,11 @@ llvm::ArrayRef<ExecutionMode> getAllExecutionBits() {
|
||||
ExecutionMode::ALWAYS_PARALLEL_MISSING_USE_OR_DEF,
|
||||
ExecutionMode::PARALLEL_VIA_EXPLICIT_REGS,
|
||||
};
|
||||
return llvm::makeArrayRef(kAllExecutionModeBits);
|
||||
return makeArrayRef(kAllExecutionModeBits);
|
||||
}
|
||||
|
||||
llvm::SmallVector<ExecutionMode, 4>
|
||||
getExecutionModeBits(ExecutionMode Execution) {
|
||||
llvm::SmallVector<ExecutionMode, 4> Result;
|
||||
SmallVector<ExecutionMode, 4> getExecutionModeBits(ExecutionMode Execution) {
|
||||
SmallVector<ExecutionMode, 4> Result;
|
||||
for (const auto Bit : getAllExecutionBits())
|
||||
if ((Execution & Bit) == Bit)
|
||||
Result.push_back(Bit);
|
||||
|
@ -31,19 +31,19 @@ struct InstructionTemplate {
|
||||
InstructionTemplate &operator=(InstructionTemplate &&); // default
|
||||
|
||||
unsigned getOpcode() const;
|
||||
llvm::MCOperand &getValueFor(const Variable &Var);
|
||||
const llvm::MCOperand &getValueFor(const Variable &Var) const;
|
||||
llvm::MCOperand &getValueFor(const Operand &Op);
|
||||
const llvm::MCOperand &getValueFor(const Operand &Op) const;
|
||||
MCOperand &getValueFor(const Variable &Var);
|
||||
const MCOperand &getValueFor(const Variable &Var) const;
|
||||
MCOperand &getValueFor(const Operand &Op);
|
||||
const MCOperand &getValueFor(const Operand &Op) const;
|
||||
bool hasImmediateVariables() const;
|
||||
|
||||
// Builds an llvm::MCInst from this InstructionTemplate setting its operands
|
||||
// Builds an MCInst from this InstructionTemplate setting its operands
|
||||
// to the corresponding variable values. Precondition: All VariableValues must
|
||||
// be set.
|
||||
llvm::MCInst build() const;
|
||||
MCInst build() const;
|
||||
|
||||
Instruction Instr;
|
||||
llvm::SmallVector<llvm::MCOperand, 4> VariableValues;
|
||||
SmallVector<MCOperand, 4> VariableValues;
|
||||
};
|
||||
|
||||
enum class ExecutionMode : uint8_t {
|
||||
@ -91,14 +91,14 @@ enum class ExecutionMode : uint8_t {
|
||||
bool isEnumValue(ExecutionMode Execution);
|
||||
|
||||
// Returns a human readable string for the enum.
|
||||
llvm::StringRef getName(ExecutionMode Execution);
|
||||
StringRef getName(ExecutionMode Execution);
|
||||
|
||||
// Returns a sequence of increasing powers of two corresponding to all the
|
||||
// Execution flags.
|
||||
llvm::ArrayRef<ExecutionMode> getAllExecutionBits();
|
||||
ArrayRef<ExecutionMode> getAllExecutionBits();
|
||||
|
||||
// Decomposes Execution into individual set bits.
|
||||
llvm::SmallVector<ExecutionMode, 4> getExecutionModeBits(ExecutionMode);
|
||||
SmallVector<ExecutionMode, 4> getExecutionModeBits(ExecutionMode);
|
||||
|
||||
LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
|
||||
|
||||
|
@ -84,7 +84,7 @@ static void appendCodeTemplates(const LLVMState &State,
|
||||
const Instruction &Instr,
|
||||
const BitVector &ForbiddenRegisters,
|
||||
ExecutionMode ExecutionModeBit,
|
||||
llvm::StringRef ExecutionClassDescription,
|
||||
StringRef ExecutionClassDescription,
|
||||
std::vector<CodeTemplate> &CodeTemplates) {
|
||||
assert(isEnumValue(ExecutionModeBit) && "Bit must be a power of two");
|
||||
switch (ExecutionModeBit) {
|
||||
@ -151,7 +151,7 @@ static void appendCodeTemplates(const LLVMState &State,
|
||||
|
||||
LatencySnippetGenerator::~LatencySnippetGenerator() = default;
|
||||
|
||||
llvm::Expected<std::vector<CodeTemplate>>
|
||||
Expected<std::vector<CodeTemplate>>
|
||||
LatencySnippetGenerator::generateCodeTemplates(
|
||||
const Instruction &Instr, const BitVector &ForbiddenRegisters) const {
|
||||
std::vector<CodeTemplate> Results;
|
||||
@ -179,8 +179,7 @@ LatencyBenchmarkRunner::LatencyBenchmarkRunner(const LLVMState &State,
|
||||
|
||||
LatencyBenchmarkRunner::~LatencyBenchmarkRunner() = default;
|
||||
|
||||
llvm::Expected<std::vector<BenchmarkMeasure>>
|
||||
LatencyBenchmarkRunner::runMeasurements(
|
||||
Expected<std::vector<BenchmarkMeasure>> LatencyBenchmarkRunner::runMeasurements(
|
||||
const FunctionExecutor &Executor) const {
|
||||
// Cycle measurements include some overhead from the kernel. Repeat the
|
||||
// measure several times and take the minimum value.
|
||||
@ -188,7 +187,7 @@ LatencyBenchmarkRunner::runMeasurements(
|
||||
int64_t MinValue = std::numeric_limits<int64_t>::max();
|
||||
const char *CounterName = State.getPfmCounters().CycleCounter;
|
||||
if (!CounterName)
|
||||
llvm::report_fatal_error("sched model does not define a cycle counter");
|
||||
report_fatal_error("sched model does not define a cycle counter");
|
||||
for (size_t I = 0; I < NumMeasurements; ++I) {
|
||||
auto ExpectedCounterValue = Executor.runAndMeasure(CounterName);
|
||||
if (!ExpectedCounterValue)
|
||||
|
@ -27,7 +27,7 @@ public:
|
||||
using SnippetGenerator::SnippetGenerator;
|
||||
~LatencySnippetGenerator() override;
|
||||
|
||||
llvm::Expected<std::vector<CodeTemplate>>
|
||||
Expected<std::vector<CodeTemplate>>
|
||||
generateCodeTemplates(const Instruction &Instr,
|
||||
const BitVector &ForbiddenRegisters) const override;
|
||||
};
|
||||
@ -39,7 +39,7 @@ public:
|
||||
~LatencyBenchmarkRunner() override;
|
||||
|
||||
private:
|
||||
llvm::Expected<std::vector<BenchmarkMeasure>>
|
||||
Expected<std::vector<BenchmarkMeasure>>
|
||||
runMeasurements(const FunctionExecutor &Executor) const override;
|
||||
};
|
||||
} // namespace exegesis
|
||||
|
@ -24,16 +24,15 @@ namespace exegesis {
|
||||
LLVMState::LLVMState(const std::string &Triple, const std::string &CpuName,
|
||||
const std::string &Features) {
|
||||
std::string Error;
|
||||
const llvm::Target *const TheTarget =
|
||||
llvm::TargetRegistry::lookupTarget(Triple, Error);
|
||||
const Target *const TheTarget = TargetRegistry::lookupTarget(Triple, Error);
|
||||
assert(TheTarget && "unknown target for host");
|
||||
const llvm::TargetOptions Options;
|
||||
const TargetOptions Options;
|
||||
TargetMachine.reset(
|
||||
static_cast<llvm::LLVMTargetMachine *>(TheTarget->createTargetMachine(
|
||||
Triple, CpuName, Features, Options, llvm::Reloc::Model::Static)));
|
||||
static_cast<LLVMTargetMachine *>(TheTarget->createTargetMachine(
|
||||
Triple, CpuName, Features, Options, Reloc::Model::Static)));
|
||||
TheExegesisTarget = ExegesisTarget::lookup(TargetMachine->getTargetTriple());
|
||||
if (!TheExegesisTarget) {
|
||||
llvm::errs() << "no exegesis target for " << Triple << ", using default\n";
|
||||
errs() << "no exegesis target for " << Triple << ", using default\n";
|
||||
TheExegesisTarget = &ExegesisTarget::getDefault();
|
||||
}
|
||||
PfmCounters = &TheExegesisTarget->getPfmCounters(CpuName);
|
||||
@ -47,32 +46,29 @@ LLVMState::LLVMState(const std::string &Triple, const std::string &CpuName,
|
||||
}
|
||||
|
||||
LLVMState::LLVMState(const std::string &CpuName)
|
||||
: LLVMState(llvm::sys::getProcessTriple(),
|
||||
CpuName.empty() ? llvm::sys::getHostCPUName().str() : CpuName,
|
||||
"") {}
|
||||
: LLVMState(sys::getProcessTriple(),
|
||||
CpuName.empty() ? sys::getHostCPUName().str() : CpuName, "") {}
|
||||
|
||||
std::unique_ptr<llvm::LLVMTargetMachine>
|
||||
LLVMState::createTargetMachine() const {
|
||||
return std::unique_ptr<llvm::LLVMTargetMachine>(
|
||||
static_cast<llvm::LLVMTargetMachine *>(
|
||||
TargetMachine->getTarget().createTargetMachine(
|
||||
TargetMachine->getTargetTriple().normalize(),
|
||||
TargetMachine->getTargetCPU(),
|
||||
TargetMachine->getTargetFeatureString(), TargetMachine->Options,
|
||||
llvm::Reloc::Model::Static)));
|
||||
std::unique_ptr<LLVMTargetMachine> LLVMState::createTargetMachine() const {
|
||||
return std::unique_ptr<LLVMTargetMachine>(static_cast<LLVMTargetMachine *>(
|
||||
TargetMachine->getTarget().createTargetMachine(
|
||||
TargetMachine->getTargetTriple().normalize(),
|
||||
TargetMachine->getTargetCPU(),
|
||||
TargetMachine->getTargetFeatureString(), TargetMachine->Options,
|
||||
Reloc::Model::Static)));
|
||||
}
|
||||
|
||||
bool LLVMState::canAssemble(const llvm::MCInst &Inst) const {
|
||||
llvm::MCObjectFileInfo ObjectFileInfo;
|
||||
llvm::MCContext Context(TargetMachine->getMCAsmInfo(),
|
||||
TargetMachine->getMCRegisterInfo(), &ObjectFileInfo);
|
||||
std::unique_ptr<const llvm::MCCodeEmitter> CodeEmitter(
|
||||
bool LLVMState::canAssemble(const MCInst &Inst) const {
|
||||
MCObjectFileInfo ObjectFileInfo;
|
||||
MCContext Context(TargetMachine->getMCAsmInfo(),
|
||||
TargetMachine->getMCRegisterInfo(), &ObjectFileInfo);
|
||||
std::unique_ptr<const MCCodeEmitter> CodeEmitter(
|
||||
TargetMachine->getTarget().createMCCodeEmitter(
|
||||
*TargetMachine->getMCInstrInfo(), *TargetMachine->getMCRegisterInfo(),
|
||||
Context));
|
||||
llvm::SmallVector<char, 16> Tmp;
|
||||
llvm::raw_svector_ostream OS(Tmp);
|
||||
llvm::SmallVector<llvm::MCFixup, 4> Fixups;
|
||||
SmallVector<char, 16> Tmp;
|
||||
raw_svector_ostream OS(Tmp);
|
||||
SmallVector<MCFixup, 4> Fixups;
|
||||
CodeEmitter->encodeInstruction(Inst, OS, Fixups,
|
||||
*TargetMachine->getMCSubtargetInfo());
|
||||
return Tmp.size() > 0;
|
||||
|
@ -42,21 +42,21 @@ public:
|
||||
const std::string &CpuName,
|
||||
const std::string &Features = ""); // For tests.
|
||||
|
||||
const llvm::TargetMachine &getTargetMachine() const { return *TargetMachine; }
|
||||
std::unique_ptr<llvm::LLVMTargetMachine> createTargetMachine() const;
|
||||
const TargetMachine &getTargetMachine() const { return *TargetMachine; }
|
||||
std::unique_ptr<LLVMTargetMachine> createTargetMachine() const;
|
||||
|
||||
const ExegesisTarget &getExegesisTarget() const { return *TheExegesisTarget; }
|
||||
|
||||
bool canAssemble(const llvm::MCInst &mc_inst) const;
|
||||
bool canAssemble(const MCInst &mc_inst) const;
|
||||
|
||||
// For convenience:
|
||||
const llvm::MCInstrInfo &getInstrInfo() const {
|
||||
const MCInstrInfo &getInstrInfo() const {
|
||||
return *TargetMachine->getMCInstrInfo();
|
||||
}
|
||||
const llvm::MCRegisterInfo &getRegInfo() const {
|
||||
const MCRegisterInfo &getRegInfo() const {
|
||||
return *TargetMachine->getMCRegisterInfo();
|
||||
}
|
||||
const llvm::MCSubtargetInfo &getSubtargetInfo() const {
|
||||
const MCSubtargetInfo &getSubtargetInfo() const {
|
||||
return *TargetMachine->getMCSubtargetInfo();
|
||||
}
|
||||
|
||||
@ -67,7 +67,7 @@ public:
|
||||
|
||||
private:
|
||||
const ExegesisTarget *TheExegesisTarget;
|
||||
std::unique_ptr<const llvm::TargetMachine> TargetMachine;
|
||||
std::unique_ptr<const TargetMachine> TargetMachine;
|
||||
std::unique_ptr<const RegisterAliasingTrackerCache> RATC;
|
||||
std::unique_ptr<const InstructionsCache> IC;
|
||||
const PfmCountersInfo *PfmCounters;
|
||||
|
@ -59,12 +59,12 @@ bool Operand::isVariable() const { return VariableIndex >= 0; }
|
||||
|
||||
bool Operand::isMemory() const {
|
||||
return isExplicit() &&
|
||||
getExplicitOperandInfo().OperandType == llvm::MCOI::OPERAND_MEMORY;
|
||||
getExplicitOperandInfo().OperandType == MCOI::OPERAND_MEMORY;
|
||||
}
|
||||
|
||||
bool Operand::isImmediate() const {
|
||||
return isExplicit() &&
|
||||
getExplicitOperandInfo().OperandType == llvm::MCOI::OPERAND_IMMEDIATE;
|
||||
getExplicitOperandInfo().OperandType == MCOI::OPERAND_IMMEDIATE;
|
||||
}
|
||||
|
||||
unsigned Operand::getTiedToIndex() const {
|
||||
@ -89,12 +89,12 @@ const RegisterAliasingTracker &Operand::getRegisterAliasing() const {
|
||||
return *Tracker;
|
||||
}
|
||||
|
||||
const llvm::MCOperandInfo &Operand::getExplicitOperandInfo() const {
|
||||
const MCOperandInfo &Operand::getExplicitOperandInfo() const {
|
||||
assert(Info);
|
||||
return *Info;
|
||||
}
|
||||
|
||||
Instruction::Instruction(const llvm::MCInstrInfo &InstrInfo,
|
||||
Instruction::Instruction(const MCInstrInfo &InstrInfo,
|
||||
const RegisterAliasingTrackerCache &RATC,
|
||||
unsigned Opcode)
|
||||
: Description(&InstrInfo.get(Opcode)), Name(InstrInfo.getName(Opcode)) {
|
||||
@ -108,11 +108,11 @@ Instruction::Instruction(const llvm::MCInstrInfo &InstrInfo,
|
||||
if (OpInfo.RegClass >= 0)
|
||||
Operand.Tracker = &RATC.getRegisterClass(OpInfo.RegClass);
|
||||
Operand.TiedToIndex =
|
||||
Description->getOperandConstraint(OpIndex, llvm::MCOI::TIED_TO);
|
||||
Description->getOperandConstraint(OpIndex, MCOI::TIED_TO);
|
||||
Operand.Info = &OpInfo;
|
||||
Operands.push_back(Operand);
|
||||
}
|
||||
for (const llvm::MCPhysReg *MCPhysReg = Description->getImplicitDefs();
|
||||
for (const MCPhysReg *MCPhysReg = Description->getImplicitDefs();
|
||||
MCPhysReg && *MCPhysReg; ++MCPhysReg, ++OpIndex) {
|
||||
Operand Operand;
|
||||
Operand.Index = OpIndex;
|
||||
@ -121,7 +121,7 @@ Instruction::Instruction(const llvm::MCInstrInfo &InstrInfo,
|
||||
Operand.ImplicitReg = MCPhysReg;
|
||||
Operands.push_back(Operand);
|
||||
}
|
||||
for (const llvm::MCPhysReg *MCPhysReg = Description->getImplicitUses();
|
||||
for (const MCPhysReg *MCPhysReg = Description->getImplicitUses();
|
||||
MCPhysReg && *MCPhysReg; ++MCPhysReg, ++OpIndex) {
|
||||
Operand Operand;
|
||||
Operand.Index = OpIndex;
|
||||
@ -209,8 +209,8 @@ bool Instruction::hasAliasingRegistersThrough(
|
||||
}
|
||||
|
||||
bool Instruction::hasTiedRegisters() const {
|
||||
return llvm::any_of(
|
||||
Variables, [](const Variable &Var) { return Var.hasTiedOperands(); });
|
||||
return any_of(Variables,
|
||||
[](const Variable &Var) { return Var.hasTiedOperands(); });
|
||||
}
|
||||
|
||||
bool Instruction::hasAliasingRegisters(
|
||||
@ -223,9 +223,9 @@ bool Instruction::hasOneUseOrOneDef() const {
|
||||
return AllDefRegs.count() || AllUseRegs.count();
|
||||
}
|
||||
|
||||
void Instruction::dump(const llvm::MCRegisterInfo &RegInfo,
|
||||
void Instruction::dump(const MCRegisterInfo &RegInfo,
|
||||
const RegisterAliasingTrackerCache &RATC,
|
||||
llvm::raw_ostream &Stream) const {
|
||||
raw_ostream &Stream) const {
|
||||
Stream << "- " << Name << "\n";
|
||||
for (const auto &Op : Operands) {
|
||||
Stream << "- Op" << Op.getIndex();
|
||||
@ -277,7 +277,7 @@ void Instruction::dump(const llvm::MCRegisterInfo &RegInfo,
|
||||
Stream << "- hasAliasingRegisters\n";
|
||||
}
|
||||
|
||||
InstructionsCache::InstructionsCache(const llvm::MCInstrInfo &InstrInfo,
|
||||
InstructionsCache::InstructionsCache(const MCInstrInfo &InstrInfo,
|
||||
const RegisterAliasingTrackerCache &RATC)
|
||||
: InstrInfo(InstrInfo), RATC(RATC) {}
|
||||
|
||||
@ -298,9 +298,10 @@ operator==(const AliasingRegisterOperands &Other) const {
|
||||
return std::tie(Defs, Uses) == std::tie(Other.Defs, Other.Uses);
|
||||
}
|
||||
|
||||
static void addOperandIfAlias(
|
||||
const llvm::MCPhysReg Reg, bool SelectDef, llvm::ArrayRef<Operand> Operands,
|
||||
llvm::SmallVectorImpl<RegisterOperandAssignment> &OperandValues) {
|
||||
static void
|
||||
addOperandIfAlias(const MCPhysReg Reg, bool SelectDef,
|
||||
ArrayRef<Operand> Operands,
|
||||
SmallVectorImpl<RegisterOperandAssignment> &OperandValues) {
|
||||
for (const auto &Op : Operands) {
|
||||
if (Op.isReg() && Op.isDef() == SelectDef) {
|
||||
const int SourceReg = Op.getRegisterAliasing().getOrigin(Reg);
|
||||
@ -314,13 +315,13 @@ bool AliasingRegisterOperands::hasImplicitAliasing() const {
|
||||
const auto HasImplicit = [](const RegisterOperandAssignment &ROV) {
|
||||
return ROV.Op->isImplicit();
|
||||
};
|
||||
return llvm::any_of(Defs, HasImplicit) && llvm::any_of(Uses, HasImplicit);
|
||||
return any_of(Defs, HasImplicit) && any_of(Uses, HasImplicit);
|
||||
}
|
||||
|
||||
bool AliasingConfigurations::empty() const { return Configurations.empty(); }
|
||||
|
||||
bool AliasingConfigurations::hasImplicitAliasing() const {
|
||||
return llvm::any_of(Configurations, [](const AliasingRegisterOperands &ARO) {
|
||||
return any_of(Configurations, [](const AliasingRegisterOperands &ARO) {
|
||||
return ARO.hasImplicitAliasing();
|
||||
});
|
||||
}
|
||||
@ -330,19 +331,19 @@ AliasingConfigurations::AliasingConfigurations(
|
||||
if (UseInstruction.AllUseRegs.anyCommon(DefInstruction.AllDefRegs)) {
|
||||
auto CommonRegisters = UseInstruction.AllUseRegs;
|
||||
CommonRegisters &= DefInstruction.AllDefRegs;
|
||||
for (const llvm::MCPhysReg Reg : CommonRegisters.set_bits()) {
|
||||
for (const MCPhysReg Reg : CommonRegisters.set_bits()) {
|
||||
AliasingRegisterOperands ARO;
|
||||
addOperandIfAlias(Reg, true, DefInstruction.Operands, ARO.Defs);
|
||||
addOperandIfAlias(Reg, false, UseInstruction.Operands, ARO.Uses);
|
||||
if (!ARO.Defs.empty() && !ARO.Uses.empty() &&
|
||||
!llvm::is_contained(Configurations, ARO))
|
||||
!is_contained(Configurations, ARO))
|
||||
Configurations.push_back(std::move(ARO));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DumpMCOperand(const llvm::MCRegisterInfo &MCRegisterInfo,
|
||||
const llvm::MCOperand &Op, llvm::raw_ostream &OS) {
|
||||
void DumpMCOperand(const MCRegisterInfo &MCRegisterInfo, const MCOperand &Op,
|
||||
raw_ostream &OS) {
|
||||
if (!Op.isValid())
|
||||
OS << "Invalid";
|
||||
else if (Op.isReg())
|
||||
@ -357,9 +358,9 @@ void DumpMCOperand(const llvm::MCRegisterInfo &MCRegisterInfo,
|
||||
OS << "SubInst";
|
||||
}
|
||||
|
||||
void DumpMCInst(const llvm::MCRegisterInfo &MCRegisterInfo,
|
||||
const llvm::MCInstrInfo &MCInstrInfo,
|
||||
const llvm::MCInst &MCInst, llvm::raw_ostream &OS) {
|
||||
void DumpMCInst(const MCRegisterInfo &MCRegisterInfo,
|
||||
const MCInstrInfo &MCInstrInfo, const MCInst &MCInst,
|
||||
raw_ostream &OS) {
|
||||
OS << MCInstrInfo.getName(MCInst.getOpcode());
|
||||
for (unsigned I = 0, E = MCInst.getNumOperands(); I < E; ++I) {
|
||||
if (I > 0)
|
||||
|
@ -44,7 +44,7 @@ struct Variable {
|
||||
bool hasTiedOperands() const;
|
||||
|
||||
// The indices of the operands tied to this Variable.
|
||||
llvm::SmallVector<unsigned, 2> TiedOperands;
|
||||
SmallVector<unsigned, 2> TiedOperands;
|
||||
|
||||
// The index of this Variable in Instruction.Variables and its associated
|
||||
// Value in InstructionBuilder.VariableValues.
|
||||
@ -78,22 +78,22 @@ struct Operand {
|
||||
unsigned getVariableIndex() const;
|
||||
unsigned getImplicitReg() const;
|
||||
const RegisterAliasingTracker &getRegisterAliasing() const;
|
||||
const llvm::MCOperandInfo &getExplicitOperandInfo() const;
|
||||
const MCOperandInfo &getExplicitOperandInfo() const;
|
||||
|
||||
// Please use the accessors above and not the following fields.
|
||||
int Index = -1;
|
||||
bool IsDef = false;
|
||||
const RegisterAliasingTracker *Tracker = nullptr; // Set for Register Op.
|
||||
const llvm::MCOperandInfo *Info = nullptr; // Set for Explicit Op.
|
||||
const MCOperandInfo *Info = nullptr; // Set for Explicit Op.
|
||||
int TiedToIndex = -1; // Set for Reg&Explicit Op.
|
||||
const llvm::MCPhysReg *ImplicitReg = nullptr; // Set for Implicit Op.
|
||||
const MCPhysReg *ImplicitReg = nullptr; // Set for Implicit Op.
|
||||
int VariableIndex = -1; // Set for Explicit Op.
|
||||
};
|
||||
|
||||
// A view over an MCInstrDesc offering a convenient interface to compute
|
||||
// Register aliasing.
|
||||
struct Instruction {
|
||||
Instruction(const llvm::MCInstrInfo &InstrInfo,
|
||||
Instruction(const MCInstrInfo &InstrInfo,
|
||||
const RegisterAliasingTrackerCache &RATC, unsigned Opcode);
|
||||
|
||||
// Returns the Operand linked to this Variable.
|
||||
@ -129,31 +129,31 @@ struct Instruction {
|
||||
bool hasOneUseOrOneDef() const;
|
||||
|
||||
// Convenient function to help with debugging.
|
||||
void dump(const llvm::MCRegisterInfo &RegInfo,
|
||||
void dump(const MCRegisterInfo &RegInfo,
|
||||
const RegisterAliasingTrackerCache &RATC,
|
||||
llvm::raw_ostream &Stream) const;
|
||||
raw_ostream &Stream) const;
|
||||
|
||||
const llvm::MCInstrDesc *Description; // Never nullptr.
|
||||
llvm::StringRef Name; // The name of this instruction.
|
||||
llvm::SmallVector<Operand, 8> Operands;
|
||||
llvm::SmallVector<Variable, 4> Variables;
|
||||
llvm::BitVector ImplDefRegs; // The set of aliased implicit def registers.
|
||||
llvm::BitVector ImplUseRegs; // The set of aliased implicit use registers.
|
||||
llvm::BitVector AllDefRegs; // The set of all aliased def registers.
|
||||
llvm::BitVector AllUseRegs; // The set of all aliased use registers.
|
||||
const MCInstrDesc *Description; // Never nullptr.
|
||||
StringRef Name; // The name of this instruction.
|
||||
SmallVector<Operand, 8> Operands;
|
||||
SmallVector<Variable, 4> Variables;
|
||||
BitVector ImplDefRegs; // The set of aliased implicit def registers.
|
||||
BitVector ImplUseRegs; // The set of aliased implicit use registers.
|
||||
BitVector AllDefRegs; // The set of all aliased def registers.
|
||||
BitVector AllUseRegs; // The set of all aliased use registers.
|
||||
};
|
||||
|
||||
// Instructions are expensive to instantiate. This class provides a cache of
|
||||
// Instructions with lazy construction.
|
||||
struct InstructionsCache {
|
||||
InstructionsCache(const llvm::MCInstrInfo &InstrInfo,
|
||||
InstructionsCache(const MCInstrInfo &InstrInfo,
|
||||
const RegisterAliasingTrackerCache &RATC);
|
||||
|
||||
// Returns the Instruction object corresponding to this Opcode.
|
||||
const Instruction &getInstr(unsigned Opcode) const;
|
||||
|
||||
private:
|
||||
const llvm::MCInstrInfo &InstrInfo;
|
||||
const MCInstrInfo &InstrInfo;
|
||||
const RegisterAliasingTrackerCache &RATC;
|
||||
mutable std::unordered_map<unsigned, std::unique_ptr<Instruction>>
|
||||
Instructions;
|
||||
@ -161,11 +161,11 @@ private:
|
||||
|
||||
// Represents the assignment of a Register to an Operand.
|
||||
struct RegisterOperandAssignment {
|
||||
RegisterOperandAssignment(const Operand *Operand, llvm::MCPhysReg Reg)
|
||||
RegisterOperandAssignment(const Operand *Operand, MCPhysReg Reg)
|
||||
: Op(Operand), Reg(Reg) {}
|
||||
|
||||
const Operand *Op; // Pointer to an Explicit Register Operand.
|
||||
llvm::MCPhysReg Reg;
|
||||
MCPhysReg Reg;
|
||||
|
||||
bool operator==(const RegisterOperandAssignment &other) const;
|
||||
};
|
||||
@ -177,8 +177,8 @@ struct RegisterOperandAssignment {
|
||||
// other (e.g. AX/AL)
|
||||
// - The operands are tied.
|
||||
struct AliasingRegisterOperands {
|
||||
llvm::SmallVector<RegisterOperandAssignment, 1> Defs; // Unlikely size() > 1.
|
||||
llvm::SmallVector<RegisterOperandAssignment, 2> Uses;
|
||||
SmallVector<RegisterOperandAssignment, 1> Defs; // Unlikely size() > 1.
|
||||
SmallVector<RegisterOperandAssignment, 2> Uses;
|
||||
|
||||
// True is Defs and Use contain an Implicit Operand.
|
||||
bool hasImplicitAliasing() const;
|
||||
@ -195,15 +195,15 @@ struct AliasingConfigurations {
|
||||
bool empty() const; // True if no aliasing configuration is found.
|
||||
bool hasImplicitAliasing() const;
|
||||
|
||||
llvm::SmallVector<AliasingRegisterOperands, 32> Configurations;
|
||||
SmallVector<AliasingRegisterOperands, 32> Configurations;
|
||||
};
|
||||
|
||||
// Writes MCInst to OS.
|
||||
// This is not assembly but the internal LLVM's name for instructions and
|
||||
// registers.
|
||||
void DumpMCInst(const llvm::MCRegisterInfo &MCRegisterInfo,
|
||||
const llvm::MCInstrInfo &MCInstrInfo,
|
||||
const llvm::MCInst &MCInst, llvm::raw_ostream &OS);
|
||||
void DumpMCInst(const MCRegisterInfo &MCRegisterInfo,
|
||||
const MCInstrInfo &MCInstrInfo, const MCInst &MCInst,
|
||||
raw_ostream &OS);
|
||||
|
||||
} // namespace exegesis
|
||||
} // namespace llvm
|
||||
|
@ -52,7 +52,7 @@ PerfEvent::PerfEvent(PerfEvent &&Other)
|
||||
Other.Attr = nullptr;
|
||||
}
|
||||
|
||||
PerfEvent::PerfEvent(llvm::StringRef PfmEventString)
|
||||
PerfEvent::PerfEvent(StringRef PfmEventString)
|
||||
: EventString(PfmEventString.str()), Attr(nullptr) {
|
||||
#ifdef HAVE_LIBPFM
|
||||
char *Fstr = nullptr;
|
||||
@ -67,8 +67,8 @@ PerfEvent::PerfEvent(llvm::StringRef PfmEventString)
|
||||
// We don't know beforehand which counters are available (e.g. 6 uops ports
|
||||
// on Sandybridge but 8 on Haswell) so we report the missing counter without
|
||||
// crashing.
|
||||
llvm::errs() << pfm_strerror(Result) << " - cannot create event "
|
||||
<< EventString << "\n";
|
||||
errs() << pfm_strerror(Result) << " - cannot create event " << EventString
|
||||
<< "\n";
|
||||
}
|
||||
if (Fstr) {
|
||||
FullQualifiedEventString = Fstr;
|
||||
@ -77,13 +77,13 @@ PerfEvent::PerfEvent(llvm::StringRef PfmEventString)
|
||||
#endif
|
||||
}
|
||||
|
||||
llvm::StringRef PerfEvent::name() const { return EventString; }
|
||||
StringRef PerfEvent::name() const { return EventString; }
|
||||
|
||||
bool PerfEvent::valid() const { return !FullQualifiedEventString.empty(); }
|
||||
|
||||
const perf_event_attr *PerfEvent::attribute() const { return Attr; }
|
||||
|
||||
llvm::StringRef PerfEvent::getPfmEventString() const {
|
||||
StringRef PerfEvent::getPfmEventString() const {
|
||||
return FullQualifiedEventString;
|
||||
}
|
||||
|
||||
@ -97,9 +97,9 @@ Counter::Counter(const PerfEvent &Event) {
|
||||
perf_event_attr AttrCopy = *Event.attribute();
|
||||
FileDescriptor = perf_event_open(&AttrCopy, Pid, Cpu, GroupFd, Flags);
|
||||
if (FileDescriptor == -1) {
|
||||
llvm::errs() << "Unable to open event, make sure your kernel allows user "
|
||||
"space perf monitoring.\nYou may want to try:\n$ sudo sh "
|
||||
"-c 'echo -1 > /proc/sys/kernel/perf_event_paranoid'\n";
|
||||
errs() << "Unable to open event, make sure your kernel allows user "
|
||||
"space perf monitoring.\nYou may want to try:\n$ sudo sh "
|
||||
"-c 'echo -1 > /proc/sys/kernel/perf_event_paranoid'\n";
|
||||
}
|
||||
assert(FileDescriptor != -1 && "Unable to open event");
|
||||
}
|
||||
@ -115,7 +115,7 @@ int64_t Counter::read() const {
|
||||
ssize_t ReadSize = ::read(FileDescriptor, &Count, sizeof(Count));
|
||||
if (ReadSize != sizeof(Count)) {
|
||||
Count = -1;
|
||||
llvm::errs() << "Failed to read event counter\n";
|
||||
errs() << "Failed to read event counter\n";
|
||||
}
|
||||
return Count;
|
||||
}
|
||||
|
@ -36,14 +36,14 @@ class PerfEvent {
|
||||
public:
|
||||
// http://perfmon2.sourceforge.net/manv4/libpfm.html
|
||||
// Events are expressed as strings. e.g. "INSTRUCTION_RETIRED"
|
||||
explicit PerfEvent(llvm::StringRef pfm_event_string);
|
||||
explicit PerfEvent(StringRef pfm_event_string);
|
||||
|
||||
PerfEvent(const PerfEvent &) = delete;
|
||||
PerfEvent(PerfEvent &&other);
|
||||
~PerfEvent();
|
||||
|
||||
// The pfm_event_string passed at construction time.
|
||||
llvm::StringRef name() const;
|
||||
StringRef name() const;
|
||||
|
||||
// Whether the event was successfully created.
|
||||
bool valid() const;
|
||||
@ -53,7 +53,7 @@ public:
|
||||
|
||||
// The fully qualified name for the event.
|
||||
// e.g. "snb_ep::INSTRUCTION_RETIRED:e=0:i=0:c=0:t=0:u=1:k=0:mg=0:mh=1"
|
||||
llvm::StringRef getPfmEventString() const;
|
||||
StringRef getPfmEventString() const;
|
||||
|
||||
private:
|
||||
const std::string EventString;
|
||||
@ -86,7 +86,7 @@ private:
|
||||
// callback is called for each successful measure (PerfEvent needs to be valid).
|
||||
template <typename Function>
|
||||
void Measure(
|
||||
llvm::ArrayRef<PerfEvent> Events,
|
||||
ArrayRef<PerfEvent> Events,
|
||||
const std::function<void(const PerfEvent &Event, int64_t Value)> &Callback,
|
||||
Function Fn) {
|
||||
for (const auto &Event : Events) {
|
||||
|
@ -22,11 +22,10 @@ public:
|
||||
ExegesisPowerPCTarget() : ExegesisTarget(PPCCpuPfmCounters) {}
|
||||
|
||||
private:
|
||||
std::vector<llvm::MCInst> setRegTo(const llvm::MCSubtargetInfo &STI,
|
||||
unsigned Reg,
|
||||
const llvm::APInt &Value) const override;
|
||||
bool matchesArch(llvm::Triple::ArchType Arch) const override {
|
||||
return Arch == llvm::Triple::ppc64le;
|
||||
std::vector<MCInst> setRegTo(const MCSubtargetInfo &STI, unsigned Reg,
|
||||
const APInt &Value) const override;
|
||||
bool matchesArch(Triple::ArchType Arch) const override {
|
||||
return Arch == Triple::ppc64le;
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace
|
||||
@ -34,31 +33,31 @@ private:
|
||||
static unsigned getLoadImmediateOpcode(unsigned RegBitWidth) {
|
||||
switch (RegBitWidth) {
|
||||
case 32:
|
||||
return llvm::PPC::LI;
|
||||
return PPC::LI;
|
||||
case 64:
|
||||
return llvm::PPC::LI8;
|
||||
return PPC::LI8;
|
||||
}
|
||||
llvm_unreachable("Invalid Value Width");
|
||||
}
|
||||
|
||||
// Generates instruction to load an immediate value into a register.
|
||||
static llvm::MCInst loadImmediate(unsigned Reg, unsigned RegBitWidth,
|
||||
const llvm::APInt &Value) {
|
||||
static MCInst loadImmediate(unsigned Reg, unsigned RegBitWidth,
|
||||
const APInt &Value) {
|
||||
if (Value.getBitWidth() > RegBitWidth)
|
||||
llvm_unreachable("Value must fit in the Register");
|
||||
return llvm::MCInstBuilder(getLoadImmediateOpcode(RegBitWidth))
|
||||
return MCInstBuilder(getLoadImmediateOpcode(RegBitWidth))
|
||||
.addReg(Reg)
|
||||
.addImm(Value.getZExtValue());
|
||||
}
|
||||
|
||||
std::vector<llvm::MCInst>
|
||||
ExegesisPowerPCTarget::setRegTo(const llvm::MCSubtargetInfo &STI, unsigned Reg,
|
||||
const llvm::APInt &Value) const {
|
||||
if (llvm::PPC::GPRCRegClass.contains(Reg))
|
||||
std::vector<MCInst> ExegesisPowerPCTarget::setRegTo(const MCSubtargetInfo &STI,
|
||||
unsigned Reg,
|
||||
const APInt &Value) const {
|
||||
if (PPC::GPRCRegClass.contains(Reg))
|
||||
return {loadImmediate(Reg, 32, Value)};
|
||||
if (llvm::PPC::G8RCRegClass.contains(Reg))
|
||||
if (PPC::G8RCRegClass.contains(Reg))
|
||||
return {loadImmediate(Reg, 64, Value)};
|
||||
llvm::errs() << "setRegTo is not implemented, results will be unreliable\n";
|
||||
errs() << "setRegTo is not implemented, results will be unreliable\n";
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -11,11 +11,11 @@
|
||||
namespace llvm {
|
||||
namespace exegesis {
|
||||
|
||||
llvm::BitVector getAliasedBits(const llvm::MCRegisterInfo &RegInfo,
|
||||
const llvm::BitVector &SourceBits) {
|
||||
llvm::BitVector AliasedBits(RegInfo.getNumRegs());
|
||||
BitVector getAliasedBits(const MCRegisterInfo &RegInfo,
|
||||
const BitVector &SourceBits) {
|
||||
BitVector AliasedBits(RegInfo.getNumRegs());
|
||||
for (const size_t PhysReg : SourceBits.set_bits()) {
|
||||
using RegAliasItr = llvm::MCRegAliasIterator;
|
||||
using RegAliasItr = MCRegAliasIterator;
|
||||
for (auto Itr = RegAliasItr(PhysReg, &RegInfo, true); Itr.isValid();
|
||||
++Itr) {
|
||||
AliasedBits.set(*Itr);
|
||||
@ -24,31 +24,30 @@ llvm::BitVector getAliasedBits(const llvm::MCRegisterInfo &RegInfo,
|
||||
return AliasedBits;
|
||||
}
|
||||
|
||||
RegisterAliasingTracker::RegisterAliasingTracker(
|
||||
const llvm::MCRegisterInfo &RegInfo)
|
||||
RegisterAliasingTracker::RegisterAliasingTracker(const MCRegisterInfo &RegInfo)
|
||||
: SourceBits(RegInfo.getNumRegs()), AliasedBits(RegInfo.getNumRegs()),
|
||||
Origins(RegInfo.getNumRegs()) {}
|
||||
|
||||
RegisterAliasingTracker::RegisterAliasingTracker(
|
||||
const llvm::MCRegisterInfo &RegInfo, const llvm::BitVector &ReservedReg,
|
||||
const llvm::MCRegisterClass &RegClass)
|
||||
const MCRegisterInfo &RegInfo, const BitVector &ReservedReg,
|
||||
const MCRegisterClass &RegClass)
|
||||
: RegisterAliasingTracker(RegInfo) {
|
||||
for (llvm::MCPhysReg PhysReg : RegClass)
|
||||
for (MCPhysReg PhysReg : RegClass)
|
||||
if (!ReservedReg[PhysReg]) // Removing reserved registers.
|
||||
SourceBits.set(PhysReg);
|
||||
FillOriginAndAliasedBits(RegInfo, SourceBits);
|
||||
}
|
||||
|
||||
RegisterAliasingTracker::RegisterAliasingTracker(
|
||||
const llvm::MCRegisterInfo &RegInfo, const llvm::MCPhysReg PhysReg)
|
||||
RegisterAliasingTracker::RegisterAliasingTracker(const MCRegisterInfo &RegInfo,
|
||||
const MCPhysReg PhysReg)
|
||||
: RegisterAliasingTracker(RegInfo) {
|
||||
SourceBits.set(PhysReg);
|
||||
FillOriginAndAliasedBits(RegInfo, SourceBits);
|
||||
}
|
||||
|
||||
void RegisterAliasingTracker::FillOriginAndAliasedBits(
|
||||
const llvm::MCRegisterInfo &RegInfo, const llvm::BitVector &SourceBits) {
|
||||
using RegAliasItr = llvm::MCRegAliasIterator;
|
||||
const MCRegisterInfo &RegInfo, const BitVector &SourceBits) {
|
||||
using RegAliasItr = MCRegAliasIterator;
|
||||
for (const size_t PhysReg : SourceBits.set_bits()) {
|
||||
for (auto Itr = RegAliasItr(PhysReg, &RegInfo, true); Itr.isValid();
|
||||
++Itr) {
|
||||
@ -59,12 +58,12 @@ void RegisterAliasingTracker::FillOriginAndAliasedBits(
|
||||
}
|
||||
|
||||
RegisterAliasingTrackerCache::RegisterAliasingTrackerCache(
|
||||
const llvm::MCRegisterInfo &RegInfo, const llvm::BitVector &ReservedReg)
|
||||
const MCRegisterInfo &RegInfo, const BitVector &ReservedReg)
|
||||
: RegInfo(RegInfo), ReservedReg(ReservedReg),
|
||||
EmptyRegisters(RegInfo.getNumRegs()) {}
|
||||
|
||||
const RegisterAliasingTracker &
|
||||
RegisterAliasingTrackerCache::getRegister(llvm::MCPhysReg PhysReg) const {
|
||||
RegisterAliasingTrackerCache::getRegister(MCPhysReg PhysReg) const {
|
||||
auto &Found = Registers[PhysReg];
|
||||
if (!Found)
|
||||
Found.reset(new RegisterAliasingTracker(RegInfo, PhysReg));
|
||||
|
@ -25,78 +25,78 @@ namespace llvm {
|
||||
namespace exegesis {
|
||||
|
||||
// Returns the registers that are aliased by the ones set in SourceBits.
|
||||
llvm::BitVector getAliasedBits(const llvm::MCRegisterInfo &RegInfo,
|
||||
const llvm::BitVector &SourceBits);
|
||||
BitVector getAliasedBits(const MCRegisterInfo &RegInfo,
|
||||
const BitVector &SourceBits);
|
||||
|
||||
// Keeps track of a mapping from one register (or a register class) to its
|
||||
// aliased registers.
|
||||
//
|
||||
// e.g.
|
||||
// RegisterAliasingTracker Tracker(RegInfo, llvm::X86::EAX);
|
||||
// Tracker.sourceBits() == { llvm::X86::EAX }
|
||||
// Tracker.aliasedBits() == { llvm::X86::AL, llvm::X86::AH, llvm::X86::AX,
|
||||
// llvm::X86::EAX,llvm::X86::HAX, llvm::X86::RAX }
|
||||
// Tracker.getOrigin(llvm::X86::AL) == llvm::X86::EAX;
|
||||
// Tracker.getOrigin(llvm::X86::BX) == -1;
|
||||
// RegisterAliasingTracker Tracker(RegInfo, X86::EAX);
|
||||
// Tracker.sourceBits() == { X86::EAX }
|
||||
// Tracker.aliasedBits() == { X86::AL, X86::AH, X86::AX,
|
||||
// X86::EAX,X86::HAX, X86::RAX }
|
||||
// Tracker.getOrigin(X86::AL) == X86::EAX;
|
||||
// Tracker.getOrigin(X86::BX) == -1;
|
||||
struct RegisterAliasingTracker {
|
||||
// Construct a tracker from an MCRegisterClass.
|
||||
RegisterAliasingTracker(const llvm::MCRegisterInfo &RegInfo,
|
||||
const llvm::BitVector &ReservedReg,
|
||||
const llvm::MCRegisterClass &RegClass);
|
||||
RegisterAliasingTracker(const MCRegisterInfo &RegInfo,
|
||||
const BitVector &ReservedReg,
|
||||
const MCRegisterClass &RegClass);
|
||||
|
||||
// Construct a tracker from an MCPhysReg.
|
||||
RegisterAliasingTracker(const llvm::MCRegisterInfo &RegInfo,
|
||||
const llvm::MCPhysReg Register);
|
||||
RegisterAliasingTracker(const MCRegisterInfo &RegInfo,
|
||||
const MCPhysReg Register);
|
||||
|
||||
const llvm::BitVector &sourceBits() const { return SourceBits; }
|
||||
const BitVector &sourceBits() const { return SourceBits; }
|
||||
|
||||
// Retrieves all the touched registers as a BitVector.
|
||||
const llvm::BitVector &aliasedBits() const { return AliasedBits; }
|
||||
const BitVector &aliasedBits() const { return AliasedBits; }
|
||||
|
||||
// Returns the origin of this register or -1.
|
||||
int getOrigin(llvm::MCPhysReg Aliased) const {
|
||||
int getOrigin(MCPhysReg Aliased) const {
|
||||
if (!AliasedBits[Aliased])
|
||||
return -1;
|
||||
return Origins[Aliased];
|
||||
}
|
||||
|
||||
private:
|
||||
RegisterAliasingTracker(const llvm::MCRegisterInfo &RegInfo);
|
||||
RegisterAliasingTracker(const MCRegisterInfo &RegInfo);
|
||||
RegisterAliasingTracker(const RegisterAliasingTracker &) = delete;
|
||||
|
||||
void FillOriginAndAliasedBits(const llvm::MCRegisterInfo &RegInfo,
|
||||
const llvm::BitVector &OriginalBits);
|
||||
void FillOriginAndAliasedBits(const MCRegisterInfo &RegInfo,
|
||||
const BitVector &OriginalBits);
|
||||
|
||||
llvm::BitVector SourceBits;
|
||||
llvm::BitVector AliasedBits;
|
||||
llvm::PackedVector<size_t, 10> Origins; // Max 1024 physical registers.
|
||||
BitVector SourceBits;
|
||||
BitVector AliasedBits;
|
||||
PackedVector<size_t, 10> Origins; // Max 1024 physical registers.
|
||||
};
|
||||
|
||||
// A cache of existing trackers.
|
||||
struct RegisterAliasingTrackerCache {
|
||||
// RegInfo must outlive the cache.
|
||||
RegisterAliasingTrackerCache(const llvm::MCRegisterInfo &RegInfo,
|
||||
const llvm::BitVector &ReservedReg);
|
||||
RegisterAliasingTrackerCache(const MCRegisterInfo &RegInfo,
|
||||
const BitVector &ReservedReg);
|
||||
|
||||
// Convenient function to retrieve a BitVector of the right size.
|
||||
const llvm::BitVector &emptyRegisters() const { return EmptyRegisters; }
|
||||
const BitVector &emptyRegisters() const { return EmptyRegisters; }
|
||||
|
||||
// Convenient function to retrieve the registers the function body can't use.
|
||||
const llvm::BitVector &reservedRegisters() const { return ReservedReg; }
|
||||
const BitVector &reservedRegisters() const { return ReservedReg; }
|
||||
|
||||
// Convenient function to retrieve the underlying MCRegInfo.
|
||||
const llvm::MCRegisterInfo ®Info() const { return RegInfo; }
|
||||
const MCRegisterInfo ®Info() const { return RegInfo; }
|
||||
|
||||
// Retrieves the RegisterAliasingTracker for this particular register.
|
||||
const RegisterAliasingTracker &getRegister(llvm::MCPhysReg Reg) const;
|
||||
const RegisterAliasingTracker &getRegister(MCPhysReg Reg) const;
|
||||
|
||||
// Retrieves the RegisterAliasingTracker for this particular register class.
|
||||
const RegisterAliasingTracker &getRegisterClass(unsigned RegClassIndex) const;
|
||||
|
||||
private:
|
||||
const llvm::MCRegisterInfo &RegInfo;
|
||||
const llvm::BitVector ReservedReg;
|
||||
const llvm::BitVector EmptyRegisters;
|
||||
const MCRegisterInfo &RegInfo;
|
||||
const BitVector ReservedReg;
|
||||
const BitVector EmptyRegisters;
|
||||
mutable std::unordered_map<unsigned, std::unique_ptr<RegisterAliasingTracker>>
|
||||
Registers;
|
||||
mutable std::unordered_map<unsigned, std::unique_ptr<RegisterAliasingTracker>>
|
||||
@ -104,7 +104,7 @@ private:
|
||||
};
|
||||
|
||||
// `a = a & ~b`, optimized for few bit sets in B and no allocation.
|
||||
inline void remove(llvm::BitVector &A, const llvm::BitVector &B) {
|
||||
inline void remove(BitVector &A, const BitVector &B) {
|
||||
assert(A.size() == B.size());
|
||||
for (auto I : B.set_bits())
|
||||
A.reset(I);
|
||||
|
@ -12,27 +12,27 @@
|
||||
namespace llvm {
|
||||
namespace exegesis {
|
||||
|
||||
static llvm::APFloat getFloatValue(const llvm::fltSemantics &FltSemantics,
|
||||
PredefinedValues Value) {
|
||||
static APFloat getFloatValue(const fltSemantics &FltSemantics,
|
||||
PredefinedValues Value) {
|
||||
switch (Value) {
|
||||
case PredefinedValues::POS_ZERO:
|
||||
return llvm::APFloat::getZero(FltSemantics);
|
||||
return APFloat::getZero(FltSemantics);
|
||||
case PredefinedValues::NEG_ZERO:
|
||||
return llvm::APFloat::getZero(FltSemantics, true);
|
||||
return APFloat::getZero(FltSemantics, true);
|
||||
case PredefinedValues::ONE:
|
||||
return llvm::APFloat(FltSemantics, "1");
|
||||
return APFloat(FltSemantics, "1");
|
||||
case PredefinedValues::TWO:
|
||||
return llvm::APFloat(FltSemantics, "2");
|
||||
return APFloat(FltSemantics, "2");
|
||||
case PredefinedValues::INF:
|
||||
return llvm::APFloat::getInf(FltSemantics);
|
||||
return APFloat::getInf(FltSemantics);
|
||||
case PredefinedValues::QNAN:
|
||||
return llvm::APFloat::getQNaN(FltSemantics);
|
||||
return APFloat::getQNaN(FltSemantics);
|
||||
case PredefinedValues::SMALLEST_NORM:
|
||||
return llvm::APFloat::getSmallestNormalized(FltSemantics);
|
||||
return APFloat::getSmallestNormalized(FltSemantics);
|
||||
case PredefinedValues::LARGEST:
|
||||
return llvm::APFloat::getLargest(FltSemantics);
|
||||
return APFloat::getLargest(FltSemantics);
|
||||
case PredefinedValues::ULP:
|
||||
return llvm::APFloat::getSmallest(FltSemantics);
|
||||
return APFloat::getSmallest(FltSemantics);
|
||||
case PredefinedValues::ONE_PLUS_ULP:
|
||||
auto Output = getFloatValue(FltSemantics, PredefinedValues::ONE);
|
||||
Output.next(false);
|
||||
@ -41,8 +41,8 @@ static llvm::APFloat getFloatValue(const llvm::fltSemantics &FltSemantics,
|
||||
llvm_unreachable("Unhandled exegesis::PredefinedValues");
|
||||
}
|
||||
|
||||
llvm::APInt bitcastFloatValue(const llvm::fltSemantics &FltSemantics,
|
||||
PredefinedValues Value) {
|
||||
APInt bitcastFloatValue(const fltSemantics &FltSemantics,
|
||||
PredefinedValues Value) {
|
||||
return getFloatValue(FltSemantics, Value).bitcastToAPInt();
|
||||
}
|
||||
|
||||
|
@ -24,9 +24,9 @@ namespace exegesis {
|
||||
|
||||
// A simple object storing the value for a particular register.
|
||||
struct RegisterValue {
|
||||
static RegisterValue zero(unsigned Reg) { return {Reg, llvm::APInt()}; }
|
||||
static RegisterValue zero(unsigned Reg) { return {Reg, APInt()}; }
|
||||
unsigned Register;
|
||||
llvm::APInt Value;
|
||||
APInt Value;
|
||||
};
|
||||
|
||||
enum class PredefinedValues {
|
||||
@ -43,8 +43,8 @@ enum class PredefinedValues {
|
||||
ONE_PLUS_ULP, // The value just after 1.0
|
||||
};
|
||||
|
||||
llvm::APInt bitcastFloatValue(const llvm::fltSemantics &FltSemantics,
|
||||
PredefinedValues Value);
|
||||
APInt bitcastFloatValue(const fltSemantics &FltSemantics,
|
||||
PredefinedValues Value);
|
||||
|
||||
} // namespace exegesis
|
||||
} // namespace llvm
|
||||
|
@ -46,20 +46,20 @@ namespace exegesis {
|
||||
// Note that in this case, P016 does not contribute any cycles, so it would
|
||||
// be removed by this function.
|
||||
// FIXME: Move this to MCSubtargetInfo and use it in llvm-mca.
|
||||
static llvm::SmallVector<llvm::MCWriteProcResEntry, 8>
|
||||
getNonRedundantWriteProcRes(const llvm::MCSchedClassDesc &SCDesc,
|
||||
const llvm::MCSubtargetInfo &STI) {
|
||||
llvm::SmallVector<llvm::MCWriteProcResEntry, 8> Result;
|
||||
static SmallVector<MCWriteProcResEntry, 8>
|
||||
getNonRedundantWriteProcRes(const MCSchedClassDesc &SCDesc,
|
||||
const MCSubtargetInfo &STI) {
|
||||
SmallVector<MCWriteProcResEntry, 8> Result;
|
||||
const auto &SM = STI.getSchedModel();
|
||||
const unsigned NumProcRes = SM.getNumProcResourceKinds();
|
||||
|
||||
// This assumes that the ProcResDescs are sorted in topological order, which
|
||||
// is guaranteed by the tablegen backend.
|
||||
llvm::SmallVector<float, 32> ProcResUnitUsage(NumProcRes);
|
||||
SmallVector<float, 32> ProcResUnitUsage(NumProcRes);
|
||||
for (const auto *WPR = STI.getWriteProcResBegin(&SCDesc),
|
||||
*const WPREnd = STI.getWriteProcResEnd(&SCDesc);
|
||||
WPR != WPREnd; ++WPR) {
|
||||
const llvm::MCProcResourceDesc *const ProcResDesc =
|
||||
const MCProcResourceDesc *const ProcResDesc =
|
||||
SM.getProcResource(WPR->ProcResourceIdx);
|
||||
if (ProcResDesc->SubUnitsIdxBegin == nullptr) {
|
||||
// This is a ProcResUnit.
|
||||
@ -123,11 +123,11 @@ getNonRedundantWriteProcRes(const llvm::MCSchedClassDesc &SCDesc,
|
||||
// RemainingPressure = 0.0
|
||||
// We stop as there is no remaining budget to distribute.
|
||||
static void distributePressure(float RemainingPressure,
|
||||
llvm::SmallVector<uint16_t, 32> Subunits,
|
||||
llvm::SmallVector<float, 32> &DensePressure) {
|
||||
SmallVector<uint16_t, 32> Subunits,
|
||||
SmallVector<float, 32> &DensePressure) {
|
||||
// Find the number of subunits with minimal pressure (they are at the
|
||||
// front).
|
||||
llvm::sort(Subunits, [&DensePressure](const uint16_t A, const uint16_t B) {
|
||||
sort(Subunits, [&DensePressure](const uint16_t A, const uint16_t B) {
|
||||
return DensePressure[A] < DensePressure[B];
|
||||
});
|
||||
const auto getPressureForSubunit = [&DensePressure,
|
||||
@ -171,27 +171,26 @@ static void distributePressure(float RemainingPressure,
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::pair<uint16_t, float>> computeIdealizedProcResPressure(
|
||||
const llvm::MCSchedModel &SM,
|
||||
llvm::SmallVector<llvm::MCWriteProcResEntry, 8> WPRS) {
|
||||
std::vector<std::pair<uint16_t, float>>
|
||||
computeIdealizedProcResPressure(const MCSchedModel &SM,
|
||||
SmallVector<MCWriteProcResEntry, 8> WPRS) {
|
||||
// DensePressure[I] is the port pressure for Proc Resource I.
|
||||
llvm::SmallVector<float, 32> DensePressure(SM.getNumProcResourceKinds());
|
||||
llvm::sort(WPRS, [](const llvm::MCWriteProcResEntry &A,
|
||||
const llvm::MCWriteProcResEntry &B) {
|
||||
SmallVector<float, 32> DensePressure(SM.getNumProcResourceKinds());
|
||||
sort(WPRS, [](const MCWriteProcResEntry &A, const MCWriteProcResEntry &B) {
|
||||
return A.ProcResourceIdx < B.ProcResourceIdx;
|
||||
});
|
||||
for (const llvm::MCWriteProcResEntry &WPR : WPRS) {
|
||||
for (const MCWriteProcResEntry &WPR : WPRS) {
|
||||
// Get units for the entry.
|
||||
const llvm::MCProcResourceDesc *const ProcResDesc =
|
||||
const MCProcResourceDesc *const ProcResDesc =
|
||||
SM.getProcResource(WPR.ProcResourceIdx);
|
||||
if (ProcResDesc->SubUnitsIdxBegin == nullptr) {
|
||||
// This is a ProcResUnit.
|
||||
DensePressure[WPR.ProcResourceIdx] += WPR.Cycles;
|
||||
} else {
|
||||
// This is a ProcResGroup.
|
||||
llvm::SmallVector<uint16_t, 32> Subunits(ProcResDesc->SubUnitsIdxBegin,
|
||||
ProcResDesc->SubUnitsIdxBegin +
|
||||
ProcResDesc->NumUnits);
|
||||
SmallVector<uint16_t, 32> Subunits(ProcResDesc->SubUnitsIdxBegin,
|
||||
ProcResDesc->SubUnitsIdxBegin +
|
||||
ProcResDesc->NumUnits);
|
||||
distributePressure(WPR.Cycles, Subunits, DensePressure);
|
||||
}
|
||||
}
|
||||
@ -204,7 +203,7 @@ std::vector<std::pair<uint16_t, float>> computeIdealizedProcResPressure(
|
||||
return Pressure;
|
||||
}
|
||||
|
||||
ResolvedSchedClass::ResolvedSchedClass(const llvm::MCSubtargetInfo &STI,
|
||||
ResolvedSchedClass::ResolvedSchedClass(const MCSubtargetInfo &STI,
|
||||
unsigned ResolvedSchedClassId,
|
||||
bool WasVariant)
|
||||
: SchedClassId(ResolvedSchedClassId),
|
||||
@ -217,9 +216,9 @@ ResolvedSchedClass::ResolvedSchedClass(const llvm::MCSubtargetInfo &STI,
|
||||
"ResolvedSchedClass should never be variant");
|
||||
}
|
||||
|
||||
static unsigned ResolveVariantSchedClassId(const llvm::MCSubtargetInfo &STI,
|
||||
static unsigned ResolveVariantSchedClassId(const MCSubtargetInfo &STI,
|
||||
unsigned SchedClassId,
|
||||
const llvm::MCInst &MCI) {
|
||||
const MCInst &MCI) {
|
||||
const auto &SM = STI.getSchedModel();
|
||||
while (SchedClassId && SM.getSchedClassDesc(SchedClassId)->isVariant())
|
||||
SchedClassId =
|
||||
@ -228,9 +227,9 @@ static unsigned ResolveVariantSchedClassId(const llvm::MCSubtargetInfo &STI,
|
||||
}
|
||||
|
||||
std::pair<unsigned /*SchedClassId*/, bool /*WasVariant*/>
|
||||
ResolvedSchedClass::resolveSchedClassId(
|
||||
const llvm::MCSubtargetInfo &SubtargetInfo,
|
||||
const llvm::MCInstrInfo &InstrInfo, const llvm::MCInst &MCI) {
|
||||
ResolvedSchedClass::resolveSchedClassId(const MCSubtargetInfo &SubtargetInfo,
|
||||
const MCInstrInfo &InstrInfo,
|
||||
const MCInst &MCI) {
|
||||
unsigned SchedClassId = InstrInfo.get(MCI.getOpcode()).getSchedClass();
|
||||
const bool WasVariant = SchedClassId && SubtargetInfo.getSchedModel()
|
||||
.getSchedClassDesc(SchedClassId)
|
||||
@ -240,11 +239,11 @@ ResolvedSchedClass::resolveSchedClassId(
|
||||
}
|
||||
|
||||
// Returns a ProxResIdx by id or name.
|
||||
static unsigned findProcResIdx(const llvm::MCSubtargetInfo &STI,
|
||||
const llvm::StringRef NameOrId) {
|
||||
static unsigned findProcResIdx(const MCSubtargetInfo &STI,
|
||||
const StringRef NameOrId) {
|
||||
// Interpret the key as an ProcResIdx.
|
||||
unsigned ProcResIdx = 0;
|
||||
if (llvm::to_integer(NameOrId, ProcResIdx, 10))
|
||||
if (to_integer(NameOrId, ProcResIdx, 10))
|
||||
return ProcResIdx;
|
||||
// Interpret the key as a ProcRes name.
|
||||
const auto &SchedModel = STI.getSchedModel();
|
||||
@ -256,7 +255,7 @@ static unsigned findProcResIdx(const llvm::MCSubtargetInfo &STI,
|
||||
}
|
||||
|
||||
std::vector<BenchmarkMeasure> ResolvedSchedClass::getAsPoint(
|
||||
InstructionBenchmark::ModeE Mode, const llvm::MCSubtargetInfo &STI,
|
||||
InstructionBenchmark::ModeE Mode, const MCSubtargetInfo &STI,
|
||||
ArrayRef<PerInstructionStats> Representative) const {
|
||||
const size_t NumMeasurements = Representative.size();
|
||||
|
||||
@ -270,13 +269,13 @@ std::vector<BenchmarkMeasure> ResolvedSchedClass::getAsPoint(
|
||||
LatencyMeasure.PerInstructionValue = 0.0;
|
||||
|
||||
for (unsigned I = 0; I < SCDesc->NumWriteLatencyEntries; ++I) {
|
||||
const llvm::MCWriteLatencyEntry *const WLE =
|
||||
const MCWriteLatencyEntry *const WLE =
|
||||
STI.getWriteLatencyEntry(SCDesc, I);
|
||||
LatencyMeasure.PerInstructionValue =
|
||||
std::max<double>(LatencyMeasure.PerInstructionValue, WLE->Cycles);
|
||||
}
|
||||
} else if (Mode == InstructionBenchmark::Uops) {
|
||||
for (const auto &I : llvm::zip(SchedClassPoint, Representative)) {
|
||||
for (const auto &I : zip(SchedClassPoint, Representative)) {
|
||||
BenchmarkMeasure &Measure = std::get<0>(I);
|
||||
const PerInstructionStats &Stats = std::get<1>(I);
|
||||
|
||||
@ -296,9 +295,9 @@ std::vector<BenchmarkMeasure> ResolvedSchedClass::getAsPoint(
|
||||
} else if (Key == "NumMicroOps") {
|
||||
Measure.PerInstructionValue = SCDesc->NumMicroOps;
|
||||
} else {
|
||||
llvm::errs() << "expected `key` to be either a ProcResIdx or a ProcRes "
|
||||
"name, got "
|
||||
<< Key << "\n";
|
||||
errs() << "expected `key` to be either a ProcResIdx or a ProcRes "
|
||||
"name, got "
|
||||
<< Key << "\n";
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
@ -31,29 +31,27 @@ namespace exegesis {
|
||||
// Computes the idealized ProcRes Unit pressure. This is the expected
|
||||
// distribution if the CPU scheduler can distribute the load as evenly as
|
||||
// possible.
|
||||
std::vector<std::pair<uint16_t, float>> computeIdealizedProcResPressure(
|
||||
const llvm::MCSchedModel &SM,
|
||||
llvm::SmallVector<llvm::MCWriteProcResEntry, 8> WPRS);
|
||||
std::vector<std::pair<uint16_t, float>>
|
||||
computeIdealizedProcResPressure(const MCSchedModel &SM,
|
||||
SmallVector<MCWriteProcResEntry, 8> WPRS);
|
||||
|
||||
// An llvm::MCSchedClassDesc augmented with some additional data.
|
||||
// An MCSchedClassDesc augmented with some additional data.
|
||||
struct ResolvedSchedClass {
|
||||
ResolvedSchedClass(const llvm::MCSubtargetInfo &STI,
|
||||
unsigned ResolvedSchedClassId, bool WasVariant);
|
||||
ResolvedSchedClass(const MCSubtargetInfo &STI, unsigned ResolvedSchedClassId,
|
||||
bool WasVariant);
|
||||
|
||||
static std::pair<unsigned /*SchedClassId*/, bool /*WasVariant*/>
|
||||
resolveSchedClassId(const llvm::MCSubtargetInfo &SubtargetInfo,
|
||||
const llvm::MCInstrInfo &InstrInfo,
|
||||
const llvm::MCInst &MCI);
|
||||
resolveSchedClassId(const MCSubtargetInfo &SubtargetInfo,
|
||||
const MCInstrInfo &InstrInfo, const MCInst &MCI);
|
||||
|
||||
std::vector<BenchmarkMeasure>
|
||||
getAsPoint(InstructionBenchmark::ModeE Mode, const llvm::MCSubtargetInfo &STI,
|
||||
getAsPoint(InstructionBenchmark::ModeE Mode, const MCSubtargetInfo &STI,
|
||||
ArrayRef<PerInstructionStats> Representative) const;
|
||||
|
||||
const unsigned SchedClassId;
|
||||
const llvm::MCSchedClassDesc *const SCDesc;
|
||||
const MCSchedClassDesc *const SCDesc;
|
||||
const bool WasVariant; // Whether the original class was variant.
|
||||
const llvm::SmallVector<llvm::MCWriteProcResEntry, 8>
|
||||
NonRedundantWriteProcRes;
|
||||
const SmallVector<MCWriteProcResEntry, 8> NonRedundantWriteProcRes;
|
||||
const std::vector<std::pair<uint16_t, float>> IdealizedProcResPressure;
|
||||
};
|
||||
|
||||
|
@ -30,18 +30,17 @@ std::vector<CodeTemplate> getSingleton(CodeTemplate &&CT) {
|
||||
return Result;
|
||||
}
|
||||
|
||||
SnippetGeneratorFailure::SnippetGeneratorFailure(const llvm::Twine &S)
|
||||
: llvm::StringError(S, llvm::inconvertibleErrorCode()) {}
|
||||
SnippetGeneratorFailure::SnippetGeneratorFailure(const Twine &S)
|
||||
: StringError(S, inconvertibleErrorCode()) {}
|
||||
|
||||
SnippetGenerator::SnippetGenerator(const LLVMState &State, const Options &Opts)
|
||||
: State(State), Opts(Opts) {}
|
||||
|
||||
SnippetGenerator::~SnippetGenerator() = default;
|
||||
|
||||
llvm::Expected<std::vector<BenchmarkCode>>
|
||||
SnippetGenerator::generateConfigurations(
|
||||
const Instruction &Instr, const llvm::BitVector &ExtraForbiddenRegs) const {
|
||||
llvm::BitVector ForbiddenRegs = State.getRATC().reservedRegisters();
|
||||
Expected<std::vector<BenchmarkCode>> SnippetGenerator::generateConfigurations(
|
||||
const Instruction &Instr, const BitVector &ExtraForbiddenRegs) const {
|
||||
BitVector ForbiddenRegs = State.getRATC().reservedRegisters();
|
||||
ForbiddenRegs |= ExtraForbiddenRegs;
|
||||
// If the instruction has memory registers, prevent the generator from
|
||||
// using the scratch register and its aliasing registers.
|
||||
@ -98,7 +97,7 @@ std::vector<RegisterValue> SnippetGenerator::computeRegisterInitialValues(
|
||||
// Ignore memory operands which are handled separately.
|
||||
// Loop invariant: DefinedRegs[i] is true iif it has been set at least once
|
||||
// before the current instruction.
|
||||
llvm::BitVector DefinedRegs = State.getRATC().emptyRegisters();
|
||||
BitVector DefinedRegs = State.getRATC().emptyRegisters();
|
||||
std::vector<RegisterValue> RIV;
|
||||
for (const InstructionTemplate &IT : Instructions) {
|
||||
// Returns the register that this Operand sets or uses, or 0 if this is not
|
||||
@ -134,11 +133,11 @@ std::vector<RegisterValue> SnippetGenerator::computeRegisterInitialValues(
|
||||
return RIV;
|
||||
}
|
||||
|
||||
llvm::Expected<std::vector<CodeTemplate>>
|
||||
Expected<std::vector<CodeTemplate>>
|
||||
generateSelfAliasingCodeTemplates(const Instruction &Instr) {
|
||||
const AliasingConfigurations SelfAliasing(Instr, Instr);
|
||||
if (SelfAliasing.empty())
|
||||
return llvm::make_error<SnippetGeneratorFailure>("empty self aliasing");
|
||||
return make_error<SnippetGeneratorFailure>("empty self aliasing");
|
||||
std::vector<CodeTemplate> Result;
|
||||
Result.emplace_back();
|
||||
CodeTemplate &CT = Result.back();
|
||||
@ -155,13 +154,12 @@ generateSelfAliasingCodeTemplates(const Instruction &Instr) {
|
||||
return std::move(Result);
|
||||
}
|
||||
|
||||
llvm::Expected<std::vector<CodeTemplate>>
|
||||
generateUnconstrainedCodeTemplates(const Instruction &Instr,
|
||||
llvm::StringRef Msg) {
|
||||
Expected<std::vector<CodeTemplate>>
|
||||
generateUnconstrainedCodeTemplates(const Instruction &Instr, StringRef Msg) {
|
||||
std::vector<CodeTemplate> Result;
|
||||
Result.emplace_back();
|
||||
CodeTemplate &CT = Result.back();
|
||||
CT.Info = llvm::formatv("{0}, repeating an unconstrained assignment", Msg);
|
||||
CT.Info = formatv("{0}, repeating an unconstrained assignment", Msg);
|
||||
CT.Instructions.emplace_back(Instr);
|
||||
return std::move(Result);
|
||||
}
|
||||
@ -193,14 +191,14 @@ static void setRegisterOperandValue(const RegisterOperandAssignment &ROV,
|
||||
assert(AssignedValue.isReg() && AssignedValue.getReg() == ROV.Reg);
|
||||
return;
|
||||
}
|
||||
AssignedValue = llvm::MCOperand::createReg(ROV.Reg);
|
||||
AssignedValue = MCOperand::createReg(ROV.Reg);
|
||||
} else {
|
||||
assert(ROV.Op->isImplicitReg());
|
||||
assert(ROV.Reg == ROV.Op->getImplicitReg());
|
||||
}
|
||||
}
|
||||
|
||||
size_t randomBit(const llvm::BitVector &Vector) {
|
||||
size_t randomBit(const BitVector &Vector) {
|
||||
assert(Vector.any());
|
||||
auto Itr = Vector.set_bits_begin();
|
||||
for (size_t I = randomIndex(Vector.count() - 1); I != 0; --I)
|
||||
@ -218,10 +216,10 @@ void setRandomAliasing(const AliasingConfigurations &AliasingConfigurations,
|
||||
}
|
||||
|
||||
void randomizeUnsetVariables(const ExegesisTarget &Target,
|
||||
const llvm::BitVector &ForbiddenRegs,
|
||||
const BitVector &ForbiddenRegs,
|
||||
InstructionTemplate &IT) {
|
||||
for (const Variable &Var : IT.Instr.Variables) {
|
||||
llvm::MCOperand &AssignedValue = IT.getValueFor(Var);
|
||||
MCOperand &AssignedValue = IT.getValueFor(Var);
|
||||
if (!AssignedValue.isValid())
|
||||
Target.randomizeMCOperand(IT.Instr, Var, AssignedValue, ForbiddenRegs);
|
||||
}
|
||||
|
@ -33,19 +33,18 @@ namespace exegesis {
|
||||
std::vector<CodeTemplate> getSingleton(CodeTemplate &&CT);
|
||||
|
||||
// Generates code templates that has a self-dependency.
|
||||
llvm::Expected<std::vector<CodeTemplate>>
|
||||
Expected<std::vector<CodeTemplate>>
|
||||
generateSelfAliasingCodeTemplates(const Instruction &Instr);
|
||||
|
||||
// Generates code templates without assignment constraints.
|
||||
llvm::Expected<std::vector<CodeTemplate>>
|
||||
generateUnconstrainedCodeTemplates(const Instruction &Instr,
|
||||
llvm::StringRef Msg);
|
||||
Expected<std::vector<CodeTemplate>>
|
||||
generateUnconstrainedCodeTemplates(const Instruction &Instr, StringRef Msg);
|
||||
|
||||
// A class representing failures that happened during Benchmark, they are used
|
||||
// to report informations to the user.
|
||||
class SnippetGeneratorFailure : public llvm::StringError {
|
||||
class SnippetGeneratorFailure : public StringError {
|
||||
public:
|
||||
SnippetGeneratorFailure(const llvm::Twine &S);
|
||||
SnippetGeneratorFailure(const Twine &S);
|
||||
};
|
||||
|
||||
// Common code for all benchmark modes.
|
||||
@ -60,9 +59,9 @@ public:
|
||||
virtual ~SnippetGenerator();
|
||||
|
||||
// Calls generateCodeTemplate and expands it into one or more BenchmarkCode.
|
||||
llvm::Expected<std::vector<BenchmarkCode>>
|
||||
Expected<std::vector<BenchmarkCode>>
|
||||
generateConfigurations(const Instruction &Instr,
|
||||
const llvm::BitVector &ExtraForbiddenRegs) const;
|
||||
const BitVector &ExtraForbiddenRegs) const;
|
||||
|
||||
// Given a snippet, computes which registers the setup code needs to define.
|
||||
std::vector<RegisterValue> computeRegisterInitialValues(
|
||||
@ -74,7 +73,7 @@ protected:
|
||||
|
||||
private:
|
||||
// API to be implemented by subclasses.
|
||||
virtual llvm::Expected<std::vector<CodeTemplate>>
|
||||
virtual Expected<std::vector<CodeTemplate>>
|
||||
generateCodeTemplates(const Instruction &Instr,
|
||||
const BitVector &ForbiddenRegisters) const = 0;
|
||||
};
|
||||
@ -89,7 +88,7 @@ size_t randomIndex(size_t Max);
|
||||
|
||||
// Picks a random bit among the bits set in Vector and returns its index.
|
||||
// Precondition: Vector must have at least one bit set.
|
||||
size_t randomBit(const llvm::BitVector &Vector);
|
||||
size_t randomBit(const BitVector &Vector);
|
||||
|
||||
// Picks a random configuration, then selects a random def and a random use from
|
||||
// it and finally set the selected values in the provided InstructionInstances.
|
||||
@ -99,7 +98,7 @@ void setRandomAliasing(const AliasingConfigurations &AliasingConfigurations,
|
||||
// Assigns a Random Value to all Variables in IT that are still Invalid.
|
||||
// Do not use any of the registers in `ForbiddenRegs`.
|
||||
void randomizeUnsetVariables(const ExegesisTarget &Target,
|
||||
const llvm::BitVector &ForbiddenRegs,
|
||||
const BitVector &ForbiddenRegs,
|
||||
InstructionTemplate &IT);
|
||||
|
||||
} // namespace exegesis
|
||||
|
@ -69,8 +69,8 @@ public:
|
||||
Entry.addInstruction(Inst);
|
||||
|
||||
// Set up the loop basic block.
|
||||
Entry.MBB->addSuccessor(Loop.MBB, llvm::BranchProbability::getOne());
|
||||
Loop.MBB->addSuccessor(Loop.MBB, llvm::BranchProbability::getOne());
|
||||
Entry.MBB->addSuccessor(Loop.MBB, BranchProbability::getOne());
|
||||
Loop.MBB->addSuccessor(Loop.MBB, BranchProbability::getOne());
|
||||
// The live ins are: the loop counter, the registers that were setup by
|
||||
// the entry block, and entry block live ins.
|
||||
Loop.MBB->addLiveIn(LoopCounter);
|
||||
@ -83,7 +83,7 @@ public:
|
||||
State.getInstrInfo());
|
||||
|
||||
// Set up the exit basic block.
|
||||
Loop.MBB->addSuccessor(Exit.MBB, llvm::BranchProbability::getZero());
|
||||
Loop.MBB->addSuccessor(Exit.MBB, BranchProbability::getZero());
|
||||
Exit.addReturn();
|
||||
};
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ ExegesisTarget::~ExegesisTarget() {} // anchor.
|
||||
|
||||
static ExegesisTarget *FirstTarget = nullptr;
|
||||
|
||||
const ExegesisTarget *ExegesisTarget::lookup(llvm::Triple TT) {
|
||||
const ExegesisTarget *ExegesisTarget::lookup(Triple TT) {
|
||||
for (const ExegesisTarget *T = FirstTarget; T != nullptr; T = T->Next) {
|
||||
if (T->matchesArch(TT.getArch()))
|
||||
return T;
|
||||
@ -86,23 +86,23 @@ ExegesisTarget::createUopsBenchmarkRunner(const LLVMState &State) const {
|
||||
return std::make_unique<UopsBenchmarkRunner>(State);
|
||||
}
|
||||
|
||||
void ExegesisTarget::randomizeMCOperand(
|
||||
const Instruction &Instr, const Variable &Var,
|
||||
llvm::MCOperand &AssignedValue,
|
||||
const llvm::BitVector &ForbiddenRegs) const {
|
||||
void ExegesisTarget::randomizeMCOperand(const Instruction &Instr,
|
||||
const Variable &Var,
|
||||
MCOperand &AssignedValue,
|
||||
const BitVector &ForbiddenRegs) const {
|
||||
const Operand &Op = Instr.getPrimaryOperand(Var);
|
||||
switch (Op.getExplicitOperandInfo().OperandType) {
|
||||
case llvm::MCOI::OperandType::OPERAND_IMMEDIATE:
|
||||
case MCOI::OperandType::OPERAND_IMMEDIATE:
|
||||
// FIXME: explore immediate values too.
|
||||
AssignedValue = llvm::MCOperand::createImm(1);
|
||||
AssignedValue = MCOperand::createImm(1);
|
||||
break;
|
||||
case llvm::MCOI::OperandType::OPERAND_REGISTER: {
|
||||
case MCOI::OperandType::OPERAND_REGISTER: {
|
||||
assert(Op.isReg());
|
||||
auto AllowedRegs = Op.getRegisterAliasing().sourceBits();
|
||||
assert(AllowedRegs.size() == ForbiddenRegs.size());
|
||||
for (auto I : ForbiddenRegs.set_bits())
|
||||
AllowedRegs.reset(I);
|
||||
AssignedValue = llvm::MCOperand::createReg(randomBit(AllowedRegs));
|
||||
AssignedValue = MCOperand::createReg(randomBit(AllowedRegs));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@ -115,8 +115,7 @@ static_assert(std::is_pod<PfmCountersInfo>::value,
|
||||
const PfmCountersInfo PfmCountersInfo::Default = {nullptr, nullptr, nullptr,
|
||||
0u};
|
||||
|
||||
const PfmCountersInfo &
|
||||
ExegesisTarget::getPfmCounters(llvm::StringRef CpuName) const {
|
||||
const PfmCountersInfo &ExegesisTarget::getPfmCounters(StringRef CpuName) const {
|
||||
assert(std::is_sorted(
|
||||
CpuPfmCounters.begin(), CpuPfmCounters.end(),
|
||||
[](const CpuAndPfmCounters &LHS, const CpuAndPfmCounters &RHS) {
|
||||
@ -127,8 +126,7 @@ ExegesisTarget::getPfmCounters(llvm::StringRef CpuName) const {
|
||||
// Find entry
|
||||
auto Found =
|
||||
std::lower_bound(CpuPfmCounters.begin(), CpuPfmCounters.end(), CpuName);
|
||||
if (Found == CpuPfmCounters.end() ||
|
||||
llvm::StringRef(Found->CpuName) != CpuName) {
|
||||
if (Found == CpuPfmCounters.end() || StringRef(Found->CpuName) != CpuName) {
|
||||
// Use the default.
|
||||
if (CpuPfmCounters.begin() != CpuPfmCounters.end() &&
|
||||
CpuPfmCounters.begin()->CpuName[0] == '\0') {
|
||||
@ -149,13 +147,12 @@ public:
|
||||
ExegesisDefaultTarget() : ExegesisTarget({}) {}
|
||||
|
||||
private:
|
||||
std::vector<llvm::MCInst> setRegTo(const llvm::MCSubtargetInfo &STI,
|
||||
unsigned Reg,
|
||||
const llvm::APInt &Value) const override {
|
||||
std::vector<MCInst> setRegTo(const MCSubtargetInfo &STI, unsigned Reg,
|
||||
const APInt &Value) const override {
|
||||
llvm_unreachable("Not yet implemented");
|
||||
}
|
||||
|
||||
bool matchesArch(llvm::Triple::ArchType Arch) const override {
|
||||
bool matchesArch(Triple::ArchType Arch) const override {
|
||||
llvm_unreachable("never called");
|
||||
return false;
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
/// \file
|
||||
///
|
||||
/// Classes that handle the creation of target-specific objects. This is
|
||||
/// similar to llvm::Target/TargetRegistry.
|
||||
/// similar to Target/TargetRegistry.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
@ -56,31 +56,26 @@ struct PfmCountersInfo {
|
||||
struct CpuAndPfmCounters {
|
||||
const char *CpuName;
|
||||
const PfmCountersInfo *PCI;
|
||||
bool operator<(llvm::StringRef S) const {
|
||||
return llvm::StringRef(CpuName) < S;
|
||||
}
|
||||
bool operator<(StringRef S) const { return StringRef(CpuName) < S; }
|
||||
};
|
||||
|
||||
class ExegesisTarget {
|
||||
public:
|
||||
explicit ExegesisTarget(llvm::ArrayRef<CpuAndPfmCounters> CpuPfmCounters)
|
||||
explicit ExegesisTarget(ArrayRef<CpuAndPfmCounters> CpuPfmCounters)
|
||||
: CpuPfmCounters(CpuPfmCounters) {}
|
||||
|
||||
// Targets can use this to add target-specific passes in assembleToStream();
|
||||
virtual void addTargetSpecificPasses(llvm::PassManagerBase &PM) const {}
|
||||
virtual void addTargetSpecificPasses(PassManagerBase &PM) const {}
|
||||
|
||||
// Generates code to move a constant into a the given register.
|
||||
// Precondition: Value must fit into Reg.
|
||||
virtual std::vector<llvm::MCInst>
|
||||
setRegTo(const llvm::MCSubtargetInfo &STI, unsigned Reg,
|
||||
const llvm::APInt &Value) const = 0;
|
||||
virtual std::vector<MCInst> setRegTo(const MCSubtargetInfo &STI, unsigned Reg,
|
||||
const APInt &Value) const = 0;
|
||||
|
||||
// Returns the register pointing to scratch memory, or 0 if this target
|
||||
// does not support memory operands. The benchmark function uses the
|
||||
// default calling convention.
|
||||
virtual unsigned getScratchMemoryRegister(const llvm::Triple &) const {
|
||||
return 0;
|
||||
}
|
||||
virtual unsigned getScratchMemoryRegister(const Triple &) const { return 0; }
|
||||
|
||||
// Fills memory operands with references to the address at [Reg] + Offset.
|
||||
virtual void fillMemoryOperands(InstructionTemplate &IT, unsigned Reg,
|
||||
@ -90,14 +85,12 @@ public:
|
||||
}
|
||||
|
||||
// Returns a counter usable as a loop counter.
|
||||
virtual unsigned getLoopCounterRegister(const llvm::Triple &) const {
|
||||
return 0;
|
||||
}
|
||||
virtual unsigned getLoopCounterRegister(const Triple &) const { return 0; }
|
||||
|
||||
// Adds the code to decrement the loop counter and
|
||||
virtual void decrementLoopCounterAndJump(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock &TargetMBB,
|
||||
const llvm::MCInstrInfo &MII) const {
|
||||
const MCInstrInfo &MII) const {
|
||||
llvm_unreachable("decrementLoopCounterAndBranch() requires "
|
||||
"getLoopCounterRegister() > 0");
|
||||
}
|
||||
@ -119,8 +112,8 @@ public:
|
||||
// The target is responsible for handling any operand
|
||||
// starting from OPERAND_FIRST_TARGET.
|
||||
virtual void randomizeMCOperand(const Instruction &Instr, const Variable &Var,
|
||||
llvm::MCOperand &AssignedValue,
|
||||
const llvm::BitVector &ForbiddenRegs) const;
|
||||
MCOperand &AssignedValue,
|
||||
const BitVector &ForbiddenRegs) const;
|
||||
|
||||
// Creates a snippet generator for the given mode.
|
||||
std::unique_ptr<SnippetGenerator>
|
||||
@ -134,7 +127,7 @@ public:
|
||||
|
||||
// Returns the ExegesisTarget for the given triple or nullptr if the target
|
||||
// does not exist.
|
||||
static const ExegesisTarget *lookup(llvm::Triple TT);
|
||||
static const ExegesisTarget *lookup(Triple TT);
|
||||
// Returns the default (unspecialized) ExegesisTarget.
|
||||
static const ExegesisTarget &getDefault();
|
||||
// Registers a target. Not thread safe.
|
||||
@ -144,10 +137,10 @@ public:
|
||||
|
||||
// Returns the Pfm counters for the given CPU (or the default if no pfm
|
||||
// counters are defined for this CPU).
|
||||
const PfmCountersInfo &getPfmCounters(llvm::StringRef CpuName) const;
|
||||
const PfmCountersInfo &getPfmCounters(StringRef CpuName) const;
|
||||
|
||||
private:
|
||||
virtual bool matchesArch(llvm::Triple::ArchType Arch) const = 0;
|
||||
virtual bool matchesArch(Triple::ArchType Arch) const = 0;
|
||||
|
||||
// Targets can implement their own snippet generators/benchmarks runners by
|
||||
// implementing these.
|
||||
@ -161,7 +154,7 @@ private:
|
||||
const LLVMState &State) const;
|
||||
|
||||
const ExegesisTarget *Next = nullptr;
|
||||
const llvm::ArrayRef<CpuAndPfmCounters> CpuPfmCounters;
|
||||
const ArrayRef<CpuAndPfmCounters> CpuPfmCounters;
|
||||
};
|
||||
|
||||
} // namespace exegesis
|
||||
|
@ -80,9 +80,9 @@
|
||||
namespace llvm {
|
||||
namespace exegesis {
|
||||
|
||||
static llvm::SmallVector<const Variable *, 8>
|
||||
static SmallVector<const Variable *, 8>
|
||||
getVariablesWithTiedOperands(const Instruction &Instr) {
|
||||
llvm::SmallVector<const Variable *, 8> Result;
|
||||
SmallVector<const Variable *, 8> Result;
|
||||
for (const auto &Var : Instr.Variables)
|
||||
if (Var.hasTiedOperands())
|
||||
Result.push_back(&Var);
|
||||
@ -145,7 +145,7 @@ static std::vector<InstructionTemplate> generateSnippetUsingStaticRenaming(
|
||||
return Instructions;
|
||||
}
|
||||
TmpIT.getValueFor(*TiedVariables[VarId]) =
|
||||
llvm::MCOperand::createReg(NextPossibleReg);
|
||||
MCOperand::createReg(NextPossibleReg);
|
||||
// Bump iterator.
|
||||
Iterators[VarId] = NextPossibleReg;
|
||||
// Prevent other variables from using the register.
|
||||
@ -157,8 +157,7 @@ static std::vector<InstructionTemplate> generateSnippetUsingStaticRenaming(
|
||||
}
|
||||
}
|
||||
|
||||
llvm::Expected<std::vector<CodeTemplate>>
|
||||
UopsSnippetGenerator::generateCodeTemplates(
|
||||
Expected<std::vector<CodeTemplate>> UopsSnippetGenerator::generateCodeTemplates(
|
||||
const Instruction &Instr, const BitVector &ForbiddenRegisters) const {
|
||||
CodeTemplate CT;
|
||||
CT.ScratchSpacePointerInReg =
|
||||
@ -189,7 +188,7 @@ UopsSnippetGenerator::generateCodeTemplates(
|
||||
return getSingleton(std::move(CT));
|
||||
}
|
||||
// No tied variables, we pick random values for defs.
|
||||
llvm::BitVector Defs(State.getRegInfo().getNumRegs());
|
||||
BitVector Defs(State.getRegInfo().getNumRegs());
|
||||
for (const auto &Op : Instr.Operands) {
|
||||
if (Op.isReg() && Op.isExplicit() && Op.isDef() && !Op.isMemory()) {
|
||||
auto PossibleRegisters = Op.getRegisterAliasing().sourceBits();
|
||||
@ -198,7 +197,7 @@ UopsSnippetGenerator::generateCodeTemplates(
|
||||
assert(PossibleRegisters.any() && "No register left to choose from");
|
||||
const auto RandomReg = randomBit(PossibleRegisters);
|
||||
Defs.set(RandomReg);
|
||||
IT.getValueFor(Op) = llvm::MCOperand::createReg(RandomReg);
|
||||
IT.getValueFor(Op) = MCOperand::createReg(RandomReg);
|
||||
}
|
||||
}
|
||||
// And pick random use values that are not reserved and don't alias with defs.
|
||||
@ -210,7 +209,7 @@ UopsSnippetGenerator::generateCodeTemplates(
|
||||
remove(PossibleRegisters, DefAliases);
|
||||
assert(PossibleRegisters.any() && "No register left to choose from");
|
||||
const auto RandomReg = randomBit(PossibleRegisters);
|
||||
IT.getValueFor(Op) = llvm::MCOperand::createReg(RandomReg);
|
||||
IT.getValueFor(Op) = MCOperand::createReg(RandomReg);
|
||||
}
|
||||
}
|
||||
CT.Info =
|
||||
@ -220,7 +219,7 @@ UopsSnippetGenerator::generateCodeTemplates(
|
||||
return getSingleton(std::move(CT));
|
||||
}
|
||||
|
||||
llvm::Expected<std::vector<BenchmarkMeasure>>
|
||||
Expected<std::vector<BenchmarkMeasure>>
|
||||
UopsBenchmarkRunner::runMeasurements(const FunctionExecutor &Executor) const {
|
||||
std::vector<BenchmarkMeasure> Result;
|
||||
const PfmCountersInfo &PCI = State.getPfmCounters();
|
||||
|
@ -25,7 +25,7 @@ public:
|
||||
using SnippetGenerator::SnippetGenerator;
|
||||
~UopsSnippetGenerator() override;
|
||||
|
||||
llvm::Expected<std::vector<CodeTemplate>>
|
||||
Expected<std::vector<CodeTemplate>>
|
||||
generateCodeTemplates(const Instruction &Instr,
|
||||
const BitVector &ForbiddenRegisters) const override;
|
||||
|
||||
@ -69,7 +69,7 @@ public:
|
||||
static constexpr const size_t kMinNumDifferentAddresses = 6;
|
||||
|
||||
private:
|
||||
llvm::Expected<std::vector<BenchmarkMeasure>>
|
||||
Expected<std::vector<BenchmarkMeasure>>
|
||||
runMeasurements(const FunctionExecutor &Executor) const override;
|
||||
};
|
||||
|
||||
|
@ -148,34 +148,31 @@ static Error isInvalidMemoryInstr(const Instruction &Instr) {
|
||||
}
|
||||
}
|
||||
|
||||
static llvm::Error IsInvalidOpcode(const Instruction &Instr) {
|
||||
static Error IsInvalidOpcode(const Instruction &Instr) {
|
||||
const auto OpcodeName = Instr.Name;
|
||||
if ((Instr.Description->TSFlags & X86II::FormMask) == X86II::Pseudo)
|
||||
return llvm::make_error<Failure>("unsupported opcode: pseudo instruction");
|
||||
return make_error<Failure>("unsupported opcode: pseudo instruction");
|
||||
if (OpcodeName.startswith("POPF") || OpcodeName.startswith("PUSHF") ||
|
||||
OpcodeName.startswith("ADJCALLSTACK"))
|
||||
return llvm::make_error<Failure>(
|
||||
"unsupported opcode: Push/Pop/AdjCallStack");
|
||||
if (llvm::Error Error = isInvalidMemoryInstr(Instr))
|
||||
return make_error<Failure>("unsupported opcode: Push/Pop/AdjCallStack");
|
||||
if (Error Error = isInvalidMemoryInstr(Instr))
|
||||
return Error;
|
||||
// We do not handle instructions with OPERAND_PCREL.
|
||||
for (const Operand &Op : Instr.Operands)
|
||||
if (Op.isExplicit() &&
|
||||
Op.getExplicitOperandInfo().OperandType == llvm::MCOI::OPERAND_PCREL)
|
||||
return llvm::make_error<Failure>(
|
||||
"unsupported opcode: PC relative operand");
|
||||
Op.getExplicitOperandInfo().OperandType == MCOI::OPERAND_PCREL)
|
||||
return make_error<Failure>("unsupported opcode: PC relative operand");
|
||||
// We do not handle second-form X87 instructions. We only handle first-form
|
||||
// ones (_Fp), see comment in X86InstrFPStack.td.
|
||||
for (const Operand &Op : Instr.Operands)
|
||||
if (Op.isReg() && Op.isExplicit() &&
|
||||
Op.getExplicitOperandInfo().RegClass == llvm::X86::RSTRegClassID)
|
||||
return llvm::make_error<Failure>(
|
||||
"unsupported second-form X87 instruction");
|
||||
return llvm::Error::success();
|
||||
Op.getExplicitOperandInfo().RegClass == X86::RSTRegClassID)
|
||||
return make_error<Failure>("unsupported second-form X87 instruction");
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
static unsigned getX86FPFlags(const Instruction &Instr) {
|
||||
return Instr.Description->TSFlags & llvm::X86II::FPTypeMask;
|
||||
return Instr.Description->TSFlags & X86II::FPTypeMask;
|
||||
}
|
||||
|
||||
// Helper to fill a memory operand with a value.
|
||||
@ -188,7 +185,7 @@ static void setMemOp(InstructionTemplate &IT, int OpIdx,
|
||||
|
||||
// Common (latency, uops) code for LEA templates. `GetDestReg` takes the
|
||||
// addressing base and index registers and returns the LEA destination register.
|
||||
static llvm::Expected<std::vector<CodeTemplate>> generateLEATemplatesCommon(
|
||||
static Expected<std::vector<CodeTemplate>> generateLEATemplatesCommon(
|
||||
const Instruction &Instr, const BitVector &ForbiddenRegisters,
|
||||
const LLVMState &State, const SnippetGenerator::Options &Opts,
|
||||
std::function<unsigned(unsigned, unsigned)> GetDestReg) {
|
||||
@ -249,13 +246,13 @@ class X86LatencySnippetGenerator : public LatencySnippetGenerator {
|
||||
public:
|
||||
using LatencySnippetGenerator::LatencySnippetGenerator;
|
||||
|
||||
llvm::Expected<std::vector<CodeTemplate>>
|
||||
Expected<std::vector<CodeTemplate>>
|
||||
generateCodeTemplates(const Instruction &Instr,
|
||||
const BitVector &ForbiddenRegisters) const override;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
llvm::Expected<std::vector<CodeTemplate>>
|
||||
Expected<std::vector<CodeTemplate>>
|
||||
X86LatencySnippetGenerator::generateCodeTemplates(
|
||||
const Instruction &Instr, const BitVector &ForbiddenRegisters) const {
|
||||
if (auto E = IsInvalidOpcode(Instr))
|
||||
@ -273,17 +270,17 @@ X86LatencySnippetGenerator::generateCodeTemplates(
|
||||
}
|
||||
|
||||
switch (getX86FPFlags(Instr)) {
|
||||
case llvm::X86II::NotFP:
|
||||
case X86II::NotFP:
|
||||
return LatencySnippetGenerator::generateCodeTemplates(Instr,
|
||||
ForbiddenRegisters);
|
||||
case llvm::X86II::ZeroArgFP:
|
||||
case llvm::X86II::OneArgFP:
|
||||
case llvm::X86II::SpecialFP:
|
||||
case llvm::X86II::CompareFP:
|
||||
case llvm::X86II::CondMovFP:
|
||||
return llvm::make_error<Failure>("Unsupported x87 Instruction");
|
||||
case llvm::X86II::OneArgFPRW:
|
||||
case llvm::X86II::TwoArgFP:
|
||||
case X86II::ZeroArgFP:
|
||||
case X86II::OneArgFP:
|
||||
case X86II::SpecialFP:
|
||||
case X86II::CompareFP:
|
||||
case X86II::CondMovFP:
|
||||
return make_error<Failure>("Unsupported x87 Instruction");
|
||||
case X86II::OneArgFPRW:
|
||||
case X86II::TwoArgFP:
|
||||
// These are instructions like
|
||||
// - `ST(0) = fsqrt(ST(0))` (OneArgFPRW)
|
||||
// - `ST(0) = ST(0) + ST(i)` (TwoArgFP)
|
||||
@ -299,14 +296,14 @@ class X86UopsSnippetGenerator : public UopsSnippetGenerator {
|
||||
public:
|
||||
using UopsSnippetGenerator::UopsSnippetGenerator;
|
||||
|
||||
llvm::Expected<std::vector<CodeTemplate>>
|
||||
Expected<std::vector<CodeTemplate>>
|
||||
generateCodeTemplates(const Instruction &Instr,
|
||||
const BitVector &ForbiddenRegisters) const override;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
llvm::Expected<std::vector<CodeTemplate>>
|
||||
Expected<std::vector<CodeTemplate>>
|
||||
X86UopsSnippetGenerator::generateCodeTemplates(
|
||||
const Instruction &Instr, const BitVector &ForbiddenRegisters) const {
|
||||
if (auto E = IsInvalidOpcode(Instr))
|
||||
@ -335,23 +332,23 @@ X86UopsSnippetGenerator::generateCodeTemplates(
|
||||
}
|
||||
|
||||
switch (getX86FPFlags(Instr)) {
|
||||
case llvm::X86II::NotFP:
|
||||
case X86II::NotFP:
|
||||
return UopsSnippetGenerator::generateCodeTemplates(Instr,
|
||||
ForbiddenRegisters);
|
||||
case llvm::X86II::ZeroArgFP:
|
||||
case llvm::X86II::OneArgFP:
|
||||
case llvm::X86II::SpecialFP:
|
||||
return llvm::make_error<Failure>("Unsupported x87 Instruction");
|
||||
case llvm::X86II::OneArgFPRW:
|
||||
case llvm::X86II::TwoArgFP:
|
||||
case X86II::ZeroArgFP:
|
||||
case X86II::OneArgFP:
|
||||
case X86II::SpecialFP:
|
||||
return make_error<Failure>("Unsupported x87 Instruction");
|
||||
case X86II::OneArgFPRW:
|
||||
case X86II::TwoArgFP:
|
||||
// These are instructions like
|
||||
// - `ST(0) = fsqrt(ST(0))` (OneArgFPRW)
|
||||
// - `ST(0) = ST(0) + ST(i)` (TwoArgFP)
|
||||
// They are intrinsically serial and do not modify the state of the stack.
|
||||
// We generate the same code for latency and uops.
|
||||
return generateSelfAliasingCodeTemplates(Instr);
|
||||
case llvm::X86II::CompareFP:
|
||||
case llvm::X86II::CondMovFP:
|
||||
case X86II::CompareFP:
|
||||
case X86II::CondMovFP:
|
||||
// We can compute uops for any FP instruction that does not grow or shrink
|
||||
// the stack (either do not touch the stack or push as much as they pop).
|
||||
return generateUnconstrainedCodeTemplates(
|
||||
@ -364,66 +361,66 @@ X86UopsSnippetGenerator::generateCodeTemplates(
|
||||
static unsigned getLoadImmediateOpcode(unsigned RegBitWidth) {
|
||||
switch (RegBitWidth) {
|
||||
case 8:
|
||||
return llvm::X86::MOV8ri;
|
||||
return X86::MOV8ri;
|
||||
case 16:
|
||||
return llvm::X86::MOV16ri;
|
||||
return X86::MOV16ri;
|
||||
case 32:
|
||||
return llvm::X86::MOV32ri;
|
||||
return X86::MOV32ri;
|
||||
case 64:
|
||||
return llvm::X86::MOV64ri;
|
||||
return X86::MOV64ri;
|
||||
}
|
||||
llvm_unreachable("Invalid Value Width");
|
||||
}
|
||||
|
||||
// Generates instruction to load an immediate value into a register.
|
||||
static llvm::MCInst loadImmediate(unsigned Reg, unsigned RegBitWidth,
|
||||
const llvm::APInt &Value) {
|
||||
static MCInst loadImmediate(unsigned Reg, unsigned RegBitWidth,
|
||||
const APInt &Value) {
|
||||
if (Value.getBitWidth() > RegBitWidth)
|
||||
llvm_unreachable("Value must fit in the Register");
|
||||
return llvm::MCInstBuilder(getLoadImmediateOpcode(RegBitWidth))
|
||||
return MCInstBuilder(getLoadImmediateOpcode(RegBitWidth))
|
||||
.addReg(Reg)
|
||||
.addImm(Value.getZExtValue());
|
||||
}
|
||||
|
||||
// Allocates scratch memory on the stack.
|
||||
static llvm::MCInst allocateStackSpace(unsigned Bytes) {
|
||||
return llvm::MCInstBuilder(llvm::X86::SUB64ri8)
|
||||
.addReg(llvm::X86::RSP)
|
||||
.addReg(llvm::X86::RSP)
|
||||
static MCInst allocateStackSpace(unsigned Bytes) {
|
||||
return MCInstBuilder(X86::SUB64ri8)
|
||||
.addReg(X86::RSP)
|
||||
.addReg(X86::RSP)
|
||||
.addImm(Bytes);
|
||||
}
|
||||
|
||||
// Fills scratch memory at offset `OffsetBytes` with value `Imm`.
|
||||
static llvm::MCInst fillStackSpace(unsigned MovOpcode, unsigned OffsetBytes,
|
||||
uint64_t Imm) {
|
||||
return llvm::MCInstBuilder(MovOpcode)
|
||||
static MCInst fillStackSpace(unsigned MovOpcode, unsigned OffsetBytes,
|
||||
uint64_t Imm) {
|
||||
return MCInstBuilder(MovOpcode)
|
||||
// Address = ESP
|
||||
.addReg(llvm::X86::RSP) // BaseReg
|
||||
.addImm(1) // ScaleAmt
|
||||
.addReg(0) // IndexReg
|
||||
.addImm(OffsetBytes) // Disp
|
||||
.addReg(0) // Segment
|
||||
.addReg(X86::RSP) // BaseReg
|
||||
.addImm(1) // ScaleAmt
|
||||
.addReg(0) // IndexReg
|
||||
.addImm(OffsetBytes) // Disp
|
||||
.addReg(0) // Segment
|
||||
// Immediate.
|
||||
.addImm(Imm);
|
||||
}
|
||||
|
||||
// Loads scratch memory into register `Reg` using opcode `RMOpcode`.
|
||||
static llvm::MCInst loadToReg(unsigned Reg, unsigned RMOpcode) {
|
||||
return llvm::MCInstBuilder(RMOpcode)
|
||||
static MCInst loadToReg(unsigned Reg, unsigned RMOpcode) {
|
||||
return MCInstBuilder(RMOpcode)
|
||||
.addReg(Reg)
|
||||
// Address = ESP
|
||||
.addReg(llvm::X86::RSP) // BaseReg
|
||||
.addImm(1) // ScaleAmt
|
||||
.addReg(0) // IndexReg
|
||||
.addImm(0) // Disp
|
||||
.addReg(0); // Segment
|
||||
.addReg(X86::RSP) // BaseReg
|
||||
.addImm(1) // ScaleAmt
|
||||
.addReg(0) // IndexReg
|
||||
.addImm(0) // Disp
|
||||
.addReg(0); // Segment
|
||||
}
|
||||
|
||||
// Releases scratch memory.
|
||||
static llvm::MCInst releaseStackSpace(unsigned Bytes) {
|
||||
return llvm::MCInstBuilder(llvm::X86::ADD64ri8)
|
||||
.addReg(llvm::X86::RSP)
|
||||
.addReg(llvm::X86::RSP)
|
||||
static MCInst releaseStackSpace(unsigned Bytes) {
|
||||
return MCInstBuilder(X86::ADD64ri8)
|
||||
.addReg(X86::RSP)
|
||||
.addReg(X86::RSP)
|
||||
.addImm(Bytes);
|
||||
}
|
||||
|
||||
@ -431,19 +428,19 @@ static llvm::MCInst releaseStackSpace(unsigned Bytes) {
|
||||
// constant and provide methods to load the stack value into a register.
|
||||
namespace {
|
||||
struct ConstantInliner {
|
||||
explicit ConstantInliner(const llvm::APInt &Constant) : Constant_(Constant) {}
|
||||
explicit ConstantInliner(const APInt &Constant) : Constant_(Constant) {}
|
||||
|
||||
std::vector<llvm::MCInst> loadAndFinalize(unsigned Reg, unsigned RegBitWidth,
|
||||
unsigned Opcode);
|
||||
std::vector<MCInst> loadAndFinalize(unsigned Reg, unsigned RegBitWidth,
|
||||
unsigned Opcode);
|
||||
|
||||
std::vector<llvm::MCInst> loadX87STAndFinalize(unsigned Reg);
|
||||
std::vector<MCInst> loadX87STAndFinalize(unsigned Reg);
|
||||
|
||||
std::vector<llvm::MCInst> loadX87FPAndFinalize(unsigned Reg);
|
||||
std::vector<MCInst> loadX87FPAndFinalize(unsigned Reg);
|
||||
|
||||
std::vector<llvm::MCInst> popFlagAndFinalize();
|
||||
std::vector<MCInst> popFlagAndFinalize();
|
||||
|
||||
private:
|
||||
ConstantInliner &add(const llvm::MCInst &Inst) {
|
||||
ConstantInliner &add(const MCInst &Inst) {
|
||||
Instructions.push_back(Inst);
|
||||
return *this;
|
||||
}
|
||||
@ -452,14 +449,14 @@ private:
|
||||
|
||||
static constexpr const unsigned kF80Bytes = 10; // 80 bits.
|
||||
|
||||
llvm::APInt Constant_;
|
||||
std::vector<llvm::MCInst> Instructions;
|
||||
APInt Constant_;
|
||||
std::vector<MCInst> Instructions;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
std::vector<llvm::MCInst> ConstantInliner::loadAndFinalize(unsigned Reg,
|
||||
unsigned RegBitWidth,
|
||||
unsigned Opcode) {
|
||||
std::vector<MCInst> ConstantInliner::loadAndFinalize(unsigned Reg,
|
||||
unsigned RegBitWidth,
|
||||
unsigned Opcode) {
|
||||
assert((RegBitWidth & 7) == 0 && "RegBitWidth must be a multiple of 8 bits");
|
||||
initStack(RegBitWidth / 8);
|
||||
add(loadToReg(Reg, Opcode));
|
||||
@ -467,62 +464,62 @@ std::vector<llvm::MCInst> ConstantInliner::loadAndFinalize(unsigned Reg,
|
||||
return std::move(Instructions);
|
||||
}
|
||||
|
||||
std::vector<llvm::MCInst> ConstantInliner::loadX87STAndFinalize(unsigned Reg) {
|
||||
std::vector<MCInst> ConstantInliner::loadX87STAndFinalize(unsigned Reg) {
|
||||
initStack(kF80Bytes);
|
||||
add(llvm::MCInstBuilder(llvm::X86::LD_F80m)
|
||||
add(MCInstBuilder(X86::LD_F80m)
|
||||
// Address = ESP
|
||||
.addReg(llvm::X86::RSP) // BaseReg
|
||||
.addImm(1) // ScaleAmt
|
||||
.addReg(0) // IndexReg
|
||||
.addImm(0) // Disp
|
||||
.addReg(0)); // Segment
|
||||
if (Reg != llvm::X86::ST0)
|
||||
add(llvm::MCInstBuilder(llvm::X86::ST_Frr).addReg(Reg));
|
||||
.addReg(X86::RSP) // BaseReg
|
||||
.addImm(1) // ScaleAmt
|
||||
.addReg(0) // IndexReg
|
||||
.addImm(0) // Disp
|
||||
.addReg(0)); // Segment
|
||||
if (Reg != X86::ST0)
|
||||
add(MCInstBuilder(X86::ST_Frr).addReg(Reg));
|
||||
add(releaseStackSpace(kF80Bytes));
|
||||
return std::move(Instructions);
|
||||
}
|
||||
|
||||
std::vector<llvm::MCInst> ConstantInliner::loadX87FPAndFinalize(unsigned Reg) {
|
||||
std::vector<MCInst> ConstantInliner::loadX87FPAndFinalize(unsigned Reg) {
|
||||
initStack(kF80Bytes);
|
||||
add(llvm::MCInstBuilder(llvm::X86::LD_Fp80m)
|
||||
add(MCInstBuilder(X86::LD_Fp80m)
|
||||
.addReg(Reg)
|
||||
// Address = ESP
|
||||
.addReg(llvm::X86::RSP) // BaseReg
|
||||
.addImm(1) // ScaleAmt
|
||||
.addReg(0) // IndexReg
|
||||
.addImm(0) // Disp
|
||||
.addReg(0)); // Segment
|
||||
.addReg(X86::RSP) // BaseReg
|
||||
.addImm(1) // ScaleAmt
|
||||
.addReg(0) // IndexReg
|
||||
.addImm(0) // Disp
|
||||
.addReg(0)); // Segment
|
||||
add(releaseStackSpace(kF80Bytes));
|
||||
return std::move(Instructions);
|
||||
}
|
||||
|
||||
std::vector<llvm::MCInst> ConstantInliner::popFlagAndFinalize() {
|
||||
std::vector<MCInst> ConstantInliner::popFlagAndFinalize() {
|
||||
initStack(8);
|
||||
add(llvm::MCInstBuilder(llvm::X86::POPF64));
|
||||
add(MCInstBuilder(X86::POPF64));
|
||||
return std::move(Instructions);
|
||||
}
|
||||
|
||||
void ConstantInliner::initStack(unsigned Bytes) {
|
||||
assert(Constant_.getBitWidth() <= Bytes * 8 &&
|
||||
"Value does not have the correct size");
|
||||
const llvm::APInt WideConstant = Constant_.getBitWidth() < Bytes * 8
|
||||
? Constant_.sext(Bytes * 8)
|
||||
: Constant_;
|
||||
const APInt WideConstant = Constant_.getBitWidth() < Bytes * 8
|
||||
? Constant_.sext(Bytes * 8)
|
||||
: Constant_;
|
||||
add(allocateStackSpace(Bytes));
|
||||
size_t ByteOffset = 0;
|
||||
for (; Bytes - ByteOffset >= 4; ByteOffset += 4)
|
||||
add(fillStackSpace(
|
||||
llvm::X86::MOV32mi, ByteOffset,
|
||||
X86::MOV32mi, ByteOffset,
|
||||
WideConstant.extractBits(32, ByteOffset * 8).getZExtValue()));
|
||||
if (Bytes - ByteOffset >= 2) {
|
||||
add(fillStackSpace(
|
||||
llvm::X86::MOV16mi, ByteOffset,
|
||||
X86::MOV16mi, ByteOffset,
|
||||
WideConstant.extractBits(16, ByteOffset * 8).getZExtValue()));
|
||||
ByteOffset += 2;
|
||||
}
|
||||
if (Bytes - ByteOffset >= 1)
|
||||
add(fillStackSpace(
|
||||
llvm::X86::MOV8mi, ByteOffset,
|
||||
X86::MOV8mi, ByteOffset,
|
||||
WideConstant.extractBits(8, ByteOffset * 8).getZExtValue()));
|
||||
}
|
||||
|
||||
@ -534,28 +531,27 @@ public:
|
||||
ExegesisX86Target() : ExegesisTarget(X86CpuPfmCounters) {}
|
||||
|
||||
private:
|
||||
void addTargetSpecificPasses(llvm::PassManagerBase &PM) const override;
|
||||
void addTargetSpecificPasses(PassManagerBase &PM) const override;
|
||||
|
||||
unsigned getScratchMemoryRegister(const llvm::Triple &TT) const override;
|
||||
unsigned getScratchMemoryRegister(const Triple &TT) const override;
|
||||
|
||||
unsigned getLoopCounterRegister(const llvm::Triple &) const override;
|
||||
unsigned getLoopCounterRegister(const Triple &) const override;
|
||||
|
||||
unsigned getMaxMemoryAccessSize() const override { return 64; }
|
||||
|
||||
void randomizeMCOperand(const Instruction &Instr, const Variable &Var,
|
||||
llvm::MCOperand &AssignedValue,
|
||||
const llvm::BitVector &ForbiddenRegs) const override;
|
||||
MCOperand &AssignedValue,
|
||||
const BitVector &ForbiddenRegs) const override;
|
||||
|
||||
void fillMemoryOperands(InstructionTemplate &IT, unsigned Reg,
|
||||
unsigned Offset) const override;
|
||||
|
||||
void decrementLoopCounterAndJump(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock &TargetMBB,
|
||||
const llvm::MCInstrInfo &MII) const override;
|
||||
const MCInstrInfo &MII) const override;
|
||||
|
||||
std::vector<llvm::MCInst> setRegTo(const llvm::MCSubtargetInfo &STI,
|
||||
unsigned Reg,
|
||||
const llvm::APInt &Value) const override;
|
||||
std::vector<MCInst> setRegTo(const MCSubtargetInfo &STI, unsigned Reg,
|
||||
const APInt &Value) const override;
|
||||
|
||||
ArrayRef<unsigned> getUnavailableRegisters() const override {
|
||||
return makeArrayRef(kUnavailableRegisters,
|
||||
@ -575,8 +571,8 @@ private:
|
||||
return std::make_unique<X86UopsSnippetGenerator>(State, Opts);
|
||||
}
|
||||
|
||||
bool matchesArch(llvm::Triple::ArchType Arch) const override {
|
||||
return Arch == llvm::Triple::x86_64 || Arch == llvm::Triple::x86;
|
||||
bool matchesArch(Triple::ArchType Arch) const override {
|
||||
return Arch == Triple::x86_64 || Arch == Triple::x86;
|
||||
}
|
||||
|
||||
static const unsigned kUnavailableRegisters[4];
|
||||
@ -594,24 +590,21 @@ constexpr const unsigned kLoopCounterReg = X86::R8;
|
||||
|
||||
} // namespace
|
||||
|
||||
void ExegesisX86Target::addTargetSpecificPasses(
|
||||
llvm::PassManagerBase &PM) const {
|
||||
void ExegesisX86Target::addTargetSpecificPasses(PassManagerBase &PM) const {
|
||||
// Lowers FP pseudo-instructions, e.g. ABS_Fp32 -> ABS_F.
|
||||
PM.add(llvm::createX86FloatingPointStackifierPass());
|
||||
PM.add(createX86FloatingPointStackifierPass());
|
||||
}
|
||||
|
||||
unsigned
|
||||
ExegesisX86Target::getScratchMemoryRegister(const llvm::Triple &TT) const {
|
||||
unsigned ExegesisX86Target::getScratchMemoryRegister(const Triple &TT) const {
|
||||
if (!TT.isArch64Bit()) {
|
||||
// FIXME: This would require popping from the stack, so we would have to
|
||||
// add some additional setup code.
|
||||
return 0;
|
||||
}
|
||||
return TT.isOSWindows() ? llvm::X86::RCX : llvm::X86::RDI;
|
||||
return TT.isOSWindows() ? X86::RCX : X86::RDI;
|
||||
}
|
||||
|
||||
unsigned
|
||||
ExegesisX86Target::getLoopCounterRegister(const llvm::Triple &TT) const {
|
||||
unsigned ExegesisX86Target::getLoopCounterRegister(const Triple &TT) const {
|
||||
if (!TT.isArch64Bit()) {
|
||||
return 0;
|
||||
}
|
||||
@ -619,16 +612,15 @@ ExegesisX86Target::getLoopCounterRegister(const llvm::Triple &TT) const {
|
||||
}
|
||||
|
||||
void ExegesisX86Target::randomizeMCOperand(
|
||||
const Instruction &Instr, const Variable &Var,
|
||||
llvm::MCOperand &AssignedValue,
|
||||
const llvm::BitVector &ForbiddenRegs) const {
|
||||
const Instruction &Instr, const Variable &Var, MCOperand &AssignedValue,
|
||||
const BitVector &ForbiddenRegs) const {
|
||||
ExegesisTarget::randomizeMCOperand(Instr, Var, AssignedValue, ForbiddenRegs);
|
||||
|
||||
const Operand &Op = Instr.getPrimaryOperand(Var);
|
||||
switch (Op.getExplicitOperandInfo().OperandType) {
|
||||
case llvm::X86::OperandType::OPERAND_COND_CODE:
|
||||
AssignedValue = llvm::MCOperand::createImm(
|
||||
randomIndex(llvm::X86::CondCode::LAST_VALID_COND));
|
||||
case X86::OperandType::OPERAND_COND_CODE:
|
||||
AssignedValue =
|
||||
MCOperand::createImm(randomIndex(X86::CondCode::LAST_VALID_COND));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -658,7 +650,7 @@ void ExegesisX86Target::fillMemoryOperands(InstructionTemplate &IT,
|
||||
|
||||
void ExegesisX86Target::decrementLoopCounterAndJump(
|
||||
MachineBasicBlock &MBB, MachineBasicBlock &TargetMBB,
|
||||
const llvm::MCInstrInfo &MII) const {
|
||||
const MCInstrInfo &MII) const {
|
||||
BuildMI(&MBB, DebugLoc(), MII.get(X86::ADD64ri8))
|
||||
.addDef(kLoopCounterReg)
|
||||
.addUse(kLoopCounterReg)
|
||||
@ -668,45 +660,44 @@ void ExegesisX86Target::decrementLoopCounterAndJump(
|
||||
.addImm(X86::COND_NE);
|
||||
}
|
||||
|
||||
std::vector<llvm::MCInst>
|
||||
ExegesisX86Target::setRegTo(const llvm::MCSubtargetInfo &STI, unsigned Reg,
|
||||
const llvm::APInt &Value) const {
|
||||
if (llvm::X86::GR8RegClass.contains(Reg))
|
||||
std::vector<MCInst> ExegesisX86Target::setRegTo(const MCSubtargetInfo &STI,
|
||||
unsigned Reg,
|
||||
const APInt &Value) const {
|
||||
if (X86::GR8RegClass.contains(Reg))
|
||||
return {loadImmediate(Reg, 8, Value)};
|
||||
if (llvm::X86::GR16RegClass.contains(Reg))
|
||||
if (X86::GR16RegClass.contains(Reg))
|
||||
return {loadImmediate(Reg, 16, Value)};
|
||||
if (llvm::X86::GR32RegClass.contains(Reg))
|
||||
if (X86::GR32RegClass.contains(Reg))
|
||||
return {loadImmediate(Reg, 32, Value)};
|
||||
if (llvm::X86::GR64RegClass.contains(Reg))
|
||||
if (X86::GR64RegClass.contains(Reg))
|
||||
return {loadImmediate(Reg, 64, Value)};
|
||||
ConstantInliner CI(Value);
|
||||
if (llvm::X86::VR64RegClass.contains(Reg))
|
||||
return CI.loadAndFinalize(Reg, 64, llvm::X86::MMX_MOVQ64rm);
|
||||
if (llvm::X86::VR128XRegClass.contains(Reg)) {
|
||||
if (STI.getFeatureBits()[llvm::X86::FeatureAVX512])
|
||||
return CI.loadAndFinalize(Reg, 128, llvm::X86::VMOVDQU32Z128rm);
|
||||
if (STI.getFeatureBits()[llvm::X86::FeatureAVX])
|
||||
return CI.loadAndFinalize(Reg, 128, llvm::X86::VMOVDQUrm);
|
||||
return CI.loadAndFinalize(Reg, 128, llvm::X86::MOVDQUrm);
|
||||
if (X86::VR64RegClass.contains(Reg))
|
||||
return CI.loadAndFinalize(Reg, 64, X86::MMX_MOVQ64rm);
|
||||
if (X86::VR128XRegClass.contains(Reg)) {
|
||||
if (STI.getFeatureBits()[X86::FeatureAVX512])
|
||||
return CI.loadAndFinalize(Reg, 128, X86::VMOVDQU32Z128rm);
|
||||
if (STI.getFeatureBits()[X86::FeatureAVX])
|
||||
return CI.loadAndFinalize(Reg, 128, X86::VMOVDQUrm);
|
||||
return CI.loadAndFinalize(Reg, 128, X86::MOVDQUrm);
|
||||
}
|
||||
if (llvm::X86::VR256XRegClass.contains(Reg)) {
|
||||
if (STI.getFeatureBits()[llvm::X86::FeatureAVX512])
|
||||
return CI.loadAndFinalize(Reg, 256, llvm::X86::VMOVDQU32Z256rm);
|
||||
if (STI.getFeatureBits()[llvm::X86::FeatureAVX])
|
||||
return CI.loadAndFinalize(Reg, 256, llvm::X86::VMOVDQUYrm);
|
||||
if (X86::VR256XRegClass.contains(Reg)) {
|
||||
if (STI.getFeatureBits()[X86::FeatureAVX512])
|
||||
return CI.loadAndFinalize(Reg, 256, X86::VMOVDQU32Z256rm);
|
||||
if (STI.getFeatureBits()[X86::FeatureAVX])
|
||||
return CI.loadAndFinalize(Reg, 256, X86::VMOVDQUYrm);
|
||||
}
|
||||
if (llvm::X86::VR512RegClass.contains(Reg))
|
||||
if (STI.getFeatureBits()[llvm::X86::FeatureAVX512])
|
||||
return CI.loadAndFinalize(Reg, 512, llvm::X86::VMOVDQU32Zrm);
|
||||
if (llvm::X86::RSTRegClass.contains(Reg)) {
|
||||
if (X86::VR512RegClass.contains(Reg))
|
||||
if (STI.getFeatureBits()[X86::FeatureAVX512])
|
||||
return CI.loadAndFinalize(Reg, 512, X86::VMOVDQU32Zrm);
|
||||
if (X86::RSTRegClass.contains(Reg)) {
|
||||
return CI.loadX87STAndFinalize(Reg);
|
||||
}
|
||||
if (llvm::X86::RFP32RegClass.contains(Reg) ||
|
||||
llvm::X86::RFP64RegClass.contains(Reg) ||
|
||||
llvm::X86::RFP80RegClass.contains(Reg)) {
|
||||
if (X86::RFP32RegClass.contains(Reg) || X86::RFP64RegClass.contains(Reg) ||
|
||||
X86::RFP80RegClass.contains(Reg)) {
|
||||
return CI.loadX87FPAndFinalize(Reg);
|
||||
}
|
||||
if (Reg == llvm::X86::EFLAGS)
|
||||
if (Reg == X86::EFLAGS)
|
||||
return CI.popFlagAndFinalize();
|
||||
return {}; // Not yet implemented.
|
||||
}
|
||||
|
@ -165,13 +165,12 @@ static ExitOnError ExitOnErr;
|
||||
// Checks that only one of OpcodeNames, OpcodeIndex or SnippetsFile is provided,
|
||||
// and returns the opcode indices or {} if snippets should be read from
|
||||
// `SnippetsFile`.
|
||||
static std::vector<unsigned>
|
||||
getOpcodesOrDie(const llvm::MCInstrInfo &MCInstrInfo) {
|
||||
static std::vector<unsigned> getOpcodesOrDie(const MCInstrInfo &MCInstrInfo) {
|
||||
const size_t NumSetFlags = (OpcodeNames.empty() ? 0 : 1) +
|
||||
(OpcodeIndex == 0 ? 0 : 1) +
|
||||
(SnippetsFile.empty() ? 0 : 1);
|
||||
if (NumSetFlags != 1)
|
||||
llvm::report_fatal_error(
|
||||
report_fatal_error(
|
||||
"please provide one and only one of 'opcode-index', 'opcode-name' or "
|
||||
"'snippets-file'");
|
||||
if (!SnippetsFile.empty())
|
||||
@ -185,33 +184,31 @@ getOpcodesOrDie(const llvm::MCInstrInfo &MCInstrInfo) {
|
||||
return Result;
|
||||
}
|
||||
// Resolve opcode name -> opcode.
|
||||
const auto ResolveName =
|
||||
[&MCInstrInfo](llvm::StringRef OpcodeName) -> unsigned {
|
||||
const auto ResolveName = [&MCInstrInfo](StringRef OpcodeName) -> unsigned {
|
||||
for (unsigned I = 1, E = MCInstrInfo.getNumOpcodes(); I < E; ++I)
|
||||
if (MCInstrInfo.getName(I) == OpcodeName)
|
||||
return I;
|
||||
return 0u;
|
||||
};
|
||||
llvm::SmallVector<llvm::StringRef, 2> Pieces;
|
||||
llvm::StringRef(OpcodeNames.getValue())
|
||||
SmallVector<StringRef, 2> Pieces;
|
||||
StringRef(OpcodeNames.getValue())
|
||||
.split(Pieces, ",", /* MaxSplit */ -1, /* KeepEmpty */ false);
|
||||
std::vector<unsigned> Result;
|
||||
for (const llvm::StringRef OpcodeName : Pieces) {
|
||||
for (const StringRef OpcodeName : Pieces) {
|
||||
if (unsigned Opcode = ResolveName(OpcodeName))
|
||||
Result.push_back(Opcode);
|
||||
else
|
||||
llvm::report_fatal_error(
|
||||
llvm::Twine("unknown opcode ").concat(OpcodeName));
|
||||
report_fatal_error(Twine("unknown opcode ").concat(OpcodeName));
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
// Generates code snippets for opcode `Opcode`.
|
||||
static llvm::Expected<std::vector<BenchmarkCode>>
|
||||
static Expected<std::vector<BenchmarkCode>>
|
||||
generateSnippets(const LLVMState &State, unsigned Opcode,
|
||||
const llvm::BitVector &ForbiddenRegs) {
|
||||
const BitVector &ForbiddenRegs) {
|
||||
const Instruction &Instr = State.getIC().getInstr(Opcode);
|
||||
const llvm::MCInstrDesc &InstrDesc = *Instr.Description;
|
||||
const MCInstrDesc &InstrDesc = *Instr.Description;
|
||||
// Ignore instructions that we cannot run.
|
||||
if (InstrDesc.isPseudo())
|
||||
return make_error<Failure>("Unsupported opcode: isPseudo");
|
||||
@ -226,22 +223,22 @@ generateSnippets(const LLVMState &State, unsigned Opcode,
|
||||
State.getExegesisTarget().createSnippetGenerator(BenchmarkMode, State,
|
||||
Options);
|
||||
if (!Generator)
|
||||
llvm::report_fatal_error("cannot create snippet generator");
|
||||
report_fatal_error("cannot create snippet generator");
|
||||
return Generator->generateConfigurations(Instr, ForbiddenRegs);
|
||||
}
|
||||
|
||||
void benchmarkMain() {
|
||||
#ifndef HAVE_LIBPFM
|
||||
llvm::report_fatal_error(
|
||||
report_fatal_error(
|
||||
"benchmarking unavailable, LLVM was built without libpfm.");
|
||||
#endif
|
||||
|
||||
if (exegesis::pfm::pfmInitialize())
|
||||
llvm::report_fatal_error("cannot initialize libpfm");
|
||||
report_fatal_error("cannot initialize libpfm");
|
||||
|
||||
llvm::InitializeNativeTarget();
|
||||
llvm::InitializeNativeTargetAsmPrinter();
|
||||
llvm::InitializeNativeTargetAsmParser();
|
||||
InitializeNativeTarget();
|
||||
InitializeNativeTargetAsmPrinter();
|
||||
InitializeNativeTargetAsmParser();
|
||||
InitializeNativeExegesisTarget();
|
||||
|
||||
const LLVMState State(CpuName);
|
||||
@ -256,16 +253,16 @@ void benchmarkMain() {
|
||||
// -ignore-invalid-sched-class is passed.
|
||||
if (IgnoreInvalidSchedClass &&
|
||||
State.getInstrInfo().get(Opcode).getSchedClass() == 0) {
|
||||
llvm::errs() << State.getInstrInfo().getName(Opcode)
|
||||
<< ": ignoring instruction without sched class\n";
|
||||
errs() << State.getInstrInfo().getName(Opcode)
|
||||
<< ": ignoring instruction without sched class\n";
|
||||
continue;
|
||||
}
|
||||
auto ConfigsForInstr =
|
||||
generateSnippets(State, Opcode, Repetitor->getReservedRegs());
|
||||
if (!ConfigsForInstr) {
|
||||
llvm::logAllUnhandledErrors(
|
||||
ConfigsForInstr.takeError(), llvm::errs(),
|
||||
llvm::Twine(State.getInstrInfo().getName(Opcode)).concat(": "));
|
||||
logAllUnhandledErrors(
|
||||
ConfigsForInstr.takeError(), errs(),
|
||||
Twine(State.getInstrInfo().getName(Opcode)).concat(": "));
|
||||
continue;
|
||||
}
|
||||
std::move(ConfigsForInstr->begin(), ConfigsForInstr->end(),
|
||||
@ -278,11 +275,11 @@ void benchmarkMain() {
|
||||
const std::unique_ptr<BenchmarkRunner> Runner =
|
||||
State.getExegesisTarget().createBenchmarkRunner(BenchmarkMode, State);
|
||||
if (!Runner) {
|
||||
llvm::report_fatal_error("cannot create benchmark runner");
|
||||
report_fatal_error("cannot create benchmark runner");
|
||||
}
|
||||
|
||||
if (NumRepetitions == 0)
|
||||
llvm::report_fatal_error("--num-repetitions must be greater than zero");
|
||||
report_fatal_error("--num-repetitions must be greater than zero");
|
||||
|
||||
// Write to standard output if file is not set.
|
||||
if (BenchmarkFile.empty())
|
||||
@ -304,40 +301,39 @@ static void maybeRunAnalysis(const Analysis &Analyzer, const std::string &Name,
|
||||
if (OutputFilename.empty())
|
||||
return;
|
||||
if (OutputFilename != "-") {
|
||||
llvm::errs() << "Printing " << Name << " results to file '"
|
||||
<< OutputFilename << "'\n";
|
||||
errs() << "Printing " << Name << " results to file '" << OutputFilename
|
||||
<< "'\n";
|
||||
}
|
||||
std::error_code ErrorCode;
|
||||
llvm::raw_fd_ostream ClustersOS(OutputFilename, ErrorCode,
|
||||
llvm::sys::fs::FA_Read |
|
||||
llvm::sys::fs::FA_Write);
|
||||
raw_fd_ostream ClustersOS(OutputFilename, ErrorCode,
|
||||
sys::fs::FA_Read | sys::fs::FA_Write);
|
||||
if (ErrorCode)
|
||||
llvm::report_fatal_error("cannot open out file: " + OutputFilename);
|
||||
report_fatal_error("cannot open out file: " + OutputFilename);
|
||||
if (auto Err = Analyzer.run<Pass>(ClustersOS))
|
||||
llvm::report_fatal_error(std::move(Err));
|
||||
report_fatal_error(std::move(Err));
|
||||
}
|
||||
|
||||
static void analysisMain() {
|
||||
if (BenchmarkFile.empty())
|
||||
llvm::report_fatal_error("--benchmarks-file must be set.");
|
||||
report_fatal_error("--benchmarks-file must be set.");
|
||||
|
||||
if (AnalysisClustersOutputFile.empty() &&
|
||||
AnalysisInconsistenciesOutputFile.empty()) {
|
||||
llvm::report_fatal_error(
|
||||
report_fatal_error(
|
||||
"At least one of --analysis-clusters-output-file and "
|
||||
"--analysis-inconsistencies-output-file must be specified.");
|
||||
}
|
||||
|
||||
llvm::InitializeNativeTarget();
|
||||
llvm::InitializeNativeTargetAsmPrinter();
|
||||
llvm::InitializeNativeTargetDisassembler();
|
||||
InitializeNativeTarget();
|
||||
InitializeNativeTargetAsmPrinter();
|
||||
InitializeNativeTargetDisassembler();
|
||||
// Read benchmarks.
|
||||
const LLVMState State("");
|
||||
const std::vector<InstructionBenchmark> Points =
|
||||
ExitOnErr(InstructionBenchmark::readYamls(State, BenchmarkFile));
|
||||
llvm::outs() << "Parsed " << Points.size() << " benchmark points\n";
|
||||
outs() << "Parsed " << Points.size() << " benchmark points\n";
|
||||
if (Points.empty()) {
|
||||
llvm::errs() << "no benchmarks to analyze\n";
|
||||
errs() << "no benchmarks to analyze\n";
|
||||
return;
|
||||
}
|
||||
// FIXME: Check that all points have the same triple/cpu.
|
||||
@ -345,13 +341,13 @@ static void analysisMain() {
|
||||
|
||||
std::string Error;
|
||||
const auto *TheTarget =
|
||||
llvm::TargetRegistry::lookupTarget(Points[0].LLVMTriple, Error);
|
||||
TargetRegistry::lookupTarget(Points[0].LLVMTriple, Error);
|
||||
if (!TheTarget) {
|
||||
llvm::errs() << "unknown target '" << Points[0].LLVMTriple << "'\n";
|
||||
errs() << "unknown target '" << Points[0].LLVMTriple << "'\n";
|
||||
return;
|
||||
}
|
||||
|
||||
std::unique_ptr<llvm::MCInstrInfo> InstrInfo(TheTarget->createMCInstrInfo());
|
||||
std::unique_ptr<MCInstrInfo> InstrInfo(TheTarget->createMCInstrInfo());
|
||||
|
||||
const auto Clustering = ExitOnErr(InstructionBenchmarkClustering::create(
|
||||
Points, AnalysisClusteringAlgorithm, AnalysisDbscanNumPoints,
|
||||
@ -375,8 +371,8 @@ int main(int Argc, char **Argv) {
|
||||
using namespace llvm;
|
||||
cl::ParseCommandLineOptions(Argc, Argv, "");
|
||||
|
||||
exegesis::ExitOnErr.setExitCodeMapper([](const llvm::Error &Err) {
|
||||
if (Err.isA<llvm::StringError>())
|
||||
exegesis::ExitOnErr.setExitCodeMapper([](const Error &Err) {
|
||||
if (Err.isA<StringError>())
|
||||
return EXIT_SUCCESS;
|
||||
return EXIT_FAILURE;
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user