| ... | ... | @@ -359,6 +359,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionDivExact *) { |
| 359 | 359 | return IrInstructionIdDivExact; |
| 360 | 360 | } |
| 361 | 361 | |
| 362 | static constexpr IrInstructionId ir_instruction_id(IrInstructionTruncate *) { |
| 363 | return IrInstructionIdTruncate; |
| 364 | } |
| 365 | |
| 362 | 366 | template<typename T> |
| 363 | 367 | static T *ir_create_instruction(IrExecutable *exec, Scope *scope, AstNode *source_node) { |
| 364 | 368 | T *special_instruction = allocate<T>(1); |
| ... | ... | @@ -1434,6 +1438,23 @@ static IrInstruction *ir_build_div_exact_from(IrBuilder *irb, IrInstruction *old |
| 1434 | 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 | 1458 | static void ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, |
| 1438 | 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 | 2248 | |
| 2228 | 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 | 2265 | case BuiltinFnIdMemcpy: |
| 2231 | 2266 | case BuiltinFnIdMemset: |
| 2232 | 2267 | case BuiltinFnIdAlignof: |
| ... | ... | @@ -2238,7 +2273,6 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 2238 | 2273 | case BuiltinFnIdBreakpoint: |
| 2239 | 2274 | case BuiltinFnIdReturnAddress: |
| 2240 | 2275 | case BuiltinFnIdFrameAddress: |
| 2241 | | case BuiltinFnIdTruncate: |
| 2242 | 2276 | case BuiltinFnIdIntType: |
| 2243 | 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 | 7136 | { |
| 7103 | 7137 | TypeTableEntry *target_type = ir_resolve_type(ira, target_type_value); |
| 7104 | 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 | 7141 | case TypeTableEntryIdInvalid: |
| 7107 | 7142 | return ira->codegen->builtin_types.entry_invalid; |
| 7108 | 7143 | case TypeTableEntryIdInt: |
| 7109 | 7144 | { |
| 7110 | 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 | 7147 | return ira->codegen->builtin_types.entry_num_lit_int; |
| 7113 | 7148 | } |
| 7114 | 7149 | case TypeTableEntryIdFloat: |
| 7115 | 7150 | { |
| 7116 | 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 | 7153 | return ira->codegen->builtin_types.entry_num_lit_float; |
| 7119 | 7154 | } |
| 7120 | 7155 | case TypeTableEntryIdBool: |
| 7121 | 7156 | case TypeTableEntryIdVoid: |
| 7122 | 7157 | { |
| 7123 | 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 | 7160 | return target_type; |
| 7126 | 7161 | } |
| 7127 | 7162 | case TypeTableEntryIdVar: |
| ... | ... | @@ -7150,6 +7185,7 @@ static TypeTableEntry *ir_analyze_min_max(IrAnalyze *ira, IrInstruction *source_ |
| 7150 | 7185 | "no min value available for type '%s'"; |
| 7151 | 7186 | ir_add_error(ira, source_instruction, |
| 7152 | 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 | 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 | 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 | 7623 | static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) { |
| 7534 | 7624 | switch (instruction->id) { |
| 7535 | 7625 | case IrInstructionIdInvalid: |
| ... | ... | @@ -7638,6 +7728,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi |
| 7638 | 7728 | return ir_analyze_instruction_fence(ira, (IrInstructionFence *)instruction); |
| 7639 | 7729 | case IrInstructionIdDivExact: |
| 7640 | 7730 | return ir_analyze_instruction_div_exact(ira, (IrInstructionDivExact *)instruction); |
| 7731 | case IrInstructionIdTruncate: |
| 7732 | return ir_analyze_instruction_truncate(ira, (IrInstructionTruncate *)instruction); |
| 7641 | 7733 | case IrInstructionIdCast: |
| 7642 | 7734 | case IrInstructionIdStructFieldPtr: |
| 7643 | 7735 | case IrInstructionIdEnumFieldPtr: |
| ... | ... | @@ -7776,6 +7868,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 7776 | 7868 | case IrInstructionIdErrName: |
| 7777 | 7869 | case IrInstructionIdEmbedFile: |
| 7778 | 7870 | case IrInstructionIdDivExact: |
| 7871 | case IrInstructionIdTruncate: |
| 7779 | 7872 | return false; |
| 7780 | 7873 | case IrInstructionIdAsm: |
| 7781 | 7874 | { |
| ... | ... | @@ -7787,46 +7880,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 7787 | 7880 | } |
| 7788 | 7881 | |
| 7789 | 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 | 7883 | //static TypeTableEntry *analyze_int_type(CodeGen *g, ImportTableEntry *import, |
| 7831 | 7884 | // BlockContext *context, AstNode *node) |
| 7832 | 7885 | //{ |
| ... | ... | @@ -7996,8 +8049,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 7996 | 8049 | // case BuiltinFnIdFrameAddress: |
| 7997 | 8050 | // mark_impure_fn(g, context, node); |
| 7998 | 8051 | // return builtin_fn->return_type; |
| 7999 | | // case BuiltinFnIdTruncate: |
| 8000 | | // return analyze_truncate(g, import, context, node); |
| 8001 | 8052 | // case BuiltinFnIdIntType: |
| 8002 | 8053 | // return analyze_int_type(g, import, context, node); |
| 8003 | 8054 | // } |
| ... | ... | @@ -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 | 8369 | //static LLVMValueRef gen_shl_with_overflow(CodeGen *g, AstNode *node) { |
| 8332 | 8370 | // assert(node->type == NodeTypeFnCallExpr); |
| 8333 | 8371 | // |
| ... | ... | @@ -8483,8 +8521,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 8483 | 8521 | // return gen_cmp_exchange(g, node); |
| 8484 | 8522 | // case BuiltinFnIdFence: |
| 8485 | 8523 | // return gen_fence(g, node); |
| 8486 | | // case BuiltinFnIdTruncate: |
| 8487 | | // return gen_truncate(g, node); |
| 8488 | 8524 | // case BuiltinFnIdUnreachable: |
| 8489 | 8525 | // zig_panic("moved to ir render"); |
| 8490 | 8526 | // case BuiltinFnIdSetFnTest: |