| ... | @@ -12932,7 +12932,52 @@ static bool optional_value_is_null(ConstExprValue *val) { | ... | @@ -12932,7 +12932,52 @@ static bool optional_value_is_null(ConstExprValue *val) { |
| 12932 | } | 12932 | } |
| 12933 | } | 12933 | } |
| 12934 | | 12934 | |
| | 12935 | // Returns ErrorNotLazy when the value cannot be determined |
| | 12936 | static Error lazy_cmp_zero(AstNode *source_node, ConstExprValue *val, Cmp *result) { |
| | 12937 | Error err; |
| | 12938 | |
| | 12939 | switch (val->special) { |
| | 12940 | case ConstValSpecialRuntime: |
| | 12941 | case ConstValSpecialUndef: |
| | 12942 | return ErrorNotLazy; |
| | 12943 | case ConstValSpecialStatic: |
| | 12944 | switch (val->type->id) { |
| | 12945 | case ZigTypeIdComptimeInt: |
| | 12946 | case ZigTypeIdInt: |
| | 12947 | *result = bigint_cmp_zero(&val->data.x_bigint); |
| | 12948 | return ErrorNone; |
| | 12949 | default: |
| | 12950 | return ErrorNotLazy; |
| | 12951 | } |
| | 12952 | case ConstValSpecialLazy: |
| | 12953 | switch (val->data.x_lazy->id) { |
| | 12954 | case LazyValueIdInvalid: |
| | 12955 | zig_unreachable(); |
| | 12956 | case LazyValueIdAlignOf: |
| | 12957 | *result = CmpGT; |
| | 12958 | return ErrorNone; |
| | 12959 | case LazyValueIdSizeOf: { |
| | 12960 | LazyValueSizeOf *lazy_size_of = reinterpret_cast<LazyValueSizeOf *>(val->data.x_lazy); |
| | 12961 | IrAnalyze *ira = lazy_size_of->ira; |
| | 12962 | bool is_zero_bits; |
| | 12963 | if ((err = type_val_resolve_zero_bits(ira->codegen, &lazy_size_of->target_type->value, |
| | 12964 | nullptr, nullptr, &is_zero_bits))) |
| | 12965 | { |
| | 12966 | return err; |
| | 12967 | } |
| | 12968 | *result = is_zero_bits ? CmpEQ : CmpGT; |
| | 12969 | return ErrorNone; |
| | 12970 | } |
| | 12971 | default: |
| | 12972 | return ErrorNotLazy; |
| | 12973 | } |
| | 12974 | } |
| | 12975 | zig_unreachable(); |
| | 12976 | } |
| | 12977 | |
| 12935 | static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) { | 12978 | static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) { |
| | 12979 | Error err; |
| | 12980 | |
| 12936 | IrInstruction *op1 = bin_op_instruction->op1->child; | 12981 | IrInstruction *op1 = bin_op_instruction->op1->child; |
| 12937 | if (type_is_invalid(op1->value.type)) | 12982 | if (type_is_invalid(op1->value.type)) |
| 12938 | return ira->codegen->invalid_instruction; | 12983 | return ira->codegen->invalid_instruction; |
| ... | @@ -13182,6 +13227,50 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp * | ... | @@ -13182,6 +13227,50 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp * |
| 13182 | } | 13227 | } |
| 13183 | | 13228 | |
| 13184 | if (one_possible_value || (instr_is_comptime(casted_op1) && instr_is_comptime(casted_op2))) { | 13229 | if (one_possible_value || (instr_is_comptime(casted_op1) && instr_is_comptime(casted_op2))) { |
| | 13230 | { |
| | 13231 | // Before resolving the values, we special case comparisons against zero. These can often be done |
| | 13232 | // without resolving lazy values, preventing potential dependency loops. |
| | 13233 | Cmp op1_cmp_zero; |
| | 13234 | if ((err = lazy_cmp_zero(bin_op_instruction->base.source_node, &casted_op1->value, &op1_cmp_zero))) { |
| | 13235 | if (err == ErrorNotLazy) goto never_mind_just_calculate_it_normally; |
| | 13236 | return ira->codegen->invalid_instruction; |
| | 13237 | } |
| | 13238 | Cmp op2_cmp_zero; |
| | 13239 | if ((err = lazy_cmp_zero(bin_op_instruction->base.source_node, &casted_op2->value, &op2_cmp_zero))) { |
| | 13240 | if (err == ErrorNotLazy) goto never_mind_just_calculate_it_normally; |
| | 13241 | return ira->codegen->invalid_instruction; |
| | 13242 | } |
| | 13243 | bool can_cmp_zero = false; |
| | 13244 | Cmp cmp_result; |
| | 13245 | if (op1_cmp_zero == CmpEQ && op2_cmp_zero == CmpEQ) { |
| | 13246 | can_cmp_zero = true; |
| | 13247 | cmp_result = CmpEQ; |
| | 13248 | } else if (op1_cmp_zero == CmpGT && op2_cmp_zero == CmpEQ) { |
| | 13249 | can_cmp_zero = true; |
| | 13250 | cmp_result = CmpGT; |
| | 13251 | } else if (op1_cmp_zero == CmpEQ && op2_cmp_zero == CmpGT) { |
| | 13252 | can_cmp_zero = true; |
| | 13253 | cmp_result = CmpLT; |
| | 13254 | } else if (op1_cmp_zero == CmpLT && op2_cmp_zero == CmpEQ) { |
| | 13255 | can_cmp_zero = true; |
| | 13256 | cmp_result = CmpLT; |
| | 13257 | } else if (op1_cmp_zero == CmpEQ && op2_cmp_zero == CmpLT) { |
| | 13258 | can_cmp_zero = true; |
| | 13259 | cmp_result = CmpGT; |
| | 13260 | } else if (op1_cmp_zero == CmpLT && op2_cmp_zero == CmpGT) { |
| | 13261 | can_cmp_zero = true; |
| | 13262 | cmp_result = CmpLT; |
| | 13263 | } else if (op1_cmp_zero == CmpGT && op2_cmp_zero == CmpLT) { |
| | 13264 | can_cmp_zero = true; |
| | 13265 | cmp_result = CmpGT; |
| | 13266 | } |
| | 13267 | if (can_cmp_zero) { |
| | 13268 | bool answer = resolve_cmp_op_id(op_id, cmp_result); |
| | 13269 | return ir_const_bool(ira, &bin_op_instruction->base, answer); |
| | 13270 | } |
| | 13271 | } |
| | 13272 | never_mind_just_calculate_it_normally: |
| | 13273 | |
| 13185 | ConstExprValue *op1_val = one_possible_value ? &casted_op1->value : ir_resolve_const(ira, casted_op1, UndefBad); | 13274 | ConstExprValue *op1_val = one_possible_value ? &casted_op1->value : ir_resolve_const(ira, casted_op1, UndefBad); |
| 13186 | if (op1_val == nullptr) | 13275 | if (op1_val == nullptr) |
| 13187 | return ira->codegen->invalid_instruction; | 13276 | return ira->codegen->invalid_instruction; |