| ... | @@ -6,6 +6,7 @@ | ... | @@ -6,6 +6,7 @@ |
| 6 | */ | 6 | */ |
| 7 | | 7 | |
| 8 | #include "analyze.hpp" | 8 | #include "analyze.hpp" |
| | 9 | #include "ast_render.hpp" |
| 9 | #include "error.hpp" | 10 | #include "error.hpp" |
| 10 | #include "eval.hpp" | 11 | #include "eval.hpp" |
| 11 | #include "ir.hpp" | 12 | #include "ir.hpp" |
| ... | @@ -2814,7 +2815,7 @@ IrInstruction *ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutabl | ... | @@ -2814,7 +2815,7 @@ IrInstruction *ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutabl |
| 2814 | return return_instruction; | 2815 | return return_instruction; |
| 2815 | } | 2816 | } |
| 2816 | | 2817 | |
| 2817 | IrInstruction *ir_gen_fn(CodeGen *codegn, FnTableEntry *fn_entry) { | 2818 | IrInstruction *ir_gen_fn(CodeGen *codegen, FnTableEntry *fn_entry) { |
| 2818 | assert(fn_entry); | 2819 | assert(fn_entry); |
| 2819 | | 2820 | |
| 2820 | IrExecutable *ir_executable = &fn_entry->ir_executable; | 2821 | IrExecutable *ir_executable = &fn_entry->ir_executable; |
| ... | @@ -2826,18 +2827,30 @@ IrInstruction *ir_gen_fn(CodeGen *codegn, FnTableEntry *fn_entry) { | ... | @@ -2826,18 +2827,30 @@ IrInstruction *ir_gen_fn(CodeGen *codegn, FnTableEntry *fn_entry) { |
| 2826 | assert(fn_entry->child_scope); | 2827 | assert(fn_entry->child_scope); |
| 2827 | Scope *child_scope = fn_entry->child_scope; | 2828 | Scope *child_scope = fn_entry->child_scope; |
| 2828 | | 2829 | |
| 2829 | return ir_gen(codegn, body_node, child_scope, ir_executable); | 2830 | return ir_gen(codegen, body_node, child_scope, ir_executable); |
| 2830 | } | 2831 | } |
| 2831 | | 2832 | |
| 2832 | static ErrorMsg *ir_add_error(IrAnalyze *ira, IrInstruction *source_instruction, Buf *msg) { | 2833 | static ErrorMsg *ir_add_error(IrAnalyze *ira, IrInstruction *source_instruction, Buf *msg) { |
| | 2834 | ira->new_irb.exec->invalid = true; |
| 2833 | return add_node_error(ira->codegen, source_instruction->source_node, msg); | 2835 | return add_node_error(ira->codegen, source_instruction->source_node, msg); |
| 2834 | } | 2836 | } |
| 2835 | | 2837 | |
| 2836 | static IrInstruction *ir_eval_fn(IrAnalyze *ira, IrInstruction *source_instruction, | 2838 | static IrInstruction *ir_exec_const_result(IrExecutable *exec) { |
| 2837 | size_t arg_count, IrInstruction **args) | 2839 | if (exec->basic_block_list.length != 1) |
| 2838 | { | 2840 | return nullptr; |
| 2839 | // TODO count this as part of the backward branch quota | 2841 | |
| 2840 | zig_panic("TODO ir_eval_fn"); | 2842 | IrBasicBlock *bb = exec->basic_block_list.at(0); |
| | 2843 | if (bb->instruction_list.length != 1) |
| | 2844 | return nullptr; |
| | 2845 | |
| | 2846 | IrInstruction *only_inst = bb->instruction_list.at(0); |
| | 2847 | if (only_inst->id != IrInstructionIdReturn) |
| | 2848 | return nullptr; |
| | 2849 | |
| | 2850 | IrInstructionReturn *ret_inst = (IrInstructionReturn *)only_inst; |
| | 2851 | IrInstruction *value = ret_inst->value; |
| | 2852 | assert(value->static_value.special != ConstValSpecialRuntime); |
| | 2853 | return value; |
| 2841 | } | 2854 | } |
| 2842 | | 2855 | |
| 2843 | static bool ir_emit_global_runtime_side_effect(IrAnalyze *ira, IrInstruction *source_instruction) { | 2856 | static bool ir_emit_global_runtime_side_effect(IrAnalyze *ira, IrInstruction *source_instruction) { |
| ... | @@ -3140,14 +3153,26 @@ static TypeTableEntry *ir_unreach_error(IrAnalyze *ira) { | ... | @@ -3140,14 +3153,26 @@ static TypeTableEntry *ir_unreach_error(IrAnalyze *ira) { |
| 3140 | return ira->codegen->builtin_types.entry_unreachable; | 3153 | return ira->codegen->builtin_types.entry_unreachable; |
| 3141 | } | 3154 | } |
| 3142 | | 3155 | |
| | 3156 | static bool ir_emit_backward_branch(IrAnalyze *ira, IrInstruction *source_instruction) { |
| | 3157 | size_t *bbc = ira->new_irb.exec->backward_branch_count; |
| | 3158 | size_t quota = ira->new_irb.exec->backward_branch_quota; |
| | 3159 | |
| | 3160 | // If we're already over quota, we've already given an error message for this. |
| | 3161 | if (*bbc > quota) |
| | 3162 | return false; |
| | 3163 | |
| | 3164 | *bbc += 1; |
| | 3165 | if (*bbc > quota) { |
| | 3166 | ir_add_error(ira, source_instruction, buf_sprintf("evaluation exceeded %zu backwards branches", quota)); |
| | 3167 | return false; |
| | 3168 | } |
| | 3169 | return true; |
| | 3170 | } |
| | 3171 | |
| 3143 | static TypeTableEntry *ir_inline_bb(IrAnalyze *ira, IrInstruction *source_instruction, IrBasicBlock *old_bb) { | 3172 | static TypeTableEntry *ir_inline_bb(IrAnalyze *ira, IrInstruction *source_instruction, IrBasicBlock *old_bb) { |
| 3144 | if (old_bb->debug_id <= ira->old_irb.current_basic_block->debug_id) { | 3173 | if (old_bb->debug_id <= ira->old_irb.current_basic_block->debug_id) { |
| 3145 | ira->new_irb.exec->backward_branch_count += 1; | 3174 | if (!ir_emit_backward_branch(ira, source_instruction)) |
| 3146 | if (ira->new_irb.exec->backward_branch_count > ira->new_irb.exec->backward_branch_quota) { | | |
| 3147 | add_node_error(ira->codegen, source_instruction->source_node, | | |
| 3148 | buf_sprintf("evaluation exceeded %zu backwards branches", ira->new_irb.exec->backward_branch_quota)); | | |
| 3149 | return ir_unreach_error(ira); | 3175 | return ir_unreach_error(ira); |
| 3150 | } | | |
| 3151 | } | 3176 | } |
| 3152 | | 3177 | |
| 3153 | ir_start_bb(ira, old_bb, ira->old_irb.current_basic_block); | 3178 | ir_start_bb(ira, old_bb, ira->old_irb.current_basic_block); |
| ... | @@ -3216,13 +3241,90 @@ static TypeTableEntry *ir_analyze_const_usize(IrAnalyze *ira, IrInstruction *ins | ... | @@ -3216,13 +3241,90 @@ static TypeTableEntry *ir_analyze_const_usize(IrAnalyze *ira, IrInstruction *ins |
| 3216 | | 3241 | |
| 3217 | static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value) { | 3242 | static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value) { |
| 3218 | if (value->static_value.special != ConstValSpecialStatic) { | 3243 | if (value->static_value.special != ConstValSpecialStatic) { |
| 3219 | add_node_error(ira->codegen, value->source_node, | 3244 | ir_add_error(ira, value, buf_sprintf("unable to evaluate constant expression")); |
| 3220 | buf_sprintf("unable to evaluate constant expression")); | | |
| 3221 | return nullptr; | 3245 | return nullptr; |
| 3222 | } | 3246 | } |
| 3223 | return &value->static_value; | 3247 | return &value->static_value; |
| 3224 | } | 3248 | } |
| 3225 | | 3249 | |
| | 3250 | IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node, |
| | 3251 | TypeTableEntry *expected_type, size_t *backward_branch_count, size_t backward_branch_quota) |
| | 3252 | { |
| | 3253 | IrExecutable ir_executable = {0}; |
| | 3254 | ir_executable.is_inline = true; |
| | 3255 | ir_gen(codegen, node, scope, &ir_executable); |
| | 3256 | |
| | 3257 | if (ir_executable.invalid) |
| | 3258 | return codegen->invalid_instruction; |
| | 3259 | |
| | 3260 | if (codegen->verbose) { |
| | 3261 | fprintf(stderr, "\nSource: "); |
| | 3262 | ast_render(stderr, node, 4); |
| | 3263 | fprintf(stderr, "\n{ // (IR)\n"); |
| | 3264 | ir_print(stderr, &ir_executable, 4); |
| | 3265 | fprintf(stderr, "}\n"); |
| | 3266 | } |
| | 3267 | IrExecutable analyzed_executable = {0}; |
| | 3268 | analyzed_executable.is_inline = true; |
| | 3269 | analyzed_executable.backward_branch_count = backward_branch_count; |
| | 3270 | analyzed_executable.backward_branch_quota = backward_branch_quota; |
| | 3271 | TypeTableEntry *result_type = ir_analyze(codegen, &ir_executable, &analyzed_executable, expected_type, node); |
| | 3272 | if (result_type->id == TypeTableEntryIdInvalid) |
| | 3273 | return codegen->invalid_instruction; |
| | 3274 | |
| | 3275 | if (codegen->verbose) { |
| | 3276 | fprintf(stderr, "{ // (analyzed)\n"); |
| | 3277 | ir_print(stderr, &analyzed_executable, 4); |
| | 3278 | fprintf(stderr, "}\n"); |
| | 3279 | } |
| | 3280 | |
| | 3281 | IrInstruction *result = ir_exec_const_result(&analyzed_executable); |
| | 3282 | if (!result) { |
| | 3283 | add_node_error(codegen, node, buf_sprintf("unable to evaluate constant expression")); |
| | 3284 | return codegen->invalid_instruction; |
| | 3285 | } |
| | 3286 | |
| | 3287 | return result; |
| | 3288 | } |
| | 3289 | |
| | 3290 | static IrInstruction *ir_eval_fn(IrAnalyze *ira, IrInstruction *source_instruction, |
| | 3291 | FnTableEntry *fn_entry, IrInstruction **args) |
| | 3292 | { |
| | 3293 | if (!fn_entry) { |
| | 3294 | ir_add_error(ira, source_instruction, |
| | 3295 | buf_sprintf("unable to evaluate constant expression")); |
| | 3296 | return ira->codegen->invalid_instruction; |
| | 3297 | } |
| | 3298 | |
| | 3299 | if (!ir_emit_backward_branch(ira, source_instruction)) |
| | 3300 | return ira->codegen->invalid_instruction; |
| | 3301 | |
| | 3302 | TypeTableEntry *fn_type = fn_entry->type_entry; |
| | 3303 | FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id; |
| | 3304 | |
| | 3305 | // Fork a scope of the function with known values for the parameters. |
| | 3306 | |
| | 3307 | Scope *exec_scope = &fn_entry->fndef_scope->base; |
| | 3308 | for (size_t i = 0; i < fn_type_id->param_count; i += 1) { |
| | 3309 | AstNode *param_decl_node = fn_entry->proto_node->data.fn_proto.params.at(i); |
| | 3310 | Buf *param_name = param_decl_node->data.param_decl.name; |
| | 3311 | IrInstruction *arg = args[i]; |
| | 3312 | ConstExprValue *arg_val = ir_resolve_const(ira, arg); |
| | 3313 | if (!arg_val) |
| | 3314 | return ira->codegen->invalid_instruction; |
| | 3315 | |
| | 3316 | VariableTableEntry *var = add_variable(ira->codegen, param_decl_node, exec_scope, param_name, |
| | 3317 | arg->type_entry, true, arg_val); |
| | 3318 | exec_scope = var->child_scope; |
| | 3319 | } |
| | 3320 | |
| | 3321 | // Analyze the fn body block like any other constant expression. |
| | 3322 | |
| | 3323 | AstNode *body_node = fn_entry->fn_def_node->data.fn_def.body; |
| | 3324 | return ir_eval_const_value(ira->codegen, exec_scope, body_node, fn_type_id->return_type, |
| | 3325 | ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota); |
| | 3326 | } |
| | 3327 | |
| 3226 | static TypeTableEntry *ir_resolve_type_lval(IrAnalyze *ira, IrInstruction *type_value, LValPurpose lval) { | 3328 | static TypeTableEntry *ir_resolve_type_lval(IrAnalyze *ira, IrInstruction *type_value, LValPurpose lval) { |
| 3227 | if (lval != LValPurposeNone) | 3329 | if (lval != LValPurposeNone) |
| 3228 | zig_panic("TODO"); | 3330 | zig_panic("TODO"); |
| ... | @@ -4238,7 +4340,8 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal | ... | @@ -4238,7 +4340,8 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal |
| 4238 | return ira->codegen->builtin_types.entry_invalid; | 4340 | return ira->codegen->builtin_types.entry_invalid; |
| 4239 | | 4341 | |
| 4240 | if (is_inline) { | 4342 | if (is_inline) { |
| 4241 | IrInstruction *result = ir_eval_fn(ira, &call_instruction->base, call_param_count, casted_args); | 4343 | assert(call_param_count == fn_type_id->param_count); |
| | 4344 | IrInstruction *result = ir_eval_fn(ira, &call_instruction->base, fn_entry, casted_args); |
| 4242 | if (result->type_entry->id == TypeTableEntryIdInvalid) | 4345 | if (result->type_entry->id == TypeTableEntryIdInvalid) |
| 4243 | return ira->codegen->builtin_types.entry_invalid; | 4346 | return ira->codegen->builtin_types.entry_invalid; |
| 4244 | | 4347 | |
| ... | @@ -4252,9 +4355,9 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal | ... | @@ -4252,9 +4355,9 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal |
| 4252 | fn_entry, fn_ref, call_param_count, casted_args); | 4355 | fn_entry, fn_ref, call_param_count, casted_args); |
| 4253 | | 4356 | |
| 4254 | if (type_has_bits(return_type) && handle_is_ptr(return_type)) { | 4357 | if (type_has_bits(return_type) && handle_is_ptr(return_type)) { |
| 4255 | FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec); | 4358 | FnTableEntry *owner_fn = exec_fn_entry(ira->new_irb.exec); |
| 4256 | assert(fn_entry); | 4359 | assert(owner_fn); |
| 4257 | fn_entry->alloca_list.append(new_call_instruction); | 4360 | owner_fn->alloca_list.append(new_call_instruction); |
| 4258 | } | 4361 | } |
| 4259 | | 4362 | |
| 4260 | return ir_finish_anal(ira, return_type); | 4363 | return ir_finish_anal(ira, return_type); |
| ... | @@ -4782,13 +4885,13 @@ static TypeTableEntry *ir_analyze_var_ptr(IrAnalyze *ira, IrInstruction *instruc | ... | @@ -4782,13 +4885,13 @@ static TypeTableEntry *ir_analyze_var_ptr(IrAnalyze *ira, IrInstruction *instruc |
| 4782 | | 4885 | |
| 4783 | ConstExprValue *mem_slot = nullptr; | 4886 | ConstExprValue *mem_slot = nullptr; |
| 4784 | FnTableEntry *fn_entry = scope_fn_entry(var->parent_scope); | 4887 | FnTableEntry *fn_entry = scope_fn_entry(var->parent_scope); |
| 4785 | if (fn_entry) { | 4888 | if (var->src_is_const && var->value) { |
| | 4889 | mem_slot = var->value; |
| | 4890 | assert(mem_slot->special != ConstValSpecialRuntime); |
| | 4891 | } else if (fn_entry) { |
| 4786 | // TODO once the analyze code is fully ported over to IR we won't need this SIZE_MAX thing. | 4892 | // TODO once the analyze code is fully ported over to IR we won't need this SIZE_MAX thing. |
| 4787 | if (var->mem_slot_index != SIZE_MAX) | 4893 | if (var->mem_slot_index != SIZE_MAX) |
| 4788 | mem_slot = &ira->exec_context.mem_slot_list[var->mem_slot_index]; | 4894 | mem_slot = &ira->exec_context.mem_slot_list[var->mem_slot_index]; |
| 4789 | } else if (var->src_is_const) { | | |
| 4790 | mem_slot = var->value; | | |
| 4791 | assert(mem_slot->special != ConstValSpecialRuntime); | | |
| 4792 | } | 4895 | } |
| 4793 | | 4896 | |
| 4794 | if (mem_slot && mem_slot->special != ConstValSpecialRuntime) { | 4897 | if (mem_slot && mem_slot->special != ConstValSpecialRuntime) { |
| ... | @@ -6481,24 +6584,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { | ... | @@ -6481,24 +6584,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 6481 | zig_unreachable(); | 6584 | zig_unreachable(); |
| 6482 | } | 6585 | } |
| 6483 | | 6586 | |
| 6484 | IrInstruction *ir_exec_const_result(IrExecutable *exec) { | | |
| 6485 | if (exec->basic_block_list.length != 1) | | |
| 6486 | return nullptr; | | |
| 6487 | | | |
| 6488 | IrBasicBlock *bb = exec->basic_block_list.at(0); | | |
| 6489 | if (bb->instruction_list.length != 1) | | |
| 6490 | return nullptr; | | |
| 6491 | | | |
| 6492 | IrInstruction *only_inst = bb->instruction_list.at(0); | | |
| 6493 | if (only_inst->id != IrInstructionIdReturn) | | |
| 6494 | return nullptr; | | |
| 6495 | | | |
| 6496 | IrInstructionReturn *ret_inst = (IrInstructionReturn *)only_inst; | | |
| 6497 | IrInstruction *value = ret_inst->value; | | |
| 6498 | assert(value->static_value.special != ConstValSpecialRuntime); | | |
| 6499 | return value; | | |
| 6500 | } | | |
| 6501 | | | |
| 6502 | // TODO port over all this commented out code into new IR way of doing things | 6587 | // TODO port over all this commented out code into new IR way of doing things |
| 6503 | | 6588 | |
| 6504 | //static TypeTableEntry *analyze_min_max_value(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 6589 | //static TypeTableEntry *analyze_min_max_value(CodeGen *g, ImportTableEntry *import, BlockContext *context, |