authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-12-05 01:08:17-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-12-05 01:08:17-05:00
log363606d87b3f45c7f62969f85062e2a7b1b4b5dc
treef530fc69be3905eb8577f6d8ff77c226ac07e371
parent25a89e7a362ab4876139fad7427a2193665cb042

IR: inline function evaluation works on generic functions


3 files changed, 100 insertions(+), 65 deletions(-)

src/analyze.cpp+14-1
......@@ -878,7 +878,7 @@ static IrInstruction *analyze_const_value(CodeGen *g, Scope *scope, AstNode *nod
878878 return ir_eval_const_value(g, scope, node, type_entry, &backward_branch_count, default_backward_branch_quota);
879879}
880880
881static TypeTableEntry *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node) {
881TypeTableEntry *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node) {
882882 IrInstruction *result = analyze_const_value(g, scope, node, g->builtin_types.entry_type);
883883 if (result->type_entry->id == TypeTableEntryIdInvalid)
884884 return g->builtin_types.entry_invalid;
......@@ -889,6 +889,19 @@ static TypeTableEntry *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node
889889
890890static TypeTableEntry *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
891891 TypeTableEntry *fn_type = new_type_table_entry(TypeTableEntryIdFn);
892 buf_init_from_str(&fn_type->name, "fn(");
893 size_t i = 0;
894 for (; i < fn_type_id->next_param_index; i += 1) {
895 const char *comma_str = (i == 0) ? "" : ",";
896 buf_appendf(&fn_type->name, "%s%s", comma_str,
897 buf_ptr(&fn_type_id->param_info[i].type->name));
898 }
899 for (; i < fn_type_id->param_count; i += 1) {
900 const char *comma_str = (i == 0) ? "" : ",";
901 buf_appendf(&fn_type->name, "%svar", comma_str);
902 }
903 buf_appendf(&fn_type->name, ")->var");
904
892905 fn_type->data.fn.fn_type_id = *fn_type_id;
893906 fn_type->data.fn.is_generic = true;
894907 return fn_type;
src/analyze.hpp+1
......@@ -69,6 +69,7 @@ void init_tld(Tld *tld, TldId id, Buf *name, VisibMod visib_mod, AstNode *source
6969 Scope *parent_scope, Tld *parent_tld);
7070VariableTableEntry *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf *name,
7171 TypeTableEntry *type_entry, bool is_const, ConstExprValue *init_value);
72TypeTableEntry *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node);
7273
7374Scope *create_block_scope(AstNode *node, Scope *parent);
7475Scope *create_defer_scope(AstNode *node, Scope *parent);
src/ir.cpp+85-64
......@@ -2119,7 +2119,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
21192119 child_scope = elem_var->child_scope;
21202120
21212121 IrInstruction *undefined_value = ir_build_const_undefined(irb, child_scope, elem_node);
2122 ir_build_var_decl(irb, child_scope, elem_node, elem_var, elem_var_type, undefined_value);
2122 ir_build_var_decl(irb, child_scope, elem_node, elem_var, elem_var_type, undefined_value);
21232123 IrInstruction *elem_var_ptr = ir_build_var_ptr(irb, child_scope, node, elem_var);
21242124
21252125 AstNode *index_var_source_node;
......@@ -2137,7 +2137,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
21372137 IrInstruction *usize = ir_build_const_type(irb, child_scope, node, irb->codegen->builtin_types.entry_usize);
21382138 IrInstruction *zero = ir_build_const_usize(irb, child_scope, node, 0);
21392139 IrInstruction *one = ir_build_const_usize(irb, child_scope, node, 1);
2140 ir_build_var_decl(irb, child_scope, index_var_source_node, index_var, usize, zero);
2140 ir_build_var_decl(irb, child_scope, index_var_source_node, index_var, usize, zero);
21412141 IrInstruction *index_ptr = ir_build_var_ptr(irb, child_scope, node, index_var);
21422142
21432143
......@@ -2347,7 +2347,7 @@ static IrInstruction *ir_gen_if_var_expr(IrBuilder *irb, Scope *scope, AstNode *
23472347
23482348 IrInstruction *var_ptr_value = ir_build_unwrap_maybe(irb, scope, node, expr_value, false);
23492349 IrInstruction *var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, scope, node, var_ptr_value);
2350 ir_build_var_decl(irb, scope, node, var, var_type, var_value);
2350 ir_build_var_decl(irb, scope, node, var, var_type, var_value);
23512351 IrInstruction *then_expr_result = ir_gen_node(irb, then_node, var->child_scope);
23522352 if (then_expr_result == irb->codegen->invalid_instruction)
23532353 return then_expr_result;
......@@ -2405,7 +2405,7 @@ static bool ir_gen_switch_prong_expr(IrBuilder *irb, Scope *scope, AstNode *swit
24052405 var_value = var_is_ptr ? target_value_ptr : ir_build_load_ptr(irb, scope, var_symbol_node, target_value_ptr);
24062406 }
24072407 IrInstruction *var_type = nullptr; // infer the type
2408 ir_build_var_decl(irb, scope, var_symbol_node, var, var_type, var_value);
2408 ir_build_var_decl(irb, scope, var_symbol_node, var, var_type, var_value);
24092409 } else {
24102410 child_scope = scope;
24112411 }
......@@ -3287,44 +3287,6 @@ IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node
32873287 return result;
32883288}
32893289
3290static 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
33283290static TypeTableEntry *ir_resolve_type_lval(IrAnalyze *ira, IrInstruction *type_value, LValPurpose lval) {
33293291 if (lval != LValPurposeNone)
33303292 zig_panic("TODO");
......@@ -4257,6 +4219,33 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
42574219 return ira->codegen->builtin_types.entry_void;
42584220}
42594221
4222static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node,
4223 IrInstruction *arg, Scope **exec_scope, size_t *next_arg_index)
4224{
4225 AstNode *param_decl_node = fn_proto_node->data.fn_proto.params.at(*next_arg_index);
4226 assert(param_decl_node->type == NodeTypeParamDecl);
4227 AstNode *param_type_node = param_decl_node->data.param_decl.type;
4228 TypeTableEntry *param_type = analyze_type_expr(ira->codegen, *exec_scope, param_type_node);
4229 if (param_type->id == TypeTableEntryIdInvalid)
4230 return false;
4231
4232 IrInstruction *casted_arg = ir_get_casted_value(ira, arg, param_type);
4233 if (casted_arg->type_entry->id == TypeTableEntryIdInvalid)
4234 return false;
4235
4236 ConstExprValue *first_arg_val = ir_resolve_const(ira, casted_arg);
4237 if (!first_arg_val)
4238 return false;
4239
4240 Buf *param_name = param_decl_node->data.param_decl.name;
4241 VariableTableEntry *var = add_variable(ira->codegen, param_decl_node,
4242 *exec_scope, param_name, param_type, true, first_arg_val);
4243 *exec_scope = var->child_scope;
4244 *next_arg_index += 1;
4245
4246 return true;
4247}
4248
42604249static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call_instruction,
42614250 FnTableEntry *fn_entry, TypeTableEntry *fn_type, IrInstruction *fn_ref,
42624251 IrInstruction *first_arg_ptr, bool is_inline)
......@@ -4289,8 +4278,58 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
42894278 return ira->codegen->builtin_types.entry_invalid;
42904279 }
42914280
4281 if (is_inline) {
4282 if (!fn_entry) {
4283 ir_add_error(ira, fn_ref, buf_sprintf("unable to evaluate constant expression"));
4284 return ira->codegen->builtin_types.entry_invalid;
4285 }
4286
4287 if (!ir_emit_backward_branch(ira, &call_instruction->base))
4288 return ira->codegen->builtin_types.entry_invalid;
4289
4290 // Fork a scope of the function with known values for the parameters.
4291 Scope *exec_scope = &fn_entry->fndef_scope->base;
4292
4293 size_t next_arg_index = 0;
4294 if (first_arg_ptr) {
4295 IrInstruction *first_arg = ir_get_deref(ira, first_arg_ptr, first_arg_ptr);
4296 if (first_arg->type_entry->id == TypeTableEntryIdInvalid)
4297 return ira->codegen->builtin_types.entry_invalid;
4298
4299 if (!ir_analyze_fn_call_inline_arg(ira, fn_proto_node, first_arg, &exec_scope, &next_arg_index))
4300 return ira->codegen->builtin_types.entry_invalid;
4301 }
4302
4303 for (size_t call_i = 0; call_i < call_instruction->arg_count; call_i += 1) {
4304 IrInstruction *old_arg = call_instruction->args[call_i]->other;
4305 if (old_arg->type_entry->id == TypeTableEntryIdInvalid)
4306 return ira->codegen->builtin_types.entry_invalid;
4307
4308 if (!ir_analyze_fn_call_inline_arg(ira, fn_proto_node, old_arg, &exec_scope, &next_arg_index))
4309 return ira->codegen->builtin_types.entry_invalid;
4310 }
4311
4312 AstNode *return_type_node = fn_proto_node->data.fn_proto.return_type;
4313 TypeTableEntry *return_type = analyze_type_expr(ira->codegen, exec_scope, return_type_node);
4314 if (return_type->id == TypeTableEntryIdInvalid)
4315 return ira->codegen->builtin_types.entry_invalid;
4316
4317 // Analyze the fn body block like any other constant expression.
4318 AstNode *body_node = fn_entry->fn_def_node->data.fn_def.body;
4319 IrInstruction *result = ir_eval_const_value(ira->codegen, exec_scope, body_node, return_type,
4320 ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota);
4321 if (result->type_entry->id == TypeTableEntryIdInvalid)
4322 return ira->codegen->builtin_types.entry_invalid;
4323
4324 ConstExprValue *out_val = ir_build_const_from(ira, &call_instruction->base,
4325 result->static_value.depends_on_compile_var);
4326 *out_val = result->static_value;
4327 return ir_finish_anal(ira, return_type);
4328 }
4329
42924330 IrInstruction **casted_args = allocate<IrInstruction *>(call_param_count);
42934331 size_t next_arg_index = 0;
4332
42944333 if (first_arg_ptr) {
42954334 IrInstruction *first_arg = ir_get_deref(ira, first_arg_ptr, first_arg_ptr);
42964335 if (first_arg->type_entry->id == TypeTableEntryIdInvalid)
......@@ -4304,9 +4343,6 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
43044343 if (casted_arg->type_entry->id == TypeTableEntryIdInvalid)
43054344 return ira->codegen->builtin_types.entry_invalid;
43064345
4307 if (is_inline && !ir_resolve_const(ira, casted_arg))
4308 return ira->codegen->builtin_types.entry_invalid;
4309
43104346 casted_args[next_arg_index] = casted_arg;
43114347 next_arg_index += 1;
43124348 }
......@@ -4326,9 +4362,6 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
43264362 casted_arg = old_arg;
43274363 }
43284364
4329 if (is_inline && !ir_resolve_const(ira, casted_arg))
4330 return ira->codegen->builtin_types.entry_invalid;
4331
43324365 casted_args[next_arg_index] = casted_arg;
43334366 next_arg_index += 1;
43344367 }
......@@ -4339,25 +4372,13 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
43394372 if (return_type->id == TypeTableEntryIdInvalid)
43404373 return ira->codegen->builtin_types.entry_invalid;
43414374
4342 if (is_inline) {
4343 assert(call_param_count == fn_type_id->param_count);
4344 IrInstruction *result = ir_eval_fn(ira, &call_instruction->base, fn_entry, casted_args);
4345 if (result->type_entry->id == TypeTableEntryIdInvalid)
4346 return ira->codegen->builtin_types.entry_invalid;
4347
4348 ConstExprValue *out_val = ir_build_const_from(ira, &call_instruction->base,
4349 result->static_value.depends_on_compile_var);
4350 *out_val = result->static_value;
4351 return ir_finish_anal(ira, return_type);
4352 }
4353
43544375 IrInstruction *new_call_instruction = ir_build_call_from(&ira->new_irb, &call_instruction->base,
43554376 fn_entry, fn_ref, call_param_count, casted_args);
43564377
43574378 if (type_has_bits(return_type) && handle_is_ptr(return_type)) {
4358 FnTableEntry *owner_fn = exec_fn_entry(ira->new_irb.exec);
4359 assert(owner_fn);
4360 owner_fn->alloca_list.append(new_call_instruction);
4379 FnTableEntry *callsite_fn = exec_fn_entry(ira->new_irb.exec);
4380 assert(callsite_fn);
4381 callsite_fn->alloca_list.append(new_call_instruction);
43614382 }
43624383
43634384 return ir_finish_anal(ira, return_type);
......@@ -5349,7 +5370,7 @@ static TypeTableEntry *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructi
53495370 case TypeTableEntryIdTypeDecl:
53505371 {
53515372 ConstExprValue *out_val = ir_build_const_from(ira, &typeof_instruction->base, false);
5352 // TODO depends_on_compile_var should be set based on whether the type of the expression
5373 // TODO depends_on_compile_var should be set based on whether the type of the expression
53535374 // depends_on_compile_var. but we currently don't have a thing to tell us if the type of
53545375 // something depends on a compile var
53555376 out_val->data.x_type = type_entry;