authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-03-09 16:13:38-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-03-09 16:13:38-05:00
logc62db5721c1bf3a4f5a469c7ae0ded7c84008c81
tree70aa2d2949eb1c626f60bb5dc3fdc27e44aeee8e
parent558ae2f21a49ae5d75d1836cf86dbe4250d5fdbe

support passing var args directly

See #77

2 files changed, 116 insertions(+), 66 deletions(-)

src/ir.cpp+104-66
......@@ -790,16 +790,6 @@ static IrInstruction *ir_build_var_ptr(IrBuilder *irb, Scope *scope, AstNode *so
790790 return &instruction->base;
791791}
792792
793static IrInstruction *ir_build_var_ptr_from(IrBuilder *irb, IrInstruction *old_instruction,
794 VariableTableEntry *var, bool is_const, bool is_volatile)
795{
796 IrInstruction *new_instruction = ir_build_var_ptr(irb, old_instruction->scope,
797 old_instruction->source_node, var, is_const, is_volatile);
798 ir_link_new_instruction(new_instruction, old_instruction);
799 return new_instruction;
800
801}
802
803793static IrInstruction *ir_build_elem_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *array_ptr,
804794 IrInstruction *elem_index, bool safety_check_on)
805795{
......@@ -8048,6 +8038,65 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod
80488038 return true;
80498039}
80508040
8041static VariableTableEntry *get_fn_var_by_index(FnTableEntry *fn_entry, size_t index) {
8042 size_t next_var_i = 0;
8043 FnGenParamInfo *gen_param_info = fn_entry->type_entry->data.fn.gen_param_info;
8044 for (size_t param_i = 0; param_i < index; param_i += 1) {
8045 FnGenParamInfo *info = &gen_param_info[param_i];
8046 if (info->gen_index == SIZE_MAX)
8047 continue;
8048
8049 next_var_i += 1;
8050 }
8051 FnGenParamInfo *info = &gen_param_info[index];
8052 if (info->gen_index == SIZE_MAX)
8053 return nullptr;
8054
8055 return fn_entry->variable_list.at(next_var_i);
8056}
8057
8058static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
8059 VariableTableEntry *var, bool is_const_ptr, bool is_volatile_ptr)
8060{
8061 assert(var->value->type);
8062 if (type_is_invalid(var->value->type))
8063 return ira->codegen->invalid_instruction;
8064
8065 bool comptime_var_mem = ir_get_var_is_comptime(var);
8066
8067 ConstExprValue *mem_slot = nullptr;
8068 FnTableEntry *fn_entry = scope_fn_entry(var->parent_scope);
8069 if (var->value->special == ConstValSpecialStatic) {
8070 mem_slot = var->value;
8071 } else if (fn_entry) {
8072 // TODO once the analyze code is fully ported over to IR we won't need this SIZE_MAX thing.
8073 if (var->mem_slot_index != SIZE_MAX && (comptime_var_mem || var->gen_is_const))
8074 mem_slot = &ira->exec_context.mem_slot_list[var->mem_slot_index];
8075 }
8076
8077 bool is_const = (var->value->type->id == TypeTableEntryIdMetaType) ? is_const_ptr : var->src_is_const;
8078 bool is_volatile = (var->value->type->id == TypeTableEntryIdMetaType) ? is_volatile_ptr : false;
8079 if (mem_slot && mem_slot->special != ConstValSpecialRuntime) {
8080 ConstPtrMut ptr_mut;
8081 if (comptime_var_mem) {
8082 ptr_mut = ConstPtrMutComptimeVar;
8083 } else if (var->gen_is_const) {
8084 ptr_mut = ConstPtrMutComptimeConst;
8085 } else {
8086 assert(!comptime_var_mem);
8087 ptr_mut = ConstPtrMutRuntimeVar;
8088 }
8089 return ir_get_const_ptr(ira, instruction, mem_slot, var->value->type,
8090 ptr_mut, is_const, is_volatile);
8091 } else {
8092 IrInstruction *var_ptr_instruction = ir_build_var_ptr(&ira->new_irb,
8093 instruction->scope, instruction->source_node, var, is_const, is_volatile);
8094 var_ptr_instruction->value.type = get_pointer_to_type(ira->codegen, var->value->type, var->src_is_const);
8095 type_ensure_zero_bits_known(ira->codegen, var->value->type);
8096 return var_ptr_instruction;
8097 }
8098}
8099
80518100static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call_instruction,
80528101 FnTableEntry *fn_entry, TypeTableEntry *fn_type, IrInstruction *fn_ref,
80538102 IrInstruction *first_arg_ptr, bool inline_fn_call)
......@@ -8149,17 +8198,31 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
81498198 if (fn_type->data.fn.is_generic) {
81508199 assert(fn_entry);
81518200
8152 IrInstruction **casted_args = allocate<IrInstruction *>(call_param_count);
8201 // Count the arguments of the function type id we are creating
8202 size_t new_fn_arg_count = 0;
8203 for (size_t call_i = 0; call_i < call_instruction->arg_count; call_i += 1) {
8204 IrInstruction *arg = call_instruction->args[call_i]->other;
8205 if (type_is_invalid(arg->value.type))
8206 return ira->codegen->builtin_types.entry_invalid;
8207
8208 if (arg->value.type->id == TypeTableEntryIdArgTuple) {
8209 new_fn_arg_count += arg->value.data.x_arg_tuple.end_index - arg->value.data.x_arg_tuple.start_index;
8210 } else {
8211 new_fn_arg_count += 1;
8212 }
8213 }
8214
8215 IrInstruction **casted_args = allocate<IrInstruction *>(new_fn_arg_count);
81538216
81548217 // Fork a scope of the function with known values for the parameters.
81558218 Scope *parent_scope = fn_entry->fndef_scope->base.parent;
81568219 FnTableEntry *impl_fn = create_fn(fn_proto_node);
8157 impl_fn->param_source_nodes = allocate<AstNode *>(call_param_count);
8220 impl_fn->param_source_nodes = allocate<AstNode *>(new_fn_arg_count);
81588221 buf_init_from_buf(&impl_fn->symbol_name, &fn_entry->symbol_name);
81598222 impl_fn->fndef_scope = create_fndef_scope(impl_fn->fn_def_node, parent_scope, impl_fn);
81608223 impl_fn->child_scope = &impl_fn->fndef_scope->base;
81618224 FnTypeId inst_fn_type_id = {0};
8162 init_fn_type_id(&inst_fn_type_id, fn_proto_node, call_param_count);
8225 init_fn_type_id(&inst_fn_type_id, fn_proto_node, new_fn_arg_count);
81638226 inst_fn_type_id.param_count = 0;
81648227 inst_fn_type_id.is_var_args = false;
81658228
......@@ -8168,7 +8231,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
81688231 GenericFnTypeId *generic_id = allocate<GenericFnTypeId>(1);
81698232 generic_id->fn_entry = fn_entry;
81708233 generic_id->param_count = 0;
8171 generic_id->params = allocate<ConstExprValue>(call_param_count);
8234 generic_id->params = allocate<ConstExprValue>(new_fn_arg_count);
81728235 size_t next_proto_i = 0;
81738236
81748237 if (first_arg_ptr) {
......@@ -8191,6 +8254,9 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
81918254
81928255 bool found_first_var_arg = false;
81938256 size_t first_var_arg = inst_fn_type_id.param_count;
8257
8258 FnTableEntry *parent_fn_entry = exec_fn_entry(ira->new_irb.exec);
8259 assert(parent_fn_entry);
81948260 for (size_t call_i = 0; call_i < call_instruction->arg_count; call_i += 1) {
81958261 IrInstruction *arg = call_instruction->args[call_i]->other;
81968262 if (type_is_invalid(arg->value.type))
......@@ -8204,7 +8270,27 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
82048270 found_first_var_arg = true;
82058271 }
82068272
8207 if (!ir_analyze_fn_call_generic_arg(ira, fn_proto_node, arg, &impl_fn->child_scope,
8273 if (arg->value.type->id == TypeTableEntryIdArgTuple) {
8274 for (size_t arg_tuple_i = arg->value.data.x_arg_tuple.start_index;
8275 arg_tuple_i < arg->value.data.x_arg_tuple.end_index; arg_tuple_i += 1)
8276 {
8277 VariableTableEntry *arg_var = get_fn_var_by_index(parent_fn_entry, arg_tuple_i);
8278 assert(arg_var != nullptr);
8279 IrInstruction *arg_var_ptr_inst = ir_get_var_ptr(ira, arg, arg_var, true, false);
8280 if (type_is_invalid(arg_var_ptr_inst->value.type))
8281 return ira->codegen->builtin_types.entry_invalid;
8282
8283 IrInstruction *arg_tuple_arg = ir_get_deref(ira, arg, arg_var_ptr_inst);
8284 if (type_is_invalid(arg_tuple_arg->value.type))
8285 return ira->codegen->builtin_types.entry_invalid;
8286
8287 if (!ir_analyze_fn_call_generic_arg(ira, fn_proto_node, arg_tuple_arg, &impl_fn->child_scope,
8288 &next_proto_i, generic_id, &inst_fn_type_id, casted_args, impl_fn))
8289 {
8290 return ira->codegen->builtin_types.entry_invalid;
8291 }
8292 }
8293 } else if (!ir_analyze_fn_call_generic_arg(ira, fn_proto_node, arg, &impl_fn->child_scope,
82088294 &next_proto_i, generic_id, &inst_fn_type_id, casted_args, impl_fn))
82098295 {
82108296 return ira->codegen->builtin_types.entry_invalid;
......@@ -8769,40 +8855,9 @@ static TypeTableEntry *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionP
87698855static TypeTableEntry *ir_analyze_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
87708856 VariableTableEntry *var, bool is_const_ptr, bool is_volatile_ptr)
87718857{
8772 assert(var->value->type);
8773 if (type_is_invalid(var->value->type))
8774 return var->value->type;
8775
8776 bool comptime_var_mem = ir_get_var_is_comptime(var);
8777
8778 ConstExprValue *mem_slot = nullptr;
8779 FnTableEntry *fn_entry = scope_fn_entry(var->parent_scope);
8780 if (var->value->special == ConstValSpecialStatic) {
8781 mem_slot = var->value;
8782 } else if (fn_entry) {
8783 // TODO once the analyze code is fully ported over to IR we won't need this SIZE_MAX thing.
8784 if (var->mem_slot_index != SIZE_MAX && (comptime_var_mem || var->gen_is_const))
8785 mem_slot = &ira->exec_context.mem_slot_list[var->mem_slot_index];
8786 }
8787
8788 bool is_const = (var->value->type->id == TypeTableEntryIdMetaType) ? is_const_ptr : var->src_is_const;
8789 bool is_volatile = (var->value->type->id == TypeTableEntryIdMetaType) ? is_volatile_ptr : false;
8790 if (mem_slot && mem_slot->special != ConstValSpecialRuntime) {
8791 ConstPtrMut ptr_mut;
8792 if (comptime_var_mem) {
8793 ptr_mut = ConstPtrMutComptimeVar;
8794 } else if (var->gen_is_const) {
8795 ptr_mut = ConstPtrMutComptimeConst;
8796 } else {
8797 assert(!comptime_var_mem);
8798 ptr_mut = ConstPtrMutRuntimeVar;
8799 }
8800 return ir_analyze_const_ptr(ira, instruction, mem_slot, var->value->type, ptr_mut, is_const, is_volatile);
8801 } else {
8802 ir_build_var_ptr_from(&ira->new_irb, instruction, var, is_const, is_volatile);
8803 type_ensure_zero_bits_known(ira->codegen, var->value->type);
8804 return get_pointer_to_type(ira->codegen, var->value->type, var->src_is_const);
8805 }
8858 IrInstruction *result = ir_get_var_ptr(ira, instruction, var, is_const_ptr, is_volatile_ptr);
8859 ir_link_new_instruction(result, instruction);
8860 return result->value.type;
88068861}
88078862
88088863static TypeTableEntry *ir_analyze_instruction_var_ptr(IrAnalyze *ira, IrInstructionVarPtr *var_ptr_instruction) {
......@@ -8811,23 +8866,6 @@ static TypeTableEntry *ir_analyze_instruction_var_ptr(IrAnalyze *ira, IrInstruct
88118866 var_ptr_instruction->is_volatile);
88128867}
88138868
8814static VariableTableEntry *get_fn_var_by_index(FnTableEntry *fn_entry, size_t index) {
8815 size_t next_var_i = 0;
8816 FnGenParamInfo *gen_param_info = fn_entry->type_entry->data.fn.gen_param_info;
8817 for (size_t param_i = 0; param_i < index; param_i += 1) {
8818 FnGenParamInfo *info = &gen_param_info[param_i];
8819 if (info->gen_index == SIZE_MAX)
8820 continue;
8821
8822 next_var_i += 1;
8823 }
8824 FnGenParamInfo *info = &gen_param_info[index];
8825 if (info->gen_index == SIZE_MAX)
8826 return nullptr;
8827
8828 return fn_entry->variable_list.at(next_var_i);
8829}
8830
88318869static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstructionElemPtr *elem_ptr_instruction) {
88328870 IrInstruction *array_ptr = elem_ptr_instruction->array_ptr->other;
88338871 if (type_is_invalid(array_ptr->value.type))
test/cases/var_args.zig+12
......@@ -25,3 +25,15 @@ fn sendVoidArgToVarArgs() {
2525
2626 readFirstVarArg({});
2727}
28
29fn testPassArgsDirectly() {
30 @setFnTest(this);
31
32 assert(addSomeStuff(i32(1), i32(2), i32(3), i32(4)) == 10);
33 assert(addSomeStuff(i32(1234)) == 1234);
34 assert(addSomeStuff() == 0);
35}
36
37fn addSomeStuff(args: ...) -> i32 {
38 return add(args);
39}