| ... | @@ -690,7 +690,7 @@ fn typeToValtype(self: *Self, ty: Type) InnerError!wasm.Valtype { | ... | @@ -690,7 +690,7 @@ fn typeToValtype(self: *Self, ty: Type) InnerError!wasm.Valtype { |
| 690 | const info = ty.intInfo(self.target); | 690 | const info = ty.intInfo(self.target); |
| 691 | if (info.bits <= 32) break :blk wasm.Valtype.i32; | 691 | if (info.bits <= 32) break :blk wasm.Valtype.i32; |
| 692 | if (info.bits > 32 and info.bits <= 64) break :blk wasm.Valtype.i64; | 692 | if (info.bits > 32 and info.bits <= 64) break :blk wasm.Valtype.i64; |
| 693 | return self.fail("TODO: Support integer bitsize: '{d}'", .{info.bits}); | 693 | break :blk wasm.Valtype.i32; // represented as pointer to stack |
| 694 | }, | 694 | }, |
| 695 | .Enum => switch (ty.tag()) { | 695 | .Enum => switch (ty.tag()) { |
| 696 | .enum_simple => wasm.Valtype.i32, | 696 | .enum_simple => wasm.Valtype.i32, |
| ... | @@ -753,7 +753,7 @@ fn genFunctype(self: *Self, fn_ty: Type) !wasm.Type { | ... | @@ -753,7 +753,7 @@ fn genFunctype(self: *Self, fn_ty: Type) !wasm.Type { |
| 753 | defer returns.deinit(); | 753 | defer returns.deinit(); |
| 754 | const return_type = fn_ty.fnReturnType(); | 754 | const return_type = fn_ty.fnReturnType(); |
| 755 | | 755 | |
| 756 | const want_sret = isByRef(return_type); | 756 | const want_sret = self.isByRef(return_type); |
| 757 | | 757 | |
| 758 | if (want_sret) { | 758 | if (want_sret) { |
| 759 | try params.append(try self.typeToValtype(Type.usize)); | 759 | try params.append(try self.typeToValtype(Type.usize)); |
| ... | @@ -1084,7 +1084,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) InnerError!CallWValu | ... | @@ -1084,7 +1084,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) InnerError!CallWValu |
| 1084 | const ret_ty = fn_ty.fnReturnType(); | 1084 | const ret_ty = fn_ty.fnReturnType(); |
| 1085 | // Check if we store the result as a pointer to the stack rather than | 1085 | // Check if we store the result as a pointer to the stack rather than |
| 1086 | // by value | 1086 | // by value |
| 1087 | if (isByRef(ret_ty)) { | 1087 | if (self.isByRef(ret_ty)) { |
| 1088 | // the sret arg will be passed as first argument, therefore we | 1088 | // the sret arg will be passed as first argument, therefore we |
| 1089 | // set the `return_value` before allocating locals for regular args. | 1089 | // set the `return_value` before allocating locals for regular args. |
| 1090 | result.return_value = .{ .local = self.local_index }; | 1090 | result.return_value = .{ .local = self.local_index }; |
| ... | @@ -1209,7 +1209,7 @@ fn ptrSize(self: *const Self) u16 { | ... | @@ -1209,7 +1209,7 @@ fn ptrSize(self: *const Self) u16 { |
| 1209 | | 1209 | |
| 1210 | /// For a given `Type`, will return true when the type will be passed | 1210 | /// For a given `Type`, will return true when the type will be passed |
| 1211 | /// by reference, rather than by value. | 1211 | /// by reference, rather than by value. |
| 1212 | fn isByRef(ty: Type) bool { | 1212 | fn isByRef(self: Self, ty: Type) bool { |
| 1213 | switch (ty.zigTypeTag()) { | 1213 | switch (ty.zigTypeTag()) { |
| 1214 | .Type, | 1214 | .Type, |
| 1215 | .ComptimeInt, | 1215 | .ComptimeInt, |
| ... | @@ -1224,7 +1224,6 @@ fn isByRef(ty: Type) bool { | ... | @@ -1224,7 +1224,6 @@ fn isByRef(ty: Type) bool { |
| 1224 | .NoReturn, | 1224 | .NoReturn, |
| 1225 | .Void, | 1225 | .Void, |
| 1226 | .Bool, | 1226 | .Bool, |
| 1227 | .Int, | | |
| 1228 | .Float, | 1227 | .Float, |
| 1229 | .ErrorSet, | 1228 | .ErrorSet, |
| 1230 | .Fn, | 1229 | .Fn, |
| ... | @@ -1238,6 +1237,7 @@ fn isByRef(ty: Type) bool { | ... | @@ -1238,6 +1237,7 @@ fn isByRef(ty: Type) bool { |
| 1238 | .Frame, | 1237 | .Frame, |
| 1239 | .Union, | 1238 | .Union, |
| 1240 | => return ty.hasCodeGenBits(), | 1239 | => return ty.hasCodeGenBits(), |
| | 1240 | .Int => return if (ty.intInfo(self.target).bits > 64) true else false, |
| 1241 | .ErrorUnion => { | 1241 | .ErrorUnion => { |
| 1242 | const has_tag = ty.errorUnionSet().hasCodeGenBits(); | 1242 | const has_tag = ty.errorUnionSet().hasCodeGenBits(); |
| 1243 | const has_pl = ty.errorUnionPayload().hasCodeGenBits(); | 1243 | const has_pl = ty.errorUnionPayload().hasCodeGenBits(); |
| ... | @@ -1412,7 +1412,7 @@ fn airRetPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -1412,7 +1412,7 @@ fn airRetPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 1412 | const child_type = self.air.typeOfIndex(inst).childType(); | 1412 | const child_type = self.air.typeOfIndex(inst).childType(); |
| 1413 | if (child_type.abiSize(self.target) == 0) return WValue{ .none = {} }; | 1413 | if (child_type.abiSize(self.target) == 0) return WValue{ .none = {} }; |
| 1414 | | 1414 | |
| 1415 | if (isByRef(child_type)) { | 1415 | if (self.isByRef(child_type)) { |
| 1416 | return self.return_value; | 1416 | return self.return_value; |
| 1417 | } | 1417 | } |
| 1418 | | 1418 | |
| ... | @@ -1429,7 +1429,7 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -1429,7 +1429,7 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 1429 | const ret_ty = self.air.typeOf(un_op).childType(); | 1429 | const ret_ty = self.air.typeOf(un_op).childType(); |
| 1430 | if (!ret_ty.hasCodeGenBits()) return WValue.none; | 1430 | if (!ret_ty.hasCodeGenBits()) return WValue.none; |
| 1431 | | 1431 | |
| 1432 | if (!isByRef(ret_ty)) { | 1432 | if (!self.isByRef(ret_ty)) { |
| 1433 | const result = try self.load(operand, ret_ty, 0); | 1433 | const result = try self.load(operand, ret_ty, 0); |
| 1434 | try self.emitWValue(result); | 1434 | try self.emitWValue(result); |
| 1435 | } | 1435 | } |
| ... | @@ -1451,7 +1451,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -1451,7 +1451,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 1451 | else => unreachable, | 1451 | else => unreachable, |
| 1452 | }; | 1452 | }; |
| 1453 | const ret_ty = fn_ty.fnReturnType(); | 1453 | const ret_ty = fn_ty.fnReturnType(); |
| 1454 | const first_param_sret = isByRef(ret_ty); | 1454 | const first_param_sret = self.isByRef(ret_ty); |
| 1455 | | 1455 | |
| 1456 | const target: ?*Decl = blk: { | 1456 | const target: ?*Decl = blk: { |
| 1457 | const func_val = self.air.value(pl_op.operand) orelse break :blk null; | 1457 | const func_val = self.air.value(pl_op.operand) orelse break :blk null; |
| ... | @@ -1479,7 +1479,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -1479,7 +1479,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 1479 | | 1479 | |
| 1480 | // If we need to pass by reference, but the argument is a constant, | 1480 | // If we need to pass by reference, but the argument is a constant, |
| 1481 | // we must first lower it before passing it. | 1481 | // we must first lower it before passing it. |
| 1482 | if (isByRef(arg_ty) and arg_val == .constant) { | 1482 | if (self.isByRef(arg_ty) and arg_val == .constant) { |
| 1483 | const arg_local = try self.allocStack(arg_ty); | 1483 | const arg_local = try self.allocStack(arg_ty); |
| 1484 | try self.store(arg_local, arg_val, arg_ty, 0); | 1484 | try self.store(arg_local, arg_val, arg_ty, 0); |
| 1485 | try self.emitWValue(arg_local); | 1485 | try self.emitWValue(arg_local); |
| ... | @@ -1591,7 +1591,12 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro | ... | @@ -1591,7 +1591,12 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro |
| 1591 | if (payload_ty.hasCodeGenBits()) { | 1591 | if (payload_ty.hasCodeGenBits()) { |
| 1592 | const payload_local = try self.allocLocal(payload_ty); | 1592 | const payload_local = try self.allocLocal(payload_ty); |
| 1593 | try self.addLabel(.local_set, payload_local.local); | 1593 | try self.addLabel(.local_set, payload_local.local); |
| 1594 | try self.store(lhs, payload_local, payload_ty, payload_offset); | 1594 | if (self.isByRef(payload_ty)) { |
| | 1595 | const ptr = try self.buildPointerOffset(lhs, payload_offset, .new); |
| | 1596 | try self.store(ptr, payload_local, payload_ty, 0); |
| | 1597 | } else { |
| | 1598 | try self.store(lhs, payload_local, payload_ty, payload_offset); |
| | 1599 | } |
| 1595 | } | 1600 | } |
| 1596 | try self.addLabel(.local_set, tag_local.local); | 1601 | try self.addLabel(.local_set, tag_local.local); |
| 1597 | | 1602 | |
| ... | @@ -1608,7 +1613,7 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro | ... | @@ -1608,7 +1613,7 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro |
| 1608 | // Load values from `rhs` stack position and store in `lhs` instead | 1613 | // Load values from `rhs` stack position and store in `lhs` instead |
| 1609 | const tag_local = try self.load(rhs, tag_ty, 0); | 1614 | const tag_local = try self.load(rhs, tag_ty, 0); |
| 1610 | if (payload_ty.hasCodeGenBits()) { | 1615 | if (payload_ty.hasCodeGenBits()) { |
| 1611 | if (isByRef(payload_ty)) { | 1616 | if (self.isByRef(payload_ty)) { |
| 1612 | const payload_ptr = try self.buildPointerOffset(rhs, payload_offset, .new); | 1617 | const payload_ptr = try self.buildPointerOffset(rhs, payload_offset, .new); |
| 1613 | const lhs_payload_ptr = try self.buildPointerOffset(lhs, payload_offset, .new); | 1618 | const lhs_payload_ptr = try self.buildPointerOffset(lhs, payload_offset, .new); |
| 1614 | try self.store(lhs_payload_ptr, payload_ptr, payload_ty, 0); | 1619 | try self.store(lhs_payload_ptr, payload_ptr, payload_ty, 0); |
| ... | @@ -1734,7 +1739,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -1734,7 +1739,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 1734 | | 1739 | |
| 1735 | if (!ty.hasCodeGenBits()) return WValue{ .none = {} }; | 1740 | if (!ty.hasCodeGenBits()) return WValue{ .none = {} }; |
| 1736 | | 1741 | |
| 1737 | if (isByRef(ty)) { | 1742 | if (self.isByRef(ty)) { |
| 1738 | const new_local = try self.allocStack(ty); | 1743 | const new_local = try self.allocStack(ty); |
| 1739 | try self.store(new_local, operand, ty, 0); | 1744 | try self.store(new_local, operand, ty, 0); |
| 1740 | return new_local; | 1745 | return new_local; |
| ... | @@ -1803,6 +1808,11 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue { | ... | @@ -1803,6 +1808,11 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue { |
| 1803 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1808 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1804 | const lhs = self.resolveInst(bin_op.lhs); | 1809 | const lhs = self.resolveInst(bin_op.lhs); |
| 1805 | const rhs = self.resolveInst(bin_op.rhs); | 1810 | const rhs = self.resolveInst(bin_op.rhs); |
| | 1811 | const operand_ty = self.air.typeOfIndex(inst); |
| | 1812 | |
| | 1813 | if (self.isByRef(operand_ty)) { |
| | 1814 | return self.fail("TODO: Implement binary operation for type: {}", .{operand_ty}); |
| | 1815 | } |
| 1806 | | 1816 | |
| 1807 | try self.emitWValue(lhs); | 1817 | try self.emitWValue(lhs); |
| 1808 | try self.emitWValue(rhs); | 1818 | try self.emitWValue(rhs); |
| ... | @@ -1893,9 +1903,7 @@ fn emitConstant(self: *Self, val: Value, ty: Type) InnerError!void { | ... | @@ -1893,9 +1903,7 @@ fn emitConstant(self: *Self, val: Value, ty: Type) InnerError!void { |
| 1893 | const result = try self.allocStack(ty); | 1903 | const result = try self.allocStack(ty); |
| 1894 | var space: Value.BigIntSpace = undefined; | 1904 | var space: Value.BigIntSpace = undefined; |
| 1895 | const bigint = val.toBigInt(&space); | 1905 | const bigint = val.toBigInt(&space); |
| 1896 | if (bigint.limbs.len == 1) { | 1906 | if (bigint.limbs.len == 1 and bigint.limbs[0] == 0) { |
| 1897 | // value is '0'. As wasm's values are zeroed by default, | | |
| 1898 | // just return and pop its stack pointer value. | | |
| 1899 | try self.addLabel(.local_get, result.local); | 1907 | try self.addLabel(.local_get, result.local); |
| 1900 | return; | 1908 | return; |
| 1901 | } | 1909 | } |
| ... | @@ -2277,6 +2285,8 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: std.math.CompareOperator) Inner | ... | @@ -2277,6 +2285,8 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: std.math.CompareOperator) Inner |
| 2277 | // both lhs and rhs, as well as checking the payload are matching of lhs and rhs | 2285 | // both lhs and rhs, as well as checking the payload are matching of lhs and rhs |
| 2278 | return self.cmpOptionals(lhs, rhs, operand_ty, op); | 2286 | return self.cmpOptionals(lhs, rhs, operand_ty, op); |
| 2279 | } | 2287 | } |
| | 2288 | } else if (self.isByRef(operand_ty)) { |
| | 2289 | return self.cmpBigInt(lhs, rhs, operand_ty, op); |
| 2280 | } | 2290 | } |
| 2281 | | 2291 | |
| 2282 | try self.emitWValue(lhs); | 2292 | try self.emitWValue(lhs); |
| ... | @@ -2425,7 +2435,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -2425,7 +2435,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 2425 | return self.fail("Field type '{}' too big to fit into stack frame", .{field_ty}); | 2435 | return self.fail("Field type '{}' too big to fit into stack frame", .{field_ty}); |
| 2426 | }; | 2436 | }; |
| 2427 | | 2437 | |
| 2428 | if (isByRef(field_ty)) { | 2438 | if (self.isByRef(field_ty)) { |
| 2429 | return WValue{ .local_with_offset = .{ .local = operand.local, .offset = offset } }; | 2439 | return WValue{ .local_with_offset = .{ .local = operand.local, .offset = offset } }; |
| 2430 | } | 2440 | } |
| 2431 | | 2441 | |
| ... | @@ -2608,13 +2618,16 @@ fn airIsErr(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerError!W | ... | @@ -2608,13 +2618,16 @@ fn airIsErr(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerError!W |
| 2608 | } | 2618 | } |
| 2609 | | 2619 | |
| 2610 | fn airUnwrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | 2620 | fn airUnwrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 2611 | if (self.liveness.isUnused(inst)) return WValue.none; | 2621 | if (self.liveness.isUnused(inst)) return WValue{ .none = {} }; |
| 2612 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2622 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2613 | const operand = self.resolveInst(ty_op.operand); | 2623 | const operand = self.resolveInst(ty_op.operand); |
| 2614 | const err_ty = self.air.typeOf(ty_op.operand); | 2624 | const err_ty = self.air.typeOf(ty_op.operand); |
| 2615 | const payload_ty = err_ty.errorUnionPayload(); | 2625 | const payload_ty = err_ty.errorUnionPayload(); |
| 2616 | if (!payload_ty.hasCodeGenBits()) return WValue.none; | 2626 | if (!payload_ty.hasCodeGenBits()) return WValue{ .none = {} }; |
| 2617 | const offset = @intCast(u32, err_ty.errorUnionSet().abiSize(self.target)); | 2627 | const offset = @intCast(u32, err_ty.errorUnionSet().abiSize(self.target)); |
| | 2628 | if (self.isByRef(payload_ty)) { |
| | 2629 | return self.buildPointerOffset(operand, offset, .new); |
| | 2630 | } |
| 2618 | return try self.load(operand, payload_ty, offset); | 2631 | return try self.load(operand, payload_ty, offset); |
| 2619 | } | 2632 | } |
| 2620 | | 2633 | |
| ... | @@ -2741,7 +2754,7 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -2741,7 +2754,7 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 2741 | | 2754 | |
| 2742 | const offset = opt_ty.abiSize(self.target) - payload_ty.abiSize(self.target); | 2755 | const offset = opt_ty.abiSize(self.target) - payload_ty.abiSize(self.target); |
| 2743 | | 2756 | |
| 2744 | if (isByRef(payload_ty)) { | 2757 | if (self.isByRef(payload_ty)) { |
| 2745 | return self.buildPointerOffset(operand, offset, .new); | 2758 | return self.buildPointerOffset(operand, offset, .new); |
| 2746 | } | 2759 | } |
| 2747 | | 2760 | |
| ... | @@ -2872,7 +2885,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -2872,7 +2885,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 2872 | const result = try self.allocLocal(elem_ty); | 2885 | const result = try self.allocLocal(elem_ty); |
| 2873 | try self.addLabel(.local_set, result.local); | 2886 | try self.addLabel(.local_set, result.local); |
| 2874 | | 2887 | |
| 2875 | if (isByRef(elem_ty)) { | 2888 | if (self.isByRef(elem_ty)) { |
| 2876 | return result; | 2889 | return result; |
| 2877 | } | 2890 | } |
| 2878 | return try self.load(result, elem_ty, 0); | 2891 | return try self.load(result, elem_ty, 0); |
| ... | @@ -3033,7 +3046,7 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -3033,7 +3046,7 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 3033 | | 3046 | |
| 3034 | const result = try self.allocLocal(elem_ty); | 3047 | const result = try self.allocLocal(elem_ty); |
| 3035 | try self.addLabel(.local_set, result.local); | 3048 | try self.addLabel(.local_set, result.local); |
| 3036 | if (isByRef(elem_ty)) { | 3049 | if (self.isByRef(elem_ty)) { |
| 3037 | return result; | 3050 | return result; |
| 3038 | } | 3051 | } |
| 3039 | return try self.load(result, elem_ty, 0); | 3052 | return try self.load(result, elem_ty, 0); |
| ... | @@ -3183,7 +3196,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -3183,7 +3196,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 3183 | const result = try self.allocLocal(elem_ty); | 3196 | const result = try self.allocLocal(elem_ty); |
| 3184 | try self.addLabel(.local_set, result.local); | 3197 | try self.addLabel(.local_set, result.local); |
| 3185 | | 3198 | |
| 3186 | if (isByRef(elem_ty)) { | 3199 | if (self.isByRef(elem_ty)) { |
| 3187 | return result; | 3200 | return result; |
| 3188 | } | 3201 | } |
| 3189 | return try self.load(result, elem_ty, 0); | 3202 | return try self.load(result, elem_ty, 0); |
| ... | @@ -3244,10 +3257,43 @@ fn cmpOptionals(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std | ... | @@ -3244,10 +3257,43 @@ fn cmpOptionals(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std |
| 3244 | try self.addLabel(.local_set, result.local); | 3257 | try self.addLabel(.local_set, result.local); |
| 3245 | try self.endBlock(); | 3258 | try self.endBlock(); |
| 3246 | | 3259 | |
| 3247 | const is_equal = try self.allocLocal(Type.initTag(.i32)); | | |
| 3248 | try self.emitWValue(result); | 3260 | try self.emitWValue(result); |
| 3249 | try self.addImm32(0); | 3261 | try self.addImm32(0); |
| 3250 | try self.addTag(if (op == .eq) .i32_ne else .i32_eq); | 3262 | try self.addTag(if (op == .eq) .i32_ne else .i32_eq); |
| 3251 | try self.addLabel(.local_set, is_equal.local); | 3263 | try self.addLabel(.local_set, result.local); |
| 3252 | return is_equal; | 3264 | return result; |
| | 3265 | } |
| | 3266 | |
| | 3267 | /// Compares big integers by checking both its high bits and low bits. |
| | 3268 | /// TODO: Lower this to compiler_rt call |
| | 3269 | fn cmpBigInt(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.math.CompareOperator) InnerError!WValue { |
| | 3270 | if (operand_ty.intInfo(self.target).bits > 128) { |
| | 3271 | return self.fail("TODO: Support cmpBigInt for integer bitsize: '{d}'", .{operand_ty.intInfo(self.target).bits}); |
| | 3272 | } |
| | 3273 | |
| | 3274 | const result = try self.allocLocal(Type.initTag(.i32)); |
| | 3275 | { |
| | 3276 | try self.startBlock(.block, wasm.block_empty); |
| | 3277 | const lhs_high_bit = try self.load(lhs, Type.initTag(.u64), 0); |
| | 3278 | const lhs_low_bit = try self.load(lhs, Type.initTag(.u64), 8); |
| | 3279 | const rhs_high_bit = try self.load(rhs, Type.initTag(.u64), 0); |
| | 3280 | const rhs_low_bit = try self.load(rhs, Type.initTag(.u64), 8); |
| | 3281 | try self.emitWValue(lhs_high_bit); |
| | 3282 | try self.emitWValue(rhs_high_bit); |
| | 3283 | try self.addTag(.i64_ne); |
| | 3284 | try self.addLabel(.br_if, 0); |
| | 3285 | try self.emitWValue(lhs_low_bit); |
| | 3286 | try self.emitWValue(rhs_low_bit); |
| | 3287 | try self.addTag(.i64_ne); |
| | 3288 | try self.addLabel(.br_if, 0); |
| | 3289 | try self.addImm32(1); |
| | 3290 | try self.addLabel(.local_set, result.local); |
| | 3291 | try self.endBlock(); |
| | 3292 | } |
| | 3293 | |
| | 3294 | try self.emitWValue(result); |
| | 3295 | try self.addImm32(0); |
| | 3296 | try self.addTag(if (op == .eq) .i32_ne else .i32_eq); |
| | 3297 | try self.addLabel(.local_set, result.local); |
| | 3298 | return result; |
| 3253 | } | 3299 | } |