authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-12-11 15:31:07-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-12-11 15:31:07-05:00
log3429639e848a9ffa9ff9fbd940d3fc2d348e10e7
tree67ff12dd3c9a578d443f46be232db38b49b08b7f
parent433c17aeb192740053b1b9aea6220dca760303e2

IR: implement truncate builtin


5 files changed, 136 insertions(+), 62 deletions(-)

src/all_types.hpp+8
...@@ -1410,6 +1410,7 @@ enum IrInstructionId {...@@ -1410,6 +1410,7 @@ enum IrInstructionId {
1410 IrInstructionIdCmpxchg,1410 IrInstructionIdCmpxchg,
1411 IrInstructionIdFence,1411 IrInstructionIdFence,
1412 IrInstructionIdDivExact,1412 IrInstructionIdDivExact,
1413 IrInstructionIdTruncate,
1413};1414};
14141415
1415struct IrInstruction {1416struct IrInstruction {
...@@ -1892,6 +1893,13 @@ struct IrInstructionDivExact {...@@ -1892,6 +1893,13 @@ struct IrInstructionDivExact {
1892 IrInstruction *op2;1893 IrInstruction *op2;
1893};1894};
18941895
1896struct IrInstructionTruncate {
1897 IrInstruction base;
1898
1899 IrInstruction *dest_type;
1900 IrInstruction *target;
1901};
1902
1895enum LValPurpose {1903enum LValPurpose {
1896 LValPurposeNone,1904 LValPurposeNone,
1897 LValPurposeAssign,1905 LValPurposeAssign,
src/codegen.cpp+10
...@@ -1879,6 +1879,14 @@ static LLVMValueRef ir_render_div_exact(CodeGen *g, IrExecutable *executable, Ir...@@ -1879,6 +1879,14 @@ static LLVMValueRef ir_render_div_exact(CodeGen *g, IrExecutable *executable, Ir
1879 return gen_div(g, want_debug_safety, op1_val, op2_val, instruction->base.type_entry, true);1879 return gen_div(g, want_debug_safety, op1_val, op2_val, instruction->base.type_entry, true);
1880}1880}
18811881
1882static LLVMValueRef ir_render_truncate(CodeGen *g, IrExecutable *executable, IrInstructionTruncate *instruction) {
1883 assert(instruction->dest_type->type_entry->id == TypeTableEntryIdMetaType);
1884 TypeTableEntry *dest_type = get_underlying_type(instruction->dest_type->static_value.data.x_type);
1885 assert(dest_type->id == TypeTableEntryIdInt);
1886 LLVMValueRef target_val = ir_llvm_value(g, instruction->target);
1887 return LLVMBuildTrunc(g->builder, target_val, dest_type->type_ref, "");
1888}
1889
1882static void set_debug_location(CodeGen *g, IrInstruction *instruction) {1890static void set_debug_location(CodeGen *g, IrInstruction *instruction) {
1883 AstNode *source_node = instruction->source_node;1891 AstNode *source_node = instruction->source_node;
1884 Scope *scope = instruction->scope;1892 Scope *scope = instruction->scope;
...@@ -1974,6 +1982,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -1974,6 +1982,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
1974 return ir_render_fence(g, executable, (IrInstructionFence *)instruction);1982 return ir_render_fence(g, executable, (IrInstructionFence *)instruction);
1975 case IrInstructionIdDivExact:1983 case IrInstructionIdDivExact:
1976 return ir_render_div_exact(g, executable, (IrInstructionDivExact *)instruction);1984 return ir_render_div_exact(g, executable, (IrInstructionDivExact *)instruction);
1985 case IrInstructionIdTruncate:
1986 return ir_render_truncate(g, executable, (IrInstructionTruncate *)instruction);
1977 case IrInstructionIdSwitchVar:1987 case IrInstructionIdSwitchVar:
1978 case IrInstructionIdContainerInitList:1988 case IrInstructionIdContainerInitList:
1979 case IrInstructionIdStructInit:1989 case IrInstructionIdStructInit:
src/ir.cpp+98-62
...@@ -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}
361361
362static constexpr IrInstructionId ir_instruction_id(IrInstructionTruncate *) {
363 return IrInstructionIdTruncate;
364}
365
362template<typename T>366template<typename T>
363static T *ir_create_instruction(IrExecutable *exec, Scope *scope, AstNode *source_node) {367static 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}
14361440
1441static 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
1452static 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
1437static void ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope,1458static 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
22272248
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}
75327568
7569static 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
7533static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {7623static 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}
77887881
7789// TODO port over all this commented out code into new IR way of doing things7882// 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:
src/ir_print.cpp+11
...@@ -747,6 +747,14 @@ static void ir_print_div_exact(IrPrint *irp, IrInstructionDivExact *instruction)...@@ -747,6 +747,14 @@ static void ir_print_div_exact(IrPrint *irp, IrInstructionDivExact *instruction)
747 fprintf(irp->f, ")");747 fprintf(irp->f, ")");
748}748}
749749
750static void ir_print_truncate(IrPrint *irp, IrInstructionTruncate *instruction) {
751 fprintf(irp->f, "@truncate(");
752 ir_print_other_instruction(irp, instruction->dest_type);
753 fprintf(irp->f, ", ");
754 ir_print_other_instruction(irp, instruction->target);
755 fprintf(irp->f, ")");
756}
757
750static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {758static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
751 ir_print_prefix(irp, instruction);759 ir_print_prefix(irp, instruction);
752 switch (instruction->id) {760 switch (instruction->id) {
...@@ -920,6 +928,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {...@@ -920,6 +928,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
920 case IrInstructionIdDivExact:928 case IrInstructionIdDivExact:
921 ir_print_div_exact(irp, (IrInstructionDivExact *)instruction);929 ir_print_div_exact(irp, (IrInstructionDivExact *)instruction);
922 break;930 break;
931 case IrInstructionIdTruncate:
932 ir_print_truncate(irp, (IrInstructionTruncate *)instruction);
933 break;
923 }934 }
924 fprintf(irp->f, "\n");935 fprintf(irp->f, "\n");
925}936}
test/self_hosted2.zig+9
...@@ -292,6 +292,14 @@ fn divExact(a: u32, b: u32) -> u32 {...@@ -292,6 +292,14 @@ fn divExact(a: u32, b: u32) -> u32 {
292 @divExact(a, b)292 @divExact(a, b)
293}293}
294294
295fn truncate() {
296 assert(testTruncate(0x10fd) == 0xfd);
297}
298fn testTruncate(x: u32) -> u8 {
299 @truncate(u8, x)
300}
301
302
295fn assert(ok: bool) {303fn assert(ok: bool) {
296 if (!ok)304 if (!ok)
297 @unreachable();305 @unreachable();
...@@ -322,6 +330,7 @@ fn runAllTests() {...@@ -322,6 +330,7 @@ fn runAllTests() {
322 cmpxchg();330 cmpxchg();
323 fence();331 fence();
324 exactDivision();332 exactDivision();
333 truncate();
325}334}
326335
327export nakedcc fn _start() -> unreachable {336export nakedcc fn _start() -> unreachable {