authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2021-07-16 14:48:51+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-07-20 12:19:16-07:00
log424f260f850cb22637888bbfdf5bfaf9c08a4dae
tree627d18c4ab1a7905cfa041028a8fdb4d680b651b
parent8082660118bba78de00e1e103e53730a87b2b70f

Fix wasm-related compile errors:

- Update `fail()` to not require a `srcLoc`. This brings it in line with other backends, and we were always passing 'node_offset = 0', anyway. - Fix unused local due to change of architecture wrt function/decl generation. - Replace all old instructions to indexes within the function signatures.

2 files changed, 118 insertions(+), 120 deletions(-)

src/codegen/wasm.zig+108-113
...@@ -25,7 +25,7 @@ const WValue = union(enum) {...@@ -25,7 +25,7 @@ const WValue = union(enum) {
25 /// Index of the local variable25 /// Index of the local variable
26 local: u32,26 local: u32,
27 /// Instruction holding a constant `Value`27 /// Instruction holding a constant `Value`
28 constant: *Inst,28 constant: Air.Inst.Index,
29 /// Offset position in the list of bytecode instructions29 /// Offset position in the list of bytecode instructions
30 code_offset: usize,30 code_offset: usize,
31 /// Used for variables that create multiple locals on the stack when allocated31 /// Used for variables that create multiple locals on the stack when allocated
...@@ -484,7 +484,7 @@ pub const Result = union(enum) {...@@ -484,7 +484,7 @@ pub const Result = union(enum) {
484};484};
485485
486/// Hashmap to store generated `WValue` for each `Inst`486/// Hashmap to store generated `WValue` for each `Inst`
487pub const ValueTable = std.AutoHashMapUnmanaged(*Inst, WValue);487pub const ValueTable = std.AutoHashMapUnmanaged(Air.Inst.Index, WValue);
488488
489/// Code represents the `Code` section of wasm that489/// Code represents the `Code` section of wasm that
490/// belongs to a function490/// belongs to a function
...@@ -497,8 +497,8 @@ pub const Context = struct {...@@ -497,8 +497,8 @@ pub const Context = struct {
497 gpa: *mem.Allocator,497 gpa: *mem.Allocator,
498 /// Table to save `WValue`'s generated by an `Inst`498 /// Table to save `WValue`'s generated by an `Inst`
499 values: ValueTable,499 values: ValueTable,
500 /// Mapping from *Inst.Block to block ids500 /// Mapping from Air.Inst.Index to block ids
501 blocks: std.AutoArrayHashMapUnmanaged(*Inst.Block, u32) = .{},501 blocks: std.AutoArrayHashMapUnmanaged(Air.Inst.Index, u32) = .{},
502 /// `bytes` contains the wasm bytecode belonging to the 'code' section.502 /// `bytes` contains the wasm bytecode belonging to the 'code' section.
503 code: ArrayList(u8),503 code: ArrayList(u8),
504 /// Contains the generated function type bytecode for the current function504 /// Contains the generated function type bytecode for the current function
...@@ -538,7 +538,8 @@ pub const Context = struct {...@@ -538,7 +538,8 @@ pub const Context = struct {
538 }538 }
539539
540 /// Sets `err_msg` on `Context` and returns `error.CodegemFail` which is caught in link/Wasm.zig540 /// Sets `err_msg` on `Context` and returns `error.CodegemFail` which is caught in link/Wasm.zig
541 fn fail(self: *Context, src: LazySrcLoc, comptime fmt: []const u8, args: anytype) InnerError {541 fn fail(self: *Context, comptime fmt: []const u8, args: anytype) InnerError {
542 const src: LazySrcLoc = .{ .node_offset = 0 };
542 const src_loc = src.toSrcLocWithDecl(self.decl);543 const src_loc = src.toSrcLocWithDecl(self.decl);
543 self.err_msg = try Module.ErrorMsg.create(self.gpa, src_loc, fmt, args);544 self.err_msg = try Module.ErrorMsg.create(self.gpa, src_loc, fmt, args);
544 return error.CodegenFail;545 return error.CodegenFail;
...@@ -546,7 +547,7 @@ pub const Context = struct {...@@ -546,7 +547,7 @@ pub const Context = struct {
546547
547 /// Resolves the `WValue` for the given instruction `inst`548 /// Resolves the `WValue` for the given instruction `inst`
548 /// When the given instruction has a `Value`, it returns a constant instead549 /// When the given instruction has a `Value`, it returns a constant instead
549 fn resolveInst(self: Context, inst: *Inst) WValue {550 fn resolveInst(self: Context, inst: Air.Inst) Index {
550 if (!inst.ty.hasCodeGenBits()) return .none;551 if (!inst.ty.hasCodeGenBits()) return .none;
551552
552 if (inst.value()) |_| {553 if (inst.value()) |_| {
...@@ -557,48 +558,45 @@ pub const Context = struct {...@@ -557,48 +558,45 @@ pub const Context = struct {
557 }558 }
558559
559 /// Using a given `Type`, returns the corresponding wasm Valtype560 /// Using a given `Type`, returns the corresponding wasm Valtype
560 fn typeToValtype(self: *Context, src: LazySrcLoc, ty: Type) InnerError!wasm.Valtype {561 fn typeToValtype(self: *Context, ty: Type) InnerError!wasm.Valtype {
561 return switch (ty.zigTypeTag()) {562 return switch (ty.zigTypeTag()) {
562 .Float => blk: {563 .Float => blk: {
563 const bits = ty.floatBits(self.target);564 const bits = ty.floatBits(self.target);
564 if (bits == 16 or bits == 32) break :blk wasm.Valtype.f32;565 if (bits == 16 or bits == 32) break :blk wasm.Valtype.f32;
565 if (bits == 64) break :blk wasm.Valtype.f64;566 if (bits == 64) break :blk wasm.Valtype.f64;
566 return self.fail(src, "Float bit size not supported by wasm: '{d}'", .{bits});567 return self.fail("Float bit size not supported by wasm: '{d}'", .{bits});
567 },568 },
568 .Int => blk: {569 .Int => blk: {
569 const info = ty.intInfo(self.target);570 const info = ty.intInfo(self.target);
570 if (info.bits <= 32) break :blk wasm.Valtype.i32;571 if (info.bits <= 32) break :blk wasm.Valtype.i32;
571 if (info.bits > 32 and info.bits <= 64) break :blk wasm.Valtype.i64;572 if (info.bits > 32 and info.bits <= 64) break :blk wasm.Valtype.i64;
572 return self.fail(src, "Integer bit size not supported by wasm: '{d}'", .{info.bits});573 return self.fail("Integer bit size not supported by wasm: '{d}'", .{info.bits});
573 },574 },
574 .Enum => switch (ty.tag()) {575 .Enum => switch (ty.tag()) {
575 .enum_simple => wasm.Valtype.i32,576 .enum_simple => wasm.Valtype.i32,
576 else => self.typeToValtype(577 else => self.typeToValtype(ty.cast(Type.Payload.EnumFull).?.data.tag_ty),
577 src,
578 ty.cast(Type.Payload.EnumFull).?.data.tag_ty,
579 ),
580 },578 },
581 .Bool,579 .Bool,
582 .Pointer,580 .Pointer,
583 .ErrorSet,581 .ErrorSet,
584 => wasm.Valtype.i32,582 => wasm.Valtype.i32,
585 .Struct, .ErrorUnion => unreachable, // Multi typed, must be handled individually.583 .Struct, .ErrorUnion => unreachable, // Multi typed, must be handled individually.
586 else => self.fail(src, "TODO - Wasm valtype for type '{s}'", .{ty.zigTypeTag()}),584 else => self.fail("TODO - Wasm valtype for type '{s}'", .{ty.zigTypeTag()}),
587 };585 };
588 }586 }
589587
590 /// Using a given `Type`, returns the byte representation of its wasm value type588 /// Using a given `Type`, returns the byte representation of its wasm value type
591 fn genValtype(self: *Context, src: LazySrcLoc, ty: Type) InnerError!u8 {589 fn genValtype(self: *Context, ty: Type) InnerError!u8 {
592 return wasm.valtype(try self.typeToValtype(src, ty));590 return wasm.valtype(try self.typeToValtype(ty));
593 }591 }
594592
595 /// Using a given `Type`, returns the corresponding wasm value type593 /// Using a given `Type`, returns the corresponding wasm value type
596 /// Differently from `genValtype` this also allows `void` to create a block594 /// Differently from `genValtype` this also allows `void` to create a block
597 /// with no return type595 /// with no return type
598 fn genBlockType(self: *Context, src: LazySrcLoc, ty: Type) InnerError!u8 {596 fn genBlockType(self: *Context, ty: Type) InnerError!u8 {
599 return switch (ty.tag()) {597 return switch (ty.tag()) {
600 .void, .noreturn => wasm.block_empty,598 .void, .noreturn => wasm.block_empty,
601 else => self.genValtype(src, ty),599 else => self.genValtype(ty),
602 };600 };
603 }601 }
604602
...@@ -612,7 +610,7 @@ pub const Context = struct {...@@ -612,7 +610,7 @@ pub const Context = struct {
612 try writer.writeByte(wasm.opcode(.local_get));610 try writer.writeByte(wasm.opcode(.local_get));
613 try leb.writeULEB128(writer, idx);611 try leb.writeULEB128(writer, idx);
614 },612 },
615 .constant => |inst| try self.emitConstant(inst.src, inst.value().?, inst.ty), // creates a new constant onto the stack613 .constant => |inst| try self.emitConstant(inst.value().?, inst.ty), // creates a new constant onto the stack
616 }614 }
617 }615 }
618616
...@@ -682,7 +680,7 @@ pub const Context = struct {...@@ -682,7 +680,7 @@ pub const Context = struct {
682 ty.fnParamTypes(params);680 ty.fnParamTypes(params);
683 for (params) |param_type| {681 for (params) |param_type| {
684 // Can we maybe get the source index of each param?682 // Can we maybe get the source index of each param?
685 const val_type = try self.genValtype(.{ .node_offset = 0 }, param_type);683 const val_type = try self.genValtype(param_type);
686 try writer.writeByte(val_type);684 try writer.writeByte(val_type);
687 }685 }
688 }686 }
...@@ -691,13 +689,10 @@ pub const Context = struct {...@@ -691,13 +689,10 @@ pub const Context = struct {
691 const return_type = ty.fnReturnType();689 const return_type = ty.fnReturnType();
692 switch (return_type.zigTypeTag()) {690 switch (return_type.zigTypeTag()) {
693 .Void, .NoReturn => try leb.writeULEB128(writer, @as(u32, 0)),691 .Void, .NoReturn => try leb.writeULEB128(writer, @as(u32, 0)),
694 .Struct => return self.fail(.{ .node_offset = 0 }, "TODO: Implement struct as return type for wasm", .{}),692 .Struct => return self.fail("TODO: Implement struct as return type for wasm", .{}),
695 .Optional => return self.fail(.{ .node_offset = 0 }, "TODO: Implement optionals as return type for wasm", .{}),693 .Optional => return self.fail("TODO: Implement optionals as return type for wasm", .{}),
696 .ErrorUnion => {694 .ErrorUnion => {
697 const val_type = try self.genValtype(695 const val_type = try self.genValtype(return_type.errorUnionChild());
698 .{ .node_offset = 0 },
699 return_type.errorUnionChild(),
700 );
701696
702 // write down the amount of return values697 // write down the amount of return values
703 try leb.writeULEB128(writer, @as(u32, 2));698 try leb.writeULEB128(writer, @as(u32, 2));
...@@ -707,22 +702,21 @@ pub const Context = struct {...@@ -707,22 +702,21 @@ pub const Context = struct {
707 else => {702 else => {
708 try leb.writeULEB128(writer, @as(u32, 1));703 try leb.writeULEB128(writer, @as(u32, 1));
709 // Can we maybe get the source index of the return type?704 // Can we maybe get the source index of the return type?
710 const val_type = try self.genValtype(.{ .node_offset = 0 }, return_type);705 const val_type = try self.genValtype(return_type);
711 try writer.writeByte(val_type);706 try writer.writeByte(val_type);
712 },707 },
713 }708 }
714 }709 }
715710
716 pub fn genFunc(self: *Context, func: *Module.Fn) InnerError!Result {711 pub fn genFunc(self: *Context, func: *Module.Fn) InnerError!Result {
712 _ = func;
717 try self.genFunctype();713 try self.genFunctype();
718
719 // Write instructions
720 // TODO: check for and handle death of instructions714 // TODO: check for and handle death of instructions
721715
722 // Reserve space to write the size after generating the code as well as space for locals count716 // Reserve space to write the size after generating the code as well as space for locals count
723 try self.code.resize(10);717 try self.code.resize(10);
724718
725 try self.genBody(func.body);719 try self.genBody(self.air.getMainBody());
726720
727 // finally, write our local types at the 'offset' position721 // finally, write our local types at the 'offset' position
728 {722 {
...@@ -753,7 +747,7 @@ pub const Context = struct {...@@ -753,7 +747,7 @@ pub const Context = struct {
753 return Result.appended;747 return Result.appended;
754 }748 }
755749
756 /// Generates the wasm bytecode for the function declaration belonging to `Context`750 /// Generates the wasm bytecode for the declaration belonging to `Context`
757 pub fn gen(self: *Context, typed_value: TypedValue) InnerError!Result {751 pub fn gen(self: *Context, typed_value: TypedValue) InnerError!Result {
758 switch (typed_value.ty.zigTypeTag()) {752 switch (typed_value.ty.zigTypeTag()) {
759 .Fn => {753 .Fn => {
...@@ -793,58 +787,59 @@ pub const Context = struct {...@@ -793,58 +787,59 @@ pub const Context = struct {
793 }787 }
794 }788 }
795789
796 fn genInst(self: *Context, inst: *Inst) InnerError!WValue {790 fn genInst(self: *Context, inst: Air.Inst.Index) !WValue {
797 return switch (inst.tag) {791 const air_tags = self.air.instructions.items(.tag);
798 .add => self.genBinOp(inst.castTag(.add).?, .add),792 return switch (air_tags[inst]) {
799 .alloc => self.genAlloc(inst.castTag(.alloc).?),793 // .add => self.genBinOp(inst.castTag(.add).?, .add),
800 .arg => self.genArg(inst.castTag(.arg).?),794 // .alloc => self.genAlloc(inst.castTag(.alloc).?),
801 .bit_and => self.genBinOp(inst.castTag(.bit_and).?, .@"and"),795 // .arg => self.genArg(inst.castTag(.arg).?),
802 .bitcast => self.genBitcast(inst.castTag(.bitcast).?),796 // .bit_and => self.genBinOp(inst.castTag(.bit_and).?, .@"and"),
803 .bit_or => self.genBinOp(inst.castTag(.bit_or).?, .@"or"),797 // .bitcast => self.genBitcast(inst.castTag(.bitcast).?),
804 .block => self.genBlock(inst.castTag(.block).?),798 // .bit_or => self.genBinOp(inst.castTag(.bit_or).?, .@"or"),
805 .bool_and => self.genBinOp(inst.castTag(.bool_and).?, .@"and"),799 // .block => self.genBlock(inst.castTag(.block).?),
806 .bool_or => self.genBinOp(inst.castTag(.bool_or).?, .@"or"),800 // .bool_and => self.genBinOp(inst.castTag(.bool_and).?, .@"and"),
807 .breakpoint => self.genBreakpoint(inst.castTag(.breakpoint).?),801 // .bool_or => self.genBinOp(inst.castTag(.bool_or).?, .@"or"),
808 .br => self.genBr(inst.castTag(.br).?),802 // .breakpoint => self.genBreakpoint(inst.castTag(.breakpoint).?),
809 .call => self.genCall(inst.castTag(.call).?),803 // .br => self.genBr(inst.castTag(.br).?),
810 .cmp_eq => self.genCmp(inst.castTag(.cmp_eq).?, .eq),804 // .call => self.genCall(inst.castTag(.call).?),
811 .cmp_gte => self.genCmp(inst.castTag(.cmp_gte).?, .gte),805 // .cmp_eq => self.genCmp(inst.castTag(.cmp_eq).?, .eq),
812 .cmp_gt => self.genCmp(inst.castTag(.cmp_gt).?, .gt),806 // .cmp_gte => self.genCmp(inst.castTag(.cmp_gte).?, .gte),
813 .cmp_lte => self.genCmp(inst.castTag(.cmp_lte).?, .lte),807 // .cmp_gt => self.genCmp(inst.castTag(.cmp_gt).?, .gt),
814 .cmp_lt => self.genCmp(inst.castTag(.cmp_lt).?, .lt),808 // .cmp_lte => self.genCmp(inst.castTag(.cmp_lte).?, .lte),
815 .cmp_neq => self.genCmp(inst.castTag(.cmp_neq).?, .neq),809 // .cmp_lt => self.genCmp(inst.castTag(.cmp_lt).?, .lt),
816 .condbr => self.genCondBr(inst.castTag(.condbr).?),810 // .cmp_neq => self.genCmp(inst.castTag(.cmp_neq).?, .neq),
817 .constant => unreachable,811 // .condbr => self.genCondBr(inst.castTag(.condbr).?),
818 .dbg_stmt => WValue.none,812 // .constant => unreachable,
819 .div => self.genBinOp(inst.castTag(.div).?, .div),813 // .dbg_stmt => WValue.none,
820 .is_err => self.genIsErr(inst.castTag(.is_err).?, .i32_ne),814 // .div => self.genBinOp(inst.castTag(.div).?, .div),
821 .is_non_err => self.genIsErr(inst.castTag(.is_non_err).?, .i32_eq),815 // .is_err => self.genIsErr(inst.castTag(.is_err).?, .i32_ne),
822 .load => self.genLoad(inst.castTag(.load).?),816 // .is_non_err => self.genIsErr(inst.castTag(.is_non_err).?, .i32_eq),
823 .loop => self.genLoop(inst.castTag(.loop).?),817 // .load => self.genLoad(inst.castTag(.load).?),
824 .mul => self.genBinOp(inst.castTag(.mul).?, .mul),818 // .loop => self.genLoop(inst.castTag(.loop).?),
825 .not => self.genNot(inst.castTag(.not).?),819 // .mul => self.genBinOp(inst.castTag(.mul).?, .mul),
826 .ret => self.genRet(inst.castTag(.ret).?),820 // .not => self.genNot(inst.castTag(.not).?),
827 .retvoid => WValue.none,821 // .ret => self.genRet(inst.castTag(.ret).?),
828 .store => self.genStore(inst.castTag(.store).?),822 // .retvoid => WValue.none,
829 .struct_field_ptr => self.genStructFieldPtr(inst.castTag(.struct_field_ptr).?),823 // .store => self.genStore(inst.castTag(.store).?),
830 .sub => self.genBinOp(inst.castTag(.sub).?, .sub),824 // .struct_field_ptr => self.genStructFieldPtr(inst.castTag(.struct_field_ptr).?),
831 .switchbr => self.genSwitchBr(inst.castTag(.switchbr).?),825 // .sub => self.genBinOp(inst.castTag(.sub).?, .sub),
832 .unreach => self.genUnreachable(inst.castTag(.unreach).?),826 // .switchbr => self.genSwitchBr(inst.castTag(.switchbr).?),
833 .unwrap_errunion_payload => self.genUnwrapErrUnionPayload(inst.castTag(.unwrap_errunion_payload).?),827 // .unreach => self.genUnreachable(inst.castTag(.unreach).?),
834 .wrap_errunion_payload => self.genWrapErrUnionPayload(inst.castTag(.wrap_errunion_payload).?),828 // .unwrap_errunion_payload => self.genUnwrapErrUnionPayload(inst.castTag(.unwrap_errunion_payload).?),
835 .xor => self.genBinOp(inst.castTag(.xor).?, .xor),829 // .wrap_errunion_payload => self.genWrapErrUnionPayload(inst.castTag(.wrap_errunion_payload).?),
836 else => self.fail(.{ .node_offset = 0 }, "TODO: Implement wasm inst: {s}", .{inst.tag}),830 // .xor => self.genBinOp(inst.castTag(.xor).?, .xor),
831 else => |tag| self.fail("TODO: Implement wasm inst: {s}", .{@tagName(tag)}),
837 };832 };
838 }833 }
839834
840 fn genBody(self: *Context, body: ir.Body) InnerError!void {835 fn genBody(self: *Context, body: []const Air.Inst.Index) InnerError!void {
841 for (body.instructions) |inst| {836 for (body) |inst| {
842 const result = try self.genInst(inst);837 const result = try self.genInst(inst);
843 try self.values.putNoClobber(self.gpa, inst, result);838 try self.values.putNoClobber(self.gpa, inst, result);
844 }839 }
845 }840 }
846841
847 fn genRet(self: *Context, inst: *Inst.UnOp) InnerError!WValue {842 fn genRet(self: *Context, inst: Air.Inst.Index) InnerError!WValue {
848 // TODO: Implement tail calls843 // TODO: Implement tail calls
849 const operand = self.resolveInst(inst.operand);844 const operand = self.resolveInst(inst.operand);
850 try self.emitWValue(operand);845 try self.emitWValue(operand);
...@@ -852,7 +847,7 @@ pub const Context = struct {...@@ -852,7 +847,7 @@ pub const Context = struct {
852 return .none;847 return .none;
853 }848 }
854849
855 fn genCall(self: *Context, inst: *Inst.Call) InnerError!WValue {850 fn genCall(self: *Context, inst: Air.Inst.Index) InnerError!WValue {
856 const func_val = inst.func.value().?;851 const func_val = inst.func.value().?;
857852
858 const target: *Decl = blk: {853 const target: *Decl = blk: {
...@@ -861,7 +856,7 @@ pub const Context = struct {...@@ -861,7 +856,7 @@ pub const Context = struct {
861 } else if (func_val.castTag(.extern_fn)) |ext_fn| {856 } else if (func_val.castTag(.extern_fn)) |ext_fn| {
862 break :blk ext_fn.data;857 break :blk ext_fn.data;
863 }858 }
864 return self.fail(inst.base.src, "Expected a function, but instead found type '{s}'", .{func_val.tag()});859 return self.fail("Expected a function, but instead found type '{s}'", .{func_val.tag()});
865 };860 };
866861
867 for (inst.args) |arg| {862 for (inst.args) |arg| {
...@@ -881,12 +876,12 @@ pub const Context = struct {...@@ -881,12 +876,12 @@ pub const Context = struct {
881 return .none;876 return .none;
882 }877 }
883878
884 fn genAlloc(self: *Context, inst: *Inst.NoOp) InnerError!WValue {879 fn genAlloc(self: *Context, inst: Air.Inst.Index) InnerError!WValue {
885 const elem_type = inst.base.ty.elemType();880 const elem_type = inst.base.ty.elemType();
886 return self.allocLocal(elem_type);881 return self.allocLocal(elem_type);
887 }882 }
888883
889 fn genStore(self: *Context, inst: *Inst.BinOp) InnerError!WValue {884 fn genStore(self: *Context, inst: Air.Inst.Index) InnerError!WValue {
890 const writer = self.code.writer();885 const writer = self.code.writer();
891886
892 const lhs = self.resolveInst(inst.lhs);887 const lhs = self.resolveInst(inst.lhs);
...@@ -924,18 +919,18 @@ pub const Context = struct {...@@ -924,18 +919,18 @@ pub const Context = struct {
924 return .none;919 return .none;
925 }920 }
926921
927 fn genLoad(self: *Context, inst: *Inst.UnOp) InnerError!WValue {922 fn genLoad(self: *Context, inst: Air.Inst.Index) InnerError!WValue {
928 return self.resolveInst(inst.operand);923 return self.resolveInst(inst.operand);
929 }924 }
930925
931 fn genArg(self: *Context, inst: *Inst.Arg) InnerError!WValue {926 fn genArg(self: *Context, inst: Air.Inst.Index) InnerError!WValue {
932 _ = inst;927 _ = inst;
933 // arguments share the index with locals928 // arguments share the index with locals
934 defer self.local_index += 1;929 defer self.local_index += 1;
935 return WValue{ .local = self.local_index };930 return WValue{ .local = self.local_index };
936 }931 }
937932
938 fn genBinOp(self: *Context, inst: *Inst.BinOp, op: Op) InnerError!WValue {933 fn genBinOp(self: *Context, inst: Air.Inst.Index, op: Op) InnerError!WValue {
939 const lhs = self.resolveInst(inst.lhs);934 const lhs = self.resolveInst(inst.lhs);
940 const rhs = self.resolveInst(inst.rhs);935 const rhs = self.resolveInst(inst.rhs);
941936
...@@ -952,21 +947,21 @@ pub const Context = struct {...@@ -952,21 +947,21 @@ pub const Context = struct {
952947
953 const opcode: wasm.Opcode = buildOpcode(.{948 const opcode: wasm.Opcode = buildOpcode(.{
954 .op = op,949 .op = op,
955 .valtype1 = try self.typeToValtype(inst.base.src, inst.base.ty),950 .valtype1 = try self.typeToValtype(inst.base.ty),
956 .signedness = if (inst.base.ty.isSignedInt()) .signed else .unsigned,951 .signedness = if (inst.base.ty.isSignedInt()) .signed else .unsigned,
957 });952 });
958 try self.code.append(wasm.opcode(opcode));953 try self.code.append(wasm.opcode(opcode));
959 return WValue{ .code_offset = offset };954 return WValue{ .code_offset = offset };
960 }955 }
961956
962 fn emitConstant(self: *Context, src: LazySrcLoc, value: Value, ty: Type) InnerError!void {957 fn emitConstant(self: *Context, value: Value, ty: Type) InnerError!void {
963 const writer = self.code.writer();958 const writer = self.code.writer();
964 switch (ty.zigTypeTag()) {959 switch (ty.zigTypeTag()) {
965 .Int => {960 .Int => {
966 // write opcode961 // write opcode
967 const opcode: wasm.Opcode = buildOpcode(.{962 const opcode: wasm.Opcode = buildOpcode(.{
968 .op = .@"const",963 .op = .@"const",
969 .valtype1 = try self.typeToValtype(src, ty),964 .valtype1 = try self.typeToValtype(ty),
970 });965 });
971 try writer.writeByte(wasm.opcode(opcode));966 try writer.writeByte(wasm.opcode(opcode));
972 // write constant967 // write constant
...@@ -985,14 +980,14 @@ pub const Context = struct {...@@ -985,14 +980,14 @@ pub const Context = struct {
985 // write opcode980 // write opcode
986 const opcode: wasm.Opcode = buildOpcode(.{981 const opcode: wasm.Opcode = buildOpcode(.{
987 .op = .@"const",982 .op = .@"const",
988 .valtype1 = try self.typeToValtype(src, ty),983 .valtype1 = try self.typeToValtype(ty),
989 });984 });
990 try writer.writeByte(wasm.opcode(opcode));985 try writer.writeByte(wasm.opcode(opcode));
991 // write constant986 // write constant
992 switch (ty.floatBits(self.target)) {987 switch (ty.floatBits(self.target)) {
993 0...32 => try writer.writeIntLittle(u32, @bitCast(u32, value.toFloat(f32))),988 0...32 => try writer.writeIntLittle(u32, @bitCast(u32, value.toFloat(f32))),
994 64 => try writer.writeIntLittle(u64, @bitCast(u64, value.toFloat(f64))),989 64 => try writer.writeIntLittle(u64, @bitCast(u64, value.toFloat(f64))),
995 else => |bits| return self.fail(src, "Wasm TODO: emitConstant for float with {d} bits", .{bits}),990 else => |bits| return self.fail("Wasm TODO: emitConstant for float with {d} bits", .{bits}),
996 }991 }
997 },992 },
998 .Pointer => {993 .Pointer => {
...@@ -1009,7 +1004,7 @@ pub const Context = struct {...@@ -1009,7 +1004,7 @@ pub const Context = struct {
1009 try writer.writeByte(wasm.opcode(.i32_load));1004 try writer.writeByte(wasm.opcode(.i32_load));
1010 try leb.writeULEB128(writer, @as(u32, 0));1005 try leb.writeULEB128(writer, @as(u32, 0));
1011 try leb.writeULEB128(writer, @as(u32, 0));1006 try leb.writeULEB128(writer, @as(u32, 0));
1012 } else return self.fail(src, "Wasm TODO: emitConstant for other const pointer tag {s}", .{value.tag()});1007 } else return self.fail("Wasm TODO: emitConstant for other const pointer tag {s}", .{value.tag()});
1013 },1008 },
1014 .Void => {},1009 .Void => {},
1015 .Enum => {1010 .Enum => {
...@@ -1023,7 +1018,7 @@ pub const Context = struct {...@@ -1023,7 +1018,7 @@ pub const Context = struct {
1023 const enum_full = ty.cast(Type.Payload.EnumFull).?.data;1018 const enum_full = ty.cast(Type.Payload.EnumFull).?.data;
1024 if (enum_full.values.count() != 0) {1019 if (enum_full.values.count() != 0) {
1025 const tag_val = enum_full.values.keys()[field_index.data];1020 const tag_val = enum_full.values.keys()[field_index.data];
1026 try self.emitConstant(src, tag_val, enum_full.tag_ty);1021 try self.emitConstant(tag_val, enum_full.tag_ty);
1027 } else {1022 } else {
1028 try writer.writeByte(wasm.opcode(.i32_const));1023 try writer.writeByte(wasm.opcode(.i32_const));
1029 try leb.writeULEB128(writer, field_index.data);1024 try leb.writeULEB128(writer, field_index.data);
...@@ -1034,7 +1029,7 @@ pub const Context = struct {...@@ -1034,7 +1029,7 @@ pub const Context = struct {
1034 } else {1029 } else {
1035 var int_tag_buffer: Type.Payload.Bits = undefined;1030 var int_tag_buffer: Type.Payload.Bits = undefined;
1036 const int_tag_ty = ty.intTagType(&int_tag_buffer);1031 const int_tag_ty = ty.intTagType(&int_tag_buffer);
1037 try self.emitConstant(src, value, int_tag_ty);1032 try self.emitConstant(value, int_tag_ty);
1038 }1033 }
1039 },1034 },
1040 .ErrorSet => {1035 .ErrorSet => {
...@@ -1048,12 +1043,12 @@ pub const Context = struct {...@@ -1048,12 +1043,12 @@ pub const Context = struct {
1048 const payload_type = ty.errorUnionChild();1043 const payload_type = ty.errorUnionChild();
1049 if (value.getError()) |_| {1044 if (value.getError()) |_| {
1050 // write the error value1045 // write the error value
1051 try self.emitConstant(src, data, error_type);1046 try self.emitConstant(data, error_type);
10521047
1053 // no payload, so write a '0' const1048 // no payload, so write a '0' const
1054 const opcode: wasm.Opcode = buildOpcode(.{1049 const opcode: wasm.Opcode = buildOpcode(.{
1055 .op = .@"const",1050 .op = .@"const",
1056 .valtype1 = try self.typeToValtype(src, payload_type),1051 .valtype1 = try self.typeToValtype(payload_type),
1057 });1052 });
1058 try writer.writeByte(wasm.opcode(opcode));1053 try writer.writeByte(wasm.opcode(opcode));
1059 try leb.writeULEB128(writer, @as(u32, 0));1054 try leb.writeULEB128(writer, @as(u32, 0));
...@@ -1062,15 +1057,15 @@ pub const Context = struct {...@@ -1062,15 +1057,15 @@ pub const Context = struct {
1062 try writer.writeByte(wasm.opcode(.i32_const));1057 try writer.writeByte(wasm.opcode(.i32_const));
1063 try leb.writeULEB128(writer, @as(u32, 0));1058 try leb.writeULEB128(writer, @as(u32, 0));
1064 // after the error code, we emit the payload1059 // after the error code, we emit the payload
1065 try self.emitConstant(src, data, payload_type);1060 try self.emitConstant(data, payload_type);
1066 }1061 }
1067 },1062 },
1068 else => |zig_type| return self.fail(src, "Wasm TODO: emitConstant for zigTypeTag {s}", .{zig_type}),1063 else => |zig_type| return self.fail("Wasm TODO: emitConstant for zigTypeTag {s}", .{zig_type}),
1069 }1064 }
1070 }1065 }
10711066
1072 fn genBlock(self: *Context, block: *Inst.Block) InnerError!WValue {1067 fn genBlock(self: *Context, block: Air.Inst.Index) InnerError!WValue {
1073 const block_ty = try self.genBlockType(block.base.src, block.base.ty);1068 const block_ty = try self.genBlockType(block.base.ty);
10741069
1075 try self.startBlock(.block, block_ty, null);1070 try self.startBlock(.block, block_ty, null);
1076 // Here we set the current block idx, so breaks know the depth to jump1071 // Here we set the current block idx, so breaks know the depth to jump
...@@ -1100,8 +1095,8 @@ pub const Context = struct {...@@ -1100,8 +1095,8 @@ pub const Context = struct {
1100 self.block_depth -= 1;1095 self.block_depth -= 1;
1101 }1096 }
11021097
1103 fn genLoop(self: *Context, loop: *Inst.Loop) InnerError!WValue {1098 fn genLoop(self: *Context, loop: Air.Inst.Index) InnerError!WValue {
1104 const loop_ty = try self.genBlockType(loop.base.src, loop.base.ty);1099 const loop_ty = try self.genBlockType(loop.base.ty);
11051100
1106 try self.startBlock(.loop, loop_ty, null);1101 try self.startBlock(.loop, loop_ty, null);
1107 try self.genBody(loop.body);1102 try self.genBody(loop.body);
...@@ -1115,7 +1110,7 @@ pub const Context = struct {...@@ -1115,7 +1110,7 @@ pub const Context = struct {
1115 return .none;1110 return .none;
1116 }1111 }
11171112
1118 fn genCondBr(self: *Context, condbr: *Inst.CondBr) InnerError!WValue {1113 fn genCondBr(self: *Context, condbr: Air.Inst.Index) InnerError!WValue {
1119 const condition = self.resolveInst(condbr.condition);1114 const condition = self.resolveInst(condbr.condition);
1120 const writer = self.code.writer();1115 const writer = self.code.writer();
11211116
...@@ -1131,7 +1126,7 @@ pub const Context = struct {...@@ -1131,7 +1126,7 @@ pub const Context = struct {
1131 break :blk offset;1126 break :blk offset;
1132 },1127 },
1133 };1128 };
1134 const block_ty = try self.genBlockType(condbr.base.src, condbr.base.ty);1129 const block_ty = try self.genBlockType(condbr.base.ty);
1135 try self.startBlock(.block, block_ty, offset);1130 try self.startBlock(.block, block_ty, offset);
11361131
1137 // we inserted the block in front of the condition1132 // we inserted the block in front of the condition
...@@ -1149,7 +1144,7 @@ pub const Context = struct {...@@ -1149,7 +1144,7 @@ pub const Context = struct {
1149 return .none;1144 return .none;
1150 }1145 }
11511146
1152 fn genCmp(self: *Context, inst: *Inst.BinOp, op: std.math.CompareOperator) InnerError!WValue {1147 fn genCmp(self: *Context, inst: Air.Inst.Index, op: std.math.CompareOperator) InnerError!WValue {
1153 // save offset, so potential conditions can insert blocks in front of1148 // save offset, so potential conditions can insert blocks in front of
1154 // the comparison that we can later jump back to1149 // the comparison that we can later jump back to
1155 const offset = self.code.items.len;1150 const offset = self.code.items.len;
...@@ -1168,7 +1163,7 @@ pub const Context = struct {...@@ -1168,7 +1163,7 @@ pub const Context = struct {
1168 break :blk inst.lhs.ty.intInfo(self.target).signedness;1163 break :blk inst.lhs.ty.intInfo(self.target).signedness;
1169 };1164 };
1170 const opcode: wasm.Opcode = buildOpcode(.{1165 const opcode: wasm.Opcode = buildOpcode(.{
1171 .valtype1 = try self.typeToValtype(inst.base.src, inst.lhs.ty),1166 .valtype1 = try self.typeToValtype(inst.lhs.ty),
1172 .op = switch (op) {1167 .op = switch (op) {
1173 .lt => .lt,1168 .lt => .lt,
1174 .lte => .le,1169 .lte => .le,
...@@ -1183,7 +1178,7 @@ pub const Context = struct {...@@ -1183,7 +1178,7 @@ pub const Context = struct {
1183 return WValue{ .code_offset = offset };1178 return WValue{ .code_offset = offset };
1184 }1179 }
11851180
1186 fn genBr(self: *Context, br: *Inst.Br) InnerError!WValue {1181 fn genBr(self: *Context, br: Air.Inst.Index) InnerError!WValue {
1187 // if operand has codegen bits we should break with a value1182 // if operand has codegen bits we should break with a value
1188 if (br.operand.ty.hasCodeGenBits()) {1183 if (br.operand.ty.hasCodeGenBits()) {
1189 const operand = self.resolveInst(br.operand);1184 const operand = self.resolveInst(br.operand);
...@@ -1200,7 +1195,7 @@ pub const Context = struct {...@@ -1200,7 +1195,7 @@ pub const Context = struct {
1200 return .none;1195 return .none;
1201 }1196 }
12021197
1203 fn genNot(self: *Context, not: *Inst.UnOp) InnerError!WValue {1198 fn genNot(self: *Context, not: Air.Inst.Index) InnerError!WValue {
1204 const offset = self.code.items.len;1199 const offset = self.code.items.len;
12051200
1206 const operand = self.resolveInst(not.operand);1201 const operand = self.resolveInst(not.operand);
...@@ -1217,7 +1212,7 @@ pub const Context = struct {...@@ -1217,7 +1212,7 @@ pub const Context = struct {
1217 return WValue{ .code_offset = offset };1212 return WValue{ .code_offset = offset };
1218 }1213 }
12191214
1220 fn genBreakpoint(self: *Context, breakpoint: *Inst.NoOp) InnerError!WValue {1215 fn genBreakpoint(self: *Context, breakpoint: Air.Inst.Index) InnerError!WValue {
1221 _ = self;1216 _ = self;
1222 _ = breakpoint;1217 _ = breakpoint;
1223 // unsupported by wasm itself. Can be implemented once we support DWARF1218 // unsupported by wasm itself. Can be implemented once we support DWARF
...@@ -1225,27 +1220,27 @@ pub const Context = struct {...@@ -1225,27 +1220,27 @@ pub const Context = struct {
1225 return .none;1220 return .none;
1226 }1221 }
12271222
1228 fn genUnreachable(self: *Context, unreach: *Inst.NoOp) InnerError!WValue {1223 fn genUnreachable(self: *Context, unreach: Air.Inst.Index) InnerError!WValue {
1229 _ = unreach;1224 _ = unreach;
1230 try self.code.append(wasm.opcode(.@"unreachable"));1225 try self.code.append(wasm.opcode(.@"unreachable"));
1231 return .none;1226 return .none;
1232 }1227 }
12331228
1234 fn genBitcast(self: *Context, bitcast: *Inst.UnOp) InnerError!WValue {1229 fn genBitcast(self: *Context, bitcast: Air.Inst.Index) InnerError!WValue {
1235 return self.resolveInst(bitcast.operand);1230 return self.resolveInst(bitcast.operand);
1236 }1231 }
12371232
1238 fn genStructFieldPtr(self: *Context, inst: *Inst.StructFieldPtr) InnerError!WValue {1233 fn genStructFieldPtr(self: *Context, inst: Air.Inst.Index) InnerError!WValue {
1239 const struct_ptr = self.resolveInst(inst.struct_ptr);1234 const struct_ptr = self.resolveInst(inst.struct_ptr);
12401235
1241 return WValue{ .local = struct_ptr.multi_value.index + @intCast(u32, inst.field_index) };1236 return WValue{ .local = struct_ptr.multi_value.index + @intCast(u32, inst.field_index) };
1242 }1237 }
12431238
1244 fn genSwitchBr(self: *Context, inst: *Inst.SwitchBr) InnerError!WValue {1239 fn genSwitchBr(self: *Context, inst: Air.Inst.Index) InnerError!WValue {
1245 const target = self.resolveInst(inst.target);1240 const target = self.resolveInst(inst.target);
1246 const target_ty = inst.target.ty;1241 const target_ty = inst.target.ty;
1247 const valtype = try self.typeToValtype(.{ .node_offset = 0 }, target_ty);1242 const valtype = try self.typeToValtype(.{ .node_offset = 0 }, target_ty);
1248 const blocktype = try self.genBlockType(inst.base.src, inst.base.ty);1243 const blocktype = try self.genBlockType(inst.base.ty);
12491244
1250 const signedness: std.builtin.Signedness = blk: {1245 const signedness: std.builtin.Signedness = blk: {
1251 // by default we tell the operand type is unsigned (i.e. bools and enum values)1246 // by default we tell the operand type is unsigned (i.e. bools and enum values)
...@@ -1282,7 +1277,7 @@ pub const Context = struct {...@@ -1282,7 +1277,7 @@ pub const Context = struct {
1282 return .none;1277 return .none;
1283 }1278 }
12841279
1285 fn genIsErr(self: *Context, inst: *Inst.UnOp, opcode: wasm.Opcode) InnerError!WValue {1280 fn genIsErr(self: *Context, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerError!WValue {
1286 const operand = self.resolveInst(inst.operand);1281 const operand = self.resolveInst(inst.operand);
1287 const offset = self.code.items.len;1282 const offset = self.code.items.len;
1288 const writer = self.code.writer();1283 const writer = self.code.writer();
...@@ -1298,7 +1293,7 @@ pub const Context = struct {...@@ -1298,7 +1293,7 @@ pub const Context = struct {
1298 return WValue{ .code_offset = offset };1293 return WValue{ .code_offset = offset };
1299 }1294 }
13001295
1301 fn genUnwrapErrUnionPayload(self: *Context, inst: *Inst.UnOp) InnerError!WValue {1296 fn genUnwrapErrUnionPayload(self: *Context, inst: Air.Inst.Index) InnerError!WValue {
1302 const operand = self.resolveInst(inst.operand);1297 const operand = self.resolveInst(inst.operand);
1303 // The index of multi_value contains the error code. To get the initial index of the payload we get1298 // The index of multi_value contains the error code. To get the initial index of the payload we get
1304 // the following index. Next, convert it to a `WValue.local`1299 // the following index. Next, convert it to a `WValue.local`
...@@ -1307,7 +1302,7 @@ pub const Context = struct {...@@ -1307,7 +1302,7 @@ pub const Context = struct {
1307 return WValue{ .local = operand.multi_value.index + 1 };1302 return WValue{ .local = operand.multi_value.index + 1 };
1308 }1303 }
13091304
1310 fn genWrapErrUnionPayload(self: *Context, inst: *Inst.UnOp) InnerError!WValue {1305 fn genWrapErrUnionPayload(self: *Context, inst: Air.Inst.Index) InnerError!WValue {
1311 return self.resolveInst(inst.operand);1306 return self.resolveInst(inst.operand);
1312 }1307 }
1313};1308};
src/link/Wasm.zig+10-7
...@@ -228,7 +228,7 @@ pub fn updateFunc(self: *Wasm, module: *Module, func: *Module.Fn, air: Air, live...@@ -228,7 +228,7 @@ pub fn updateFunc(self: *Wasm, module: *Module, func: *Module.Fn, air: Air, live
228 },228 },
229 else => |e| return e,229 else => |e| return e,
230 };230 };
231 return self.finishUpdateDecl(decl, result);231 return self.finishUpdateDecl(decl, result, &context);
232}232}
233233
234// Generate code for the Decl, storing it in memory to be later written to234// Generate code for the Decl, storing it in memory to be later written to
...@@ -270,18 +270,21 @@ pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void {...@@ -270,18 +270,21 @@ pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void {
270 },270 },
271 else => |e| return e,271 else => |e| return e,
272 };272 };
273 return self.finishUpdateDecl(decl, result);273
274 return self.finishUpdateDecl(decl, result, &context);
274}275}
275276
276fn finishUpdateDecl(self: *Wasm, decl: *Module.Decl, result: codegen.Result) !void {277fn finishUpdateDecl(self: *Wasm, decl: *Module.Decl, result: codegen.Result, context: *codegen.Context) !void {
277 const code: []const u8 = switch (result) {278 const fn_data: *FnData = &decl.fn_link.wasm;
278 .appended => @as([]const u8, context.code.items),
279 .externally_managed => |payload| payload,
280 };
281279
282 fn_data.code = context.code.toUnmanaged();280 fn_data.code = context.code.toUnmanaged();
283 fn_data.functype = context.func_type_data.toUnmanaged();281 fn_data.functype = context.func_type_data.toUnmanaged();
284282
283 const code: []const u8 = switch (result) {
284 .appended => @as([]const u8, fn_data.code.items),
285 .externally_managed => |payload| payload,
286 };
287
285 const block = &decl.link.wasm;288 const block = &decl.link.wasm;
286 if (decl.ty.zigTypeTag() == .Fn) {289 if (decl.ty.zigTypeTag() == .Fn) {
287 // as locals are patched afterwards, the offsets of funcidx's are off,290 // as locals are patched afterwards, the offsets of funcidx's are off,