authorgravatar for topolarity@tapscott.meCody Tapscott <topolarity@tapscott.me> 2022-02-27 01:19:02-07:00
committergravatar for topolarity@tapscott.meCody Tapscott <topolarity@tapscott.me> 2022-02-27 02:24:28-07:00
loga7a508fcd9a961ea9d903f9065556a02b4045b95
tree32a18d391650f39f4b67bf679fc213b2446a6b21
parentb52948444f16c082f0e29bb75b246370c4b11326

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

2 files changed, 38 insertions(+), 18 deletions(-)

src/Sema.zig+38-16
......@@ -17036,30 +17036,41 @@ fn cmpNumeric(
1703617036 if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lhs_val| {
1703717037 if (lhs_val.isUndef())
1703817038 return sema.addConstUndef(Type.bool);
17039 const is_unsigned = if (lhs_is_float) x: {
17039 if (!rhs_is_signed) {
17040 switch (lhs_val.orderAgainstZero()) {
17041 .gt => {},
17042 .eq => switch (op) { // LHS = 0, RHS is unsigned
17043 .lte => return Air.Inst.Ref.bool_true,
17044 .gt => return Air.Inst.Ref.bool_false,
17045 else => {},
17046 },
17047 .lt => switch (op) { // LHS < 0, RHS is unsigned
17048 .neq, .lt, .lte => return Air.Inst.Ref.bool_true,
17049 .eq, .gt, .gte => return Air.Inst.Ref.bool_false,
17050 },
17051 }
17052 }
17053 if (lhs_is_float) {
1704017054 var bigint_space: Value.BigIntSpace = undefined;
1704117055 var bigint = try lhs_val.toBigInt(&bigint_space).toManaged(sema.gpa);
1704217056 defer bigint.deinit();
17043 const zcmp = lhs_val.orderAgainstZero();
1704417057 if (lhs_val.floatHasFraction()) {
1704517058 switch (op) {
1704617059 .eq => return Air.Inst.Ref.bool_false,
1704717060 .neq => return Air.Inst.Ref.bool_true,
1704817061 else => {},
1704917062 }
17050 if (zcmp == .lt) {
17063 if (lhs_is_signed) {
1705117064 try bigint.addScalar(bigint.toConst(), -1);
1705217065 } else {
1705317066 try bigint.addScalar(bigint.toConst(), 1);
1705417067 }
1705517068 }
1705617069 lhs_bits = bigint.toConst().bitCountTwosComp();
17057 break :x (zcmp != .lt);
17058 } else x: {
17070 } else {
1705917071 lhs_bits = lhs_val.intBitCountTwosComp(target);
17060 break :x (lhs_val.orderAgainstZero() != .lt);
17061 };
17062 lhs_bits += @boolToInt(is_unsigned and dest_int_is_signed);
17072 }
17073 lhs_bits += @boolToInt(!lhs_is_signed and dest_int_is_signed);
1706317074 } else if (lhs_is_float) {
1706417075 dest_float_type = lhs_ty;
1706517076 } else {
......@@ -17071,30 +17082,41 @@ fn cmpNumeric(
1707117082 if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rhs_val| {
1707217083 if (rhs_val.isUndef())
1707317084 return sema.addConstUndef(Type.bool);
17074 const is_unsigned = if (rhs_is_float) x: {
17085 if (!lhs_is_signed) {
17086 switch (rhs_val.orderAgainstZero()) {
17087 .gt => {},
17088 .eq => switch (op) { // RHS = 0, LHS is unsigned
17089 .gte => return Air.Inst.Ref.bool_true,
17090 .lt => return Air.Inst.Ref.bool_false,
17091 else => {},
17092 },
17093 .lt => switch (op) { // RHS < 0, LHS is unsigned
17094 .neq, .gt, .gte => return Air.Inst.Ref.bool_true,
17095 .eq, .lt, .lte => return Air.Inst.Ref.bool_false,
17096 },
17097 }
17098 }
17099 if (rhs_is_float) {
1707517100 var bigint_space: Value.BigIntSpace = undefined;
1707617101 var bigint = try rhs_val.toBigInt(&bigint_space).toManaged(sema.gpa);
1707717102 defer bigint.deinit();
17078 const zcmp = rhs_val.orderAgainstZero();
1707917103 if (rhs_val.floatHasFraction()) {
1708017104 switch (op) {
1708117105 .eq => return Air.Inst.Ref.bool_false,
1708217106 .neq => return Air.Inst.Ref.bool_true,
1708317107 else => {},
1708417108 }
17085 if (zcmp == .lt) {
17109 if (rhs_is_signed) {
1708617110 try bigint.addScalar(bigint.toConst(), -1);
1708717111 } else {
1708817112 try bigint.addScalar(bigint.toConst(), 1);
1708917113 }
1709017114 }
1709117115 rhs_bits = bigint.toConst().bitCountTwosComp();
17092 break :x (zcmp != .lt);
17093 } else x: {
17116 } else {
1709417117 rhs_bits = rhs_val.intBitCountTwosComp(target);
17095 break :x (rhs_val.orderAgainstZero() != .lt);
17096 };
17097 rhs_bits += @boolToInt(is_unsigned and dest_int_is_signed);
17118 }
17119 rhs_bits += @boolToInt(!rhs_is_signed and dest_int_is_signed);
1709817120 } else if (rhs_is_float) {
1709917121 dest_float_type = rhs_ty;
1710017122 } else {
test/behavior/eval.zig-2
......@@ -559,8 +559,6 @@ fn modifySomeBytes(bytes: []u8) void {
559559}
560560
561561test "comparisons 0 <= uint and 0 > uint should be comptime" {
562 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
563
564562 testCompTimeUIntComparisons(1234);
565563}
566564fn testCompTimeUIntComparisons(x: u32) void {