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(...@@ -17036,30 +17036,41 @@ fn cmpNumeric(
17036 if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lhs_val| {17036 if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lhs_val| {
17037 if (lhs_val.isUndef())17037 if (lhs_val.isUndef())
17038 return sema.addConstUndef(Type.bool);17038 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) {
17040 var bigint_space: Value.BigIntSpace = undefined;17054 var bigint_space: Value.BigIntSpace = undefined;
17041 var bigint = try lhs_val.toBigInt(&bigint_space).toManaged(sema.gpa);17055 var bigint = try lhs_val.toBigInt(&bigint_space).toManaged(sema.gpa);
17042 defer bigint.deinit();17056 defer bigint.deinit();
17043 const zcmp = lhs_val.orderAgainstZero();
17044 if (lhs_val.floatHasFraction()) {17057 if (lhs_val.floatHasFraction()) {
17045 switch (op) {17058 switch (op) {
17046 .eq => return Air.Inst.Ref.bool_false,17059 .eq => return Air.Inst.Ref.bool_false,
17047 .neq => return Air.Inst.Ref.bool_true,17060 .neq => return Air.Inst.Ref.bool_true,
17048 else => {},17061 else => {},
17049 }17062 }
17050 if (zcmp == .lt) {17063 if (lhs_is_signed) {
17051 try bigint.addScalar(bigint.toConst(), -1);17064 try bigint.addScalar(bigint.toConst(), -1);
17052 } else {17065 } else {
17053 try bigint.addScalar(bigint.toConst(), 1);17066 try bigint.addScalar(bigint.toConst(), 1);
17054 }17067 }
17055 }17068 }
17056 lhs_bits = bigint.toConst().bitCountTwosComp();17069 lhs_bits = bigint.toConst().bitCountTwosComp();
17057 break :x (zcmp != .lt);17070 } else {
17058 } else x: {
17059 lhs_bits = lhs_val.intBitCountTwosComp(target);17071 lhs_bits = lhs_val.intBitCountTwosComp(target);
17060 break :x (lhs_val.orderAgainstZero() != .lt);17072 }
17061 };17073 lhs_bits += @boolToInt(!lhs_is_signed and dest_int_is_signed);
17062 lhs_bits += @boolToInt(is_unsigned and dest_int_is_signed);
17063 } else if (lhs_is_float) {17074 } else if (lhs_is_float) {
17064 dest_float_type = lhs_ty;17075 dest_float_type = lhs_ty;
17065 } else {17076 } else {
...@@ -17071,30 +17082,41 @@ fn cmpNumeric(...@@ -17071,30 +17082,41 @@ fn cmpNumeric(
17071 if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rhs_val| {17082 if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rhs_val| {
17072 if (rhs_val.isUndef())17083 if (rhs_val.isUndef())
17073 return sema.addConstUndef(Type.bool);17084 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) {
17075 var bigint_space: Value.BigIntSpace = undefined;17100 var bigint_space: Value.BigIntSpace = undefined;
17076 var bigint = try rhs_val.toBigInt(&bigint_space).toManaged(sema.gpa);17101 var bigint = try rhs_val.toBigInt(&bigint_space).toManaged(sema.gpa);
17077 defer bigint.deinit();17102 defer bigint.deinit();
17078 const zcmp = rhs_val.orderAgainstZero();
17079 if (rhs_val.floatHasFraction()) {17103 if (rhs_val.floatHasFraction()) {
17080 switch (op) {17104 switch (op) {
17081 .eq => return Air.Inst.Ref.bool_false,17105 .eq => return Air.Inst.Ref.bool_false,
17082 .neq => return Air.Inst.Ref.bool_true,17106 .neq => return Air.Inst.Ref.bool_true,
17083 else => {},17107 else => {},
17084 }17108 }
17085 if (zcmp == .lt) {17109 if (rhs_is_signed) {
17086 try bigint.addScalar(bigint.toConst(), -1);17110 try bigint.addScalar(bigint.toConst(), -1);
17087 } else {17111 } else {
17088 try bigint.addScalar(bigint.toConst(), 1);17112 try bigint.addScalar(bigint.toConst(), 1);
17089 }17113 }
17090 }17114 }
17091 rhs_bits = bigint.toConst().bitCountTwosComp();17115 rhs_bits = bigint.toConst().bitCountTwosComp();
17092 break :x (zcmp != .lt);17116 } else {
17093 } else x: {
17094 rhs_bits = rhs_val.intBitCountTwosComp(target);17117 rhs_bits = rhs_val.intBitCountTwosComp(target);
17095 break :x (rhs_val.orderAgainstZero() != .lt);17118 }
17096 };17119 rhs_bits += @boolToInt(!rhs_is_signed and dest_int_is_signed);
17097 rhs_bits += @boolToInt(is_unsigned and dest_int_is_signed);
17098 } else if (rhs_is_float) {17120 } else if (rhs_is_float) {
17099 dest_float_type = rhs_ty;17121 dest_float_type = rhs_ty;
17100 } else {17122 } else {
test/behavior/eval.zig-2
...@@ -559,8 +559,6 @@ fn modifySomeBytes(bytes: []u8) void {...@@ -559,8 +559,6 @@ fn modifySomeBytes(bytes: []u8) void {
559}559}
560560
561test "comparisons 0 <= uint and 0 > uint should be comptime" {561test "comparisons 0 <= uint and 0 > uint should be comptime" {
562 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
563
564 testCompTimeUIntComparisons(1234);562 testCompTimeUIntComparisons(1234);
565}563}
566fn testCompTimeUIntComparisons(x: u32) void {564fn testCompTimeUIntComparisons(x: u32) void {