Skip to content

Commit

Permalink
use equivalent Zig builtin for C builtins when possible
Browse files Browse the repository at this point in the history
  • Loading branch information
Vexu committed Dec 27, 2024
1 parent 7971b5e commit 2bbe992
Show file tree
Hide file tree
Showing 33 changed files with 322 additions and 119 deletions.
49 changes: 31 additions & 18 deletions src/Translator.zig
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ tree: Tree,
comp: *aro.Compilation,
mapper: aro.TypeMapper,

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

fn getMangle(t: *Translator) u32 {
Expand Down Expand Up @@ -172,6 +172,7 @@ pub fn translate(
translator.global_scope.deinit();
translator.pattern_list.deinit(gpa);
translator.render_buf.deinit();
translator.rendered_builtins.deinit(gpa);
}

try prepopulateGlobalNameTable(&translator);
Expand Down Expand Up @@ -1614,31 +1615,43 @@ fn transBuiltinCall(
},
else => unreachable,
};
const builtin = std.meta.stringToEnum(builtins.Builtin, builtin_name) orelse {
const builtin = builtins.map.get(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);
}
if (builtin.tag) |tag| switch (tag) {
.byte_swap, .ceil, .cos, .sin, .exp, .exp2, .exp10, .abs, .log, .log2, .log10, .round, .sqrt, .trunc, .floor => {
assert(arg_nodes.len == 1);
const ptr = try t.arena.create(ast.Payload.UnOp);
ptr.* = .{
.base = .{ .tag = tag },
.data = try t.transExpr(scope, arg_nodes[0], .used),
};
return ZigNode.initPayload(&ptr.base);
},
.@"unreachable" => return ZigTag.@"unreachable".init(),
else => unreachable,
};

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);
}
// Overriding a builtin function is a hard error in C
// so we do not need to worry about aliasing.
const gop = try t.rendered_builtins.getOrPut(t.gpa, builtin_name);
if (!gop.found_existing) {
try t.render_buf.appendSlice(builtin.source);
}

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);
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);
}

@panic("TODO transBulitinCall others");
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);
}

