[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:
Clement Courbet 2019-10-09 11:58:42 +00:00
parent 99479f2b1a
commit de4e3c1cf7
37 changed files with 821 additions and 904 deletions

View File

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

View File

@ -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 << "&lt;";
@ -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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 &regInfo() const { return RegInfo; }
const MCRegisterInfo &regInfo() 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);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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