Skip to content

Commit 7971b5e

Browse files
committed
avoid using Zig std for builtin translation
1 parent afdf9da commit 7971b5e

30 files changed

+345
-37
lines changed

src/Translator.zig

Lines changed: 85 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ const Type = aro.Type;
1313
const ast = @import("ast.zig");
1414
const ZigNode = ast.Node;
1515
const ZigTag = ZigNode.Tag;
16+
const builtins = @import("builtins.zig");
1617
const Scope = @import("Scope.zig");
1718

1819
const Translator = @This();
@@ -55,6 +56,9 @@ tree: Tree,
5556
comp: *aro.Compilation,
5657
mapper: aro.TypeMapper,
5758

59+
rendered_builtins: std.EnumSet(builtins.Builtin) = .{},
60+
render_buf: std.ArrayList(u8),
61+
5862
fn getMangle(t: *Translator) u32 {
5963
t.mangle_count += 1;
6064
return t.mangle_count;
@@ -137,15 +141,15 @@ pub fn translate(
137141
gpa: mem.Allocator,
138142
comp: *aro.Compilation,
139143
tree: aro.Tree,
140-
) !std.zig.Ast {
144+
) ![]u8 {
141145
const mapper = tree.comp.string_interner.getFastTypeMapper(tree.comp.gpa) catch tree.comp.string_interner.getSlowTypeMapper();
142146
defer mapper.deinit(tree.comp.gpa);
143147

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

148-
var context: Translator = .{
152+
var translator: Translator = .{
149153
.gpa = gpa,
150154
.arena = arena,
151155
.alias_list = .empty,
@@ -154,39 +158,39 @@ pub fn translate(
154158
.comp = comp,
155159
.mapper = mapper,
156160
.tree = tree,
161+
.render_buf = .init(gpa),
157162
};
158-
context.global_scope.* = Scope.Root.init(&context);
163+
translator.global_scope.* = Scope.Root.init(&translator);
159164
defer {
160-
context.decl_table.deinit(gpa);
161-
context.alias_list.deinit(gpa);
162-
context.global_names.deinit(gpa);
163-
context.weak_global_names.deinit(gpa);
164-
context.opaque_demotes.deinit(gpa);
165-
context.unnamed_typedefs.deinit(gpa);
166-
context.typedefs.deinit(gpa);
167-
context.global_scope.deinit();
168-
context.pattern_list.deinit(gpa);
169-
}
170-
171-
inline for (@typeInfo(std.zig.c_builtins).@"struct".decls) |decl| {
172-
const builtin_fn = try ZigTag.pub_var_simple.create(arena, .{
173-
.name = decl.name,
174-
.init = try ZigTag.import_c_builtin.create(arena, decl.name),
175-
});
176-
try addTopLevelDecl(&context, decl.name, builtin_fn);
165+
translator.decl_table.deinit(gpa);
166+
translator.alias_list.deinit(gpa);
167+
translator.global_names.deinit(gpa);
168+
translator.weak_global_names.deinit(gpa);
169+
translator.opaque_demotes.deinit(gpa);
170+
translator.unnamed_typedefs.deinit(gpa);
171+
translator.typedefs.deinit(gpa);
172+
translator.global_scope.deinit();
173+
translator.pattern_list.deinit(gpa);
174+
translator.render_buf.deinit();
177175
}
178176

179-
try prepopulateGlobalNameTable(&context);
180-
try transTopLevelDecls(&context);
177+
try prepopulateGlobalNameTable(&translator);
178+
try transTopLevelDecls(&translator);
181179

182-
for (context.alias_list.items) |alias| {
183-
if (!context.global_scope.sym_table.contains(alias.alias)) {
180+
for (translator.alias_list.items) |alias| {
181+
if (!translator.global_scope.sym_table.contains(alias.alias)) {
184182
const node = try ZigTag.alias.create(arena, .{ .actual = alias.alias, .mangled = alias.name });
185-
try addTopLevelDecl(&context, alias.alias, node);
183+
try addTopLevelDecl(&translator, alias.alias, node);
186184
}
187185
}
188186

189-
return ast.render(gpa, context.global_scope.nodes.items);
187+
var zig_ast = try ast.render(gpa, translator.global_scope.nodes.items);
188+
defer {
189+
gpa.free(zig_ast.source);
190+
zig_ast.deinit(gpa);
191+
}
192+
try zig_ast.renderToArrayList(&translator.render_buf, .{});
193+
return translator.render_buf.toOwnedSlice();
190194
}
191195

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

13531357
.shl_expr => return t.transShiftExpr(scope, expr, .shl, used),
13541358
.shr_expr => return t.transShiftExpr(scope, expr, .shr, used),
1359+
1360+
.builtin_call_expr => return t.transBuiltinCall(scope, expr, used),
1361+
.builtin_call_expr_one => return t.transBuiltinCall(scope, expr, used),
13551362
else => unreachable, // Not an expression.
13561363
}
13571364
}
@@ -1582,6 +1589,58 @@ fn transPointerArithmeticSignedOp(
15821589
return t.transCreateNodeInfixOp(if (is_add) .add else .sub, lhs_node, bitcast_node, used);
15831590
}
15841591

1592+
fn transBuiltinCall(
1593+
t: *Translator,
1594+
scope: *Scope,
1595+
call_node: NodeIndex,
1596+
used: ResultUsed,
1597+
) TransError!ZigNode {
1598+
// TODO would be nice to have a helper to extract the builtin name
1599+
const builtin_name, const arg_nodes = switch (t.nodeTag(call_node)) {
1600+
.builtin_call_expr => blk: {
1601+
const range = t.nodeData(call_node).range;
1602+
const name = t.tree.tokSlice(@intFromEnum(t.tree.data[range.start]));
1603+
const arg_nodes = t.tree.data[range.start + 1 .. range.end];
1604+
break :blk .{ name, arg_nodes };
1605+
},
1606+
.builtin_call_expr_one => blk: {
1607+
const decl = t.nodeData(call_node).decl;
1608+
const name = t.tree.tokSlice(decl.name);
1609+
const ptr: [*]const NodeIndex = @ptrCast(&decl.node);
1610+
const slice = ptr[0..1];
1611+
const end = std.mem.indexOfScalar(NodeIndex, slice, .none) orelse 1;
1612+
const arg_nodes = slice[0..end];
1613+
break :blk .{ name, arg_nodes };
1614+
},
1615+
else => unreachable,
1616+
};
1617+
const builtin = std.meta.stringToEnum(builtins.Builtin, builtin_name) orelse {
1618+
const call_loc = 0; // TODO builtin call source location
1619+
return t.fail(error.UnsupportedTranslation, call_loc, "TODO implement function '{s}' in std.zig.c_builtins", .{builtin_name});
1620+
};
1621+
1622+
if (builtin.source()) |source| {
1623+
if (!t.rendered_builtins.contains(builtin)) {
1624+
t.rendered_builtins.insert(builtin);
1625+
try t.render_buf.appendSlice(source);
1626+
}
1627+
1628+
const args = try t.arena.alloc(ZigNode, arg_nodes.len);
1629+
for (arg_nodes, args) |arg_node, *arg| {
1630+
arg.* = try t.transExpr(scope, arg_node, .used);
1631+
}
1632+
1633+
const res = try ZigTag.call.create(t.arena, .{
1634+
.lhs = try ZigTag.fn_identifier.create(t.arena, builtin_name),
1635+
.args = args,
1636+
});
1637+
if (t.nodeType(call_node).is(.void)) return res;
1638+
return t.maybeSuppressResult(used, res);
1639+
}
1640+
1641+
@panic("TODO transBulitinCall others");
1642+
}
1643+
15851644
// =====================
15861645
// Node creation helpers
15871646
// =====================

src/ast.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -785,7 +785,7 @@ pub fn render(gpa: Allocator, nodes: []const Node) !std.zig.Ast {
785785
defer ctx.tokens.deinit(gpa);
786786

787787
// Estimate that each top level node has 10 child nodes.
788-
const estimated_node_count = nodes.len * 10;
788+
const estimated_node_count = nodes.len * 10 + 1; // +1 for the .root node
789789
try ctx.nodes.ensureTotalCapacity(gpa, estimated_node_count);
790790
// Estimate that each each node has 2 tokens.
791791
const estimated_tokens_count = estimated_node_count * 2;

src/builtins.zig

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
pub const Builtin = enum {
2+
__builtin_bswap16,
3+
__builtin_bswap32,
4+
__builtin_bswap64,
5+
__builtin_signbit,
6+
__builtin_signbitf,
7+
__builtin_popcount,
8+
__builtin_ctz,
9+
__builtin_clz,
10+
__builtin_sqrt,
11+
__builtin_sqrtf,
12+
__builtin_sin,
13+
__builtin_sinf,
14+
__builtin_cos,
15+
__builtin_cosf,
16+
__builtin_exp,
17+
__builtin_expf,
18+
__builtin_exp2,
19+
__builtin_exp2f,
20+
__builtin_log,
21+
__builtin_logf,
22+
__builtin_log2,
23+
__builtin_log2f,
24+
__builtin_log10,
25+
__builtin_log10f,
26+
__builtin_abs,
27+
__builtin_labs,
28+
__builtin_llabs,
29+
__builtin_fabs,
30+
__builtin_fabsf,
31+
__builtin_floor,
32+
__builtin_floorf,
33+
__builtin_ceil,
34+
__builtin_ceilf,
35+
__builtin_trunc,
36+
__builtin_truncf,
37+
__builtin_round,
38+
__builtin_roundf,
39+
__builtin_strlen,
40+
__builtin_strcmp,
41+
__builtin_object_size,
42+
__builtin___memset_chk,
43+
__builtin_memset,
44+
__builtin___memcpy_chk,
45+
__builtin_memcpy,
46+
__builtin_nanf,
47+
__builtin_huge_valf,
48+
__builtin_inff,
49+
__builtin_isnan,
50+
__builtin_isinf,
51+
__builtin_isinf_sign,
52+
__has_builtin,
53+
__builtin_assume,
54+
__builtin_unreachable,
55+
__builtin_constant_p,
56+
__builtin_mul_overflow,
57+
58+
// __builtin_alloca_with_align is not currently implemented.
59+
// It is used in a run and a translate test to ensure that non-implemented
60+
// builtins are correctly demoted. If you implement __builtin_alloca_with_align,
61+
// please update the tests to use a different non-implemented builtin.
62+
63+
pub fn source(b: Builtin) ?[]const u8 {
64+
return switch (b) {
65+
.__builtin_signbit => @embedFile("builtins/signbit.zig"),
66+
.__builtin_signbitf => @embedFile("builtins/signbitf.zig"),
67+
.__builtin_popcount => @embedFile("builtins/popcount.zig"),
68+
.__builtin_ctz => @embedFile("builtins/ctz.zig"),
69+
.__builtin_clz => @embedFile("builtins/clz.zig"),
70+
.__builtin_abs => @embedFile("builtins/abs.zig"),
71+
.__builtin_labs => @embedFile("builtins/labs.zig"),
72+
.__builtin_llabs => @embedFile("builtins/llabs.zig"),
73+
.__builtin_strlen => @embedFile("builtins/strlen.zig"),
74+
.__builtin_strcmp => @embedFile("builtins/strcmp.zig"),
75+
.__builtin_object_size => @embedFile("builtins/object_size.zig"),
76+
.__builtin___memset_chk => @embedFile("builtins/memset_chk.zig"),
77+
.__builtin_memset => @embedFile("builtins/memset.zig"),
78+
.__builtin___memcpy_chk => @embedFile("builtins/memcpy_chk.zig"),
79+
.__builtin_memcpy => @embedFile("builtins/memcpy.zig"),
80+
.__builtin_nanf => @embedFile("builtins/nanf.zig"),
81+
.__builtin_huge_valf => @embedFile("builtins/huge_valf.zig"),
82+
.__builtin_inff => @embedFile("builtins/inff.zig"),
83+
.__builtin_isnan => @embedFile("builtins/isnan.zig"),
84+
.__builtin_isinf => @embedFile("builtins/isinf.zig"),
85+
.__builtin_isinf_sign => @embedFile("builtins/isinf_sign.zig"),
86+
.__has_builtin => @embedFile("builtins/has_builtin.zig"),
87+
.__builtin_assume => @embedFile("builtins/assume.zig"),
88+
.__builtin_constant_p => @embedFile("builtins/constant_p.zig"),
89+
.__builtin_mul_overflow => @embedFile("builtins/mul_overflow.zig"),
90+
else => return null,
91+
};
92+
}
93+
};

src/builtins/abs.zig

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/// Standard C Library bug: The absolute value of the most negative integer remains negative.
2+
pub inline fn __builtin_abs(val: c_int) c_int {
3+
return if (val == @import("std").math.minInt(c_int)) val else @intCast(@abs(val));
4+
}

src/builtins/assume.zig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
pub inline fn __builtin_assume(cond: bool) void {
2+
if (!cond) unreachable;
3+
}

src/builtins/clz.zig

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/// Returns the number of leading 0-bits in x, starting at the most significant bit position.
2+
/// In C if `val` is 0, the result is undefined; in zig it's the number of bits in a c_uint
3+
pub inline fn __builtin_clz(val: c_uint) c_int {
4+
@setRuntimeSafety(false);
5+
return @as(c_int, @bitCast(@as(c_uint, @clz(val))));
6+
}

src/builtins/constant_p.zig

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
pub inline fn __builtin_constant_p(expr: anytype) c_int {
2+
_ = expr;
3+
return @intFromBool(false);
4+
}

src/builtins/ctz.zig

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/// Returns the number of trailing 0-bits in val, starting at the least significant bit position.
2+
/// In C if `val` is 0, the result is undefined; in zig it's the number of bits in a c_uint
3+
pub inline fn __builtin_ctz(val: c_uint) c_int {
4+
@setRuntimeSafety(false);
5+
return @as(c_int, @bitCast(@as(c_uint, @ctz(val))));
6+
}

src/builtins/has_builtin.zig

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
pub inline fn __has_builtin(func: anytype) c_int {
2+
_ = func;
3+
return @intFromBool(true);
4+
}

src/builtins/huge_valf.zig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
pub inline fn __builtin_huge_valf() f32 {
2+
return @import("std").math.inf(f32);
3+
}

src/builtins/inff.zig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
pub inline fn __builtin_inff() f32 {
2+
return @import("std").math.inf(f32);
3+
}

src/builtins/isinf.zig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
pub inline fn __builtin_isinf(x: anytype) c_int {
2+
return @intFromBool(@import("std").math.isInf(x));
3+
}

src/builtins/isinf_sign.zig

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/// Similar to isinf, except the return value is -1 for an argument of -Inf and 1 for an argument of +Inf.
2+
pub inline fn __builtin_isinf_sign(x: anytype) c_int {
3+
if (!@import("std").math.isInf(x)) return 0;
4+
return if (@import("std").math.isPositiveInf(x)) 1 else -1;
5+
}

src/builtins/isnan.zig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
pub inline fn __builtin_isnan(x: anytype) c_int {
2+
return @intFromBool(@import("std").math.isNan(x));
3+
}

src/builtins/labs.zig

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/// Standard C Library bug: The absolute value of the most negative integer remains negative.
2+
pub inline fn __builtin_labs(val: c_long) c_long {
3+
return if (val == @import("std").math.minInt(c_long)) val else @intCast(@abs(val));
4+
}

src/builtins/llabs.zig

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/// Standard C Library bug: The absolute value of the most negative integer remains negative.
2+
pub inline fn __builtin_llabs(val: c_longlong) c_longlong {
3+
return if (val == @import("std").math.minInt(c_longlong)) val else @intCast(@abs(val));
4+
}

src/builtins/memcpy.zig

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
pub inline fn __builtin_memcpy(
2+
noalias dst: ?*anyopaque,
3+
noalias src: ?*const anyopaque,
4+
len: usize,
5+
) ?*anyopaque {
6+
if (len > 0) @memcpy(
7+
@as([*]u8, @ptrCast(dst.?))[0..len],
8+
@as([*]const u8, @ptrCast(src.?)),
9+
);
10+
return dst;
11+
}

src/builtins/memcpy_chk.zig

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
pub inline fn __builtin___memcpy_chk(
2+
noalias dst: ?*anyopaque,
3+
noalias src: ?*const anyopaque,
4+
len: usize,
5+
remaining: usize,
6+
) ?*anyopaque {
7+
if (len > remaining) @panic("__builtin___memcpy_chk called with len > remaining");
8+
if (len > 0) @memcpy(
9+
@as([*]u8, @ptrCast(dst.?))[0..len],
10+
@as([*]const u8, @ptrCast(src.?)),
11+
);
12+
return dst;
13+
}

src/builtins/memset.zig

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pub inline fn __builtin_memset(dst: ?*anyopaque, val: c_int, len: usize) ?*anyopaque {
2+
const dst_cast = @as([*c]u8, @ptrCast(dst));
3+
@memset(dst_cast[0..len], @as(u8, @bitCast(@as(i8, @truncate(val)))));
4+
return dst;
5+
}

src/builtins/memset_chk.zig

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
pub inline fn __builtin___memset_chk(
2+
dst: ?*anyopaque,
3+
val: c_int,
4+
len: usize,
5+
remaining: usize,
6+
) ?*anyopaque {
7+
if (len > remaining) @panic("__builtin___memset_chk called with len > remaining");
8+
const dst_cast = @as([*c]u8, @ptrCast(dst));
9+
@memset(dst_cast[0..len], @as(u8, @bitCast(@as(i8, @truncate(val)))));
10+
return dst;
11+
}

src/builtins/mul_overflow.zig

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pub fn __builtin_mul_overflow(a: anytype, b: anytype, result: *@TypeOf(a, b)) c_int {
2+
const res = @mulWithOverflow(a, b);
3+
result.* = res[0];
4+
return res[1];
5+
}

0 commit comments

Comments
 (0)