| ... | ... | @@ -306,6 +306,14 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionStructInit *) { |
| 306 | 306 | return IrInstructionIdStructInit; |
| 307 | 307 | } |
| 308 | 308 | |
| 309 | static constexpr IrInstructionId ir_instruction_id(IrInstructionMinValue *) { |
| 310 | return IrInstructionIdMinValue; |
| 311 | } |
| 312 | |
| 313 | static constexpr IrInstructionId ir_instruction_id(IrInstructionMaxValue *) { |
| 314 | return IrInstructionIdMaxValue; |
| 315 | } |
| 316 | |
| 309 | 317 | template<typename T> |
| 310 | 318 | static T *ir_create_instruction(IrExecutable *exec, Scope *scope, AstNode *source_node) { |
| 311 | 319 | T *special_instruction = allocate<T>(1); |
| ... | ... | @@ -1241,6 +1249,25 @@ static IrInstruction *ir_build_ref_from(IrBuilder *irb, IrInstruction *old_instr |
| 1241 | 1249 | return new_instruction; |
| 1242 | 1250 | } |
| 1243 | 1251 | |
| 1252 | static IrInstruction *ir_build_min_value(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) { |
| 1253 | IrInstructionMinValue *instruction = ir_build_instruction<IrInstructionMinValue>(irb, scope, source_node); |
| 1254 | instruction->value = value; |
| 1255 | |
| 1256 | ir_ref_instruction(value); |
| 1257 | |
| 1258 | return &instruction->base; |
| 1259 | } |
| 1260 | |
| 1261 | static IrInstruction *ir_build_max_value(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) { |
| 1262 | IrInstructionMaxValue *instruction = ir_build_instruction<IrInstructionMaxValue>(irb, scope, source_node); |
| 1263 | instruction->value = value; |
| 1264 | |
| 1265 | ir_ref_instruction(value); |
| 1266 | |
| 1267 | return &instruction->base; |
| 1268 | } |
| 1269 | |
| 1270 | |
| 1244 | 1271 | static void ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, |
| 1245 | 1272 | bool gen_error_defers, bool gen_maybe_defers) |
| 1246 | 1273 | { |
| ... | ... | @@ -1879,11 +1906,27 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 1879 | 1906 | |
| 1880 | 1907 | return ir_build_import(irb, scope, node, arg0_value); |
| 1881 | 1908 | } |
| 1909 | case BuiltinFnIdMaxValue: |
| 1910 | { |
| 1911 | AstNode *arg0_node = node->data.fn_call_expr.params.at(0); |
| 1912 | IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); |
| 1913 | if (arg0_value == irb->codegen->invalid_instruction) |
| 1914 | return arg0_value; |
| 1915 | |
| 1916 | return ir_build_max_value(irb, scope, node, arg0_value); |
| 1917 | } |
| 1918 | case BuiltinFnIdMinValue: |
| 1919 | { |
| 1920 | AstNode *arg0_node = node->data.fn_call_expr.params.at(0); |
| 1921 | IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); |
| 1922 | if (arg0_value == irb->codegen->invalid_instruction) |
| 1923 | return arg0_value; |
| 1924 | |
| 1925 | return ir_build_min_value(irb, scope, node, arg0_value); |
| 1926 | } |
| 1882 | 1927 | case BuiltinFnIdMemcpy: |
| 1883 | 1928 | case BuiltinFnIdMemset: |
| 1884 | 1929 | case BuiltinFnIdAlignof: |
| 1885 | | case BuiltinFnIdMaxValue: |
| 1886 | | case BuiltinFnIdMinValue: |
| 1887 | 1930 | case BuiltinFnIdMemberCount: |
| 1888 | 1931 | case BuiltinFnIdAddWithOverflow: |
| 1889 | 1932 | case BuiltinFnIdSubWithOverflow: |
| ... | ... | @@ -4670,7 +4713,7 @@ static TypeTableEntry *ir_analyze_instruction_call(IrAnalyze *ira, IrInstruction |
| 4670 | 4713 | if (is_inline || fn_ref->static_value.special != ConstValSpecialRuntime) { |
| 4671 | 4714 | if (fn_ref->type_entry->id == TypeTableEntryIdMetaType) { |
| 4672 | 4715 | TypeTableEntry *dest_type = ir_resolve_type(ira, fn_ref); |
| 4673 | | if (!dest_type) |
| 4716 | if (dest_type->id == TypeTableEntryIdInvalid) |
| 4674 | 4717 | return ira->codegen->builtin_types.entry_invalid; |
| 4675 | 4718 | |
| 4676 | 4719 | size_t actual_param_count = call_instruction->arg_count; |
| ... | ... | @@ -4958,6 +5001,48 @@ static TypeTableEntry *ir_analyze_unwrap_maybe(IrAnalyze *ira, IrInstructionUnOp |
| 4958 | 5001 | } |
| 4959 | 5002 | } |
| 4960 | 5003 | |
| 5004 | static TypeTableEntry *ir_analyze_negation(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction) { |
| 5005 | IrInstruction *value = un_op_instruction->value->other; |
| 5006 | TypeTableEntry *expr_type = value->type_entry; |
| 5007 | if (expr_type->id == TypeTableEntryIdInvalid) |
| 5008 | return ira->codegen->builtin_types.entry_invalid; |
| 5009 | |
| 5010 | bool is_wrap_op = (un_op_instruction->op_id == IrUnOpNegationWrap); |
| 5011 | |
| 5012 | if ((expr_type->id == TypeTableEntryIdInt && expr_type->data.integral.is_signed) || |
| 5013 | expr_type->id == TypeTableEntryIdNumLitInt || |
| 5014 | ((expr_type->id == TypeTableEntryIdFloat || expr_type->id == TypeTableEntryIdNumLitFloat) && |
| 5015 | !is_wrap_op)) |
| 5016 | { |
| 5017 | ConstExprValue *target_const_val = &value->static_value; |
| 5018 | if (target_const_val->special != ConstValSpecialRuntime) { |
| 5019 | bool depends_on_compile_var = value->static_value.depends_on_compile_var; |
| 5020 | ConstExprValue *out_val = ir_build_const_from(ira, &un_op_instruction->base, depends_on_compile_var); |
| 5021 | bignum_negate(&out_val->data.x_bignum, &target_const_val->data.x_bignum); |
| 5022 | if (expr_type->id == TypeTableEntryIdFloat || |
| 5023 | expr_type->id == TypeTableEntryIdNumLitFloat || |
| 5024 | expr_type->id == TypeTableEntryIdNumLitInt) |
| 5025 | { |
| 5026 | return expr_type; |
| 5027 | } |
| 5028 | |
| 5029 | bool overflow = !bignum_fits_in_bits(&out_val->data.x_bignum, expr_type->data.integral.bit_count, true); |
| 5030 | if (is_wrap_op) { |
| 5031 | if (overflow) |
| 5032 | out_val->data.x_bignum.is_negative = true; |
| 5033 | } else if (overflow) { |
| 5034 | ir_add_error(ira, &un_op_instruction->base, buf_sprintf("negation caused overflow")); |
| 5035 | return ira->codegen->builtin_types.entry_invalid; |
| 5036 | } |
| 5037 | return expr_type; |
| 5038 | } |
| 5039 | } |
| 5040 | |
| 5041 | const char *fmt = is_wrap_op ? "invalid wrapping negation type: '%s'" : "invalid negation type: '%s'"; |
| 5042 | ir_add_error(ira, &un_op_instruction->base, buf_sprintf(fmt, buf_ptr(&expr_type->name))); |
| 5043 | return ira->codegen->builtin_types.entry_invalid; |
| 5044 | } |
| 5045 | |
| 4961 | 5046 | static TypeTableEntry *ir_analyze_instruction_un_op(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction) { |
| 4962 | 5047 | IrUnOp op_id = un_op_instruction->op_id; |
| 4963 | 5048 | switch (op_id) { |
| ... | ... | @@ -4983,51 +5068,7 @@ static TypeTableEntry *ir_analyze_instruction_un_op(IrAnalyze *ira, IrInstructio |
| 4983 | 5068 | //} |
| 4984 | 5069 | case IrUnOpNegation: |
| 4985 | 5070 | case IrUnOpNegationWrap: |
| 4986 | | zig_panic("TODO analyze PrefixOpNegation[Wrap]"); |
| 4987 | | //{ |
| 4988 | | // TypeTableEntry *expr_type = analyze_expression(g, import, context, nullptr, *expr_node); |
| 4989 | | // if (expr_type->id == TypeTableEntryIdInvalid) { |
| 4990 | | // return expr_type; |
| 4991 | | // } else if ((expr_type->id == TypeTableEntryIdInt && |
| 4992 | | // expr_type->data.integral.is_signed) || |
| 4993 | | // expr_type->id == TypeTableEntryIdNumLitInt || |
| 4994 | | // ((expr_type->id == TypeTableEntryIdFloat || |
| 4995 | | // expr_type->id == TypeTableEntryIdNumLitFloat) && |
| 4996 | | // prefix_op != PrefixOpNegationWrap)) |
| 4997 | | // { |
| 4998 | | // ConstExprValue *target_const_val = &get_resolved_expr(*expr_node)->const_val; |
| 4999 | | // if (!target_const_val->ok) { |
| 5000 | | // return expr_type; |
| 5001 | | // } |
| 5002 | | // ConstExprValue *const_val = &get_resolved_expr(node)->const_val; |
| 5003 | | // const_val->ok = true; |
| 5004 | | // const_val->depends_on_compile_var = target_const_val->depends_on_compile_var; |
| 5005 | | // bignum_negate(&const_val->data.x_bignum, &target_const_val->data.x_bignum); |
| 5006 | | // if (expr_type->id == TypeTableEntryIdFloat || |
| 5007 | | // expr_type->id == TypeTableEntryIdNumLitFloat || |
| 5008 | | // expr_type->id == TypeTableEntryIdNumLitInt) |
| 5009 | | // { |
| 5010 | | // return expr_type; |
| 5011 | | // } |
| 5012 | | |
| 5013 | | // bool overflow = !bignum_fits_in_bits(&const_val->data.x_bignum, |
| 5014 | | // expr_type->data.integral.bit_count, expr_type->data.integral.is_signed); |
| 5015 | | // if (prefix_op == PrefixOpNegationWrap) { |
| 5016 | | // if (overflow) { |
| 5017 | | // const_val->data.x_bignum.is_negative = true; |
| 5018 | | // } |
| 5019 | | // } else if (overflow) { |
| 5020 | | // add_node_error(g, *expr_node, buf_sprintf("negation caused overflow")); |
| 5021 | | // return g->builtin_types.entry_invalid; |
| 5022 | | // } |
| 5023 | | // return expr_type; |
| 5024 | | // } else { |
| 5025 | | // const char *fmt = (prefix_op == PrefixOpNegationWrap) ? |
| 5026 | | // "invalid wrapping negation type: '%s'" : "invalid negation type: '%s'"; |
| 5027 | | // add_node_error(g, node, buf_sprintf(fmt, buf_ptr(&expr_type->name))); |
| 5028 | | // return g->builtin_types.entry_invalid; |
| 5029 | | // } |
| 5030 | | //} |
| 5071 | return ir_analyze_negation(ira, un_op_instruction); |
| 5031 | 5072 | case IrUnOpAddressOf: |
| 5032 | 5073 | case IrUnOpConstAddressOf: |
| 5033 | 5074 | return ir_analyze_unary_address_of(ira, un_op_instruction, op_id == IrUnOpConstAddressOf); |
| ... | ... | @@ -6575,7 +6616,7 @@ static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstru |
| 6575 | 6616 | static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira, IrInstructionContainerInitList *instruction) { |
| 6576 | 6617 | IrInstruction *container_type_value = instruction->container_type->other; |
| 6577 | 6618 | TypeTableEntry *container_type = ir_resolve_type(ira, container_type_value); |
| 6578 | | if (!container_type) |
| 6619 | if (container_type->id == TypeTableEntryIdInvalid) |
| 6579 | 6620 | return ira->codegen->builtin_types.entry_invalid; |
| 6580 | 6621 | |
| 6581 | 6622 | size_t elem_count = instruction->item_count; |
| ... | ... | @@ -6661,7 +6702,7 @@ static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira |
| 6661 | 6702 | static TypeTableEntry *ir_analyze_instruction_container_init_fields(IrAnalyze *ira, IrInstructionContainerInitFields *instruction) { |
| 6662 | 6703 | IrInstruction *container_type_value = instruction->container_type->other; |
| 6663 | 6704 | TypeTableEntry *container_type = ir_resolve_type(ira, container_type_value); |
| 6664 | | if (!container_type) |
| 6705 | if (container_type->id == TypeTableEntryIdInvalid) |
| 6665 | 6706 | return ira->codegen->builtin_types.entry_invalid; |
| 6666 | 6707 | |
| 6667 | 6708 | bool depends_on_compile_var = container_type_value->static_value.depends_on_compile_var; |
| ... | ... | @@ -6670,6 +6711,77 @@ static TypeTableEntry *ir_analyze_instruction_container_init_fields(IrAnalyze *i |
| 6670 | 6711 | instruction->field_count, instruction->fields, depends_on_compile_var); |
| 6671 | 6712 | } |
| 6672 | 6713 | |
| 6714 | static TypeTableEntry *ir_analyze_min_max(IrAnalyze *ira, IrInstruction *source_instruction, |
| 6715 | IrInstruction *target_type_value, bool is_max) |
| 6716 | { |
| 6717 | TypeTableEntry *target_type = ir_resolve_type(ira, target_type_value); |
| 6718 | bool depends_on_compile_var = target_type_value->static_value.depends_on_compile_var; |
| 6719 | switch (target_type->id) { |
| 6720 | case TypeTableEntryIdInvalid: |
| 6721 | return ira->codegen->builtin_types.entry_invalid; |
| 6722 | case TypeTableEntryIdInt: |
| 6723 | { |
| 6724 | ConstExprValue *out_val = ir_build_const_from(ira, source_instruction, depends_on_compile_var); |
| 6725 | eval_min_max_value(ira->codegen, target_type, out_val, is_max); |
| 6726 | return ira->codegen->builtin_types.entry_num_lit_int; |
| 6727 | } |
| 6728 | case TypeTableEntryIdFloat: |
| 6729 | { |
| 6730 | ConstExprValue *out_val = ir_build_const_from(ira, source_instruction, depends_on_compile_var); |
| 6731 | eval_min_max_value(ira->codegen, target_type, out_val, is_max); |
| 6732 | return ira->codegen->builtin_types.entry_num_lit_float; |
| 6733 | } |
| 6734 | case TypeTableEntryIdBool: |
| 6735 | case TypeTableEntryIdVoid: |
| 6736 | { |
| 6737 | ConstExprValue *out_val = ir_build_const_from(ira, source_instruction, depends_on_compile_var); |
| 6738 | eval_min_max_value(ira->codegen, target_type, out_val, is_max); |
| 6739 | return target_type; |
| 6740 | } |
| 6741 | case TypeTableEntryIdVar: |
| 6742 | case TypeTableEntryIdMetaType: |
| 6743 | case TypeTableEntryIdUnreachable: |
| 6744 | case TypeTableEntryIdPointer: |
| 6745 | case TypeTableEntryIdArray: |
| 6746 | case TypeTableEntryIdStruct: |
| 6747 | case TypeTableEntryIdNumLitFloat: |
| 6748 | case TypeTableEntryIdNumLitInt: |
| 6749 | case TypeTableEntryIdUndefLit: |
| 6750 | case TypeTableEntryIdNullLit: |
| 6751 | case TypeTableEntryIdMaybe: |
| 6752 | case TypeTableEntryIdErrorUnion: |
| 6753 | case TypeTableEntryIdPureError: |
| 6754 | case TypeTableEntryIdEnum: |
| 6755 | case TypeTableEntryIdUnion: |
| 6756 | case TypeTableEntryIdFn: |
| 6757 | case TypeTableEntryIdTypeDecl: |
| 6758 | case TypeTableEntryIdNamespace: |
| 6759 | case TypeTableEntryIdBlock: |
| 6760 | case TypeTableEntryIdBoundFn: |
| 6761 | { |
| 6762 | const char *err_format = is_max ? |
| 6763 | "no max value available for type '%s'" : |
| 6764 | "no min value available for type '%s'"; |
| 6765 | ir_add_error(ira, source_instruction, |
| 6766 | buf_sprintf(err_format, buf_ptr(&target_type->name))); |
| 6767 | return ira->codegen->builtin_types.entry_invalid; |
| 6768 | } |
| 6769 | } |
| 6770 | zig_unreachable(); |
| 6771 | } |
| 6772 | |
| 6773 | static TypeTableEntry *ir_analyze_instruction_min_value(IrAnalyze *ira, |
| 6774 | IrInstructionMinValue *instruction) |
| 6775 | { |
| 6776 | return ir_analyze_min_max(ira, &instruction->base, instruction->value->other, false); |
| 6777 | } |
| 6778 | |
| 6779 | static TypeTableEntry *ir_analyze_instruction_max_value(IrAnalyze *ira, |
| 6780 | IrInstructionMaxValue *instruction) |
| 6781 | { |
| 6782 | return ir_analyze_min_max(ira, &instruction->base, instruction->value->other, true); |
| 6783 | } |
| 6784 | |
| 6673 | 6785 | static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) { |
| 6674 | 6786 | switch (instruction->id) { |
| 6675 | 6787 | case IrInstructionIdInvalid: |
| ... | ... | @@ -6754,6 +6866,10 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi |
| 6754 | 6866 | return ir_analyze_instruction_container_init_list(ira, (IrInstructionContainerInitList *)instruction); |
| 6755 | 6867 | case IrInstructionIdContainerInitFields: |
| 6756 | 6868 | return ir_analyze_instruction_container_init_fields(ira, (IrInstructionContainerInitFields *)instruction); |
| 6869 | case IrInstructionIdMinValue: |
| 6870 | return ir_analyze_instruction_min_value(ira, (IrInstructionMinValue *)instruction); |
| 6871 | case IrInstructionIdMaxValue: |
| 6872 | return ir_analyze_instruction_max_value(ira, (IrInstructionMaxValue *)instruction); |
| 6757 | 6873 | case IrInstructionIdCast: |
| 6758 | 6874 | case IrInstructionIdStructFieldPtr: |
| 6759 | 6875 | case IrInstructionIdEnumFieldPtr: |
| ... | ... | @@ -6880,6 +6996,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 6880 | 6996 | case IrInstructionIdEnumTag: |
| 6881 | 6997 | case IrInstructionIdStaticEval: |
| 6882 | 6998 | case IrInstructionIdRef: |
| 6999 | case IrInstructionIdMinValue: |
| 7000 | case IrInstructionIdMaxValue: |
| 6883 | 7001 | return false; |
| 6884 | 7002 | case IrInstructionIdAsm: |
| 6885 | 7003 | { |
| ... | ... | @@ -6892,32 +7010,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 6892 | 7010 | |
| 6893 | 7011 | // TODO port over all this commented out code into new IR way of doing things |
| 6894 | 7012 | |
| 6895 | | //static TypeTableEntry *analyze_min_max_value(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 6896 | | // AstNode *node, const char *err_format, bool is_max) |
| 6897 | | //{ |
| 6898 | | // assert(node->type == NodeTypeFnCallExpr); |
| 6899 | | // assert(node->data.fn_call_expr.params.length == 1); |
| 6900 | | // |
| 6901 | | // AstNode *type_node = node->data.fn_call_expr.params.at(0); |
| 6902 | | // TypeTableEntry *type_entry = analyze_type_expr(g, import, context, type_node); |
| 6903 | | // |
| 6904 | | // if (type_entry->id == TypeTableEntryIdInvalid) { |
| 6905 | | // return g->builtin_types.entry_invalid; |
| 6906 | | // } else if (type_entry->id == TypeTableEntryIdInt) { |
| 6907 | | // eval_min_max_value(g, type_entry, &get_resolved_expr(node)->const_val, is_max); |
| 6908 | | // return g->builtin_types.entry_num_lit_int; |
| 6909 | | // } else if (type_entry->id == TypeTableEntryIdFloat) { |
| 6910 | | // eval_min_max_value(g, type_entry, &get_resolved_expr(node)->const_val, is_max); |
| 6911 | | // return g->builtin_types.entry_num_lit_float; |
| 6912 | | // } else if (type_entry->id == TypeTableEntryIdBool) { |
| 6913 | | // eval_min_max_value(g, type_entry, &get_resolved_expr(node)->const_val, is_max); |
| 6914 | | // return type_entry; |
| 6915 | | // } else { |
| 6916 | | // add_node_error(g, node, |
| 6917 | | // buf_sprintf(err_format, buf_ptr(&type_entry->name))); |
| 6918 | | // return g->builtin_types.entry_invalid; |
| 6919 | | // } |
| 6920 | | //} |
| 6921 | 7013 | |
| 6922 | 7014 | //static TypeTableEntry *analyze_c_import(CodeGen *g, ImportTableEntry *parent_import, |
| 6923 | 7015 | // BlockContext *parent_context, AstNode *node) |
| ... | ... | @@ -7393,12 +7485,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 7393 | 7485 | // align_in_bytes, false); |
| 7394 | 7486 | // } |
| 7395 | 7487 | // } |
| 7396 | | // case BuiltinFnIdMaxValue: |
| 7397 | | // return analyze_min_max_value(g, import, context, node, |
| 7398 | | // "no max value available for type '%s'", true); |
| 7399 | | // case BuiltinFnIdMinValue: |
| 7400 | | // return analyze_min_max_value(g, import, context, node, |
| 7401 | | // "no min value available for type '%s'", false); |
| 7402 | 7488 | // case BuiltinFnIdMemberCount: |
| 7403 | 7489 | // { |
| 7404 | 7490 | // AstNode *type_node = node->data.fn_call_expr.params.at(0); |