From b52948444f16c082f0e29bb75b246370c4b11326 Mon Sep 17 00:00:00 2001 From: Cody Tapscott Date: Sun, 27 Feb 2022 01:53:56 -0700 Subject: [PATCH 1/2] stage2: Resolve union layout before getting tag type in zirTagname This bug only causes a failure on my machine when running test/behavior/eval.zig directly. If running the full behavior test suite, std.builtin.TypeInfo will have already resolved its layout, causing the test to pass. I'd love to add a test that can reliably reproduce this problem, but I'm afraid I'm not sure how to reliably create a union with un-resolved layout. --- src/Sema.zig | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Sema.zig b/src/Sema.zig index 8e93d2525b..4dad9a6c8c 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -11837,6 +11837,7 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air const operand = sema.resolveInst(inst_data.operand); const operand_ty = sema.typeOf(operand); + try sema.resolveTypeLayout(block, operand_src, operand_ty); const enum_ty = switch (operand_ty.zigTypeTag()) { .EnumLiteral => { const val = try sema.resolveConstValue(block, operand_src, operand); From a7a508fcd9a961ea9d903f9065556a02b4045b95 Mon Sep 17 00:00:00 2001 From: Cody Tapscott Date: Sun, 27 Feb 2022 01:19:02 -0700 Subject: [PATCH 2/2] 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 --- src/Sema.zig | 54 +++++++++++++++++++++++++++++------------- test/behavior/eval.zig | 2 -- 2 files changed, 38 insertions(+), 18 deletions(-) diff --git a/src/Sema.zig b/src/Sema.zig index 4dad9a6c8c..9b03b4c32e 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -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 { diff --git a/test/behavior/eval.zig b/test/behavior/eval.zig index c7b5b016b4..9832cd2161 100644 --- a/test/behavior/eval.zig +++ b/test/behavior/eval.zig @@ -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 {