mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-08 23:04:24 +00:00
parent
558ae2f21a
commit
c62db5721c
2 changed files with 116 additions and 66 deletions
170
src/ir.cpp
170
src/ir.cpp
|
|
@ -790,16 +790,6 @@ static IrInstruction *ir_build_var_ptr(IrBuilder *irb, Scope *scope, AstNode *so
|
||||||
return &instruction->base;
|
return &instruction->base;
|
||||||
}
|
}
|
||||||
|
|
||||||
static IrInstruction *ir_build_var_ptr_from(IrBuilder *irb, IrInstruction *old_instruction,
|
|
||||||
VariableTableEntry *var, bool is_const, bool is_volatile)
|
|
||||||
{
|
|
||||||
IrInstruction *new_instruction = ir_build_var_ptr(irb, old_instruction->scope,
|
|
||||||
old_instruction->source_node, var, is_const, is_volatile);
|
|
||||||
ir_link_new_instruction(new_instruction, old_instruction);
|
|
||||||
return new_instruction;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static IrInstruction *ir_build_elem_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *array_ptr,
|
static IrInstruction *ir_build_elem_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *array_ptr,
|
||||||
IrInstruction *elem_index, bool safety_check_on)
|
IrInstruction *elem_index, bool safety_check_on)
|
||||||
{
|
{
|
||||||
|
|
@ -8048,6 +8038,65 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static VariableTableEntry *get_fn_var_by_index(FnTableEntry *fn_entry, size_t index) {
|
||||||
|
size_t next_var_i = 0;
|
||||||
|
FnGenParamInfo *gen_param_info = fn_entry->type_entry->data.fn.gen_param_info;
|
||||||
|
for (size_t param_i = 0; param_i < index; param_i += 1) {
|
||||||
|
FnGenParamInfo *info = &gen_param_info[param_i];
|
||||||
|
if (info->gen_index == SIZE_MAX)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
next_var_i += 1;
|
||||||
|
}
|
||||||
|
FnGenParamInfo *info = &gen_param_info[index];
|
||||||
|
if (info->gen_index == SIZE_MAX)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
return fn_entry->variable_list.at(next_var_i);
|
||||||
|
}
|
||||||
|
|
||||||
|
static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
|
||||||
|
VariableTableEntry *var, bool is_const_ptr, bool is_volatile_ptr)
|
||||||
|
{
|
||||||
|
assert(var->value->type);
|
||||||
|
if (type_is_invalid(var->value->type))
|
||||||
|
return ira->codegen->invalid_instruction;
|
||||||
|
|
||||||
|
bool comptime_var_mem = ir_get_var_is_comptime(var);
|
||||||
|
|
||||||
|
ConstExprValue *mem_slot = nullptr;
|
||||||
|
FnTableEntry *fn_entry = scope_fn_entry(var->parent_scope);
|
||||||
|
if (var->value->special == ConstValSpecialStatic) {
|
||||||
|
mem_slot = var->value;
|
||||||
|
} else if (fn_entry) {
|
||||||
|
// TODO once the analyze code is fully ported over to IR we won't need this SIZE_MAX thing.
|
||||||
|
if (var->mem_slot_index != SIZE_MAX && (comptime_var_mem || var->gen_is_const))
|
||||||
|
mem_slot = &ira->exec_context.mem_slot_list[var->mem_slot_index];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_const = (var->value->type->id == TypeTableEntryIdMetaType) ? is_const_ptr : var->src_is_const;
|
||||||
|
bool is_volatile = (var->value->type->id == TypeTableEntryIdMetaType) ? is_volatile_ptr : false;
|
||||||
|
if (mem_slot && mem_slot->special != ConstValSpecialRuntime) {
|
||||||
|
ConstPtrMut ptr_mut;
|
||||||
|
if (comptime_var_mem) {
|
||||||
|
ptr_mut = ConstPtrMutComptimeVar;
|
||||||
|
} else if (var->gen_is_const) {
|
||||||
|
ptr_mut = ConstPtrMutComptimeConst;
|
||||||
|
} else {
|
||||||
|
assert(!comptime_var_mem);
|
||||||
|
ptr_mut = ConstPtrMutRuntimeVar;
|
||||||
|
}
|
||||||
|
return ir_get_const_ptr(ira, instruction, mem_slot, var->value->type,
|
||||||
|
ptr_mut, is_const, is_volatile);
|
||||||
|
} else {
|
||||||
|
IrInstruction *var_ptr_instruction = ir_build_var_ptr(&ira->new_irb,
|
||||||
|
instruction->scope, instruction->source_node, var, is_const, is_volatile);
|
||||||
|
var_ptr_instruction->value.type = get_pointer_to_type(ira->codegen, var->value->type, var->src_is_const);
|
||||||
|
type_ensure_zero_bits_known(ira->codegen, var->value->type);
|
||||||
|
return var_ptr_instruction;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call_instruction,
|
static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call_instruction,
|
||||||
FnTableEntry *fn_entry, TypeTableEntry *fn_type, IrInstruction *fn_ref,
|
FnTableEntry *fn_entry, TypeTableEntry *fn_type, IrInstruction *fn_ref,
|
||||||
IrInstruction *first_arg_ptr, bool inline_fn_call)
|
IrInstruction *first_arg_ptr, bool inline_fn_call)
|
||||||
|
|
@ -8149,17 +8198,31 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
|
||||||
if (fn_type->data.fn.is_generic) {
|
if (fn_type->data.fn.is_generic) {
|
||||||
assert(fn_entry);
|
assert(fn_entry);
|
||||||
|
|
||||||
IrInstruction **casted_args = allocate<IrInstruction *>(call_param_count);
|
// Count the arguments of the function type id we are creating
|
||||||
|
size_t new_fn_arg_count = 0;
|
||||||
|
for (size_t call_i = 0; call_i < call_instruction->arg_count; call_i += 1) {
|
||||||
|
IrInstruction *arg = call_instruction->args[call_i]->other;
|
||||||
|
if (type_is_invalid(arg->value.type))
|
||||||
|
return ira->codegen->builtin_types.entry_invalid;
|
||||||
|
|
||||||
|
if (arg->value.type->id == TypeTableEntryIdArgTuple) {
|
||||||
|
new_fn_arg_count += arg->value.data.x_arg_tuple.end_index - arg->value.data.x_arg_tuple.start_index;
|
||||||
|
} else {
|
||||||
|
new_fn_arg_count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IrInstruction **casted_args = allocate<IrInstruction *>(new_fn_arg_count);
|
||||||
|
|
||||||
// Fork a scope of the function with known values for the parameters.
|
// Fork a scope of the function with known values for the parameters.
|
||||||
Scope *parent_scope = fn_entry->fndef_scope->base.parent;
|
Scope *parent_scope = fn_entry->fndef_scope->base.parent;
|
||||||
FnTableEntry *impl_fn = create_fn(fn_proto_node);
|
FnTableEntry *impl_fn = create_fn(fn_proto_node);
|
||||||
impl_fn->param_source_nodes = allocate<AstNode *>(call_param_count);
|
impl_fn->param_source_nodes = allocate<AstNode *>(new_fn_arg_count);
|
||||||
buf_init_from_buf(&impl_fn->symbol_name, &fn_entry->symbol_name);
|
buf_init_from_buf(&impl_fn->symbol_name, &fn_entry->symbol_name);
|
||||||
impl_fn->fndef_scope = create_fndef_scope(impl_fn->fn_def_node, parent_scope, impl_fn);
|
impl_fn->fndef_scope = create_fndef_scope(impl_fn->fn_def_node, parent_scope, impl_fn);
|
||||||
impl_fn->child_scope = &impl_fn->fndef_scope->base;
|
impl_fn->child_scope = &impl_fn->fndef_scope->base;
|
||||||
FnTypeId inst_fn_type_id = {0};
|
FnTypeId inst_fn_type_id = {0};
|
||||||
init_fn_type_id(&inst_fn_type_id, fn_proto_node, call_param_count);
|
init_fn_type_id(&inst_fn_type_id, fn_proto_node, new_fn_arg_count);
|
||||||
inst_fn_type_id.param_count = 0;
|
inst_fn_type_id.param_count = 0;
|
||||||
inst_fn_type_id.is_var_args = false;
|
inst_fn_type_id.is_var_args = false;
|
||||||
|
|
||||||
|
|
@ -8168,7 +8231,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
|
||||||
GenericFnTypeId *generic_id = allocate<GenericFnTypeId>(1);
|
GenericFnTypeId *generic_id = allocate<GenericFnTypeId>(1);
|
||||||
generic_id->fn_entry = fn_entry;
|
generic_id->fn_entry = fn_entry;
|
||||||
generic_id->param_count = 0;
|
generic_id->param_count = 0;
|
||||||
generic_id->params = allocate<ConstExprValue>(call_param_count);
|
generic_id->params = allocate<ConstExprValue>(new_fn_arg_count);
|
||||||
size_t next_proto_i = 0;
|
size_t next_proto_i = 0;
|
||||||
|
|
||||||
if (first_arg_ptr) {
|
if (first_arg_ptr) {
|
||||||
|
|
@ -8191,6 +8254,9 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
|
||||||
|
|
||||||
bool found_first_var_arg = false;
|
bool found_first_var_arg = false;
|
||||||
size_t first_var_arg = inst_fn_type_id.param_count;
|
size_t first_var_arg = inst_fn_type_id.param_count;
|
||||||
|
|
||||||
|
FnTableEntry *parent_fn_entry = exec_fn_entry(ira->new_irb.exec);
|
||||||
|
assert(parent_fn_entry);
|
||||||
for (size_t call_i = 0; call_i < call_instruction->arg_count; call_i += 1) {
|
for (size_t call_i = 0; call_i < call_instruction->arg_count; call_i += 1) {
|
||||||
IrInstruction *arg = call_instruction->args[call_i]->other;
|
IrInstruction *arg = call_instruction->args[call_i]->other;
|
||||||
if (type_is_invalid(arg->value.type))
|
if (type_is_invalid(arg->value.type))
|
||||||
|
|
@ -8204,7 +8270,27 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
|
||||||
found_first_var_arg = true;
|
found_first_var_arg = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ir_analyze_fn_call_generic_arg(ira, fn_proto_node, arg, &impl_fn->child_scope,
|
if (arg->value.type->id == TypeTableEntryIdArgTuple) {
|
||||||
|
for (size_t arg_tuple_i = arg->value.data.x_arg_tuple.start_index;
|
||||||
|
arg_tuple_i < arg->value.data.x_arg_tuple.end_index; arg_tuple_i += 1)
|
||||||
|
{
|
||||||
|
VariableTableEntry *arg_var = get_fn_var_by_index(parent_fn_entry, arg_tuple_i);
|
||||||
|
assert(arg_var != nullptr);
|
||||||
|
IrInstruction *arg_var_ptr_inst = ir_get_var_ptr(ira, arg, arg_var, true, false);
|
||||||
|
if (type_is_invalid(arg_var_ptr_inst->value.type))
|
||||||
|
return ira->codegen->builtin_types.entry_invalid;
|
||||||
|
|
||||||
|
IrInstruction *arg_tuple_arg = ir_get_deref(ira, arg, arg_var_ptr_inst);
|
||||||
|
if (type_is_invalid(arg_tuple_arg->value.type))
|
||||||
|
return ira->codegen->builtin_types.entry_invalid;
|
||||||
|
|
||||||
|
if (!ir_analyze_fn_call_generic_arg(ira, fn_proto_node, arg_tuple_arg, &impl_fn->child_scope,
|
||||||
|
&next_proto_i, generic_id, &inst_fn_type_id, casted_args, impl_fn))
|
||||||
|
{
|
||||||
|
return ira->codegen->builtin_types.entry_invalid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (!ir_analyze_fn_call_generic_arg(ira, fn_proto_node, arg, &impl_fn->child_scope,
|
||||||
&next_proto_i, generic_id, &inst_fn_type_id, casted_args, impl_fn))
|
&next_proto_i, generic_id, &inst_fn_type_id, casted_args, impl_fn))
|
||||||
{
|
{
|
||||||
return ira->codegen->builtin_types.entry_invalid;
|
return ira->codegen->builtin_types.entry_invalid;
|
||||||
|
|
@ -8769,40 +8855,9 @@ static TypeTableEntry *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionP
|
||||||
static TypeTableEntry *ir_analyze_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
|
static TypeTableEntry *ir_analyze_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
|
||||||
VariableTableEntry *var, bool is_const_ptr, bool is_volatile_ptr)
|
VariableTableEntry *var, bool is_const_ptr, bool is_volatile_ptr)
|
||||||
{
|
{
|
||||||
assert(var->value->type);
|
IrInstruction *result = ir_get_var_ptr(ira, instruction, var, is_const_ptr, is_volatile_ptr);
|
||||||
if (type_is_invalid(var->value->type))
|
ir_link_new_instruction(result, instruction);
|
||||||
return var->value->type;
|
return result->value.type;
|
||||||
|
|
||||||
bool comptime_var_mem = ir_get_var_is_comptime(var);
|
|
||||||
|
|
||||||
ConstExprValue *mem_slot = nullptr;
|
|
||||||
FnTableEntry *fn_entry = scope_fn_entry(var->parent_scope);
|
|
||||||
if (var->value->special == ConstValSpecialStatic) {
|
|
||||||
mem_slot = var->value;
|
|
||||||
} else if (fn_entry) {
|
|
||||||
// TODO once the analyze code is fully ported over to IR we won't need this SIZE_MAX thing.
|
|
||||||
if (var->mem_slot_index != SIZE_MAX && (comptime_var_mem || var->gen_is_const))
|
|
||||||
mem_slot = &ira->exec_context.mem_slot_list[var->mem_slot_index];
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_const = (var->value->type->id == TypeTableEntryIdMetaType) ? is_const_ptr : var->src_is_const;
|
|
||||||
bool is_volatile = (var->value->type->id == TypeTableEntryIdMetaType) ? is_volatile_ptr : false;
|
|
||||||
if (mem_slot && mem_slot->special != ConstValSpecialRuntime) {
|
|
||||||
ConstPtrMut ptr_mut;
|
|
||||||
if (comptime_var_mem) {
|
|
||||||
ptr_mut = ConstPtrMutComptimeVar;
|
|
||||||
} else if (var->gen_is_const) {
|
|
||||||
ptr_mut = ConstPtrMutComptimeConst;
|
|
||||||
} else {
|
|
||||||
assert(!comptime_var_mem);
|
|
||||||
ptr_mut = ConstPtrMutRuntimeVar;
|
|
||||||
}
|
|
||||||
return ir_analyze_const_ptr(ira, instruction, mem_slot, var->value->type, ptr_mut, is_const, is_volatile);
|
|
||||||
} else {
|
|
||||||
ir_build_var_ptr_from(&ira->new_irb, instruction, var, is_const, is_volatile);
|
|
||||||
type_ensure_zero_bits_known(ira->codegen, var->value->type);
|
|
||||||
return get_pointer_to_type(ira->codegen, var->value->type, var->src_is_const);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static TypeTableEntry *ir_analyze_instruction_var_ptr(IrAnalyze *ira, IrInstructionVarPtr *var_ptr_instruction) {
|
static 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
|
||||||
var_ptr_instruction->is_volatile);
|
var_ptr_instruction->is_volatile);
|
||||||
}
|
}
|
||||||
|
|
||||||
static VariableTableEntry *get_fn_var_by_index(FnTableEntry *fn_entry, size_t index) {
|
|
||||||
size_t next_var_i = 0;
|
|
||||||
FnGenParamInfo *gen_param_info = fn_entry->type_entry->data.fn.gen_param_info;
|
|
||||||
for (size_t param_i = 0; param_i < index; param_i += 1) {
|
|
||||||
FnGenParamInfo *info = &gen_param_info[param_i];
|
|
||||||
if (info->gen_index == SIZE_MAX)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
next_var_i += 1;
|
|
||||||
}
|
|
||||||
FnGenParamInfo *info = &gen_param_info[index];
|
|
||||||
if (info->gen_index == SIZE_MAX)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
return fn_entry->variable_list.at(next_var_i);
|
|
||||||
}
|
|
||||||
|
|
||||||
static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstructionElemPtr *elem_ptr_instruction) {
|
static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstructionElemPtr *elem_ptr_instruction) {
|
||||||
IrInstruction *array_ptr = elem_ptr_instruction->array_ptr->other;
|
IrInstruction *array_ptr = elem_ptr_instruction->array_ptr->other;
|
||||||
if (type_is_invalid(array_ptr->value.type))
|
if (type_is_invalid(array_ptr->value.type))
|
||||||
|
|
|
||||||
|
|
@ -25,3 +25,15 @@ fn sendVoidArgToVarArgs() {
|
||||||
|
|
||||||
readFirstVarArg({});
|
readFirstVarArg({});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn testPassArgsDirectly() {
|
||||||
|
@setFnTest(this);
|
||||||
|
|
||||||
|
assert(addSomeStuff(i32(1), i32(2), i32(3), i32(4)) == 10);
|
||||||
|
assert(addSomeStuff(i32(1234)) == 1234);
|
||||||
|
assert(addSomeStuff() == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn addSomeStuff(args: ...) -> i32 {
|
||||||
|
return add(args);
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue