Skip to content

Commit 21cd653

Browse files
committed
[llvm-exegesis] [AArch64] Implement memory management required functions
1 parent a75c835 commit 21cd653

File tree

2 files changed

+210
-1
lines changed

2 files changed

+210
-1
lines changed

llvm/tools/llvm-exegesis/lib/AArch64/Target.cpp

Lines changed: 206 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,34 @@
66
//
77
//===----------------------------------------------------------------------===//
88
#include "../Target.h"
9+
#include "../Error.h"
10+
#include "../MmapUtils.h"
11+
#include "../SerialSnippetGenerator.h"
12+
#include "../SnippetGenerator.h"
13+
#include "../SubprocessMemory.h"
914
#include "AArch64.h"
1015
#include "AArch64RegisterInfo.h"
16+
#include "llvm/CodeGen/MachineInstrBuilder.h"
17+
#include "llvm/MC/MCInstBuilder.h"
18+
#include "llvm/MC/MCRegisterInfo.h"
19+
#include <vector>
20+
#define DEBUG_TYPE "exegesis-aarch64-target"
1121

1222
#if defined(__aarch64__) && defined(__linux__)
13-
#include <sys/prctl.h> // For PR_PAC_* constants
23+
#include <sys/mman.h>
24+
#include <sys/syscall.h>
25+
#include <unistd.h> // for getpagesize()
26+
#ifdef HAVE_LIBPFM
27+
#include <perfmon/perf_event.h>
28+
#endif // HAVE_LIBPFM
29+
#include <linux/prctl.h> // For PR_PAC_* constants
30+
#include <sys/prctl.h>
31+
#ifndef PR_PAC_SET_ENABLED_KEYS
32+
#define PR_PAC_SET_ENABLED_KEYS 60
33+
#endif
34+
#ifndef PR_PAC_GET_ENABLED_KEYS
35+
#define PR_PAC_GET_ENABLED_KEYS 61
36+
#endif
1437
#ifndef PR_PAC_APIAKEY
1538
#define PR_PAC_APIAKEY (1UL << 0)
1639
#endif
@@ -197,7 +220,39 @@ class ExegesisAArch64Target : public ExegesisTarget {
197220
ExegesisAArch64Target()
198221
: ExegesisTarget(AArch64CpuPfmCounters, AArch64_MC::isOpcodeAvailable) {}
199222

223+
enum ArgumentRegisters {
224+
CodeSize = AArch64::X12,
225+
AuxiliaryMemoryFD = AArch64::X13,
226+
TempRegister = AArch64::X16,
227+
};
228+
229+
std::vector<MCInst> _generateRegisterStackPop(MCRegister Reg,
230+
int imm = 0) const override {
231+
std::vector<MCInst> Insts;
232+
if (AArch64::GPR32RegClass.contains(Reg) ||
233+
AArch64::GPR64RegClass.contains(Reg)) {
234+
generateRegisterStackPop(Reg, Insts, imm);
235+
return Insts;
236+
}
237+
return {};
238+
}
239+
200240
private:
241+
#ifdef __linux__
242+
std::vector<MCInst> generateExitSyscall(unsigned ExitCode) const override;
243+
std::vector<MCInst>
244+
generateMmap(uintptr_t Address, size_t Length,
245+
uintptr_t FileDescriptorAddress) const override;
246+
void generateMmapAuxMem(std::vector<MCInst> &GeneratedCode) const override;
247+
std::vector<MCInst> generateMemoryInitialSetup() const override;
248+
std::vector<MCInst> setStackRegisterToAuxMem() const override;
249+
uintptr_t getAuxiliaryMemoryStartAddress() const override;
250+
std::vector<MCInst> configurePerfCounter(long Request,
251+
bool SaveRegisters) const override;
252+
std::vector<MCRegister> getArgumentRegisters() const override;
253+
std::vector<MCRegister> getRegistersNeedSaving() const override;
254+
#endif // __linux__
255+
201256
std::vector<MCInst> setRegTo(const MCSubtargetInfo &STI, MCRegister Reg,
202257
const APInt &Value) const override {
203258
if (AArch64::GPR32RegClass.contains(Reg))
@@ -237,6 +292,156 @@ class ExegesisAArch64Target : public ExegesisTarget {
237292

238293
} // namespace
239294

295+
#ifdef __linux__
296+
// true : let use of fixed address to Virtual Address Space Ceiling
297+
// false: let kernel choose the address of the auxiliary memory
298+
bool UseFixedAddress = true;
299+
300+
static constexpr const uintptr_t VAddressSpaceCeiling = 0x0000800000000000;
301+
302+
static void generateRoundToNearestPage(unsigned int TargetRegister,
303+
std::vector<MCInst> &GeneratedCode) {
304+
int PageSizeShift = static_cast<int>(round(log2(getpagesize())));
305+
// Round down to the nearest page by getting rid of the least significant bits
306+
// representing location in the page.
307+
308+
// Single instruction using AND with inverted mask (effectively BIC)
309+
uint64_t BitsToClearMask = (1ULL << PageSizeShift) - 1; // 0xFFF
310+
uint64_t AndMask = ~BitsToClearMask; // ...FFFFFFFFFFFF000
311+
GeneratedCode.push_back(MCInstBuilder(AArch64::ANDXri)
312+
.addReg(TargetRegister) // Xd
313+
.addReg(TargetRegister) // Xn
314+
.addImm(AndMask) // imm bitmask
315+
);
316+
}
317+
318+
std::vector<MCInst>
319+
ExegesisAArch64Target::generateExitSyscall(unsigned ExitCode) const {
320+
std::vector<MCInst> ExitCallCode;
321+
ExitCallCode.push_back(loadImmediate(AArch64::X0, 64, APInt(64, ExitCode)));
322+
generateSysCall(SYS_exit, ExitCallCode); // SYS_exit is 93
323+
return ExitCallCode;
324+
}
325+
326+
std::vector<MCInst>
327+
ExegesisAArch64Target::generateMmap(uintptr_t Address, size_t Length,
328+
uintptr_t FileDescriptorAddress) const {
329+
// mmap(address, length, prot, flags, fd, offset=0)
330+
int flags = MAP_SHARED;
331+
if (Address != 0) {
332+
flags |= MAP_FIXED_NOREPLACE;
333+
}
334+
std::vector<MCInst> MmapCode;
335+
MmapCode.push_back(
336+
loadImmediate(AArch64::X0, 64, APInt(64, Address))); // map adr
337+
MmapCode.push_back(
338+
loadImmediate(AArch64::X1, 64, APInt(64, Length))); // length
339+
MmapCode.push_back(loadImmediate(AArch64::X2, 64,
340+
APInt(64, PROT_READ | PROT_WRITE))); // prot
341+
MmapCode.push_back(loadImmediate(AArch64::X3, 64, APInt(64, flags))); // flags
342+
// FIXME: File descriptor address is not initialized.
343+
// Copy file descriptor location from aux memory into X4
344+
MmapCode.push_back(
345+
loadImmediate(AArch64::X4, 64, APInt(64, FileDescriptorAddress))); // fd
346+
// Dereference file descriptor into FD argument register
347+
// MmapCode.push_back(MCInstBuilder(AArch64::LDRWui)
348+
// .addReg(AArch64::W4) // Destination register
349+
// .addReg(AArch64::X4) // Base register (address)
350+
// .addImm(0)); // Offset (-byte words)
351+
// FIXME: This is not correct.
352+
MmapCode.push_back(loadImmediate(AArch64::X5, 64, APInt(64, 0))); // offset
353+
generateSysCall(SYS_mmap, MmapCode); // SYS_mmap is 222
354+
return MmapCode;
355+
}
356+
357+
void ExegesisAArch64Target::generateMmapAuxMem(
358+
std::vector<MCInst> &GeneratedCode) const {
359+
int fd = -1;
360+
int flags = MAP_SHARED;
361+
uintptr_t address = getAuxiliaryMemoryStartAddress();
362+
if (fd == -1)
363+
flags |= MAP_ANONYMOUS;
364+
if (address != 0)
365+
flags |= MAP_FIXED_NOREPLACE;
366+
int prot = PROT_READ | PROT_WRITE;
367+
368+
GeneratedCode.push_back(
369+
loadImmediate(AArch64::X0, 64, APInt(64, address))); // map adr
370+
GeneratedCode.push_back(loadImmediate(
371+
AArch64::X1, 64,
372+
APInt(64, SubprocessMemory::AuxiliaryMemorySize))); // length
373+
GeneratedCode.push_back(
374+
loadImmediate(AArch64::X2, 64, APInt(64, prot))); // prot
375+
GeneratedCode.push_back(
376+
loadImmediate(AArch64::X3, 64, APInt(64, flags))); // flags
377+
GeneratedCode.push_back(loadImmediate(AArch64::X4, 64, APInt(64, fd))); // fd
378+
GeneratedCode.push_back(
379+
loadImmediate(AArch64::X5, 64, APInt(64, 0))); // offset
380+
generateSysCall(SYS_mmap, GeneratedCode); // SYS_mmap is 222
381+
}
382+
383+
std::vector<MCInst> ExegesisAArch64Target::generateMemoryInitialSetup() const {
384+
std::vector<MCInst> MemoryInitialSetupCode;
385+
generateMmapAuxMem(MemoryInitialSetupCode); // FIXME: Uninit file descriptor
386+
387+
// If using fixed address for auxiliary memory skip this step,
388+
// When using dynamic memory allocation (non-fixed address), we must preserve
389+
// the mmap return value (X0) which contains the allocated memory address.
390+
// This value is saved to the stack to ensure registers requiring memory
391+
// access can retrieve the correct address even if X0 is modified by
392+
// intermediate code.
393+
generateRegisterStackPush(AArch64::X0, MemoryInitialSetupCode);
394+
// FIXME: Ensure stack pointer remains stable to prevent loss of saved address
395+
return MemoryInitialSetupCode;
396+
}
397+
398+
std::vector<MCInst> ExegesisAArch64Target::setStackRegisterToAuxMem() const {
399+
std::vector<MCInst> instructions; // NOP
400+
// TODO: Implement this, Found no need for this in AArch64.
401+
return instructions;
402+
}
403+
404+
uintptr_t ExegesisAArch64Target::getAuxiliaryMemoryStartAddress() const {
405+
if (!UseFixedAddress)
406+
// Allow kernel to select an appropriate memory address
407+
return 0;
408+
// Return the second to last page in the virtual address space
409+
// to try and prevent interference with memory annotations in the snippet
410+
// VAddressSpaceCeiling = 0x0000800000000000
411+
// FIXME: Why 2 pages?
412+
return VAddressSpaceCeiling - (2 * getpagesize());
413+
}
414+
415+
std::vector<MCInst>
416+
ExegesisAArch64Target::configurePerfCounter(long Request,
417+
bool SaveRegisters) const {
418+
std::vector<MCInst> ConfigurePerfCounterCode; // NOP
419+
// FIXME: SYSCALL exits with EBADF error - file descriptor is invalid
420+
// No file is opened previosly to add as file descriptor
421+
return ConfigurePerfCounterCode;
422+
}
423+
424+
std::vector<MCRegister> ExegesisAArch64Target::getArgumentRegisters() const {
425+
return {AArch64::X0, AArch64::X1};
426+
}
427+
428+
std::vector<MCRegister> ExegesisAArch64Target::getRegistersNeedSaving() const {
429+
return {
430+
AArch64::X0,
431+
AArch64::X1,
432+
AArch64::X2,
433+
AArch64::X3,
434+
AArch64::X4,
435+
AArch64::X5,
436+
AArch64::X8,
437+
ArgumentRegisters::TempRegister,
438+
ArgumentRegisters::CodeSize,
439+
ArgumentRegisters::AuxiliaryMemoryFD,
440+
};
441+
}
442+
443+
#endif // __linux__
444+
240445
static ExegesisTarget *getTheExegesisAArch64Target() {
241446
static ExegesisAArch64Target Target;
242447
return &Target;

llvm/tools/llvm-exegesis/lib/Target.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,10 @@ class ExegesisTarget {
308308
return std::make_unique<SavedState>();
309309
}
310310

311+
virtual std::vector<MCInst> _generateRegisterStackPop(MCRegister Reg, int imm = 0) const {
312+
return {};
313+
}
314+
311315
private:
312316
virtual bool matchesArch(Triple::ArchType Arch) const = 0;
313317

0 commit comments

Comments
 (0)