When generating snippets for AArch64 with --opcode-index=-1, the code generator asserts on opcodes that are not supported according to CPU features. The same assertion can be triggered even when generating a serial snippet for a supported opcode if SERIAL_VIA_NON_MEMORY_INSTR execution mode is used and an unsupported instruction is chosen as the "other instruction". Unlike the first case, this one may result in flaky failures because the other instruction is randomly chosen from the instructions suitable for serializing execution. This patch adjusts TableGen emitter for *GenInstrInfo.inc to make possible to query for opcode availability instead of just asserting on unsupported ones. ~~ Huawei RRI, OS Lab Reviewed By: courbet Differential Revision: https://reviews.llvm.org/D146303
81 lines
2.4 KiB
C++
81 lines
2.4 KiB
C++
//===-- Target.cpp ----------------------------------------------*- C++ -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
#include "../Target.h"
|
|
#include "AArch64.h"
|
|
#include "AArch64RegisterInfo.h"
|
|
|
|
#define GET_AVAILABLE_OPCODE_CHECKER
|
|
#include "AArch64GenInstrInfo.inc"
|
|
|
|
namespace llvm {
|
|
namespace exegesis {
|
|
|
|
static unsigned getLoadImmediateOpcode(unsigned RegBitWidth) {
|
|
switch (RegBitWidth) {
|
|
case 32:
|
|
return AArch64::MOVi32imm;
|
|
case 64:
|
|
return AArch64::MOVi64imm;
|
|
}
|
|
llvm_unreachable("Invalid Value Width");
|
|
}
|
|
|
|
// Generates instruction to load an immediate value into a register.
|
|
static MCInst loadImmediate(unsigned Reg, unsigned RegBitWidth,
|
|
const APInt &Value) {
|
|
if (Value.getBitWidth() > RegBitWidth)
|
|
llvm_unreachable("Value must fit in the Register");
|
|
return MCInstBuilder(getLoadImmediateOpcode(RegBitWidth))
|
|
.addReg(Reg)
|
|
.addImm(Value.getZExtValue());
|
|
}
|
|
|
|
#include "AArch64GenExegesis.inc"
|
|
|
|
namespace {
|
|
|
|
class ExegesisAArch64Target : public ExegesisTarget {
|
|
public:
|
|
ExegesisAArch64Target()
|
|
: ExegesisTarget(AArch64CpuPfmCounters, AArch64_MC::isOpcodeAvailable) {}
|
|
|
|
private:
|
|
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 (AArch64::GPR64RegClass.contains(Reg))
|
|
return {loadImmediate(Reg, 64, Value)};
|
|
errs() << "setRegTo is not implemented, results will be unreliable\n";
|
|
return {};
|
|
}
|
|
|
|
bool matchesArch(Triple::ArchType Arch) const override {
|
|
return Arch == Triple::aarch64 || Arch == Triple::aarch64_be;
|
|
}
|
|
|
|
void addTargetSpecificPasses(PassManagerBase &PM) const override {
|
|
// Function return is a pseudo-instruction that needs to be expanded
|
|
PM.add(createAArch64ExpandPseudoPass());
|
|
}
|
|
};
|
|
|
|
} // namespace
|
|
|
|
static ExegesisTarget *getTheExegesisAArch64Target() {
|
|
static ExegesisAArch64Target Target;
|
|
return &Target;
|
|
}
|
|
|
|
void InitializeAArch64ExegesisTarget() {
|
|
ExegesisTarget::registerTarget(getTheExegesisAArch64Target());
|
|
}
|
|
|
|
} // namespace exegesis
|
|
} // namespace llvm
|