authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-12-11 14:27:37-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-12-11 14:27:37-05:00
log433c17aeb192740053b1b9aea6220dca760303e2
treecd6a06a06215879cfafe9981913025f9cc1550da
parent8fcb1a141b1f76a0c6b28338723535ec5fbf638b

IR: implement divExact builtin


5 files changed, 145 insertions(+), 48 deletions(-)

src/all_types.hpp+8
......@@ -1409,6 +1409,7 @@ enum IrInstructionId {
14091409 IrInstructionIdEmbedFile,
14101410 IrInstructionIdCmpxchg,
14111411 IrInstructionIdFence,
1412 IrInstructionIdDivExact,
14121413};
14131414
14141415struct IrInstruction {
......@@ -1884,6 +1885,13 @@ struct IrInstructionFence {
18841885 AtomicOrder order;
18851886};
18861887
1888struct IrInstructionDivExact {
1889 IrInstruction base;
1890
1891 IrInstruction *op1;
1892 IrInstruction *op2;
1893};
1894
18871895enum LValPurpose {
18881896 LValPurposeNone,
18891897 LValPurposeAssign,
src/codegen.cpp+10
......@@ -1871,6 +1871,14 @@ static LLVMValueRef ir_render_fence(CodeGen *g, IrExecutable *executable, IrInst
18711871 return nullptr;
18721872}
18731873
1874static LLVMValueRef ir_render_div_exact(CodeGen *g, IrExecutable *executable, IrInstructionDivExact *instruction) {
1875 LLVMValueRef op1_val = ir_llvm_value(g, instruction->op1);
1876 LLVMValueRef op2_val = ir_llvm_value(g, instruction->op2);
1877
1878 bool want_debug_safety = ir_want_debug_safety(g, &instruction->base);
1879 return gen_div(g, want_debug_safety, op1_val, op2_val, instruction->base.type_entry, true);
1880}
1881
18741882static void set_debug_location(CodeGen *g, IrInstruction *instruction) {
18751883 AstNode *source_node = instruction->source_node;
18761884 Scope *scope = instruction->scope;
......@@ -1964,6 +1972,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
19641972 return ir_render_cmpxchg(g, executable, (IrInstructionCmpxchg *)instruction);
19651973 case IrInstructionIdFence:
19661974 return ir_render_fence(g, executable, (IrInstructionFence *)instruction);
1975 case IrInstructionIdDivExact:
1976 return ir_render_div_exact(g, executable, (IrInstructionDivExact *)instruction);
19671977 case IrInstructionIdSwitchVar:
19681978 case IrInstructionIdContainerInitList:
19691979 case IrInstructionIdStructInit:
src/ir.cpp+108-48
......@@ -355,6 +355,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionFence *) {
355355 return IrInstructionIdFence;
356356}
357357
358static constexpr IrInstructionId ir_instruction_id(IrInstructionDivExact *) {
359 return IrInstructionIdDivExact;
360}
361
358362template<typename T>
359363static T *ir_create_instruction(IrExecutable *exec, Scope *scope, AstNode *source_node) {
360364 T *special_instruction = allocate<T>(1);
......@@ -1413,6 +1417,23 @@ static IrInstruction *ir_build_fence_from(IrBuilder *irb, IrInstruction *old_ins
14131417 return new_instruction;
14141418}
14151419
1420static IrInstruction *ir_build_div_exact(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *op1, IrInstruction *op2) {
1421 IrInstructionDivExact *instruction = ir_build_instruction<IrInstructionDivExact>(irb, scope, source_node);
1422 instruction->op1 = op1;
1423 instruction->op2 = op2;
1424
1425 ir_ref_instruction(op1);
1426 ir_ref_instruction(op2);
1427
1428 return &instruction->base;
1429}
1430
1431static IrInstruction *ir_build_div_exact_from(IrBuilder *irb, IrInstruction *old_instruction, IrInstruction *op1, IrInstruction *op2) {
1432 IrInstruction *new_instruction = ir_build_div_exact(irb, old_instruction->scope, old_instruction->source_node, op1, op2);
1433 ir_link_new_instruction(new_instruction, old_instruction);
1434 return new_instruction;
1435}
1436
14161437static void ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope,
14171438 bool gen_error_defers, bool gen_maybe_defers)
14181439{
......@@ -2192,6 +2213,20 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
21922213
21932214 return ir_build_fence(irb, scope, node, arg0_value, AtomicOrderUnordered);
21942215 }
2216 case BuiltinFnIdDivExact:
2217 {
2218 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
2219 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
2220 if (arg0_value == irb->codegen->invalid_instruction)
2221 return arg0_value;
2222
2223 AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
2224 IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
2225 if (arg1_value == irb->codegen->invalid_instruction)
2226 return arg1_value;
2227
2228 return ir_build_div_exact(irb, scope, node, arg0_value, arg1_value);
2229 }
21952230 case BuiltinFnIdMemcpy:
21962231 case BuiltinFnIdMemset:
21972232 case BuiltinFnIdAlignof:
......@@ -2203,7 +2238,6 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
22032238 case BuiltinFnIdBreakpoint:
22042239 case BuiltinFnIdReturnAddress:
22052240 case BuiltinFnIdFrameAddress:
2206 case BuiltinFnIdDivExact:
22072241 case BuiltinFnIdTruncate:
22082242 case BuiltinFnIdIntType:
22092243 zig_panic("TODO IR gen more builtin functions");
......@@ -7426,6 +7460,76 @@ static TypeTableEntry *ir_analyze_instruction_fence(IrAnalyze *ira, IrInstructio
74267460 return ira->codegen->builtin_types.entry_void;
74277461}
74287462
7463static TypeTableEntry *ir_analyze_instruction_div_exact(IrAnalyze *ira, IrInstructionDivExact *instruction) {
7464 IrInstruction *op1 = instruction->op1->other;
7465 if (op1->type_entry->id == TypeTableEntryIdInvalid)
7466 return ira->codegen->builtin_types.entry_invalid;
7467
7468 IrInstruction *op2 = instruction->op2->other;
7469 if (op2->type_entry->id == TypeTableEntryIdInvalid)
7470 return ira->codegen->builtin_types.entry_invalid;
7471
7472
7473 IrInstruction *peer_instructions[] = { op1, op2 };
7474 TypeTableEntry *result_type = ir_resolve_peer_types(ira, instruction->base.source_node, peer_instructions, 2);
7475
7476 if (result_type->id == TypeTableEntryIdInvalid)
7477 return ira->codegen->builtin_types.entry_invalid;
7478
7479 TypeTableEntry *canon_type = get_underlying_type(result_type);
7480
7481 if (canon_type->id != TypeTableEntryIdInt &&
7482 canon_type->id != TypeTableEntryIdNumLitInt)
7483 {
7484 ir_add_error(ira, &instruction->base,
7485 buf_sprintf("expected integer type, found '%s'", buf_ptr(&result_type->name)));
7486 // TODO if meta_type is type decl, add note pointing to type decl declaration
7487 return ira->codegen->builtin_types.entry_invalid;
7488 }
7489
7490 IrInstruction *casted_op1 = ir_get_casted_value(ira, op1, result_type);
7491 if (casted_op1->type_entry->id == TypeTableEntryIdInvalid)
7492 return ira->codegen->builtin_types.entry_invalid;
7493
7494 IrInstruction *casted_op2 = ir_get_casted_value(ira, op2, result_type);
7495 if (casted_op2->type_entry->id == TypeTableEntryIdInvalid)
7496 return ira->codegen->builtin_types.entry_invalid;
7497
7498 if (casted_op1->static_value.special == ConstValSpecialStatic &&
7499 casted_op2->static_value.special == ConstValSpecialStatic)
7500 {
7501 ConstExprValue *op1_val = ir_resolve_const(ira, casted_op1);
7502 ConstExprValue *op2_val = ir_resolve_const(ira, casted_op2);
7503 assert(op1_val);
7504 assert(op2_val);
7505
7506 if (op1_val->data.x_bignum.data.x_uint == 0) {
7507 ir_add_error(ira, &instruction->base, buf_sprintf("division by zero"));
7508 return ira->codegen->builtin_types.entry_invalid;
7509 }
7510
7511 BigNum remainder;
7512 if (bignum_mod(&remainder, &op1_val->data.x_bignum, &op2_val->data.x_bignum)) {
7513 ir_add_error(ira, &instruction->base, buf_sprintf("integer overflow"));
7514 return ira->codegen->builtin_types.entry_invalid;
7515 }
7516
7517 if (remainder.data.x_uint != 0) {
7518 ir_add_error(ira, &instruction->base, buf_sprintf("exact division had a remainder"));
7519 return ira->codegen->builtin_types.entry_invalid;
7520 }
7521
7522 bool depends_on_compile_var = casted_op1->static_value.depends_on_compile_var ||
7523 casted_op2->static_value.depends_on_compile_var;
7524 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, depends_on_compile_var);
7525 bignum_div(&out_val->data.x_bignum, &op1_val->data.x_bignum, &op2_val->data.x_bignum);
7526 return result_type;
7527 }
7528
7529 ir_build_div_exact_from(&ira->new_irb, &instruction->base, casted_op1, casted_op2);
7530 return result_type;
7531}
7532
74297533static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
74307534 switch (instruction->id) {
74317535 case IrInstructionIdInvalid:
......@@ -7532,6 +7636,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
75327636 return ir_analyze_instruction_cmpxchg(ira, (IrInstructionCmpxchg *)instruction);
75337637 case IrInstructionIdFence:
75347638 return ir_analyze_instruction_fence(ira, (IrInstructionFence *)instruction);
7639 case IrInstructionIdDivExact:
7640 return ir_analyze_instruction_div_exact(ira, (IrInstructionDivExact *)instruction);
75357641 case IrInstructionIdCast:
75367642 case IrInstructionIdStructFieldPtr:
75377643 case IrInstructionIdEnumFieldPtr:
......@@ -7669,6 +7775,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
76697775 case IrInstructionIdMaxValue:
76707776 case IrInstructionIdErrName:
76717777 case IrInstructionIdEmbedFile:
7778 case IrInstructionIdDivExact:
76727779 return false;
76737780 case IrInstructionIdAsm:
76747781 {
......@@ -7682,37 +7789,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
76827789// TODO port over all this commented out code into new IR way of doing things
76837790
76847791
7685//static TypeTableEntry *analyze_div_exact(CodeGen *g, ImportTableEntry *import,
7686// BlockContext *context, AstNode *node)
7687//{
7688// assert(node->type == NodeTypeFnCallExpr);
7689//
7690// AstNode **op1 = &node->data.fn_call_expr.params.at(0);
7691// AstNode **op2 = &node->data.fn_call_expr.params.at(1);
7692//
7693// TypeTableEntry *op1_type = analyze_expression(g, import, context, nullptr, *op1);
7694// TypeTableEntry *op2_type = analyze_expression(g, import, context, nullptr, *op2);
7695//
7696// AstNode *op_nodes[] = {*op1, *op2};
7697// TypeTableEntry *op_types[] = {op1_type, op2_type};
7698// TypeTableEntry *result_type = resolve_peer_type_compatibility(g, import, context, node,
7699// op_nodes, op_types, 2);
7700//
7701// if (result_type->id == TypeTableEntryIdInvalid) {
7702// return g->builtin_types.entry_invalid;
7703// } else if (result_type->id == TypeTableEntryIdInt) {
7704// return result_type;
7705// } else if (result_type->id == TypeTableEntryIdNumLitInt) {
7706// // check for division by zero
7707// // check for non exact division
7708// zig_panic("TODO");
7709// } else {
7710// add_node_error(g, node,
7711// buf_sprintf("expected integer type, found '%s'", buf_ptr(&result_type->name)));
7712// return g->builtin_types.entry_invalid;
7713// }
7714//}
7715//
77167792//static TypeTableEntry *analyze_truncate(CodeGen *g, ImportTableEntry *import,
77177793// BlockContext *context, AstNode *node)
77187794//{
......@@ -7920,8 +7996,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
79207996// case BuiltinFnIdFrameAddress:
79217997// mark_impure_fn(g, context, node);
79227998// return builtin_fn->return_type;
7923// case BuiltinFnIdDivExact:
7924// return analyze_div_exact(g, import, context, node);
79257999// case BuiltinFnIdTruncate:
79268000// return analyze_truncate(g, import, context, node);
79278001// case BuiltinFnIdIntType:
......@@ -8243,18 +8317,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
82438317//
82448318
82458319
8246//static LLVMValueRef gen_div_exact(CodeGen *g, AstNode *node) {
8247// assert(node->type == NodeTypeFnCallExpr);
8248//
8249// AstNode *op1_node = node->data.fn_call_expr.params.at(0);
8250// AstNode *op2_node = node->data.fn_call_expr.params.at(1);
8251//
8252// LLVMValueRef op1_val = gen_expr(g, op1_node);
8253// LLVMValueRef op2_val = gen_expr(g, op2_node);
8254//
8255// return gen_div(g, node, op1_val, op2_val, get_expr_type(op1_node), true);
8256//}
8257//
82588320//static LLVMValueRef gen_truncate(CodeGen *g, AstNode *node) {
82598321// assert(node->type == NodeTypeFnCallExpr);
82608322//
......@@ -8421,8 +8483,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
84218483// return gen_cmp_exchange(g, node);
84228484// case BuiltinFnIdFence:
84238485// return gen_fence(g, node);
8424// case BuiltinFnIdDivExact:
8425// return gen_div_exact(g, node);
84268486// case BuiltinFnIdTruncate:
84278487// return gen_truncate(g, node);
84288488// case BuiltinFnIdUnreachable:
src/ir_print.cpp+11
......@@ -739,6 +739,14 @@ static void ir_print_fence(IrPrint *irp, IrInstructionFence *instruction) {
739739 fprintf(irp->f, ")");
740740}
741741
742static void ir_print_div_exact(IrPrint *irp, IrInstructionDivExact *instruction) {
743 fprintf(irp->f, "@divExact(");
744 ir_print_other_instruction(irp, instruction->op1);
745 fprintf(irp->f, ", ");
746 ir_print_other_instruction(irp, instruction->op2);
747 fprintf(irp->f, ")");
748}
749
742750static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
743751 ir_print_prefix(irp, instruction);
744752 switch (instruction->id) {
......@@ -909,6 +917,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
909917 case IrInstructionIdFence:
910918 ir_print_fence(irp, (IrInstructionFence *)instruction);
911919 break;
920 case IrInstructionIdDivExact:
921 ir_print_div_exact(irp, (IrInstructionDivExact *)instruction);
922 break;
912923 }
913924 fprintf(irp->f, "\n");
914925}
test/self_hosted2.zig+8
......@@ -285,6 +285,13 @@ fn fence() {
285285 x = 5678;
286286}
287287
288fn exactDivision() {
289 assert(divExact(55, 11) == 5);
290}
291fn divExact(a: u32, b: u32) -> u32 {
292 @divExact(a, b)
293}
294
288295fn assert(ok: bool) {
289296 if (!ok)
290297 @unreachable();
......@@ -314,6 +321,7 @@ fn runAllTests() {
314321 testErrorName();
315322 cmpxchg();
316323 fence();
324 exactDivision();
317325}
318326
319327export nakedcc fn _start() -> unreachable {