authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-02-27 15:32:46-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-02-27 15:32:46-05:00
log104a8840dbc0a09ce5e0035470052354a98693f1
treeee8a81a21eeaaa6baffc3fafb85bce7063a5d406
parent0bdc3d8f4e065f87083b52700350ca96330463ad
parenta7a508fcd9a961ea9d903f9065556a02b4045b95
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #11002 from topolarity/comptime-int-comparison

stage2: Add comptime result for certain unsigned/comptime comparisons

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

src/Sema.zig+39-16
......@@ -11842,6 +11842,7 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
1184211842 const operand = sema.resolveInst(inst_data.operand);
1184311843 const operand_ty = sema.typeOf(operand);
1184411844
11845 try sema.resolveTypeLayout(block, operand_src, operand_ty);
1184511846 const enum_ty = switch (operand_ty.zigTypeTag()) {
1184611847 .EnumLiteral => {
1184711848 const val = try sema.resolveConstValue(block, operand_src, operand);
......@@ -17113,30 +17114,41 @@ fn cmpNumeric(
1711317114 if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lhs_val| {
1711417115 if (lhs_val.isUndef())
1711517116 return sema.addConstUndef(Type.bool);
17116 const is_unsigned = if (lhs_is_float) x: {
17117 if (!rhs_is_signed) {
17118 switch (lhs_val.orderAgainstZero()) {
17119 .gt => {},
17120 .eq => switch (op) { // LHS = 0, RHS is unsigned
17121 .lte => return Air.Inst.Ref.bool_true,
17122 .gt => return Air.Inst.Ref.bool_false,
17123 else => {},
17124 },
17125 .lt => switch (op) { // LHS < 0, RHS is unsigned
17126 .neq, .lt, .lte => return Air.Inst.Ref.bool_true,
17127 .eq, .gt, .gte => return Air.Inst.Ref.bool_false,
17128 },
17129 }
17130 }
17131 if (lhs_is_float) {
1711717132 var bigint_space: Value.BigIntSpace = undefined;
1711817133 var bigint = try lhs_val.toBigInt(&bigint_space).toManaged(sema.gpa);
1711917134 defer bigint.deinit();
17120 const zcmp = lhs_val.orderAgainstZero();
1712117135 if (lhs_val.floatHasFraction()) {
1712217136 switch (op) {
1712317137 .eq => return Air.Inst.Ref.bool_false,
1712417138 .neq => return Air.Inst.Ref.bool_true,
1712517139 else => {},
1712617140 }
17127 if (zcmp == .lt) {
17141 if (lhs_is_signed) {
1712817142 try bigint.addScalar(bigint.toConst(), -1);
1712917143 } else {
1713017144 try bigint.addScalar(bigint.toConst(), 1);
1713117145 }
1713217146 }
1713317147 lhs_bits = bigint.toConst().bitCountTwosComp();
17134 break :x (zcmp != .lt);
17135 } else x: {
17148 } else {
1713617149 lhs_bits = lhs_val.intBitCountTwosComp(target);
17137 break :x (lhs_val.orderAgainstZero() != .lt);
17138 };
17139 lhs_bits += @boolToInt(is_unsigned and dest_int_is_signed);
17150 }
17151 lhs_bits += @boolToInt(!lhs_is_signed and dest_int_is_signed);
1714017152 } else if (lhs_is_float) {
1714117153 dest_float_type = lhs_ty;
1714217154 } else {
......@@ -17148,30 +17160,41 @@ fn cmpNumeric(
1714817160 if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rhs_val| {
1714917161 if (rhs_val.isUndef())
1715017162 return sema.addConstUndef(Type.bool);
17151 const is_unsigned = if (rhs_is_float) x: {
17163 if (!lhs_is_signed) {
17164 switch (rhs_val.orderAgainstZero()) {
17165 .gt => {},
17166 .eq => switch (op) { // RHS = 0, LHS is unsigned
17167 .gte => return Air.Inst.Ref.bool_true,
17168 .lt => return Air.Inst.Ref.bool_false,
17169 else => {},
17170 },
17171 .lt => switch (op) { // RHS < 0, LHS is unsigned
17172 .neq, .gt, .gte => return Air.Inst.Ref.bool_true,
17173 .eq, .lt, .lte => return Air.Inst.Ref.bool_false,
17174 },
17175 }
17176 }
17177 if (rhs_is_float) {
1715217178 var bigint_space: Value.BigIntSpace = undefined;
1715317179 var bigint = try rhs_val.toBigInt(&bigint_space).toManaged(sema.gpa);
1715417180 defer bigint.deinit();
17155 const zcmp = rhs_val.orderAgainstZero();
1715617181 if (rhs_val.floatHasFraction()) {
1715717182 switch (op) {
1715817183 .eq => return Air.Inst.Ref.bool_false,
1715917184 .neq => return Air.Inst.Ref.bool_true,
1716017185 else => {},
1716117186 }
17162 if (zcmp == .lt) {
17187 if (rhs_is_signed) {
1716317188 try bigint.addScalar(bigint.toConst(), -1);
1716417189 } else {
1716517190 try bigint.addScalar(bigint.toConst(), 1);
1716617191 }
1716717192 }
1716817193 rhs_bits = bigint.toConst().bitCountTwosComp();
17169 break :x (zcmp != .lt);
17170 } else x: {
17194 } else {
1717117195 rhs_bits = rhs_val.intBitCountTwosComp(target);
17172 break :x (rhs_val.orderAgainstZero() != .lt);
17173 };
17174 rhs_bits += @boolToInt(is_unsigned and dest_int_is_signed);
17196 }
17197 rhs_bits += @boolToInt(!rhs_is_signed and dest_int_is_signed);
1717517198 } else if (rhs_is_float) {
1717617199 dest_float_type = rhs_ty;
1717717200 } 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 {