Skip to content

Commit

Permalink
jit: Gen stencils for x64.
Browse files Browse the repository at this point in the history
  • Loading branch information
fubark committed Dec 8, 2023
1 parent 0b68f7c commit 08cee6b
Show file tree
Hide file tree
Showing 5 changed files with 197 additions and 3 deletions.
File renamed without changes.
18 changes: 16 additions & 2 deletions src/jit/gen-stencils.cy → src/jit/gen-stencils-a64.cy
Original file line number Diff line number Diff line change
Expand Up @@ -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 = ''
Expand All @@ -20,19 +20,31 @@ 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)
codeBuf = ccodeBuf.toArray(0, size)
break
llvm.MoveToNextSection(llSectIter)

if codeBuf == none:
throw error.MissingTextSection

var llSymIter = llvm.ObjectFileCopySymbolIterator(llBin)

type Sym object:
Expand All @@ -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
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -119,4 +133,4 @@ while llvm.IsRelocationIteratorAtEnd(llSectIter, llRelocIter) == 0:

llvm.MoveToNextRelocation(llRelocIter)

os.writeFile('$(curDir)/stencils.zig', out)
os.writeFile('$(curDir)/a64_stencils.zig', out)
147 changes: 147 additions & 0 deletions src/jit/gen-stencils-x64.cy
Original file line number Diff line number Diff line change
@@ -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)
9 changes: 8 additions & 1 deletion src/jit/stencils.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -118,4 +121,8 @@ void release(VM* vm, Value* fp, Value val) {
}
}
[[clang::musttail]] return cont3(vm, fp, val);
}
}

// void test(VM* vm, Value* fp, Value a, Value b) {
// // [[clang::musttail]] return cont4(vm+1, fp, a, b);
// }
26 changes: 26 additions & 0 deletions src/jit/x64_stencils.zig
Original file line number Diff line number Diff line change
@@ -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 };

0 comments on commit 08cee6b

Please sign in to comment.