Skip to content

Commit

Permalink
avoid using Zig std for builtin translation
Browse files Browse the repository at this point in the history
  • Loading branch information
Vexu committed Dec 27, 2024
1 parent afdf9da commit 7971b5e
Show file tree
Hide file tree
Showing 30 changed files with 345 additions and 37 deletions.
111 changes: 85 additions & 26 deletions src/Translator.zig
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const Type = aro.Type;
const ast = @import("ast.zig");
const ZigNode = ast.Node;
const ZigTag = ZigNode.Tag;
const builtins = @import("builtins.zig");
const Scope = @import("Scope.zig");

const Translator = @This();
Expand Down Expand Up @@ -55,6 +56,9 @@ tree: Tree,
comp: *aro.Compilation,
mapper: aro.TypeMapper,

rendered_builtins: std.EnumSet(builtins.Builtin) = .{},
render_buf: std.ArrayList(u8),

fn getMangle(t: *Translator) u32 {
t.mangle_count += 1;
return t.mangle_count;
Expand Down Expand Up @@ -137,15 +141,15 @@ pub fn translate(
gpa: mem.Allocator,
comp: *aro.Compilation,
tree: aro.Tree,
) !std.zig.Ast {
) ![]u8 {
const mapper = tree.comp.string_interner.getFastTypeMapper(tree.comp.gpa) catch tree.comp.string_interner.getSlowTypeMapper();
defer mapper.deinit(tree.comp.gpa);

var arena_allocator = std.heap.ArenaAllocator.init(gpa);
defer arena_allocator.deinit();
const arena = arena_allocator.allocator();

var context: Translator = .{
var translator: Translator = .{
.gpa = gpa,
.arena = arena,
.alias_list = .empty,
Expand All @@ -154,39 +158,39 @@ pub fn translate(
.comp = comp,
.mapper = mapper,
.tree = tree,
.render_buf = .init(gpa),
};
context.global_scope.* = Scope.Root.init(&context);
translator.global_scope.* = Scope.Root.init(&translator);
defer {
context.decl_table.deinit(gpa);
context.alias_list.deinit(gpa);
context.global_names.deinit(gpa);
context.weak_global_names.deinit(gpa);
context.opaque_demotes.deinit(gpa);
context.unnamed_typedefs.deinit(gpa);
context.typedefs.deinit(gpa);
context.global_scope.deinit();
context.pattern_list.deinit(gpa);
}

inline for (@typeInfo(std.zig.c_builtins).@"struct".decls) |decl| {
const builtin_fn = try ZigTag.pub_var_simple.create(arena, .{
.name = decl.name,
.init = try ZigTag.import_c_builtin.create(arena, decl.name),
});
try addTopLevelDecl(&context, decl.name, builtin_fn);
translator.decl_table.deinit(gpa);
translator.alias_list.deinit(gpa);
translator.global_names.deinit(gpa);
translator.weak_global_names.deinit(gpa);
translator.opaque_demotes.deinit(gpa);
translator.unnamed_typedefs.deinit(gpa);
translator.typedefs.deinit(gpa);
translator.global_scope.deinit();
translator.pattern_list.deinit(gpa);
translator.render_buf.deinit();
}

try prepopulateGlobalNameTable(&context);
try transTopLevelDecls(&context);
try prepopulateGlobalNameTable(&translator);
try transTopLevelDecls(&translator);

for (context.alias_list.items) |alias| {
if (!context.global_scope.sym_table.contains(alias.alias)) {
for (translator.alias_list.items) |alias| {
if (!translator.global_scope.sym_table.contains(alias.alias)) {
const node = try ZigTag.alias.create(arena, .{ .actual = alias.alias, .mangled = alias.name });
try addTopLevelDecl(&context, alias.alias, node);
try addTopLevelDecl(&translator, alias.alias, node);
}
}

return ast.render(gpa, context.global_scope.nodes.items);
var zig_ast = try ast.render(gpa, translator.global_scope.nodes.items);
defer {
gpa.free(zig_ast.source);
zig_ast.deinit(gpa);
}
try zig_ast.renderToArrayList(&translator.render_buf, .{});
return translator.render_buf.toOwnedSlice();
}

fn prepopulateGlobalNameTable(t: *Translator) !void {
Expand Down Expand Up @@ -1352,6 +1356,9 @@ fn transExpr(t: *Translator, scope: *Scope, expr: NodeIndex, used: ResultUsed) T

.shl_expr => return t.transShiftExpr(scope, expr, .shl, used),
.shr_expr => return t.transShiftExpr(scope, expr, .shr, used),

.builtin_call_expr => return t.transBuiltinCall(scope, expr, used),
.builtin_call_expr_one => return t.transBuiltinCall(scope, expr, used),
else => unreachable, // Not an expression.
}
}
Expand Down Expand Up @@ -1582,6 +1589,58 @@ fn transPointerArithmeticSignedOp(
return t.transCreateNodeInfixOp(if (is_add) .add else .sub, lhs_node, bitcast_node, used);
}

fn transBuiltinCall(
t: *Translator,
scope: *Scope,
call_node: NodeIndex,
used: ResultUsed,
) TransError!ZigNode {
// TODO would be nice to have a helper to extract the builtin name
const builtin_name, const arg_nodes = switch (t.nodeTag(call_node)) {
.builtin_call_expr => blk: {
const range = t.nodeData(call_node).range;
const name = t.tree.tokSlice(@intFromEnum(t.tree.data[range.start]));
const arg_nodes = t.tree.data[range.start + 1 .. range.end];
break :blk .{ name, arg_nodes };
},
.builtin_call_expr_one => blk: {
const decl = t.nodeData(call_node).decl;
const name = t.tree.tokSlice(decl.name);
const ptr: [*]const NodeIndex = @ptrCast(&decl.node);
const slice = ptr[0..1];
const end = std.mem.indexOfScalar(NodeIndex, slice, .none) orelse 1;
const arg_nodes = slice[0..end];
break :blk .{ name, arg_nodes };
},
else => unreachable,
};
const builtin = std.meta.stringToEnum(builtins.Builtin, builtin_name) orelse {
const call_loc = 0; // TODO builtin call source location
return t.fail(error.UnsupportedTranslation, call_loc, "TODO implement function '{s}' in std.zig.c_builtins", .{builtin_name});
};

if (builtin.source()) |source| {
if (!t.rendered_builtins.contains(builtin)) {
t.rendered_builtins.insert(builtin);
try t.render_buf.appendSlice(source);
}

const args = try t.arena.alloc(ZigNode, arg_nodes.len);
for (arg_nodes, args) |arg_node, *arg| {
arg.* = try t.transExpr(scope, arg_node, .used);
}

const res = try ZigTag.call.create(t.arena, .{
.lhs = try ZigTag.fn_identifier.create(t.arena, builtin_name),
.args = args,
});
if (t.nodeType(call_node).is(.void)) return res;
return t.maybeSuppressResult(used, res);
}

@panic("TODO transBulitinCall others");
}

// =====================
// Node creation helpers
// =====================
Expand Down
2 changes: 1 addition & 1 deletion src/ast.zig
Original file line number Diff line number Diff line change
Expand Up @@ -785,7 +785,7 @@ pub fn render(gpa: Allocator, nodes: []const Node) !std.zig.Ast {
defer ctx.tokens.deinit(gpa);

// Estimate that each top level node has 10 child nodes.
const estimated_node_count = nodes.len * 10;
const estimated_node_count = nodes.len * 10 + 1; // +1 for the .root node
try ctx.nodes.ensureTotalCapacity(gpa, estimated_node_count);
// Estimate that each each node has 2 tokens.
const estimated_tokens_count = estimated_node_count * 2;
Expand Down
93 changes: 93 additions & 0 deletions src/builtins.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
pub const Builtin = enum {
__builtin_bswap16,
__builtin_bswap32,
__builtin_bswap64,
__builtin_signbit,
__builtin_signbitf,
__builtin_popcount,
__builtin_ctz,
__builtin_clz,
__builtin_sqrt,
__builtin_sqrtf,
__builtin_sin,
__builtin_sinf,
__builtin_cos,
__builtin_cosf,
__builtin_exp,
__builtin_expf,
__builtin_exp2,
__builtin_exp2f,
__builtin_log,
__builtin_logf,
__builtin_log2,
__builtin_log2f,
__builtin_log10,
__builtin_log10f,
__builtin_abs,
__builtin_labs,
__builtin_llabs,
__builtin_fabs,
__builtin_fabsf,
__builtin_floor,
__builtin_floorf,
__builtin_ceil,
__builtin_ceilf,
__builtin_trunc,
__builtin_truncf,
__builtin_round,
__builtin_roundf,
__builtin_strlen,
__builtin_strcmp,
__builtin_object_size,
__builtin___memset_chk,
__builtin_memset,
__builtin___memcpy_chk,
__builtin_memcpy,
__builtin_nanf,
__builtin_huge_valf,
__builtin_inff,
__builtin_isnan,
__builtin_isinf,
__builtin_isinf_sign,
__has_builtin,
__builtin_assume,
__builtin_unreachable,
__builtin_constant_p,
__builtin_mul_overflow,

// __builtin_alloca_with_align is not currently implemented.
// It is used in a run and a translate test to ensure that non-implemented
// builtins are correctly demoted. If you implement __builtin_alloca_with_align,
// please update the tests to use a different non-implemented builtin.

pub fn source(b: Builtin) ?[]const u8 {
return switch (b) {
.__builtin_signbit => @embedFile("builtins/signbit.zig"),
.__builtin_signbitf => @embedFile("builtins/signbitf.zig"),
.__builtin_popcount => @embedFile("builtins/popcount.zig"),
.__builtin_ctz => @embedFile("builtins/ctz.zig"),
.__builtin_clz => @embedFile("builtins/clz.zig"),
.__builtin_abs => @embedFile("builtins/abs.zig"),
.__builtin_labs => @embedFile("builtins/labs.zig"),
.__builtin_llabs => @embedFile("builtins/llabs.zig"),
.__builtin_strlen => @embedFile("builtins/strlen.zig"),
.__builtin_strcmp => @embedFile("builtins/strcmp.zig"),
.__builtin_object_size => @embedFile("builtins/object_size.zig"),
.__builtin___memset_chk => @embedFile("builtins/memset_chk.zig"),
.__builtin_memset => @embedFile("builtins/memset.zig"),
.__builtin___memcpy_chk => @embedFile("builtins/memcpy_chk.zig"),
.__builtin_memcpy => @embedFile("builtins/memcpy.zig"),
.__builtin_nanf => @embedFile("builtins/nanf.zig"),
.__builtin_huge_valf => @embedFile("builtins/huge_valf.zig"),
.__builtin_inff => @embedFile("builtins/inff.zig"),
.__builtin_isnan => @embedFile("builtins/isnan.zig"),
.__builtin_isinf => @embedFile("builtins/isinf.zig"),
.__builtin_isinf_sign => @embedFile("builtins/isinf_sign.zig"),
.__has_builtin => @embedFile("builtins/has_builtin.zig"),
.__builtin_assume => @embedFile("builtins/assume.zig"),
.__builtin_constant_p => @embedFile("builtins/constant_p.zig"),
.__builtin_mul_overflow => @embedFile("builtins/mul_overflow.zig"),
else => return null,
};
}
};
4 changes: 4 additions & 0 deletions src/builtins/abs.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/// Standard C Library bug: The absolute value of the most negative integer remains negative.
pub inline fn __builtin_abs(val: c_int) c_int {
return if (val == @import("std").math.minInt(c_int)) val else @intCast(@abs(val));
}
3 changes: 3 additions & 0 deletions src/builtins/assume.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub inline fn __builtin_assume(cond: bool) void {
if (!cond) unreachable;
}
6 changes: 6 additions & 0 deletions src/builtins/clz.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/// Returns the number of leading 0-bits in x, starting at the most significant bit position.
/// In C if `val` is 0, the result is undefined; in zig it's the number of bits in a c_uint
pub inline fn __builtin_clz(val: c_uint) c_int {
@setRuntimeSafety(false);
return @as(c_int, @bitCast(@as(c_uint, @clz(val))));
}
4 changes: 4 additions & 0 deletions src/builtins/constant_p.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
pub inline fn __builtin_constant_p(expr: anytype) c_int {
_ = expr;
return @intFromBool(false);
}
6 changes: 6 additions & 0 deletions src/builtins/ctz.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/// Returns the number of trailing 0-bits in val, starting at the least significant bit position.
/// In C if `val` is 0, the result is undefined; in zig it's the number of bits in a c_uint
pub inline fn __builtin_ctz(val: c_uint) c_int {
@setRuntimeSafety(false);
return @as(c_int, @bitCast(@as(c_uint, @ctz(val))));
}
4 changes: 4 additions & 0 deletions src/builtins/has_builtin.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
pub inline fn __has_builtin(func: anytype) c_int {
_ = func;
return @intFromBool(true);
}
3 changes: 3 additions & 0 deletions src/builtins/huge_valf.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub inline fn __builtin_huge_valf() f32 {
return @import("std").math.inf(f32);
}
3 changes: 3 additions & 0 deletions src/builtins/inff.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub inline fn __builtin_inff() f32 {
return @import("std").math.inf(f32);
}
3 changes: 3 additions & 0 deletions src/builtins/isinf.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub inline fn __builtin_isinf(x: anytype) c_int {
return @intFromBool(@import("std").math.isInf(x));
}
5 changes: 5 additions & 0 deletions src/builtins/isinf_sign.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/// Similar to isinf, except the return value is -1 for an argument of -Inf and 1 for an argument of +Inf.
pub inline fn __builtin_isinf_sign(x: anytype) c_int {
if (!@import("std").math.isInf(x)) return 0;
return if (@import("std").math.isPositiveInf(x)) 1 else -1;
}
3 changes: 3 additions & 0 deletions src/builtins/isnan.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub inline fn __builtin_isnan(x: anytype) c_int {
return @intFromBool(@import("std").math.isNan(x));
}
4 changes: 4 additions & 0 deletions src/builtins/labs.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/// Standard C Library bug: The absolute value of the most negative integer remains negative.
pub inline fn __builtin_labs(val: c_long) c_long {
return if (val == @import("std").math.minInt(c_long)) val else @intCast(@abs(val));
}
4 changes: 4 additions & 0 deletions src/builtins/llabs.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/// Standard C Library bug: The absolute value of the most negative integer remains negative.
pub inline fn __builtin_llabs(val: c_longlong) c_longlong {
return if (val == @import("std").math.minInt(c_longlong)) val else @intCast(@abs(val));
}
11 changes: 11 additions & 0 deletions src/builtins/memcpy.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
pub inline fn __builtin_memcpy(
noalias dst: ?*anyopaque,
noalias src: ?*const anyopaque,
len: usize,
) ?*anyopaque {
if (len > 0) @memcpy(
@as([*]u8, @ptrCast(dst.?))[0..len],
@as([*]const u8, @ptrCast(src.?)),
);
return dst;
}
13 changes: 13 additions & 0 deletions src/builtins/memcpy_chk.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
pub inline fn __builtin___memcpy_chk(
noalias dst: ?*anyopaque,
noalias src: ?*const anyopaque,
len: usize,
remaining: usize,
) ?*anyopaque {
if (len > remaining) @panic("__builtin___memcpy_chk called with len > remaining");
if (len > 0) @memcpy(
@as([*]u8, @ptrCast(dst.?))[0..len],
@as([*]const u8, @ptrCast(src.?)),
);
return dst;
}
5 changes: 5 additions & 0 deletions src/builtins/memset.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pub inline fn __builtin_memset(dst: ?*anyopaque, val: c_int, len: usize) ?*anyopaque {
const dst_cast = @as([*c]u8, @ptrCast(dst));
@memset(dst_cast[0..len], @as(u8, @bitCast(@as(i8, @truncate(val)))));
return dst;
}
11 changes: 11 additions & 0 deletions src/builtins/memset_chk.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
pub inline fn __builtin___memset_chk(
dst: ?*anyopaque,
val: c_int,
len: usize,
remaining: usize,
) ?*anyopaque {
if (len > remaining) @panic("__builtin___memset_chk called with len > remaining");
const dst_cast = @as([*c]u8, @ptrCast(dst));
@memset(dst_cast[0..len], @as(u8, @bitCast(@as(i8, @truncate(val)))));
return dst;
}
5 changes: 5 additions & 0 deletions src/builtins/mul_overflow.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pub fn __builtin_mul_overflow(a: anytype, b: anytype, result: *@TypeOf(a, b)) c_int {
const res = @mulWithOverflow(a, b);
result.* = res[0];
return res[1];
}
Loading

0 comments on commit 7971b5e

Please sign in to comment.