authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-12-16 10:17:43-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-12-16 11:09:10-05:00
log9468d6381997dedaf3330f0c6e1b4290a9af1345
tree89b91f227cca342d895d1f8475da28fc71867e74
parent143603b39faa55f42fffa36d859b380bf1b13984
signaturelock-open Commit is signed but in an unrecognized format.

allow comparison of any numeric types


7 files changed, 716 insertions(+), 307 deletions(-)

lib/std/math.zig+48-93
...@@ -944,102 +944,57 @@ test "math.mulWide" {...@@ -944,102 +944,57 @@ test "math.mulWide" {
944 testing.expect(mulWide(u8, 100, 100) == 10000);944 testing.expect(mulWide(u8, 100, 100) == 10000);
945}945}
946946
947// not to be confused with std.mem.Compare947/// Not to be confused with `std.mem.Compare`.
948pub const CompareOperator = enum {948pub const CompareOperator = enum {
949 lessThan,949 /// Less than (`<`)
950 lessThanOrEqual,950 lt,
951 equal,951
952 greaterThan,952 /// Less than or equal (`<=`)
953 greaterThanOrEqual,953 lte,
954
955 /// Equal (`==`)
956 eq,
957
958 /// Greater than or equal (`>=`)
959 gte,
960
961 /// Greater than (`>`)
962 gt,
963
964 /// Not equal (`!=`)
965 neq,
954};966};
955967
956pub fn compare(a: var, comptime op: CompareOperator, b: var) bool {968/// This function does the same thing as comparison operators, however the
957 const A = @typeOf(a);969/// operator is a runtime-known enum value. Works on any operands that
958 const B = @typeOf(b);970/// support comparison operators.
959 if (@typeId(@typeOf(a)) != .Int or @typeId(@typeOf(b)) != .Int) @compileError("only integers supported");971pub fn compare(a: var, op: CompareOperator, b: var) bool {
960 if (A.is_signed == B.is_signed) {972 return switch (op) {
961 return switch (op) {973 .lt => a < b,
962 .lessThan => a < b,974 .lte => a <= b,
963 .lessThanOrEqual => a <= b,975 .eq => a == b,
964 .equal => a == b,976 .neq => a != b,
965 .greaterThan => a > b,977 .gt => a > b,
966 .greaterThanOrEqual => a >= b,978 .gte => a >= b,
967 };979 };
968 }
969 const Signed = if (A.is_signed) A else B;
970 const Unsigned = if (B.is_signed) A else B;
971 const signedMoreBits = Signed.bit_count > Unsigned.bit_count;
972 const bits = if (signedMoreBits) Signed.bit_count else Unsigned.bit_count;
973 if (signedMoreBits) {
974 const T = @IntType(true, bits);
975 if (A.is_signed) {
976 return switch (op) {
977 .lessThan => a < @intCast(T, b),
978 .lessThanOrEqual => a <= @intCast(T, b),
979 .equal => a == @intCast(T, b),
980 .greaterThan => a > @intCast(T, b),
981 .greaterThanOrEqual => a >= @intCast(T, b),
982 };
983 } else {
984 return switch (op) {
985 .lessThan => @intCast(T, a) < b,
986 .lessThanOrEqual => @intCast(T, a) <= b,
987 .equal => @intCast(T, a) == b,
988 .greaterThan => @intCast(T, a) > b,
989 .greaterThanOrEqual => @intCast(T, a) >= b,
990 };
991 }
992 }
993 if (A.is_signed) {
994 const U = @IntType(false, A.bit_count);
995 const T = @IntType(false, A.bit_count - 1);
996 switch (op) {
997 .lessThan => if (a < 0 or maxInt(A) < b) return true,
998 .lessThanOrEqual => if (a <= 0 or maxInt(A) <= b) return true,
999 .equal => if (A.bit_count <= B.bit_count and a < 0) return false,
1000 else => {},
1001 }
1002 return switch (op) {
1003 .lessThan => @truncate(T, @bitCast(U, a)) < b,
1004 .lessThanOrEqual => @truncate(T, @bitCast(U, a)) <= b,
1005 .equal => @truncate(T, @bitCast(U, a)) == b,
1006 .greaterThan => @truncate(T, @bitCast(U, a)) > b,
1007 .greaterThanOrEqual => @truncate(T, @bitCast(U, a)) >= b,
1008 };
1009 } else {
1010 const U = @IntType(false, B.bit_count);
1011 const T = @IntType(false, B.bit_count - 1);
1012 switch (op) {
1013 .greaterThan => if (0 > b or a > maxInt(B)) return true,
1014 .greaterThanOrEqual => if (0 >= b or a >= maxInt(B)) return true,
1015 .equal => if (A.bit_count >= B.bit_count and 0 > b) return false,
1016 else => {},
1017 }
1018 return switch (op) {
1019 .lessThan => a < @truncate(T, @bitCast(U, b)),
1020 .lessThanOrEqual => a <= @truncate(T, @bitCast(U, b)),
1021 .equal => a == @truncate(T, @bitCast(U, b)),
1022 .greaterThan => a > @truncate(T, @bitCast(U, b)),
1023 .greaterThanOrEqual => a >= @truncate(T, @bitCast(U, b)),
1024 };
1025 }
1026}980}
1027981
1028test "math.lessThan, et al < <= > >= between signed and unsigned" {982test "math.lt, et al < <= > >= between signed and unsigned" {
1029 testing.expect(compare(i8(-1), .lessThan, u8(255)));983 testing.expect(compare(@as(i8, -1), .lt, @as(u8, 255)));
1030 testing.expect(!compare(i8(-1), .greaterThanOrEqual, u8(255)));984 testing.expect(compare(@as(i8, 2), .gt, @as(u8, 1)));
1031 testing.expect(compare(u8(255), .greaterThan, i8(-1)));985 testing.expect(!compare(@as(i8, -1), .gte, @as(u8, 255)));
1032 testing.expect(!compare(u8(255), .lessThanOrEqual, i8(-1)));986 testing.expect(compare(@as(u8, 255), .gt, @as(i8, -1)));
1033 testing.expect(compare(i8(-1), .lessThan, u9(255)));987 testing.expect(!compare(@as(u8, 255), .lte, @as(i8, -1)));
1034 testing.expect(!compare(i8(-1), .greaterThanOrEqual, u9(255)));988 testing.expect(compare(@as(i8, -1), .lt, @as(u9, 255)));
1035 testing.expect(compare(u9(255), .greaterThan, i8(-1)));989 testing.expect(!compare(@as(i8, -1), .gte, @as(u9, 255)));
1036 testing.expect(!compare(u9(255), .lessThanOrEqual, i8(-1)));990 testing.expect(compare(@as(u9, 255), .gt, @as(i8, -1)));
1037 testing.expect(compare(i9(-1), .lessThan, u8(255)));991 testing.expect(!compare(@as(u9, 255), .lte, @as(i8, -1)));
1038 testing.expect(!compare(i9(-1), .greaterThanOrEqual, u8(255)));992 testing.expect(compare(@as(i9, -1), .lt, @as(u8, 255)));
1039 testing.expect(compare(u8(255), .greaterThan, i9(-1)));993 testing.expect(!compare(@as(i9, -1), .gte, @as(u8, 255)));
1040 testing.expect(!compare(u8(255), .lessThanOrEqual, i9(-1)));994 testing.expect(compare(@as(u8, 255), .gt, @as(i9, -1)));
1041 testing.expect(compare(u8(1), .lessThan, u8(2)));995 testing.expect(!compare(@as(u8, 255), .lte, @as(i9, -1)));
1042 testing.expect(@bitCast(u8, i8(-1)) == u8(255));996 testing.expect(compare(@as(u8, 1), .lt, @as(u8, 2)));
1043 testing.expect(!compare(u8(255), .equal, i8(-1)));997 testing.expect(@bitCast(u8, @as(i8, -1)) == @as(u8, 255));
1044 testing.expect(compare(u8(1), .equal, u8(1)));998 testing.expect(!compare(@as(u8, 255), .eq, @as(i8, -1)));
999 testing.expect(compare(@as(u8, 1), .eq, @as(u8, 1)));
1045}1000}
src/analyze.cpp+38
...@@ -9219,3 +9219,41 @@ void copy_const_val(ZigValue *dest, ZigValue *src) {...@@ -9219,3 +9219,41 @@ void copy_const_val(ZigValue *dest, ZigValue *src) {
9219 dest->data.x_optional->parent.data.p_optional_payload.optional_val = dest;9219 dest->data.x_optional->parent.data.p_optional_payload.optional_val = dest;
9220 }9220 }
9221}9221}
9222
9223bool type_is_numeric(ZigType *ty) {
9224 switch (ty->id) {
9225 case ZigTypeIdInvalid:
9226 zig_unreachable();
9227 case ZigTypeIdComptimeFloat:
9228 case ZigTypeIdComptimeInt:
9229 case ZigTypeIdInt:
9230 case ZigTypeIdFloat:
9231 return true;
9232
9233 case ZigTypeIdVector:
9234 return type_is_numeric(ty->data.vector.elem_type);
9235
9236 case ZigTypeIdMetaType:
9237 case ZigTypeIdVoid:
9238 case ZigTypeIdBool:
9239 case ZigTypeIdUnreachable:
9240 case ZigTypeIdPointer:
9241 case ZigTypeIdArray:
9242 case ZigTypeIdStruct:
9243 case ZigTypeIdUndefined:
9244 case ZigTypeIdNull:
9245 case ZigTypeIdOptional:
9246 case ZigTypeIdErrorUnion:
9247 case ZigTypeIdErrorSet:
9248 case ZigTypeIdEnum:
9249 case ZigTypeIdUnion:
9250 case ZigTypeIdFn:
9251 case ZigTypeIdBoundFn:
9252 case ZigTypeIdOpaque:
9253 case ZigTypeIdFnFrame:
9254 case ZigTypeIdAnyFrame:
9255 case ZigTypeIdEnumLiteral:
9256 return false;
9257 }
9258 zig_unreachable();
9259}
src/analyze.hpp+1
...@@ -279,4 +279,5 @@ bool is_anon_container(ZigType *ty);...@@ -279,4 +279,5 @@ bool is_anon_container(ZigType *ty);
279void copy_const_val(ZigValue *dest, ZigValue *src);279void copy_const_val(ZigValue *dest, ZigValue *src);
280bool type_has_optional_repr(ZigType *ty);280bool type_has_optional_repr(ZigType *ty);
281bool is_opt_err_set(ZigType *ty);281bool is_opt_err_set(ZigType *ty);
282bool type_is_numeric(ZigType *ty);
282#endif283#endif
src/bigint.cpp+24
...@@ -1759,3 +1759,27 @@ void bigint_incr(BigInt *x) {...@@ -1759,3 +1759,27 @@ void bigint_incr(BigInt *x) {
1759 bigint_add(x, &copy, &one);1759 bigint_add(x, &copy, &one);
1760}1760}
17611761
1762void bigint_decr(BigInt *x) {
1763 if (x->digit_count == 0) {
1764 bigint_init_signed(x, -1);
1765 return;
1766 }
1767
1768 if (x->digit_count == 1) {
1769 if (x->is_negative && x->data.digit != UINT64_MAX) {
1770 x->data.digit += 1;
1771 return;
1772 } else if (!x->is_negative && x->data.digit != 0) {
1773 x->data.digit -= 1;
1774 return;
1775 }
1776 }
1777
1778 BigInt copy;
1779 bigint_init_bigint(&copy, x);
1780
1781 BigInt neg_one;
1782 bigint_init_signed(&neg_one, -1);
1783
1784 bigint_add(x, &copy, &neg_one);
1785}
src/bigint.hpp+1
...@@ -95,6 +95,7 @@ size_t bigint_bits_needed(const BigInt *op);...@@ -95,6 +95,7 @@ size_t bigint_bits_needed(const BigInt *op);
95Cmp bigint_cmp_zero(const BigInt *op);95Cmp bigint_cmp_zero(const BigInt *op);
9696
97void bigint_incr(BigInt *value);97void bigint_incr(BigInt *value);
98void bigint_decr(BigInt *value);
9899
99bool mul_u64_overflow(uint64_t op1, uint64_t op2, uint64_t *result);100bool mul_u64_overflow(uint64_t op1, uint64_t op2, uint64_t *result);
100101
src/ir.cpp+579-181
...@@ -1792,6 +1792,24 @@ static IrInstruction *ir_build_bin_op(IrBuilder *irb, Scope *scope, AstNode *sou...@@ -1792,6 +1792,24 @@ static IrInstruction *ir_build_bin_op(IrBuilder *irb, Scope *scope, AstNode *sou
1792 return &bin_op_instruction->base;1792 return &bin_op_instruction->base;
1793}1793}
17941794
1795static IrInstruction *ir_build_bin_op_gen(IrAnalyze *ira, IrInstruction *source_instr, ZigType *res_type,
1796 IrBinOp op_id, IrInstruction *op1, IrInstruction *op2, bool safety_check_on)
1797{
1798 IrInstructionBinOp *bin_op_instruction = ir_build_instruction<IrInstructionBinOp>(&ira->new_irb,
1799 source_instr->scope, source_instr->source_node);
1800 bin_op_instruction->base.value->type = res_type;
1801 bin_op_instruction->op_id = op_id;
1802 bin_op_instruction->op1 = op1;
1803 bin_op_instruction->op2 = op2;
1804 bin_op_instruction->safety_check_on = safety_check_on;
1805
1806 ir_ref_instruction(op1, ira->new_irb.current_basic_block);
1807 ir_ref_instruction(op2, ira->new_irb.current_basic_block);
1808
1809 return &bin_op_instruction->base;
1810}
1811
1812
1795static IrInstruction *ir_build_merge_err_sets(IrBuilder *irb, Scope *scope, AstNode *source_node,1813static IrInstruction *ir_build_merge_err_sets(IrBuilder *irb, Scope *scope, AstNode *source_node,
1796 IrInstruction *op1, IrInstruction *op2, Buf *type_name)1814 IrInstruction *op1, IrInstruction *op2, Buf *type_name)
1797{1815{
...@@ -9591,51 +9609,58 @@ static bool float_is_nan(ZigValue *op) {...@@ -9591,51 +9609,58 @@ static bool float_is_nan(ZigValue *op) {
9591}9609}
95929610
9593static Cmp float_cmp(ZigValue *op1, ZigValue *op2) {9611static Cmp float_cmp(ZigValue *op1, ZigValue *op2) {
9594 assert(op1->type == op2->type);9612 if (op1->type == op2->type) {
9595 if (op1->type->id == ZigTypeIdComptimeFloat) {9613 if (op1->type->id == ZigTypeIdComptimeFloat) {
9596 return bigfloat_cmp(&op1->data.x_bigfloat, &op2->data.x_bigfloat);9614 return bigfloat_cmp(&op1->data.x_bigfloat, &op2->data.x_bigfloat);
9597 } else if (op1->type->id == ZigTypeIdFloat) {9615 } else if (op1->type->id == ZigTypeIdFloat) {
9598 switch (op1->type->data.floating.bit_count) {9616 switch (op1->type->data.floating.bit_count) {
9599 case 16:9617 case 16:
9600 if (f16_lt(op1->data.x_f16, op2->data.x_f16)) {9618 if (f16_lt(op1->data.x_f16, op2->data.x_f16)) {
9601 return CmpLT;9619 return CmpLT;
9602 } else if (f16_lt(op2->data.x_f16, op1->data.x_f16)) {9620 } else if (f16_lt(op2->data.x_f16, op1->data.x_f16)) {
9603 return CmpGT;9621 return CmpGT;
9604 } else {9622 } else {
9605 return CmpEQ;9623 return CmpEQ;
9606 }9624 }
9607 case 32:9625 case 32:
9608 if (op1->data.x_f32 > op2->data.x_f32) {9626 if (op1->data.x_f32 > op2->data.x_f32) {
9609 return CmpGT;9627 return CmpGT;
9610 } else if (op1->data.x_f32 < op2->data.x_f32) {9628 } else if (op1->data.x_f32 < op2->data.x_f32) {
9611 return CmpLT;9629 return CmpLT;
9612 } else {9630 } else {
9613 return CmpEQ;9631 return CmpEQ;
9614 }9632 }
9615 case 64:9633 case 64:
9616 if (op1->data.x_f64 > op2->data.x_f64) {9634 if (op1->data.x_f64 > op2->data.x_f64) {
9617 return CmpGT;9635 return CmpGT;
9618 } else if (op1->data.x_f64 < op2->data.x_f64) {9636 } else if (op1->data.x_f64 < op2->data.x_f64) {
9619 return CmpLT;9637 return CmpLT;
9620 } else {9638 } else {
9621 return CmpEQ;9639 return CmpEQ;
9622 }9640 }
9623 case 128:9641 case 128:
9624 if (f128M_lt(&op1->data.x_f128, &op2->data.x_f128)) {9642 if (f128M_lt(&op1->data.x_f128, &op2->data.x_f128)) {
9625 return CmpLT;9643 return CmpLT;
9626 } else if (f128M_eq(&op1->data.x_f128, &op2->data.x_f128)) {9644 } else if (f128M_eq(&op1->data.x_f128, &op2->data.x_f128)) {
9627 return CmpEQ;9645 return CmpEQ;
9628 } else {9646 } else {
9629 return CmpGT;9647 return CmpGT;
9630 }9648 }
9631 default:9649 default:
9632 zig_unreachable();9650 zig_unreachable();
9651 }
9652 } else {
9653 zig_unreachable();
9633 }9654 }
9634 } else {
9635 zig_unreachable();
9636 }9655 }
9656 BigFloat op1_big;
9657 BigFloat op2_big;
9658 float_init_bigfloat(op1, &op1_big);
9659 float_init_bigfloat(op2, &op2_big);
9660 return bigfloat_cmp(&op1_big, &op2_big);
9637}9661}
96389662
9663// This function cannot handle NaN
9639static Cmp float_cmp_zero(ZigValue *op) {9664static Cmp float_cmp_zero(ZigValue *op) {
9640 if (op->type->id == ZigTypeIdComptimeFloat) {9665 if (op->type->id == ZigTypeIdComptimeFloat) {
9641 return bigfloat_cmp_zero(&op->data.x_bigfloat);9666 return bigfloat_cmp_zero(&op->data.x_bigfloat);
...@@ -14421,18 +14446,7 @@ static IrInstruction *ir_evaluate_bin_op_cmp(IrAnalyze *ira, ZigType *resolved_t...@@ -14421,18 +14446,7 @@ static IrInstruction *ir_evaluate_bin_op_cmp(IrAnalyze *ira, ZigType *resolved_t
14421 if (op1_val->special == ConstValSpecialUndef ||14446 if (op1_val->special == ConstValSpecialUndef ||
14422 op2_val->special == ConstValSpecialUndef)14447 op2_val->special == ConstValSpecialUndef)
14423 return ir_const_undef(ira, &bin_op_instruction->base, resolved_type);14448 return ir_const_undef(ira, &bin_op_instruction->base, resolved_type);
14424 if (resolved_type->id == ZigTypeIdComptimeFloat || resolved_type->id == ZigTypeIdFloat) {14449 if (resolved_type->id == ZigTypeIdPointer && op_id != IrBinOpCmpEq && op_id != IrBinOpCmpNotEq) {
14425 if (float_is_nan(op1_val) || float_is_nan(op2_val)) {
14426 return ir_const_bool(ira, &bin_op_instruction->base, op_id == IrBinOpCmpNotEq);
14427 }
14428 Cmp cmp_result = float_cmp(op1_val, op2_val);
14429 bool answer = resolve_cmp_op_id(op_id, cmp_result);
14430 return ir_const_bool(ira, &bin_op_instruction->base, answer);
14431 } else if (resolved_type->id == ZigTypeIdComptimeInt || resolved_type->id == ZigTypeIdInt) {
14432 Cmp cmp_result = bigint_cmp(&op1_val->data.x_bigint, &op2_val->data.x_bigint);
14433 bool answer = resolve_cmp_op_id(op_id, cmp_result);
14434 return ir_const_bool(ira, &bin_op_instruction->base, answer);
14435 } else if (resolved_type->id == ZigTypeIdPointer && op_id != IrBinOpCmpEq && op_id != IrBinOpCmpNotEq) {
14436 if ((op1_val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr ||14450 if ((op1_val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr ||
14437 op1_val->data.x_ptr.special == ConstPtrSpecialNull) &&14451 op1_val->data.x_ptr.special == ConstPtrSpecialNull) &&
14438 (op2_val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr ||14452 (op2_val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr ||
...@@ -14482,6 +14496,12 @@ static Error lazy_cmp_zero(AstNode *source_node, ZigValue *val, Cmp *result) {...@@ -14482,6 +14496,12 @@ static Error lazy_cmp_zero(AstNode *source_node, ZigValue *val, Cmp *result) {
14482 case ZigTypeIdInt:14496 case ZigTypeIdInt:
14483 *result = bigint_cmp_zero(&val->data.x_bigint);14497 *result = bigint_cmp_zero(&val->data.x_bigint);
14484 return ErrorNone;14498 return ErrorNone;
14499 case ZigTypeIdComptimeFloat:
14500 case ZigTypeIdFloat:
14501 if (float_is_nan(val))
14502 return ErrorNotLazy;
14503 *result = float_cmp_zero(val);
14504 return ErrorNone;
14485 default:14505 default:
14486 return ErrorNotLazy;14506 return ErrorNotLazy;
14487 }14507 }
...@@ -14511,9 +14531,450 @@ static Error lazy_cmp_zero(AstNode *source_node, ZigValue *val, Cmp *result) {...@@ -14511,9 +14531,450 @@ static Error lazy_cmp_zero(AstNode *source_node, ZigValue *val, Cmp *result) {
14511 zig_unreachable();14531 zig_unreachable();
14512}14532}
1451314533
14514static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) {14534static ErrorMsg *ir_eval_bin_op_cmp_scalar(IrAnalyze *ira, IrInstruction *source_instr,
14535 ZigValue *op1_val, IrBinOp op_id, ZigValue *op2_val, ZigValue *out_val)
14536{
14515 Error err;14537 Error err;
14538 {
14539 // Before resolving the values, we special case comparisons against zero. These can often
14540 // be done without resolving lazy values, preventing potential dependency loops.
14541 Cmp op1_cmp_zero;
14542 if ((err = lazy_cmp_zero(source_instr->source_node, op1_val, &op1_cmp_zero))) {
14543 if (err == ErrorNotLazy) goto never_mind_just_calculate_it_normally;
14544 return ira->codegen->trace_err;
14545 }
14546 Cmp op2_cmp_zero;
14547 if ((err = lazy_cmp_zero(source_instr->source_node, op2_val, &op2_cmp_zero))) {
14548 if (err == ErrorNotLazy) goto never_mind_just_calculate_it_normally;
14549 return ira->codegen->trace_err;
14550 }
14551 bool can_cmp_zero = false;
14552 Cmp cmp_result;
14553 if (op1_cmp_zero == CmpEQ && op2_cmp_zero == CmpEQ) {
14554 can_cmp_zero = true;
14555 cmp_result = CmpEQ;
14556 } else if (op1_cmp_zero == CmpGT && op2_cmp_zero == CmpEQ) {
14557 can_cmp_zero = true;
14558 cmp_result = CmpGT;
14559 } else if (op1_cmp_zero == CmpEQ && op2_cmp_zero == CmpGT) {
14560 can_cmp_zero = true;
14561 cmp_result = CmpLT;
14562 } else if (op1_cmp_zero == CmpLT && op2_cmp_zero == CmpEQ) {
14563 can_cmp_zero = true;
14564 cmp_result = CmpLT;
14565 } else if (op1_cmp_zero == CmpEQ && op2_cmp_zero == CmpLT) {
14566 can_cmp_zero = true;
14567 cmp_result = CmpGT;
14568 } else if (op1_cmp_zero == CmpLT && op2_cmp_zero == CmpGT) {
14569 can_cmp_zero = true;
14570 cmp_result = CmpLT;
14571 } else if (op1_cmp_zero == CmpGT && op2_cmp_zero == CmpLT) {
14572 can_cmp_zero = true;
14573 cmp_result = CmpGT;
14574 }
14575 if (can_cmp_zero) {
14576 bool answer = resolve_cmp_op_id(op_id, cmp_result);
14577 out_val->special = ConstValSpecialStatic;
14578 out_val->data.x_bool = answer;
14579 return nullptr;
14580 }
14581 }
14582never_mind_just_calculate_it_normally:
14583
14584 if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, source_instr->source_node,
14585 op1_val, UndefOk)))
14586 {
14587 return ira->codegen->trace_err;
14588 }
14589 if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, source_instr->source_node,
14590 op2_val, UndefOk)))
14591 {
14592 return ira->codegen->trace_err;
14593 }
14594
14595
14596 if (op1_val->special == ConstValSpecialUndef || op2_val->special == ConstValSpecialUndef) {
14597 out_val->special = ConstValSpecialUndef;
14598 return nullptr;
14599 }
14600
14601 bool op1_is_float = op1_val->type->id == ZigTypeIdFloat || op1_val->type->id == ZigTypeIdComptimeFloat;
14602 bool op2_is_float = op2_val->type->id == ZigTypeIdFloat || op2_val->type->id == ZigTypeIdComptimeFloat;
14603 if (op1_is_float && op2_is_float) {
14604 if (float_is_nan(op1_val) || float_is_nan(op2_val)) {
14605 out_val->special = ConstValSpecialStatic;
14606 out_val->data.x_bool = op_id == IrBinOpCmpNotEq;
14607 return nullptr;
14608 }
14609 if (op1_val->type->id == ZigTypeIdComptimeFloat) {
14610 IrInstruction *tmp = ir_const_noval(ira, source_instr);
14611 tmp->value = op1_val;
14612 IrInstruction *casted = ir_implicit_cast(ira, tmp, op2_val->type);
14613 op1_val = casted->value;
14614 } else if (op2_val->type->id == ZigTypeIdComptimeFloat) {
14615 IrInstruction *tmp = ir_const_noval(ira, source_instr);
14616 tmp->value = op2_val;
14617 IrInstruction *casted = ir_implicit_cast(ira, tmp, op1_val->type);
14618 op2_val = casted->value;
14619 }
14620 Cmp cmp_result = float_cmp(op1_val, op2_val);
14621 out_val->special = ConstValSpecialStatic;
14622 out_val->data.x_bool = resolve_cmp_op_id(op_id, cmp_result);
14623 return nullptr;
14624 }
14625
14626 bool op1_is_int = op1_val->type->id == ZigTypeIdInt || op1_val->type->id == ZigTypeIdComptimeInt;
14627 bool op2_is_int = op2_val->type->id == ZigTypeIdInt || op2_val->type->id == ZigTypeIdComptimeInt;
14628
14629 BigInt *op1_bigint;
14630 BigInt *op2_bigint;
14631 bool need_to_free_op1_bigint = false;
14632 bool need_to_free_op2_bigint = false;
14633 if (op1_is_float) {
14634 op1_bigint = allocate<BigInt>(1, "BigInt");
14635 need_to_free_op1_bigint = true;
14636 float_init_bigint(op1_bigint, op1_val);
14637 } else {
14638 assert(op1_is_int);
14639 op1_bigint = &op1_val->data.x_bigint;
14640 }
14641 if (op2_is_float) {
14642 op2_bigint = allocate<BigInt>(1, "BigInt");
14643 need_to_free_op2_bigint = true;
14644 float_init_bigint(op2_bigint, op2_val);
14645 } else {
14646 assert(op2_is_int);
14647 op2_bigint = &op2_val->data.x_bigint;
14648 }
14649
14650 Cmp cmp_result = bigint_cmp(op1_bigint, op2_bigint);
14651 out_val->special = ConstValSpecialStatic;
14652 out_val->data.x_bool = resolve_cmp_op_id(op_id, cmp_result);
1451614653
14654 if (need_to_free_op1_bigint) destroy(op1_bigint, "BigInt");
14655 if (need_to_free_op2_bigint) destroy(op2_bigint, "BigInt");
14656 return nullptr;
14657}
14658
14659static IrInstruction *ir_analyze_bin_op_cmp_numeric(IrAnalyze *ira, IrInstruction *source_instr,
14660 IrInstruction *op1, IrInstruction *op2, IrBinOp op_id)
14661{
14662 Error err;
14663
14664 ZigType *scalar_result_type = ira->codegen->builtin_types.entry_bool;
14665 ZigType *result_type = scalar_result_type;
14666 ZigType *op1_scalar_type = op1->value->type;
14667 ZigType *op2_scalar_type = op2->value->type;
14668 if (op1->value->type->id == ZigTypeIdVector && op2->value->type->id == ZigTypeIdVector) {
14669 if (op1->value->type->data.vector.len != op2->value->type->data.vector.len) {
14670 ir_add_error(ira, source_instr,
14671 buf_sprintf("vector length mismatch: %" PRIu32 " and %" PRIu32,
14672 op1->value->type->data.vector.len, op2->value->type->data.vector.len));
14673 return ira->codegen->invalid_instruction;
14674 }
14675 result_type = get_vector_type(ira->codegen, op1->value->type->data.vector.len, scalar_result_type);
14676 op1_scalar_type = op1->value->type->data.vector.elem_type;
14677 op2_scalar_type = op2->value->type->data.vector.elem_type;
14678 } else if (op1->value->type->id == ZigTypeIdVector || op2->value->type->id == ZigTypeIdVector) {
14679 ir_add_error(ira, source_instr,
14680 buf_sprintf("mixed scalar and vector operands to comparison operator: '%s' and '%s'",
14681 buf_ptr(&op1->value->type->name), buf_ptr(&op2->value->type->name)));
14682 return ira->codegen->invalid_instruction;
14683 }
14684
14685 bool opv_op1;
14686 switch (type_has_one_possible_value(ira->codegen, op1->value->type)) {
14687 case OnePossibleValueInvalid:
14688 return ira->codegen->invalid_instruction;
14689 case OnePossibleValueYes:
14690 opv_op1 = true;
14691 break;
14692 case OnePossibleValueNo:
14693 opv_op1 = false;
14694 break;
14695 }
14696 bool opv_op2;
14697 switch (type_has_one_possible_value(ira->codegen, op2->value->type)) {
14698 case OnePossibleValueInvalid:
14699 return ira->codegen->invalid_instruction;
14700 case OnePossibleValueYes:
14701 opv_op2 = true;
14702 break;
14703 case OnePossibleValueNo:
14704 opv_op2 = false;
14705 break;
14706 }
14707 Cmp op1_cmp_zero;
14708 bool have_op1_cmp_zero = false;
14709 if ((err = lazy_cmp_zero(source_instr->source_node, op1->value, &op1_cmp_zero))) {
14710 if (err != ErrorNotLazy) return ira->codegen->invalid_instruction;
14711 } else {
14712 have_op1_cmp_zero = true;
14713 }
14714 Cmp op2_cmp_zero;
14715 bool have_op2_cmp_zero = false;
14716 if ((err = lazy_cmp_zero(source_instr->source_node, op2->value, &op2_cmp_zero))) {
14717 if (err != ErrorNotLazy) return ira->codegen->invalid_instruction;
14718 } else {
14719 have_op2_cmp_zero = true;
14720 }
14721 if (((opv_op1 || instr_is_comptime(op1)) && (opv_op2 || instr_is_comptime(op2))) ||
14722 (have_op1_cmp_zero && have_op2_cmp_zero))
14723 {
14724 IrInstruction *result_instruction = ir_const(ira, source_instr, result_type);
14725 ZigValue *out_val = result_instruction->value;
14726 if (result_type->id == ZigTypeIdVector) {
14727 size_t len = result_type->data.vector.len;
14728 expand_undef_array(ira->codegen, op1->value);
14729 expand_undef_array(ira->codegen, op2->value);
14730 out_val->special = ConstValSpecialUndef;
14731 expand_undef_array(ira->codegen, out_val);
14732 for (size_t i = 0; i < len; i += 1) {
14733 ZigValue *scalar_op1_val = &op1->value->data.x_array.data.s_none.elements[i];
14734 ZigValue *scalar_op2_val = &op2->value->data.x_array.data.s_none.elements[i];
14735 ZigValue *scalar_out_val = &out_val->data.x_array.data.s_none.elements[i];
14736 assert(scalar_out_val->type == scalar_result_type);
14737 ErrorMsg *msg = ir_eval_bin_op_cmp_scalar(ira, source_instr,
14738 scalar_op1_val, op_id, scalar_op2_val, scalar_out_val);
14739 if (msg != nullptr) {
14740 add_error_note(ira->codegen, msg, source_instr->source_node,
14741 buf_sprintf("when computing vector element at index %" ZIG_PRI_usize, i));
14742 return ira->codegen->invalid_instruction;
14743 }
14744 }
14745 out_val->type = result_type;
14746 out_val->special = ConstValSpecialStatic;
14747 } else {
14748 if (ir_eval_bin_op_cmp_scalar(ira, source_instr, op1->value, op_id,
14749 op2->value, out_val) != nullptr)
14750 {
14751 return ira->codegen->invalid_instruction;
14752 }
14753 }
14754 return result_instruction;
14755 }
14756
14757 // If one operand has a comptime-known comparison with 0, and the other operand is unsigned, we might
14758 // know the answer, depending on the operator.
14759 // TODO make this work with vectors
14760 if (have_op1_cmp_zero && op2_scalar_type->id == ZigTypeIdInt && !op2_scalar_type->data.integral.is_signed) {
14761 if (op1_cmp_zero == CmpEQ) {
14762 // 0 <= unsigned_x // true
14763 // 0 > unsigned_x // false
14764 switch (op_id) {
14765 case IrBinOpCmpLessOrEq:
14766 return ir_const_bool(ira, source_instr, true);
14767 case IrBinOpCmpGreaterThan:
14768 return ir_const_bool(ira, source_instr, false);
14769 default:
14770 break;
14771 }
14772 } else if (op1_cmp_zero == CmpLT) {
14773 // -1 != unsigned_x // true
14774 // -1 <= unsigned_x // true
14775 // -1 < unsigned_x // true
14776 // -1 == unsigned_x // false
14777 // -1 >= unsigned_x // false
14778 // -1 > unsigned_x // false
14779 switch (op_id) {
14780 case IrBinOpCmpNotEq:
14781 case IrBinOpCmpLessOrEq:
14782 case IrBinOpCmpLessThan:
14783 return ir_const_bool(ira, source_instr, true);
14784 case IrBinOpCmpEq:
14785 case IrBinOpCmpGreaterOrEq:
14786 case IrBinOpCmpGreaterThan:
14787 return ir_const_bool(ira, source_instr, false);
14788 default:
14789 break;
14790 }
14791 }
14792 }
14793 if (have_op2_cmp_zero && op1_scalar_type->id == ZigTypeIdInt && !op1_scalar_type->data.integral.is_signed) {
14794 if (op2_cmp_zero == CmpEQ) {
14795 // unsigned_x < 0 // false
14796 // unsigned_x >= 0 // true
14797 switch (op_id) {
14798 case IrBinOpCmpLessThan:
14799 return ir_const_bool(ira, source_instr, false);
14800 case IrBinOpCmpGreaterOrEq:
14801 return ir_const_bool(ira, source_instr, true);
14802 default:
14803 break;
14804 }
14805 } else if (op2_cmp_zero == CmpLT) {
14806 // unsigned_x != -1 // true
14807 // unsigned_x >= -1 // true
14808 // unsigned_x > -1 // true
14809 // unsigned_x == -1 // false
14810 // unsigned_x < -1 // false
14811 // unsigned_x <= -1 // false
14812 switch (op_id) {
14813 case IrBinOpCmpNotEq:
14814 case IrBinOpCmpGreaterOrEq:
14815 case IrBinOpCmpGreaterThan:
14816 return ir_const_bool(ira, source_instr, true);
14817 case IrBinOpCmpEq:
14818 case IrBinOpCmpLessThan:
14819 case IrBinOpCmpLessOrEq:
14820 return ir_const_bool(ira, source_instr, false);
14821 default:
14822 break;
14823 }
14824 }
14825 }
14826
14827 // It must be a runtime comparison.
14828 // For floats, emit a float comparison instruction.
14829 bool op1_is_float = op1_scalar_type->id == ZigTypeIdFloat || op1_scalar_type->id == ZigTypeIdComptimeFloat;
14830 bool op2_is_float = op2_scalar_type->id == ZigTypeIdFloat || op2_scalar_type->id == ZigTypeIdComptimeFloat;
14831 if (op1_is_float && op2_is_float) {
14832 // Implicit cast the smaller one to the larger one.
14833 ZigType *dest_scalar_type;
14834 if (op1_scalar_type->id == ZigTypeIdComptimeFloat) {
14835 dest_scalar_type = op2_scalar_type;
14836 } else if (op2_scalar_type->id == ZigTypeIdComptimeFloat) {
14837 dest_scalar_type = op1_scalar_type;
14838 } else if (op1_scalar_type->data.floating.bit_count >= op2_scalar_type->data.floating.bit_count) {
14839 dest_scalar_type = op1_scalar_type;
14840 } else {
14841 dest_scalar_type = op2_scalar_type;
14842 }
14843 ZigType *dest_type = (result_type->id == ZigTypeIdVector) ?
14844 get_vector_type(ira->codegen, result_type->data.vector.len, dest_scalar_type) : dest_scalar_type;
14845 IrInstruction *casted_op1 = ir_implicit_cast(ira, op1, dest_type);
14846 IrInstruction *casted_op2 = ir_implicit_cast(ira, op2, dest_type);
14847 if (type_is_invalid(casted_op1->value->type) || type_is_invalid(casted_op2->value->type))
14848 return ira->codegen->invalid_instruction;
14849 return ir_build_bin_op_gen(ira, source_instr, result_type, op_id, casted_op1, casted_op2, true);
14850 }
14851
14852 // For mixed unsigned integer sizes, implicit cast both operands to the larger integer.
14853 // For mixed signed and unsigned integers, implicit cast both operands to a signed
14854 // integer with + 1 bit.
14855 // For mixed floats and integers, extract the integer part from the float, cast that to
14856 // a signed integer with mantissa bits + 1, and if there was any non-integral part of the float,
14857 // add/subtract 1.
14858 bool dest_int_is_signed = false;
14859 if (have_op1_cmp_zero) {
14860 if (op1_cmp_zero == CmpLT) dest_int_is_signed = true;
14861 } else if (op1_is_float) {
14862 dest_int_is_signed = true;
14863 } else if (op1_scalar_type->id == ZigTypeIdInt && op1_scalar_type->data.integral.is_signed) {
14864 dest_int_is_signed = true;
14865 }
14866 if (have_op2_cmp_zero) {
14867 if (op2_cmp_zero == CmpLT) dest_int_is_signed = true;
14868 } else if (op2_is_float) {
14869 dest_int_is_signed = true;
14870 } else if (op2->value->type->id == ZigTypeIdInt && op2->value->type->data.integral.is_signed) {
14871 dest_int_is_signed = true;
14872 }
14873 ZigType *dest_float_type = nullptr;
14874 uint32_t op1_bits;
14875 if (instr_is_comptime(op1)) {
14876 ZigValue *op1_val = ir_resolve_const(ira, op1, UndefOk);
14877 if (op1_val == nullptr)
14878 return ira->codegen->invalid_instruction;
14879 if (op1_val->special == ConstValSpecialUndef)
14880 return ir_const_undef(ira, source_instr, ira->codegen->builtin_types.entry_bool);
14881 if (result_type->id == ZigTypeIdVector) {
14882 ir_add_error(ira, op1, buf_sprintf("compiler bug: TODO: support comptime vector here"));
14883 return ira->codegen->invalid_instruction;
14884 }
14885 bool is_unsigned;
14886 if (op1_is_float) {
14887 BigInt bigint = {};
14888 float_init_bigint(&bigint, op1_val);
14889 Cmp zcmp = float_cmp_zero(op1_val);
14890 if (float_has_fraction(op1_val)) {
14891 if (op_id == IrBinOpCmpEq || op_id == IrBinOpCmpNotEq) {
14892 return ir_const_bool(ira, source_instr, op_id == IrBinOpCmpNotEq);
14893 }
14894 if (zcmp == CmpLT) {
14895 bigint_decr(&bigint);
14896 } else {
14897 bigint_incr(&bigint);
14898 }
14899 }
14900 op1_bits = bigint_bits_needed(&bigint);
14901 is_unsigned = zcmp != CmpLT;
14902 } else {
14903 op1_bits = bigint_bits_needed(&op1_val->data.x_bigint);
14904 is_unsigned = bigint_cmp_zero(&op1_val->data.x_bigint) != CmpLT;
14905 }
14906 if (is_unsigned && dest_int_is_signed) {
14907 op1_bits += 1;
14908 }
14909 } else if (op1_is_float) {
14910 dest_float_type = op1_scalar_type;
14911 } else {
14912 ir_assert(op1_scalar_type->id == ZigTypeIdInt, source_instr);
14913 op1_bits = op1_scalar_type->data.integral.bit_count;
14914 if (!op1_scalar_type->data.integral.is_signed && dest_int_is_signed) {
14915 op1_bits += 1;
14916 }
14917 }
14918 uint32_t op2_bits;
14919 if (instr_is_comptime(op2)) {
14920 ZigValue *op2_val = ir_resolve_const(ira, op2, UndefOk);
14921 if (op2_val == nullptr)
14922 return ira->codegen->invalid_instruction;
14923 if (op2_val->special == ConstValSpecialUndef)
14924 return ir_const_undef(ira, source_instr, ira->codegen->builtin_types.entry_bool);
14925 if (result_type->id == ZigTypeIdVector) {
14926 ir_add_error(ira, op2, buf_sprintf("compiler bug: TODO: support comptime vector here"));
14927 return ira->codegen->invalid_instruction;
14928 }
14929 bool is_unsigned;
14930 if (op2_is_float) {
14931 BigInt bigint = {};
14932 float_init_bigint(&bigint, op2_val);
14933 Cmp zcmp = float_cmp_zero(op2_val);
14934 if (float_has_fraction(op2_val)) {
14935 if (op_id == IrBinOpCmpEq || op_id == IrBinOpCmpNotEq) {
14936 return ir_const_bool(ira, source_instr, op_id == IrBinOpCmpNotEq);
14937 }
14938 if (zcmp == CmpLT) {
14939 bigint_decr(&bigint);
14940 } else {
14941 bigint_incr(&bigint);
14942 }
14943 }
14944 op2_bits = bigint_bits_needed(&bigint);
14945 is_unsigned = zcmp != CmpLT;
14946 } else {
14947 op2_bits = bigint_bits_needed(&op2_val->data.x_bigint);
14948 is_unsigned = bigint_cmp_zero(&op2_val->data.x_bigint) != CmpLT;
14949 }
14950 if (is_unsigned && dest_int_is_signed) {
14951 op2_bits += 1;
14952 }
14953 } else if (op2_is_float) {
14954 dest_float_type = op2_scalar_type;
14955 } else {
14956 ir_assert(op2_scalar_type->id == ZigTypeIdInt, source_instr);
14957 op2_bits = op2_scalar_type->data.integral.bit_count;
14958 if (!op2_scalar_type->data.integral.is_signed && dest_int_is_signed) {
14959 op2_bits += 1;
14960 }
14961 }
14962 uint32_t dest_int_bits = (op1_bits > op2_bits) ? op1_bits : op2_bits;
14963 ZigType *dest_scalar_type = (dest_float_type == nullptr) ?
14964 get_int_type(ira->codegen, dest_int_is_signed, dest_int_bits) : dest_float_type;
14965 ZigType *dest_type = (result_type->id == ZigTypeIdVector) ?
14966 get_vector_type(ira->codegen, result_type->data.vector.len, dest_scalar_type) : dest_scalar_type;
14967
14968 IrInstruction *casted_op1 = ir_implicit_cast(ira, op1, dest_type);
14969 if (type_is_invalid(casted_op1->value->type))
14970 return ira->codegen->invalid_instruction;
14971 IrInstruction *casted_op2 = ir_implicit_cast(ira, op2, dest_type);
14972 if (type_is_invalid(casted_op2->value->type))
14973 return ira->codegen->invalid_instruction;
14974 return ir_build_bin_op_gen(ira, source_instr, result_type, op_id, casted_op1, casted_op2, true);
14975}
14976
14977static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) {
14517 IrInstruction *op1 = bin_op_instruction->op1->child;14978 IrInstruction *op1 = bin_op_instruction->op1->child;
14518 if (type_is_invalid(op1->value->type))14979 if (type_is_invalid(op1->value->type))
14519 return ira->codegen->invalid_instruction;14980 return ira->codegen->invalid_instruction;
...@@ -14726,6 +15187,13 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *...@@ -14726,6 +15187,13 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *
14726 return result;15187 return result;
14727 }15188 }
1472815189
15190 if (type_is_numeric(op1->value->type) && type_is_numeric(op2->value->type)) {
15191 // This operation allows any combination of integer and float types, regardless of the
15192 // signed-ness, comptime-ness, and bit-width. So peer type resolution is incorrect for
15193 // numeric types.
15194 return ir_analyze_bin_op_cmp_numeric(ira, &bin_op_instruction->base, op1, op2, op_id);
15195 }
15196
14729 IrInstruction *instructions[] = {op1, op2};15197 IrInstruction *instructions[] = {op1, op2};
14730 ZigType *resolved_type = ir_resolve_peer_types(ira, source_node, nullptr, instructions, 2);15198 ZigType *resolved_type = ir_resolve_peer_types(ira, source_node, nullptr, instructions, 2);
14731 if (type_is_invalid(resolved_type))15199 if (type_is_invalid(resolved_type))
...@@ -14741,8 +15209,7 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *...@@ -14741,8 +15209,7 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *
14741 case ZigTypeIdInt:15209 case ZigTypeIdInt:
14742 case ZigTypeIdFloat:15210 case ZigTypeIdFloat:
14743 case ZigTypeIdVector:15211 case ZigTypeIdVector:
14744 operator_allowed = true;15212 zig_unreachable(); // handled with the type_is_numeric checks above
14745 break;
1474615213
14747 case ZigTypeIdBool:15214 case ZigTypeIdBool:
14748 case ZigTypeIdMetaType:15215 case ZigTypeIdMetaType:
...@@ -14802,50 +15269,6 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *...@@ -14802,50 +15269,6 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *
14802 }15269 }
1480315270
14804 if (one_possible_value || (instr_is_comptime(casted_op1) && instr_is_comptime(casted_op2))) {15271 if (one_possible_value || (instr_is_comptime(casted_op1) && instr_is_comptime(casted_op2))) {
14805 {
14806 // Before resolving the values, we special case comparisons against zero. These can often be done
14807 // without resolving lazy values, preventing potential dependency loops.
14808 Cmp op1_cmp_zero;
14809 if ((err = lazy_cmp_zero(bin_op_instruction->base.source_node, casted_op1->value, &op1_cmp_zero))) {
14810 if (err == ErrorNotLazy) goto never_mind_just_calculate_it_normally;
14811 return ira->codegen->invalid_instruction;
14812 }
14813 Cmp op2_cmp_zero;
14814 if ((err = lazy_cmp_zero(bin_op_instruction->base.source_node, casted_op2->value, &op2_cmp_zero))) {
14815 if (err == ErrorNotLazy) goto never_mind_just_calculate_it_normally;
14816 return ira->codegen->invalid_instruction;
14817 }
14818 bool can_cmp_zero = false;
14819 Cmp cmp_result;
14820 if (op1_cmp_zero == CmpEQ && op2_cmp_zero == CmpEQ) {
14821 can_cmp_zero = true;
14822 cmp_result = CmpEQ;
14823 } else if (op1_cmp_zero == CmpGT && op2_cmp_zero == CmpEQ) {
14824 can_cmp_zero = true;
14825 cmp_result = CmpGT;
14826 } else if (op1_cmp_zero == CmpEQ && op2_cmp_zero == CmpGT) {
14827 can_cmp_zero = true;
14828 cmp_result = CmpLT;
14829 } else if (op1_cmp_zero == CmpLT && op2_cmp_zero == CmpEQ) {
14830 can_cmp_zero = true;
14831 cmp_result = CmpLT;
14832 } else if (op1_cmp_zero == CmpEQ && op2_cmp_zero == CmpLT) {
14833 can_cmp_zero = true;
14834 cmp_result = CmpGT;
14835 } else if (op1_cmp_zero == CmpLT && op2_cmp_zero == CmpGT) {
14836 can_cmp_zero = true;
14837 cmp_result = CmpLT;
14838 } else if (op1_cmp_zero == CmpGT && op2_cmp_zero == CmpLT) {
14839 can_cmp_zero = true;
14840 cmp_result = CmpGT;
14841 }
14842 if (can_cmp_zero) {
14843 bool answer = resolve_cmp_op_id(op_id, cmp_result);
14844 return ir_const_bool(ira, &bin_op_instruction->base, answer);
14845 }
14846 }
14847never_mind_just_calculate_it_normally:
14848
14849 ZigValue *op1_val = one_possible_value ? casted_op1->value : ir_resolve_const(ira, casted_op1, UndefBad);15272 ZigValue *op1_val = one_possible_value ? casted_op1->value : ir_resolve_const(ira, casted_op1, UndefBad);
14850 if (op1_val == nullptr)15273 if (op1_val == nullptr)
14851 return ira->codegen->invalid_instruction;15274 return ira->codegen->invalid_instruction;
...@@ -14870,43 +15293,6 @@ never_mind_just_calculate_it_normally:...@@ -14870,43 +15293,6 @@ never_mind_just_calculate_it_normally:
14870 return result;15293 return result;
14871 }15294 }
1487215295
14873 // some comparisons with unsigned numbers can be evaluated
14874 if (resolved_type->id == ZigTypeIdInt && !resolved_type->data.integral.is_signed) {
14875 ZigValue *known_left_val;
14876 IrBinOp flipped_op_id;
14877 if (instr_is_comptime(casted_op1)) {
14878 known_left_val = ir_resolve_const(ira, casted_op1, UndefBad);
14879 if (known_left_val == nullptr)
14880 return ira->codegen->invalid_instruction;
14881
14882 flipped_op_id = op_id;
14883 } else if (instr_is_comptime(casted_op2)) {
14884 known_left_val = ir_resolve_const(ira, casted_op2, UndefBad);
14885 if (known_left_val == nullptr)
14886 return ira->codegen->invalid_instruction;
14887
14888 if (op_id == IrBinOpCmpLessThan) {
14889 flipped_op_id = IrBinOpCmpGreaterThan;
14890 } else if (op_id == IrBinOpCmpGreaterThan) {
14891 flipped_op_id = IrBinOpCmpLessThan;
14892 } else if (op_id == IrBinOpCmpLessOrEq) {
14893 flipped_op_id = IrBinOpCmpGreaterOrEq;
14894 } else if (op_id == IrBinOpCmpGreaterOrEq) {
14895 flipped_op_id = IrBinOpCmpLessOrEq;
14896 } else {
14897 flipped_op_id = op_id;
14898 }
14899 } else {
14900 known_left_val = nullptr;
14901 }
14902 if (known_left_val != nullptr && bigint_cmp_zero(&known_left_val->data.x_bigint) == CmpEQ &&
14903 (flipped_op_id == IrBinOpCmpLessOrEq || flipped_op_id == IrBinOpCmpGreaterThan))
14904 {
14905 bool answer = (flipped_op_id == IrBinOpCmpLessOrEq);
14906 return ir_const_bool(ira, &bin_op_instruction->base, answer);
14907 }
14908 }
14909
14910 IrInstruction *result = ir_build_bin_op(&ira->new_irb,15296 IrInstruction *result = ir_build_bin_op(&ira->new_irb,
14911 bin_op_instruction->base.scope, bin_op_instruction->base.source_node,15297 bin_op_instruction->base.scope, bin_op_instruction->base.source_node,
14912 op_id, casted_op1, casted_op2, bin_op_instruction->safety_check_on);15298 op_id, casted_op1, casted_op2, bin_op_instruction->safety_check_on);
...@@ -23959,26 +24345,32 @@ static IrInstruction *ir_analyze_instruction_int_to_float(IrAnalyze *ira, IrInst...@@ -23959,26 +24345,32 @@ static IrInstruction *ir_analyze_instruction_int_to_float(IrAnalyze *ira, IrInst
23959 return ir_resolve_cast(ira, &instruction->base, target, dest_type, CastOpIntToFloat);24345 return ir_resolve_cast(ira, &instruction->base, target, dest_type, CastOpIntToFloat);
23960}24346}
2396124347
24348static IrInstruction *ir_analyze_float_to_int(IrAnalyze *ira, IrInstruction *source_instr,
24349 ZigType *dest_type, IrInstruction *operand, AstNode *operand_source_node)
24350{
24351 if (operand->value->type->id == ZigTypeIdComptimeInt) {
24352 return ir_implicit_cast(ira, operand, dest_type);
24353 }
24354
24355 if (operand->value->type->id != ZigTypeIdFloat && operand->value->type->id != ZigTypeIdComptimeFloat) {
24356 ir_add_error_node(ira, operand_source_node, buf_sprintf("expected float type, found '%s'",
24357 buf_ptr(&operand->value->type->name)));
24358 return ira->codegen->invalid_instruction;
24359 }
24360
24361 return ir_resolve_cast(ira, source_instr, operand, dest_type, CastOpFloatToInt);
24362}
24363
23962static IrInstruction *ir_analyze_instruction_float_to_int(IrAnalyze *ira, IrInstructionFloatToInt *instruction) {24364static IrInstruction *ir_analyze_instruction_float_to_int(IrAnalyze *ira, IrInstructionFloatToInt *instruction) {
23963 ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child);24365 ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child);
23964 if (type_is_invalid(dest_type))24366 if (type_is_invalid(dest_type))
23965 return ira->codegen->invalid_instruction;24367 return ira->codegen->invalid_instruction;
2396624368
23967 IrInstruction *target = instruction->target->child;24369 IrInstruction *operand = instruction->target->child;
23968 if (type_is_invalid(target->value->type))24370 if (type_is_invalid(operand->value->type))
23969 return ira->codegen->invalid_instruction;24371 return ira->codegen->invalid_instruction;
2397024372
23971 if (target->value->type->id == ZigTypeIdComptimeInt) {24373 return ir_analyze_float_to_int(ira, &instruction->base, dest_type, operand, instruction->target->source_node);
23972 return ir_implicit_cast(ira, target, dest_type);
23973 }
23974
23975 if (target->value->type->id != ZigTypeIdFloat && target->value->type->id != ZigTypeIdComptimeFloat) {
23976 ir_add_error(ira, instruction->target, buf_sprintf("expected float type, found '%s'",
23977 buf_ptr(&target->value->type->name)));
23978 return ira->codegen->invalid_instruction;
23979 }
23980
23981 return ir_resolve_cast(ira, &instruction->base, target, dest_type, CastOpFloatToInt);
23982}24374}
2398324375
23984static IrInstruction *ir_analyze_instruction_err_to_int(IrAnalyze *ira, IrInstructionErrToInt *instruction) {24376static IrInstruction *ir_analyze_instruction_err_to_int(IrAnalyze *ira, IrInstructionErrToInt *instruction) {
...@@ -27111,13 +27503,13 @@ static IrInstruction *ir_analyze_instruction_save_err_ret_addr(IrAnalyze *ira, I...@@ -27111,13 +27503,13 @@ static IrInstruction *ir_analyze_instruction_save_err_ret_addr(IrAnalyze *ira, I
27111 return result;27503 return result;
27112}27504}
2711327505
27114static void ir_eval_float_op(IrAnalyze *ira, IrInstructionFloatOp *source_instr, ZigType *float_type,27506static void ir_eval_float_op(IrAnalyze *ira, IrInstruction *source_instr, BuiltinFnId fop, ZigType *float_type,
27115 ZigValue *op, ZigValue *out_val) {27507 ZigValue *op, ZigValue *out_val)
27508{
27116 assert(ira && source_instr && float_type && out_val && op);27509 assert(ira && source_instr && float_type && out_val && op);
27117 assert(float_type->id == ZigTypeIdFloat ||27510 assert(float_type->id == ZigTypeIdFloat ||
27118 float_type->id == ZigTypeIdComptimeFloat);27511 float_type->id == ZigTypeIdComptimeFloat);
2711927512
27120 BuiltinFnId fop = source_instr->op;
27121 unsigned bits;27513 unsigned bits;
2712227514
27123 switch (float_type->id) {27515 switch (float_type->id) {
...@@ -27291,45 +27683,39 @@ static void ir_eval_float_op(IrAnalyze *ira, IrInstructionFloatOp *source_instr,...@@ -27291,45 +27683,39 @@ static void ir_eval_float_op(IrAnalyze *ira, IrInstructionFloatOp *source_instr,
27291 }27683 }
27292}27684}
2729327685
27294static IrInstruction *ir_analyze_instruction_float_op(IrAnalyze *ira, IrInstructionFloatOp *instruction) {27686static IrInstruction *ir_analyze_float_op(IrAnalyze *ira, IrInstruction *source_instr,
27295 IrInstruction *type = instruction->type->child;27687 ZigType *expr_type, AstNode *expr_type_src_node, IrInstruction *operand, BuiltinFnId op)
27296 if (type_is_invalid(type->value->type))27688{
27297 return ira->codegen->invalid_instruction;
27298
27299 ZigType *expr_type = ir_resolve_type(ira, type);
27300 if (type_is_invalid(expr_type))
27301 return ira->codegen->invalid_instruction;
27302
27303 // Only allow float types, and vectors of floats.27689 // Only allow float types, and vectors of floats.
27304 ZigType *float_type = (expr_type->id == ZigTypeIdVector) ? expr_type->data.vector.elem_type : expr_type;27690 ZigType *float_type = (expr_type->id == ZigTypeIdVector) ? expr_type->data.vector.elem_type : expr_type;
27305 if (float_type->id != ZigTypeIdFloat && float_type->id != ZigTypeIdComptimeFloat) {27691 if (float_type->id != ZigTypeIdFloat && float_type->id != ZigTypeIdComptimeFloat) {
27306 ir_add_error(ira, instruction->type, buf_sprintf("@%s does not support type '%s'", float_op_to_name(instruction->op, false), buf_ptr(&float_type->name)));27692 ir_add_error_node(ira, expr_type_src_node,
27693 buf_sprintf("@%s does not support type '%s'",
27694 float_op_to_name(op, false), buf_ptr(&float_type->name)));
27307 return ira->codegen->invalid_instruction;27695 return ira->codegen->invalid_instruction;
27308 }27696 }
2730927697
27310 IrInstruction *op1 = instruction->op1->child;27698 IrInstruction *casted_op = ir_implicit_cast(ira, operand, float_type);
27311 if (type_is_invalid(op1->value->type))27699 if (type_is_invalid(casted_op->value->type))
27312 return ira->codegen->invalid_instruction;
27313
27314 IrInstruction *casted_op1 = ir_implicit_cast(ira, op1, float_type);
27315 if (type_is_invalid(casted_op1->value->type))
27316 return ira->codegen->invalid_instruction;27700 return ira->codegen->invalid_instruction;
2731727701
27318 if (instr_is_comptime(casted_op1)) {27702 if (instr_is_comptime(casted_op)) {
27319 // Our comptime 16-bit and 128-bit support is quite limited.
27320 if ((float_type->id == ZigTypeIdComptimeFloat ||27703 if ((float_type->id == ZigTypeIdComptimeFloat ||
27321 float_type->data.floating.bit_count == 16 ||27704 float_type->data.floating.bit_count == 16 ||
27322 float_type->data.floating.bit_count == 128) &&27705 float_type->data.floating.bit_count == 128) &&
27323 instruction->op != BuiltinFnIdSqrt) {27706 op != BuiltinFnIdSqrt)
27324 ir_add_error(ira, instruction->type, buf_sprintf("@%s does not support type '%s'", float_op_to_name(instruction->op, false), buf_ptr(&float_type->name)));27707 {
27708 ir_add_error(ira, source_instr,
27709 buf_sprintf("compiler bug: TODO make @%s support type '%s'",
27710 float_op_to_name(op, false), buf_ptr(&float_type->name)));
27325 return ira->codegen->invalid_instruction;27711 return ira->codegen->invalid_instruction;
27326 }27712 }
2732727713
27328 ZigValue *op1_const = ir_resolve_const(ira, casted_op1, UndefBad);27714 ZigValue *op1_const = ir_resolve_const(ira, casted_op, UndefBad);
27329 if (!op1_const)27715 if (!op1_const)
27330 return ira->codegen->invalid_instruction;27716 return ira->codegen->invalid_instruction;
2733127717
27332 IrInstruction *result = ir_const(ira, &instruction->base, expr_type);27718 IrInstruction *result = ir_const(ira, source_instr, expr_type);
27333 ZigValue *out_val = result->value;27719 ZigValue *out_val = result->value;
2733427720
27335 if (expr_type->id == ZigTypeIdVector) {27721 if (expr_type->id == ZigTypeIdVector) {
...@@ -27342,26 +27728,38 @@ static IrInstruction *ir_analyze_instruction_float_op(IrAnalyze *ira, IrInstruct...@@ -27342,26 +27728,38 @@ static IrInstruction *ir_analyze_instruction_float_op(IrAnalyze *ira, IrInstruct
27342 ZigValue *float_out_val = &out_val->data.x_array.data.s_none.elements[i];27728 ZigValue *float_out_val = &out_val->data.x_array.data.s_none.elements[i];
27343 assert(float_operand_op1->type == float_type);27729 assert(float_operand_op1->type == float_type);
27344 assert(float_out_val->type == float_type);27730 assert(float_out_val->type == float_type);
27345 ir_eval_float_op(ira, instruction, float_type,27731 ir_eval_float_op(ira, source_instr, op, float_type, op1_const, float_out_val);
27346 op1_const, float_out_val);
27347 float_out_val->type = float_type;27732 float_out_val->type = float_type;
27348 }27733 }
27349 out_val->type = expr_type;27734 out_val->type = expr_type;
27350 out_val->special = ConstValSpecialStatic;27735 out_val->special = ConstValSpecialStatic;
27351 } else {27736 } else {
27352 ir_eval_float_op(ira, instruction, float_type, op1_const, out_val);27737 ir_eval_float_op(ira, source_instr, op, float_type, op1_const, out_val);
27353 }27738 }
27354 return result;27739 return result;
27355 }27740 }
2735627741
27357 ir_assert(float_type->id == ZigTypeIdFloat, &instruction->base);27742 ir_assert(float_type->id == ZigTypeIdFloat, source_instr);
2735827743
27359 IrInstruction *result = ir_build_float_op(&ira->new_irb, instruction->base.scope,27744 IrInstruction *result = ir_build_float_op(&ira->new_irb, source_instr->scope,
27360 instruction->base.source_node, nullptr, casted_op1, instruction->op);27745 source_instr->source_node, nullptr, casted_op, op);
27361 result->value->type = expr_type;27746 result->value->type = expr_type;
27362 return result;27747 return result;
27363}27748}
2736427749
27750static IrInstruction *ir_analyze_instruction_float_op(IrAnalyze *ira, IrInstructionFloatOp *instruction) {
27751 ZigType *expr_type = ir_resolve_type(ira, instruction->type->child);
27752 if (type_is_invalid(expr_type))
27753 return ira->codegen->invalid_instruction;
27754
27755 IrInstruction *operand = instruction->op1->child;
27756 if (type_is_invalid(operand->value->type))
27757 return ira->codegen->invalid_instruction;
27758
27759 return ir_analyze_float_op(ira, &instruction->base, expr_type, instruction->type->source_node,
27760 operand, instruction->op);
27761}
27762
27365static IrInstruction *ir_analyze_instruction_bswap(IrAnalyze *ira, IrInstructionBswap *instruction) {27763static IrInstruction *ir_analyze_instruction_bswap(IrAnalyze *ira, IrInstructionBswap *instruction) {
27366 Error err;27764 Error err;
2736727765
test/compile_errors.zig+25-33
...@@ -4174,58 +4174,50 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4174,58 +4174,50 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4174 "tmp.zig:3:5: error: use of undefined value here causes undefined behavior",4174 "tmp.zig:3:5: error: use of undefined value here causes undefined behavior",
4175 });4175 });
41764176
4177 cases.add("equal on undefined value",4177 cases.add("comparison operators with undefined value",
4178 \\// operator ==
4178 \\comptime {4179 \\comptime {
4179 \\ var a: i64 = undefined;4180 \\ var a: i64 = undefined;
4180 \\ _ = a == a;4181 \\ var x: i32 = 0;
4182 \\ if (a == a) x += 1;
4181 \\}4183 \\}
4182 , &[_][]const u8{4184 \\// operator !=
4183 "tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
4184 });
4185
4186 cases.add("not equal on undefined value",
4187 \\comptime {4185 \\comptime {
4188 \\ var a: i64 = undefined;4186 \\ var a: i64 = undefined;
4189 \\ _ = a != a;4187 \\ var x: i32 = 0;
4188 \\ if (a != a) x += 1;
4190 \\}4189 \\}
4191 , &[_][]const u8{4190 \\// operator >
4192 "tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
4193 });
4194
4195 cases.add("greater than on undefined value",
4196 \\comptime {4191 \\comptime {
4197 \\ var a: i64 = undefined;4192 \\ var a: i64 = undefined;
4198 \\ _ = a > a;4193 \\ var x: i32 = 0;
4194 \\ if (a > a) x += 1;
4199 \\}4195 \\}
4200 , &[_][]const u8{4196 \\// operator <
4201 "tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
4202 });
4203
4204 cases.add("greater than equal on undefined value",
4205 \\comptime {4197 \\comptime {
4206 \\ var a: i64 = undefined;4198 \\ var a: i64 = undefined;
4207 \\ _ = a >= a;4199 \\ var x: i32 = 0;
4200 \\ if (a < a) x += 1;
4208 \\}4201 \\}
4209 , &[_][]const u8{4202 \\// operator >=
4210 "tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
4211 });
4212
4213 cases.add("less than on undefined value",
4214 \\comptime {4203 \\comptime {
4215 \\ var a: i64 = undefined;4204 \\ var a: i64 = undefined;
4216 \\ _ = a < a;4205 \\ var x: i32 = 0;
4206 \\ if (a >= a) x += 1;
4217 \\}4207 \\}
4218 , &[_][]const u8{4208 \\// operator <=
4219 "tmp.zig:3:9: error: use of undefined value here causes undefined behavior",
4220 });
4221
4222 cases.add("less than equal on undefined value",
4223 \\comptime {4209 \\comptime {
4224 \\ var a: i64 = undefined;4210 \\ var a: i64 = undefined;
4225 \\ _ = a <= a;4211 \\ var x: i32 = 0;
4212 \\ if (a <= a) x += 1;
4226 \\}4213 \\}
4227 , &[_][]const u8{4214 , &[_][]const u8{
4228 "tmp.zig:3:9: error: use of undefined value here causes undefined behavior",4215 "tmp.zig:5:11: error: use of undefined value here causes undefined behavior",
4216 "tmp.zig:11:11: error: use of undefined value here causes undefined behavior",
4217 "tmp.zig:17:11: error: use of undefined value here causes undefined behavior",
4218 "tmp.zig:23:11: error: use of undefined value here causes undefined behavior",
4219 "tmp.zig:29:11: error: use of undefined value here causes undefined behavior",
4220 "tmp.zig:35:11: error: use of undefined value here causes undefined behavior",
4229 });4221 });
42304222
4231 cases.add("and on undefined value",4223 cases.add("and on undefined value",