| ... | @@ -359,6 +359,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionDivExact *) { | ... | @@ -359,6 +359,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionDivExact *) { |
| 359 | return IrInstructionIdDivExact; | 359 | return IrInstructionIdDivExact; |
| 360 | } | 360 | } |
| 361 | | 361 | |
| | 362 | static constexpr IrInstructionId ir_instruction_id(IrInstructionTruncate *) { |
| | 363 | return IrInstructionIdTruncate; |
| | 364 | } |
| | 365 | |
| 362 | template<typename T> | 366 | template<typename T> |
| 363 | static T *ir_create_instruction(IrExecutable *exec, Scope *scope, AstNode *source_node) { | 367 | static T *ir_create_instruction(IrExecutable *exec, Scope *scope, AstNode *source_node) { |
| 364 | T *special_instruction = allocate<T>(1); | 368 | T *special_instruction = allocate<T>(1); |
| ... | @@ -1434,6 +1438,23 @@ static IrInstruction *ir_build_div_exact_from(IrBuilder *irb, IrInstruction *old | ... | @@ -1434,6 +1438,23 @@ static IrInstruction *ir_build_div_exact_from(IrBuilder *irb, IrInstruction *old |
| 1434 | return new_instruction; | 1438 | return new_instruction; |
| 1435 | } | 1439 | } |
| 1436 | | 1440 | |
| | 1441 | static IrInstruction *ir_build_truncate(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *dest_type, IrInstruction *target) { |
| | 1442 | IrInstructionTruncate *instruction = ir_build_instruction<IrInstructionTruncate>(irb, scope, source_node); |
| | 1443 | instruction->dest_type = dest_type; |
| | 1444 | instruction->target = target; |
| | 1445 | |
| | 1446 | ir_ref_instruction(dest_type); |
| | 1447 | ir_ref_instruction(target); |
| | 1448 | |
| | 1449 | return &instruction->base; |
| | 1450 | } |
| | 1451 | |
| | 1452 | static IrInstruction *ir_build_truncate_from(IrBuilder *irb, IrInstruction *old_instruction, IrInstruction *dest_type, IrInstruction *target) { |
| | 1453 | IrInstruction *new_instruction = ir_build_truncate(irb, old_instruction->scope, old_instruction->source_node, dest_type, target); |
| | 1454 | ir_link_new_instruction(new_instruction, old_instruction); |
| | 1455 | return new_instruction; |
| | 1456 | } |
| | 1457 | |
| 1437 | static void ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, | 1458 | static void ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, |
| 1438 | bool gen_error_defers, bool gen_maybe_defers) | 1459 | bool gen_error_defers, bool gen_maybe_defers) |
| 1439 | { | 1460 | { |
| ... | @@ -2227,6 +2248,20 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo | ... | @@ -2227,6 +2248,20 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 2227 | | 2248 | |
| 2228 | return ir_build_div_exact(irb, scope, node, arg0_value, arg1_value); | 2249 | return ir_build_div_exact(irb, scope, node, arg0_value, arg1_value); |
| 2229 | } | 2250 | } |
| | 2251 | case BuiltinFnIdTruncate: |
| | 2252 | { |
| | 2253 | AstNode *arg0_node = node->data.fn_call_expr.params.at(0); |
| | 2254 | IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); |
| | 2255 | if (arg0_value == irb->codegen->invalid_instruction) |
| | 2256 | return arg0_value; |
| | 2257 | |
| | 2258 | AstNode *arg1_node = node->data.fn_call_expr.params.at(1); |
| | 2259 | IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope); |
| | 2260 | if (arg1_value == irb->codegen->invalid_instruction) |
| | 2261 | return arg1_value; |
| | 2262 | |
| | 2263 | return ir_build_truncate(irb, scope, node, arg0_value, arg1_value); |
| | 2264 | } |
| 2230 | case BuiltinFnIdMemcpy: | 2265 | case BuiltinFnIdMemcpy: |
| 2231 | case BuiltinFnIdMemset: | 2266 | case BuiltinFnIdMemset: |
| 2232 | case BuiltinFnIdAlignof: | 2267 | case BuiltinFnIdAlignof: |
| ... | @@ -2238,7 +2273,6 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo | ... | @@ -2238,7 +2273,6 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 2238 | case BuiltinFnIdBreakpoint: | 2273 | case BuiltinFnIdBreakpoint: |
| 2239 | case BuiltinFnIdReturnAddress: | 2274 | case BuiltinFnIdReturnAddress: |
| 2240 | case BuiltinFnIdFrameAddress: | 2275 | case BuiltinFnIdFrameAddress: |
| 2241 | case BuiltinFnIdTruncate: | | |
| 2242 | case BuiltinFnIdIntType: | 2276 | case BuiltinFnIdIntType: |
| 2243 | zig_panic("TODO IR gen more builtin functions"); | 2277 | zig_panic("TODO IR gen more builtin functions"); |
| 2244 | } | 2278 | } |
| ... | @@ -7102,26 +7136,27 @@ static TypeTableEntry *ir_analyze_min_max(IrAnalyze *ira, IrInstruction *source_ | ... | @@ -7102,26 +7136,27 @@ static TypeTableEntry *ir_analyze_min_max(IrAnalyze *ira, IrInstruction *source_ |
| 7102 | { | 7136 | { |
| 7103 | TypeTableEntry *target_type = ir_resolve_type(ira, target_type_value); | 7137 | TypeTableEntry *target_type = ir_resolve_type(ira, target_type_value); |
| 7104 | bool depends_on_compile_var = target_type_value->static_value.depends_on_compile_var; | 7138 | bool depends_on_compile_var = target_type_value->static_value.depends_on_compile_var; |
| 7105 | switch (target_type->id) { | 7139 | TypeTableEntry *canon_type = get_underlying_type(target_type); |
| | 7140 | switch (canon_type->id) { |
| 7106 | case TypeTableEntryIdInvalid: | 7141 | case TypeTableEntryIdInvalid: |
| 7107 | return ira->codegen->builtin_types.entry_invalid; | 7142 | return ira->codegen->builtin_types.entry_invalid; |
| 7108 | case TypeTableEntryIdInt: | 7143 | case TypeTableEntryIdInt: |
| 7109 | { | 7144 | { |
| 7110 | ConstExprValue *out_val = ir_build_const_from(ira, source_instruction, depends_on_compile_var); | 7145 | ConstExprValue *out_val = ir_build_const_from(ira, source_instruction, depends_on_compile_var); |
| 7111 | eval_min_max_value(ira->codegen, target_type, out_val, is_max); | 7146 | eval_min_max_value(ira->codegen, canon_type, out_val, is_max); |
| 7112 | return ira->codegen->builtin_types.entry_num_lit_int; | 7147 | return ira->codegen->builtin_types.entry_num_lit_int; |
| 7113 | } | 7148 | } |
| 7114 | case TypeTableEntryIdFloat: | 7149 | case TypeTableEntryIdFloat: |
| 7115 | { | 7150 | { |
| 7116 | ConstExprValue *out_val = ir_build_const_from(ira, source_instruction, depends_on_compile_var); | 7151 | ConstExprValue *out_val = ir_build_const_from(ira, source_instruction, depends_on_compile_var); |
| 7117 | eval_min_max_value(ira->codegen, target_type, out_val, is_max); | 7152 | eval_min_max_value(ira->codegen, canon_type, out_val, is_max); |
| 7118 | return ira->codegen->builtin_types.entry_num_lit_float; | 7153 | return ira->codegen->builtin_types.entry_num_lit_float; |
| 7119 | } | 7154 | } |
| 7120 | case TypeTableEntryIdBool: | 7155 | case TypeTableEntryIdBool: |
| 7121 | case TypeTableEntryIdVoid: | 7156 | case TypeTableEntryIdVoid: |
| 7122 | { | 7157 | { |
| 7123 | ConstExprValue *out_val = ir_build_const_from(ira, source_instruction, depends_on_compile_var); | 7158 | ConstExprValue *out_val = ir_build_const_from(ira, source_instruction, depends_on_compile_var); |
| 7124 | eval_min_max_value(ira->codegen, target_type, out_val, is_max); | 7159 | eval_min_max_value(ira->codegen, canon_type, out_val, is_max); |
| 7125 | return target_type; | 7160 | return target_type; |
| 7126 | } | 7161 | } |
| 7127 | case TypeTableEntryIdVar: | 7162 | case TypeTableEntryIdVar: |
| ... | @@ -7150,6 +7185,7 @@ static TypeTableEntry *ir_analyze_min_max(IrAnalyze *ira, IrInstruction *source_ | ... | @@ -7150,6 +7185,7 @@ static TypeTableEntry *ir_analyze_min_max(IrAnalyze *ira, IrInstruction *source_ |
| 7150 | "no min value available for type '%s'"; | 7185 | "no min value available for type '%s'"; |
| 7151 | ir_add_error(ira, source_instruction, | 7186 | ir_add_error(ira, source_instruction, |
| 7152 | buf_sprintf(err_format, buf_ptr(&target_type->name))); | 7187 | buf_sprintf(err_format, buf_ptr(&target_type->name))); |
| | 7188 | // TODO if this is a typedecl, add error note showing the declaration of the type decl |
| 7153 | return ira->codegen->builtin_types.entry_invalid; | 7189 | return ira->codegen->builtin_types.entry_invalid; |
| 7154 | } | 7190 | } |
| 7155 | } | 7191 | } |
| ... | @@ -7530,6 +7566,60 @@ static TypeTableEntry *ir_analyze_instruction_div_exact(IrAnalyze *ira, IrInstru | ... | @@ -7530,6 +7566,60 @@ static TypeTableEntry *ir_analyze_instruction_div_exact(IrAnalyze *ira, IrInstru |
| 7530 | return result_type; | 7566 | return result_type; |
| 7531 | } | 7567 | } |
| 7532 | | 7568 | |
| | 7569 | static TypeTableEntry *ir_analyze_instruction_truncate(IrAnalyze *ira, IrInstructionTruncate *instruction) { |
| | 7570 | IrInstruction *dest_type_value = instruction->dest_type->other; |
| | 7571 | TypeTableEntry *dest_type = ir_resolve_type(ira, dest_type_value); |
| | 7572 | TypeTableEntry *canon_dest_type = get_underlying_type(dest_type); |
| | 7573 | |
| | 7574 | if (canon_dest_type->id == TypeTableEntryIdInvalid) |
| | 7575 | return ira->codegen->builtin_types.entry_invalid; |
| | 7576 | |
| | 7577 | if (canon_dest_type->id != TypeTableEntryIdInt && |
| | 7578 | canon_dest_type->id != TypeTableEntryIdNumLitInt) |
| | 7579 | { |
| | 7580 | ir_add_error(ira, dest_type_value, buf_sprintf("expected integer type, found '%s'", buf_ptr(&dest_type->name))); |
| | 7581 | // TODO if meta_type is type decl, add note pointing to type decl declaration |
| | 7582 | return ira->codegen->builtin_types.entry_invalid; |
| | 7583 | } |
| | 7584 | |
| | 7585 | IrInstruction *target = instruction->target->other; |
| | 7586 | TypeTableEntry *src_type = target->type_entry; |
| | 7587 | TypeTableEntry *canon_src_type = get_underlying_type(src_type); |
| | 7588 | if (canon_src_type->id == TypeTableEntryIdInvalid) |
| | 7589 | return ira->codegen->builtin_types.entry_invalid; |
| | 7590 | |
| | 7591 | if (canon_src_type->id != TypeTableEntryIdInt && |
| | 7592 | canon_src_type->id != TypeTableEntryIdNumLitInt) |
| | 7593 | { |
| | 7594 | ir_add_error(ira, target, buf_sprintf("expected integer type, found '%s'", buf_ptr(&src_type->name))); |
| | 7595 | // TODO if meta_type is type decl, add note pointing to type decl declaration |
| | 7596 | return ira->codegen->builtin_types.entry_invalid; |
| | 7597 | } |
| | 7598 | |
| | 7599 | if (canon_src_type->data.integral.is_signed != canon_dest_type->data.integral.is_signed) { |
| | 7600 | const char *sign_str = canon_dest_type->data.integral.is_signed ? "signed" : "unsigned"; |
| | 7601 | ir_add_error(ira, target, buf_sprintf("expected %s integer type, found '%s'", sign_str, buf_ptr(&src_type->name))); |
| | 7602 | // TODO if meta_type is type decl, add note pointing to type decl declaration |
| | 7603 | return ira->codegen->builtin_types.entry_invalid; |
| | 7604 | } else if (canon_src_type->data.integral.bit_count <= canon_dest_type->data.integral.bit_count) { |
| | 7605 | ir_add_error(ira, target, buf_sprintf("type '%s' has same or fewer bits than destination type '%s'", |
| | 7606 | buf_ptr(&src_type->name), buf_ptr(&dest_type->name))); |
| | 7607 | // TODO if meta_type is type decl, add note pointing to type decl declaration |
| | 7608 | return ira->codegen->builtin_types.entry_invalid; |
| | 7609 | } |
| | 7610 | |
| | 7611 | if (target->static_value.special == ConstValSpecialStatic) { |
| | 7612 | bool depends_on_compile_var = dest_type_value->static_value.depends_on_compile_var || target->static_value.depends_on_compile_var; |
| | 7613 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, depends_on_compile_var); |
| | 7614 | bignum_init_bignum(&out_val->data.x_bignum, &target->static_value.data.x_bignum); |
| | 7615 | bignum_truncate(&out_val->data.x_bignum, canon_dest_type->data.integral.bit_count); |
| | 7616 | return dest_type; |
| | 7617 | } |
| | 7618 | |
| | 7619 | ir_build_truncate_from(&ira->new_irb, &instruction->base, dest_type_value, target); |
| | 7620 | return dest_type; |
| | 7621 | } |
| | 7622 | |
| 7533 | static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) { | 7623 | static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) { |
| 7534 | switch (instruction->id) { | 7624 | switch (instruction->id) { |
| 7535 | case IrInstructionIdInvalid: | 7625 | case IrInstructionIdInvalid: |
| ... | @@ -7638,6 +7728,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi | ... | @@ -7638,6 +7728,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi |
| 7638 | return ir_analyze_instruction_fence(ira, (IrInstructionFence *)instruction); | 7728 | return ir_analyze_instruction_fence(ira, (IrInstructionFence *)instruction); |
| 7639 | case IrInstructionIdDivExact: | 7729 | case IrInstructionIdDivExact: |
| 7640 | return ir_analyze_instruction_div_exact(ira, (IrInstructionDivExact *)instruction); | 7730 | return ir_analyze_instruction_div_exact(ira, (IrInstructionDivExact *)instruction); |
| | 7731 | case IrInstructionIdTruncate: |
| | 7732 | return ir_analyze_instruction_truncate(ira, (IrInstructionTruncate *)instruction); |
| 7641 | case IrInstructionIdCast: | 7733 | case IrInstructionIdCast: |
| 7642 | case IrInstructionIdStructFieldPtr: | 7734 | case IrInstructionIdStructFieldPtr: |
| 7643 | case IrInstructionIdEnumFieldPtr: | 7735 | case IrInstructionIdEnumFieldPtr: |
| ... | @@ -7776,6 +7868,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { | ... | @@ -7776,6 +7868,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 7776 | case IrInstructionIdErrName: | 7868 | case IrInstructionIdErrName: |
| 7777 | case IrInstructionIdEmbedFile: | 7869 | case IrInstructionIdEmbedFile: |
| 7778 | case IrInstructionIdDivExact: | 7870 | case IrInstructionIdDivExact: |
| | 7871 | case IrInstructionIdTruncate: |
| 7779 | return false; | 7872 | return false; |
| 7780 | case IrInstructionIdAsm: | 7873 | case IrInstructionIdAsm: |
| 7781 | { | 7874 | { |
| ... | @@ -7787,46 +7880,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { | ... | @@ -7787,46 +7880,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 7787 | } | 7880 | } |
| 7788 | | 7881 | |
| 7789 | // TODO port over all this commented out code into new IR way of doing things | 7882 | // TODO port over all this commented out code into new IR way of doing things |
| 7790 | | | |
| 7791 | | | |
| 7792 | //static TypeTableEntry *analyze_truncate(CodeGen *g, ImportTableEntry *import, | | |
| 7793 | // BlockContext *context, AstNode *node) | | |
| 7794 | //{ | | |
| 7795 | // assert(node->type == NodeTypeFnCallExpr); | | |
| 7796 | // | | |
| 7797 | // AstNode **op1 = &node->data.fn_call_expr.params.at(0); | | |
| 7798 | // AstNode **op2 = &node->data.fn_call_expr.params.at(1); | | |
| 7799 | // | | |
| 7800 | // TypeTableEntry *dest_type = analyze_type_expr(g, import, context, *op1); | | |
| 7801 | // TypeTableEntry *src_type = analyze_expression(g, import, context, nullptr, *op2); | | |
| 7802 | // | | |
| 7803 | // if (dest_type->id == TypeTableEntryIdInvalid || src_type->id == TypeTableEntryIdInvalid) { | | |
| 7804 | // return g->builtin_types.entry_invalid; | | |
| 7805 | // } else if (dest_type->id != TypeTableEntryIdInt) { | | |
| 7806 | // add_node_error(g, *op1, | | |
| 7807 | // buf_sprintf("expected integer type, found '%s'", buf_ptr(&dest_type->name))); | | |
| 7808 | // return g->builtin_types.entry_invalid; | | |
| 7809 | // } else if (src_type->id != TypeTableEntryIdInt) { | | |
| 7810 | // add_node_error(g, *op2, | | |
| 7811 | // buf_sprintf("expected integer type, found '%s'", buf_ptr(&src_type->name))); | | |
| 7812 | // return g->builtin_types.entry_invalid; | | |
| 7813 | // } else if (src_type->data.integral.is_signed != dest_type->data.integral.is_signed) { | | |
| 7814 | // const char *sign_str = dest_type->data.integral.is_signed ? "signed" : "unsigned"; | | |
| 7815 | // add_node_error(g, *op2, | | |
| 7816 | // buf_sprintf("expected %s integer type, found '%s'", sign_str, buf_ptr(&src_type->name))); | | |
| 7817 | // return g->builtin_types.entry_invalid; | | |
| 7818 | // } else if (src_type->data.integral.bit_count <= dest_type->data.integral.bit_count) { | | |
| 7819 | // add_node_error(g, *op2, | | |
| 7820 | // buf_sprintf("type '%s' has same or fewer bits than destination type '%s'", | | |
| 7821 | // buf_ptr(&src_type->name), buf_ptr(&dest_type->name))); | | |
| 7822 | // return g->builtin_types.entry_invalid; | | |
| 7823 | // } | | |
| 7824 | // | | |
| 7825 | // // TODO const expr eval | | |
| 7826 | // | | |
| 7827 | // return dest_type; | | |
| 7828 | //} | | |
| 7829 | // | | |
| 7830 | //static TypeTableEntry *analyze_int_type(CodeGen *g, ImportTableEntry *import, | 7883 | //static TypeTableEntry *analyze_int_type(CodeGen *g, ImportTableEntry *import, |
| 7831 | // BlockContext *context, AstNode *node) | 7884 | // BlockContext *context, AstNode *node) |
| 7832 | //{ | 7885 | //{ |
| ... | @@ -7996,8 +8049,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { | ... | @@ -7996,8 +8049,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 7996 | // case BuiltinFnIdFrameAddress: | 8049 | // case BuiltinFnIdFrameAddress: |
| 7997 | // mark_impure_fn(g, context, node); | 8050 | // mark_impure_fn(g, context, node); |
| 7998 | // return builtin_fn->return_type; | 8051 | // return builtin_fn->return_type; |
| 7999 | // case BuiltinFnIdTruncate: | | |
| 8000 | // return analyze_truncate(g, import, context, node); | | |
| 8001 | // case BuiltinFnIdIntType: | 8052 | // case BuiltinFnIdIntType: |
| 8002 | // return analyze_int_type(g, import, context, node); | 8053 | // return analyze_int_type(g, import, context, node); |
| 8003 | // } | 8054 | // } |
| ... | @@ -8315,19 +8366,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { | ... | @@ -8315,19 +8366,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 8315 | // } | 8366 | // } |
| 8316 | //} | 8367 | //} |
| 8317 | // | 8368 | // |
| 8318 | | | |
| 8319 | | | |
| 8320 | //static LLVMValueRef gen_truncate(CodeGen *g, AstNode *node) { | | |
| 8321 | // assert(node->type == NodeTypeFnCallExpr); | | |
| 8322 | // | | |
| 8323 | // TypeTableEntry *dest_type = get_type_for_type_node(node->data.fn_call_expr.params.at(0)); | | |
| 8324 | // AstNode *src_node = node->data.fn_call_expr.params.at(1); | | |
| 8325 | // | | |
| 8326 | // LLVMValueRef src_val = gen_expr(g, src_node); | | |
| 8327 | // | | |
| 8328 | // return LLVMBuildTrunc(g->builder, src_val, dest_type->type_ref, ""); | | |
| 8329 | //} | | |
| 8330 | // | | |
| 8331 | //static LLVMValueRef gen_shl_with_overflow(CodeGen *g, AstNode *node) { | 8369 | //static LLVMValueRef gen_shl_with_overflow(CodeGen *g, AstNode *node) { |
| 8332 | // assert(node->type == NodeTypeFnCallExpr); | 8370 | // assert(node->type == NodeTypeFnCallExpr); |
| 8333 | // | 8371 | // |
| ... | @@ -8483,8 +8521,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { | ... | @@ -8483,8 +8521,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 8483 | // return gen_cmp_exchange(g, node); | 8521 | // return gen_cmp_exchange(g, node); |
| 8484 | // case BuiltinFnIdFence: | 8522 | // case BuiltinFnIdFence: |
| 8485 | // return gen_fence(g, node); | 8523 | // return gen_fence(g, node); |
| 8486 | // case BuiltinFnIdTruncate: | | |
| 8487 | // return gen_truncate(g, node); | | |
| 8488 | // case BuiltinFnIdUnreachable: | 8524 | // case BuiltinFnIdUnreachable: |
| 8489 | // zig_panic("moved to ir render"); | 8525 | // zig_panic("moved to ir render"); |
| 8490 | // case BuiltinFnIdSetFnTest: | 8526 | // case BuiltinFnIdSetFnTest: |