authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-01-18 21:43:20+01:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-01-19 20:01:23+01:00
log1fe1e4d29207de8c972fcc1b61266fbaddb07d63
tree1f5b8756eab0056a2f6c3cdf05a7bdbfc977fc3b
parent28acbdb02ff934fed3363a580128575e7d8c92ee
signaturelock-open Commit is signed but in an unrecognized format.

wasm: Split funcgen and declgen

This allows us to get rid of unused fields when generating code for non-function decls. We can now create seperate instances of `DeclGen` which in turn can then be used to generate the code for a constant. Besides those reasons, it will be much easier to switch to the generic purpose `codegen.zig` that any backend should use. Allowing us to deduplicate this code.

3 files changed, 363 insertions(+), 312 deletions(-)

src/arch/wasm/CodeGen.zig+290-287
......@@ -542,10 +542,9 @@ locals: std.ArrayListUnmanaged(u8),
542542target: std.Target,
543543/// Represents the wasm binary file that is being linked.
544544bin_file: *link.File.Wasm,
545/// Table with the global error set. Consists of every error found in
546/// the compiled code. Each error name maps to a `Module.ErrorInt` which is emitted
547/// during codegen to determine the error value.
548global_error_set: std.StringHashMapUnmanaged(Module.ErrorInt),
545/// Reference to the Module that this decl is part of.
546/// Used to find the error value.
547module: *Module,
549548/// List of MIR Instructions
550549mir_instructions: std.MultiArrayList(Mir.Inst) = .{},
551550/// Contains extra data for MIR
......@@ -581,7 +580,7 @@ pub fn deinit(self: *Self) void {
581580 self.* = undefined;
582581}
583582
584/// Sets `err_msg` on `Context` and returns `error.CodegemFail` which is caught in link/Wasm.zig
583/// Sets `err_msg` on `CodeGen` and returns `error.CodegenFail` which is caught in link/Wasm.zig
585584fn fail(self: *Self, comptime fmt: []const u8, args: anytype) InnerError {
586585 const src: LazySrcLoc = .{ .node_offset = 0 };
587586 const src_loc = src.toSrcLoc(self.decl);
......@@ -674,50 +673,41 @@ fn addExtraAssumeCapacity(self: *Self, extra: anytype) error{OutOfMemory}!u32 {
674673 return result;
675674}
676675
677/// Using a given `Type`, returns the corresponding wasm Valtype
678fn typeToValtype(self: *Self, ty: Type) InnerError!wasm.Valtype {
676/// Using a given `Type`, returns the corresponding type
677fn typeToValtype(ty: Type, target: std.Target) wasm.Valtype {
679678 return switch (ty.zigTypeTag()) {
680679 .Float => blk: {
681 const bits = ty.floatBits(self.target);
680 const bits = ty.floatBits(target);
682681 if (bits == 16 or bits == 32) break :blk wasm.Valtype.f32;
683682 if (bits == 64) break :blk wasm.Valtype.f64;
684 return self.fail("Float bit size not supported by wasm: '{d}'", .{bits});
683 return wasm.Valtype.i32; // represented as pointer to stack
685684 },
686685 .Int => blk: {
687 const info = ty.intInfo(self.target);
686 const info = ty.intInfo(target);
688687 if (info.bits <= 32) break :blk wasm.Valtype.i32;
689688 if (info.bits > 32 and info.bits <= 64) break :blk wasm.Valtype.i64;
690689 break :blk wasm.Valtype.i32; // represented as pointer to stack
691690 },
692691 .Enum => switch (ty.tag()) {
693692 .enum_simple => wasm.Valtype.i32,
694 else => self.typeToValtype(ty.cast(Type.Payload.EnumFull).?.data.tag_ty),
693 else => typeToValtype(ty.cast(Type.Payload.EnumFull).?.data.tag_ty, target),
695694 },
696 .Bool,
697 .Pointer,
698 .ErrorSet,
699 .Struct,
700 .ErrorUnion,
701 .Optional,
702 .Fn,
703 .Array,
704 => wasm.Valtype.i32,
705 else => self.fail("TODO - Wasm typeToValtype for type '{}'", .{ty}),
695 else => wasm.Valtype.i32, // all represented as reference/immediate
706696 };
707697}
708698
709699/// Using a given `Type`, returns the byte representation of its wasm value type
710fn genValtype(self: *Self, ty: Type) InnerError!u8 {
711 return wasm.valtype(try self.typeToValtype(ty));
700fn genValtype(ty: Type, target: std.Target) u8 {
701 return wasm.valtype(typeToValtype(ty, target));
712702}
713703
714704/// Using a given `Type`, returns the corresponding wasm value type
715705/// Differently from `genValtype` this also allows `void` to create a block
716706/// with no return type
717fn genBlockType(self: *Self, ty: Type) InnerError!u8 {
707fn genBlockType(ty: Type, target: std.Target) u8 {
718708 return switch (ty.tag()) {
719709 .void, .noreturn => wasm.block_empty,
720 else => self.genValtype(ty),
710 else => genValtype(ty, target),
721711 };
722712}
723713
......@@ -739,7 +729,7 @@ fn emitWValue(self: *Self, value: WValue) InnerError!void {
739729/// Returns a corresponding `Wvalue` with `local` as active tag
740730fn allocLocal(self: *Self, ty: Type) InnerError!WValue {
741731 const initial_index = self.local_index;
742 const valtype = try self.genValtype(ty);
732 const valtype = genValtype(ty, self.target);
743733 try self.locals.append(self.gpa, valtype);
744734 self.local_index += 1;
745735 return WValue{ .local = initial_index };
......@@ -747,33 +737,33 @@ fn allocLocal(self: *Self, ty: Type) InnerError!WValue {
747737
748738/// Generates a `wasm.Type` from a given function type.
749739/// Memory is owned by the caller.
750fn genFunctype(self: *Self, fn_ty: Type) !wasm.Type {
751 var params = std.ArrayList(wasm.Valtype).init(self.gpa);
740fn genFunctype(gpa: Allocator, fn_ty: Type, target: std.Target) !wasm.Type {
741 var params = std.ArrayList(wasm.Valtype).init(gpa);
752742 defer params.deinit();
753 var returns = std.ArrayList(wasm.Valtype).init(self.gpa);
743 var returns = std.ArrayList(wasm.Valtype).init(gpa);
754744 defer returns.deinit();
755745 const return_type = fn_ty.fnReturnType();
756746
757 const want_sret = self.isByRef(return_type);
747 const want_sret = isByRef(return_type, target);
758748
759749 if (want_sret) {
760 try params.append(try self.typeToValtype(Type.usize));
750 try params.append(typeToValtype(return_type, target));
761751 }
762752
763753 // param types
764754 if (fn_ty.fnParamLen() != 0) {
765 const fn_params = try self.gpa.alloc(Type, fn_ty.fnParamLen());
766 defer self.gpa.free(fn_params);
755 const fn_params = try gpa.alloc(Type, fn_ty.fnParamLen());
756 defer gpa.free(fn_params);
767757 fn_ty.fnParamTypes(fn_params);
768758 for (fn_params) |param_type| {
769759 if (!param_type.hasCodeGenBits()) continue;
770 try params.append(try self.typeToValtype(param_type));
760 try params.append(typeToValtype(param_type, target));
771761 }
772762 }
773763
774764 // return type
775765 if (!want_sret and return_type.hasCodeGenBits()) {
776 try returns.append(try self.typeToValtype(return_type));
766 try returns.append(typeToValtype(return_type, target));
777767 }
778768
779769 return wasm.Type{
......@@ -782,8 +772,8 @@ fn genFunctype(self: *Self, fn_ty: Type) !wasm.Type {
782772 };
783773}
784774
785pub fn genFunc(self: *Self) InnerError!Result {
786 var func_type = try self.genFunctype(self.decl.ty);
775pub fn genFunc(self: *Self) InnerError!void {
776 var func_type = try genFunctype(self.gpa, self.decl.ty, self.target);
787777 defer func_type.deinit(self.gpa);
788778 self.decl.fn_link.wasm.type_index = try self.bin_file.putOrGetFuncType(func_type);
789779
......@@ -828,240 +818,260 @@ pub fn genFunc(self: *Self) InnerError!Result {
828818 },
829819 else => |e| return e,
830820 };
831
832 // codegen data has been appended to `code`
833 return Result.appended;
834821}
835822
836pub fn genDecl(self: *Self) InnerError!Result {
837 const decl = self.decl;
838 assert(decl.has_tv);
839
840 log.debug("gen: {s} type: {}, value: {}", .{ decl.name, decl.ty, decl.val });
841
842 if (decl.val.castTag(.function)) |func_payload| {
843 _ = func_payload;
844 return self.fail("TODO wasm backend genDecl function pointer", .{});
845 } else if (decl.val.castTag(.extern_fn)) |extern_fn| {
846 const ext_decl = extern_fn.data;
847 var func_type = try self.genFunctype(ext_decl.ty);
848 func_type.deinit(self.gpa);
849 ext_decl.fn_link.wasm.type_index = try self.bin_file.putOrGetFuncType(func_type);
850 return Result.appended;
851 } else {
852 const init_val = if (decl.val.castTag(.variable)) |payload| init_val: {
853 break :init_val payload.data.init;
854 } else decl.val;
855 if (init_val.tag() != .unreachable_value) {
856 return try self.genTypedValue(decl.ty, init_val);
823pub const DeclGen = struct {
824 /// The decl we are generating code for.
825 decl: *Decl,
826 /// The symbol we're generating code for.
827 /// This can either be the symbol of the Decl itself,
828 /// or one of its locals.
829 symbol_index: u32,
830 gpa: Allocator,
831 /// A reference to the linker, that will process the decl's
832 /// code and create any relocations it deems neccesary.
833 bin_file: *link.File.Wasm,
834 /// This will be set when `InnerError` has been returned.
835 /// In any other case, this will be 'undefined'.
836 err_msg: *Module.ErrorMsg,
837 /// Reference to the Module that is being compiled.
838 /// Used to find the error value of an error.
839 module: *Module,
840 /// The list of bytes that have been generated so far,
841 /// can be used to calculate the offset into a section.
842 code: *std.ArrayList(u8),
843
844 /// Sets `err_msg` on `DeclGen` and returns `error.CodegenFail` which is caught in link/Wasm.zig
845 fn fail(self: *DeclGen, comptime fmt: []const u8, args: anytype) InnerError {
846 const src: LazySrcLoc = .{ .node_offset = 0 };
847 const src_loc = src.toSrcLoc(self.decl);
848 self.err_msg = try Module.ErrorMsg.create(self.gpa, src_loc, fmt, args);
849 return error.CodegenFail;
850 }
851
852 fn target(self: *const DeclGen) std.Target {
853 return self.bin_file.base.options.target;
854 }
855
856 pub fn genDecl(self: *DeclGen) InnerError!Result {
857 const decl = self.decl;
858 assert(decl.has_tv);
859
860 log.debug("gen: {s} type: {}, value: {}", .{ decl.name, decl.ty, decl.val });
861
862 if (decl.val.castTag(.function)) |func_payload| {
863 _ = func_payload;
864 return self.fail("TODO wasm backend genDecl function pointer", .{});
865 } else if (decl.val.castTag(.extern_fn)) |extern_fn| {
866 const ext_decl = extern_fn.data;
867 var func_type = try genFunctype(self.gpa, ext_decl.ty, self.target());
868 func_type.deinit(self.gpa);
869 ext_decl.fn_link.wasm.type_index = try self.bin_file.putOrGetFuncType(func_type);
870 return Result.appended;
871 } else {
872 const init_val = if (decl.val.castTag(.variable)) |payload| init_val: {
873 break :init_val payload.data.init;
874 } else decl.val;
875 if (init_val.tag() != .unreachable_value) {
876 return try self.genTypedValue(decl.ty, init_val, self.code.writer());
877 }
878 return Result.appended;
857879 }
858 return Result.appended;
859880 }
860}
861881
862/// Generates the wasm bytecode for the declaration belonging to `Context`
863fn genTypedValue(self: *Self, ty: Type, val: Value) InnerError!Result {
864 if (val.isUndef()) {
865 try self.code.appendNTimes(0xaa, @intCast(usize, ty.abiSize(self.target)));
866 return Result.appended;
867 }
868 switch (ty.zigTypeTag()) {
869 .Fn => {
870 const fn_decl = switch (val.tag()) {
871 .extern_fn => val.castTag(.extern_fn).?.data,
872 .function => val.castTag(.function).?.data.owner_decl,
873 else => unreachable,
874 };
875 return try self.lowerDeclRef(ty, val, fn_decl);
876 },
877 .Optional => {
878 var opt_buf: Type.Payload.ElemType = undefined;
879 const payload_type = ty.optionalChild(&opt_buf);
880 if (ty.isPtrLikeOptional()) {
881 if (val.castTag(.opt_payload)) |payload| {
882 return try self.genTypedValue(payload_type, payload.data);
883 } else if (!val.isNull()) {
884 return try self.genTypedValue(payload_type, val);
885 } else {
886 try self.code.appendNTimes(0, @intCast(usize, ty.abiSize(self.target)));
882 /// Generates the wasm bytecode for the declaration belonging to `Context`
883 fn genTypedValue(self: *DeclGen, ty: Type, val: Value, writer: anytype) InnerError!Result {
884 if (val.isUndef()) {
885 try writer.writeByteNTimes(0xaa, @intCast(usize, ty.abiSize(self.target())));
886 return Result.appended;
887 }
888 switch (ty.zigTypeTag()) {
889 .Fn => {
890 const fn_decl = switch (val.tag()) {
891 .extern_fn => val.castTag(.extern_fn).?.data,
892 .function => val.castTag(.function).?.data.owner_decl,
893 else => unreachable,
894 };
895 return try self.lowerDeclRef(ty, val, fn_decl, writer);
896 },
897 .Optional => {
898 var opt_buf: Type.Payload.ElemType = undefined;
899 const payload_type = ty.optionalChild(&opt_buf);
900 const is_pl = !val.isNull();
901
902 if (!payload_type.hasCodeGenBits()) {
903 try writer.writeByteNTimes(@boolToInt(is_pl), 4);
887904 return Result.appended;
888905 }
889 }
890 // `null-tag` byte
891 try self.code.appendNTimes(@boolToInt(!val.isNull()), 4);
892 const pl_result = try self.genTypedValue(
893 payload_type,
894 if (val.castTag(.opt_payload)) |pl| pl.data else Value.initTag(.undef),
895 );
896 switch (pl_result) {
897 .appended => {},
898 .externally_managed => |payload| try self.code.appendSlice(payload),
899 }
900 return Result.appended;
901 },
902 .Array => switch (val.tag()) {
903 .bytes => {
904 const payload = val.castTag(.bytes).?;
905 return Result{ .externally_managed = payload.data };
906
907 if (ty.isPtrLikeOptional()) {
908 if (val.castTag(.opt_payload)) |payload| {
909 return try self.genTypedValue(payload_type, payload.data, writer);
910 } else if (!val.isNull()) {
911 return try self.genTypedValue(payload_type, val, writer);
912 } else {
913 try writer.writeByteNTimes(0, @intCast(usize, ty.abiSize(self.target())));
914 return Result.appended;
915 }
916 }
917
918 // `null-tag` bytes
919 try writer.writeByteNTimes(@boolToInt(is_pl), 4);
920 const pl_result = try self.genTypedValue(
921 payload_type,
922 if (val.castTag(.opt_payload)) |pl| pl.data else Value.initTag(.undef),
923 writer,
924 );
925 switch (pl_result) {
926 .appended => {},
927 .externally_managed => |payload| try writer.writeAll(payload),
928 }
929 return Result.appended;
906930 },
907 .array => {
908 const elem_vals = val.castTag(.array).?.data;
909 const elem_ty = ty.childType();
910 for (elem_vals) |elem_val| {
911 switch (try self.genTypedValue(elem_ty, elem_val)) {
931 .Array => switch (val.tag()) {
932 .bytes => {
933 const payload = val.castTag(.bytes).?;
934 return Result{ .externally_managed = payload.data };
935 },
936 .array => {
937 const elem_vals = val.castTag(.array).?.data;
938 const elem_ty = ty.childType();
939 for (elem_vals) |elem_val| {
940 switch (try self.genTypedValue(elem_ty, elem_val, writer)) {
941 .appended => {},
942 .externally_managed => |data| try writer.writeAll(data),
943 }
944 }
945 return Result.appended;
946 },
947 else => return self.fail("TODO implement genTypedValue for array type value: {s}", .{@tagName(val.tag())}),
948 },
949 .Int => {
950 const info = ty.intInfo(self.target());
951 const abi_size = @intCast(usize, ty.abiSize(self.target()));
952 // todo: Implement integer sizes larger than 64bits
953 if (info.bits > 64) return self.fail("TODO: Implement genTypedValue for integer bit size: {d}", .{info.bits});
954 var buf: [8]u8 = undefined;
955 if (info.signedness == .unsigned) {
956 std.mem.writeIntLittle(u64, &buf, val.toUnsignedInt());
957 } else std.mem.writeIntLittle(i64, &buf, val.toSignedInt());
958 try writer.writeAll(buf[0..abi_size]);
959 return Result.appended;
960 },
961 .Enum => {
962 try writer.writeByteNTimes(0xaa, @intCast(usize, ty.abiSize(self.target())));
963 return Result.appended;
964 },
965 .Bool => {
966 try writer.writeByte(@boolToInt(val.toBool()));
967 return Result.appended;
968 },
969 .Struct => {
970 const field_vals = val.castTag(.@"struct").?.data;
971 for (field_vals) |field_val, index| {
972 const field_ty = ty.structFieldType(index);
973 if (!field_ty.hasCodeGenBits()) continue;
974 switch (try self.genTypedValue(field_ty, field_val, writer)) {
912975 .appended => {},
913 .externally_managed => |data| try self.code.appendSlice(data),
976 .externally_managed => |payload| try writer.writeAll(payload),
914977 }
915978 }
916979 return Result.appended;
917980 },
918 else => return self.fail("TODO implement genTypedValue for array type value: {s}", .{@tagName(val.tag())}),
919 },
920 .Int => {
921 const info = ty.intInfo(self.target);
922 const abi_size = @intCast(usize, ty.abiSize(self.target));
923 // todo: Implement integer sizes larger than 64bits
924 if (info.bits > 64) return self.fail("TODO: Implement genTypedValue for integer bit size: {d}", .{info.bits});
925 var buf: [8]u8 = undefined;
926 if (info.signedness == .unsigned) {
927 std.mem.writeIntLittle(u64, &buf, val.toUnsignedInt());
928 } else std.mem.writeIntLittle(i64, &buf, val.toSignedInt());
929 try self.code.appendSlice(buf[0..abi_size]);
930 return Result.appended;
931 },
932 .Enum => {
933 const size = @intCast(usize, ty.abiSize(self.target));
934 try self.code.appendNTimes(0xaa, size);
935 return Result.appended;
936 },
937 .Bool => {
938 const int_byte: u8 = @boolToInt(val.toBool());
939 try self.code.append(int_byte);
940 return Result.appended;
941 },
942 .Struct => {
943 const field_vals = val.castTag(.@"struct").?.data;
944 for (field_vals) |field_val, index| {
945 const field_ty = ty.structFieldType(index);
946 if (!field_ty.hasCodeGenBits()) continue;
947 switch (try self.genTypedValue(field_ty, field_val)) {
948 .appended => {},
949 .externally_managed => |payload| try self.code.appendSlice(payload),
950 }
951 }
952 return Result.appended;
953 },
954 .Union => {
955 // TODO: Implement Union declarations
956 const abi_size = @intCast(usize, ty.abiSize(self.target));
957 try self.code.appendNTimes(0xaa, abi_size);
958 return Result.appended;
959 },
960 .Pointer => switch (val.tag()) {
961 .variable => {
962 const decl = val.castTag(.variable).?.data.owner_decl;
963 return try self.lowerDeclRef(ty, val, decl);
981 .Union => {
982 // TODO: Implement Union declarations
983 try writer.writeByteNTimes(0xaa, @intCast(usize, ty.abiSize(self.target())));
984 return Result.appended;
964985 },
965 .decl_ref => {
966 const decl = val.castTag(.decl_ref).?.data;
967 return try self.lowerDeclRef(ty, val, decl);
986 .Pointer => switch (val.tag()) {
987 .variable => {
988 const decl = val.castTag(.variable).?.data.owner_decl;
989 return try self.lowerDeclRef(ty, val, decl, writer);
990 },
991 .decl_ref => {
992 const decl = val.castTag(.decl_ref).?.data;
993 return try self.lowerDeclRef(ty, val, decl, writer);
994 },
995 .slice => {
996 const slice = val.castTag(.slice).?.data;
997 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
998 const ptr_ty = ty.slicePtrFieldType(&buf);
999 switch (try self.genTypedValue(ptr_ty, slice.ptr, writer)) {
1000 .externally_managed => |data| try writer.writeAll(data),
1001 .appended => {},
1002 }
1003 switch (try self.genTypedValue(Type.usize, slice.len, writer)) {
1004 .externally_managed => |data| try writer.writeAll(data),
1005 .appended => {},
1006 }
1007 return Result.appended;
1008 },
1009 else => return self.fail("TODO: Implement zig decl gen for pointer type value: '{s}'", .{@tagName(val.tag())}),
9681010 },
969 .slice => {
970 const slice = val.castTag(.slice).?.data;
971 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
972 const ptr_ty = ty.slicePtrFieldType(&buf);
973 switch (try self.genTypedValue(ptr_ty, slice.ptr)) {
974 .externally_managed => |data| try self.code.appendSlice(data),
1011 .ErrorUnion => {
1012 const error_ty = ty.errorUnionSet();
1013 const payload_ty = ty.errorUnionPayload();
1014 const is_pl = val.errorUnionIsPayload();
1015
1016 const err_val = if (!is_pl) val else Value.initTag(.zero);
1017 switch (try self.genTypedValue(error_ty, err_val, writer)) {
1018 .externally_managed => |data| try writer.writeAll(data),
9751019 .appended => {},
9761020 }
977 switch (try self.genTypedValue(Type.usize, slice.len)) {
978 .externally_managed => |data| try self.code.appendSlice(data),
979 .appended => {},
1021
1022 if (payload_ty.hasCodeGenBits()) {
1023 const pl_val = if (val.castTag(.eu_payload)) |pl| pl.data else Value.initTag(.undef);
1024 switch (try self.genTypedValue(payload_ty, pl_val, writer)) {
1025 .externally_managed => |data| try writer.writeAll(data),
1026 .appended => {},
1027 }
9801028 }
1029
9811030 return Result.appended;
9821031 },
983 else => return self.fail("TODO: Implement zig decl gen for pointer type value: '{s}'", .{@tagName(val.tag())}),
984 },
985 .ErrorUnion => {
986 const error_ty = ty.errorUnionSet();
987 const payload_ty = ty.errorUnionPayload();
988 const is_pl = val.errorUnionIsPayload();
989
990 const err_val = if (!is_pl) val else Value.initTag(.zero);
991 switch (try self.genTypedValue(error_ty, err_val)) {
992 .externally_managed => |data| try self.code.appendSlice(data),
993 .appended => {},
994 }
995
996 if (payload_ty.hasCodeGenBits()) {
997 const pl_val = if (val.castTag(.eu_payload)) |pl| pl.data else Value.initTag(.undef);
998 switch (try self.genTypedValue(payload_ty, pl_val)) {
999 .externally_managed => |data| try self.code.appendSlice(data),
1000 .appended => {},
1032 .ErrorSet => {
1033 switch (val.tag()) {
1034 .@"error" => {
1035 const name = val.castTag(.@"error").?.data.name;
1036 const kv = try self.module.getErrorValue(name);
1037 try writer.writeIntLittle(u32, kv.value);
1038 },
1039 else => {
1040 try writer.writeByteNTimes(0, @intCast(usize, ty.abiSize(self.target())));
1041 },
10011042 }
1002 }
1003
1004 return Result.appended;
1005 },
1006 .ErrorSet => {
1007 switch (val.tag()) {
1008 .@"error" => {
1009 const name = val.castTag(.@"error").?.data.name;
1010 const value = self.global_error_set.get(name).?;
1011 try self.code.writer().writeIntLittle(u32, value);
1012 },
1013 else => {
1014 const abi_size = @intCast(usize, ty.abiSize(self.target));
1015 try self.code.appendNTimes(0, abi_size);
1016 },
1017 }
1018 return Result.appended;
1019 },
1020 else => |tag| return self.fail("TODO: Implement zig type codegen for type: '{s}'", .{tag}),
1043 return Result.appended;
1044 },
1045 else => |tag| return self.fail("TODO: Implement zig type codegen for type: '{s}'", .{tag}),
1046 }
10211047 }
1022}
10231048
1024fn lowerDeclRef(self: *Self, ty: Type, val: Value, decl: *Module.Decl) InnerError!Result {
1025 if (ty.isSlice()) {
1026 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
1027 const slice_ty = ty.slicePtrFieldType(&buf);
1028 switch (try self.genTypedValue(slice_ty, val)) {
1029 .appended => {},
1030 .externally_managed => |payload| try self.code.appendSlice(payload),
1049 fn lowerDeclRef(self: *DeclGen, ty: Type, val: Value, decl: *Module.Decl, writer: anytype) InnerError!Result {
1050 if (ty.isSlice()) {
1051 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
1052 const slice_ty = ty.slicePtrFieldType(&buf);
1053 switch (try self.genTypedValue(slice_ty, val, writer)) {
1054 .appended => {},
1055 .externally_managed => |payload| try writer.writeAll(payload),
1056 }
1057 var slice_len: Value.Payload.U64 = .{
1058 .base = .{ .tag = .int_u64 },
1059 .data = val.sliceLen(),
1060 };
1061 return try self.genTypedValue(Type.usize, Value.initPayload(&slice_len.base), writer);
10311062 }
1032 var slice_len: Value.Payload.U64 = .{
1033 .base = .{ .tag = .int_u64 },
1034 .data = val.sliceLen(),
1035 };
1036 return try self.genTypedValue(Type.usize, Value.initPayload(&slice_len.base));
1037 }
1038
1039 const offset = @intCast(u32, self.code.items.len);
1040 const atom = &self.decl.link.wasm;
1041 const target_sym_index = decl.link.wasm.sym_index;
1042 decl.markAlive();
1043 if (decl.ty.zigTypeTag() == .Fn) {
1044 // We found a function pointer, so add it to our table,
1045 // as function pointers are not allowed to be stored inside the data section,
1046 // but rather in a function table which are called by index
1047 try self.bin_file.addTableFunction(target_sym_index);
1048 try atom.relocs.append(self.gpa, .{
1049 .index = target_sym_index,
1050 .offset = offset,
1051 .relocation_type = .R_WASM_TABLE_INDEX_I32,
1052 });
1053 } else {
1054 try atom.relocs.append(self.gpa, .{
1055 .index = target_sym_index,
1056 .offset = offset,
1057 .relocation_type = .R_WASM_MEMORY_ADDR_I32,
1058 });
1059 }
1060 const ptr_width = @intCast(usize, self.target.cpu.arch.ptrBitWidth() / 8);
1061 try self.code.appendNTimes(0xaa, ptr_width);
10621063
1063 return Result.appended;
1064}
1064 decl.markAlive();
1065 try writer.writeIntLittle(u32, try self.bin_file.getDeclVAddr(
1066 self.decl, // The decl containing the source symbol index
1067 decl.ty, // type we generate the address of
1068 self.symbol_index, // source symbol index
1069 decl.link.wasm.sym_index, // target symbol index
1070 @intCast(u32, self.code.items.len), // offset
1071 ));
1072 return Result.appended;
1073 }
1074};
10651075
10661076const CallWValues = struct {
10671077 args: []WValue,
......@@ -1086,7 +1096,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) InnerError!CallWValu
10861096 const ret_ty = fn_ty.fnReturnType();
10871097 // Check if we store the result as a pointer to the stack rather than
10881098 // by value
1089 if (self.isByRef(ret_ty)) {
1099 if (isByRef(ret_ty, self.target)) {
10901100 // the sret arg will be passed as first argument, therefore we
10911101 // set the `return_value` before allocating locals for regular args.
10921102 result.return_value = .{ .local = self.local_index };
......@@ -1213,8 +1223,8 @@ fn arch(self: *const Self) std.Target.Cpu.Arch {
12131223}
12141224
12151225/// For a given `Type`, will return true when the type will be passed
1216/// by reference, rather than by value.
1217fn isByRef(self: Self, ty: Type) bool {
1226/// by reference, rather than by value
1227fn isByRef(ty: Type, target: std.Target) bool {
12181228 switch (ty.zigTypeTag()) {
12191229 .Type,
12201230 .ComptimeInt,
......@@ -1242,7 +1252,7 @@ fn isByRef(self: Self, ty: Type) bool {
12421252 .Frame,
12431253 .Union,
12441254 => return ty.hasCodeGenBits(),
1245 .Int => return if (ty.intInfo(self.target).bits > 64) true else false,
1255 .Int => return if (ty.intInfo(target).bits > 64) true else false,
12461256 .ErrorUnion => {
12471257 const has_tag = ty.errorUnionSet().hasCodeGenBits();
12481258 const has_pl = ty.errorUnionPayload().hasCodeGenBits();
......@@ -1470,7 +1480,7 @@ fn airRetPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
14701480 const child_type = self.air.typeOfIndex(inst).childType();
14711481 if (child_type.abiSize(self.target) == 0) return WValue{ .none = {} };
14721482
1473 if (self.isByRef(child_type)) {
1483 if (isByRef(child_type, self.target)) {
14741484 return self.return_value;
14751485 }
14761486
......@@ -1487,7 +1497,7 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
14871497 const ret_ty = self.air.typeOf(un_op).childType();
14881498 if (!ret_ty.hasCodeGenBits()) return WValue.none;
14891499
1490 if (!self.isByRef(ret_ty)) {
1500 if (!isByRef(ret_ty, self.target)) {
14911501 const result = try self.load(operand, ret_ty, 0);
14921502 try self.emitWValue(result);
14931503 }
......@@ -1509,7 +1519,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
15091519 else => unreachable,
15101520 };
15111521 const ret_ty = fn_ty.fnReturnType();
1512 const first_param_sret = self.isByRef(ret_ty);
1522 const first_param_sret = isByRef(ret_ty, self.target);
15131523
15141524 const target: ?*Decl = blk: {
15151525 const func_val = self.air.value(pl_op.operand) orelse break :blk null;
......@@ -1546,7 +1556,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
15461556 const operand = try self.resolveInst(pl_op.operand);
15471557 try self.emitWValue(operand);
15481558
1549 var fn_type = try self.genFunctype(fn_ty);
1559 var fn_type = try genFunctype(self.gpa, fn_ty, self.target);
15501560 defer fn_type.deinit(self.gpa);
15511561
15521562 const fn_type_index = try self.bin_file.putOrGetFuncType(fn_type);
......@@ -1642,7 +1652,7 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro
16421652 }
16431653 try self.emitWValue(lhs);
16441654 try self.emitWValue(rhs);
1645 const valtype = try self.typeToValtype(ty);
1655 const valtype = typeToValtype(ty, self.target);
16461656 // check if we should pass by pointer or value based on ABI size
16471657 // TODO: Implement a way to get ABI values from a given type,
16481658 // that is portable across the backend, rather than copying logic.
......@@ -1675,7 +1685,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
16751685
16761686 if (!ty.hasCodeGenBits()) return WValue{ .none = {} };
16771687
1678 if (self.isByRef(ty)) {
1688 if (isByRef(ty, self.target)) {
16791689 const new_local = try self.allocStack(ty);
16801690 try self.store(new_local, operand, ty, 0);
16811691 return new_local;
......@@ -1712,7 +1722,7 @@ fn load(self: *Self, operand: WValue, ty: Type, offset: u32) InnerError!WValue {
17121722 };
17131723
17141724 const opcode = buildOpcode(.{
1715 .valtype1 = try self.typeToValtype(ty),
1725 .valtype1 = typeToValtype(ty, self.target),
17161726 .width = abi_size * 8, // use bitsize instead of byte size
17171727 .op = .load,
17181728 .signedness = signedness,
......@@ -1743,7 +1753,7 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue {
17431753 const rhs = try self.resolveInst(bin_op.rhs);
17441754 const operand_ty = self.air.typeOfIndex(inst);
17451755
1746 if (self.isByRef(operand_ty)) {
1756 if (isByRef(operand_ty, self.target)) {
17471757 return self.fail("TODO: Implement binary operation for type: {}", .{operand_ty});
17481758 }
17491759
......@@ -1753,7 +1763,7 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue {
17531763 const bin_ty = self.air.typeOf(bin_op.lhs);
17541764 const opcode: wasm.Opcode = buildOpcode(.{
17551765 .op = op,
1756 .valtype1 = try self.typeToValtype(bin_ty),
1766 .valtype1 = typeToValtype(bin_ty, self.target),
17571767 .signedness = if (bin_ty.isSignedInt()) .signed else .unsigned,
17581768 });
17591769 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));
......@@ -1775,7 +1785,7 @@ fn airWrapBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue {
17751785 const bin_ty = self.air.typeOf(bin_op.lhs);
17761786 const opcode: wasm.Opcode = buildOpcode(.{
17771787 .op = op,
1778 .valtype1 = try self.typeToValtype(bin_ty),
1788 .valtype1 = typeToValtype(bin_ty, self.target),
17791789 .signedness = if (bin_ty.isSignedInt()) .signed else .unsigned,
17801790 });
17811791 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));
......@@ -1924,8 +1934,8 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue {
19241934 },
19251935 .ErrorSet => switch (val.tag()) {
19261936 .@"error" => {
1927 const error_index = self.global_error_set.get(val.getError().?).?;
1928 return WValue{ .imm32 = error_index };
1937 const kv = try self.module.getErrorValue(val.getError().?);
1938 return WValue{ .imm32 = kv.value };
19291939 },
19301940 else => return WValue{ .imm32 = 0 },
19311941 },
......@@ -1945,7 +1955,7 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue {
19451955 if (val.castTag(.eu_payload)) |pl| pl.data else Value.initTag(.undef),
19461956 payload_type,
19471957 );
1948 const pl_ptr = if (self.isByRef(payload_type))
1958 const pl_ptr = if (isByRef(payload_type, self.target))
19491959 try self.buildPointerOffset(result, error_type.abiSize(self.target), .new)
19501960 else
19511961 result;
......@@ -2159,8 +2169,8 @@ fn valueAsI32(self: Self, val: Value, ty: Type) i32 {
21592169 .unsigned => return @bitCast(i32, @truncate(u32, val.toUnsignedInt())),
21602170 },
21612171 .ErrorSet => {
2162 const error_index = self.global_error_set.get(val.getError().?).?;
2163 return @bitCast(i32, error_index);
2172 const kv = self.module.getErrorValue(val.getError().?) catch unreachable; // passed invalid `Value` to function
2173 return @bitCast(i32, kv.value);
21642174 },
21652175 else => unreachable, // Programmer called this function for an illegal type
21662176 }
......@@ -2168,7 +2178,7 @@ fn valueAsI32(self: Self, val: Value, ty: Type) i32 {
21682178
21692179fn airBlock(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
21702180 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
2171 const block_ty = try self.genBlockType(self.air.getRefType(ty_pl.ty));
2181 const block_ty = genBlockType(self.air.getRefType(ty_pl.ty), self.target);
21722182 const extra = self.air.extraData(Air.Block, ty_pl.payload);
21732183 const body = self.air.extra[extra.end..][0..extra.data.body_len];
21742184
......@@ -2265,7 +2275,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: std.math.CompareOperator) Inner
22652275 // both lhs and rhs, as well as checking the payload are matching of lhs and rhs
22662276 return self.cmpOptionals(lhs, rhs, operand_ty, op);
22672277 }
2268 } else if (self.isByRef(operand_ty)) {
2278 } else if (isByRef(operand_ty, self.target)) {
22692279 return self.cmpBigInt(lhs, rhs, operand_ty, op);
22702280 }
22712281
......@@ -2280,7 +2290,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: std.math.CompareOperator) Inner
22802290 break :blk operand_ty.intInfo(self.target).signedness;
22812291 };
22822292 const opcode: wasm.Opcode = buildOpcode(.{
2283 .valtype1 = try self.typeToValtype(operand_ty),
2293 .valtype1 = typeToValtype(operand_ty, self.target),
22842294 .op = switch (op) {
22852295 .lt => .lt,
22862296 .lte => .le,
......@@ -2353,13 +2363,6 @@ fn airUnreachable(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
23532363fn airBitcast(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
23542364 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
23552365 const operand = try self.resolveInst(ty_op.operand);
2356 // if (operand == .constant) {
2357 // std.debug.print("Let's take a look at this!!!!!!\n--------------------\n", .{});
2358 // const result = try self.allocLocal(self.air.typeOfIndex(inst));
2359 // try self.emitWValue(operand);
2360 // try self.addLabel(.local_set, result.local);
2361 // return result;
2362 // }
23632366 return operand;
23642367}
23652368
......@@ -2407,7 +2410,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
24072410 return self.fail("Field type '{}' too big to fit into stack frame", .{field_ty});
24082411 };
24092412
2410 if (self.isByRef(field_ty)) {
2413 if (isByRef(field_ty, self.target)) {
24112414 return self.buildPointerOffset(operand, offset, .new);
24122415 }
24132416
......@@ -2527,7 +2530,7 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
25272530 const val = try self.lowerConstant(case.values[0].value, target_ty);
25282531 try self.emitWValue(val);
25292532 const opcode = buildOpcode(.{
2530 .valtype1 = try self.typeToValtype(target_ty),
2533 .valtype1 = typeToValtype(target_ty, self.target),
25312534 .op = .ne, // not equal, because we want to jump out of this block if it does not match the condition.
25322535 .signedness = signedness,
25332536 });
......@@ -2541,7 +2544,7 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
25412544 const val = try self.lowerConstant(value.value, target_ty);
25422545 try self.emitWValue(val);
25432546 const opcode = buildOpcode(.{
2544 .valtype1 = try self.typeToValtype(target_ty),
2547 .valtype1 = typeToValtype(target_ty, self.target),
25452548 .op = .eq,
25462549 .signedness = signedness,
25472550 });
......@@ -2596,7 +2599,7 @@ fn airUnwrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue
25962599 const payload_ty = err_ty.errorUnionPayload();
25972600 if (!payload_ty.hasCodeGenBits()) return WValue{ .none = {} };
25982601 const offset = @intCast(u32, err_ty.errorUnionSet().abiSize(self.target));
2599 if (self.isByRef(payload_ty)) {
2602 if (isByRef(payload_ty, self.target)) {
26002603 return self.buildPointerOffset(operand, offset, .new);
26012604 }
26022605 return try self.load(operand, payload_ty, offset);
......@@ -2725,7 +2728,7 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
27252728
27262729 const offset = opt_ty.abiSize(self.target) - payload_ty.abiSize(self.target);
27272730
2728 if (self.isByRef(payload_ty)) {
2731 if (isByRef(payload_ty, self.target)) {
27292732 return self.buildPointerOffset(operand, offset, .new);
27302733 }
27312734
......@@ -2856,7 +2859,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
28562859 const result = try self.allocLocal(elem_ty);
28572860 try self.addLabel(.local_set, result.local);
28582861
2859 if (self.isByRef(elem_ty)) {
2862 if (isByRef(elem_ty, self.target)) {
28602863 return result;
28612864 }
28622865 return try self.load(result, elem_ty, 0);
......@@ -3017,7 +3020,7 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
30173020
30183021 const result = try self.allocLocal(elem_ty);
30193022 try self.addLabel(.local_set, result.local);
3020 if (self.isByRef(elem_ty)) {
3023 if (isByRef(elem_ty, self.target)) {
30213024 return result;
30223025 }
30233026 return try self.load(result, elem_ty, 0);
......@@ -3064,7 +3067,7 @@ fn airPtrBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue {
30643067 else => ptr_ty.childType(),
30653068 };
30663069
3067 const valtype = try self.typeToValtype(Type.usize);
3070 const valtype = typeToValtype(Type.usize, self.target);
30683071 const mul_opcode = buildOpcode(.{ .valtype1 = valtype, .op = .mul });
30693072 const bin_opcode = buildOpcode(.{ .valtype1 = valtype, .op = op });
30703073
......@@ -3167,7 +3170,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
31673170 const result = try self.allocLocal(elem_ty);
31683171 try self.addLabel(.local_set, result.local);
31693172
3170 if (self.isByRef(elem_ty)) {
3173 if (isByRef(elem_ty, self.target)) {
31713174 return result;
31723175 }
31733176 return try self.load(result, elem_ty, 0);
......@@ -3184,8 +3187,8 @@ fn airFloatToInt(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
31843187 try self.emitWValue(operand);
31853188 const op = buildOpcode(.{
31863189 .op = .trunc,
3187 .valtype1 = try self.typeToValtype(dest_ty),
3188 .valtype2 = try self.typeToValtype(op_ty),
3190 .valtype1 = typeToValtype(dest_ty, self.target),
3191 .valtype2 = typeToValtype(op_ty, self.target),
31893192 .signedness = if (dest_ty.isSignedInt()) .signed else .unsigned,
31903193 });
31913194 try self.addTag(Mir.Inst.Tag.fromOpcode(op));
......@@ -3249,7 +3252,7 @@ fn cmpOptionals(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std
32493252
32503253 try self.emitWValue(lhs_pl);
32513254 try self.emitWValue(rhs_pl);
3252 const opcode = buildOpcode(.{ .op = .ne, .valtype1 = try self.typeToValtype(payload_ty) });
3255 const opcode = buildOpcode(.{ .op = .ne, .valtype1 = typeToValtype(payload_ty, self.target) });
32533256 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));
32543257 try self.addLabel(.br_if, 0);
32553258
src/link/Wasm.zig+55-25
......@@ -234,12 +234,12 @@ pub fn updateFunc(self: *Wasm, module: *Module, func: *Module.Fn, air: Air, live
234234 .locals = .{},
235235 .target = self.base.options.target,
236236 .bin_file = self,
237 .global_error_set = self.base.options.module.?.global_error_set,
237 .module = module,
238238 };
239239 defer codegen.deinit();
240240
241241 // generate the 'code' section for the function declaration
242 const result = codegen.genFunc() catch |err| switch (err) {
242 codegen.genFunc() catch |err| switch (err) {
243243 error.CodegenFail => {
244244 decl.analysis = .codegen_failure;
245245 try module.failed_decls.put(module.gpa, decl, codegen.err_msg);
......@@ -247,7 +247,7 @@ pub fn updateFunc(self: *Wasm, module: *Module, func: *Module.Fn, air: Air, live
247247 },
248248 else => |e| return e,
249249 };
250 return self.finishUpdateDecl(decl, result, &codegen);
250 return self.finishUpdateDecl(decl, codegen.code.items);
251251}
252252
253253// Generate code for the Decl, storing it in memory to be later written to
......@@ -264,40 +264,37 @@ pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void {
264264
265265 decl.link.wasm.clear();
266266
267 var codegen: CodeGen = .{
267 var code_writer = std.ArrayList(u8).init(self.base.allocator);
268 defer code_writer.deinit();
269 var decl_gen: CodeGen.DeclGen = .{
268270 .gpa = self.base.allocator,
269 .air = undefined,
270 .liveness = undefined,
271 .values = .{},
272 .code = std.ArrayList(u8).init(self.base.allocator),
273271 .decl = decl,
274 .err_msg = undefined,
275 .locals = .{},
276 .target = self.base.options.target,
272 .symbol_index = decl.link.wasm.sym_index,
277273 .bin_file = self,
278 .global_error_set = self.base.options.module.?.global_error_set,
274 .err_msg = undefined,
275 .code = &code_writer,
276 .module = module,
279277 };
280 defer codegen.deinit();
281278
282279 // generate the 'code' section for the function declaration
283 const result = codegen.genDecl() catch |err| switch (err) {
280 const result = decl_gen.genDecl() catch |err| switch (err) {
284281 error.CodegenFail => {
285282 decl.analysis = .codegen_failure;
286 try module.failed_decls.put(module.gpa, decl, codegen.err_msg);
283 try module.failed_decls.put(module.gpa, decl, decl_gen.err_msg);
287284 return;
288285 },
289286 else => |e| return e,
290287 };
291288
292 return self.finishUpdateDecl(decl, result, &codegen);
293}
294
295fn finishUpdateDecl(self: *Wasm, decl: *Module.Decl, result: CodeGen.Result, codegen: *CodeGen) !void {
296 const code: []const u8 = switch (result) {
297 .appended => @as([]const u8, codegen.code.items),
298 .externally_managed => |payload| payload,
289 const code = switch (result) {
290 .externally_managed => |data| data,
291 .appended => code_writer.items,
299292 };
300293
294 return self.finishUpdateDecl(decl, code);
295}
296
297fn finishUpdateDecl(self: *Wasm, decl: *Module.Decl, code: []const u8) !void {
301298 if (decl.isExtern()) {
302299 try self.addOrUpdateImport(decl);
303300 return;
......@@ -313,7 +310,7 @@ fn finishUpdateDecl(self: *Wasm, decl: *Module.Decl, result: CodeGen.Result, cod
313310
314311/// Creates a new local symbol for a given type (and its bytes it's represented by)
315312/// and then append it as a 'contained' atom onto the Decl.
316pub fn createLocalSymbol(self: *Wasm, decl: *Module.Decl, ty: Type, code: []const u8) !u32 {
313pub fn createLocalSymbol(self: *Wasm, decl: *Module.Decl, ty: Type) !u32 {
317314 assert(ty.zigTypeTag() != .Fn); // cannot create local symbols for functions
318315 var symbol: Symbol = .{
319316 .name = "unnamed_local",
......@@ -325,9 +322,7 @@ pub fn createLocalSymbol(self: *Wasm, decl: *Module.Decl, ty: Type, code: []cons
325322 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
326323
327324 var atom = Atom.empty;
328 atom.size = @intCast(u32, code.len);
329325 atom.alignment = ty.abiAlignment(self.base.options.target);
330 try atom.code.appendSlice(self.base.allocator, code);
331326
332327 if (self.symbols_free_list.popOrNull()) |index| {
333328 atom.sym_index = index;
......@@ -341,6 +336,41 @@ pub fn createLocalSymbol(self: *Wasm, decl: *Module.Decl, ty: Type, code: []cons
341336 return atom.sym_index;
342337}
343338
339pub fn updateLocalSymbolCode(self: *Wasm, decl: *Module.Decl, symbol_index: u32, code: []const u8) !void {
340 const atom = decl.link.wasm.symbolAtom(symbol_index);
341 atom.size = @intCast(u32, code.len);
342 try atom.code.appendSlice(self.base.allocator, code);
343}
344
345/// For a given decl, find the given symbol index's atom, and create a relocation for the type.
346/// Returns the given pointer address
347pub fn getDeclVAddr(self: *Wasm, decl: *Module.Decl, ty: Type, symbol_index: u32, target_symbol_index: u32, offset: u32) !u32 {
348 const atom = decl.link.wasm.symbolAtom(symbol_index);
349 const is_wasm32 = self.base.options.target.cpu.arch == .wasm32;
350 if (ty.zigTypeTag() == .Fn) {
351 // We found a function pointer, so add it to our table,
352 // as function pointers are not allowed to be stored inside the data section.
353 // They are instead stored in a function table which are called by index.
354 try self.addTableFunction(target_symbol_index);
355 try atom.relocs.append(self.base.allocator, .{
356 .index = target_symbol_index,
357 .offset = offset,
358 .relocation_type = if (is_wasm32) .R_WASM_TABLE_INDEX_I32 else .R_WASM_TABLE_INDEX_I64,
359 });
360 } else {
361 try atom.relocs.append(self.base.allocator, .{
362 .index = target_symbol_index,
363 .offset = offset,
364 .relocation_type = if (is_wasm32) .R_WASM_MEMORY_ADDR_I32 else .R_WASM_MEMORY_ADDR_I64,
365 });
366 }
367 // we do not know the final address at this point,
368 // as atom allocation will determine the address and relocations
369 // will calculate and rewrite this. Therefore, we simply return the symbol index
370 // that was targeted.
371 return target_symbol_index;
372}
373
344374pub fn updateDeclExports(
345375 self: *Wasm,
346376 module: *Module,
src/link/Wasm/Atom.zig+18
......@@ -31,6 +31,10 @@ next: ?*Atom,
3131/// is null when this atom is the first in its order
3232prev: ?*Atom,
3333
34/// Contains atoms local to a decl, all managed by this `Atom`.
35/// When the parent atom is being freed, it will also do so for all local atoms.
36locals: std.ArrayListUnmanaged(Atom) = .{},
37
3438/// Represents a default empty wasm `Atom`
3539pub const empty: Atom = .{
3640 .alignment = 0,
......@@ -45,6 +49,11 @@ pub const empty: Atom = .{
4549pub fn deinit(self: *Atom, gpa: Allocator) void {
4650 self.relocs.deinit(gpa);
4751 self.code.deinit(gpa);
52
53 while (self.locals.popOrNull()) |*local| {
54 local.deinit(gpa);
55 }
56 self.locals.deinit(gpa);
4857}
4958
5059/// Sets the length of relocations and code to '0',
......@@ -72,6 +81,15 @@ pub fn getFirst(self: *Atom) *Atom {
7281 return tmp;
7382}
7483
84/// Returns the atom for the given `symbol_index`.
85/// This can be either the `Atom` itself, or one of its locals.
86pub fn symbolAtom(self: *Atom, symbol_index: u32) *Atom {
87 if (self.sym_index == symbol_index) return self;
88 return for (self.locals.items) |*local_atom| {
89 if (local_atom.sym_index == symbol_index) break local_atom;
90 } else unreachable; // Used a symbol index not present in this atom or its children.
91}
92
7593/// Resolves the relocations within the atom, writing the new value
7694/// at the calculated offset.
7795pub fn resolveRelocs(self: *Atom, wasm_bin: *const Wasm) !void {