authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-11-27 00:14:19-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-11-27 00:14:19-05:00
logbd4d4ee51efebb79ed7b563a10eec992a71220fd
tree4f01f7f8c967dc8e94ef94eaedfa2f46978ec04d
parent1fba7f36960551fe0a12aa754c2d789c8784a8cc

IR: detect error for exceeding branch quota


3 files changed, 41 insertions(+), 27 deletions(-)

src/all_types.hpp+2
...@@ -36,6 +36,8 @@ struct IrExecutable {...@@ -36,6 +36,8 @@ struct IrExecutable {
36 ZigList<IrBasicBlock *> basic_block_list;36 ZigList<IrBasicBlock *> basic_block_list;
37 size_t mem_slot_count;37 size_t mem_slot_count;
38 size_t next_debug_id;38 size_t next_debug_id;
39 size_t backward_branch_count;
40 size_t backward_branch_quota;
39 bool invalid;41 bool invalid;
40 ZigList<LabelTableEntry *> all_labels;42 ZigList<LabelTableEntry *> all_labels;
41 ZigList<AstNode *> goto_list;43 ZigList<AstNode *> goto_list;
src/analyze.cpp+5-1
...@@ -17,6 +17,8 @@...@@ -17,6 +17,8 @@
17#include "parser.hpp"17#include "parser.hpp"
18#include "zig_llvm.hpp"18#include "zig_llvm.hpp"
1919
20static const size_t default_backward_branch_quota = 1000;
21
20static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEntry *enum_type);22static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEntry *enum_type);
21static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableEntry *struct_type);23static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableEntry *struct_type);
2224
...@@ -836,7 +838,6 @@ static IrInstruction *analyze_const_value(CodeGen *g, BlockContext *scope, AstNo...@@ -836,7 +838,6 @@ static IrInstruction *analyze_const_value(CodeGen *g, BlockContext *scope, AstNo
836 TypeTableEntry *expected_type)838 TypeTableEntry *expected_type)
837{839{
838 IrExecutable ir_executable = {0};840 IrExecutable ir_executable = {0};
839 IrExecutable analyzed_executable = {0};
840 ir_gen(g, node, scope, &ir_executable);841 ir_gen(g, node, scope, &ir_executable);
841842
842 if (ir_executable.invalid)843 if (ir_executable.invalid)
...@@ -849,6 +850,8 @@ static IrInstruction *analyze_const_value(CodeGen *g, BlockContext *scope, AstNo...@@ -849,6 +850,8 @@ static IrInstruction *analyze_const_value(CodeGen *g, BlockContext *scope, AstNo
849 ir_print(stderr, &ir_executable, 4);850 ir_print(stderr, &ir_executable, 4);
850 fprintf(stderr, "}\n");851 fprintf(stderr, "}\n");
851 }852 }
853 IrExecutable analyzed_executable = {0};
854 analyzed_executable.backward_branch_quota = default_backward_branch_quota;
852 TypeTableEntry *result_type = ir_analyze(g, &ir_executable, &analyzed_executable, expected_type, node);855 TypeTableEntry *result_type = ir_analyze(g, &ir_executable, &analyzed_executable, expected_type, node);
853 if (result_type->id == TypeTableEntryIdInvalid)856 if (result_type->id == TypeTableEntryIdInvalid)
854 return g->invalid_instruction;857 return g->invalid_instruction;
...@@ -1514,6 +1517,7 @@ static void preview_fn_proto_instance(CodeGen *g, ImportTableEntry *import, AstN...@@ -1514,6 +1517,7 @@ static void preview_fn_proto_instance(CodeGen *g, ImportTableEntry *import, AstN
1514 }1517 }
15151518
1516 FnTableEntry *fn_table_entry = allocate<FnTableEntry>(1);1519 FnTableEntry *fn_table_entry = allocate<FnTableEntry>(1);
1520 fn_table_entry->analyzed_executable.backward_branch_quota = default_backward_branch_quota;
1517 fn_table_entry->import_entry = import;1521 fn_table_entry->import_entry = import;
1518 fn_table_entry->proto_node = proto_node;1522 fn_table_entry->proto_node = proto_node;
1519 fn_table_entry->fn_def_node = fn_def_node;1523 fn_table_entry->fn_def_node = fn_def_node;
src/ir.cpp+34-26
...@@ -2957,8 +2957,24 @@ static void ir_finish_bb(IrAnalyze *ira) {...@@ -2957,8 +2957,24 @@ static void ir_finish_bb(IrAnalyze *ira) {
2957 }2957 }
2958}2958}
29592959
2960static void ir_inline_bb(IrAnalyze *ira, IrBasicBlock *old_bb) {2960static TypeTableEntry *ir_unreach_error(IrAnalyze *ira) {
2961 ira->block_queue_index = SIZE_MAX;
2962 ira->new_irb.exec->invalid = true;
2963 return ira->codegen->builtin_types.entry_unreachable;
2964}
2965
2966static TypeTableEntry *ir_inline_bb(IrAnalyze *ira, IrInstruction *source_instruction, IrBasicBlock *old_bb) {
2967 if (old_bb->debug_id <= ira->old_irb.current_basic_block->debug_id) {
2968 ira->new_irb.exec->backward_branch_count += 1;
2969 if (ira->new_irb.exec->backward_branch_count > ira->new_irb.exec->backward_branch_quota) {
2970 add_node_error(ira->codegen, source_instruction->source_node,
2971 buf_sprintf("evaluation exceeded %zu backwards branches", ira->new_irb.exec->backward_branch_quota));
2972 return ir_unreach_error(ira);
2973 }
2974 }
2975
2961 ir_start_bb(ira, old_bb, ira->old_irb.current_basic_block);2976 ir_start_bb(ira, old_bb, ira->old_irb.current_basic_block);
2977 return ira->codegen->builtin_types.entry_unreachable;
2962}2978}
29632979
2964static TypeTableEntry *ir_finish_anal(IrAnalyze *ira, TypeTableEntry *result_type) {2980static TypeTableEntry *ir_finish_anal(IrAnalyze *ira, TypeTableEntry *result_type) {
...@@ -3439,12 +3455,12 @@ static TypeTableEntry *ir_analyze_instruction_return(IrAnalyze *ira,...@@ -3439,12 +3455,12 @@ static TypeTableEntry *ir_analyze_instruction_return(IrAnalyze *ira,
3439{3455{
3440 IrInstruction *value = return_instruction->value->other;3456 IrInstruction *value = return_instruction->value->other;
3441 if (value->type_entry->id == TypeTableEntryIdInvalid)3457 if (value->type_entry->id == TypeTableEntryIdInvalid)
3442 return ir_finish_anal(ira, ira->codegen->builtin_types.entry_unreachable);3458 return ir_unreach_error(ira);
3443 ira->implicit_return_type_list.append(value);3459 ira->implicit_return_type_list.append(value);
34443460
3445 IrInstruction *casted_value = ir_get_casted_value(ira, value, ira->explicit_return_type);3461 IrInstruction *casted_value = ir_get_casted_value(ira, value, ira->explicit_return_type);
3446 if (casted_value == ira->codegen->invalid_instruction)3462 if (casted_value == ira->codegen->invalid_instruction)
3447 return ir_finish_anal(ira, ira->codegen->builtin_types.entry_unreachable);3463 return ir_unreach_error(ira);
34483464
3449 ir_build_return_from(&ira->new_irb, &return_instruction->base, casted_value);3465 ir_build_return_from(&ira->new_irb, &return_instruction->base, casted_value);
3450 return ir_finish_anal(ira, ira->codegen->builtin_types.entry_unreachable);3466 return ir_finish_anal(ira, ira->codegen->builtin_types.entry_unreachable);
...@@ -4302,11 +4318,8 @@ static TypeTableEntry *ir_analyze_instruction_un_op(IrAnalyze *ira, IrInstructio...@@ -4302,11 +4318,8 @@ static TypeTableEntry *ir_analyze_instruction_un_op(IrAnalyze *ira, IrInstructio
4302static TypeTableEntry *ir_analyze_instruction_br(IrAnalyze *ira, IrInstructionBr *br_instruction) {4318static TypeTableEntry *ir_analyze_instruction_br(IrAnalyze *ira, IrInstructionBr *br_instruction) {
4303 IrBasicBlock *old_dest_block = br_instruction->dest_block;4319 IrBasicBlock *old_dest_block = br_instruction->dest_block;
43044320
4305 // TODO detect backward jumps
4306
4307 if (br_instruction->is_inline || old_dest_block->ref_count == 1) {4321 if (br_instruction->is_inline || old_dest_block->ref_count == 1) {
4308 ir_inline_bb(ira, old_dest_block);4322 return ir_inline_bb(ira, &br_instruction->base, old_dest_block);
4309 return ira->codegen->builtin_types.entry_unreachable;
4310 }4323 }
43114324
4312 IrBasicBlock *new_bb = ir_get_new_bb(ira, old_dest_block);4325 IrBasicBlock *new_bb = ir_get_new_bb(ira, old_dest_block);
...@@ -4317,28 +4330,24 @@ static TypeTableEntry *ir_analyze_instruction_br(IrAnalyze *ira, IrInstructionBr...@@ -4317,28 +4330,24 @@ static TypeTableEntry *ir_analyze_instruction_br(IrAnalyze *ira, IrInstructionBr
4317static TypeTableEntry *ir_analyze_instruction_cond_br(IrAnalyze *ira, IrInstructionCondBr *cond_br_instruction) {4330static TypeTableEntry *ir_analyze_instruction_cond_br(IrAnalyze *ira, IrInstructionCondBr *cond_br_instruction) {
4318 IrInstruction *condition = cond_br_instruction->condition->other;4331 IrInstruction *condition = cond_br_instruction->condition->other;
4319 if (condition->type_entry->id == TypeTableEntryIdInvalid)4332 if (condition->type_entry->id == TypeTableEntryIdInvalid)
4320 return ir_finish_anal(ira, ira->codegen->builtin_types.entry_unreachable);4333 return ir_unreach_error(ira);
4321
4322 // TODO detect backward jumps
43234334
4324 if (cond_br_instruction->is_inline || condition->static_value.special != ConstValSpecialRuntime) {4335 if (cond_br_instruction->is_inline || condition->static_value.special != ConstValSpecialRuntime) {
4325 bool cond_is_true;4336 bool cond_is_true;
4326 if (!ir_resolve_bool(ira, condition, &cond_is_true))4337 if (!ir_resolve_bool(ira, condition, &cond_is_true))
4327 return ir_finish_anal(ira, ira->codegen->builtin_types.entry_unreachable);4338 return ir_unreach_error(ira);
43284339
4329 IrBasicBlock *old_dest_block = cond_is_true ?4340 IrBasicBlock *old_dest_block = cond_is_true ?
4330 cond_br_instruction->then_block : cond_br_instruction->else_block;4341 cond_br_instruction->then_block : cond_br_instruction->else_block;
43314342
4332 if (cond_br_instruction->is_inline || old_dest_block->ref_count == 1) {4343 if (cond_br_instruction->is_inline || old_dest_block->ref_count == 1)
4333 ir_inline_bb(ira, old_dest_block);4344 return ir_inline_bb(ira, &cond_br_instruction->base, old_dest_block);
4334 return ira->codegen->builtin_types.entry_unreachable;
4335 }
4336 }4345 }
43374346
4338 TypeTableEntry *bool_type = ira->codegen->builtin_types.entry_bool;4347 TypeTableEntry *bool_type = ira->codegen->builtin_types.entry_bool;
4339 IrInstruction *casted_condition = ir_get_casted_value(ira, condition, bool_type);4348 IrInstruction *casted_condition = ir_get_casted_value(ira, condition, bool_type);
4340 if (casted_condition == ira->codegen->invalid_instruction)4349 if (casted_condition == ira->codegen->invalid_instruction)
4341 return ir_finish_anal(ira, ira->codegen->builtin_types.entry_unreachable);4350 return ir_unreach_error(ira);
43424351
4343 IrBasicBlock *new_then_block = ir_get_new_bb(ira, cond_br_instruction->then_block);4352 IrBasicBlock *new_then_block = ir_get_new_bb(ira, cond_br_instruction->then_block);
4344 IrBasicBlock *new_else_block = ir_get_new_bb(ira, cond_br_instruction->else_block);4353 IrBasicBlock *new_else_block = ir_get_new_bb(ira, cond_br_instruction->else_block);
...@@ -5418,9 +5427,7 @@ static TypeTableEntry *ir_analyze_instruction_switch_br(IrAnalyze *ira,...@@ -5418,9 +5427,7 @@ static TypeTableEntry *ir_analyze_instruction_switch_br(IrAnalyze *ira,
5418{5427{
5419 IrInstruction *target_value = switch_br_instruction->target_value->other;5428 IrInstruction *target_value = switch_br_instruction->target_value->other;
5420 if (target_value->type_entry->id == TypeTableEntryIdInvalid)5429 if (target_value->type_entry->id == TypeTableEntryIdInvalid)
5421 return ir_finish_anal(ira, ira->codegen->builtin_types.entry_unreachable);5430 return ir_unreach_error(ira);
5422
5423 // TODO detect backward jumps
54245431
5425 size_t case_count = switch_br_instruction->case_count;5432 size_t case_count = switch_br_instruction->case_count;
5426 bool is_inline = switch_br_instruction->is_inline;5433 bool is_inline = switch_br_instruction->is_inline;
...@@ -5428,27 +5435,26 @@ static TypeTableEntry *ir_analyze_instruction_switch_br(IrAnalyze *ira,...@@ -5428,27 +5435,26 @@ static TypeTableEntry *ir_analyze_instruction_switch_br(IrAnalyze *ira,
5428 if (is_inline || target_value->static_value.special != ConstValSpecialRuntime) {5435 if (is_inline || target_value->static_value.special != ConstValSpecialRuntime) {
5429 ConstExprValue *target_val = ir_resolve_const(ira, target_value);5436 ConstExprValue *target_val = ir_resolve_const(ira, target_value);
5430 if (!target_val)5437 if (!target_val)
5431 return ir_finish_anal(ira, ira->codegen->builtin_types.entry_unreachable);5438 return ir_unreach_error(ira);
54325439
5433 for (size_t i = 0; i < case_count; i += 1) {5440 for (size_t i = 0; i < case_count; i += 1) {
5434 IrInstructionSwitchBrCase *old_case = &switch_br_instruction->cases[i];5441 IrInstructionSwitchBrCase *old_case = &switch_br_instruction->cases[i];
5435 IrInstruction *case_value = old_case->value->other;5442 IrInstruction *case_value = old_case->value->other;
5436 if (case_value->type_entry->id == TypeTableEntryIdInvalid)5443 if (case_value->type_entry->id == TypeTableEntryIdInvalid)
5437 return ir_finish_anal(ira, ira->codegen->builtin_types.entry_unreachable);5444 return ir_unreach_error(ira);
54385445
5439 IrInstruction *casted_case_value = ir_get_casted_value(ira, case_value, target_value->type_entry);5446 IrInstruction *casted_case_value = ir_get_casted_value(ira, case_value, target_value->type_entry);
5440 if (casted_case_value->type_entry->id == TypeTableEntryIdInvalid)5447 if (casted_case_value->type_entry->id == TypeTableEntryIdInvalid)
5441 return ir_finish_anal(ira, ira->codegen->builtin_types.entry_unreachable);5448 return ir_unreach_error(ira);
54425449
5443 ConstExprValue *case_val = ir_resolve_const(ira, casted_case_value);5450 ConstExprValue *case_val = ir_resolve_const(ira, casted_case_value);
5444 if (!case_val)5451 if (!case_val)
5445 return ir_finish_anal(ira, ira->codegen->builtin_types.entry_unreachable);5452 return ir_unreach_error(ira);
54465453
5447 if (const_values_equal(target_val, case_val, target_value->type_entry)) {5454 if (const_values_equal(target_val, case_val, target_value->type_entry)) {
5448 IrBasicBlock *old_dest_block = old_case->block;5455 IrBasicBlock *old_dest_block = old_case->block;
5449 if (is_inline || old_dest_block->ref_count == 1) {5456 if (is_inline || old_dest_block->ref_count == 1) {
5450 ir_inline_bb(ira, old_dest_block);5457 return ir_inline_bb(ira, &switch_br_instruction->base, old_dest_block);
5451 return ira->codegen->builtin_types.entry_unreachable;
5452 } else {5458 } else {
5453 IrBasicBlock *new_dest_block = ir_get_new_bb(ira, old_dest_block);5459 IrBasicBlock *new_dest_block = ir_get_new_bb(ira, old_dest_block);
5454 ir_build_br_from(&ira->new_irb, &switch_br_instruction->base, new_dest_block);5460 ir_build_br_from(&ira->new_irb, &switch_br_instruction->base, new_dest_block);
...@@ -5840,7 +5846,9 @@ TypeTableEntry *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutabl...@@ -5840,7 +5846,9 @@ TypeTableEntry *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutabl
5840 ira->instruction_index += 1;5846 ira->instruction_index += 1;
5841 }5847 }
58425848
5843 if (ira->implicit_return_type_list.length == 0) {5849 if (new_exec->invalid) {
5850 return ira->codegen->builtin_types.entry_invalid;
5851 } else if (ira->implicit_return_type_list.length == 0) {
5844 return codegen->builtin_types.entry_unreachable;5852 return codegen->builtin_types.entry_unreachable;
5845 } else {5853 } else {
5846 return ir_resolve_peer_types(ira, expected_type_source_node, ira->implicit_return_type_list.items,5854 return ir_resolve_peer_types(ira, expected_type_source_node, ira->implicit_return_type_list.items,