| ... | @@ -1210,7 +1210,7 @@ fn allocStackPtr(self: *Self, inst: Air.Inst.Index) !WValue { | ... | @@ -1210,7 +1210,7 @@ fn allocStackPtr(self: *Self, inst: Air.Inst.Index) !WValue { |
| 1210 | | 1210 | |
| 1211 | /// From given zig bitsize, returns the wasm bitsize | 1211 | /// From given zig bitsize, returns the wasm bitsize |
| 1212 | fn toWasmBits(bits: u16) ?u16 { | 1212 | fn toWasmBits(bits: u16) ?u16 { |
| 1213 | return for ([_]u16{ 32, 64 }) |wasm_bits| { | 1213 | return for ([_]u16{ 32, 64, 128 }) |wasm_bits| { |
| 1214 | if (bits <= wasm_bits) return wasm_bits; | 1214 | if (bits <= wasm_bits) return wasm_bits; |
| 1215 | } else null; | 1215 | } else null; |
| 1216 | } | 1216 | } |
| ... | @@ -1837,8 +1837,11 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro | ... | @@ -1837,8 +1837,11 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro |
| 1837 | } | 1837 | } |
| 1838 | }, | 1838 | }, |
| 1839 | .Int => if (ty.intInfo(self.target).bits > 64) { | 1839 | .Int => if (ty.intInfo(self.target).bits > 64) { |
| 1840 | const len = @intCast(u32, ty.abiSize(self.target)); | 1840 | const lsb = try self.load(rhs, Type.u64, 0); |
| 1841 | return self.memcpy(lhs, rhs, .{ .imm32 = len }); | 1841 | const msb = try self.load(rhs, Type.u64, 8); |
| | 1842 | try self.store(lhs, lsb, Type.u64, 0); |
| | 1843 | try self.store(lhs, msb, Type.u64, 8); |
| | 1844 | return; |
| 1842 | }, | 1845 | }, |
| 1843 | else => {}, | 1846 | else => {}, |
| 1844 | } | 1847 | } |
| ... | @@ -2900,8 +2903,11 @@ fn airIntcast(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -2900,8 +2903,11 @@ fn airIntcast(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 2900 | const ty = self.air.getRefType(ty_op.ty); | 2903 | const ty = self.air.getRefType(ty_op.ty); |
| 2901 | const operand = try self.resolveInst(ty_op.operand); | 2904 | const operand = try self.resolveInst(ty_op.operand); |
| 2902 | const operand_ty = self.air.typeOf(ty_op.operand); | 2905 | const operand_ty = self.air.typeOf(ty_op.operand); |
| 2903 | if (ty.abiSize(self.target) > 8 or operand_ty.abiSize(self.target) > 8) { | 2906 | if (ty.zigTypeTag() == .Vector or operand_ty.zigTypeTag() == .Vector) { |
| 2904 | return self.fail("todo Wasm intcast for bitsize > 64", .{}); | 2907 | return self.fail("todo Wasm intcast for vectors", .{}); |
| | 2908 | } |
| | 2909 | if (ty.abiSize(self.target) > 16 or operand_ty.abiSize(self.target) > 16) { |
| | 2910 | return self.fail("todo Wasm intcast for bitsize > 128", .{}); |
| 2905 | } | 2911 | } |
| 2906 | | 2912 | |
| 2907 | return self.intcast(operand, operand_ty, ty); | 2913 | return self.intcast(operand, operand_ty, ty); |
| ... | @@ -2909,25 +2915,53 @@ fn airIntcast(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -2909,25 +2915,53 @@ fn airIntcast(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 2909 | | 2915 | |
| 2910 | /// Upcasts or downcasts an integer based on the given and wanted types, | 2916 | /// Upcasts or downcasts an integer based on the given and wanted types, |
| 2911 | /// and stores the result in a new operand. | 2917 | /// and stores the result in a new operand. |
| 2912 | /// Asserts type's bitsize <= 64 | 2918 | /// Asserts type's bitsize <= 128 |
| 2913 | fn intcast(self: *Self, operand: WValue, given: Type, wanted: Type) InnerError!WValue { | 2919 | fn intcast(self: *Self, operand: WValue, given: Type, wanted: Type) InnerError!WValue { |
| 2914 | const given_info = given.intInfo(self.target); | 2920 | const given_info = given.intInfo(self.target); |
| 2915 | const wanted_info = wanted.intInfo(self.target); | 2921 | const wanted_info = wanted.intInfo(self.target); |
| 2916 | assert(given_info.bits <= 64); | 2922 | assert(given_info.bits <= 128); |
| 2917 | assert(wanted_info.bits <= 64); | 2923 | assert(wanted_info.bits <= 128); |
| 2918 | | 2924 | |
| 2919 | const op_bits = toWasmBits(given_info.bits).?; | 2925 | const op_bits = toWasmBits(given_info.bits).?; |
| 2920 | const wanted_bits = toWasmBits(wanted_info.bits).?; | 2926 | const wanted_bits = toWasmBits(wanted_info.bits).?; |
| 2921 | if (op_bits == wanted_bits) return operand; | 2927 | if (op_bits == wanted_bits) return operand; |
| 2922 | | 2928 | |
| 2923 | try self.emitWValue(operand); | 2929 | if (op_bits > 32 and op_bits <= 64 and wanted_bits == 32) { |
| 2924 | if (op_bits > 32 and wanted_bits == 32) { | 2930 | try self.emitWValue(operand); |
| 2925 | try self.addTag(.i32_wrap_i64); | 2931 | try self.addTag(.i32_wrap_i64); |
| 2926 | } else if (op_bits == 32 and wanted_bits > 32) { | 2932 | } else if (op_bits == 32 and wanted_bits > 32 and wanted_bits <= 64) { |
| | 2933 | try self.emitWValue(operand); |
| 2927 | try self.addTag(switch (wanted_info.signedness) { | 2934 | try self.addTag(switch (wanted_info.signedness) { |
| 2928 | .signed => .i64_extend_i32_s, | 2935 | .signed => .i64_extend_i32_s, |
| 2929 | .unsigned => .i64_extend_i32_u, | 2936 | .unsigned => .i64_extend_i32_u, |
| 2930 | }); | 2937 | }); |
| | 2938 | } else if (wanted_bits == 128) { |
| | 2939 | // for 128bit integers we store the integer in the virtual stack, rather than a local |
| | 2940 | const stack_ptr = try self.allocStack(wanted); |
| | 2941 | |
| | 2942 | // for 32 bit integers, we first coerce the value into a 64 bit integer before storing it |
| | 2943 | // meaning less store operations are required. |
| | 2944 | const lhs = if (op_bits == 32) blk: { |
| | 2945 | const tmp = try self.intcast( |
| | 2946 | operand, |
| | 2947 | given, |
| | 2948 | if (wanted.isSignedInt()) Type.i64 else Type.u64, |
| | 2949 | ); |
| | 2950 | break :blk tmp; |
| | 2951 | } else operand; |
| | 2952 | |
| | 2953 | // store msb first |
| | 2954 | try self.store(stack_ptr, lhs, Type.u64, 0); |
| | 2955 | |
| | 2956 | // For signed integers we shift msb by 63 (64bit integer - 1 sign bit) and store remaining value |
| | 2957 | if (wanted.isSignedInt()) { |
| | 2958 | const shr = try self.binOp(lhs, .{ .imm64 = 63 }, Type.i64, .shr); |
| | 2959 | try self.store(stack_ptr, shr, Type.u64, 8); |
| | 2960 | } else { |
| | 2961 | // Ensure memory of lsb is zero'd |
| | 2962 | try self.store(stack_ptr, .{ .imm64 = 0 }, Type.u64, 8); |
| | 2963 | } |
| | 2964 | return stack_ptr; |
| 2931 | } else unreachable; | 2965 | } else unreachable; |
| 2932 | | 2966 | |
| 2933 | const result = try self.allocLocal(wanted); | 2967 | const result = try self.allocLocal(wanted); |