| ... | @@ -6,6 +6,7 @@ const testing = std.testing; | ... | @@ -6,6 +6,7 @@ const testing = std.testing; |
| 6 | const leb = std.leb; | 6 | const leb = std.leb; |
| 7 | const mem = std.mem; | 7 | const mem = std.mem; |
| 8 | const wasm = std.wasm; | 8 | const wasm = std.wasm; |
| | 9 | const log = std.log.scoped(.codegen); |
| 9 | | 10 | |
| 10 | const Module = @import("../../Module.zig"); | 11 | const Module = @import("../../Module.zig"); |
| 11 | const Decl = Module.Decl; | 12 | const 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 failed | 564 | /// 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 | } |
| 811 | | 810 | |
| | 811 | pub 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` |
| 813 | pub fn genDecl(self: *Self, ty: Type, val: Value) InnerError!Result { | 838 | fn 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` byte | 865 | // `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); |
| 857 | | 882 | |
| 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 64bits | 909 | // 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; |
| 909 | | 932 | 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 | } |
| 951 | | 973 | |
| 952 | fn lowerDeclRef(self: *Self, decl: *Module.Decl) InnerError!Result { | 974 | fn 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 | } |
| 954 | | 988 | |
| 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; |
| 958 | | 992 | 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); |
| 2226 | | 2260 | |
| 2227 | // load pointer onto stack | 2261 | // 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); |
| 2229 | | 2264 | |
| 2230 | // calculate index into slice | 2265 | // 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); |
| 2235 | | 2270 | |
| 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; |