aboutsummaryrefslogtreecommitdiff
path: root/src/codegen.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/codegen.cpp')
-rw-r--r--src/codegen.cpp519
1 files changed, 420 insertions, 99 deletions
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 0300ccca99..8acc7e9702 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -466,7 +466,8 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) {
}
bool external_linkage = linkage != GlobalLinkageIdInternal;
- if (fn_table_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionStdcall && external_linkage &&
+ CallingConvention cc = fn_table_entry->type_entry->data.fn.fn_type_id.cc;
+ if (cc == CallingConventionStdcall && external_linkage &&
g->zig_target.arch.arch == ZigLLVM_x86)
{
// prevent llvm name mangling
@@ -510,17 +511,17 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) {
break;
}
- if (fn_type->data.fn.fn_type_id.cc == CallingConventionNaked) {
+ if (cc == CallingConventionNaked) {
addLLVMFnAttr(fn_table_entry->llvm_value, "naked");
} else {
LLVMSetFunctionCallConv(fn_table_entry->llvm_value, get_llvm_cc(g, fn_type->data.fn.fn_type_id.cc));
}
- if (fn_type->data.fn.fn_type_id.cc == CallingConventionAsync) {
+ if (cc == CallingConventionAsync) {
addLLVMFnAttr(fn_table_entry->llvm_value, "optnone");
addLLVMFnAttr(fn_table_entry->llvm_value, "noinline");
}
- bool want_cold = fn_table_entry->is_cold || fn_type->data.fn.fn_type_id.cc == CallingConventionCold;
+ bool want_cold = fn_table_entry->is_cold || cc == CallingConventionCold;
if (want_cold) {
ZigLLVMAddFunctionAttrCold(fn_table_entry->llvm_value);
}
@@ -576,37 +577,16 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) {
// nothing to do
} else if (type_is_codegen_pointer(return_type)) {
addLLVMAttr(fn_table_entry->llvm_value, 0, "nonnull");
- } else if (handle_is_ptr(return_type) &&
- calling_convention_does_first_arg_return(fn_type->data.fn.fn_type_id.cc))
- {
+ } else if (handle_is_ptr(return_type) && calling_convention_does_first_arg_return(cc)) {
addLLVMArgAttr(fn_table_entry->llvm_value, 0, "sret");
addLLVMArgAttr(fn_table_entry->llvm_value, 0, "nonnull");
}
-
// set parameter attributes
- for (size_t param_i = 0; param_i < fn_type->data.fn.fn_type_id.param_count; param_i += 1) {
- FnGenParamInfo *gen_info = &fn_type->data.fn.gen_param_info[param_i];
- size_t gen_index = gen_info->gen_index;
- bool is_byval = gen_info->is_byval;
-
- if (gen_index == SIZE_MAX) {
- continue;
- }
-
- FnTypeParamInfo *param_info = &fn_type->data.fn.fn_type_id.param_info[param_i];
-
- ZigType *param_type = gen_info->type;
- if (param_info->is_noalias) {
- addLLVMArgAttr(fn_table_entry->llvm_value, (unsigned)gen_index, "noalias");
- }
- if ((param_type->id == ZigTypeIdPointer && param_type->data.pointer.is_const) || is_byval) {
- addLLVMArgAttr(fn_table_entry->llvm_value, (unsigned)gen_index, "readonly");
- }
- if (param_type->id == ZigTypeIdPointer) {
- addLLVMArgAttr(fn_table_entry->llvm_value, (unsigned)gen_index, "nonnull");
- }
- }
+ FnWalk fn_walk = {};
+ fn_walk.id = FnWalkIdAttrs;
+ fn_walk.data.attrs.fn = fn_table_entry;
+ walk_function_params(g, fn_type, &fn_walk);
uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn_table_entry);
if (err_ret_trace_arg_index != UINT32_MAX) {
@@ -1858,6 +1838,7 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, LLVMValueRef ptr, ZigType *ptr_ty
}
static void gen_var_debug_decl(CodeGen *g, ZigVar *var) {
+ assert(var->di_loc_var != nullptr);
AstNode *source_node = var->decl_node;
ZigLLVMDILocation *debug_loc = ZigLLVMGetDebugLoc((unsigned)source_node->line + 1,
(unsigned)source_node->column + 1, get_di_scope(g, var->parent_scope));
@@ -1888,6 +1869,381 @@ static LLVMValueRef ir_llvm_value(CodeGen *g, IrInstruction *instruction) {
return instruction->llvm_value;
}
+ATTRIBUTE_NORETURN
+static void report_errors_and_exit(CodeGen *g) {
+ assert(g->errors.length != 0);
+ for (size_t i = 0; i < g->errors.length; i += 1) {
+ ErrorMsg *err = g->errors.at(i);
+ print_err_msg(err, g->err_color);
+ }
+ exit(1);
+}
+
+static void report_errors_and_maybe_exit(CodeGen *g) {
+ if (g->errors.length != 0) {
+ report_errors_and_exit(g);
+ }
+}
+
+ATTRIBUTE_NORETURN
+static void give_up_with_c_abi_error(CodeGen *g, AstNode *source_node) {
+ ErrorMsg *msg = add_node_error(g, source_node,
+ buf_sprintf("TODO: support C ABI for more targets. https://github.com/ziglang/zig/issues/1481"));
+ add_error_note(g, msg, source_node,
+ buf_sprintf("pointers, integers, floats, bools, and enums work on all targets"));
+ report_errors_and_exit(g);
+}
+
+static bool type_is_c_abi_int(CodeGen *g, ZigType *ty) {
+ size_t ty_size = type_size(g, ty);
+ if (ty_size > g->pointer_size_bytes)
+ return false;
+ return (ty->id == ZigTypeIdInt ||
+ ty->id == ZigTypeIdFloat ||
+ ty->id == ZigTypeIdBool ||
+ ty->id == ZigTypeIdEnum ||
+ get_codegen_ptr_type(ty) != nullptr);
+}
+
+static LLVMValueRef build_alloca(CodeGen *g, ZigType *type_entry, const char *name, uint32_t alignment) {
+ assert(alignment > 0);
+ LLVMValueRef result = LLVMBuildAlloca(g->builder, type_entry->type_ref, name);
+ LLVMSetAlignment(result, alignment);
+ return result;
+}
+
+static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk, size_t src_i) {
+ // Initialized from the type for some walks, but because of C var args,
+ // initialized based on callsite instructions for that one.
+ FnTypeParamInfo *param_info = nullptr;
+ ZigType *ty;
+ ZigType *dest_ty = nullptr;
+ AstNode *source_node = nullptr;
+ LLVMValueRef val;
+ LLVMValueRef llvm_fn;
+ unsigned di_arg_index;
+ ZigVar *var;
+ switch (fn_walk->id) {
+ case FnWalkIdAttrs:
+ if (src_i >= fn_type->data.fn.fn_type_id.param_count)
+ return false;
+ param_info = &fn_type->data.fn.fn_type_id.param_info[src_i];
+ ty = param_info->type;
+ source_node = fn_walk->data.attrs.fn->proto_node;
+ llvm_fn = fn_walk->data.attrs.fn->llvm_value;
+ break;
+ case FnWalkIdCall: {
+ if (src_i >= fn_walk->data.call.inst->arg_count)
+ return false;
+ IrInstruction *arg = fn_walk->data.call.inst->args[src_i];
+ ty = arg->value.type;
+ source_node = arg->source_node;
+ val = ir_llvm_value(g, arg);
+ break;
+ }
+ case FnWalkIdTypes:
+ if (src_i >= fn_type->data.fn.fn_type_id.param_count)
+ return false;
+ param_info = &fn_type->data.fn.fn_type_id.param_info[src_i];
+ ty = param_info->type;
+ break;
+ case FnWalkIdVars:
+ assert(src_i < fn_type->data.fn.fn_type_id.param_count);
+ param_info = &fn_type->data.fn.fn_type_id.param_info[src_i];
+ ty = param_info->type;
+ var = fn_walk->data.vars.var;
+ source_node = var->decl_node;
+ llvm_fn = fn_walk->data.vars.llvm_fn;
+ break;
+ case FnWalkIdInits:
+ if (src_i >= fn_type->data.fn.fn_type_id.param_count)
+ return false;
+ param_info = &fn_type->data.fn.fn_type_id.param_info[src_i];
+ ty = param_info->type;
+ var = fn_walk->data.inits.fn->variable_list.at(src_i);
+ source_node = fn_walk->data.inits.fn->proto_node;
+ llvm_fn = fn_walk->data.inits.llvm_fn;
+ break;
+ }
+
+ if (type_is_c_abi_int(g, ty) || ty->id == ZigTypeIdFloat ||
+ ty->id == ZigTypeIdInt // TODO investigate if we need to change this
+ ) {
+ switch (fn_walk->id) {
+ case FnWalkIdAttrs: {
+ ZigType *ptr_type = get_codegen_ptr_type(ty);
+ if (ptr_type != nullptr) {
+ if (ty->id != ZigTypeIdOptional) {
+ addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "nonnull");
+ }
+ if (ptr_type->data.pointer.is_const) {
+ addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "readonly");
+ }
+ if (param_info->is_noalias) {
+ addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "noalias");
+ }
+ }
+ fn_walk->data.attrs.gen_i += 1;
+ break;
+ }
+ case FnWalkIdCall:
+ fn_walk->data.call.gen_param_values->append(val);
+ break;
+ case FnWalkIdTypes:
+ fn_walk->data.types.gen_param_types->append(ty->type_ref);
+ fn_walk->data.types.param_di_types->append(ty->di_type);
+ break;
+ case FnWalkIdVars: {
+ var->value_ref = build_alloca(g, ty, buf_ptr(&var->name), var->align_bytes);
+ di_arg_index = fn_walk->data.vars.gen_i;
+ fn_walk->data.vars.gen_i += 1;
+ dest_ty = ty;
+ goto var_ok;
+ }
+ case FnWalkIdInits:
+ clear_debug_source_node(g);
+ gen_store_untyped(g, LLVMGetParam(llvm_fn, fn_walk->data.inits.gen_i), var->value_ref, var->align_bytes, false);
+ if (var->decl_node) {
+ gen_var_debug_decl(g, var);
+ }
+ fn_walk->data.inits.gen_i += 1;
+ break;
+ }
+ return true;
+ }
+
+ // Arrays are just pointers
+ if (ty->id == ZigTypeIdArray) {
+ assert(handle_is_ptr(ty));
+ switch (fn_walk->id) {
+ case FnWalkIdAttrs:
+ addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "nonnull");
+ fn_walk->data.attrs.gen_i += 1;
+ break;
+ case FnWalkIdCall:
+ fn_walk->data.call.gen_param_values->append(val);
+ break;
+ case FnWalkIdTypes: {
+ ZigType *gen_type = get_pointer_to_type(g, ty, true);
+ fn_walk->data.types.gen_param_types->append(gen_type->type_ref);
+ fn_walk->data.types.param_di_types->append(gen_type->di_type);
+ break;
+ }
+ case FnWalkIdVars: {
+ var->value_ref = LLVMGetParam(llvm_fn, fn_walk->data.vars.gen_i);
+ di_arg_index = fn_walk->data.vars.gen_i;
+ dest_ty = get_pointer_to_type(g, ty, false);
+ fn_walk->data.vars.gen_i += 1;
+ goto var_ok;
+ }
+ case FnWalkIdInits:
+ if (var->decl_node) {
+ gen_var_debug_decl(g, var);
+ }
+ fn_walk->data.inits.gen_i += 1;
+ break;
+ }
+ return true;
+ }
+
+ if (g->zig_target.arch.arch == ZigLLVM_x86_64) {
+ size_t ty_size = type_size(g, ty);
+ if (ty->id == ZigTypeIdStruct || ty->id == ZigTypeIdUnion) {
+ assert(handle_is_ptr(ty));
+
+ // "If the size of an object is larger than four eightbytes, or it contains unaligned
+ // fields, it has class MEMORY"
+ if (ty_size > 32) {
+ switch (fn_walk->id) {
+ case FnWalkIdAttrs:
+ addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "byval");
+ addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "nonnull");
+ fn_walk->data.attrs.gen_i += 1;
+ break;
+ case FnWalkIdCall:
+ fn_walk->data.call.gen_param_values->append(val);
+ break;
+ case FnWalkIdTypes: {
+ ZigType *gen_type = get_pointer_to_type(g, ty, true);
+ fn_walk->data.types.gen_param_types->append(gen_type->type_ref);
+ fn_walk->data.types.param_di_types->append(gen_type->di_type);
+ break;
+ }
+ case FnWalkIdVars: {
+ di_arg_index = fn_walk->data.vars.gen_i;
+ var->value_ref = LLVMGetParam(llvm_fn, fn_walk->data.vars.gen_i);
+ dest_ty = get_pointer_to_type(g, ty, false);
+ fn_walk->data.vars.gen_i += 1;
+ goto var_ok;
+ }
+ case FnWalkIdInits:
+ if (var->decl_node) {
+ gen_var_debug_decl(g, var);
+ }
+ fn_walk->data.inits.gen_i += 1;
+ break;
+ }
+ return true;
+ }
+ }
+ if (ty->id == ZigTypeIdStruct) {
+ assert(handle_is_ptr(ty));
+ // "If the size of the aggregate exceeds a single eightbyte, each is classified
+ // separately. Each eightbyte gets initialized to class NO_CLASS."
+ if (ty_size <= 8) {
+ bool contains_int = false;
+ for (size_t i = 0; i < ty->data.structure.src_field_count; i += 1) {
+ if (type_is_c_abi_int(g, ty->data.structure.fields[i].type_entry)) {
+ contains_int = true;
+ break;
+ }
+ }
+ if (contains_int) {
+ switch (fn_walk->id) {
+ case FnWalkIdAttrs:
+ fn_walk->data.attrs.gen_i += 1;
+ break;
+ case FnWalkIdCall: {
+ LLVMTypeRef ptr_to_int_type_ref = LLVMPointerType(LLVMIntType((unsigned)ty_size * 8), 0);
+ LLVMValueRef bitcasted = LLVMBuildBitCast(g->builder, val, ptr_to_int_type_ref, "");
+ LLVMValueRef loaded = LLVMBuildLoad(g->builder, bitcasted, "");
+ fn_walk->data.call.gen_param_values->append(loaded);
+ break;
+ }
+ case FnWalkIdTypes: {
+ ZigType *gen_type = get_int_type(g, false, ty_size * 8);
+ fn_walk->data.types.gen_param_types->append(gen_type->type_ref);
+ fn_walk->data.types.param_di_types->append(gen_type->di_type);
+ break;
+ }
+ case FnWalkIdVars: {
+ di_arg_index = fn_walk->data.vars.gen_i;
+ var->value_ref = build_alloca(g, ty, buf_ptr(&var->name), var->align_bytes);
+ fn_walk->data.vars.gen_i += 1;
+ dest_ty = ty;
+ goto var_ok;
+ }
+ case FnWalkIdInits: {
+ clear_debug_source_node(g);
+ LLVMValueRef arg = LLVMGetParam(llvm_fn, fn_walk->data.inits.gen_i);
+ LLVMTypeRef ptr_to_int_type_ref = LLVMPointerType(LLVMIntType((unsigned)ty_size * 8), 0);
+ LLVMValueRef bitcasted = LLVMBuildBitCast(g->builder, var->value_ref, ptr_to_int_type_ref, "");
+ gen_store_untyped(g, arg, bitcasted, var->align_bytes, false);
+ if (var->decl_node) {
+ gen_var_debug_decl(g, var);
+ }
+ fn_walk->data.inits.gen_i += 1;
+ break;
+ }
+ }
+ return true;
+ }
+ }
+ }
+ }
+ if (source_node != nullptr) {
+ give_up_with_c_abi_error(g, source_node);
+ }
+ // otherwise allow codegen code to report a compile error
+ return false;
+
+var_ok:
+ if (dest_ty != nullptr && var->decl_node) {
+ // arg index + 1 because the 0 index is return value
+ var->di_loc_var = ZigLLVMCreateParameterVariable(g->dbuilder, get_di_scope(g, var->parent_scope),
+ buf_ptr(&var->name), fn_walk->data.vars.import->di_file,
+ (unsigned)(var->decl_node->line + 1),
+ dest_ty->di_type, !g->strip_debug_symbols, 0, di_arg_index + 1);
+ }
+ return true;
+}
+
+void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk) {
+ CallingConvention cc = fn_type->data.fn.fn_type_id.cc;
+ if (cc == CallingConventionC) {
+ size_t src_i = 0;
+ for (;;) {
+ if (!iter_function_params_c_abi(g, fn_type, fn_walk, src_i))
+ break;
+ src_i += 1;
+ }
+ return;
+ }
+ if (fn_walk->id == FnWalkIdCall) {
+ IrInstructionCall *instruction = fn_walk->data.call.inst;
+ bool is_var_args = fn_walk->data.call.is_var_args;
+ for (size_t call_i = 0; call_i < instruction->arg_count; call_i += 1) {
+ IrInstruction *param_instruction = instruction->args[call_i];
+ ZigType *param_type = param_instruction->value.type;
+ if (is_var_args || type_has_bits(param_type)) {
+ LLVMValueRef param_value = ir_llvm_value(g, param_instruction);
+ assert(param_value);
+ fn_walk->data.call.gen_param_values->append(param_value);
+ }
+ }
+ return;
+ }
+ size_t next_var_i = 0;
+ for (size_t param_i = 0; param_i < fn_type->data.fn.fn_type_id.param_count; param_i += 1) {
+ FnGenParamInfo *gen_info = &fn_type->data.fn.gen_param_info[param_i];
+ size_t gen_index = gen_info->gen_index;
+
+ if (gen_index == SIZE_MAX) {
+ continue;
+ }
+
+ switch (fn_walk->id) {
+ case FnWalkIdAttrs: {
+ LLVMValueRef llvm_fn = fn_walk->data.attrs.fn->llvm_value;
+ bool is_byval = gen_info->is_byval;
+ FnTypeParamInfo *param_info = &fn_type->data.fn.fn_type_id.param_info[param_i];
+
+ ZigType *param_type = gen_info->type;
+ if (param_info->is_noalias) {
+ addLLVMArgAttr(llvm_fn, (unsigned)gen_index, "noalias");
+ }
+ if ((param_type->id == ZigTypeIdPointer && param_type->data.pointer.is_const) || is_byval) {
+ addLLVMArgAttr(llvm_fn, (unsigned)gen_index, "readonly");
+ }
+ if (param_type->id == ZigTypeIdPointer) {
+ addLLVMArgAttr(llvm_fn, (unsigned)gen_index, "nonnull");
+ }
+ break;
+ }
+ case FnWalkIdInits: {
+ ZigFn *fn_table_entry = fn_walk->data.inits.fn;
+ LLVMValueRef llvm_fn = fn_table_entry->llvm_value;
+ ZigVar *variable = fn_table_entry->variable_list.at(next_var_i);
+ assert(variable->src_arg_index != SIZE_MAX);
+ next_var_i += 1;
+
+ assert(variable);
+ assert(variable->value_ref);
+
+ if (!handle_is_ptr(variable->value->type)) {
+ clear_debug_source_node(g);
+ gen_store_untyped(g, LLVMGetParam(llvm_fn, (unsigned)variable->gen_arg_index), variable->value_ref,
+ variable->align_bytes, false);
+ }
+
+ if (variable->decl_node) {
+ gen_var_debug_decl(g, variable);
+ }
+ break;
+ }
+ case FnWalkIdCall:
+ // handled before for loop
+ zig_unreachable();
+ case FnWalkIdTypes:
+ // Not called for non-c-abi
+ zig_unreachable();
+ case FnWalkIdVars:
+ // iter_function_params_c_abi is called directly for this one
+ zig_unreachable();
+ }
+ }
+}
+
static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, IrExecutable *executable,
IrInstructionSaveErrRetAddr *save_err_ret_addr_instruction)
{
@@ -3128,40 +3484,31 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
ZigType *src_return_type = fn_type_id->return_type;
bool ret_has_bits = type_has_bits(src_return_type);
+ CallingConvention cc = fn_type->data.fn.fn_type_id.cc;
+
bool first_arg_ret = ret_has_bits && handle_is_ptr(src_return_type) &&
- calling_convention_does_first_arg_return(fn_type->data.fn.fn_type_id.cc);
+ calling_convention_does_first_arg_return(cc);
bool prefix_arg_err_ret_stack = get_prefix_arg_err_ret_stack(g, fn_type_id);
- // +2 for the async args
- size_t actual_param_count = instruction->arg_count + (first_arg_ret ? 1 : 0) + (prefix_arg_err_ret_stack ? 1 : 0) + 2;
bool is_var_args = fn_type_id->is_var_args;
- LLVMValueRef *gen_param_values = allocate<LLVMValueRef>(actual_param_count);
- size_t gen_param_index = 0;
+ ZigList<LLVMValueRef> gen_param_values = {};
if (first_arg_ret) {
- gen_param_values[gen_param_index] = instruction->tmp_ptr;
- gen_param_index += 1;
+ gen_param_values.append(instruction->tmp_ptr);
}
if (prefix_arg_err_ret_stack) {
- gen_param_values[gen_param_index] = get_cur_err_ret_trace_val(g, instruction->base.scope);
- gen_param_index += 1;
+ gen_param_values.append(get_cur_err_ret_trace_val(g, instruction->base.scope));
}
if (instruction->is_async) {
- gen_param_values[gen_param_index] = ir_llvm_value(g, instruction->async_allocator);
- gen_param_index += 1;
+ gen_param_values.append(ir_llvm_value(g, instruction->async_allocator));
LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_err_index, "");
- gen_param_values[gen_param_index] = err_val_ptr;
- gen_param_index += 1;
- }
- for (size_t call_i = 0; call_i < instruction->arg_count; call_i += 1) {
- IrInstruction *param_instruction = instruction->args[call_i];
- ZigType *param_type = param_instruction->value.type;
- if (is_var_args || type_has_bits(param_type)) {
- LLVMValueRef param_value = ir_llvm_value(g, param_instruction);
- assert(param_value);
- gen_param_values[gen_param_index] = param_value;
- gen_param_index += 1;
- }
+ gen_param_values.append(err_val_ptr);
}
+ FnWalk fn_walk = {};
+ fn_walk.id = FnWalkIdCall;
+ fn_walk.data.call.inst = instruction;
+ fn_walk.data.call.is_var_args = is_var_args;
+ fn_walk.data.call.gen_param_values = &gen_param_values;
+ walk_function_params(g, fn_type, &fn_walk);
ZigLLVM_FnInline fn_inline;
switch (instruction->fn_inline) {
@@ -3176,12 +3523,12 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
break;
}
- LLVMCallConv llvm_cc = get_llvm_cc(g, fn_type->data.fn.fn_type_id.cc);
+ LLVMCallConv llvm_cc = get_llvm_cc(g, cc);
LLVMValueRef result;
if (instruction->new_stack == nullptr) {
result = ZigLLVMBuildCall(g->builder, fn_val,
- gen_param_values, (unsigned)gen_param_index, llvm_cc, fn_inline, "");
+ gen_param_values.items, (unsigned)gen_param_values.length, llvm_cc, fn_inline, "");
} else {
LLVMValueRef stacksave_fn_val = get_stacksave_fn_val(g);
LLVMValueRef stackrestore_fn_val = get_stackrestore_fn_val(g);
@@ -3190,7 +3537,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
LLVMValueRef old_stack_ref = LLVMBuildCall(g->builder, stacksave_fn_val, nullptr, 0, "");
gen_set_stack_pointer(g, new_stack_addr);
result = ZigLLVMBuildCall(g->builder, fn_val,
- gen_param_values, (unsigned)gen_param_index, llvm_cc, fn_inline, "");
+ gen_param_values.items, (unsigned)gen_param_values.length, llvm_cc, fn_inline, "");
LLVMBuildCall(g->builder, stackrestore_fn_val, &old_stack_ref, 1, "");
}
@@ -5721,13 +6068,6 @@ static void gen_global_var(CodeGen *g, ZigVar *var, LLVMValueRef init_val,
// TODO ^^ make an actual global variable
}
-static LLVMValueRef build_alloca(CodeGen *g, ZigType *type_entry, const char *name, uint32_t alignment) {
- assert(alignment > 0);
- LLVMValueRef result = LLVMBuildAlloca(g->builder, type_entry->type_ref, name);
- LLVMSetAlignment(result, alignment);
- return result;
-}
-
static void ensure_cache_dir(CodeGen *g) {
int err;
if ((err = os_make_path(&g->cache_dir))) {
@@ -5735,16 +6075,6 @@ static void ensure_cache_dir(CodeGen *g) {
}
}
-static void report_errors_and_maybe_exit(CodeGen *g) {
- if (g->errors.length != 0) {
- for (size_t i = 0; i < g->errors.length; i += 1) {
- ErrorMsg *err = g->errors.at(i);
- print_err_msg(err, g->err_color);
- }
- exit(1);
- }
-}
-
static void validate_inline_fns(CodeGen *g) {
for (size_t i = 0; i < g->inline_fns.length; i += 1) {
ZigFn *fn_entry = g->inline_fns.at(i);
@@ -5865,6 +6195,8 @@ static void do_code_gen(CodeGen *g) {
// Generate function definitions.
for (size_t fn_i = 0; fn_i < g->fn_defs.length; fn_i += 1) {
ZigFn *fn_table_entry = g->fn_defs.at(fn_i);
+ CallingConvention cc = fn_table_entry->type_entry->data.fn.fn_type_id.cc;
+ bool is_c_abi = cc == CallingConventionC;
LLVMValueRef fn = fn_llvm_value(g, fn_table_entry);
g->cur_fn = fn_table_entry;
@@ -5888,7 +6220,7 @@ static void do_code_gen(CodeGen *g) {
}
// error return tracing setup
- bool is_async = fn_table_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync;
+ bool is_async = cc == CallingConventionAsync;
bool have_err_ret_trace_stack = g->have_err_ret_tracing && fn_table_entry->calls_or_awaits_errorable_fn && !is_async && !have_err_ret_trace_arg;
LLVMValueRef err_ret_array_val = nullptr;
if (have_err_ret_trace_stack) {
@@ -5948,6 +6280,12 @@ static void do_code_gen(CodeGen *g) {
ImportTableEntry *import = get_scope_import(&fn_table_entry->fndef_scope->base);
// create debug variable declarations for variables and allocate all local variables
+ FnWalk fn_walk_var = {};
+ fn_walk_var.id = FnWalkIdVars;
+ fn_walk_var.data.vars.import = import;
+ fn_walk_var.data.vars.fn = fn_table_entry;
+ fn_walk_var.data.vars.llvm_fn = fn;
+ fn_walk_var.data.vars.gen_i = 0;
for (size_t var_i = 0; var_i < fn_table_entry->variable_list.length; var_i += 1) {
ZigVar *var = fn_table_entry->variable_list.at(var_i);
@@ -5966,6 +6304,9 @@ static void do_code_gen(CodeGen *g) {
buf_ptr(&var->name), import->di_file, (unsigned)(var->decl_node->line + 1),
var->value->type->di_type, !g->strip_debug_symbols, 0);
+ } else if (is_c_abi) {
+ fn_walk_var.data.vars.var = var;
+ iter_function_params_c_abi(g, fn_table_entry->type_entry, &fn_walk_var, var->src_arg_index);
} else {
assert(var->gen_arg_index != SIZE_MAX);
ZigType *gen_type;
@@ -6017,33 +6358,13 @@ static void do_code_gen(CodeGen *g) {
gen_store(g, LLVMConstInt(usize->type_ref, stack_trace_ptr_count, false), len_field_ptr, get_pointer_to_type(g, usize, false));
}
- FnTypeId *fn_type_id = &fn_table_entry->type_entry->data.fn.fn_type_id;
-
// create debug variable declarations for parameters
// rely on the first variables in the variable_list being parameters.
- size_t next_var_i = 0;
- for (size_t param_i = 0; param_i < fn_type_id->param_count; param_i += 1) {
- FnGenParamInfo *info = &fn_table_entry->type_entry->data.fn.gen_param_info[param_i];
- if (info->gen_index == SIZE_MAX)
- continue;
-
- ZigVar *variable = fn_table_entry->variable_list.at(next_var_i);
- assert(variable->src_arg_index != SIZE_MAX);
- next_var_i += 1;
-
- assert(variable);
- assert(variable->value_ref);
-
- if (!handle_is_ptr(variable->value->type)) {
- clear_debug_source_node(g);
- gen_store_untyped(g, LLVMGetParam(fn, (unsigned)variable->gen_arg_index), variable->value_ref,
- variable->align_bytes, false);
- }
-
- if (variable->decl_node) {
- gen_var_debug_decl(g, variable);
- }
- }
+ FnWalk fn_walk_init = {};
+ fn_walk_init.id = FnWalkIdInits;
+ fn_walk_init.data.inits.fn = fn_table_entry;
+ fn_walk_init.data.inits.llvm_fn = fn;
+ walk_function_params(g, fn_table_entry->type_entry, &fn_walk_init);
ir_render(g, fn_table_entry);