stage2 sema: Implement comptime result for comparison of uint to comptime value

This adds a comptime result when comparing a comptime value to an
unsigned integer. For example:
   ( 0 <= (unsigned runtime value)) => true
   (-1 <  (unsigned runtime value)) => true
   ((unsigned runtime value) < -15) => false
This commit is contained in:
Cody Tapscott
2022-02-27 01:19:02 -07:00
parent b52948444f
commit a7a508fcd9
2 changed files with 38 additions and 18 deletions

View File

@@ -17036,30 +17036,41 @@ fn cmpNumeric(
if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lhs_val| {
if (lhs_val.isUndef())
return sema.addConstUndef(Type.bool);
const is_unsigned = if (lhs_is_float) x: {
if (!rhs_is_signed) {
switch (lhs_val.orderAgainstZero()) {
.gt => {},
.eq => switch (op) { // LHS = 0, RHS is unsigned
.lte => return Air.Inst.Ref.bool_true,
.gt => return Air.Inst.Ref.bool_false,
else => {},
},
.lt => switch (op) { // LHS < 0, RHS is unsigned
.neq, .lt, .lte => return Air.Inst.Ref.bool_true,
.eq, .gt, .gte => return Air.Inst.Ref.bool_false,
},
}
}
if (lhs_is_float) {
var bigint_space: Value.BigIntSpace = undefined;
var bigint = try lhs_val.toBigInt(&bigint_space).toManaged(sema.gpa);
defer bigint.deinit();
const zcmp = lhs_val.orderAgainstZero();
if (lhs_val.floatHasFraction()) {
switch (op) {
.eq => return Air.Inst.Ref.bool_false,
.neq => return Air.Inst.Ref.bool_true,
else => {},
}
if (zcmp == .lt) {
if (lhs_is_signed) {
try bigint.addScalar(bigint.toConst(), -1);
} else {
try bigint.addScalar(bigint.toConst(), 1);
}
}
lhs_bits = bigint.toConst().bitCountTwosComp();
break :x (zcmp != .lt);
} else x: {
} else {
lhs_bits = lhs_val.intBitCountTwosComp(target);
break :x (lhs_val.orderAgainstZero() != .lt);
};
lhs_bits += @boolToInt(is_unsigned and dest_int_is_signed);
}
lhs_bits += @boolToInt(!lhs_is_signed and dest_int_is_signed);
} else if (lhs_is_float) {
dest_float_type = lhs_ty;
} else {
@@ -17071,30 +17082,41 @@ fn cmpNumeric(
if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rhs_val| {
if (rhs_val.isUndef())
return sema.addConstUndef(Type.bool);
const is_unsigned = if (rhs_is_float) x: {
if (!lhs_is_signed) {
switch (rhs_val.orderAgainstZero()) {
.gt => {},
.eq => switch (op) { // RHS = 0, LHS is unsigned
.gte => return Air.Inst.Ref.bool_true,
.lt => return Air.Inst.Ref.bool_false,
else => {},
},
.lt => switch (op) { // RHS < 0, LHS is unsigned
.neq, .gt, .gte => return Air.Inst.Ref.bool_true,
.eq, .lt, .lte => return Air.Inst.Ref.bool_false,
},
}
}
if (rhs_is_float) {
var bigint_space: Value.BigIntSpace = undefined;
var bigint = try rhs_val.toBigInt(&bigint_space).toManaged(sema.gpa);
defer bigint.deinit();
const zcmp = rhs_val.orderAgainstZero();
if (rhs_val.floatHasFraction()) {
switch (op) {
.eq => return Air.Inst.Ref.bool_false,
.neq => return Air.Inst.Ref.bool_true,
else => {},
}
if (zcmp == .lt) {
if (rhs_is_signed) {
try bigint.addScalar(bigint.toConst(), -1);
} else {
try bigint.addScalar(bigint.toConst(), 1);
}
}
rhs_bits = bigint.toConst().bitCountTwosComp();
break :x (zcmp != .lt);
} else x: {
} else {
rhs_bits = rhs_val.intBitCountTwosComp(target);
break :x (rhs_val.orderAgainstZero() != .lt);
};
rhs_bits += @boolToInt(is_unsigned and dest_int_is_signed);
}
rhs_bits += @boolToInt(!rhs_is_signed and dest_int_is_signed);
} else if (rhs_is_float) {
dest_float_type = rhs_ty;
} else {

View File

@@ -559,8 +559,6 @@ fn modifySomeBytes(bytes: []u8) void {
}
test "comparisons 0 <= uint and 0 > uint should be comptime" {
if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
testCompTimeUIntComparisons(1234);
}
fn testCompTimeUIntComparisons(x: u32) void {