mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 06:13:07 +00:00
stage2-wasm: fix big int comparison
Unexpected to be found only now
This commit is contained in:
parent
a57479afc2
commit
d1bd9518f9
@ -2675,41 +2675,41 @@ fn binOpBigInt(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) Inner
|
|||||||
.@"and", .@"or", .xor => {
|
.@"and", .@"or", .xor => {
|
||||||
const result = try func.allocStack(ty);
|
const result = try func.allocStack(ty);
|
||||||
try func.emitWValue(result);
|
try func.emitWValue(result);
|
||||||
const lhs_high_bit = try func.load(lhs, Type.u64, 0);
|
const lhs_low_bit = try func.load(lhs, Type.u64, 0);
|
||||||
const rhs_high_bit = try func.load(rhs, Type.u64, 0);
|
const rhs_low_bit = try func.load(rhs, Type.u64, 0);
|
||||||
const op_high_bit = try func.binOp(lhs_high_bit, rhs_high_bit, Type.u64, op);
|
const op_low_bit = try func.binOp(lhs_low_bit, rhs_low_bit, Type.u64, op);
|
||||||
try func.store(.stack, op_high_bit, Type.u64, result.offset());
|
try func.store(.stack, op_low_bit, Type.u64, result.offset());
|
||||||
|
|
||||||
try func.emitWValue(result);
|
try func.emitWValue(result);
|
||||||
const lhs_low_bit = try func.load(lhs, Type.u64, 8);
|
const lhs_high_bit = try func.load(lhs, Type.u64, 8);
|
||||||
const rhs_low_bit = try func.load(rhs, Type.u64, 8);
|
const rhs_high_bit = try func.load(rhs, Type.u64, 8);
|
||||||
const op_low_bit = try func.binOp(lhs_low_bit, rhs_low_bit, Type.u64, op);
|
const op_high_bit = try func.binOp(lhs_high_bit, rhs_high_bit, Type.u64, op);
|
||||||
try func.store(.stack, op_low_bit, Type.u64, result.offset() + 8);
|
try func.store(.stack, op_high_bit, Type.u64, result.offset() + 8);
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
.add, .sub => {
|
.add, .sub => {
|
||||||
const result = try func.allocStack(ty);
|
const result = try func.allocStack(ty);
|
||||||
var lhs_high_bit = try (try func.load(lhs, Type.u64, 0)).toLocal(func, Type.u64);
|
var lhs_low_bit = try (try func.load(lhs, Type.u64, 0)).toLocal(func, Type.u64);
|
||||||
defer lhs_high_bit.free(func);
|
defer lhs_low_bit.free(func);
|
||||||
var rhs_high_bit = try (try func.load(rhs, Type.u64, 0)).toLocal(func, Type.u64);
|
var rhs_low_bit = try (try func.load(rhs, Type.u64, 0)).toLocal(func, Type.u64);
|
||||||
defer rhs_high_bit.free(func);
|
defer rhs_low_bit.free(func);
|
||||||
var high_op_res = try (try func.binOp(lhs_high_bit, rhs_high_bit, Type.u64, op)).toLocal(func, Type.u64);
|
var low_op_res = try (try func.binOp(lhs_low_bit, rhs_low_bit, Type.u64, op)).toLocal(func, Type.u64);
|
||||||
defer high_op_res.free(func);
|
defer low_op_res.free(func);
|
||||||
|
|
||||||
const lhs_low_bit = try func.load(lhs, Type.u64, 8);
|
const lhs_high_bit = try func.load(lhs, Type.u64, 8);
|
||||||
const rhs_low_bit = try func.load(rhs, Type.u64, 8);
|
const rhs_high_bit = try func.load(rhs, Type.u64, 8);
|
||||||
const low_op_res = try func.binOp(lhs_low_bit, rhs_low_bit, Type.u64, op);
|
const high_op_res = try func.binOp(lhs_high_bit, rhs_high_bit, Type.u64, op);
|
||||||
|
|
||||||
const lt = if (op == .add) blk: {
|
const lt = if (op == .add) blk: {
|
||||||
break :blk try func.cmp(high_op_res, rhs_high_bit, Type.u64, .lt);
|
break :blk try func.cmp(low_op_res, rhs_low_bit, Type.u64, .lt);
|
||||||
} else if (op == .sub) blk: {
|
} else if (op == .sub) blk: {
|
||||||
break :blk try func.cmp(lhs_high_bit, rhs_high_bit, Type.u64, .lt);
|
break :blk try func.cmp(lhs_low_bit, rhs_low_bit, Type.u64, .lt);
|
||||||
} else unreachable;
|
} else unreachable;
|
||||||
const tmp = try func.intcast(lt, Type.u32, Type.u64);
|
const tmp = try func.intcast(lt, Type.u32, Type.u64);
|
||||||
var tmp_op = try (try func.binOp(low_op_res, tmp, Type.u64, op)).toLocal(func, Type.u64);
|
var tmp_op = try (try func.binOp(high_op_res, tmp, Type.u64, op)).toLocal(func, Type.u64);
|
||||||
defer tmp_op.free(func);
|
defer tmp_op.free(func);
|
||||||
|
|
||||||
try func.store(result, high_op_res, Type.u64, 0);
|
try func.store(result, low_op_res, Type.u64, 0);
|
||||||
try func.store(result, tmp_op, Type.u64, 8);
|
try func.store(result, tmp_op, Type.u64, 8);
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
@ -5523,16 +5523,16 @@ fn cmpBigInt(func: *CodeGen, lhs: WValue, rhs: WValue, operand_ty: Type, op: std
|
|||||||
return func.fail("TODO: Support cmpBigInt for integer bitsize: '{d}'", .{operand_ty.bitSize(pt)});
|
return func.fail("TODO: Support cmpBigInt for integer bitsize: '{d}'", .{operand_ty.bitSize(pt)});
|
||||||
}
|
}
|
||||||
|
|
||||||
var lhs_high_bit = try (try func.load(lhs, Type.u64, 0)).toLocal(func, Type.u64);
|
var lhs_high_bit = try (try func.load(lhs, Type.u64, 8)).toLocal(func, Type.u64);
|
||||||
defer lhs_high_bit.free(func);
|
defer lhs_high_bit.free(func);
|
||||||
var rhs_high_bit = try (try func.load(rhs, Type.u64, 0)).toLocal(func, Type.u64);
|
var rhs_high_bit = try (try func.load(rhs, Type.u64, 8)).toLocal(func, Type.u64);
|
||||||
defer rhs_high_bit.free(func);
|
defer rhs_high_bit.free(func);
|
||||||
|
|
||||||
switch (op) {
|
switch (op) {
|
||||||
.eq, .neq => {
|
.eq, .neq => {
|
||||||
const xor_high = try func.binOp(lhs_high_bit, rhs_high_bit, Type.u64, .xor);
|
const xor_high = try func.binOp(lhs_high_bit, rhs_high_bit, Type.u64, .xor);
|
||||||
const lhs_low_bit = try func.load(lhs, Type.u64, 8);
|
const lhs_low_bit = try func.load(lhs, Type.u64, 0);
|
||||||
const rhs_low_bit = try func.load(rhs, Type.u64, 8);
|
const rhs_low_bit = try func.load(rhs, Type.u64, 0);
|
||||||
const xor_low = try func.binOp(lhs_low_bit, rhs_low_bit, Type.u64, .xor);
|
const xor_low = try func.binOp(lhs_low_bit, rhs_low_bit, Type.u64, .xor);
|
||||||
const or_result = try func.binOp(xor_high, xor_low, Type.u64, .@"or");
|
const or_result = try func.binOp(xor_high, xor_low, Type.u64, .@"or");
|
||||||
|
|
||||||
@ -5545,9 +5545,9 @@ fn cmpBigInt(func: *CodeGen, lhs: WValue, rhs: WValue, operand_ty: Type, op: std
|
|||||||
else => {
|
else => {
|
||||||
const ty = if (operand_ty.isSignedInt(mod)) Type.i64 else Type.u64;
|
const ty = if (operand_ty.isSignedInt(mod)) Type.i64 else Type.u64;
|
||||||
// leave those value on top of the stack for '.select'
|
// leave those value on top of the stack for '.select'
|
||||||
const lhs_low_bit = try func.load(lhs, Type.u64, 8);
|
const lhs_low_bit = try func.load(lhs, Type.u64, 0);
|
||||||
const rhs_low_bit = try func.load(rhs, Type.u64, 8);
|
const rhs_low_bit = try func.load(rhs, Type.u64, 0);
|
||||||
_ = try func.cmp(lhs_low_bit, rhs_low_bit, ty, op);
|
_ = try func.cmp(lhs_low_bit, rhs_low_bit, Type.u64, op);
|
||||||
_ = try func.cmp(lhs_high_bit, rhs_high_bit, ty, op);
|
_ = try func.cmp(lhs_high_bit, rhs_high_bit, ty, op);
|
||||||
_ = try func.cmp(lhs_high_bit, rhs_high_bit, ty, .eq);
|
_ = try func.cmp(lhs_high_bit, rhs_high_bit, ty, .eq);
|
||||||
try func.addTag(.select);
|
try func.addTag(.select);
|
||||||
|
|||||||
@ -1134,55 +1134,80 @@ test "pointer to struct literal with runtime field is constant" {
|
|||||||
try expect(@typeInfo(@TypeOf(ptr)).Pointer.is_const);
|
try expect(@typeInfo(@TypeOf(ptr)).Pointer.is_const);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "integer compare" {
|
fn testSignedCmp(comptime T: type) !void {
|
||||||
|
var z: T = 0;
|
||||||
|
var p: T = 123;
|
||||||
|
var n: T = -123;
|
||||||
|
var min: T = std.math.minInt(T);
|
||||||
|
var max: T = std.math.maxInt(T);
|
||||||
|
var half_min: T = std.math.minInt(T) / 2;
|
||||||
|
var half_max: T = std.math.minInt(T) / 2;
|
||||||
|
_ = .{ &z, &p, &n, &min, &max, &half_min, &half_max };
|
||||||
|
try expect(z == z and z != p and z != n);
|
||||||
|
try expect(p == p and p != n and n == n);
|
||||||
|
try expect(z > n and z < p and z >= n and z <= p);
|
||||||
|
try expect(!(z < n or z > p or z <= n or z >= p or z > z or z < z));
|
||||||
|
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);
|
||||||
|
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));
|
||||||
|
try expect(z == 0 and z != 123 and z != -123 and 0 == z and 0 != p and 0 != n);
|
||||||
|
try expect(z > -123 and p > -123 and !(n > 123));
|
||||||
|
try expect(z < 123 and !(p < 123) and n < 123);
|
||||||
|
try expect(-123 <= z and -123 <= p and -123 <= n);
|
||||||
|
try expect(123 >= z and 123 >= p and 123 >= n);
|
||||||
|
try expect(!(0 != z or 123 != p or -123 != n));
|
||||||
|
try expect(!(z > 0 or -123 > p or 123 < n));
|
||||||
|
|
||||||
|
try expect(min <= max and z <= max and p <= max and n <= max and half_max <= max and half_min <= max);
|
||||||
|
try expect(min <= max and min <= z and min <= p and min <= n and min <= half_min and min <= half_max);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn testUnsignedCmp(comptime T: type) !void {
|
||||||
|
var z: T = 0;
|
||||||
|
var p: T = 123;
|
||||||
|
var max: T = std.math.maxInt(T);
|
||||||
|
var half_max: T = std.math.minInt(T) / 2;
|
||||||
|
_ = .{ &z, &p, &max, &half_max };
|
||||||
|
try expect(z == z and z != p);
|
||||||
|
try expect(p == p);
|
||||||
|
try expect(z < p and z <= p);
|
||||||
|
try expect(!(z > p or z >= p or z > z or z < z));
|
||||||
|
try expect(p >= p and p <= p);
|
||||||
|
try expect(!(p > p or p < p));
|
||||||
|
try expect(z == 0 and z != 123 and z != -123 and 0 == z and 0 != p);
|
||||||
|
try expect(z > -123 and p > -123);
|
||||||
|
try expect(z < 123 and !(p < 123));
|
||||||
|
try expect(-123 <= z and -123 <= p);
|
||||||
|
try expect(123 >= z and 123 >= p);
|
||||||
|
try expect(!(0 != z or 123 != p));
|
||||||
|
try expect(!(z > 0 or -123 > p));
|
||||||
|
|
||||||
|
try expect(z <= max and p <= max and half_max <= max);
|
||||||
|
try expect(half_max != max);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "integer compare <= 64 bits" {
|
||||||
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
|
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
|
||||||
|
|
||||||
const S = struct {
|
|
||||||
fn doTheTestSigned(comptime T: type) !void {
|
|
||||||
var z: T = 0;
|
|
||||||
var p: T = 123;
|
|
||||||
var n: T = -123;
|
|
||||||
_ = .{ &z, &p, &n };
|
|
||||||
try expect(z == z and z != p and z != n);
|
|
||||||
try expect(p == p and p != n and n == n);
|
|
||||||
try expect(z > n and z < p and z >= n and z <= p);
|
|
||||||
try expect(!(z < n or z > p or z <= n or z >= p or z > z or z < z));
|
|
||||||
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);
|
|
||||||
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));
|
|
||||||
try expect(z == 0 and z != 123 and z != -123 and 0 == z and 0 != p and 0 != n);
|
|
||||||
try expect(z > -123 and p > -123 and !(n > 123));
|
|
||||||
try expect(z < 123 and !(p < 123) and n < 123);
|
|
||||||
try expect(-123 <= z and -123 <= p and -123 <= n);
|
|
||||||
try expect(123 >= z and 123 >= p and 123 >= n);
|
|
||||||
try expect(!(0 != z or 123 != p or -123 != n));
|
|
||||||
try expect(!(z > 0 or -123 > p or 123 < n));
|
|
||||||
}
|
|
||||||
fn doTheTestUnsigned(comptime T: type) !void {
|
|
||||||
var z: T = 0;
|
|
||||||
var p: T = 123;
|
|
||||||
_ = .{ &z, &p };
|
|
||||||
try expect(z == z and z != p);
|
|
||||||
try expect(p == p);
|
|
||||||
try expect(z < p and z <= p);
|
|
||||||
try expect(!(z > p or z >= p or z > z or z < z));
|
|
||||||
try expect(p >= p and p <= p);
|
|
||||||
try expect(!(p > p or p < p));
|
|
||||||
try expect(z == 0 and z != 123 and z != -123 and 0 == z and 0 != p);
|
|
||||||
try expect(z > -123 and p > -123);
|
|
||||||
try expect(z < 123 and !(p < 123));
|
|
||||||
try expect(-123 <= z and -123 <= p);
|
|
||||||
try expect(123 >= z and 123 >= p);
|
|
||||||
try expect(!(0 != z or 123 != p));
|
|
||||||
try expect(!(z > 0 or -123 > p));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
inline for (.{ u8, u16, u32, u64, usize, u10, u20, u30, u60 }) |T| {
|
inline for (.{ u8, u16, u32, u64, usize, u10, u20, u30, u60 }) |T| {
|
||||||
try S.doTheTestUnsigned(T);
|
try testUnsignedCmp(T);
|
||||||
try comptime S.doTheTestUnsigned(T);
|
try comptime testUnsignedCmp(T);
|
||||||
}
|
}
|
||||||
inline for (.{ i8, i16, i32, i64, isize, i10, i20, i30, i60 }) |T| {
|
inline for (.{ i8, i16, i32, i64, isize, i10, i20, i30, i60 }) |T| {
|
||||||
try S.doTheTestSigned(T);
|
try testSignedCmp(T);
|
||||||
try comptime S.doTheTestSigned(T);
|
try comptime testSignedCmp(T);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "integer compare <= 128 bits" {
|
||||||
|
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
|
||||||
|
|
||||||
|
inline for (.{ u65, u96, u127, u128 }) |T| {
|
||||||
|
try testUnsignedCmp(T);
|
||||||
|
try comptime testUnsignedCmp(T);
|
||||||
|
}
|
||||||
|
inline for (.{ i65, i96, i127, i128 }) |T| {
|
||||||
|
try testSignedCmp(T);
|
||||||
|
try comptime testSignedCmp(T);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user