Commit caaeab9882

Andrew Kelley <superjoe30@gmail.com>
2017-08-19 23:10:29
add setEvalBranchQuota builtin function
1 parent eb26aeb
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;
 
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) {
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<typename T>
 static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
     T *special_instruction = allocate<T>(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<IrInstructionSetEvalBranchQuota>(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:
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");
 }
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);
+    }
+}
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.