| ... | ... | @@ -11682,28 +11682,34 @@ static IrInstruction *ir_analyze_bin_op_bool(IrAnalyze *ira, IrInstructionBinOp |
| 11682 | 11682 | } |
| 11683 | 11683 | |
| 11684 | 11684 | static bool resolve_cmp_op_id(IrBinOp op_id, Cmp cmp) { |
| 11685 | | if (op_id == IrBinOpCmpEq) { |
| 11686 | | return cmp == CmpEQ; |
| 11687 | | } else if (op_id == IrBinOpCmpNotEq) { |
| 11688 | | return cmp != CmpEQ; |
| 11689 | | } else if (op_id == IrBinOpCmpLessThan) { |
| 11690 | | return cmp == CmpLT; |
| 11691 | | } else if (op_id == IrBinOpCmpGreaterThan) { |
| 11692 | | return cmp == CmpGT; |
| 11693 | | } else if (op_id == IrBinOpCmpLessOrEq) { |
| 11694 | | return cmp != CmpGT; |
| 11695 | | } else if (op_id == IrBinOpCmpGreaterOrEq) { |
| 11696 | | return cmp != CmpLT; |
| 11697 | | } else { |
| 11698 | | zig_unreachable(); |
| 11685 | switch (op_id) { |
| 11686 | case IrBinOpCmpEq: |
| 11687 | return cmp == CmpEQ; |
| 11688 | case IrBinOpCmpNotEq: |
| 11689 | return cmp != CmpEQ; |
| 11690 | case IrBinOpCmpLessThan: |
| 11691 | return cmp == CmpLT; |
| 11692 | case IrBinOpCmpGreaterThan: |
| 11693 | return cmp == CmpGT; |
| 11694 | case IrBinOpCmpLessOrEq: |
| 11695 | return cmp != CmpGT; |
| 11696 | case IrBinOpCmpGreaterOrEq: |
| 11697 | return cmp != CmpLT; |
| 11698 | default: |
| 11699 | zig_unreachable(); |
| 11699 | 11700 | } |
| 11700 | 11701 | } |
| 11701 | 11702 | |
| 11702 | 11703 | static bool optional_value_is_null(ConstExprValue *val) { |
| 11703 | 11704 | assert(val->special == ConstValSpecialStatic); |
| 11704 | 11705 | if (get_codegen_ptr_type(val->type) != nullptr) { |
| 11705 | | return val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr && |
| 11706 | | val->data.x_ptr.data.hard_coded_addr.addr == 0; |
| 11706 | if (val->data.x_ptr.special == ConstPtrSpecialNull) { |
| 11707 | return true; |
| 11708 | } else if (val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) { |
| 11709 | return val->data.x_ptr.data.hard_coded_addr.addr == 0; |
| 11710 | } else { |
| 11711 | return false; |
| 11712 | } |
| 11707 | 11713 | } else if (is_opt_err_set(val->type)) { |
| 11708 | 11714 | return val->data.x_err_set == nullptr; |
| 11709 | 11715 | } else { |
| ... | ... | @@ -11879,7 +11885,7 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp * |
| 11879 | 11885 | break; |
| 11880 | 11886 | |
| 11881 | 11887 | case ZigTypeIdPointer: |
| 11882 | | operator_allowed = is_equality_cmp || (resolved_type->data.pointer.ptr_len != PtrLenSingle); |
| 11888 | operator_allowed = is_equality_cmp || (resolved_type->data.pointer.ptr_len == PtrLenC); |
| 11883 | 11889 | break; |
| 11884 | 11890 | |
| 11885 | 11891 | case ZigTypeIdUnreachable: |
| ... | ... | @@ -11929,15 +11935,38 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp * |
| 11929 | 11935 | if (op2_val == nullptr) |
| 11930 | 11936 | return ira->codegen->invalid_instruction; |
| 11931 | 11937 | |
| 11932 | | bool answer; |
| 11933 | 11938 | if (resolved_type->id == ZigTypeIdComptimeFloat || resolved_type->id == ZigTypeIdFloat) { |
| 11934 | 11939 | Cmp cmp_result = float_cmp(op1_val, op2_val); |
| 11935 | | answer = resolve_cmp_op_id(op_id, cmp_result); |
| 11940 | bool answer = resolve_cmp_op_id(op_id, cmp_result); |
| 11941 | return ir_const_bool(ira, &bin_op_instruction->base, answer); |
| 11936 | 11942 | } else if (resolved_type->id == ZigTypeIdComptimeInt || resolved_type->id == ZigTypeIdInt) { |
| 11937 | 11943 | Cmp cmp_result = bigint_cmp(&op1_val->data.x_bigint, &op2_val->data.x_bigint); |
| 11938 | | answer = resolve_cmp_op_id(op_id, cmp_result); |
| 11944 | bool answer = resolve_cmp_op_id(op_id, cmp_result); |
| 11945 | return ir_const_bool(ira, &bin_op_instruction->base, answer); |
| 11946 | } else if (resolved_type->id == ZigTypeIdPointer && op_id != IrBinOpCmpEq && op_id != IrBinOpCmpNotEq) { |
| 11947 | if ((op1_val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr || |
| 11948 | op1_val->data.x_ptr.special == ConstPtrSpecialNull) && |
| 11949 | (op2_val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr || |
| 11950 | op2_val->data.x_ptr.special == ConstPtrSpecialNull)) |
| 11951 | { |
| 11952 | uint64_t op1_addr = op1_val->data.x_ptr.special == ConstPtrSpecialNull ? |
| 11953 | 0 : op1_val->data.x_ptr.data.hard_coded_addr.addr; |
| 11954 | uint64_t op2_addr = op2_val->data.x_ptr.special == ConstPtrSpecialNull ? |
| 11955 | 0 : op2_val->data.x_ptr.data.hard_coded_addr.addr; |
| 11956 | Cmp cmp_result; |
| 11957 | if (op1_addr > op2_addr) { |
| 11958 | cmp_result = CmpGT; |
| 11959 | } else if (op1_addr < op2_addr) { |
| 11960 | cmp_result = CmpLT; |
| 11961 | } else { |
| 11962 | cmp_result = CmpEQ; |
| 11963 | } |
| 11964 | bool answer = resolve_cmp_op_id(op_id, cmp_result); |
| 11965 | return ir_const_bool(ira, &bin_op_instruction->base, answer); |
| 11966 | } |
| 11939 | 11967 | } else { |
| 11940 | 11968 | bool are_equal = one_possible_value || const_values_equal(ira->codegen, op1_val, op2_val); |
| 11969 | bool answer; |
| 11941 | 11970 | if (op_id == IrBinOpCmpEq) { |
| 11942 | 11971 | answer = are_equal; |
| 11943 | 11972 | } else if (op_id == IrBinOpCmpNotEq) { |
| ... | ... | @@ -11945,9 +11974,8 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp * |
| 11945 | 11974 | } else { |
| 11946 | 11975 | zig_unreachable(); |
| 11947 | 11976 | } |
| 11977 | return ir_const_bool(ira, &bin_op_instruction->base, answer); |
| 11948 | 11978 | } |
| 11949 | | |
| 11950 | | return ir_const_bool(ira, &bin_op_instruction->base, answer); |
| 11951 | 11979 | } |
| 11952 | 11980 | |
| 11953 | 11981 | // some comparisons with unsigned numbers can be evaluated |
| ... | ... | @@ -12363,6 +12391,8 @@ static bool is_pointer_arithmetic_allowed(ZigType *lhs_type, IrBinOp op) { |
| 12363 | 12391 | } |
| 12364 | 12392 | |
| 12365 | 12393 | static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp *instruction) { |
| 12394 | Error err; |
| 12395 | |
| 12366 | 12396 | IrInstruction *op1 = instruction->op1->child; |
| 12367 | 12397 | if (type_is_invalid(op1->value.type)) |
| 12368 | 12398 | return ira->codegen->invalid_instruction; |
| ... | ... | @@ -12376,9 +12406,42 @@ static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp |
| 12376 | 12406 | // look for pointer math |
| 12377 | 12407 | if (is_pointer_arithmetic_allowed(op1->value.type, op_id)) { |
| 12378 | 12408 | IrInstruction *casted_op2 = ir_implicit_cast(ira, op2, ira->codegen->builtin_types.entry_usize); |
| 12379 | | if (casted_op2 == ira->codegen->invalid_instruction) |
| 12409 | if (type_is_invalid(casted_op2->value.type)) |
| 12380 | 12410 | return ira->codegen->invalid_instruction; |
| 12381 | 12411 | |
| 12412 | if (op1->value.special == ConstValSpecialUndef || casted_op2->value.special == ConstValSpecialUndef) { |
| 12413 | IrInstruction *result = ir_const(ira, &instruction->base, op1->value.type); |
| 12414 | result->value.special = ConstValSpecialUndef; |
| 12415 | return result; |
| 12416 | } |
| 12417 | if (casted_op2->value.special == ConstValSpecialStatic && op1->value.special == ConstValSpecialStatic && |
| 12418 | (op1->value.data.x_ptr.special == ConstPtrSpecialHardCodedAddr || |
| 12419 | op1->value.data.x_ptr.special == ConstPtrSpecialNull)) |
| 12420 | { |
| 12421 | uint64_t start_addr = (op1->value.data.x_ptr.special == ConstPtrSpecialNull) ? |
| 12422 | 0 : op1->value.data.x_ptr.data.hard_coded_addr.addr; |
| 12423 | uint64_t elem_offset; |
| 12424 | if (!ir_resolve_usize(ira, casted_op2, &elem_offset)) |
| 12425 | return ira->codegen->invalid_instruction; |
| 12426 | ZigType *elem_type = op1->value.type->data.pointer.child_type; |
| 12427 | if ((err = type_resolve(ira->codegen, elem_type, ResolveStatusSizeKnown))) |
| 12428 | return ira->codegen->invalid_instruction; |
| 12429 | uint64_t byte_offset = type_size(ira->codegen, elem_type) * elem_offset; |
| 12430 | uint64_t new_addr; |
| 12431 | if (op_id == IrBinOpAdd) { |
| 12432 | new_addr = start_addr + byte_offset; |
| 12433 | } else if (op_id == IrBinOpSub) { |
| 12434 | new_addr = start_addr - byte_offset; |
| 12435 | } else { |
| 12436 | zig_unreachable(); |
| 12437 | } |
| 12438 | IrInstruction *result = ir_const(ira, &instruction->base, op1->value.type); |
| 12439 | result->value.data.x_ptr.special = ConstPtrSpecialHardCodedAddr; |
| 12440 | result->value.data.x_ptr.mut = ConstPtrMutRuntimeVar; |
| 12441 | result->value.data.x_ptr.data.hard_coded_addr.addr = new_addr; |
| 12442 | return result; |
| 12443 | } |
| 12444 | |
| 12382 | 12445 | IrInstruction *result = ir_build_bin_op(&ira->new_irb, instruction->base.scope, |
| 12383 | 12446 | instruction->base.source_node, op_id, op1, casted_op2, true); |
| 12384 | 12447 | result->value.type = op1->value.type; |