// =====================
Expand Down
145 changes: 132 additions & 13 deletions src/ast.zig
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ pub const Node = extern union {
return_void,
zero_literal,
one_literal,
@"unreachable",
void_type,
noreturn_type,
@"anytype",
Expand Down Expand Up @@ -114,8 +115,6 @@ pub const Node = extern union {
ellipsis3,
assign,

/// @import("std").zig.c_builtins.<name>
import_c_builtin,
/// @intCast(operand)
int_cast,
/// @constCast(operand)
Expand Down Expand Up @@ -161,6 +160,37 @@ pub const Node = extern union {
/// @extern(ty, .{ .name = n })
builtin_extern,

/// @byteSwap(operand)
byte_swap,
/// @ceil(operand)
ceil,
/// @cos(operand)
cos,
/// @sin(operand)
sin,
/// @exp(operand)
exp,
/// @exp2(operand)
exp2,
/// @exp10(operand)
exp10,
/// @abs(operand)
abs,
/// @log(operand)
log,
/// @log2(operand)
log2,
/// @log10(operand)
log10,
/// @round(operand)
round,
/// @sqrt(operand)
sqrt,
/// @trunc(operand)
trunc,
/// @floor(operand)
floor,

/// @import("std").zig.c_translation.MacroArithmetic.<op>(lhs, rhs)
macro_arithmetic,

Expand Down Expand Up @@ -250,6 +280,7 @@ pub const Node = extern union {
.@"anytype",
.@"continue",
.@"break",
.@"unreachable",
=> @compileError("Type Tag " ++ @tagName(t) ++ " has no payload"),

.std_mem_zeroes,
Expand Down Expand Up @@ -289,6 +320,21 @@ pub const Node = extern union {
.const_cast,
.volatile_cast,
.vector_zero_init,
.byte_swap,
.ceil,
.cos,
.sin,
.exp,
.exp2,
.exp10,
.abs,
.log,
.log2,
.log10,
.round,
.sqrt,
.trunc,
.floor,
=> Payload.UnOp,

.add,
Expand Down Expand Up @@ -352,7 +398,6 @@ pub const Node = extern union {
.warning,
.type,
.helpers_macro,
.import_c_builtin,
=> Payload.Value,
.discard => Payload.Discard,
.@"if" => Payload.If,
Expand Down Expand Up @@ -1000,6 +1045,14 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
.main_token = try c.addToken(.number_literal, "1"),
.data = undefined,
}),
.@"unreachable" => return c.addNode(.{
.tag = .unreachable_literal,
.main_token = try c.addToken(.keyword_unreachable, "unreachable"),
.data = .{
.lhs = 0,
.rhs = 0,
},
}),
.void_type => return c.addNode(.{
.tag = .identifier,
.main_token = try c.addToken(.identifier, "void"),
Expand Down Expand Up @@ -1183,15 +1236,6 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
};
return renderStdImport(c, &chain);
},
.import_c_builtin => {
const payload = node.castTag(.import_c_builtin).?.data;
const chain = [_][]const u8{
"zig",
"c_builtins",
payload,
};
return renderStdImport(c, &chain);
},
.string_slice => {
const payload = node.castTag(.string_slice).?.data;

Expand Down Expand Up @@ -1507,6 +1551,66 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
const payload = node.castTag(.typeinfo).?.data;
return renderBuiltinCall(c, "@typeInfo", &.{payload});
},
.byte_swap => {
const payload = node.castTag(.byte_swap).?.data;
return renderBuiltinCall(c, "@byteSwap", &.{payload});
},
.ceil => {
const payload = node.castTag(.ceil).?.data;
return renderBuiltinCall(c, "@ceil", &.{payload});
},
.cos => {
const payload = node.castTag(.cos).?.data;
return renderBuiltinCall(c, "@cos", &.{payload});
},
.sin => {
const payload = node.castTag(.sin).?.data;
return renderBuiltinCall(c, "@sin", &.{payload});
},
.exp => {
const payload = node.castTag(.exp).?.data;
return renderBuiltinCall(c, "@exp", &.{payload});
},
.exp2 => {
const payload = node.castTag(.exp2).?.data;
return renderBuiltinCall(c, "@exp2", &.{payload});
},
.exp10 => {
const payload = node.castTag(.exp10).?.data;
return renderBuiltinCall(c, "@exp10", &.{payload});
},
.abs => {
const payload = node.castTag(.abs).?.data;
return renderBuiltinCall(c, "@abs", &.{payload});
},
.log => {
const payload = node.castTag(.log).?.data;
return renderBuiltinCall(c, "@log", &.{payload});
},
.log2 => {
const payload = node.castTag(.log2).?.data;
return renderBuiltinCall(c, "@log2", &.{payload});
},
.log10 => {
const payload = node.castTag(.log10).?.data;
return renderBuiltinCall(c, "@log10", &.{payload});
},
.round => {
const payload = node.castTag(.round).?.data;
return renderBuiltinCall(c, "@round", &.{payload});
},
.sqrt => {
const payload = node.castTag(.sqrt).?.data;
return renderBuiltinCall(c, "@sqrt", &.{payload});
},
.trunc => {
const payload = node.castTag(.trunc).?.data;
return renderBuiltinCall(c, "@trunc", &.{payload});
},
.floor => {
const payload = node.castTag(.floor).?.data;
return renderBuiltinCall(c, "@floor", &.{payload});
},
.negate => return renderPrefixOp(c, node, .negation, .minus, "-"),
.negate_wrap => return renderPrefixOp(c, node, .negation_wrap, .minus_percent, "-%"),
.bit_not => return renderPrefixOp(c, node, .bit_not, .tilde, "~"),
Expand Down Expand Up @@ -2514,6 +2618,21 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {
.extern_local_var,
.mut_str,
.macro_arithmetic,
.byte_swap,
.ceil,
.cos,
.sin,
.exp,
.exp2,
.exp10,
.abs,
.log,
.log2,
.log10,
.round,
.sqrt,
.trunc,
.floor,
=> {
// no grouping needed
return renderNode(c, node);
Expand Down Expand Up @@ -2603,8 +2722,8 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {
.bit_xor_assign,
.assign,
.helpers_macro,
.import_c_builtin,
.static_assert,
.@"unreachable",
=> {
// these should never appear in places where grouping might be needed.
unreachable;
Expand Down
Loading

0 comments on commit 2bbe992

Please sign in to comment.