Nikita Popov a2c0ac06ff
[llvm-exegesis] Fix musl build (#147954)
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.
2025-07-10 16:31:01 +02:00

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