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;...@@ -6,6 +6,7 @@ const testing = std.testing;
6const leb = std.leb;6const leb = std.leb;
7const mem = std.mem;7const mem = std.mem;
8const wasm = std.wasm;8const wasm = std.wasm;
9const log = std.log.scoped(.codegen);
910
10const Module = @import("../../Module.zig");11const Module = @import("../../Module.zig");
11const Decl = Module.Decl;12const Decl = Module.Decl;
...@@ -562,8 +563,6 @@ const InnerError = error{...@@ -562,8 +563,6 @@ const InnerError = error{
562 CodegenFail,563 CodegenFail,
563 /// Can occur when dereferencing a pointer that points to a `Decl` of which the analysis has failed564 /// Can occur when dereferencing a pointer that points to a `Decl` of which the analysis has failed
564 AnalysisFail,565 AnalysisFail,
565 /// Failed to emit MIR instructions to binary/textual representation.
566 EmitFail,
567 /// Compiler implementation could not handle a large integer.566 /// Compiler implementation could not handle a large integer.
568 Overflow,567 Overflow,
569};568};
...@@ -800,7 +799,7 @@ pub fn genFunc(self: *Self) InnerError!Result {...@@ -800,7 +799,7 @@ pub fn genFunc(self: *Self) InnerError!Result {
800 emit.emitMir() catch |err| switch (err) {799 emit.emitMir() catch |err| switch (err) {
801 error.EmitFail => {800 error.EmitFail => {
802 self.err_msg = emit.error_msg.?;801 self.err_msg = emit.error_msg.?;
803 return error.EmitFail;802 return error.CodegenFail;
804 },803 },
805 else => |e| return e,804 else => |e| return e,
806 };805 };
...@@ -809,8 +808,34 @@ pub fn genFunc(self: *Self) InnerError!Result {...@@ -809,8 +808,34 @@ pub fn genFunc(self: *Self) InnerError!Result {
809 return Result.appended;808 return Result.appended;
810}809}
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
812/// Generates the wasm bytecode for the declaration belonging to `Context`837/// 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 {
814 if (val.isUndef()) {839 if (val.isUndef()) {
815 try self.code.appendNTimes(0xaa, @intCast(usize, ty.abiSize(self.target)));840 try self.code.appendNTimes(0xaa, @intCast(usize, ty.abiSize(self.target)));
816 return Result.appended;841 return Result.appended;
...@@ -822,16 +847,16 @@ pub fn genDecl(self: *Self, ty: Type, val: Value) InnerError!Result {...@@ -822,16 +847,16 @@ pub fn genDecl(self: *Self, ty: Type, val: Value) InnerError!Result {
822 .function => val.castTag(.function).?.data.owner_decl,847 .function => val.castTag(.function).?.data.owner_decl,
823 else => unreachable,848 else => unreachable,
824 };849 };
825 return try self.lowerDeclRef(fn_decl);850 return try self.lowerDeclRef(ty, val, fn_decl);
826 },851 },
827 .Optional => {852 .Optional => {
828 var opt_buf: Type.Payload.ElemType = undefined;853 var opt_buf: Type.Payload.ElemType = undefined;
829 const payload_type = ty.optionalChild(&opt_buf);854 const payload_type = ty.optionalChild(&opt_buf);
830 if (ty.isPtrLikeOptional()) {855 if (ty.isPtrLikeOptional()) {
831 if (val.castTag(.opt_payload)) |payload| {856 if (val.castTag(.opt_payload)) |payload| {
832 return try self.genDecl(payload_type, payload.data);857 return try self.genTypedValue(payload_type, payload.data);
833 } else if (!val.isNull()) {858 } else if (!val.isNull()) {
834 return try self.genDecl(payload_type, val);859 return try self.genTypedValue(payload_type, val);
835 } else {860 } else {
836 try self.code.appendNTimes(0, @intCast(usize, ty.abiSize(self.target)));861 try self.code.appendNTimes(0, @intCast(usize, ty.abiSize(self.target)));
837 return Result.appended;862 return Result.appended;
...@@ -839,7 +864,7 @@ pub fn genDecl(self: *Self, ty: Type, val: Value) InnerError!Result {...@@ -839,7 +864,7 @@ pub fn genDecl(self: *Self, ty: Type, val: Value) InnerError!Result {
839 }864 }
840 // `null-tag` byte865 // `null-tag` byte
841 try self.code.appendNTimes(@boolToInt(!val.isNull()), 4);866 try self.code.appendNTimes(@boolToInt(!val.isNull()), 4);
842 const pl_result = try self.genDecl(867 const pl_result = try self.genTypedValue(
843 payload_type,868 payload_type,
844 if (val.castTag(.opt_payload)) |pl| pl.data else Value.initTag(.undef),869 if (val.castTag(.opt_payload)) |pl| pl.data else Value.initTag(.undef),
845 );870 );
...@@ -855,7 +880,7 @@ pub fn genDecl(self: *Self, ty: Type, val: Value) InnerError!Result {...@@ -855,7 +880,7 @@ pub fn genDecl(self: *Self, ty: Type, val: Value) InnerError!Result {
855 if (ty.sentinel()) |sentinel| {880 if (ty.sentinel()) |sentinel| {
856 try self.code.appendSlice(payload.data);881 try self.code.appendSlice(payload.data);
857882
858 switch (try self.genDecl(ty.childType(), sentinel)) {883 switch (try self.genTypedValue(ty.childType(), sentinel)) {
859 .appended => return Result.appended,884 .appended => return Result.appended,
860 .externally_managed => |data| {885 .externally_managed => |data| {
861 try self.code.appendSlice(data);886 try self.code.appendSlice(data);
...@@ -869,22 +894,20 @@ pub fn genDecl(self: *Self, ty: Type, val: Value) InnerError!Result {...@@ -869,22 +894,20 @@ pub fn genDecl(self: *Self, ty: Type, val: Value) InnerError!Result {
869 const elem_vals = val.castTag(.array).?.data;894 const elem_vals = val.castTag(.array).?.data;
870 const elem_ty = ty.elemType();895 const elem_ty = ty.elemType();
871 for (elem_vals) |elem_val| {896 for (elem_vals) |elem_val| {
872 switch (try self.genDecl(elem_ty, elem_val)) {897 switch (try self.genTypedValue(elem_ty, elem_val)) {
873 .appended => {},898 .appended => {},
874 .externally_managed => |data| {899 .externally_managed => |data| try self.code.appendSlice(data),
875 try self.code.appendSlice(data);
876 },
877 }900 }
878 }901 }
879 return Result.appended;902 return Result.appended;
880 },903 },
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())}),
882 },905 },
883 .Int => {906 .Int => {
884 const info = ty.intInfo(self.target);907 const info = ty.intInfo(self.target);
885 const abi_size = @intCast(usize, ty.abiSize(self.target));908 const abi_size = @intCast(usize, ty.abiSize(self.target));
886 // todo: Implement integer sizes larger than 64bits909 // 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});
888 var buf: [8]u8 = undefined;911 var buf: [8]u8 = undefined;
889 if (info.signedness == .unsigned) {912 if (info.signedness == .unsigned) {
890 std.mem.writeIntLittle(u64, &buf, val.toUnsignedInt());913 std.mem.writeIntLittle(u64, &buf, val.toUnsignedInt());
...@@ -906,8 +929,7 @@ pub fn genDecl(self: *Self, ty: Type, val: Value) InnerError!Result {...@@ -906,8 +929,7 @@ pub fn genDecl(self: *Self, ty: Type, val: Value) InnerError!Result {
906 for (field_vals) |field_val, index| {929 for (field_vals) |field_val, index| {
907 const field_ty = ty.structFieldType(index);930 const field_ty = ty.structFieldType(index);
908 if (!field_ty.hasCodeGenBits()) continue;931 if (!field_ty.hasCodeGenBits()) continue;
909932 switch (try self.genTypedValue(field_ty, field_val)) {
910 switch (try self.genDecl(field_ty, field_val)) {
911 .appended => {},933 .appended => {},
912 .externally_managed => |payload| try self.code.appendSlice(payload),934 .externally_managed => |payload| try self.code.appendSlice(payload),
913 }935 }
...@@ -923,21 +945,21 @@ pub fn genDecl(self: *Self, ty: Type, val: Value) InnerError!Result {...@@ -923,21 +945,21 @@ pub fn genDecl(self: *Self, ty: Type, val: Value) InnerError!Result {
923 .Pointer => switch (val.tag()) {945 .Pointer => switch (val.tag()) {
924 .variable => {946 .variable => {
925 const decl = val.castTag(.variable).?.data.owner_decl;947 const decl = val.castTag(.variable).?.data.owner_decl;
926 return try self.lowerDeclRef(decl);948 return try self.lowerDeclRef(ty, val, decl);
927 },949 },
928 .decl_ref => {950 .decl_ref => {
929 const decl = val.castTag(.decl_ref).?.data;951 const decl = val.castTag(.decl_ref).?.data;
930 return try self.lowerDeclRef(decl);952 return try self.lowerDeclRef(ty, val, decl);
931 },953 },
932 .slice => {954 .slice => {
933 const slice = val.castTag(.slice).?.data;955 const slice = val.castTag(.slice).?.data;
934 var buf: Type.SlicePtrFieldTypeBuffer = undefined;956 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
935 const ptr_ty = ty.slicePtrFieldType(&buf);957 const ptr_ty = ty.slicePtrFieldType(&buf);
936 switch (try self.genDecl(ptr_ty, slice.ptr)) {958 switch (try self.genTypedValue(ptr_ty, slice.ptr)) {
937 .externally_managed => |data| try self.code.appendSlice(data),959 .externally_managed => |data| try self.code.appendSlice(data),
938 .appended => {},960 .appended => {},
939 }961 }
940 switch (try self.genDecl(Type.usize, slice.len)) {962 switch (try self.genTypedValue(Type.usize, slice.len)) {
941 .externally_managed => |data| try self.code.appendSlice(data),963 .externally_managed => |data| try self.code.appendSlice(data),
942 .appended => {},964 .appended => {},
943 }965 }
...@@ -949,13 +971,25 @@ pub fn genDecl(self: *Self, ty: Type, val: Value) InnerError!Result {...@@ -949,13 +971,25 @@ pub fn genDecl(self: *Self, ty: Type, val: Value) InnerError!Result {
949 }971 }
950}972}
951973
952fn lowerDeclRef(self: *Self, decl: *Module.Decl) InnerError!Result {974fn lowerDeclRef(self: *Self, ty: Type, val: Value, decl: *Module.Decl) InnerError!Result {
953 decl.alive = true;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
955 const offset = @intCast(u32, self.code.items.len);989 const offset = @intCast(u32, self.code.items.len);
956 const atom = &self.decl.link.wasm;990 const atom = &self.decl.link.wasm;
957 const target_sym_index = decl.link.wasm.sym_index;991 const target_sym_index = decl.link.wasm.sym_index;
958992 decl.alive = true;
959 if (decl.ty.zigTypeTag() == .Fn) {993 if (decl.ty.zigTypeTag() == .Fn) {
960 // We found a function pointer, so add it to our table,994 // We found a function pointer, so add it to our table,
961 // as function pointers are not allowed to be stored inside the data section,995 // 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 {...@@ -2225,7 +2259,8 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2225 const elem_size = elem_ty.abiSize(self.target);2259 const elem_size = elem_ty.abiSize(self.target);
22262260
2227 // load pointer onto stack2261 // 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
2230 // calculate index into slice2265 // calculate index into slice
2231 try self.emitWValue(index);2266 try self.emitWValue(index);
...@@ -2233,24 +2268,6 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2233,24 +2268,6 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2233 try self.addTag(.i32_mul);2268 try self.addTag(.i32_mul);
2234 try self.addTag(.i32_add);2269 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
2254 const result = try self.allocLocal(elem_ty);2271 const result = try self.allocLocal(elem_ty);
2255 try self.addLabel(.local_set, result.local);2272 try self.addLabel(.local_set, result.local);
2256 return result;2273 return result;
src/link/Wasm.zig+2-1
...@@ -277,7 +277,7 @@ pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void {...@@ -277,7 +277,7 @@ pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void {
277 defer codegen.deinit();277 defer codegen.deinit();
278278
279 // generate the 'code' section for the function declaration279 // 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) {
281 error.CodegenFail => {281 error.CodegenFail => {
282 decl.analysis = .codegen_failure;282 decl.analysis = .codegen_failure;
283 try module.failed_decls.put(module.gpa, decl, codegen.err_msg);283 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...@@ -297,6 +297,7 @@ fn finishUpdateDecl(self: *Wasm, decl: *Module.Decl, result: CodeGen.Result, cod
297297
298 if (decl.isExtern()) {298 if (decl.isExtern()) {
299 try self.addOrUpdateImport(decl);299 try self.addOrUpdateImport(decl);
300 return;
300 }301 }
301302
302 if (code.len == 0) return;303 if (code.len == 0) return;