| ... | ... | @@ -355,6 +355,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionFence *) { |
| 355 | 355 | return IrInstructionIdFence; |
| 356 | 356 | } |
| 357 | 357 | |
| 358 | static constexpr IrInstructionId ir_instruction_id(IrInstructionDivExact *) { |
| 359 | return IrInstructionIdDivExact; |
| 360 | } |
| 361 | |
| 358 | 362 | template<typename T> |
| 359 | 363 | static T *ir_create_instruction(IrExecutable *exec, Scope *scope, AstNode *source_node) { |
| 360 | 364 | T *special_instruction = allocate<T>(1); |
| ... | ... | @@ -1413,6 +1417,23 @@ static IrInstruction *ir_build_fence_from(IrBuilder *irb, IrInstruction *old_ins |
| 1413 | 1417 | return new_instruction; |
| 1414 | 1418 | } |
| 1415 | 1419 | |
| 1420 | static 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 | |
| 1431 | static 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 | |
| 1416 | 1437 | static void ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, |
| 1417 | 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 | 2213 | |
| 2193 | 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 | 2230 | case BuiltinFnIdMemcpy: |
| 2196 | 2231 | case BuiltinFnIdMemset: |
| 2197 | 2232 | case BuiltinFnIdAlignof: |
| ... | ... | @@ -2203,7 +2238,6 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 2203 | 2238 | case BuiltinFnIdBreakpoint: |
| 2204 | 2239 | case BuiltinFnIdReturnAddress: |
| 2205 | 2240 | case BuiltinFnIdFrameAddress: |
| 2206 | | case BuiltinFnIdDivExact: |
| 2207 | 2241 | case BuiltinFnIdTruncate: |
| 2208 | 2242 | case BuiltinFnIdIntType: |
| 2209 | 2243 | zig_panic("TODO IR gen more builtin functions"); |
| ... | ... | @@ -7426,6 +7460,76 @@ static TypeTableEntry *ir_analyze_instruction_fence(IrAnalyze *ira, IrInstructio |
| 7426 | 7460 | return ira->codegen->builtin_types.entry_void; |
| 7427 | 7461 | } |
| 7428 | 7462 | |
| 7463 | static 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 | |
| 7429 | 7533 | static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) { |
| 7430 | 7534 | switch (instruction->id) { |
| 7431 | 7535 | case IrInstructionIdInvalid: |
| ... | ... | @@ -7532,6 +7636,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi |
| 7532 | 7636 | return ir_analyze_instruction_cmpxchg(ira, (IrInstructionCmpxchg *)instruction); |
| 7533 | 7637 | case IrInstructionIdFence: |
| 7534 | 7638 | return ir_analyze_instruction_fence(ira, (IrInstructionFence *)instruction); |
| 7639 | case IrInstructionIdDivExact: |
| 7640 | return ir_analyze_instruction_div_exact(ira, (IrInstructionDivExact *)instruction); |
| 7535 | 7641 | case IrInstructionIdCast: |
| 7536 | 7642 | case IrInstructionIdStructFieldPtr: |
| 7537 | 7643 | case IrInstructionIdEnumFieldPtr: |
| ... | ... | @@ -7669,6 +7775,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 7669 | 7775 | case IrInstructionIdMaxValue: |
| 7670 | 7776 | case IrInstructionIdErrName: |
| 7671 | 7777 | case IrInstructionIdEmbedFile: |
| 7778 | case IrInstructionIdDivExact: |
| 7672 | 7779 | return false; |
| 7673 | 7780 | case IrInstructionIdAsm: |
| 7674 | 7781 | { |
| ... | ... | @@ -7682,37 +7789,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 7682 | 7789 | // TODO port over all this commented out code into new IR way of doing things |
| 7683 | 7790 | |
| 7684 | 7791 | |
| 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 | 7792 | //static TypeTableEntry *analyze_truncate(CodeGen *g, ImportTableEntry *import, |
| 7717 | 7793 | // BlockContext *context, AstNode *node) |
| 7718 | 7794 | //{ |
| ... | ... | @@ -7920,8 +7996,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 7920 | 7996 | // case BuiltinFnIdFrameAddress: |
| 7921 | 7997 | // mark_impure_fn(g, context, node); |
| 7922 | 7998 | // return builtin_fn->return_type; |
| 7923 | | // case BuiltinFnIdDivExact: |
| 7924 | | // return analyze_div_exact(g, import, context, node); |
| 7925 | 7999 | // case BuiltinFnIdTruncate: |
| 7926 | 8000 | // return analyze_truncate(g, import, context, node); |
| 7927 | 8001 | // case BuiltinFnIdIntType: |
| ... | ... | @@ -8243,18 +8317,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 8243 | 8317 | // |
| 8244 | 8318 | |
| 8245 | 8319 | |
| 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 | 8320 | //static LLVMValueRef gen_truncate(CodeGen *g, AstNode *node) { |
| 8259 | 8321 | // assert(node->type == NodeTypeFnCallExpr); |
| 8260 | 8322 | // |
| ... | ... | @@ -8421,8 +8483,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 8421 | 8483 | // return gen_cmp_exchange(g, node); |
| 8422 | 8484 | // case BuiltinFnIdFence: |
| 8423 | 8485 | // return gen_fence(g, node); |
| 8424 | | // case BuiltinFnIdDivExact: |
| 8425 | | // return gen_div_exact(g, node); |
| 8426 | 8486 | // case BuiltinFnIdTruncate: |
| 8427 | 8487 | // return gen_truncate(g, node); |
| 8428 | 8488 | // case BuiltinFnIdUnreachable: |