authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2023-11-01 20:48:15+02:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2023-11-15 10:50:45+02:00
loga15feeb694ed6dec5a2216c7a23df88d29ba8fe6
tree281d012e7e5e92329ec66289b8a87ecdd419b158
parent0c6cb8d8c80f0a316a77eddfebaa42cb77c8bf7d

aro-translate-c: translate function types


2 files changed, 212 insertions(+), 7 deletions(-)

src/aro_translate_c.zig+212-5
......@@ -1,6 +1,7 @@
11const std = @import("std");
22const mem = std.mem;
33const assert = std.debug.assert;
4const CallingConvention = std.builtin.CallingConvention;
45const translate_c = @import("translate_c.zig");
56const aro = @import("aro");
67const Tree = aro.Tree;
......@@ -99,6 +100,12 @@ fn failDecl(c: *Context, loc: TokenIndex, name: []const u8, comptime format: []c
99100 try c.global_scope.nodes.append(try ZigTag.warning.create(c.arena, location_comment));
100101}
101102
103fn warn(c: *Context, scope: *Scope, loc: TokenIndex, comptime format: []const u8, args: anytype) !void {
104 const str = try c.locStr(loc);
105 const value = try std.fmt.allocPrint(c.arena, "// {s}: warning: " ++ format, .{str} ++ args);
106 try scope.appendNode(try ZigTag.warning.create(c.arena, value));
107}
108
102109pub fn translate(
103110 gpa: mem.Allocator,
104111 comp: *Compilation,
......@@ -299,12 +306,112 @@ fn transTypeDef(_: *Context, _: *Scope, _: NodeIndex) Error!void {
299306fn transRecordDecl(_: *Context, _: *Scope, _: NodeIndex) Error!void {
300307 @panic("TODO");
301308}
302fn transFnDecl(_: *Context, _: NodeIndex) Error!void {
303 @panic("TODO");
309
310fn transFnDecl(c: *Context, fn_decl: NodeIndex) Error!void {
311 const raw_ty = c.tree.nodes.items(.ty)[@intFromEnum(fn_decl)];
312 const fn_ty = raw_ty.canonicalize(.standard);
313 const node_data = c.tree.nodes.items(.data)[@intFromEnum(fn_decl)];
314 if (c.decl_table.get(@intFromPtr(fn_ty.data.func))) |_|
315 return; // Avoid processing this decl twice
316
317 const fn_name = c.tree.tokSlice(node_data.decl.name);
318 if (c.global_scope.sym_table.contains(fn_name))
319 return; // Avoid processing this decl twice
320
321 const fn_decl_loc = 0; // TODO
322 const has_body = node_data.decl.node != .none;
323 const is_always_inline = has_body and raw_ty.getAttribute(.always_inline) != null;
324 const proto_ctx = FnProtoContext{
325 .fn_name = fn_name,
326 .is_inline = is_always_inline,
327 .is_extern = !has_body,
328 .is_export = switch (c.tree.nodes.items(.tag)[@intFromEnum(fn_decl)]) {
329 .fn_proto,
330 .fn_def => has_body and !is_always_inline,
331
332 .inline_fn_proto,
333 .inline_fn_def,
334 .inline_static_fn_proto,
335 .inline_static_fn_def,
336 .static_fn_proto,
337 .static_fn_def => false,
338
339 else => unreachable,
340 },
341 };
342
343 const proto_node = transFnType(c, &c.global_scope.base, raw_ty, fn_ty, fn_decl_loc, proto_ctx) catch |err| switch (err) {
344 error.UnsupportedType => {
345 return failDecl(c, fn_decl_loc, fn_name, "unable to resolve prototype of function", .{});
346 },
347 error.OutOfMemory => |e| return e,
348 };
349
350 if (!has_body) {
351 return addTopLevelDecl(c, fn_name, proto_node);
352 }
353 const proto_payload = proto_node.castTag(.func).?;
354
355 // actual function definition with body
356 const body_stmt = node_data.decl.node;
357 _ = body_stmt;
358 var block_scope = try Scope.Block.init(c, &c.global_scope.base, false);
359 block_scope.return_type = fn_ty.data.func.return_type;
360 defer block_scope.deinit();
361
362 var scope = &block_scope.base;
363 _ = scope;
364
365 var param_id: c_uint = 0;
366 for (proto_payload.data.params, fn_ty.data.func.params) |*param, param_info| {
367 const param_name = param.name orelse {
368 proto_payload.data.is_extern = true;
369 proto_payload.data.is_export = false;
370 proto_payload.data.is_inline = false;
371 try warn(c, &c.global_scope.base, fn_decl_loc, "function {s} parameter has no name, demoted to extern", .{fn_name});
372 return addTopLevelDecl(c, fn_name, proto_node);
373 };
374
375 const is_const = param_info.ty.qual.@"const";
376
377 const mangled_param_name = try block_scope.makeMangledName(c, param_name);
378 param.name = mangled_param_name;
379
380 if (!is_const) {
381 const bare_arg_name = try std.fmt.allocPrint(c.arena, "arg_{s}", .{mangled_param_name});
382 const arg_name = try block_scope.makeMangledName(c, bare_arg_name);
383 param.name = arg_name;
384
385 const redecl_node = try ZigTag.arg_redecl.create(c.arena, .{ .actual = mangled_param_name, .mangled = arg_name });
386 try block_scope.statements.append(redecl_node);
387 }
388 try block_scope.discardVariable(c, mangled_param_name);
389
390 param_id += 1;
391 }
392
393 // const casted_body = @as(*const clang.CompoundStmt, @ptrCast(body_stmt));
394 // transCompoundStmtInline(c, casted_body, &block_scope) catch |err| switch (err) {
395 // error.OutOfMemory => |e| return e,
396 // error.UnsupportedTranslation,
397 // error.UnsupportedType,
398 // => {
399 // proto_payload.data.is_extern = true;
400 // proto_payload.data.is_export = false;
401 // proto_payload.data.is_inline = false;
402 // try warn(c, &c.global_scope.base, fn_decl_loc, "unable to translate function, demoted to extern", .{});
403 // return addTopLevelDecl(c, fn_name, Node.initPayload(&proto_node.base));
404 // },
405 // };
406
407 proto_payload.data.body = try block_scope.complete(c);
408 return addTopLevelDecl(c, fn_name, proto_node);
304409}
410
305411fn transVarDecl(_: *Context, _: NodeIndex, _: ?usize) Error!void {
306412 @panic("TODO");
307413}
414
308415fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: NodeIndex, field_nodes: []const NodeIndex) Error!void {
309416 const node_types = c.tree.nodes.items(.ty);
310417 const ty = node_types[@intFromEnum(enum_decl)];
......@@ -393,8 +500,6 @@ fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: NodeIndex, field_nodes:
393500}
394501
395502fn transType(c: *Context, scope: *Scope, raw_ty: Type, source_loc: TokenIndex) TypeError!ZigNode {
396 _ = source_loc;
397 _ = scope;
398503 const ty = raw_ty.canonicalize(.standard);
399504 switch (ty.specifier) {
400505 .void => return ZigTag.type.create(c.arena, "anyopaque"),
......@@ -418,10 +523,112 @@ fn transType(c: *Context, scope: *Scope, raw_ty: Type, source_loc: TokenIndex) T
418523 .long_double => return ZigTag.type.create(c.arena, "c_longdouble"),
419524 .float80 => return ZigTag.type.create(c.arena, "f80"),
420525 .float128 => return ZigTag.type.create(c.arena, "f128"),
421 else => @panic("TODO"),
526 .func,
527 .var_args_func,
528 .old_style_func,
529 => return transFnType(c, scope, raw_ty, ty, source_loc, .{}),
530 else => return error.UnsupportedType,
422531 }
423532}
424533
534fn zigAlignment(bit_alignment: u29) u32 {
535 return bit_alignment / 8;
536}
537
538const FnProtoContext = struct {
539 is_pub: bool = false,
540 is_export: bool = false,
541 is_extern: bool = false,
542 is_inline: bool = false,
543 fn_name: ?[]const u8 = null,
544};
545
546fn transFnType(
547 c: *Context,
548 scope: *Scope,
549 raw_ty: Type,
550 fn_ty: Type,
551 source_loc: TokenIndex,
552 ctx: FnProtoContext,
553) !ZigNode {
554 const param_count: usize = fn_ty.data.func.params.len;
555 var fn_params = try c.arena.alloc(ast.Payload.Param, param_count);
556
557 for (fn_ty.data.func.params, fn_params) |param_info, *param_node| {
558 const param_ty = param_info.ty;
559 const is_noalias = param_ty.qual.restrict;
560
561 const param_name: ?[]const u8 = if (param_info.name == .empty)
562 null
563 else
564 c.mapper.lookup(param_info.name);
565
566 const type_node = try transType(c, scope, param_ty, param_info.name_tok);
567 param_node.* = .{
568 .is_noalias = is_noalias,
569 .name = param_name,
570 .type = type_node,
571 };
572 }
573
574 const linksection_string = blk: {
575 if (raw_ty.getAttribute(.section)) |section| {
576 break :blk section.name.slice(c.tree.strings);
577 }
578 break :blk null;
579 };
580
581 const alignment = if (raw_ty.requestedAlignment(c.comp)) |alignment| zigAlignment(alignment) else null;
582
583 const explicit_callconv = null;
584 // const explicit_callconv = if ((ctx.is_inline or ctx.is_export or ctx.is_extern) and ctx.cc == .C) null else ctx.cc;
585
586 const return_type_node = blk: {
587 if (raw_ty.getAttribute(.noreturn) != null) {
588 break :blk ZigTag.noreturn_type.init();
589 } else {
590 const return_ty = fn_ty.data.func.return_type;
591 if (return_ty.is(.void)) {
592 // convert primitive anyopaque to actual void (only for return type)
593 break :blk ZigTag.void_type.init();
594 } else {
595 break :blk transType(c, scope, return_ty, source_loc) catch |err| switch (err) {
596 error.UnsupportedType => {
597 try warn(c, scope, source_loc, "unsupported function proto return type", .{});
598 return err;
599 },
600 error.OutOfMemory => |e| return e,
601 };
602 }
603 }
604 };
605
606 const payload = try c.arena.create(ast.Payload.Func);
607 payload.* = .{
608 .base = .{ .tag = .func },
609 .data = .{
610 .is_pub = ctx.is_pub,
611 .is_extern = ctx.is_extern,
612 .is_export = ctx.is_export,
613 .is_inline = ctx.is_inline,
614 .is_var_args = switch (fn_ty.specifier) {
615 .func => false,
616 .var_args_func => true,
617 .old_style_func => !ctx.is_export and !ctx.is_inline,
618 else => unreachable,
619 },
620 .name = ctx.fn_name,
621 .linksection_string = linksection_string,
622 .explicit_callconv = explicit_callconv,
623 .params = fn_params,
624 .return_type = return_type_node,
625 .body = null,
626 .alignment = alignment,
627 },
628 };
629 return ZigNode.initPayload(&payload.base);
630}
631
425632fn transStmt(c: *Context, node: NodeIndex) TransError!void {
426633 _ = try c.transExpr(node, .unused);
427634}
src/translate_c.zig-2
......@@ -4924,8 +4924,6 @@ fn finishTransFnProto(
49244924 const is_inline = if (fn_decl_context) |ctx| ctx.is_always_inline else false;
49254925 const scope = &c.global_scope.base;
49264926
4927 // TODO check for align attribute
4928
49294927 const param_count: usize = if (fn_proto_ty != null) fn_proto_ty.?.getNumParams() else 0;
49304928 var fn_params = try std.ArrayList(ast.Payload.Param).initCapacity(c.gpa, param_count);
49314929 defer fn_params.deinit();