authorgravatar for 81774659+gracefuu@users.noreply.github.comgracefu <81774659+gracefuu@users.noreply.github.com> 2021-04-03 16:11:29+08:00
committergravatar for 81774659+gracefuu@users.noreply.github.comgracefu <81774659+gracefuu@users.noreply.github.com> 2021-04-05 16:19:52+08:00
logec84742c89273424aab713d1ff4d55a499c85cbf
tree7d936eaa32d9fdbecb3081d06752c346d3efdb7d
parent3648e43dda9b035bcc75ab98d690916e0667f985
signaturelock-open Commit is signed but in an unrecognized format.

stage2 wasm codegen: refactor to use wasm.buildOpcode


2 files changed, 66 insertions(+), 137 deletions(-)

src/codegen/wasm.zig+65-137
...@@ -498,6 +498,8 @@ pub const Context = struct {...@@ -498,6 +498,8 @@ pub const Context = struct {
498 /// List of all locals' types generated throughout this declaration498 /// List of all locals' types generated throughout this declaration
499 /// used to emit locals count at start of 'code' section.499 /// used to emit locals count at start of 'code' section.
500 locals: std.ArrayListUnmanaged(u8),500 locals: std.ArrayListUnmanaged(u8),
501 /// The Target we're emitting (used to call intInfo)
502 target: std.Target,
501503
502 const InnerError = error{504 const InnerError = error{
503 OutOfMemory,505 OutOfMemory,
...@@ -529,17 +531,22 @@ pub const Context = struct {...@@ -529,17 +531,22 @@ pub const Context = struct {
529 return self.values.get(inst).?; // Instruction does not dominate all uses!531 return self.values.get(inst).?; // Instruction does not dominate all uses!
530 }532 }
531533
532 /// Using a given `Type`, returns the corresponding wasm value type534 /// Using a given `Type`, returns the corresponding wasm Valtype
533 fn genValtype(self: *Context, src: LazySrcLoc, ty: Type) InnerError!u8 {535 fn typeToValtype(self: *Context, src: LazySrcLoc, ty: Type) InnerError!wasm.Valtype {
534 return switch (ty.tag()) {536 return switch (ty.tag()) {
535 .f32 => wasm.valtype(.f32),537 .f32 => .f32,
536 .f64 => wasm.valtype(.f64),538 .f64 => .f64,
537 .u32, .i32, .bool => wasm.valtype(.i32),539 .u32, .i32, .bool => .i32,
538 .u64, .i64 => wasm.valtype(.i64),540 .u64, .i64 => .i64,
539 else => self.fail(src, "TODO - Wasm genValtype for type '{s}'", .{ty.tag()}),541 else => self.fail(src, "TODO - Wasm valtype for type '{s}'", .{ty.tag()}),
540 };542 };
541 }543 }
542544
545 /// Using a given `Type`, returns the byte representation of its wasm value type
546 fn genValtype(self: *Context, src: LazySrcLoc, ty: Type) InnerError!u8 {
547 return wasm.valtype(try self.typeToValtype(src, ty));
548 }
549
543 /// Using a given `Type`, returns the corresponding wasm value type550 /// Using a given `Type`, returns the corresponding wasm value type
544 /// Differently from `genValtype` this also allows `void` to create a block551 /// Differently from `genValtype` this also allows `void` to create a block
545 /// with no return type552 /// with no return type
...@@ -643,7 +650,7 @@ pub const Context = struct {...@@ -643,7 +650,7 @@ pub const Context = struct {
643650
644 fn genInst(self: *Context, inst: *Inst) InnerError!WValue {651 fn genInst(self: *Context, inst: *Inst) InnerError!WValue {
645 return switch (inst.tag) {652 return switch (inst.tag) {
646 .add => self.genAdd(inst.castTag(.add).?),653 .add => self.genBinOp(inst.castTag(.add).?, .add),
647 .alloc => self.genAlloc(inst.castTag(.alloc).?),654 .alloc => self.genAlloc(inst.castTag(.alloc).?),
648 .arg => self.genArg(inst.castTag(.arg).?),655 .arg => self.genArg(inst.castTag(.arg).?),
649 .block => self.genBlock(inst.castTag(.block).?),656 .block => self.genBlock(inst.castTag(.block).?),
...@@ -661,12 +668,12 @@ pub const Context = struct {...@@ -661,12 +668,12 @@ pub const Context = struct {
661 .dbg_stmt => WValue.none,668 .dbg_stmt => WValue.none,
662 .load => self.genLoad(inst.castTag(.load).?),669 .load => self.genLoad(inst.castTag(.load).?),
663 .loop => self.genLoop(inst.castTag(.loop).?),670 .loop => self.genLoop(inst.castTag(.loop).?),
664 .mul => self.genMul(inst.castTag(.mul).?),671 .mul => self.genBinOp(inst.castTag(.mul).?, .mul),
665 .not => self.genNot(inst.castTag(.not).?),672 .not => self.genNot(inst.castTag(.not).?),
666 .ret => self.genRet(inst.castTag(.ret).?),673 .ret => self.genRet(inst.castTag(.ret).?),
667 .retvoid => WValue.none,674 .retvoid => WValue.none,
668 .store => self.genStore(inst.castTag(.store).?),675 .store => self.genStore(inst.castTag(.store).?),
669 .sub => self.genSub(inst.castTag(.sub).?),676 .sub => self.genBinOp(inst.castTag(.sub).?, .sub),
670 .unreach => self.genUnreachable(inst.castTag(.unreach).?),677 .unreach => self.genUnreachable(inst.castTag(.unreach).?),
671 else => self.fail(inst.src, "TODO: Implement wasm inst: {s}", .{inst.tag}),678 else => self.fail(inst.src, "TODO: Implement wasm inst: {s}", .{inst.tag}),
672 };679 };
...@@ -747,94 +754,59 @@ pub const Context = struct {...@@ -747,94 +754,59 @@ pub const Context = struct {
747 return WValue{ .local = self.local_index };754 return WValue{ .local = self.local_index };
748 }755 }
749756
750 fn genAdd(self: *Context, inst: *Inst.BinOp) InnerError!WValue {757 fn genBinOp(self: *Context, inst: *Inst.BinOp, op: Op) InnerError!WValue {
751 const lhs = self.resolveInst(inst.lhs);
752 const rhs = self.resolveInst(inst.rhs);
753
754 try self.emitWValue(lhs);
755 try self.emitWValue(rhs);
756
757 const opcode: wasm.Opcode = switch (inst.base.ty.tag()) {
758 .u32, .i32 => .i32_add,
759 .u64, .i64 => .i64_add,
760 .f32 => .f32_add,
761 .f64 => .f64_add,
762 else => return self.fail(inst.base.src, "TODO - Implement wasm genAdd for type '{s}'", .{inst.base.ty.tag()}),
763 };
764
765 try self.code.append(wasm.opcode(opcode));
766 return .none;
767 }
768
769 fn genSub(self: *Context, inst: *Inst.BinOp) InnerError!WValue {
770 const lhs = self.resolveInst(inst.lhs);
771 const rhs = self.resolveInst(inst.rhs);
772
773 try self.emitWValue(lhs);
774 try self.emitWValue(rhs);
775
776 const opcode: wasm.Opcode = switch (inst.base.ty.tag()) {
777 .u32, .i32 => .i32_sub,
778 .u64, .i64 => .i64_sub,
779 .f32 => .f32_sub,
780 .f64 => .f64_sub,
781 else => return self.fail(inst.base.src, "TODO - Implement wasm genSub for type '{s}'", .{inst.base.ty.tag()}),
782 };
783
784 try self.code.append(wasm.opcode(opcode));
785 return .none;
786 }
787
788 fn genMul(self: *Context, inst: *Inst.BinOp) InnerError!WValue {
789 const lhs = self.resolveInst(inst.lhs);758 const lhs = self.resolveInst(inst.lhs);
790 const rhs = self.resolveInst(inst.rhs);759 const rhs = self.resolveInst(inst.rhs);
791760
792 try self.emitWValue(lhs);761 try self.emitWValue(lhs);
793 try self.emitWValue(rhs);762 try self.emitWValue(rhs);
794763
795 const opcode: wasm.Opcode = switch (inst.base.ty.tag()) {764 const opcode: wasm.Opcode = buildOpcode(.{
796 .u32, .i32 => .i32_mul,765 .op = op,
797 .u64, .i64 => .i64_mul,766 .valtype1 = try self.typeToValtype(inst.base.src, inst.base.ty),
798 .f32 => .f32_mul,767 });
799 .f64 => .f64_mul,
800 else => return self.fail(inst.base.src, "TODO - Implement wasm genMul for type '{s}'", .{inst.base.ty.tag()}),
801 };
802
803 try self.code.append(wasm.opcode(opcode));768 try self.code.append(wasm.opcode(opcode));
804 return .none;769 return .none;
805 }770 }
806771
807 fn emitConstant(self: *Context, inst: *Inst.Constant) InnerError!void {772 fn emitConstant(self: *Context, inst: *Inst.Constant) InnerError!void {
808 const writer = self.code.writer();773 const writer = self.code.writer();
809 switch (inst.base.ty.tag()) {774 switch (inst.base.ty.zigTypeTag()) {
810 .u32 => {775 .Int => {
811 try writer.writeByte(wasm.opcode(.i32_const));776 // write opcode
812 try leb.writeILEB128(writer, inst.val.toUnsignedInt());777 const opcode: wasm.Opcode = buildOpcode(.{
778 .op = .@"const",
779 .valtype1 = try self.typeToValtype(inst.base.src, inst.base.ty),
780 });
781 try writer.writeByte(wasm.opcode(opcode));
782 // write constant
783 switch (inst.base.ty.intInfo(self.target).signedness) {
784 .signed => try leb.writeILEB128(writer, inst.val.toSignedInt()),
785 .unsigned => try leb.writeILEB128(writer, inst.val.toUnsignedInt()),
786 }
813 },787 },
814 .i32, .bool => {788 .Bool => {
789 // write opcode
815 try writer.writeByte(wasm.opcode(.i32_const));790 try writer.writeByte(wasm.opcode(.i32_const));
791 // write constant
816 try leb.writeILEB128(writer, inst.val.toSignedInt());792 try leb.writeILEB128(writer, inst.val.toSignedInt());
817 },793 },
818 .u64 => {794 .Float => {
819 try writer.writeByte(wasm.opcode(.i64_const));795 // write opcode
820 try leb.writeILEB128(writer, inst.val.toUnsignedInt());796 const opcode: wasm.Opcode = buildOpcode(.{
821 },797 .op = .@"const",
822 .i64 => {798 .valtype1 = try self.typeToValtype(inst.base.src, inst.base.ty),
823 try writer.writeByte(wasm.opcode(.i64_const));799 });
824 try leb.writeILEB128(writer, inst.val.toSignedInt());800 try writer.writeByte(wasm.opcode(opcode));
825 },801 // write constant
826 .f32 => {802 switch (inst.base.ty.floatBits(self.target)) {
827 try writer.writeByte(wasm.opcode(.f32_const));803 0...32 => try writer.writeIntLittle(u32, @bitCast(u32, inst.val.toFloat(f32))),
828 // TODO: enforce LE byte order804 64 => try writer.writeIntLittle(u64, @bitCast(u64, inst.val.toFloat(f64))),
829 try writer.writeAll(mem.asBytes(&inst.val.toFloat(f32)));805 else => |bits| return self.fail(inst.base.src, "Wasm TODO: emitConstant for float with {d} bits", .{bits}),
830 },806 }
831 .f64 => {
832 try writer.writeByte(wasm.opcode(.f64_const));
833 // TODO: enforce LE byte order
834 try writer.writeAll(mem.asBytes(&inst.val.toFloat(f64)));
835 },807 },
836 .void => {},808 .Void => {},
837 else => |ty| return self.fail(inst.base.src, "Wasm TODO: emitConstant for type {s}", .{ty}),809 else => |ty| return self.fail(inst.base.src, "Wasm TODO: emitConstant for zigTypeTag {s}", .{ty}),
838 }810 }
839 }811 }
840812
...@@ -935,62 +907,18 @@ pub const Context = struct {...@@ -935,62 +907,18 @@ pub const Context = struct {
935 try self.emitWValue(lhs);907 try self.emitWValue(lhs);
936 try self.emitWValue(rhs);908 try self.emitWValue(rhs);
937909
938 const opcode_maybe: ?wasm.Opcode = switch (op) {910 const opcode: wasm.Opcode = buildOpcode(.{
939 .lt => @as(?wasm.Opcode, switch (ty) {911 .valtype1 = try self.typeToValtype(inst.base.src, inst.lhs.ty),
940 .i32 => .i32_lt_s,912 .op = switch (op) {
941 .u32 => .i32_lt_u,913 .lt => .lt,
942 .i64 => .i64_lt_s,914 .lte => .le,
943 .u64 => .i64_lt_u,915 .eq => .eq,
944 .f32 => .f32_lt,916 .neq => .ne,
945 .f64 => .f64_lt,917 .gte => .ge,
946 else => null,918 .gt => .gt,
947 }),919 },
948 .lte => @as(?wasm.Opcode, switch (ty) {920 .signedness = inst.lhs.ty.intInfo(self.target).signedness,
949 .i32 => .i32_le_s,921 });
950 .u32 => .i32_le_u,
951 .i64 => .i64_le_s,
952 .u64 => .i64_le_u,
953 .f32 => .f32_le,
954 .f64 => .f64_le,
955 else => null,
956 }),
957 .eq => @as(?wasm.Opcode, switch (ty) {
958 .i32, .u32 => .i32_eq,
959 .i64, .u64 => .i64_eq,
960 .f32 => .f32_eq,
961 .f64 => .f64_eq,
962 else => null,
963 }),
964 .gte => @as(?wasm.Opcode, switch (ty) {
965 .i32 => .i32_ge_s,
966 .u32 => .i32_ge_u,
967 .i64 => .i64_ge_s,
968 .u64 => .i64_ge_u,
969 .f32 => .f32_ge,
970 .f64 => .f64_ge,
971 else => null,
972 }),
973 .gt => @as(?wasm.Opcode, switch (ty) {
974 .i32 => .i32_gt_s,
975 .u32 => .i32_gt_u,
976 .i64 => .i64_gt_s,
977 .u64 => .i64_gt_u,
978 .f32 => .f32_gt,
979 .f64 => .f64_gt,
980 else => null,
981 }),
982 .neq => @as(?wasm.Opcode, switch (ty) {
983 .i32, .u32 => .i32_ne,
984 .i64, .u64 => .i64_ne,
985 .f32 => .f32_ne,
986 .f64 => .f64_ne,
987 else => null,
988 }),
989 };
990
991 const opcode = opcode_maybe orelse
992 return self.fail(inst.base.src, "TODO - Wasm genCmp for type '{s}' and operator '{s}'", .{ ty, @tagName(op) });
993
994 try self.code.append(wasm.opcode(opcode));922 try self.code.append(wasm.opcode(opcode));
995 return WValue{ .code_offset = offset };923 return WValue{ .code_offset = offset };
996 }924 }
src/link/Wasm.zig+1
...@@ -127,6 +127,7 @@ pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void {...@@ -127,6 +127,7 @@ pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void {
127 .decl = decl,127 .decl = decl,
128 .err_msg = undefined,128 .err_msg = undefined,
129 .locals = .{},129 .locals = .{},
130 .target = self.base.options.target,
130 };131 };
131 defer context.deinit();132 defer context.deinit();
132133