authorgravatar for paul.verigo@gmail.comPavel Verigo <paul.verigo@gmail.com> 2024-07-18 17:18:17+02:00
committergravatar for paul.verigo@gmail.comPavel Verigo <paul.verigo@gmail.com> 2024-07-18 17:18:17+02:00
logd1bd9518f97abc9ab80795962b8e0dfd8e4d8768
tree4e41594948a124da7f8e41602807f9ee3fefdcf7
parenta57479afc2cea1b7c2c6802b7e8a1a7db973a3a3

stage2-wasm: fix big int comparison

Unexpected to be found only now

2 files changed, 97 insertions(+), 72 deletions(-)

src/arch/wasm/CodeGen.zig+28-28
...@@ -2675,41 +2675,41 @@ fn binOpBigInt(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) Inner...@@ -2675,41 +2675,41 @@ fn binOpBigInt(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) Inner
2675 .@"and", .@"or", .xor => {2675 .@"and", .@"or", .xor => {
2676 const result = try func.allocStack(ty);2676 const result = try func.allocStack(ty);
2677 try func.emitWValue(result);2677 try func.emitWValue(result);
2678 const lhs_high_bit = try func.load(lhs, Type.u64, 0);2678 const lhs_low_bit = try func.load(lhs, Type.u64, 0);
2679 const rhs_high_bit = try func.load(rhs, Type.u64, 0);2679 const rhs_low_bit = try func.load(rhs, Type.u64, 0);
2680 const op_high_bit = try func.binOp(lhs_high_bit, rhs_high_bit, Type.u64, op);2680 const op_low_bit = try func.binOp(lhs_low_bit, rhs_low_bit, Type.u64, op);
2681 try func.store(.stack, op_high_bit, Type.u64, result.offset());2681 try func.store(.stack, op_low_bit, Type.u64, result.offset());
26822682
2683 try func.emitWValue(result);2683 try func.emitWValue(result);
2684 const lhs_low_bit = try func.load(lhs, Type.u64, 8);2684 const lhs_high_bit = try func.load(lhs, Type.u64, 8);
2685 const rhs_low_bit = try func.load(rhs, Type.u64, 8);2685 const rhs_high_bit = try func.load(rhs, Type.u64, 8);
2686 const op_low_bit = try func.binOp(lhs_low_bit, rhs_low_bit, Type.u64, op);2686 const op_high_bit = try func.binOp(lhs_high_bit, rhs_high_bit, Type.u64, op);
2687 try func.store(.stack, op_low_bit, Type.u64, result.offset() + 8);2687 try func.store(.stack, op_high_bit, Type.u64, result.offset() + 8);
2688 return result;2688 return result;
2689 },2689 },
2690 .add, .sub => {2690 .add, .sub => {
2691 const result = try func.allocStack(ty);2691 const result = try func.allocStack(ty);
2692 var lhs_high_bit = try (try func.load(lhs, Type.u64, 0)).toLocal(func, Type.u64);2692 var lhs_low_bit = try (try func.load(lhs, Type.u64, 0)).toLocal(func, Type.u64);
2693 defer lhs_high_bit.free(func);2693 defer lhs_low_bit.free(func);
2694 var rhs_high_bit = try (try func.load(rhs, Type.u64, 0)).toLocal(func, Type.u64);2694 var rhs_low_bit = try (try func.load(rhs, Type.u64, 0)).toLocal(func, Type.u64);
2695 defer rhs_high_bit.free(func);2695 defer rhs_low_bit.free(func);
2696 var high_op_res = try (try func.binOp(lhs_high_bit, rhs_high_bit, Type.u64, op)).toLocal(func, Type.u64);2696 var low_op_res = try (try func.binOp(lhs_low_bit, rhs_low_bit, Type.u64, op)).toLocal(func, Type.u64);
2697 defer high_op_res.free(func);2697 defer low_op_res.free(func);
26982698
2699 const lhs_low_bit = try func.load(lhs, Type.u64, 8);2699 const lhs_high_bit = try func.load(lhs, Type.u64, 8);
2700 const rhs_low_bit = try func.load(rhs, Type.u64, 8);2700 const rhs_high_bit = try func.load(rhs, Type.u64, 8);
2701 const low_op_res = try func.binOp(lhs_low_bit, rhs_low_bit, Type.u64, op);2701 const high_op_res = try func.binOp(lhs_high_bit, rhs_high_bit, Type.u64, op);
27022702
2703 const lt = if (op == .add) blk: {2703 const lt = if (op == .add) blk: {
2704 break :blk try func.cmp(high_op_res, rhs_high_bit, Type.u64, .lt);2704 break :blk try func.cmp(low_op_res, rhs_low_bit, Type.u64, .lt);
2705 } else if (op == .sub) blk: {2705 } else if (op == .sub) blk: {
2706 break :blk try func.cmp(lhs_high_bit, rhs_high_bit, Type.u64, .lt);2706 break :blk try func.cmp(lhs_low_bit, rhs_low_bit, Type.u64, .lt);
2707 } else unreachable;2707 } else unreachable;
2708 const tmp = try func.intcast(lt, Type.u32, Type.u64);2708 const tmp = try func.intcast(lt, Type.u32, Type.u64);
2709 var tmp_op = try (try func.binOp(low_op_res, tmp, Type.u64, op)).toLocal(func, Type.u64);2709 var tmp_op = try (try func.binOp(high_op_res, tmp, Type.u64, op)).toLocal(func, Type.u64);
2710 defer tmp_op.free(func);2710 defer tmp_op.free(func);
27112711
2712 try func.store(result, high_op_res, Type.u64, 0);2712 try func.store(result, low_op_res, Type.u64, 0);
2713 try func.store(result, tmp_op, Type.u64, 8);2713 try func.store(result, tmp_op, Type.u64, 8);
2714 return result;2714 return result;
2715 },2715 },
...@@ -5523,16 +5523,16 @@ fn cmpBigInt(func: *CodeGen, lhs: WValue, rhs: WValue, operand_ty: Type, op: std...@@ -5523,16 +5523,16 @@ fn cmpBigInt(func: *CodeGen, lhs: WValue, rhs: WValue, operand_ty: Type, op: std
5523 return func.fail("TODO: Support cmpBigInt for integer bitsize: '{d}'", .{operand_ty.bitSize(pt)});5523 return func.fail("TODO: Support cmpBigInt for integer bitsize: '{d}'", .{operand_ty.bitSize(pt)});
5524 }5524 }
55255525
5526 var lhs_high_bit = try (try func.load(lhs, Type.u64, 0)).toLocal(func, Type.u64);5526 var lhs_high_bit = try (try func.load(lhs, Type.u64, 8)).toLocal(func, Type.u64);
5527 defer lhs_high_bit.free(func);5527 defer lhs_high_bit.free(func);
5528 var rhs_high_bit = try (try func.load(rhs, Type.u64, 0)).toLocal(func, Type.u64);5528 var rhs_high_bit = try (try func.load(rhs, Type.u64, 8)).toLocal(func, Type.u64);
5529 defer rhs_high_bit.free(func);5529 defer rhs_high_bit.free(func);
55305530
5531 switch (op) {5531 switch (op) {
5532 .eq, .neq => {5532 .eq, .neq => {
5533 const xor_high = try func.binOp(lhs_high_bit, rhs_high_bit, Type.u64, .xor);5533 const xor_high = try func.binOp(lhs_high_bit, rhs_high_bit, Type.u64, .xor);
5534 const lhs_low_bit = try func.load(lhs, Type.u64, 8);5534 const lhs_low_bit = try func.load(lhs, Type.u64, 0);
5535 const rhs_low_bit = try func.load(rhs, Type.u64, 8);5535 const rhs_low_bit = try func.load(rhs, Type.u64, 0);
5536 const xor_low = try func.binOp(lhs_low_bit, rhs_low_bit, Type.u64, .xor);5536 const xor_low = try func.binOp(lhs_low_bit, rhs_low_bit, Type.u64, .xor);
5537 const or_result = try func.binOp(xor_high, xor_low, Type.u64, .@"or");5537 const or_result = try func.binOp(xor_high, xor_low, Type.u64, .@"or");
55385538
...@@ -5545,9 +5545,9 @@ fn cmpBigInt(func: *CodeGen, lhs: WValue, rhs: WValue, operand_ty: Type, op: std...@@ -5545,9 +5545,9 @@ fn cmpBigInt(func: *CodeGen, lhs: WValue, rhs: WValue, operand_ty: Type, op: std
5545 else => {5545 else => {
5546 const ty = if (operand_ty.isSignedInt(mod)) Type.i64 else Type.u64;5546 const ty = if (operand_ty.isSignedInt(mod)) Type.i64 else Type.u64;
5547 // leave those value on top of the stack for '.select'5547 // leave those value on top of the stack for '.select'
5548 const lhs_low_bit = try func.load(lhs, Type.u64, 8);5548 const lhs_low_bit = try func.load(lhs, Type.u64, 0);
5549 const rhs_low_bit = try func.load(rhs, Type.u64, 8);5549 const rhs_low_bit = try func.load(rhs, Type.u64, 0);
5550 _ = try func.cmp(lhs_low_bit, rhs_low_bit, ty, op);5550 _ = try func.cmp(lhs_low_bit, rhs_low_bit, Type.u64, op);
5551 _ = try func.cmp(lhs_high_bit, rhs_high_bit, ty, op);5551 _ = try func.cmp(lhs_high_bit, rhs_high_bit, ty, op);
5552 _ = try func.cmp(lhs_high_bit, rhs_high_bit, ty, .eq);5552 _ = try func.cmp(lhs_high_bit, rhs_high_bit, ty, .eq);
5553 try func.addTag(.select);5553 try func.addTag(.select);
test/behavior/basic.zig+69-44
...@@ -1134,55 +1134,80 @@ test "pointer to struct literal with runtime field is constant" {...@@ -1134,55 +1134,80 @@ test "pointer to struct literal with runtime field is constant" {
1134 try expect(@typeInfo(@TypeOf(ptr)).Pointer.is_const);1134 try expect(@typeInfo(@TypeOf(ptr)).Pointer.is_const);
1135}1135}
11361136
1137test "integer compare" {1137fn testSignedCmp(comptime T: type) !void {
1138 var z: T = 0;
1139 var p: T = 123;
1140 var n: T = -123;
1141 var min: T = std.math.minInt(T);
1142 var max: T = std.math.maxInt(T);
1143 var half_min: T = std.math.minInt(T) / 2;
1144 var half_max: T = std.math.minInt(T) / 2;
1145 _ = .{ &z, &p, &n, &min, &max, &half_min, &half_max };
1146 try expect(z == z and z != p and z != n);
1147 try expect(p == p and p != n and n == n);
1148 try expect(z > n and z < p and z >= n and z <= p);
1149 try expect(!(z < n or z > p or z <= n or z >= p or z > z or z < z));
1150 try expect(p > n and n < p and p >= n and n <= p and p >= p and p <= p and n >= n and n <= n);
1151 try expect(!(p < n or n > p or p <= n or n >= p or p > p or p < p or n > n or n < n));
1152 try expect(z == 0 and z != 123 and z != -123 and 0 == z and 0 != p and 0 != n);
1153 try expect(z > -123 and p > -123 and !(n > 123));
1154 try expect(z < 123 and !(p < 123) and n < 123);
1155 try expect(-123 <= z and -123 <= p and -123 <= n);
1156 try expect(123 >= z and 123 >= p and 123 >= n);
1157 try expect(!(0 != z or 123 != p or -123 != n));
1158 try expect(!(z > 0 or -123 > p or 123 < n));
1159
1160 try expect(min <= max and z <= max and p <= max and n <= max and half_max <= max and half_min <= max);
1161 try expect(min <= max and min <= z and min <= p and min <= n and min <= half_min and min <= half_max);
1162}
1163
1164fn testUnsignedCmp(comptime T: type) !void {
1165 var z: T = 0;
1166 var p: T = 123;
1167 var max: T = std.math.maxInt(T);
1168 var half_max: T = std.math.minInt(T) / 2;
1169 _ = .{ &z, &p, &max, &half_max };
1170 try expect(z == z and z != p);
1171 try expect(p == p);
1172 try expect(z < p and z <= p);
1173 try expect(!(z > p or z >= p or z > z or z < z));
1174 try expect(p >= p and p <= p);
1175 try expect(!(p > p or p < p));
1176 try expect(z == 0 and z != 123 and z != -123 and 0 == z and 0 != p);
1177 try expect(z > -123 and p > -123);
1178 try expect(z < 123 and !(p < 123));
1179 try expect(-123 <= z and -123 <= p);
1180 try expect(123 >= z and 123 >= p);
1181 try expect(!(0 != z or 123 != p));
1182 try expect(!(z > 0 or -123 > p));
1183
1184 try expect(z <= max and p <= max and half_max <= max);
1185 try expect(half_max != max);
1186}
1187
1188test "integer compare <= 64 bits" {
1138 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1189 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
11391190
1140 const S = struct {
1141 fn doTheTestSigned(comptime T: type) !void {
1142 var z: T = 0;
1143 var p: T = 123;
1144 var n: T = -123;
1145 _ = .{ &z, &p, &n };
1146 try expect(z == z and z != p and z != n);
1147 try expect(p == p and p != n and n == n);
1148 try expect(z > n and z < p and z >= n and z <= p);
1149 try expect(!(z < n or z > p or z <= n or z >= p or z > z or z < z));
1150 try expect(p > n and n < p and p >= n and n <= p and p >= p and p <= p and n >= n and n <= n);
1151 try expect(!(p < n or n > p or p <= n or n >= p or p > p or p < p or n > n or n < n));
1152 try expect(z == 0 and z != 123 and z != -123 and 0 == z and 0 != p and 0 != n);
1153 try expect(z > -123 and p > -123 and !(n > 123));
1154 try expect(z < 123 and !(p < 123) and n < 123);
1155 try expect(-123 <= z and -123 <= p and -123 <= n);
1156 try expect(123 >= z and 123 >= p and 123 >= n);
1157 try expect(!(0 != z or 123 != p or -123 != n));
1158 try expect(!(z > 0 or -123 > p or 123 < n));
1159 }
1160 fn doTheTestUnsigned(comptime T: type) !void {
1161 var z: T = 0;
1162 var p: T = 123;
1163 _ = .{ &z, &p };
1164 try expect(z == z and z != p);
1165 try expect(p == p);
1166 try expect(z < p and z <= p);
1167 try expect(!(z > p or z >= p or z > z or z < z));
1168 try expect(p >= p and p <= p);
1169 try expect(!(p > p or p < p));
1170 try expect(z == 0 and z != 123 and z != -123 and 0 == z and 0 != p);
1171 try expect(z > -123 and p > -123);
1172 try expect(z < 123 and !(p < 123));
1173 try expect(-123 <= z and -123 <= p);
1174 try expect(123 >= z and 123 >= p);
1175 try expect(!(0 != z or 123 != p));
1176 try expect(!(z > 0 or -123 > p));
1177 }
1178 };
1179 inline for (.{ u8, u16, u32, u64, usize, u10, u20, u30, u60 }) |T| {1191 inline for (.{ u8, u16, u32, u64, usize, u10, u20, u30, u60 }) |T| {
1180 try S.doTheTestUnsigned(T);1192 try testUnsignedCmp(T);
1181 try comptime S.doTheTestUnsigned(T);1193 try comptime testUnsignedCmp(T);
1182 }1194 }
1183 inline for (.{ i8, i16, i32, i64, isize, i10, i20, i30, i60 }) |T| {1195 inline for (.{ i8, i16, i32, i64, isize, i10, i20, i30, i60 }) |T| {
1184 try S.doTheTestSigned(T);1196 try testSignedCmp(T);
1185 try comptime S.doTheTestSigned(T);1197 try comptime testSignedCmp(T);
1198 }
1199}
1200
1201test "integer compare <= 128 bits" {
1202 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1203
1204 inline for (.{ u65, u96, u127, u128 }) |T| {
1205 try testUnsignedCmp(T);
1206 try comptime testUnsignedCmp(T);
1207 }
1208 inline for (.{ i65, i96, i127, i128 }) |T| {
1209 try testSignedCmp(T);
1210 try comptime testSignedCmp(T);
1186 }1211 }
1187}1212}
11881213