cjit: Fix some compilation errors

This commit is contained in:
2026-01-27 14:56:39 +01:00
parent 0a3d82a562
commit f2b7817cac
7 changed files with 38 additions and 41 deletions

View File

@@ -87,8 +87,6 @@ pub fn deinit(self: *Self) void {
} }
pub fn compile(self: *Self, filename: []const u8, code: []const u8) !void { pub fn compile(self: *Self, filename: []const u8, code: []const u8) !void {
std.debug.assert(self.state == .init);
self.tokenizer.setSource(filename, code); self.tokenizer.setSource(filename, code);
while (try self.tokenizer.nextToken(self.arena.allocator())) |token| { while (try self.tokenizer.nextToken(self.arena.allocator())) |token| {
_ = token; _ = token;
@@ -97,10 +95,11 @@ pub fn compile(self: *Self, filename: []const u8, code: []const u8) !void {
} }
pub fn setSymbol(self: *Self, comptime T: type, name: []const u8, ptr: *const T) !void { pub fn setSymbol(self: *Self, comptime T: type, name: []const u8, ptr: *const T) !void {
const symbol = self.symbols.getPtr(name) orelse return error.SymbolNotFound; const symbol = self.symbols_needed.getPtr(name) orelse return error.SymbolNotFound;
if (!types.isCompatible(T, symbol.c_type)) return error.IncompatibleType; if (!types.isCompatible(T, symbol.c_type)) return error.IncompatibleType;
symbol.ptr = @ptrCast(ptr); // TODO Figure out const-correctness
symbol.ptr = @ptrCast(@constCast(ptr));
} }
pub fn link(self: *Self) !void { pub fn link(self: *Self) !void {
@@ -121,7 +120,7 @@ pub fn link(self: *Self) !void {
.global_offset_table => { .global_offset_table => {
std.mem.writeInt( std.mem.writeInt(
usize, usize,
self.sections.rodata.data[relocation.addr .. relocation.addr + @sizeOf(usize)], self.sections.rodata.data.items[relocation.addr..][0..@sizeOf(usize)],
target_addr, target_addr,
builtin.cpu.arch.endian(), builtin.cpu.arch.endian(),
); );
@@ -129,10 +128,10 @@ pub fn link(self: *Self) !void {
.rip_disp32 => { .rip_disp32 => {
const rip = text_base + relocation.addr + 4; const rip = text_base + relocation.addr + 4;
const disp64: isize = @bitCast(rip -% target_addr); const disp64: isize = @bitCast(rip -% target_addr);
const disp32 = std.math.cast(i32, disp64) orelse error.RelocationError; const disp32 = std.math.cast(i32, disp64) orelse return error.RelocationError;
std.mem.writeInt( std.mem.writeInt(
i32, i32,
self.sections.text.data[relocation.addr .. relocation.addr + 4], self.sections.text.data.items[relocation.addr..][0..4],
disp32, disp32,
builtin.cpu.arch.endian(), builtin.cpu.arch.endian(),
); );
@@ -146,7 +145,7 @@ pub fn link(self: *Self) !void {
} }
pub fn getSymbol(self: *const Self, comptime T: type, name: []const u8) ?*const T { pub fn getSymbol(self: *const Self, comptime T: type, name: []const u8) ?*const T {
const symbol = self.symbols.get(name) orelse return null; const symbol = self.symbols_located.get(name) orelse return null;
return @ptrCast(@alignCast(symbol.ptr)); return @ptrCast(@alignCast(symbol.ptr));
} }

View File

@@ -112,7 +112,7 @@ pub fn relocateSections(self: *Self, allocator: std.mem.Allocator) !void {
@memcpy(text_slice[0..self.text.data.items.len], self.text.data.items); @memcpy(text_slice[0..self.text.data.items.len], self.text.data.items);
@memcpy(data_slice[0..self.data.data.items.len], self.data.data.items); @memcpy(data_slice[0..self.data.data.items.len], self.data.data.items);
@memcpy(rodata_slice[0..self.rodata_slice.data.items.len], self.rodata.data.items); @memcpy(rodata_slice[0..self.rodata.data.items.len], self.rodata.data.items);
self.text.data.clearAndFree(allocator); self.text.data.clearAndFree(allocator);
self.data.data.clearAndFree(allocator); self.data.data.clearAndFree(allocator);
@@ -124,7 +124,7 @@ pub fn relocateSections(self: *Self, allocator: std.mem.Allocator) !void {
} }
pub fn protectSections(self: *Self) !void { pub fn protectSections(self: *Self) !void {
const sections: []*Section = .{ &self.text, &self.data, &self.rodata }; const sections = [_]*Section{ &self.text, &self.data, &self.rodata };
for (sections) |section| { for (sections) |section| {
switch (builtin.os.tag) { switch (builtin.os.tag) {
@@ -157,7 +157,7 @@ pub fn protectSections(self: *Self) !void {
.linux => { .linux => {
const linux = std.os.linux; const linux = std.os.linux;
const protection = switch (section.protection) { const protection: usize = switch (section.protection) {
.executable => linux.PROT.EXEC, .executable => linux.PROT.EXEC,
.read_only => linux.PROT.READ, .read_only => linux.PROT.READ,
.read_write => linux.PROT.READ | linux.PROT.WRITE, .read_write => linux.PROT.READ | linux.PROT.WRITE,

View File

@@ -57,14 +57,14 @@ pub const Punctuator = enum(u32) {
pub const line_continuation_crlf = strToInt3("\\\r\n"); pub const line_continuation_crlf = strToInt3("\\\r\n");
}; };
fn strToInt1(str: *const u8[1]) u32 { fn strToInt1(str: *const [1]u8) u32 {
return @as(u8, @bitCast(str.*)); return @as(u8, @bitCast(str.*));
} }
fn strToInt2(str: *const u8[2]) u32 { fn strToInt2(str: *const [2]u8) u32 {
return @as(u16, @bitCast(str.*)); return @as(u16, @bitCast(str.*));
} }
fn strToInt3(str: *const u8[3]) u32 { fn strToInt3(str: *const [3]u8) u32 {
return @as(u24, @bitCast(str.*)); return @as(u24, @bitCast(str.*));
} }

View File

@@ -20,7 +20,7 @@ wide_string: std.ArrayList(u32),
pub fn init(arena_allocator: std.mem.Allocator) !Self { pub fn init(arena_allocator: std.mem.Allocator) !Self {
const string_buffer = try arena_allocator.alloc(u8, max_string_length); const string_buffer = try arena_allocator.alloc(u8, max_string_length);
const wide_string_buffer = try arena_allocator.alloc(u8, max_wide_string_length); const wide_string_buffer = try arena_allocator.alloc(u32, max_wide_string_length);
return .{ return .{
.string = .initBuffer(string_buffer), .string = .initBuffer(string_buffer),
@@ -34,7 +34,7 @@ pub fn setSource(self: *Self, filename: []const u8, code: []const u8) void {
} }
pub fn nextToken(self: *Self, arena_allocator: std.mem.Allocator) !?Token { pub fn nextToken(self: *Self, arena_allocator: std.mem.Allocator) !?Token {
self.skipWhitespace(); try self.skipWhitespace();
// TODO Skip C and C++ style comments // TODO Skip C and C++ style comments
// TODO Preprocessor directives // TODO Preprocessor directives
@@ -53,7 +53,7 @@ pub fn nextToken(self: *Self, arena_allocator: std.mem.Allocator) !?Token {
const state = self.it.save(); const state = self.it.save();
self.it.advanceCodepoint(cp); self.it.advanceCodepoint(cp);
const cp2 = self.peekCodepointSkipLineContinuation() orelse 0; const cp2 = try self.peekCodepointSkipLineContinuation() orelse 0;
switch (cp2) { switch (cp2) {
// Wide string // Wide string
@@ -83,7 +83,7 @@ pub fn nextToken(self: *Self, arena_allocator: std.mem.Allocator) !?Token {
next_cp = try self.peekCodepointSkipLineContinuation(); next_cp = try self.peekCodepointSkipLineContinuation();
} }
const identifier = self.str[identifier_start..self.it.ptr]; const identifier = self.it.str[identifier_start..self.it.ptr];
// TODO Preprocessor // TODO Preprocessor
@@ -92,7 +92,7 @@ pub fn nextToken(self: *Self, arena_allocator: std.mem.Allocator) !?Token {
} else if (Builtin.isBuiltin(identifier)) |builtin| { } else if (Builtin.isBuiltin(identifier)) |builtin| {
return .{ .builtin = builtin }; return .{ .builtin = builtin };
} else { } else {
return .{ .identifier = arena_allocator.dupe(u8, identifier) }; return .{ .identifier = try arena_allocator.dupe(u8, identifier) };
} }
}, },
// String // String
@@ -106,6 +106,7 @@ pub fn nextToken(self: *Self, arena_allocator: std.mem.Allocator) !?Token {
self.it.advanceCodepoint(cp); self.it.advanceCodepoint(cp);
// TODO Parse char // TODO Parse char
}, },
else => {},
} }
// Higher code points should've been already handled. The code below may // Higher code points should've been already handled. The code below may
@@ -245,7 +246,7 @@ fn skipWhitespace(self: *Self) !void {
0x000D, 0x000D,
// Space (SP) // Space (SP)
0x0020, 0x0020,
=> try self.it.advanceCodepoint(cp), => self.it.advanceCodepoint(cp),
else => return, else => return,
} }
} }

View File

@@ -78,10 +78,6 @@ pub fn peekThreeBytes(self: Self) ?u32 {
} }
} }
pub fn advanceAsciiBytes(self: *Self, bytes: usize) void {
std.debug.assert(self.str.ptr + bytes <= self.str.len);
}
/// Call with value returned by `peekCodepoint`. /// Call with value returned by `peekCodepoint`.
pub fn advanceCodepoint(self: *Self, cp: u21) void { pub fn advanceCodepoint(self: *Self, cp: u21) void {
std.debug.assert(blk: { std.debug.assert(blk: {

View File

@@ -36,7 +36,7 @@ pub const Gpr = enum(u4) {
} }
pub fn x(self: Gpr) bool { pub fn x(self: Gpr) bool {
return @intFromEnum(self & 0b1000) != 0; return @intFromEnum(self) & 0b1000 != 0;
} }
}; };
@@ -63,17 +63,17 @@ pub const Xmm = enum(u4) {
} }
pub fn x(self: Xmm) bool { pub fn x(self: Xmm) bool {
return @intFromEnum(self & 0b1000) != 0; return @intFromEnum(self) & 0b1000 != 0;
} }
}; };
// --- EMIT HELPERS ------------------------------------------------------------ // --- EMIT HELPERS ------------------------------------------------------------
pub const Rex = packed struct(u8) { pub const Rex = packed struct(u8) {
b: bool, b: bool = false,
x: bool, x: bool = false,
r: bool, r: bool = false,
w: bool, w: bool = false,
/// MUST always be the default value /// MUST always be the default value
prefix: u4 = 0b0100, prefix: u4 = 0b0100,
}; };
@@ -127,19 +127,19 @@ pub fn imm8(rt: *Runtime, value: u8) !void {
pub fn imm16(rt: *Runtime, value: u16) !void { pub fn imm16(rt: *Runtime, value: u16) !void {
var bytes: [2]u8 = undefined; var bytes: [2]u8 = undefined;
std.mem.writeInt(u16, &bytes, value, .little); std.mem.writeInt(u16, &bytes, value, .little);
try rt.sections.text.writeBytes(value, rt.allocator); try rt.sections.text.writeBytes(&bytes, rt.allocator);
} }
pub fn imm32(rt: *Runtime, value: u32) !void { pub fn imm32(rt: *Runtime, value: u32) !void {
var bytes: [4]u8 = undefined; var bytes: [4]u8 = undefined;
std.mem.writeInt(u32, &bytes, value, .little); std.mem.writeInt(u32, &bytes, value, .little);
try rt.sections.text.writeBytes(value, rt.allocator); try rt.sections.text.writeBytes(&bytes, rt.allocator);
} }
pub fn imm64(rt: *Runtime, value: u64) !void { pub fn imm64(rt: *Runtime, value: u64) !void {
var bytes: [8]u8 = undefined; var bytes: [8]u8 = undefined;
std.mem.writeInt(u64, &bytes, value, .little); std.mem.writeInt(u64, &bytes, value, .little);
try rt.sections.text.writeBytes(value, rt.allocator); try rt.sections.text.writeBytes(&bytes, rt.allocator);
} }
pub fn disp8(rt: *Runtime, value: i8) !void { pub fn disp8(rt: *Runtime, value: i8) !void {
@@ -149,7 +149,7 @@ pub fn disp8(rt: *Runtime, value: i8) !void {
pub fn disp32(rt: *Runtime, value: i32) !void { pub fn disp32(rt: *Runtime, value: i32) !void {
var bytes: [4]u8 = undefined; var bytes: [4]u8 = undefined;
std.mem.writeInt(i32, &bytes, value, .little); std.mem.writeInt(i32, &bytes, value, .little);
try rt.sections.text.writeBytes(bytes, rt.allocator); try rt.sections.text.writeBytes(&bytes, rt.allocator);
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@@ -234,7 +234,8 @@ pub fn load(rt: *Runtime, dst_register: Register, src_value: *const StackValue)
switch (src_value.value) { switch (src_value.value) {
.register => |src_register| { .register => |src_register| {
if (dst_register == src_register) return; if (std.meta.eql(dst_register, src_register)) return;
// TODO
}, },
.constant => |constant| switch (dst_register) { .constant => |constant| switch (dst_register) {
.gpr => |dest_gpr| switch (size) { .gpr => |dest_gpr| switch (size) {
@@ -246,7 +247,7 @@ pub fn load(rt: *Runtime, dst_register: Register, src_value: *const StackValue)
// otherwise ah, ch, dh and bh would be used. // otherwise ah, ch, dh and bh would be used.
try rex(rt, .{ .r = dest_gpr.x() }); try rex(rt, .{ .r = dest_gpr.x() });
} }
try op(rt, 0xB0 | dest_gpr.reg()); try op(rt, 0xB0 | @as(u8, dest_gpr.reg()));
try imm8(rt, @truncate(constant)); try imm8(rt, @truncate(constant));
}, },
2 => { 2 => {
@@ -256,7 +257,7 @@ pub fn load(rt: *Runtime, dst_register: Register, src_value: *const StackValue)
if (@intFromEnum(dest_gpr) >= 8) { if (@intFromEnum(dest_gpr) >= 8) {
try rex(rt, .{ .r = dest_gpr.x() }); try rex(rt, .{ .r = dest_gpr.x() });
} }
try op(rt, 0xB8 | dest_gpr.reg()); try op(rt, 0xB8 | @as(u8, dest_gpr.reg()));
try imm16(rt, @truncate(constant)); try imm16(rt, @truncate(constant));
}, },
4 => { 4 => {
@@ -265,14 +266,14 @@ pub fn load(rt: *Runtime, dst_register: Register, src_value: *const StackValue)
if (@intFromEnum(dest_gpr) >= 8) { if (@intFromEnum(dest_gpr) >= 8) {
try rex(rt, .{ .r = dest_gpr.x() }); try rex(rt, .{ .r = dest_gpr.x() });
} }
try op(rt, 0xB8 | dest_gpr.reg()); try op(rt, 0xB8 | @as(u8, dest_gpr.reg()));
try imm32(rt, @truncate(constant)); try imm32(rt, @truncate(constant));
}, },
8 => { 8 => {
// MOV r64, imm64 // MOV r64, imm64
// REX.W + B8+ rd io // REX.W + B8+ rd io
try rex(rt, .{ .r = dest_gpr.x(), .w = true }); try rex(rt, .{ .r = dest_gpr.x(), .w = true });
try op(rt, 0xB8 | dest_gpr.reg()); try op(rt, 0xB8 | @as(u8, dest_gpr.reg()));
try imm64(rt, constant); try imm64(rt, constant);
}, },
else => unreachable, else => unreachable,
@@ -295,7 +296,7 @@ pub fn load(rt: *Runtime, dst_register: Register, src_value: *const StackValue)
try op2(rt, 0x0F, 0x6E); try op2(rt, 0x0F, 0x6E);
// [rip + disp32] // [rip + disp32]
try modrm(rt, .{ .mod = 0b00, .reg = dest_xmm.reg(), .rm = Gpr.rbp.reg() }); try modrm(rt, .{ .mod = 0b00, .reg = dest_xmm.reg(), .rm = Gpr.rbp.reg() });
try allocRodataDisp32(rt, &data); try allocRodataDisp32(rt, data);
}, },
}, },
.symbol => |symbol| {}, .symbol => |symbol| {},

View File

@@ -9,7 +9,7 @@ test {
var rt: cjit.Runtime = try .init(std.testing.allocator); var rt: cjit.Runtime = try .init(std.testing.allocator);
defer rt.deinit(); defer rt.deinit();
try rt.compile( try rt.compile("test.c",
\\int add(int a, int b); \\int add(int a, int b);
\\ \\
\\int add_one(int x) \\int add_one(int x)