diff --git a/README.md b/README.md index 97c109e70b..19d10861c1 100644 --- a/README.md +++ b/README.md @@ -137,4 +137,4 @@ produced .gcov files. * Runtime crashes are better than bugs. * Compile errors are better than runtime crashes. * Minimize energy spent on coding style. - * Together we serve the users. + * Together we serve the end users. diff --git a/src/all_types.hpp b/src/all_types.hpp index 3bc9839746..9f898f9982 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1232,6 +1232,7 @@ enum BuiltinFnId { BuiltinFnIdTypeId, BuiltinFnIdShlExact, BuiltinFnIdShrExact, + BuiltinFnIdSetEvalBranchQuota, }; struct BuiltinFnEntry { @@ -1834,6 +1835,7 @@ enum IrInstructionId { IrInstructionIdFieldParentPtr, IrInstructionIdOffsetOf, IrInstructionIdTypeId, + IrInstructionIdSetEvalBranchQuota, }; struct IrInstruction { @@ -2603,6 +2605,12 @@ struct IrInstructionTypeId { IrInstruction *type_value; }; +struct IrInstructionSetEvalBranchQuota { + IrInstruction base; + + IrInstruction *new_quota; +}; + static const size_t slice_ptr_index = 0; static const size_t slice_len_index = 1; diff --git a/src/codegen.cpp b/src/codegen.cpp index bb95a3faae..db934b6b88 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3173,6 +3173,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdSwitchVar: case IrInstructionIdOffsetOf: case IrInstructionIdTypeId: + case IrInstructionIdSetEvalBranchQuota: zig_unreachable(); case IrInstructionIdReturn: return ir_render_return(g, executable, (IrInstructionReturn *)instruction); @@ -4635,6 +4636,7 @@ static void define_builtin_fns(CodeGen *g) { create_builtin_fn(g, BuiltinFnIdTypeId, "typeId", 1); create_builtin_fn(g, BuiltinFnIdShlExact, "shlExact", 2); create_builtin_fn(g, BuiltinFnIdShrExact, "shrExact", 2); + create_builtin_fn(g, BuiltinFnIdSetEvalBranchQuota, "setEvalBranchQuota", 1); } static const char *bool_to_str(bool b) { diff --git a/src/ir.cpp b/src/ir.cpp index 065af2ed81..4c06fe8c34 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -549,6 +549,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionTypeId *) { return IrInstructionIdTypeId; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionSetEvalBranchQuota *) { + return IrInstructionIdSetEvalBranchQuota; +} + template static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { T *special_instruction = allocate(1); @@ -2192,6 +2196,17 @@ static IrInstruction *ir_build_type_id(IrBuilder *irb, Scope *scope, AstNode *so return &instruction->base; } +static IrInstruction *ir_build_set_eval_branch_quota(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstruction *new_quota) +{ + IrInstructionSetEvalBranchQuota *instruction = ir_build_instruction(irb, scope, source_node); + instruction->new_quota = new_quota; + + ir_ref_instruction(new_quota, irb->current_basic_block); + + return &instruction->base; +} + static IrInstruction *ir_instruction_br_get_dep(IrInstructionBr *instruction, size_t index) { return nullptr; } @@ -2881,6 +2896,13 @@ static IrInstruction *ir_instruction_typeid_get_dep(IrInstructionTypeId *instruc } } +static IrInstruction *ir_instruction_setevalbranchquota_get_dep(IrInstructionSetEvalBranchQuota *instruction, size_t index) { + switch (index) { + case 0: return instruction->new_quota; + default: return nullptr; + } +} + static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t index) { switch (instruction->id) { case IrInstructionIdInvalid: @@ -3075,6 +3097,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t return ir_instruction_offsetof_get_dep((IrInstructionOffsetOf *) instruction, index); case IrInstructionIdTypeId: return ir_instruction_typeid_get_dep((IrInstructionTypeId *) instruction, index); + case IrInstructionIdSetEvalBranchQuota: + return ir_instruction_setevalbranchquota_get_dep((IrInstructionSetEvalBranchQuota *) instruction, index); } zig_unreachable(); } @@ -4481,6 +4505,15 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return ir_build_bin_op(irb, scope, node, IrBinOpBitShiftRightExact, arg0_value, arg1_value, true); } + case BuiltinFnIdSetEvalBranchQuota: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_instruction) + return arg0_value; + + return ir_build_set_eval_branch_quota(irb, scope, node, arg0_value); + } } zig_unreachable(); } @@ -12432,6 +12465,21 @@ static TypeTableEntry *ir_analyze_instruction_type_id(IrAnalyze *ira, return result_type; } +static TypeTableEntry *ir_analyze_instruction_set_eval_branch_quota(IrAnalyze *ira, + IrInstructionSetEvalBranchQuota *instruction) +{ + uint64_t new_quota; + if (!ir_resolve_usize(ira, instruction->new_quota->other, &new_quota)) + return ira->codegen->builtin_types.entry_invalid; + + if (new_quota > ira->new_irb.exec->backward_branch_quota) { + ira->new_irb.exec->backward_branch_quota = new_quota; + } + + ir_build_const_from(ira, &instruction->base); + return ira->codegen->builtin_types.entry_void; +} + static TypeTableEntry *ir_analyze_instruction_type_name(IrAnalyze *ira, IrInstructionTypeName *instruction) { IrInstruction *type_value = instruction->type_value->other; TypeTableEntry *type_entry = ir_resolve_type(ira, type_value); @@ -14249,6 +14297,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi return ir_analyze_instruction_offset_of(ira, (IrInstructionOffsetOf *)instruction); case IrInstructionIdTypeId: return ir_analyze_instruction_type_id(ira, (IrInstructionTypeId *)instruction); + case IrInstructionIdSetEvalBranchQuota: + return ir_analyze_instruction_set_eval_branch_quota(ira, (IrInstructionSetEvalBranchQuota *)instruction); case IrInstructionIdMaybeWrap: case IrInstructionIdErrWrapCode: case IrInstructionIdErrWrapPayload: @@ -14365,6 +14415,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdSetGlobalSection: case IrInstructionIdSetGlobalLinkage: case IrInstructionIdPanic: + case IrInstructionIdSetEvalBranchQuota: return true; case IrInstructionIdPhi: case IrInstructionIdUnOp: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 3af16802ad..291211668e 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -910,6 +910,12 @@ static void ir_print_type_id(IrPrint *irp, IrInstructionTypeId *instruction) { fprintf(irp->f, ")"); } +static void ir_print_set_eval_branch_quota(IrPrint *irp, IrInstructionSetEvalBranchQuota *instruction) { + fprintf(irp->f, "@setEvalBranchQuota("); + ir_print_other_instruction(irp, instruction->new_quota); + fprintf(irp->f, ")"); +} + static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { ir_print_prefix(irp, instruction); switch (instruction->id) { @@ -1200,6 +1206,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdTypeId: ir_print_type_id(irp, (IrInstructionTypeId *)instruction); break; + case IrInstructionIdSetEvalBranchQuota: + ir_print_set_eval_branch_quota(irp, (IrInstructionSetEvalBranchQuota *)instruction); + break; } fprintf(irp->f, "\n"); } diff --git a/test/cases/eval.zig b/test/cases/eval.zig index bf42062fb5..39aa10018a 100644 --- a/test/cases/eval.zig +++ b/test/cases/eval.zig @@ -342,3 +342,16 @@ test "const global shares pointer with other same one" { fn assertEqualPtrs(ptr1: &const u8, ptr2: &const u8) { assert(ptr1 == ptr2); } + +test "@setEvalBranchQuota" { + comptime { + // 1001 for the loop and then 1 more for the assert fn call + @setEvalBranchQuota(1002); + var i = 0; + var sum = 0; + while (i < 1001) : (i += 1) { + sum += i; + } + assert(sum == 500500); + } +}