1//===-- Target.cpp ----------------------------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8#include "../Target.h"
9#include "AArch64.h"
10#include "AArch64RegisterInfo.h"
11
12#if defined(__aarch64__) && defined(__linux__)
13#include <linux/prctl.h> // For PR_PAC_* constants
14#include <sys/prctl.h>
15#ifndef PR_PAC_APIAKEY
16#define PR_PAC_APIAKEY (1UL << 0)
17#endif
18#ifndef PR_PAC_APIBKEY
19#define PR_PAC_APIBKEY (1UL << 1)
20#endif
21#ifndef PR_PAC_APDAKEY
22#define PR_PAC_APDAKEY (1UL << 2)
23#endif
24#ifndef PR_PAC_APDBKEY
25#define PR_PAC_APDBKEY (1UL << 3)
26#endif
27#endif
28
29#define GET_AVAILABLE_OPCODE_CHECKER
30#include "AArch64GenInstrInfo.inc"
31
32namespace llvm {
33namespace exegesis {
34
35static unsigned getLoadImmediateOpcode(unsigned RegBitWidth) {
36 switch (RegBitWidth) {
37 case 32:
38 return AArch64::MOVi32imm;
39 case 64:
40 return AArch64::MOVi64imm;
41 }
42 llvm_unreachable("Invalid Value Width");
43}
44
45// Generates instruction to load an immediate value into a register.
46static MCInst loadImmediate(MCRegister Reg, unsigned RegBitWidth,
47 const APInt &Value) {
48 assert(Value.getBitWidth() <= RegBitWidth &&
49 "Value must fit in the Register");
50 return MCInstBuilder(getLoadImmediateOpcode(RegBitWidth))
51 .addReg(Reg)
52 .addImm(Val: Value.getZExtValue());
53}
54
55static MCInst loadZPRImmediate(MCRegister Reg, unsigned RegBitWidth,
56 const APInt &Value) {
57 assert(Value.getZExtValue() < (1 << 7) &&
58 "Value must be in the range of the immediate opcode");
59 return MCInstBuilder(AArch64::DUP_ZI_D)
60 .addReg(Reg)
61 .addImm(Value.getZExtValue())
62 .addImm(0);
63}
64
65static MCInst loadPPRImmediate(MCRegister Reg, unsigned RegBitWidth,
66 const APInt &Value) {
67 // For PPR, we typically use PTRUE instruction to set predicate registers
68 return MCInstBuilder(AArch64::PTRUE_B)
69 .addReg(Reg)
70 .addImm(31); // All lanes true for 16 bits
71}
72
73// Generates instructions to load an immediate value into an FPCR register.
74static std::vector<MCInst>
75loadFPCRImmediate(MCRegister Reg, unsigned RegBitWidth, const APInt &Value) {
76 MCRegister TempReg = AArch64::X8;
77 MCInst LoadImm = MCInstBuilder(AArch64::MOVi64imm).addReg(TempReg).addImm(0);
78 MCInst MoveToFPCR =
79 MCInstBuilder(AArch64::MSR).addImm(AArch64SysReg::FPCR).addReg(TempReg);
80 return {LoadImm, MoveToFPCR};
81}
82
83// Fetch base-instruction to load an FP immediate value into a register.
84static unsigned getLoadFPImmediateOpcode(unsigned RegBitWidth) {
85 switch (RegBitWidth) {
86 case 16:
87 return AArch64::FMOVH0; // FMOVHi;
88 case 32:
89 return AArch64::FMOVS0; // FMOVSi;
90 case 64:
91 return AArch64::MOVID; // FMOVDi;
92 case 128:
93 return AArch64::MOVIv2d_ns;
94 }
95 llvm_unreachable("Invalid Value Width");
96}
97
98// Generates instruction to load an FP immediate value into a register.
99static MCInst loadFPImmediate(MCRegister Reg, unsigned RegBitWidth,
100 const APInt &Value) {
101 assert(Value.getZExtValue() == 0 && "Expected initialisation value 0");
102 MCInst Instructions =
103 MCInstBuilder(getLoadFPImmediateOpcode(RegBitWidth)).addReg(Reg);
104 if (RegBitWidth >= 64)
105 Instructions.addOperand(Op: MCOperand::createImm(Val: Value.getZExtValue()));
106 return Instructions;
107}
108
109#include "AArch64GenExegesis.inc"
110
111namespace {
112
113class ExegesisAArch64Target : public ExegesisTarget {
114public:
115 ExegesisAArch64Target()
116 : ExegesisTarget(AArch64CpuPfmCounters, AArch64_MC::isOpcodeAvailable) {}
117
118private:
119 std::vector<MCInst> setRegTo(const MCSubtargetInfo &STI, MCRegister Reg,
120 const APInt &Value) const override {
121 if (AArch64::GPR32RegClass.contains(Reg))
122 return {loadImmediate(Reg, RegBitWidth: 32, Value)};
123 if (AArch64::GPR64RegClass.contains(Reg))
124 return {loadImmediate(Reg, RegBitWidth: 64, Value)};
125 if (AArch64::PPRRegClass.contains(Reg))
126 return {loadPPRImmediate(Reg, RegBitWidth: 16, Value)};
127 if (AArch64::FPR8RegClass.contains(Reg))
128 return {loadFPImmediate(Reg - AArch64::B0 + AArch64::D0, 64, Value)};
129 if (AArch64::FPR16RegClass.contains(Reg))
130 return {loadFPImmediate(Reg, RegBitWidth: 16, Value)};
131 if (AArch64::FPR32RegClass.contains(Reg))
132 return {loadFPImmediate(Reg, RegBitWidth: 32, Value)};
133 if (AArch64::FPR64RegClass.contains(Reg))
134 return {loadFPImmediate(Reg, RegBitWidth: 64, Value)};
135 if (AArch64::FPR128RegClass.contains(Reg))
136 return {loadFPImmediate(Reg, RegBitWidth: 128, Value)};
137 if (AArch64::ZPRRegClass.contains(Reg))
138 return {loadZPRImmediate(Reg, RegBitWidth: 128, Value)};
139 if (Reg == AArch64::FPCR)
140 return {loadFPCRImmediate(Reg, RegBitWidth: 32, Value)};
141
142 errs() << "setRegTo is not implemented, results will be unreliable\n";
143 return {};
144 }
145
146 bool matchesArch(Triple::ArchType Arch) const override {
147 return Arch == Triple::aarch64 || Arch == Triple::aarch64_be;
148 }
149
150 void addTargetSpecificPasses(PassManagerBase &PM) const override {
151 // Function return is a pseudo-instruction that needs to be expanded
152 PM.add(P: createAArch64ExpandPseudoPass());
153 }
154};
155
156} // namespace
157
158static ExegesisTarget *getTheExegesisAArch64Target() {
159 static ExegesisAArch64Target Target;
160 return &Target;
161}
162
163void InitializeAArch64ExegesisTarget() {
164 ExegesisTarget::registerTarget(T: getTheExegesisAArch64Target());
165}
166
167} // namespace exegesis
168} // namespace llvm
169

Provided by KDAB

Privacy Policy
Update your C++ knowledge – Modern C++11/14/17 Training
Find out more

source code of llvm/tools/llvm-exegesis/lib/AArch64/Target.cpp