Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# REQUIRES: aarch64-registered-target

# Check for skipping of illegal instruction errors (AUT and LDGM)
# RUN: llvm-exegesis -mcpu=neoverse-v2 -mode=latency --opcode-name=AUTIA --benchmark-phase=assemble-measured-code 2>&1 | FileCheck %s --check-prefix=CHECK-AUTIA
# CHECK-AUTIA-NOT: snippet crashed while running: Illegal instruction

# RUN: llvm-exegesis -mcpu=neoverse-v2 -mode=latency --opcode-name=LDGM --benchmark-phase=assemble-measured-code 2>&1 | FileCheck %s --check-prefix=CHECK-LDGM
# CHECK-LDGM: LDGM: Unsupported opcode: load tag multiple
75 changes: 75 additions & 0 deletions llvm/tools/llvm-exegesis/lib/AArch64/Target.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,58 @@
#include "AArch64.h"
#include "AArch64RegisterInfo.h"

#ifdef __linux__
#include <linux/prctl.h> // For PR_PAC_* constants
#include <sys/prctl.h>
#endif

#define GET_AVAILABLE_OPCODE_CHECKER
#include "AArch64GenInstrInfo.inc"

namespace llvm {
namespace exegesis {

bool isPointerAuth(unsigned Opcode) {
switch (Opcode) {
default:
return false;

// FIXME: Pointer Authentication instructions.
// We would like to measure these instructions, but they can behave
// differently on different platforms, and maybe the snippets need to look
// different for these instructions,
// Platform-specific handling: On Linux, we disable authentication, may
// interfere with measurements. On non-Linux platforms, disable opcodes for
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a note: Exegesis doesn't really support benchmarking on non-Linux platforms.

// now.
case AArch64::AUTDA:
case AArch64::AUTDB:
case AArch64::AUTDZA:
case AArch64::AUTDZB:
case AArch64::AUTIA:
case AArch64::AUTIA1716:
case AArch64::AUTIASP:
case AArch64::AUTIAZ:
case AArch64::AUTIB:
case AArch64::AUTIB1716:
case AArch64::AUTIBSP:
case AArch64::AUTIBZ:
case AArch64::AUTIZA:
case AArch64::AUTIZB:
return true;
}
}

bool isLoadTagMultiple(unsigned Opcode) {
switch (Opcode) {
default:
return false;

// Load tag multiple instruction
case AArch64::LDGM:
return true;
}
}

static unsigned getLoadImmediateOpcode(unsigned RegBitWidth) {
switch (RegBitWidth) {
case 32:
Expand Down Expand Up @@ -134,6 +180,35 @@ class ExegesisAArch64Target : public ExegesisTarget {
// Function return is a pseudo-instruction that needs to be expanded
PM.add(createAArch64ExpandPseudoPass());
}

const char *getIgnoredOpcodeReasonOrNull(const LLVMState &State,
unsigned Opcode) const override {
if (const char *Reason =
ExegesisTarget::getIgnoredOpcodeReasonOrNull(State, Opcode))
return Reason;

if (isPointerAuth(Opcode)) {
#ifdef __linux__
// Disable all PAC keys. Note that while we expect the measurements to
// be the same with PAC keys disabled, they could potentially be lower
// since authentication checks are bypassed.
if (prctl(PR_PAC_SET_ENABLED_KEYS,
PR_PAC_APIAKEY | PR_PAC_APIBKEY | PR_PAC_APDAKEY |
PR_PAC_APDBKEY, // all keys
0, // disable all
0, 0) < 0) {
return "Failed to disable PAC keys";
}
#else
return "Unsupported opcode: isPointerAuth";
#endif
}

if (isLoadTagMultiple(Opcode))
return "Unsupported opcode: load tag multiple";

return nullptr;
}
};

} // namespace
Expand Down
26 changes: 16 additions & 10 deletions llvm/tools/llvm-exegesis/lib/Target.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,18 @@ const char *
ExegesisTarget::getIgnoredOpcodeReasonOrNull(const LLVMState &State,
unsigned Opcode) const {
const MCInstrDesc &InstrDesc = State.getIC().getInstr(Opcode).Description;
if (InstrDesc.isPseudo() || InstrDesc.usesCustomInsertionHook())
return "Unsupported opcode: isPseudo/usesCustomInserter";
if (InstrDesc.isBranch() || InstrDesc.isIndirectBranch())
return "Unsupported opcode: isBranch/isIndirectBranch";
if (InstrDesc.isCall() || InstrDesc.isReturn())
return "Unsupported opcode: isCall/isReturn";
if (InstrDesc.isPseudo())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All the changes in this file seem to be formatting changes that are now irrelevant to the PR? They should probably be reverted.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

split up the first couple of if-statements as I don't like error messages that say "it can be this or that":

Sjoerd suggested 'unclubbing' the unsupported error message to specify the exact reason. Thus, keeping this and formatter's changes for this file only.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer these changes go in a separate patch.

return "Unsupported opcode: isPseudo";
if (InstrDesc.usesCustomInsertionHook())
return "Unsupported opcode: usesCustomInserter";
if (InstrDesc.isBranch())
return "Unsupported opcode: isBranch";
if (InstrDesc.isIndirectBranch())
return "Unsupported opcode: isIndirectBranch";
if (InstrDesc.isCall())
return "Unsupported opcode: isCall";
if (InstrDesc.isReturn())
return "Unsupported opcode: isReturn";
return nullptr;
}

Expand Down Expand Up @@ -113,9 +119,8 @@ ExegesisTarget::createBenchmarkRunner(
case Benchmark::InverseThroughput:
if (BenchmarkPhaseSelector == BenchmarkPhaseSelectorE::Measure &&
!PfmCounters.CycleCounter) {
const char *ModeName = Mode == Benchmark::Latency
? "latency"
: "inverse_throughput";
const char *ModeName =
Mode == Benchmark::Latency ? "latency" : "inverse_throughput";
return make_error<Failure>(
Twine("can't run '")
.concat(ModeName)
Expand Down Expand Up @@ -148,7 +153,8 @@ std::unique_ptr<SnippetGenerator> ExegesisTarget::createSerialSnippetGenerator(
return std::make_unique<SerialSnippetGenerator>(State, Opts);
}

std::unique_ptr<SnippetGenerator> ExegesisTarget::createParallelSnippetGenerator(
std::unique_ptr<SnippetGenerator>
ExegesisTarget::createParallelSnippetGenerator(
const LLVMState &State, const SnippetGenerator::Options &Opts) const {
return std::make_unique<ParallelSnippetGenerator>(State, Opts);
}
Expand Down
3 changes: 1 addition & 2 deletions llvm/tools/llvm-exegesis/lib/Target.h
Original file line number Diff line number Diff line change
Expand Up @@ -268,8 +268,7 @@ class ExegesisTarget {

// Creates a snippet generator for the given mode.
std::unique_ptr<SnippetGenerator>
createSnippetGenerator(Benchmark::ModeE Mode,
const LLVMState &State,
createSnippetGenerator(Benchmark::ModeE Mode, const LLVMState &State,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here regarding formatting.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reverted back formatting changes, Thanks!

const SnippetGenerator::Options &Opts) const;
// Creates a benchmark runner for the given mode.
Expected<std::unique_ptr<BenchmarkRunner>> createBenchmarkRunner(
Expand Down
9 changes: 3 additions & 6 deletions llvm/tools/llvm-exegesis/llvm-exegesis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ static cl::opt<std::string> MAttr(
static ExitOnError ExitOnErr("llvm-exegesis error: ");

// Helper function that logs the error(s) and exits.
template <typename... ArgTs> static void ExitWithError(ArgTs &&... Args) {
template <typename... ArgTs> static void ExitWithError(ArgTs &&...Args) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same for this file for formatting.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, Thanks :)

ExitOnErr(make_error<Failure>(std::forward<ArgTs>(Args)...));
}

Expand Down Expand Up @@ -444,8 +444,7 @@ static void runBenchmarkConfigurations(
Benchmark &Result = AllResults.front();

// If any of our measurements failed, pretend they all have failed.
if (AllResults.size() > 1 &&
any_of(AllResults, [](const Benchmark &R) {
if (AllResults.size() > 1 && any_of(AllResults, [](const Benchmark &R) {
return R.Measurements.empty();
}))
Result.Measurements.clear();
Expand Down Expand Up @@ -505,7 +504,6 @@ void benchmarkMain() {
if (!Runner) {
ExitWithError("cannot create benchmark runner");
}

const auto Opcodes = getOpcodesOrDie(State);
std::vector<BenchmarkCode> Configurations;

Expand Down Expand Up @@ -643,8 +641,7 @@ static void analysisMain() {
errorOrToExpected(MemoryBuffer::getFile(BenchmarkFile, /*IsText=*/true)));

const auto TriplesAndCpus = ExitOnFileError(
BenchmarkFile,
Benchmark::readTriplesAndCpusFromYamls(*MemoryBuffer));
BenchmarkFile, Benchmark::readTriplesAndCpusFromYamls(*MemoryBuffer));
if (TriplesAndCpus.empty()) {
errs() << "no benchmarks to analyze\n";
return;
Expand Down