aboutsummaryrefslogtreecommitdiff
path: root/src/analyze.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/analyze.cpp')
-rw-r--r--src/analyze.cpp120
1 files changed, 90 insertions, 30 deletions
diff --git a/src/analyze.cpp b/src/analyze.cpp
index a1e0421133..5ba341b541 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -346,18 +346,19 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
ImportTableEntry *import)
{
assert(node->type == NodeTypeFnProto);
+ AstNodeFnProto *fn_proto = &node->data.fn_proto;
- for (int i = 0; i < node->data.fn_proto.directives->length; i += 1) {
- AstNode *directive_node = node->data.fn_proto.directives->at(i);
+ for (int i = 0; i < fn_proto->directives->length; i += 1) {
+ AstNode *directive_node = fn_proto->directives->at(i);
Buf *name = &directive_node->data.directive.name;
if (buf_eql_str(name, "attribute")) {
Buf *attr_name = &directive_node->data.directive.param;
if (fn_table_entry->fn_def_node) {
if (buf_eql_str(attr_name, "naked")) {
- fn_table_entry->fn_attr_list.append(FnAttrIdNaked);
+ fn_table_entry->is_naked = true;
} else if (buf_eql_str(attr_name, "inline")) {
- fn_table_entry->fn_attr_list.append(FnAttrIdAlwaysInline);
+ fn_table_entry->is_inline = true;
} else {
add_node_error(g, directive_node,
buf_sprintf("invalid function attribute: '%s'", buf_ptr(name)));
@@ -382,38 +383,100 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
buf_resize(&fn_type->name, 0);
buf_appendf(&fn_type->name, "fn(");
+ int gen_param_count = 0;
+ LLVMTypeRef *gen_param_types = allocate<LLVMTypeRef>(param_count);
+ LLVMZigDIType **param_di_types = allocate<LLVMZigDIType*>(1 + param_count);
for (int i = 0; i < param_count; i += 1) {
AstNode *child = node->data.fn_proto.params.at(i);
assert(child->type == NodeTypeParamDecl);
TypeTableEntry *type_entry = analyze_type_expr(g, import, import->block_context,
child->data.param_decl.type);
- fn_table_entry->type_entry->data.fn.param_types[i] = type_entry;
-
- buf_appendf(&fn_type->name, "%s", buf_ptr(&type_entry->name));
-
- if (i + 1 < param_count) {
- buf_appendf(&fn_type->name, ", ");
- }
+ fn_type->data.fn.param_types[i] = type_entry;
if (type_entry->id == TypeTableEntryIdUnreachable) {
add_node_error(g, child->data.param_decl.type,
buf_sprintf("parameter of type 'unreachable' not allowed"));
- } else if (type_entry->id == TypeTableEntryIdVoid) {
- if (node->data.fn_proto.visib_mod == VisibModExport) {
- add_node_error(g, child->data.param_decl.type,
- buf_sprintf("parameter of type 'void' not allowed on exported functions"));
- }
+ fn_proto->skip = true;
+ } else if (type_entry->id == TypeTableEntryIdInvalid) {
+ fn_proto->skip = true;
+ }
+
+ if (!fn_proto->skip && type_entry->size_in_bits > 0) {
+ const char *comma = (gen_param_count == 0) ? "" : ", ";
+ buf_appendf(&fn_type->name, "%s%s", comma, buf_ptr(&type_entry->name));
+
+ TypeTableEntry *gen_type = handle_is_ptr(type_entry) ?
+ get_pointer_to_type(g, type_entry, true) : type_entry;
+ gen_param_types[gen_param_count] = gen_type->type_ref;
+
+ gen_param_count += 1;
+
+ // after the gen_param_count += 1 because 0 is the return type
+ param_di_types[gen_param_count] = gen_type->di_type;
}
}
TypeTableEntry *return_type = analyze_type_expr(g, import, import->block_context,
node->data.fn_proto.return_type);
- fn_table_entry->type_entry->data.fn.return_type = return_type;
+ fn_type->data.fn.return_type = return_type;
+ if (return_type->id == TypeTableEntryIdInvalid) {
+ fn_proto->skip = true;
+ }
buf_appendf(&fn_type->name, ")");
if (return_type->id != TypeTableEntryIdVoid) {
buf_appendf(&fn_type->name, " %s", buf_ptr(&return_type->name));
}
+
+ if (fn_proto->skip) {
+ return;
+ }
+
+ fn_type->type_ref = LLVMFunctionType(return_type->type_ref, gen_param_types, gen_param_count,
+ fn_proto->is_var_args);
+
+ fn_table_entry->fn_value = LLVMAddFunction(g->module, buf_ptr(&fn_table_entry->symbol_name),
+ fn_table_entry->type_entry->type_ref);
+
+ if (fn_table_entry->is_inline) {
+ LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMAlwaysInlineAttribute);
+ }
+ if (fn_table_entry->is_naked) {
+ LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMNakedAttribute);
+ }
+
+ LLVMSetLinkage(fn_table_entry->fn_value, fn_table_entry->internal_linkage ?
+ LLVMInternalLinkage : LLVMExternalLinkage);
+
+ if (return_type->id == TypeTableEntryIdUnreachable) {
+ LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMNoReturnAttribute);
+ }
+ LLVMSetFunctionCallConv(fn_table_entry->fn_value, fn_table_entry->calling_convention);
+ if (!fn_table_entry->is_extern) {
+ LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMNoUnwindAttribute);
+ }
+
+ param_di_types[0] = return_type->di_type;
+ LLVMZigDISubroutineType *di_sub_type = LLVMZigCreateSubroutineType(g->dbuilder, import->di_file,
+ param_di_types, gen_param_count + 1, 0);
+
+ // Add debug info.
+ unsigned line_number = node->line + 1;
+ unsigned scope_line = line_number;
+ bool is_definition = fn_table_entry->fn_def_node != nullptr;
+ unsigned flags = 0;
+ bool is_optimized = g->build_type == CodeGenBuildTypeRelease;
+ LLVMZigDISubprogram *subprogram = LLVMZigCreateFunction(g->dbuilder,
+ import->block_context->di_scope, buf_ptr(&fn_table_entry->symbol_name), "",
+ import->di_file, line_number,
+ di_sub_type, fn_table_entry->internal_linkage,
+ is_definition, scope_line, flags, is_optimized, fn_table_entry->fn_value);
+ fn_type->di_type = LLVMZigSubroutineToType(di_sub_type);
+ if (fn_table_entry->fn_def_node) {
+ BlockContext *context = new_block_context(fn_table_entry->fn_def_node, import->block_context);
+ fn_table_entry->fn_def_node->data.fn_def.block_context = context;
+ context->di_scope = LLVMZigSubprogramToScope(subprogram);
+ }
}
static void preview_function_labels(CodeGen *g, AstNode *node, FnTableEntry *fn_table_entry) {
@@ -724,14 +787,6 @@ static void preview_fn_proto(CodeGen *g, ImportTableEntry *import,
buf_sprintf("redefinition of '%s'", buf_ptr(proto_name)));
proto_node->data.fn_proto.skip = true;
skip = true;
- } else if (is_pub) {
- // TODO is this else if branch a mistake?
- auto entry = fn_table->maybe_get(proto_name);
- if (entry) {
- add_node_error(g, proto_node, buf_sprintf("redefinition of '%s'", buf_ptr(proto_name)));
- proto_node->data.fn_proto.skip = true;
- skip = true;
- }
}
if (!extern_node && proto_node->data.fn_proto.is_var_args) {
add_node_error(g, proto_node,
@@ -775,10 +830,8 @@ static void preview_fn_proto(CodeGen *g, ImportTableEntry *import,
g->bootstrap_import->fn_table.put(proto_name, fn_table_entry);
}
- resolve_function_proto(g, proto_node, fn_table_entry, import);
-
-
proto_node->data.fn_proto.fn_table_entry = fn_table_entry;
+ resolve_function_proto(g, proto_node, fn_table_entry, import);
if (fn_def_node) {
preview_function_labels(g, fn_def_node->data.fn_def.body, fn_table_entry);
@@ -3146,8 +3199,7 @@ static void analyze_top_level_fn_def(CodeGen *g, ImportTableEntry *import, AstNo
return;
}
- BlockContext *context = new_block_context(node, import->block_context);
- node->data.fn_def.block_context = context;
+ BlockContext *context = node->data.fn_def.block_context;
AstNodeFnProto *fn_proto = &fn_proto_node->data.fn_proto;
bool is_exported = (fn_proto->visib_mod == VisibModExport);
@@ -3923,3 +3975,11 @@ TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, int size_in_bits)
TypeTableEntry *get_int_type(CodeGen *g, bool is_signed, int size_in_bits) {
return *get_int_type_ptr(g, is_signed, size_in_bits);
}
+
+bool handle_is_ptr(TypeTableEntry *type_entry) {
+ return type_entry->id == TypeTableEntryIdStruct ||
+ (type_entry->id == TypeTableEntryIdEnum && type_entry->data.enumeration.gen_field_count != 0) ||
+ type_entry->id == TypeTableEntryIdMaybe ||
+ type_entry->id == TypeTableEntryIdArray;
+}
+