authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2021-12-01 11:31:47+01:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2021-12-04 19:22:08+01:00
log96a4692f94e202f80ca89a7fb237eb99b6352260
tree950652e425ae262b78b1ff9dced6707ba661bbba
parent1777fb25bc37c626fee91e88feeafa28f177628a
signaturelock-open Commit is signed but in an unrecognized format.

wasm: Correctly load slice value on stack


2 files changed, 62 insertions(+), 44 deletions(-)

src/arch/wasm/CodeGen.zig+60-43
......@@ -6,6 +6,7 @@ const testing = std.testing;
66const leb = std.leb;
77const mem = std.mem;
88const wasm = std.wasm;
9const log = std.log.scoped(.codegen);
910
1011const Module = @import("../../Module.zig");
1112const Decl = Module.Decl;
......@@ -562,8 +563,6 @@ const InnerError = error{
562563 CodegenFail,
563564 /// Can occur when dereferencing a pointer that points to a `Decl` of which the analysis has failed
564565 AnalysisFail,
565 /// Failed to emit MIR instructions to binary/textual representation.
566 EmitFail,
567566 /// Compiler implementation could not handle a large integer.
568567 Overflow,
569568};
......@@ -800,7 +799,7 @@ pub fn genFunc(self: *Self) InnerError!Result {
800799 emit.emitMir() catch |err| switch (err) {
801800 error.EmitFail => {
802801 self.err_msg = emit.error_msg.?;
803 return error.EmitFail;
802 return error.CodegenFail;
804803 },
805804 else => |e| return e,
806805 };
......@@ -809,8 +808,34 @@ pub fn genFunc(self: *Self) InnerError!Result {
809808 return Result.appended;
810809}
811810
811pub fn genDecl(self: *Self) InnerError!Result {
812 const decl = self.decl;
813 assert(decl.has_tv);
814
815 log.debug("gen: {s} type: {}, value: {}", .{ decl.name, decl.ty, decl.val });
816
817 if (decl.val.castTag(.function)) |func_payload| {
818 _ = func_payload;
819 return self.fail("TODO wasm backend genDecl function pointer", .{});
820 } else if (decl.val.castTag(.extern_fn)) |extern_fn| {
821 const ext_decl = extern_fn.data;
822 var func_type = try self.genFunctype(ext_decl.ty);
823 func_type.deinit(self.gpa);
824 ext_decl.fn_link.wasm.type_index = try self.bin_file.putOrGetFuncType(func_type);
825 return Result.appended;
826 } else {
827 const init_val = if (decl.val.castTag(.variable)) |payload| init_val: {
828 break :init_val payload.data.init;
829 } else decl.val;
830 if (init_val.tag() != .unreachable_value) {
831 return try self.genTypedValue(decl.ty, init_val);
832 }
833 return Result.appended;
834 }
835}
836
812837/// Generates the wasm bytecode for the declaration belonging to `Context`
813pub fn genDecl(self: *Self, ty: Type, val: Value) InnerError!Result {
838fn genTypedValue(self: *Self, ty: Type, val: Value) InnerError!Result {
814839 if (val.isUndef()) {
815840 try self.code.appendNTimes(0xaa, @intCast(usize, ty.abiSize(self.target)));
816841 return Result.appended;
......@@ -822,16 +847,16 @@ pub fn genDecl(self: *Self, ty: Type, val: Value) InnerError!Result {
822847 .function => val.castTag(.function).?.data.owner_decl,
823848 else => unreachable,
824849 };
825 return try self.lowerDeclRef(fn_decl);
850 return try self.lowerDeclRef(ty, val, fn_decl);
826851 },
827852 .Optional => {
828853 var opt_buf: Type.Payload.ElemType = undefined;
829854 const payload_type = ty.optionalChild(&opt_buf);
830855 if (ty.isPtrLikeOptional()) {
831856 if (val.castTag(.opt_payload)) |payload| {
832 return try self.genDecl(payload_type, payload.data);
857 return try self.genTypedValue(payload_type, payload.data);
833858 } else if (!val.isNull()) {
834 return try self.genDecl(payload_type, val);
859 return try self.genTypedValue(payload_type, val);
835860 } else {
836861 try self.code.appendNTimes(0, @intCast(usize, ty.abiSize(self.target)));
837862 return Result.appended;
......@@ -839,7 +864,7 @@ pub fn genDecl(self: *Self, ty: Type, val: Value) InnerError!Result {
839864 }
840865 // `null-tag` byte
841866 try self.code.appendNTimes(@boolToInt(!val.isNull()), 4);
842 const pl_result = try self.genDecl(
867 const pl_result = try self.genTypedValue(
843868 payload_type,
844869 if (val.castTag(.opt_payload)) |pl| pl.data else Value.initTag(.undef),
845870 );
......@@ -855,7 +880,7 @@ pub fn genDecl(self: *Self, ty: Type, val: Value) InnerError!Result {
855880 if (ty.sentinel()) |sentinel| {
856881 try self.code.appendSlice(payload.data);
857882
858 switch (try self.genDecl(ty.childType(), sentinel)) {
883 switch (try self.genTypedValue(ty.childType(), sentinel)) {
859884 .appended => return Result.appended,
860885 .externally_managed => |data| {
861886 try self.code.appendSlice(data);
......@@ -869,22 +894,20 @@ pub fn genDecl(self: *Self, ty: Type, val: Value) InnerError!Result {
869894 const elem_vals = val.castTag(.array).?.data;
870895 const elem_ty = ty.elemType();
871896 for (elem_vals) |elem_val| {
872 switch (try self.genDecl(elem_ty, elem_val)) {
897 switch (try self.genTypedValue(elem_ty, elem_val)) {
873898 .appended => {},
874 .externally_managed => |data| {
875 try self.code.appendSlice(data);
876 },
899 .externally_managed => |data| try self.code.appendSlice(data),
877900 }
878901 }
879902 return Result.appended;
880903 },
881 else => return self.fail("TODO implement genDecl for array type value: {s}", .{@tagName(val.tag())}),
904 else => return self.fail("TODO implement genTypedValue for array type value: {s}", .{@tagName(val.tag())}),
882905 },
883906 .Int => {
884907 const info = ty.intInfo(self.target);
885908 const abi_size = @intCast(usize, ty.abiSize(self.target));
886909 // todo: Implement integer sizes larger than 64bits
887 if (info.bits > 64) return self.fail("TODO: Implement genDecl for integer bit size: {d}", .{info.bits});
910 if (info.bits > 64) return self.fail("TODO: Implement genTypedValue for integer bit size: {d}", .{info.bits});
888911 var buf: [8]u8 = undefined;
889912 if (info.signedness == .unsigned) {
890913 std.mem.writeIntLittle(u64, &buf, val.toUnsignedInt());
......@@ -906,8 +929,7 @@ pub fn genDecl(self: *Self, ty: Type, val: Value) InnerError!Result {
906929 for (field_vals) |field_val, index| {
907930 const field_ty = ty.structFieldType(index);
908931 if (!field_ty.hasCodeGenBits()) continue;
909
910 switch (try self.genDecl(field_ty, field_val)) {
932 switch (try self.genTypedValue(field_ty, field_val)) {
911933 .appended => {},
912934 .externally_managed => |payload| try self.code.appendSlice(payload),
913935 }
......@@ -923,21 +945,21 @@ pub fn genDecl(self: *Self, ty: Type, val: Value) InnerError!Result {
923945 .Pointer => switch (val.tag()) {
924946 .variable => {
925947 const decl = val.castTag(.variable).?.data.owner_decl;
926 return try self.lowerDeclRef(decl);
948 return try self.lowerDeclRef(ty, val, decl);
927949 },
928950 .decl_ref => {
929951 const decl = val.castTag(.decl_ref).?.data;
930 return try self.lowerDeclRef(decl);
952 return try self.lowerDeclRef(ty, val, decl);
931953 },
932954 .slice => {
933955 const slice = val.castTag(.slice).?.data;
934956 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
935957 const ptr_ty = ty.slicePtrFieldType(&buf);
936 switch (try self.genDecl(ptr_ty, slice.ptr)) {
958 switch (try self.genTypedValue(ptr_ty, slice.ptr)) {
937959 .externally_managed => |data| try self.code.appendSlice(data),
938960 .appended => {},
939961 }
940 switch (try self.genDecl(Type.usize, slice.len)) {
962 switch (try self.genTypedValue(Type.usize, slice.len)) {
941963 .externally_managed => |data| try self.code.appendSlice(data),
942964 .appended => {},
943965 }
......@@ -949,13 +971,25 @@ pub fn genDecl(self: *Self, ty: Type, val: Value) InnerError!Result {
949971 }
950972}
951973
952fn lowerDeclRef(self: *Self, decl: *Module.Decl) InnerError!Result {
953 decl.alive = true;
974fn lowerDeclRef(self: *Self, ty: Type, val: Value, decl: *Module.Decl) InnerError!Result {
975 if (ty.isSlice()) {
976 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
977 const slice_ty = ty.slicePtrFieldType(&buf);
978 switch (try self.genTypedValue(slice_ty, val)) {
979 .appended => {},
980 .externally_managed => |payload| try self.code.appendSlice(payload),
981 }
982 var slice_len: Value.Payload.U64 = .{
983 .base = .{ .tag = .int_u64 },
984 .data = val.sliceLen(),
985 };
986 return try self.genTypedValue(Type.usize, Value.initPayload(&slice_len.base));
987 }
954988
955989 const offset = @intCast(u32, self.code.items.len);
956990 const atom = &self.decl.link.wasm;
957991 const target_sym_index = decl.link.wasm.sym_index;
958
992 decl.alive = true;
959993 if (decl.ty.zigTypeTag() == .Fn) {
960994 // We found a function pointer, so add it to our table,
961995 // as function pointers are not allowed to be stored inside the data section,
......@@ -2225,7 +2259,8 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
22252259 const elem_size = elem_ty.abiSize(self.target);
22262260
22272261 // load pointer onto stack
2228 try self.emitWValue(slice);
2262 const slice_ptr = try self.load(slice, slice_ty, 0);
2263 try self.addLabel(.local_get, slice_ptr.local);
22292264
22302265 // calculate index into slice
22312266 try self.emitWValue(index);
......@@ -2233,24 +2268,6 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
22332268 try self.addTag(.i32_mul);
22342269 try self.addTag(.i32_add);
22352270
2236 const abi_size = if (elem_size < 8)
2237 @intCast(u8, elem_size)
2238 else
2239 @as(u8, 4); // elements larger than 8 bytes will be passed by pointer
2240
2241 const extra_index = try self.addExtra(Mir.MemArg{
2242 .offset = 0,
2243 .alignment = elem_ty.abiAlignment(self.target),
2244 });
2245 const signedness: std.builtin.Signedness = if (elem_ty.isUnsignedInt()) .unsigned else .signed;
2246 const opcode = buildOpcode(.{
2247 .valtype1 = try self.typeToValtype(elem_ty),
2248 .width = abi_size * 8,
2249 .op = .load,
2250 .signedness = signedness,
2251 });
2252 try self.addInst(.{ .tag = Mir.Inst.Tag.fromOpcode(opcode), .data = .{ .payload = extra_index } });
2253
22542271 const result = try self.allocLocal(elem_ty);
22552272 try self.addLabel(.local_set, result.local);
22562273 return result;
src/link/Wasm.zig+2-1
......@@ -277,7 +277,7 @@ pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void {
277277 defer codegen.deinit();
278278
279279 // generate the 'code' section for the function declaration
280 const result = codegen.genDecl(decl.ty, decl.val) catch |err| switch (err) {
280 const result = codegen.genDecl() catch |err| switch (err) {
281281 error.CodegenFail => {
282282 decl.analysis = .codegen_failure;
283283 try module.failed_decls.put(module.gpa, decl, codegen.err_msg);
......@@ -297,6 +297,7 @@ fn finishUpdateDecl(self: *Wasm, decl: *Module.Decl, result: CodeGen.Result, cod
297297
298298 if (decl.isExtern()) {
299299 try self.addOrUpdateImport(decl);
300 return;
300301 }
301302
302303 if (code.len == 0) return;