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
signature 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 {
498498 /// List of all locals' types generated throughout this declaration
499499 /// used to emit locals count at start of 'code' section.
500500 locals: std.ArrayListUnmanaged(u8),
501 /// The Target we're emitting (used to call intInfo)
502 target: std.Target,
501503
502504 const InnerError = error{
503505 OutOfMemory,
......@@ -529,17 +531,22 @@ pub const Context = struct {
529531 return self.values.get(inst).?; // Instruction does not dominate all uses!
530532 }
531533
532 /// Using a given `Type`, returns the corresponding wasm value type
533 fn genValtype(self: *Context, src: LazySrcLoc, ty: Type) InnerError!u8 {
534 /// Using a given `Type`, returns the corresponding wasm Valtype
535 fn typeToValtype(self: *Context, src: LazySrcLoc, ty: Type) InnerError!wasm.Valtype {
534536 return switch (ty.tag()) {
535 .f32 => wasm.valtype(.f32),
536 .f64 => wasm.valtype(.f64),
537 .u32, .i32, .bool => wasm.valtype(.i32),
538 .u64, .i64 => wasm.valtype(.i64),
539 else => self.fail(src, "TODO - Wasm genValtype for type '{s}'", .{ty.tag()}),
537 .f32 => .f32,
538 .f64 => .f64,
539 .u32, .i32, .bool => .i32,
540 .u64, .i64 => .i64,
541 else => self.fail(src, "TODO - Wasm valtype for type '{s}'", .{ty.tag()}),
540542 };
541543 }
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
543550 /// Using a given `Type`, returns the corresponding wasm value type
544551 /// Differently from `genValtype` this also allows `void` to create a block
545552 /// with no return type
......@@ -643,7 +650,7 @@ pub const Context = struct {
643650
644651 fn genInst(self: *Context, inst: *Inst) InnerError!WValue {
645652 return switch (inst.tag) {
646 .add => self.genAdd(inst.castTag(.add).?),
653 .add => self.genBinOp(inst.castTag(.add).?, .add),
647654 .alloc => self.genAlloc(inst.castTag(.alloc).?),
648655 .arg => self.genArg(inst.castTag(.arg).?),
649656 .block => self.genBlock(inst.castTag(.block).?),
......@@ -661,12 +668,12 @@ pub const Context = struct {
661668 .dbg_stmt => WValue.none,
662669 .load => self.genLoad(inst.castTag(.load).?),
663670 .loop => self.genLoop(inst.castTag(.loop).?),
664 .mul => self.genMul(inst.castTag(.mul).?),
671 .mul => self.genBinOp(inst.castTag(.mul).?, .mul),
665672 .not => self.genNot(inst.castTag(.not).?),
666673 .ret => self.genRet(inst.castTag(.ret).?),
667674 .retvoid => WValue.none,
668675 .store => self.genStore(inst.castTag(.store).?),
669 .sub => self.genSub(inst.castTag(.sub).?),
676 .sub => self.genBinOp(inst.castTag(.sub).?, .sub),
670677 .unreach => self.genUnreachable(inst.castTag(.unreach).?),
671678 else => self.fail(inst.src, "TODO: Implement wasm inst: {s}", .{inst.tag}),
672679 };
......@@ -747,94 +754,59 @@ pub const Context = struct {
747754 return WValue{ .local = self.local_index };
748755 }
749756
750 fn genAdd(self: *Context, inst: *Inst.BinOp) 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 {
757 fn genBinOp(self: *Context, inst: *Inst.BinOp, op: Op) InnerError!WValue {
789758 const lhs = self.resolveInst(inst.lhs);
790759 const rhs = self.resolveInst(inst.rhs);
791760
792761 try self.emitWValue(lhs);
793762 try self.emitWValue(rhs);
794763
795 const opcode: wasm.Opcode = switch (inst.base.ty.tag()) {
796 .u32, .i32 => .i32_mul,
797 .u64, .i64 => .i64_mul,
798 .f32 => .f32_mul,
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
764 const opcode: wasm.Opcode = buildOpcode(.{
765 .op = op,
766 .valtype1 = try self.typeToValtype(inst.base.src, inst.base.ty),
767 });
803768 try self.code.append(wasm.opcode(opcode));
804769 return .none;
805770 }
806771
807772 fn emitConstant(self: *Context, inst: *Inst.Constant) InnerError!void {
808773 const writer = self.code.writer();
809 switch (inst.base.ty.tag()) {
810 .u32 => {
811 try writer.writeByte(wasm.opcode(.i32_const));
812 try leb.writeILEB128(writer, inst.val.toUnsignedInt());
774 switch (inst.base.ty.zigTypeTag()) {
775 .Int => {
776 // write opcode
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 }
813787 },
814 .i32, .bool => {
788 .Bool => {
789 // write opcode
815790 try writer.writeByte(wasm.opcode(.i32_const));
791 // write constant
816792 try leb.writeILEB128(writer, inst.val.toSignedInt());
817793 },
818 .u64 => {
819 try writer.writeByte(wasm.opcode(.i64_const));
820 try leb.writeILEB128(writer, inst.val.toUnsignedInt());
821 },
822 .i64 => {
823 try writer.writeByte(wasm.opcode(.i64_const));
824 try leb.writeILEB128(writer, inst.val.toSignedInt());
825 },
826 .f32 => {
827 try writer.writeByte(wasm.opcode(.f32_const));
828 // TODO: enforce LE byte order
829 try writer.writeAll(mem.asBytes(&inst.val.toFloat(f32)));
830 },
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)));
794 .Float => {
795 // write opcode
796 const opcode: wasm.Opcode = buildOpcode(.{
797 .op = .@"const",
798 .valtype1 = try self.typeToValtype(inst.base.src, inst.base.ty),
799 });
800 try writer.writeByte(wasm.opcode(opcode));
801 // write constant
802 switch (inst.base.ty.floatBits(self.target)) {
803 0...32 => try writer.writeIntLittle(u32, @bitCast(u32, inst.val.toFloat(f32))),
804 64 => try writer.writeIntLittle(u64, @bitCast(u64, inst.val.toFloat(f64))),
805 else => |bits| return self.fail(inst.base.src, "Wasm TODO: emitConstant for float with {d} bits", .{bits}),
806 }
835807 },
836 .void => {},
837 else => |ty| return self.fail(inst.base.src, "Wasm TODO: emitConstant for type {s}", .{ty}),
808 .Void => {},
809 else => |ty| return self.fail(inst.base.src, "Wasm TODO: emitConstant for zigTypeTag {s}", .{ty}),
838810 }
839811 }
840812
......@@ -935,62 +907,18 @@ pub const Context = struct {
935907 try self.emitWValue(lhs);
936908 try self.emitWValue(rhs);
937909
938 const opcode_maybe: ?wasm.Opcode = switch (op) {
939 .lt => @as(?wasm.Opcode, switch (ty) {
940 .i32 => .i32_lt_s,
941 .u32 => .i32_lt_u,
942 .i64 => .i64_lt_s,
943 .u64 => .i64_lt_u,
944 .f32 => .f32_lt,
945 .f64 => .f64_lt,
946 else => null,
947 }),
948 .lte => @as(?wasm.Opcode, switch (ty) {
949 .i32 => .i32_le_s,
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
910 const opcode: wasm.Opcode = buildOpcode(.{
911 .valtype1 = try self.typeToValtype(inst.base.src, inst.lhs.ty),
912 .op = switch (op) {
913 .lt => .lt,
914 .lte => .le,
915 .eq => .eq,
916 .neq => .ne,
917 .gte => .ge,
918 .gt => .gt,
919 },
920 .signedness = inst.lhs.ty.intInfo(self.target).signedness,
921 });
994922 try self.code.append(wasm.opcode(opcode));
995923 return WValue{ .code_offset = offset };
996924 }
src/link/Wasm.zig+1
......@@ -127,6 +127,7 @@ pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void {
127127 .decl = decl,
128128 .err_msg = undefined,
129129 .locals = .{},
130 .target = self.base.options.target,
130131 };
131132 defer context.deinit();
132133