
We should not include both linux/prctl.h and sys/prctl.h. This works with glibc because the latter includes the former, but breaks with musl because the latter redeclares the contents of the former, resulting in: ``` /usr/local/aarch64-linux-musl/include/sys/prctl.h:88:8: error: redefinition of 'struct prctl_mm_map' 88 | struct prctl_mm_map { | ^~~~~~~~~~~~ In file included from /checkout/src/llvm-project/llvm/tools/llvm-exegesis/lib/AArch64/Target.cpp:13: /usr/local/aarch64-linux-musl/include/linux/prctl.h:134:8: note: previous definition of 'struct prctl_mm_map' 134 | struct prctl_mm_map { | ^~~~~~~~~~~~ ``` Fixes https://github.com/llvm/llvm-project/issues/139443.
168 lines
5.4 KiB
C++
168 lines
5.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"
|
|
|
|
#if defined(__aarch64__) && defined(__linux__)
|
|
#include <sys/prctl.h> // For PR_PAC_* constants
|
|
#ifndef PR_PAC_APIAKEY
|
|
#define PR_PAC_APIAKEY (1UL << 0)
|
|
#endif
|
|
#ifndef PR_PAC_APIBKEY
|
|
#define PR_PAC_APIBKEY (1UL << 1)
|
|
#endif
|
|
#ifndef PR_PAC_APDAKEY
|
|
#define PR_PAC_APDAKEY (1UL << 2)
|
|
#endif
|
|
#ifndef PR_PAC_APDBKEY
|
|
#define PR_PAC_APDBKEY (1UL << 3)
|
|
#endif
|
|
#endif
|
|
|
|
#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(MCRegister Reg, unsigned RegBitWidth,
|
|
const APInt &Value) {
|
|
assert(Value.getBitWidth() <= RegBitWidth &&
|
|
"Value must fit in the Register");
|
|
return MCInstBuilder(getLoadImmediateOpcode(RegBitWidth))
|
|
.addReg(Reg)
|
|
.addImm(Value.getZExtValue());
|
|
}
|
|
|
|
static MCInst loadZPRImmediate(MCRegister Reg, unsigned RegBitWidth,
|
|
const APInt &Value) {
|
|
assert(Value.getZExtValue() < (1 << 7) &&
|
|
"Value must be in the range of the immediate opcode");
|
|
return MCInstBuilder(AArch64::DUP_ZI_D)
|
|
.addReg(Reg)
|
|
.addImm(Value.getZExtValue())
|
|
.addImm(0);
|
|
}
|
|
|
|
static MCInst loadPPRImmediate(MCRegister Reg, unsigned RegBitWidth,
|
|
const APInt &Value) {
|
|
// For PPR, we typically use PTRUE instruction to set predicate registers
|
|
return MCInstBuilder(AArch64::PTRUE_B)
|
|
.addReg(Reg)
|
|
.addImm(31); // All lanes true for 16 bits
|
|
}
|
|
|
|
// Generates instructions to load an immediate value into an FPCR register.
|
|
static std::vector<MCInst>
|
|
loadFPCRImmediate(MCRegister Reg, unsigned RegBitWidth, const APInt &Value) {
|
|
MCRegister TempReg = AArch64::X8;
|
|
MCInst LoadImm = MCInstBuilder(AArch64::MOVi64imm).addReg(TempReg).addImm(0);
|
|
MCInst MoveToFPCR =
|
|
MCInstBuilder(AArch64::MSR).addImm(AArch64SysReg::FPCR).addReg(TempReg);
|
|
return {LoadImm, MoveToFPCR};
|
|
}
|
|
|
|
// Fetch base-instruction to load an FP immediate value into a register.
|
|
static unsigned getLoadFPImmediateOpcode(unsigned RegBitWidth) {
|
|
switch (RegBitWidth) {
|
|
case 16:
|
|
return AArch64::FMOVH0; // FMOVHi;
|
|
case 32:
|
|
return AArch64::FMOVS0; // FMOVSi;
|
|
case 64:
|
|
return AArch64::MOVID; // FMOVDi;
|
|
case 128:
|
|
return AArch64::MOVIv2d_ns;
|
|
}
|
|
llvm_unreachable("Invalid Value Width");
|
|
}
|
|
|
|
// Generates instruction to load an FP immediate value into a register.
|
|
static MCInst loadFPImmediate(MCRegister Reg, unsigned RegBitWidth,
|
|
const APInt &Value) {
|
|
assert(Value.getZExtValue() == 0 && "Expected initialisation value 0");
|
|
MCInst Instructions =
|
|
MCInstBuilder(getLoadFPImmediateOpcode(RegBitWidth)).addReg(Reg);
|
|
if (RegBitWidth >= 64)
|
|
Instructions.addOperand(MCOperand::createImm(Value.getZExtValue()));
|
|
return Instructions;
|
|
}
|
|
|
|
#include "AArch64GenExegesis.inc"
|
|
|
|
namespace {
|
|
|
|
class ExegesisAArch64Target : public ExegesisTarget {
|
|
public:
|
|
ExegesisAArch64Target()
|
|
: ExegesisTarget(AArch64CpuPfmCounters, AArch64_MC::isOpcodeAvailable) {}
|
|
|
|
private:
|
|
std::vector<MCInst> setRegTo(const MCSubtargetInfo &STI, MCRegister 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)};
|
|
if (AArch64::PPRRegClass.contains(Reg))
|
|
return {loadPPRImmediate(Reg, 16, Value)};
|
|
if (AArch64::FPR8RegClass.contains(Reg))
|
|
return {loadFPImmediate(Reg - AArch64::B0 + AArch64::D0, 64, Value)};
|
|
if (AArch64::FPR16RegClass.contains(Reg))
|
|
return {loadFPImmediate(Reg, 16, Value)};
|
|
if (AArch64::FPR32RegClass.contains(Reg))
|
|
return {loadFPImmediate(Reg, 32, Value)};
|
|
if (AArch64::FPR64RegClass.contains(Reg))
|
|
return {loadFPImmediate(Reg, 64, Value)};
|
|
if (AArch64::FPR128RegClass.contains(Reg))
|
|
return {loadFPImmediate(Reg, 128, Value)};
|
|
if (AArch64::ZPRRegClass.contains(Reg))
|
|
return {loadZPRImmediate(Reg, 128, Value)};
|
|
if (Reg == AArch64::FPCR)
|
|
return {loadFPCRImmediate(Reg, 32, 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
|