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 {...@@ -1409,6 +1409,7 @@ enum IrInstructionId {
1409 IrInstructionIdEmbedFile,1409 IrInstructionIdEmbedFile,
1410 IrInstructionIdCmpxchg,1410 IrInstructionIdCmpxchg,
1411 IrInstructionIdFence,1411 IrInstructionIdFence,
1412 IrInstructionIdDivExact,
1412};1413};
14131414
1414struct IrInstruction {1415struct IrInstruction {
...@@ -1884,6 +1885,13 @@ struct IrInstructionFence {...@@ -1884,6 +1885,13 @@ struct IrInstructionFence {
1884 AtomicOrder order;1885 AtomicOrder order;
1885};1886};
18861887
1888struct IrInstructionDivExact {
1889 IrInstruction base;
1890
1891 IrInstruction *op1;
1892 IrInstruction *op2;
1893};
1894
1887enum LValPurpose {1895enum LValPurpose {
1888 LValPurposeNone,1896 LValPurposeNone,
1889 LValPurposeAssign,1897 LValPurposeAssign,
src/codegen.cpp+10
...@@ -1871,6 +1871,14 @@ static LLVMValueRef ir_render_fence(CodeGen *g, IrExecutable *executable, IrInst...@@ -1871,6 +1871,14 @@ static LLVMValueRef ir_render_fence(CodeGen *g, IrExecutable *executable, IrInst
1871 return nullptr;1871 return nullptr;
1872}1872}
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
1874static void set_debug_location(CodeGen *g, IrInstruction *instruction) {1882static void set_debug_location(CodeGen *g, IrInstruction *instruction) {
1875 AstNode *source_node = instruction->source_node;1883 AstNode *source_node = instruction->source_node;
1876 Scope *scope = instruction->scope;1884 Scope *scope = instruction->scope;
...@@ -1964,6 +1972,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -1964,6 +1972,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
1964 return ir_render_cmpxchg(g, executable, (IrInstructionCmpxchg *)instruction);1972 return ir_render_cmpxchg(g, executable, (IrInstructionCmpxchg *)instruction);
1965 case IrInstructionIdFence:1973 case IrInstructionIdFence:
1966 return ir_render_fence(g, executable, (IrInstructionFence *)instruction);1974 return ir_render_fence(g, executable, (IrInstructionFence *)instruction);
1975 case IrInstructionIdDivExact:
1976 return ir_render_div_exact(g, executable, (IrInstructionDivExact *)instruction);
1967 case IrInstructionIdSwitchVar:1977 case IrInstructionIdSwitchVar:
1968 case IrInstructionIdContainerInitList:1978 case IrInstructionIdContainerInitList:
1969 case IrInstructionIdStructInit:1979 case IrInstructionIdStructInit:
src/ir.cpp+108-48
...@@ -355,6 +355,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionFence *) {...@@ -355,6 +355,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionFence *) {
355 return IrInstructionIdFence;355 return IrInstructionIdFence;
356}356}
357357
358static constexpr IrInstructionId ir_instruction_id(IrInstructionDivExact *) {
359 return IrInstructionIdDivExact;
360}
361
358template<typename T>362template<typename T>
359static T *ir_create_instruction(IrExecutable *exec, Scope *scope, AstNode *source_node) {363static T *ir_create_instruction(IrExecutable *exec, Scope *scope, AstNode *source_node) {
360 T *special_instruction = allocate<T>(1);364 T *special_instruction = allocate<T>(1);
...@@ -1413,6 +1417,23 @@ static IrInstruction *ir_build_fence_from(IrBuilder *irb, IrInstruction *old_ins...@@ -1413,6 +1417,23 @@ static IrInstruction *ir_build_fence_from(IrBuilder *irb, IrInstruction *old_ins
1413 return new_instruction;1417 return new_instruction;
1414}1418}
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
1416static void ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope,1437static void ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope,
1417 bool gen_error_defers, bool gen_maybe_defers)1438 bool gen_error_defers, bool gen_maybe_defers)
1418{1439{
...@@ -2192,6 +2213,20 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo...@@ -2192,6 +2213,20 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
21922213
2193 return ir_build_fence(irb, scope, node, arg0_value, AtomicOrderUnordered);2214 return ir_build_fence(irb, scope, node, arg0_value, AtomicOrderUnordered);
2194 }2215 }
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 }
2195 case BuiltinFnIdMemcpy:2230 case BuiltinFnIdMemcpy:
2196 case BuiltinFnIdMemset:2231 case BuiltinFnIdMemset:
2197 case BuiltinFnIdAlignof:2232 case BuiltinFnIdAlignof:
...@@ -2203,7 +2238,6 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo...@@ -2203,7 +2238,6 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
2203 case BuiltinFnIdBreakpoint:2238 case BuiltinFnIdBreakpoint:
2204 case BuiltinFnIdReturnAddress:2239 case BuiltinFnIdReturnAddress:
2205 case BuiltinFnIdFrameAddress:2240 case BuiltinFnIdFrameAddress:
2206 case BuiltinFnIdDivExact:
2207 case BuiltinFnIdTruncate:2241 case BuiltinFnIdTruncate:
2208 case BuiltinFnIdIntType:2242 case BuiltinFnIdIntType:
2209 zig_panic("TODO IR gen more builtin functions");2243 zig_panic("TODO IR gen more builtin functions");
...@@ -7426,6 +7460,76 @@ static TypeTableEntry *ir_analyze_instruction_fence(IrAnalyze *ira, IrInstructio...@@ -7426,6 +7460,76 @@ static TypeTableEntry *ir_analyze_instruction_fence(IrAnalyze *ira, IrInstructio
7426 return ira->codegen->builtin_types.entry_void;7460 return ira->codegen->builtin_types.entry_void;
7427}7461}
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
7429static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {7533static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
7430 switch (instruction->id) {7534 switch (instruction->id) {
7431 case IrInstructionIdInvalid:7535 case IrInstructionIdInvalid:
...@@ -7532,6 +7636,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi...@@ -7532,6 +7636,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
7532 return ir_analyze_instruction_cmpxchg(ira, (IrInstructionCmpxchg *)instruction);7636 return ir_analyze_instruction_cmpxchg(ira, (IrInstructionCmpxchg *)instruction);
7533 case IrInstructionIdFence:7637 case IrInstructionIdFence:
7534 return ir_analyze_instruction_fence(ira, (IrInstructionFence *)instruction);7638 return ir_analyze_instruction_fence(ira, (IrInstructionFence *)instruction);
7639 case IrInstructionIdDivExact:
7640 return ir_analyze_instruction_div_exact(ira, (IrInstructionDivExact *)instruction);
7535 case IrInstructionIdCast:7641 case IrInstructionIdCast:
7536 case IrInstructionIdStructFieldPtr:7642 case IrInstructionIdStructFieldPtr:
7537 case IrInstructionIdEnumFieldPtr:7643 case IrInstructionIdEnumFieldPtr:
...@@ -7669,6 +7775,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -7669,6 +7775,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
7669 case IrInstructionIdMaxValue:7775 case IrInstructionIdMaxValue:
7670 case IrInstructionIdErrName:7776 case IrInstructionIdErrName:
7671 case IrInstructionIdEmbedFile:7777 case IrInstructionIdEmbedFile:
7778 case IrInstructionIdDivExact:
7672 return false;7779 return false;
7673 case IrInstructionIdAsm:7780 case IrInstructionIdAsm:
7674 {7781 {
...@@ -7682,37 +7789,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -7682,37 +7789,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
7682// TODO port over all this commented out code into new IR way of doing things7789// 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//
7716//static TypeTableEntry *analyze_truncate(CodeGen *g, ImportTableEntry *import,7792//static TypeTableEntry *analyze_truncate(CodeGen *g, ImportTableEntry *import,
7717// BlockContext *context, AstNode *node)7793// BlockContext *context, AstNode *node)
7718//{7794//{
...@@ -7920,8 +7996,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -7920,8 +7996,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
7920// case BuiltinFnIdFrameAddress:7996// case BuiltinFnIdFrameAddress:
7921// mark_impure_fn(g, context, node);7997// mark_impure_fn(g, context, node);
7922// return builtin_fn->return_type;7998// return builtin_fn->return_type;
7923// case BuiltinFnIdDivExact:
7924// return analyze_div_exact(g, import, context, node);
7925// case BuiltinFnIdTruncate:7999// case BuiltinFnIdTruncate:
7926// return analyze_truncate(g, import, context, node);8000// return analyze_truncate(g, import, context, node);
7927// case BuiltinFnIdIntType:8001// case BuiltinFnIdIntType:
...@@ -8243,18 +8317,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -8243,18 +8317,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
8243//8317//
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//
8258//static LLVMValueRef gen_truncate(CodeGen *g, AstNode *node) {8320//static LLVMValueRef gen_truncate(CodeGen *g, AstNode *node) {
8259// assert(node->type == NodeTypeFnCallExpr);8321// assert(node->type == NodeTypeFnCallExpr);
8260//8322//
...@@ -8421,8 +8483,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -8421,8 +8483,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
8421// return gen_cmp_exchange(g, node);8483// return gen_cmp_exchange(g, node);
8422// case BuiltinFnIdFence:8484// case BuiltinFnIdFence:
8423// return gen_fence(g, node);8485// return gen_fence(g, node);
8424// case BuiltinFnIdDivExact:
8425// return gen_div_exact(g, node);
8426// case BuiltinFnIdTruncate:8486// case BuiltinFnIdTruncate:
8427// return gen_truncate(g, node);8487// return gen_truncate(g, node);
8428// case BuiltinFnIdUnreachable:8488// case BuiltinFnIdUnreachable:
src/ir_print.cpp+11
...@@ -739,6 +739,14 @@ static void ir_print_fence(IrPrint *irp, IrInstructionFence *instruction) {...@@ -739,6 +739,14 @@ static void ir_print_fence(IrPrint *irp, IrInstructionFence *instruction) {
739 fprintf(irp->f, ")");739 fprintf(irp->f, ")");
740}740}
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
742static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {750static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
743 ir_print_prefix(irp, instruction);751 ir_print_prefix(irp, instruction);
744 switch (instruction->id) {752 switch (instruction->id) {
...@@ -909,6 +917,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {...@@ -909,6 +917,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
909 case IrInstructionIdFence:917 case IrInstructionIdFence:
910 ir_print_fence(irp, (IrInstructionFence *)instruction);918 ir_print_fence(irp, (IrInstructionFence *)instruction);
911 break;919 break;
920 case IrInstructionIdDivExact:
921 ir_print_div_exact(irp, (IrInstructionDivExact *)instruction);
922 break;
912 }923 }
913 fprintf(irp->f, "\n");924 fprintf(irp->f, "\n");
914}925}
test/self_hosted2.zig+8
...@@ -285,6 +285,13 @@ fn fence() {...@@ -285,6 +285,13 @@ fn fence() {
285 x = 5678;285 x = 5678;
286}286}
287287
288fn exactDivision() {
289 assert(divExact(55, 11) == 5);
290}
291fn divExact(a: u32, b: u32) -> u32 {
292 @divExact(a, b)
293}
294
288fn assert(ok: bool) {295fn assert(ok: bool) {
289 if (!ok)296 if (!ok)
290 @unreachable();297 @unreachable();
...@@ -314,6 +321,7 @@ fn runAllTests() {...@@ -314,6 +321,7 @@ fn runAllTests() {
314 testErrorName();321 testErrorName();
315 cmpxchg();322 cmpxchg();
316 fence();323 fence();
324 exactDivision();
317}325}
318326
319export nakedcc fn _start() -> unreachable {327export nakedcc fn _start() -> unreachable {