From 08cee6b4160fa2aa124335f9d4dc4c42d0d8cfdf Mon Sep 17 00:00:00 2001 From: fubark Date: Fri, 8 Dec 2023 10:15:07 -0500 Subject: [PATCH] jit: Gen stencils for x64. --- src/jit/{stencils.zig => a64_stencils.zig} | 0 .../{gen-stencils.cy => gen-stencils-a64.cy} | 18 ++- src/jit/gen-stencils-x64.cy | 147 ++++++++++++++++++ src/jit/stencils.c | 9 +- src/jit/x64_stencils.zig | 26 ++++ 5 files changed, 197 insertions(+), 3 deletions(-) rename src/jit/{stencils.zig => a64_stencils.zig} (100%) rename src/jit/{gen-stencils.cy => gen-stencils-a64.cy} (88%) create mode 100644 src/jit/gen-stencils-x64.cy create mode 100644 src/jit/x64_stencils.zig diff --git a/src/jit/stencils.zig b/src/jit/a64_stencils.zig similarity index 100% rename from src/jit/stencils.zig rename to src/jit/a64_stencils.zig diff --git a/src/jit/gen-stencils.cy b/src/jit/gen-stencils-a64.cy similarity index 88% rename from src/jit/gen-stencils.cy rename to src/jit/gen-stencils-a64.cy index 01a2009ba..cc2ddec3a 100644 --- a/src/jit/gen-stencils.cy +++ b/src/jit/gen-stencils-a64.cy @@ -2,7 +2,7 @@ import llvm '../tools/llvm.cy' import os --| ---| Takes stencils.o and generates stencils.zig. +--| Takes stencils.o and generates a64_stencils.zig --| var out = '' @@ -20,12 +20,21 @@ var buf = cbuf.toArray(0, size) var llBin = llvm.CreateBinary(llBuf, none, outMsg) +var binType = llvm.BinaryGetType(llBin) +if binType != llvm.BinaryTypeMachO64L: + throw error.UnexpectedObjectFormat + -- Find text section. my codeBuf = none var llSectIter = llvm.ObjectFileCopySectionIterator(llBin) while llvm.ObjectFileIsSectionIteratorAtEnd(llBin, llSectIter) == 0: var cname = llvm.GetSectionName(llSectIter) + if cname.addr() == 0: + llvm.MoveToNextSection(llSectIter) + continue + var name = cname.fromCstr(0).decode() + if name == '__text': var ccodeBuf = llvm.GetSectionContents(llSectIter) var size = llvm.GetSectionSize(llSectIter) @@ -33,6 +42,9 @@ while llvm.ObjectFileIsSectionIteratorAtEnd(llBin, llSectIter) == 0: break llvm.MoveToNextSection(llSectIter) +if codeBuf == none: + throw error.MissingTextSection + var llSymIter = llvm.ObjectFileCopySymbolIterator(llBin) type Sym object: @@ -51,6 +63,7 @@ while llvm.ObjectFileIsSymbolIteratorAtEnd(llBin, llSymIter) == 0: var cname = llvm.GetSymbolName(llSymIter) var name = cname.fromCstr(0).decode() var addr = llvm.GetSymbolAddress(llSymIter) + -- Size is missing, calculate by sorting symbols and using their address. var sym = [Sym name: name, addr: addr] syms.append(sym) symMap[name] = sym @@ -85,6 +98,7 @@ for syms -> sym, i: out += 'pub const $(sym.name[1..]) = [_]u8{ $(bytes.join(', ')) };\n' +-- llSectIter is already at text section. -- Visit relocation entries and record them as Zig constants. var llRelocIter = llvm.GetRelocations(llSectIter) while llvm.IsRelocationIteratorAtEnd(llSectIter, llRelocIter) == 0: @@ -119,4 +133,4 @@ while llvm.IsRelocationIteratorAtEnd(llSectIter, llRelocIter) == 0: llvm.MoveToNextRelocation(llRelocIter) -os.writeFile('$(curDir)/stencils.zig', out) \ No newline at end of file +os.writeFile('$(curDir)/a64_stencils.zig', out) \ No newline at end of file diff --git a/src/jit/gen-stencils-x64.cy b/src/jit/gen-stencils-x64.cy new file mode 100644 index 000000000..45c21bfae --- /dev/null +++ b/src/jit/gen-stencils-x64.cy @@ -0,0 +1,147 @@ +import llvm '../tools/llvm.cy' +import os + +--| +--| Takes stencils.o and generates x64_stencils.zig +--| + +var out = '' +var curDir = os.dirName(#ModUri) + +my outLLBuf = llvm.ffi.new(.voidPtr) +var outMsg = llvm.ffi.new(.charPtr) +if llvm.CreateMemoryBufferWithContentsOfFile(os.cstr('$(curDir)/stencils.o'), outLLBuf, outMsg) != 0: + throw error.Unexpected + +var llBuf = outLLBuf.get(0, .voidPtr) +var cbuf = llvm.GetBufferStart(llBuf) +var size = llvm.GetBufferSize(llBuf) +var buf = cbuf.toArray(0, size) + +var llBin = llvm.CreateBinary(llBuf, none, outMsg) + +var binType = llvm.BinaryGetType(llBin) +if binType != llvm.BinaryTypeELF64L: + throw error.UnexpectedObjectFormat + +-- Find text section. +my codeBuf = none +var llSectIter = llvm.ObjectFileCopySectionIterator(llBin) +while llvm.ObjectFileIsSectionIteratorAtEnd(llBin, llSectIter) == 0: + var cname = llvm.GetSectionName(llSectIter) + if cname.addr() == 0: + llvm.MoveToNextSection(llSectIter) + continue + + var name = cname.fromCstr(0).decode() + + if name == '.text': + var ccodeBuf = llvm.GetSectionContents(llSectIter) + var size = llvm.GetSectionSize(llSectIter) + codeBuf = ccodeBuf.toArray(0, size) + break + llvm.MoveToNextSection(llSectIter) + +if codeBuf == none: + throw error.MissingTextSection + +var llSymIter = llvm.ObjectFileCopySymbolIterator(llBin) + +type Sym object: + var name string + var addr int + var code array + +-- First pass accumulates the unordered symbols. +var syms = [] +var symMap = [:] +while llvm.ObjectFileIsSymbolIteratorAtEnd(llBin, llSymIter) == 0: + if llvm.GetSectionContainsSymbol(llSectIter, llSymIter) == 0: + -- Not in text section, skip. + llvm.MoveToNextSymbol(llSymIter) + continue + + var cname = llvm.GetSymbolName(llSymIter) + var name = cname.fromCstr(0).decode() + if name == '.text': + llvm.MoveToNextSymbol(llSymIter) + continue + + var addr = llvm.GetSymbolAddress(llSymIter) + var size = llvm.GetSymbolSize(llSymIter) + var code = codeBuf[addr..addr+size] as array + var sym = [Sym name: name, addr: addr, code: code] + syms.append(sym) + symMap[name] = sym + + llvm.MoveToNextSymbol(llSymIter) + +-- Seek to relocation section. +llSectIter = llvm.ObjectFileCopySectionIterator(llBin) +while llvm.ObjectFileIsSectionIteratorAtEnd(llBin, llSectIter) == 0: + var cname = llvm.GetSectionName(llSectIter) + if cname.addr() == 0: + llvm.MoveToNextSection(llSectIter) + continue + + var name = cname.fromCstr(0).decode() + if name == '.rela.text': + break + + llvm.MoveToNextSection(llSectIter) + +-- Visit relocation entries and record them as Zig constants. +var llRelocIter = llvm.GetRelocations(llSectIter) +while llvm.IsRelocationIteratorAtEnd(llSectIter, llRelocIter) == 0: + var symRef = llvm.GetRelocationSymbol(llRelocIter) + var csymName = llvm.GetSymbolName(symRef) + var symName = csymName.fromCstr(0).decode() + + var offset = llvm.GetRelocationOffset(llRelocIter) + var relocType = llvm.GetRelocationType(llRelocIter) + var cname = llvm.GetRelocationTypeName(llRelocIter) + var name = cname.fromCstr(0).decode() + var cvalue = llvm.GetRelocationValueString(llRelocIter) + var value = cname.fromCstr(0).decode() + + var instOffset = 0 + var R_X86_64_PLT32 = 4 + if relocType == R_X86_64_PLT32: + instOffset = 1 + + -- Find relevant func sym. + my found = none + for syms -> sym, i: + if offset >= sym.addr: + if i < syms.len()-1 and offset >= syms[i+1].addr: + continue + found = sym + break + + if found == none: + throw error.MissingSym + + var roffset = (offset - instOffset) - found.addr + if symName.startsWith('cont'): + -- Remove code after continuation. + found.code = found.code[0..roffset] + + -- Skip continuations. + llvm.MoveToNextRelocation(llRelocIter) + continue + + out += 'pub const $(found.name)_$(symName) = $(roffset);\n' + + llvm.MoveToNextRelocation(llRelocIter) + +-- After continuations are removed, gen sym's code. +for syms -> sym, i: + print '$(sym.name) $(sym.addr) $(sym.code.fmt(.x))' + + var bytes = [] + for sym.code -> byte: + bytes.append('0x$(byte.fmt(.x, [pad: `0`, width: 2]))') + + out += 'pub const $(sym.name) = [_]u8{ $(bytes.join(', ')) };\n' + +os.writeFile('$(curDir)/x64_stencils.zig', out) \ No newline at end of file diff --git a/src/jit/stencils.c b/src/jit/stencils.c index 8518e047f..f47b994a5 100644 --- a/src/jit/stencils.c +++ b/src/jit/stencils.c @@ -5,6 +5,9 @@ // clang-wasm: clang -c stencil.c -I../ -O2 --target=wasm32 -mtail-call -o stencils.o // zig: zig cc -c stencils.c -fdouble-square-bracket-attributes -O2 -I../ -o stencils.o +// For x86_64 only the linux target seems to omit the function call prelude: +// clang -c stencils.c -o stencils.o -I../ -O2 -target x86_64-linux + Value hostFunc(VM* vm, const Value* args, u8 nargs); void zDumpJitSection(VM* vm, Value* fp, u64 chunkId, u64 irIdx, u8* startPc, u8* endPc); void cont(Value* fp); @@ -118,4 +121,8 @@ void release(VM* vm, Value* fp, Value val) { } } [[clang::musttail]] return cont3(vm, fp, val); -} \ No newline at end of file +} + +// void test(VM* vm, Value* fp, Value a, Value b) { +// // [[clang::musttail]] return cont4(vm+1, fp, a, b); +// } \ No newline at end of file diff --git a/src/jit/x64_stencils.zig b/src/jit/x64_stencils.zig new file mode 100644 index 000000000..85962cdfe --- /dev/null +++ b/src/jit/x64_stencils.zig @@ -0,0 +1,26 @@ +pub const divInt_divByZero = 60; +pub const callHost_hostFunc = 41; +pub const callHost_interrupt5 = 75; +pub const stringTemplate_zAllocStringTemplate2 = 38; +pub const stringTemplate_interrupt5 = 71; +pub const dumpJitSection_zDumpJitSection = 29; +pub const release_zFreeObject = 49; +pub const addFloat = [_]u8{ 0x66, 0x48, 0x0f, 0x6e, 0xc2, 0x66, 0x48, 0x0f, 0x6e, 0xc9, 0xf2, 0x0f, 0x58, 0xc8, 0x66, 0x48, 0x0f, 0x7e, 0xca }; +pub const subFloat = [_]u8{ 0x66, 0x48, 0x0f, 0x6e, 0xc2, 0x66, 0x48, 0x0f, 0x6e, 0xc9, 0xf2, 0x0f, 0x5c, 0xc1, 0x66, 0x48, 0x0f, 0x7e, 0xc2 }; +pub const mulFloat = [_]u8{ 0x66, 0x48, 0x0f, 0x6e, 0xc2, 0x66, 0x48, 0x0f, 0x6e, 0xc9, 0xf2, 0x0f, 0x59, 0xc8, 0x66, 0x48, 0x0f, 0x7e, 0xca }; +pub const divFloat = [_]u8{ 0x66, 0x48, 0x0f, 0x6e, 0xc2, 0x66, 0x48, 0x0f, 0x6e, 0xc9, 0xf2, 0x0f, 0x5e, 0xc1, 0x66, 0x48, 0x0f, 0x7e, 0xc2 }; +pub const addInt = [_]u8{ 0x48, 0x01, 0xca, 0x48, 0xb8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x48, 0x21, 0xc2, 0x48, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x7f, 0x48, 0x09, 0xc2 }; +pub const subInt = [_]u8{ 0x48, 0x29, 0xca, 0x48, 0xb8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x48, 0x21, 0xc2, 0x48, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x7f, 0x48, 0x09, 0xc2 }; +pub const mulInt = [_]u8{ 0x48, 0x0f, 0xaf, 0xd1, 0x48, 0xb8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x48, 0x21, 0xc2, 0x48, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x7f, 0x48, 0x09, 0xc2 }; +pub const divInt = [_]u8{ 0x49, 0x89, 0xc8, 0x49, 0xc1, 0xe0, 0x10, 0x74, 0x33, 0x49, 0xc1, 0xf8, 0x10, 0x48, 0xc1, 0xe2, 0x10, 0x48, 0xc1, 0xfa, 0x10, 0x48, 0x89, 0xd0, 0x48, 0x99, 0x49, 0xf7, 0xf8, 0x49, 0xb8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x49, 0x21, 0xc0, 0x48, 0xba, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x7f, 0x4c, 0x09, 0xc2 }; +pub const lessInt = [_]u8{ 0x48, 0xc1, 0xe2, 0x10, 0x48, 0xc1, 0xfa, 0x10, 0x49, 0x89, 0xc8, 0x49, 0xc1, 0xe0, 0x10, 0x49, 0xc1, 0xf8, 0x10, 0x49, 0xb9, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xfc, 0x7f, 0x49, 0x8d, 0x41, 0x01, 0x4c, 0x39, 0xc2, 0x49, 0x0f, 0x4d, 0xc1, 0x48, 0x89, 0xc2 }; +pub const intPair = [_]u8{ 0x48, 0xc1, 0xe2, 0x10, 0x48, 0xc1, 0xfa, 0x10, 0x48, 0xc1, 0xe1, 0x10, 0x48, 0xc1, 0xf9, 0x10 }; +pub const isTrue = [_]u8{ 0x48, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0xff, 0xff, 0x48, 0x21, 0xd0, 0x48, 0xb9, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xfc, 0x7f, 0x4c, 0x8d, 0x41, 0x01, 0x45, 0x31, 0xc9, 0x4c, 0x39, 0xc2, 0x41, 0x0f, 0x94, 0xc1, 0x49, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x7f, 0x45, 0x31, 0xd2, 0x4c, 0x39, 0xc2, 0x41, 0x0f, 0x95, 0xc2, 0x48, 0x39, 0xc8, 0x45, 0x0f, 0x45, 0xca, 0x41, 0x0f, 0xb6, 0xd1 }; +pub const lessIntCFlag = [_]u8{ 0x48, 0x39, 0xca, 0x0f }; +pub const call = [_]u8{ 0x48, 0x83, 0xc6, 0x28 }; +pub const callHost = [_]u8{ 0x41, 0x57, 0x41, 0x56, 0x41, 0x55, 0x41, 0x54, 0x53, 0x48, 0x89, 0xcb, 0x49, 0x89, 0xd6, 0x49, 0x89, 0xf7, 0x49, 0x89, 0xfd, 0x49, 0xbc, 0xff, 0xff, 0x00, 0x00, 0x02, 0x00, 0xfc, 0x7f, 0x48, 0x89, 0x77, 0x20, 0x0f, 0xb6, 0xd3, 0x4c, 0x89, 0xf6, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x89, 0xef, 0x4c, 0x89, 0xfe, 0x4c, 0x89, 0xf2, 0x48, 0x89, 0xd9, 0x4c, 0x39, 0xe0, 0x75, 0x11, 0x4d, 0x89, 0xe0, 0x5b, 0x41, 0x5c, 0x41, 0x5d, 0x41, 0x5e, 0x41, 0x5f, 0xe9, 0x00, 0x00, 0x00, 0x00, 0x49, 0x89, 0xc0, 0x5b, 0x41, 0x5c, 0x41, 0x5d, 0x41, 0x5e, 0x41, 0x5f }; +pub const end = [_]u8{ 0x0f, 0xb6, 0xc2, 0x48, 0x89, 0x87, 0xb0, 0x03, 0x00, 0x00 }; +pub const stringTemplate = [_]u8{ 0x41, 0x57, 0x41, 0x56, 0x41, 0x55, 0x41, 0x54, 0x53, 0x4d, 0x89, 0xc6, 0x48, 0x89, 0xcb, 0x49, 0x89, 0xd4, 0x49, 0x89, 0xf7, 0x49, 0x89, 0xfd, 0x41, 0x8d, 0x40, 0x01, 0x0f, 0xb6, 0xd0, 0x45, 0x0f, 0xb6, 0xc6, 0x4c, 0x89, 0xe6, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x85, 0xd2, 0x74, 0x1d, 0x41, 0x89, 0xd0, 0x4c, 0x89, 0xef, 0x4c, 0x89, 0xfe, 0x4c, 0x89, 0xe2, 0x48, 0x89, 0xd9, 0x5b, 0x41, 0x5c, 0x41, 0x5d, 0x41, 0x5e, 0x41, 0x5f, 0xe9, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x89, 0xef, 0x4c, 0x89, 0xfe, 0x48, 0x89, 0xc2, 0x48, 0x89, 0xd9, 0x4d, 0x89, 0xf0, 0x5b, 0x41, 0x5c, 0x41, 0x5d, 0x41, 0x5e, 0x41, 0x5f }; +pub const dumpJitSection = [_]u8{ 0x55, 0x41, 0x57, 0x41, 0x56, 0x41, 0x55, 0x41, 0x54, 0x53, 0x50, 0x4c, 0x89, 0xcb, 0x4d, 0x89, 0xc6, 0x49, 0x89, 0xcf, 0x49, 0x89, 0xd4, 0x49, 0x89, 0xf5, 0x48, 0x89, 0xfd, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x48, 0x89, 0xef, 0x4c, 0x89, 0xee, 0x4c, 0x89, 0xe2, 0x4c, 0x89, 0xf9, 0x4d, 0x89, 0xf0, 0x49, 0x89, 0xd9, 0x48, 0x83, 0xc4, 0x08, 0x5b, 0x41, 0x5c, 0x41, 0x5d, 0x41, 0x5e, 0x41, 0x5f, 0x5d }; +pub const release = [_]u8{ 0x41, 0x57, 0x41, 0x56, 0x53, 0x48, 0x89, 0xd3, 0x49, 0x89, 0xf6, 0x49, 0x89, 0xff, 0x48, 0x89, 0xd0, 0x48, 0xc1, 0xe8, 0x32, 0x3d, 0xff, 0x3f, 0x00, 0x00, 0x72, 0x1a, 0x48, 0xbe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x48, 0x21, 0xde, 0xff, 0x4e, 0x04, 0x75, 0x08, 0x4c, 0x89, 0xff, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x89, 0xff, 0x4c, 0x89, 0xf6, 0x48, 0x89, 0xda, 0x5b, 0x41, 0x5e, 0x41, 0x5f }; +//pub const test = [_]u8{ 0x48, 0x81, 0xc7, 0xb8, 0x03, 0x00, 0x00 };