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 {
14101410 IrInstructionIdCmpxchg,
14111411 IrInstructionIdFence,
14121412 IrInstructionIdDivExact,
1413 IrInstructionIdTruncate,
14131414};
14141415
14151416struct IrInstruction {
......@@ -1892,6 +1893,13 @@ struct IrInstructionDivExact {
18921893 IrInstruction *op2;
18931894};
18941895
1896struct IrInstructionTruncate {
1897 IrInstruction base;
1898
1899 IrInstruction *dest_type;
1900 IrInstruction *target;
1901};
1902
18951903enum LValPurpose {
18961904 LValPurposeNone,
18971905 LValPurposeAssign,
src/codegen.cpp+10
......@@ -1879,6 +1879,14 @@ static LLVMValueRef ir_render_div_exact(CodeGen *g, IrExecutable *executable, Ir
18791879 return gen_div(g, want_debug_safety, op1_val, op2_val, instruction->base.type_entry, true);
18801880}
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
18821890static void set_debug_location(CodeGen *g, IrInstruction *instruction) {
18831891 AstNode *source_node = instruction->source_node;
18841892 Scope *scope = instruction->scope;
......@@ -1974,6 +1982,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
19741982 return ir_render_fence(g, executable, (IrInstructionFence *)instruction);
19751983 case IrInstructionIdDivExact:
19761984 return ir_render_div_exact(g, executable, (IrInstructionDivExact *)instruction);
1985 case IrInstructionIdTruncate:
1986 return ir_render_truncate(g, executable, (IrInstructionTruncate *)instruction);
19771987 case IrInstructionIdSwitchVar:
19781988 case IrInstructionIdContainerInitList:
19791989 case IrInstructionIdStructInit:
src/ir.cpp+98-62
......@@ -359,6 +359,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionDivExact *) {
359359 return IrInstructionIdDivExact;
360360}
361361
362static constexpr IrInstructionId ir_instruction_id(IrInstructionTruncate *) {
363 return IrInstructionIdTruncate;
364}
365
362366template<typename T>
363367static T *ir_create_instruction(IrExecutable *exec, Scope *scope, AstNode *source_node) {
364368 T *special_instruction = allocate<T>(1);
......@@ -1434,6 +1438,23 @@ static IrInstruction *ir_build_div_exact_from(IrBuilder *irb, IrInstruction *old
14341438 return new_instruction;
14351439}
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
14371458static void ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope,
14381459 bool gen_error_defers, bool gen_maybe_defers)
14391460{
......@@ -2227,6 +2248,20 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
22272248
22282249 return ir_build_div_exact(irb, scope, node, arg0_value, arg1_value);
22292250 }
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 }
22302265 case BuiltinFnIdMemcpy:
22312266 case BuiltinFnIdMemset:
22322267 case BuiltinFnIdAlignof:
......@@ -2238,7 +2273,6 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
22382273 case BuiltinFnIdBreakpoint:
22392274 case BuiltinFnIdReturnAddress:
22402275 case BuiltinFnIdFrameAddress:
2241 case BuiltinFnIdTruncate:
22422276 case BuiltinFnIdIntType:
22432277 zig_panic("TODO IR gen more builtin functions");
22442278 }
......@@ -7102,26 +7136,27 @@ static TypeTableEntry *ir_analyze_min_max(IrAnalyze *ira, IrInstruction *source_
71027136{
71037137 TypeTableEntry *target_type = ir_resolve_type(ira, target_type_value);
71047138 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) {
71067141 case TypeTableEntryIdInvalid:
71077142 return ira->codegen->builtin_types.entry_invalid;
71087143 case TypeTableEntryIdInt:
71097144 {
71107145 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);
71127147 return ira->codegen->builtin_types.entry_num_lit_int;
71137148 }
71147149 case TypeTableEntryIdFloat:
71157150 {
71167151 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);
71187153 return ira->codegen->builtin_types.entry_num_lit_float;
71197154 }
71207155 case TypeTableEntryIdBool:
71217156 case TypeTableEntryIdVoid:
71227157 {
71237158 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);
71257160 return target_type;
71267161 }
71277162 case TypeTableEntryIdVar:
......@@ -7150,6 +7185,7 @@ static TypeTableEntry *ir_analyze_min_max(IrAnalyze *ira, IrInstruction *source_
71507185 "no min value available for type '%s'";
71517186 ir_add_error(ira, source_instruction,
71527187 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
71537189 return ira->codegen->builtin_types.entry_invalid;
71547190 }
71557191 }
......@@ -7530,6 +7566,60 @@ static TypeTableEntry *ir_analyze_instruction_div_exact(IrAnalyze *ira, IrInstru
75307566 return result_type;
75317567}
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
75337623static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
75347624 switch (instruction->id) {
75357625 case IrInstructionIdInvalid:
......@@ -7638,6 +7728,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
76387728 return ir_analyze_instruction_fence(ira, (IrInstructionFence *)instruction);
76397729 case IrInstructionIdDivExact:
76407730 return ir_analyze_instruction_div_exact(ira, (IrInstructionDivExact *)instruction);
7731 case IrInstructionIdTruncate:
7732 return ir_analyze_instruction_truncate(ira, (IrInstructionTruncate *)instruction);
76417733 case IrInstructionIdCast:
76427734 case IrInstructionIdStructFieldPtr:
76437735 case IrInstructionIdEnumFieldPtr:
......@@ -7776,6 +7868,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
77767868 case IrInstructionIdErrName:
77777869 case IrInstructionIdEmbedFile:
77787870 case IrInstructionIdDivExact:
7871 case IrInstructionIdTruncate:
77797872 return false;
77807873 case IrInstructionIdAsm:
77817874 {
......@@ -7787,46 +7880,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
77877880}
77887881
77897882// 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//
78307883//static TypeTableEntry *analyze_int_type(CodeGen *g, ImportTableEntry *import,
78317884// BlockContext *context, AstNode *node)
78327885//{
......@@ -7996,8 +8049,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
79968049// case BuiltinFnIdFrameAddress:
79978050// mark_impure_fn(g, context, node);
79988051// return builtin_fn->return_type;
7999// case BuiltinFnIdTruncate:
8000// return analyze_truncate(g, import, context, node);
80018052// case BuiltinFnIdIntType:
80028053// return analyze_int_type(g, import, context, node);
80038054// }
......@@ -8315,19 +8366,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
83158366// }
83168367//}
83178368//
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//
83318369//static LLVMValueRef gen_shl_with_overflow(CodeGen *g, AstNode *node) {
83328370// assert(node->type == NodeTypeFnCallExpr);
83338371//
......@@ -8483,8 +8521,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
84838521// return gen_cmp_exchange(g, node);
84848522// case BuiltinFnIdFence:
84858523// return gen_fence(g, node);
8486// case BuiltinFnIdTruncate:
8487// return gen_truncate(g, node);
84888524// case BuiltinFnIdUnreachable:
84898525// zig_panic("moved to ir render");
84908526// case BuiltinFnIdSetFnTest:
src/ir_print.cpp+11
......@@ -747,6 +747,14 @@ static void ir_print_div_exact(IrPrint *irp, IrInstructionDivExact *instruction)
747747 fprintf(irp->f, ")");
748748}
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
750758static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
751759 ir_print_prefix(irp, instruction);
752760 switch (instruction->id) {
......@@ -920,6 +928,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
920928 case IrInstructionIdDivExact:
921929 ir_print_div_exact(irp, (IrInstructionDivExact *)instruction);
922930 break;
931 case IrInstructionIdTruncate:
932 ir_print_truncate(irp, (IrInstructionTruncate *)instruction);
933 break;
923934 }
924935 fprintf(irp->f, "\n");
925936}
test/self_hosted2.zig+9
......@@ -292,6 +292,14 @@ fn divExact(a: u32, b: u32) -> u32 {
292292 @divExact(a, b)
293293}
294294
295fn truncate() {
296 assert(testTruncate(0x10fd) == 0xfd);
297}
298fn testTruncate(x: u32) -> u8 {
299 @truncate(u8, x)
300}
301
302
295303fn assert(ok: bool) {
296304 if (!ok)
297305 @unreachable();
......@@ -322,6 +330,7 @@ fn runAllTests() {
322330 cmpxchg();
323331 fence();
324332 exactDivision();
333 truncate();
325334}
326335
327336export nakedcc fn _start() -> unreachable {