authorgravatar for 53349189+freakmangd@users.noreply.github.comfreakmangd <53349189+freakmangd@users.noreply.github.com> 2024-06-05 16:06:51-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-06-05 23:06:51+03:00
log9bbfb09fc33366bff0a53c02cd78bdd14bed9f9b
tree4808fb1d3e1392b6f1c910b8d83a6d7b84c5193d
parent8f27fdb84e3788bf6ea9ae7c992f3cf667a4f9ed
signaturebadge-check Signed by PGP key B5690EEEBB952194

translate-c: promote macros that reference var decls to inline functions


5 files changed, 80 insertions(+), 32 deletions(-)

lib/compiler/aro_translate_c.zig+1-4
...@@ -1381,7 +1381,6 @@ pub fn ScopeExtra(comptime ScopeExtraContext: type, comptime ScopeExtraType: typ...@@ -1381,7 +1381,6 @@ pub fn ScopeExtra(comptime ScopeExtraContext: type, comptime ScopeExtraType: typ
1381 pub const Root = struct {1381 pub const Root = struct {
1382 base: ScopeExtraScope,1382 base: ScopeExtraScope,
1383 sym_table: SymbolTable,1383 sym_table: SymbolTable,
1384 macro_table: SymbolTable,
1385 blank_macros: std.StringArrayHashMap(void),1384 blank_macros: std.StringArrayHashMap(void),
1386 context: *ScopeExtraContext,1385 context: *ScopeExtraContext,
1387 nodes: std.ArrayList(ast.Node),1386 nodes: std.ArrayList(ast.Node),
...@@ -1393,7 +1392,6 @@ pub fn ScopeExtra(comptime ScopeExtraContext: type, comptime ScopeExtraType: typ...@@ -1393,7 +1392,6 @@ pub fn ScopeExtra(comptime ScopeExtraContext: type, comptime ScopeExtraType: typ
1393 .parent = null,1392 .parent = null,
1394 },1393 },
1395 .sym_table = SymbolTable.init(c.gpa),1394 .sym_table = SymbolTable.init(c.gpa),
1396 .macro_table = SymbolTable.init(c.gpa),
1397 .blank_macros = std.StringArrayHashMap(void).init(c.gpa),1395 .blank_macros = std.StringArrayHashMap(void).init(c.gpa),
1398 .context = c,1396 .context = c,
1399 .nodes = std.ArrayList(ast.Node).init(c.gpa),1397 .nodes = std.ArrayList(ast.Node).init(c.gpa),
...@@ -1402,7 +1400,6 @@ pub fn ScopeExtra(comptime ScopeExtraContext: type, comptime ScopeExtraType: typ...@@ -1402,7 +1400,6 @@ pub fn ScopeExtra(comptime ScopeExtraContext: type, comptime ScopeExtraType: typ
14021400
1403 pub fn deinit(scope: *Root) void {1401 pub fn deinit(scope: *Root) void {
1404 scope.sym_table.deinit();1402 scope.sym_table.deinit();
1405 scope.macro_table.deinit();
1406 scope.blank_macros.deinit();1403 scope.blank_macros.deinit();
1407 scope.nodes.deinit();1404 scope.nodes.deinit();
1408 }1405 }
...@@ -1410,7 +1407,7 @@ pub fn ScopeExtra(comptime ScopeExtraContext: type, comptime ScopeExtraType: typ...@@ -1410,7 +1407,7 @@ pub fn ScopeExtra(comptime ScopeExtraContext: type, comptime ScopeExtraType: typ
1410 /// Check if the global scope contains this name, without looking into the "future", e.g.1407 /// Check if the global scope contains this name, without looking into the "future", e.g.
1411 /// ignore the preprocessed decl and macro names.1408 /// ignore the preprocessed decl and macro names.
1412 pub fn containsNow(scope: *Root, name: []const u8) bool {1409 pub fn containsNow(scope: *Root, name: []const u8) bool {
1413 return scope.sym_table.contains(name) or scope.macro_table.contains(name);1410 return scope.sym_table.contains(name);
1414 }1411 }
14151412
1416 /// Check if the global scope contains the name, includes all decls that haven't been translated yet.1413 /// Check if the global scope contains the name, includes all decls that haven't been translated yet.
lib/compiler/aro_translate_c/ast.zig+1
...@@ -875,6 +875,7 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {...@@ -875,6 +875,7 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
875 .declaration => unreachable,875 .declaration => unreachable,
876 .warning => {876 .warning => {
877 const payload = node.castTag(.warning).?.data;877 const payload = node.castTag(.warning).?.data;
878 try c.buf.append('\n');
878 try c.buf.appendSlice(payload);879 try c.buf.appendSlice(payload);
879 try c.buf.append('\n');880 try c.buf.append('\n');
880 return @as(NodeIndex, 0); // error: integer value 0 cannot be coerced to type 'std.mem.Allocator.Error!u32'881 return @as(NodeIndex, 0); // error: integer value 0 cannot be coerced to type 'std.mem.Allocator.Error!u32'
src/translate_c.zig+36-21
...@@ -177,7 +177,6 @@ pub fn translate(...@@ -177,7 +177,6 @@ pub fn translate(
177177
178 try transPreprocessorEntities(&context, ast_unit);178 try transPreprocessorEntities(&context, ast_unit);
179179
180 try addMacros(&context);
181 for (context.alias_list.items) |alias| {180 for (context.alias_list.items) |alias| {
182 const node = try Tag.alias.create(arena, .{ .actual = alias.alias, .mangled = alias.name });181 const node = try Tag.alias.create(arena, .{ .actual = alias.alias, .mangled = alias.name });
183 try addTopLevelDecl(&context, alias.alias, node);182 try addTopLevelDecl(&context, alias.alias, node);
...@@ -5105,6 +5104,7 @@ const MacroCtx = struct {...@@ -5105,6 +5104,7 @@ const MacroCtx = struct {
5105 i: usize = 0,5104 i: usize = 0,
5106 loc: clang.SourceLocation,5105 loc: clang.SourceLocation,
5107 name: []const u8,5106 name: []const u8,
5107 refs_var_decl: bool = false,
51085108
5109 fn peek(self: *MacroCtx) ?CToken.Id {5109 fn peek(self: *MacroCtx) ?CToken.Id {
5110 if (self.i >= self.list.len) return null;5110 if (self.i >= self.list.len) return null;
...@@ -5244,7 +5244,7 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {...@@ -5244,7 +5244,7 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {
5244 // We define it as an empty string so that it can still be used with ++5244 // We define it as an empty string so that it can still be used with ++
5245 const str_node = try Tag.string_literal.create(c.arena, "\"\"");5245 const str_node = try Tag.string_literal.create(c.arena, "\"\"");
5246 const var_decl = try Tag.pub_var_simple.create(c.arena, .{ .name = name, .init = str_node });5246 const var_decl = try Tag.pub_var_simple.create(c.arena, .{ .name = name, .init = str_node });
5247 try c.global_scope.macro_table.put(name, var_decl);5247 try addTopLevelDecl(c, name, var_decl);
5248 try c.global_scope.blank_macros.put(name, {});5248 try c.global_scope.blank_macros.put(name, {});
5249 continue;5249 continue;
5250 },5250 },
...@@ -5291,7 +5291,7 @@ fn transMacroDefine(c: *Context, m: *MacroCtx) ParseError!void {...@@ -5291,7 +5291,7 @@ fn transMacroDefine(c: *Context, m: *MacroCtx) ParseError!void {
5291 try c.global_scope.blank_macros.put(m.name, {});5291 try c.global_scope.blank_macros.put(m.name, {});
5292 const init_node = try Tag.string_literal.create(c.arena, "\"\"");5292 const init_node = try Tag.string_literal.create(c.arena, "\"\"");
5293 const var_decl = try Tag.pub_var_simple.create(c.arena, .{ .name = m.name, .init = init_node });5293 const var_decl = try Tag.pub_var_simple.create(c.arena, .{ .name = m.name, .init = init_node });
5294 try c.global_scope.macro_table.put(m.name, var_decl);5294 try addTopLevelDecl(c, m.name, var_decl);
5295 return;5295 return;
5296 },5296 },
5297 else => {},5297 else => {},
...@@ -5304,8 +5304,32 @@ fn transMacroDefine(c: *Context, m: *MacroCtx) ParseError!void {...@@ -5304,8 +5304,32 @@ fn transMacroDefine(c: *Context, m: *MacroCtx) ParseError!void {
5304 if (last != .eof and last != .nl)5304 if (last != .eof and last != .nl)
5305 return m.fail(c, "unable to translate C expr: unexpected token '{s}'", .{last.symbol()});5305 return m.fail(c, "unable to translate C expr: unexpected token '{s}'", .{last.symbol()});
53065306
5307 const var_decl = try Tag.pub_var_simple.create(c.arena, .{ .name = m.name, .init = init_node });5307 const node = node: {
5308 try c.global_scope.macro_table.put(m.name, var_decl);5308 const var_decl = try Tag.pub_var_simple.create(c.arena, .{ .name = m.name, .init = init_node });
5309
5310 if (getFnProto(c, var_decl)) |proto_node| {
5311 // If a macro aliases a global variable which is a function pointer, we conclude that
5312 // the macro is intended to represent a function that assumes the function pointer
5313 // variable is non-null and calls it.
5314 break :node try transCreateNodeMacroFn(c, m.name, var_decl, proto_node);
5315 } else if (m.refs_var_decl) {
5316 const return_type = try Tag.typeof.create(c.arena, init_node);
5317 const return_expr = try Tag.@"return".create(c.arena, init_node);
5318 const block = try Tag.block_single.create(c.arena, return_expr);
5319 try warn(c, scope, m.loc, "macro '{s}' contains a runtime value, translated to function", .{m.name});
5320
5321 break :node try Tag.pub_inline_fn.create(c.arena, .{
5322 .name = m.name,
5323 .params = &.{},
5324 .return_type = return_type,
5325 .body = block,
5326 });
5327 }
5328
5329 break :node var_decl;
5330 };
5331
5332 try addTopLevelDecl(c, m.name, node);
5309}5333}
53105334
5311fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void {5335fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void {
...@@ -5315,7 +5339,7 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void {...@@ -5315,7 +5339,7 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void {
5315 .name = m.name,5339 .name = m.name,
5316 .init = try Tag.helpers_macro.create(c.arena, pattern.impl),5340 .init = try Tag.helpers_macro.create(c.arena, pattern.impl),
5317 });5341 });
5318 try c.global_scope.macro_table.put(m.name, decl);5342 try addTopLevelDecl(c, m.name, decl);
5319 return;5343 return;
5320 }5344 }
53215345
...@@ -5380,7 +5404,7 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void {...@@ -5380,7 +5404,7 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void {
5380 .return_type = return_type,5404 .return_type = return_type,
5381 .body = try block_scope.complete(c),5405 .body = try block_scope.complete(c),
5382 });5406 });
5383 try c.global_scope.macro_table.put(m.name, fn_decl);5407 try addTopLevelDecl(c, m.name, fn_decl);
5384}5408}
53855409
5386const ParseError = Error || error{ParseError};5410const ParseError = Error || error{ParseError};
...@@ -5768,6 +5792,11 @@ fn parseCPrimaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {...@@ -5768,6 +5792,11 @@ fn parseCPrimaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
5768 if (builtin_typedef_map.get(mangled_name)) |ty| return Tag.type.create(c.arena, ty);5792 if (builtin_typedef_map.get(mangled_name)) |ty| return Tag.type.create(c.arena, ty);
5769 const identifier = try Tag.identifier.create(c.arena, mangled_name);5793 const identifier = try Tag.identifier.create(c.arena, mangled_name);
5770 scope.skipVariableDiscard(identifier.castTag(.identifier).?.data);5794 scope.skipVariableDiscard(identifier.castTag(.identifier).?.data);
5795 refs_var: {
5796 const ident_node = c.global_scope.sym_table.get(slice) orelse break :refs_var;
5797 const var_decl_node = ident_node.castTag(.var_decl) orelse break :refs_var;
5798 if (!var_decl_node.data.is_const) m.refs_var_decl = true;
5799 }
5771 return identifier;5800 return identifier;
5772 },5801 },
5773 .l_paren => {5802 .l_paren => {
...@@ -6496,17 +6525,3 @@ fn getFnProto(c: *Context, ref: Node) ?*ast.Payload.Func {...@@ -6496,17 +6525,3 @@ fn getFnProto(c: *Context, ref: Node) ?*ast.Payload.Func {
6496 }6525 }
6497 return null;6526 return null;
6498}6527}
6499
6500fn addMacros(c: *Context) !void {
6501 var it = c.global_scope.macro_table.iterator();
6502 while (it.next()) |entry| {
6503 if (getFnProto(c, entry.value_ptr.*)) |proto_node| {
6504 // If a macro aliases a global variable which is a function pointer, we conclude that
6505 // the macro is intended to represent a function that assumes the function pointer
6506 // variable is non-null and calls it.
6507 try addTopLevelDecl(c, entry.key_ptr.*, try transCreateNodeMacroFn(c, entry.key_ptr.*, entry.value_ptr.*, proto_node));
6508 } else {
6509 try addTopLevelDecl(c, entry.key_ptr.*, entry.value_ptr.*);
6510 }
6511 }
6512}
test/cases/translate_c/macro_referencing_var.c created+21
...@@ -0,0 +1,21 @@
1extern float foo;
2#define FOO_TWICE foo * 2.0f
3#define FOO_NEGATIVE -foo
4
5#define BAR 10.0f
6#define BAR_TWICE BAR * 2.0f
7
8// translate-c
9// c_frontend=clang
10//
11// pub extern var foo: f32;
12//
13// pub inline fn FOO_TWICE() @TypeOf(foo * @as(f32, 2.0)) {
14// return foo * @as(f32, 2.0);
15// }
16//
17// pub inline fn FOO_NEGATIVE() @TypeOf(-foo) {
18// return -foo;
19// }
20// pub const BAR = @as(f32, 10.0);
21// pub const BAR_TWICE = BAR * @as(f32, 2.0);
test/translate_c.zig+21-7
...@@ -223,7 +223,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -223,7 +223,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
223 \\ | (*((unsigned char *)(p) + 1) << 8) \223 \\ | (*((unsigned char *)(p) + 1) << 8) \
224 \\ | (*((unsigned char *)(p) + 2) << 16))224 \\ | (*((unsigned char *)(p) + 2) << 16))
225 , &[_][]const u8{225 , &[_][]const u8{
226 \\pub const FOO = (foo + @as(c_int, 2)).*;226 \\pub inline fn FOO() @TypeOf((foo + @as(c_int, 2)).*) {
227 \\ return (foo + @as(c_int, 2)).*;
228 \\}
227 ,229 ,
228 \\pub const VALUE = ((((@as(c_int, 1) + (@as(c_int, 2) * @as(c_int, 3))) + (@as(c_int, 4) * @as(c_int, 5))) + @as(c_int, 6)) << @as(c_int, 7)) | @intFromBool(@as(c_int, 8) == @as(c_int, 9));230 \\pub const VALUE = ((((@as(c_int, 1) + (@as(c_int, 2) * @as(c_int, 3))) + (@as(c_int, 4) * @as(c_int, 5))) + @as(c_int, 6)) << @as(c_int, 7)) | @intFromBool(@as(c_int, 8) == @as(c_int, 9));
229 ,231 ,
...@@ -452,7 +454,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -452,7 +454,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
452 \\#define FOO -\454 \\#define FOO -\
453 \\BAR455 \\BAR
454 , &[_][]const u8{456 , &[_][]const u8{
455 \\pub const FOO = -BAR;457 \\pub inline fn FOO() @TypeOf(-BAR) {
458 \\ return -BAR;
459 \\}
456 });460 });
457461
458 cases.add("struct with atomic field",462 cases.add("struct with atomic field",
...@@ -2453,9 +2457,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -2453,9 +2457,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
2453 \\ _ = c.*.b;2457 \\ _ = c.*.b;
2454 \\}2458 \\}
2455 ,2459 ,
2456 \\pub const DOT = a.b;2460 \\pub inline fn ARROW() @TypeOf(a.*.b) {
2461 \\ return a.*.b;
2462 \\}
2457 ,2463 ,
2458 \\pub const ARROW = a.*.b;2464 \\pub inline fn DOT() @TypeOf(a.b) {
2465 \\ return a.b;
2466 \\}
2459 });2467 });
24602468
2461 cases.add("array access",2469 cases.add("array access",
...@@ -2472,7 +2480,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -2472,7 +2480,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
2472 \\ return array[@as(c_uint, @intCast(index))];2480 \\ return array[@as(c_uint, @intCast(index))];
2473 \\}2481 \\}
2474 ,2482 ,
2475 \\pub const ACCESS = array[@as(usize, @intCast(@as(c_int, 2)))];2483 \\pub inline fn ACCESS() @TypeOf(array[@as(usize, @intCast(@as(c_int, 2)))]) {
2484 \\ return array[@as(usize, @intCast(@as(c_int, 2)))];
2485 \\}
2476 });2486 });
24772487
2478 cases.add("cast signed array index to unsigned",2488 cases.add("cast signed array index to unsigned",
...@@ -3130,7 +3140,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -3130,7 +3140,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
3130 \\ int a, b, c;3140 \\ int a, b, c;
3131 \\#define FOO a ? b : c3141 \\#define FOO a ? b : c
3132 , &[_][]const u8{3142 , &[_][]const u8{
3133 \\pub const FOO = if (a) b else c;3143 \\pub inline fn FOO() @TypeOf(if (a) b else c) {
3144 \\ return if (a) b else c;
3145 \\}
3134 });3146 });
31353147
3136 cases.add("do while as expr",3148 cases.add("do while as expr",
...@@ -3624,7 +3636,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -3624,7 +3636,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
3624 \\#define FOO _3636 \\#define FOO _
3625 \\int _ = 42;3637 \\int _ = 42;
3626 , &[_][]const u8{3638 , &[_][]const u8{
3627 \\pub const FOO = @"_";3639 \\pub inline fn FOO() @TypeOf(@"_") {
3640 \\ return @"_";
3641 \\}
3628 ,3642 ,
3629 \\pub export var @"_": c_int = 42;3643 \\pub export var @"_": c_int = 42;
3630 });3644 });