| 1 |
// pactor64-llc — LLVM 21 codegen tool for Pactor64 |
| 2 |
// Freestanding: uses Linux x86-64 syscalls only, no libc dependency |
| 3 |
// Compatible with Pactor64's syscall ABI |
| 4 |
#include <llvm/Config/llvm-config.h> |
| 5 |
#include <llvm/Support/TargetSelect.h> |
| 6 |
#include <llvm/MC/TargetRegistry.h> |
| 7 |
#include <llvm/TargetParser/Triple.h> |
| 8 |
#include <llvm/Target/TargetMachine.h> |
| 9 |
#include <llvm/Target/TargetOptions.h> |
| 10 |
#include <llvm/IR/LLVMContext.h> |
| 11 |
#include <llvm/IR/Module.h> |
| 12 |
#include <llvm/IR/IRBuilder.h> |
| 13 |
#include <llvm/IR/LegacyPassManager.h> |
| 14 |
#include <llvm/ADT/SmallVector.h> |
| 15 |
|
| 16 |
using namespace llvm; |
| 17 |
|
| 18 |
// Raw Linux x86-64 syscalls |
| 19 |
static long sys_write(int fd, const void *buf, unsigned long len) { |
| 20 |
long ret; |
| 21 |
__asm__ volatile ("syscall" : "=a"(ret) : "a"(1), "D"(fd), "S"(buf), "d"(len) : "rcx", "r11", "memory"); |
| 22 |
return ret; |
| 23 |
} |
| 24 |
static void sys_exit(int code) __attribute__((noreturn)); |
| 25 |
static void sys_exit(int code) { |
| 26 |
__asm__ volatile ("syscall" :: "a"(60), "D"(code)); |
| 27 |
__builtin_unreachable(); |
| 28 |
} |
| 29 |
static void *sys_brk(void *addr) { |
| 30 |
void *ret; |
| 31 |
__asm__ volatile ("syscall" : "=a"(ret) : "a"(12), "D"(addr) : "rcx", "r11", "memory"); |
| 32 |
return ret; |
| 33 |
} |
| 34 |
|
| 35 |
static void my_puts(const char *s) { |
| 36 |
const char *p = s; |
| 37 |
while (*p) p++; |
| 38 |
sys_write(1, s, p - s); |
| 39 |
} |
| 40 |
|
| 41 |
// Simple heap allocator using brk |
| 42 |
static void *heap_cur = nullptr; |
| 43 |
static void *heap_end = nullptr; |
| 44 |
static void *my_alloc(unsigned long sz) { |
| 45 |
sz = (sz + 15) & ~15UL; |
| 46 |
if (!heap_cur) { heap_cur = sys_brk(nullptr); heap_end = heap_cur; } |
| 47 |
if ((char*)heap_cur + sz > (char*)heap_end) { |
| 48 |
heap_end = sys_brk((char*)heap_end + sz + 1048576); |
| 49 |
if ((char*)heap_end < (char*)heap_cur + sz) { my_puts("OOM!\n"); sys_exit(1); } |
| 50 |
} |
| 51 |
void *r = heap_cur; |
| 52 |
heap_cur = (char*)heap_cur + sz; |
| 53 |
return r; |
| 54 |
} |
| 55 |
|
| 56 |
void *operator new(unsigned long s) { return my_alloc(s); } |
| 57 |
void *operator new[](unsigned long s) { return my_alloc(s); } |
| 58 |
void operator delete(void *p) noexcept { (void)p; } |
| 59 |
void operator delete[](void *p) noexcept { (void)p; } |
| 60 |
void operator delete(void *p, unsigned long) noexcept { (void)p; } |
| 61 |
void operator delete[](void *p, unsigned long) noexcept { (void)p; } |
| 62 |
|
| 63 |
extern "C" { |
| 64 |
int __cxa_atexit(void (*)(void*), void*, void*) { return 0; } |
| 65 |
void __cxa_pure_virtual() { sys_exit(99); } |
| 66 |
void *__dso_handle = nullptr; |
| 67 |
} |
| 68 |
|
| 69 |
extern "C" void _start() { |
| 70 |
my_puts("pactor64-llc: LLVM " LLVM_VERSION_STRING "\n"); |
| 71 |
my_puts("Default target: x86_64-pactor64-elf\n\n"); |
| 72 |
|
| 73 |
LLVMInitializeX86TargetInfo(); |
| 74 |
LLVMInitializeX86Target(); |
| 75 |
LLVMInitializeX86AsmPrinter(); |
| 76 |
|
| 77 |
LLVMContext Ctx; |
| 78 |
Module M("pactor64_demo", Ctx); |
| 79 |
|
| 80 |
FunctionType *FT = FunctionType::get( |
| 81 |
Type::getInt64Ty(Ctx), |
| 82 |
{Type::getInt64Ty(Ctx), Type::getInt64Ty(Ctx)}, false); |
| 83 |
Function *F = Function::Create(FT, Function::ExternalLinkage, "add", M); |
| 84 |
BasicBlock *BB = BasicBlock::Create(Ctx, "entry", F); |
| 85 |
IRBuilder<> Builder(BB); |
| 86 |
auto Args = F->arg_begin(); |
| 87 |
Value *A = &*Args++; Value *B = &*Args; |
| 88 |
Builder.CreateRet(Builder.CreateAdd(A, B, "sum")); |
| 89 |
|
| 90 |
std::string Error; |
| 91 |
const Target *T = TargetRegistry::lookupTarget("x86_64", Error); |
| 92 |
if (!T) { my_puts("Error: no target\n"); sys_exit(1); } |
| 93 |
|
| 94 |
Triple TT("x86_64-unknown-elf"); |
| 95 |
TargetMachine *TM = T->createTargetMachine(TT, "generic", "", TargetOptions(), Reloc::PIC_); |
| 96 |
M.setDataLayout(TM->createDataLayout()); |
| 97 |
|
| 98 |
SmallVector<char, 4096> Buf; |
| 99 |
raw_svector_ostream SOS(Buf); |
| 100 |
legacy::PassManager PM; |
| 101 |
TM->addPassesToEmitFile(PM, SOS, nullptr, CodeGenFileType::AssemblyFile); |
| 102 |
PM.run(M); |
| 103 |
|
| 104 |
my_puts("--- LLVM x86-64 Codegen Output ---\n"); |
| 105 |
sys_write(1, Buf.data(), Buf.size_in_bytes()); |
| 106 |
my_puts("\n--- End ---\n"); |
| 107 |
sys_exit(0); |
| 108 |
} |
| 109 |
|