aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGinger Bill <bill@gingerbill.org>2017-06-21 17:49:05 +0100
committerGinger Bill <bill@gingerbill.org>2017-06-21 17:49:05 +0100
commit264ca00db72f56e2af8242a90e35a49b6ae13f86 (patch)
treec7a1f170fea7c22b4d3734282716b0ee0e74ad7c /src
parent6b65ef6d8847ea7dcb23a556e12daae69738c5c2 (diff)
parent5957d7f7bee7e5fac4035d47ecaaaad022adbfb8 (diff)
Merge branch 'master' of https://github.com/gingerBill/Odin
Diffstat (limited to 'src')
-rw-r--r--src/check_decl.cpp5
-rw-r--r--src/check_expr.cpp6
-rw-r--r--src/checker.cpp12
-rw-r--r--src/ir.cpp95
-rw-r--r--src/ir_print.cpp38
-rw-r--r--src/parser.cpp19
6 files changed, 128 insertions, 47 deletions
diff --git a/src/check_decl.cpp b/src/check_decl.cpp
index dede1a26c..672673faf 100644
--- a/src/check_decl.cpp
+++ b/src/check_decl.cpp
@@ -333,6 +333,11 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
error(e->token, "Procedure type of `main` was expected to be `proc()`, got %s", str);
gb_string_free(str);
}
+ if (proc_type->Proc.calling_convention != ProcCC_Odin &&
+ proc_type->Proc.calling_convention != ProcCC_Contextless) {
+ error(e->token, "Procedure `main` cannot have a custom calling convention");
+ }
+ proc_type->Proc.calling_convention = ProcCC_Contextless;
}
if (is_inline && is_no_inline) {
diff --git a/src/check_expr.cpp b/src/check_expr.cpp
index 05096bf52..df16ab2b4 100644
--- a/src/check_expr.cpp
+++ b/src/check_expr.cpp
@@ -1419,7 +1419,9 @@ bool abi_compat_return_by_value(gbAllocator a, ProcCallingConvention cc, Type *a
if (abi_return_type == NULL) {
return false;
}
- if (cc == ProcCC_Odin) {
+ switch (cc) {
+ case ProcCC_Odin:
+ case ProcCC_Contextless:
return false;
}
@@ -1465,6 +1467,8 @@ void check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node) {
if (end->flags&EntityFlag_CVarArg) {
if (pt->calling_convention == ProcCC_Odin) {
error(end->token, "Odin calling convention does not support #c_vararg");
+ } else if (pt->calling_convention == ProcCC_Contextless) {
+ error(end->token, "Odin's contextless calling convention does not support #c_vararg");
} else if (pt->calling_convention == ProcCC_Fast) {
error(end->token, "Fast calling convention does not support #c_vararg");
} else {
diff --git a/src/checker.cpp b/src/checker.cpp
index eaa38aaa4..c5b17cc2f 100644
--- a/src/checker.cpp
+++ b/src/checker.cpp
@@ -1779,14 +1779,16 @@ void check_all_global_entities(Checker *c) {
continue;
}
- if (e->kind != Entity_Procedure && e->token.string == "main") {
- if (e->scope->is_init) {
+ if (e->token.string == "main") {
+ if (e->kind != Entity_Procedure) {
+ if (e->scope->is_init) {
+ error(e->token, "`main` is reserved as the entry point procedure in the initial scope");
+ continue;
+ }
+ } else if (e->scope->is_global) {
error(e->token, "`main` is reserved as the entry point procedure in the initial scope");
continue;
}
- } else if (e->scope->is_global && e->token.string == "main") {
- error(e->token, "`main` is reserved as the entry point procedure in the initial scope");
- continue;
}
CheckerContext prev_context = c->context;
diff --git a/src/ir.cpp b/src/ir.cpp
index f5b431ec1..cbe81fdbe 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -28,6 +28,8 @@ struct irModule {
i32 global_array_index; // For ConstantSlice
i32 global_generated_index;
+ irValue * global_default_context;
+
// NOTE(bill): To prevent strings from being copied a lot
// Mainly used for file names
Map<irValue *> const_strings; // Key: String
@@ -125,6 +127,9 @@ struct irProcedure {
irTargetList * target_list;
Array<irValue *> referrers;
+ Array<irValue *> context_stack;
+
+
Array<irBranchBlocks> branch_blocks;
i32 local_count;
@@ -216,6 +221,7 @@ struct irProcedure {
irValue * return_ptr; \
irValue **args; \
isize arg_count; \
+ irValue * context_ptr; \
}) \
IR_INSTR_KIND(StartupRuntime, i32) \
IR_INSTR_KIND(DebugDeclare, struct { \
@@ -986,22 +992,23 @@ irValue *ir_instr_select(irProcedure *p, irValue *cond, irValue *t, irValue *f)
return v;
}
-irValue *ir_instr_call(irProcedure *p, irValue *value, irValue *return_ptr, irValue **args, isize arg_count, Type *result_type) {
+irValue *ir_instr_call(irProcedure *p, irValue *value, irValue *return_ptr, irValue **args, isize arg_count, Type *result_type, irValue *context_ptr) {
irValue *v = ir_alloc_instr(p, irInstr_Call);
- v->Instr.Call.value = value;
- v->Instr.Call.return_ptr = return_ptr;
- v->Instr.Call.args = args;
- v->Instr.Call.arg_count = arg_count;
- v->Instr.Call.type = result_type;
+ v->Instr.Call.value = value;
+ v->Instr.Call.return_ptr = return_ptr;
+ v->Instr.Call.args = args;
+ v->Instr.Call.arg_count = arg_count;
+ v->Instr.Call.type = result_type;
+ v->Instr.Call.context_ptr = context_ptr;
return v;
}
irValue *ir_instr_conv(irProcedure *p, irConvKind kind, irValue *value, Type *from, Type *to) {
irValue *v = ir_alloc_instr(p, irInstr_Conv);
- v->Instr.Conv.kind = kind;
+ v->Instr.Conv.kind = kind;
v->Instr.Conv.value = value;
- v->Instr.Conv.from = from;
- v->Instr.Conv.to = to;
+ v->Instr.Conv.from = from;
+ v->Instr.Conv.to = to;
return v;
}
@@ -1472,11 +1479,30 @@ irValue *ir_emit_bitcast(irProcedure *proc, irValue *data, Type *type) {
irValue *ir_emit_transmute(irProcedure *proc, irValue *value, Type *t);
+
+irValue *ir_emit_global_call(irProcedure *proc, char *name_, irValue **args, isize arg_count);
+
+irValue *ir_find_or_generate_context_ptr(irProcedure *proc) {
+ if (proc->context_stack.count > 0) {
+ return proc->context_stack[proc->context_stack.count-1];
+ }
+ irValue *c = ir_add_local_generated(proc, t_context);
+ ir_emit_store(proc, c, ir_emit_load(proc, proc->module->global_default_context));
+ array_add(&proc->context_stack, c);
+ return c;
+}
+
+
irValue *ir_emit_call(irProcedure *p, irValue *value, irValue **args, isize arg_count) {
Type *pt = base_type(ir_type(value));
GB_ASSERT(pt->kind == Type_Proc);
Type *results = pt->Proc.results;
+ irValue *context_ptr = NULL;
+ if (pt->Proc.calling_convention == ProcCC_Odin) {
+ context_ptr = ir_find_or_generate_context_ptr(p);
+ }
+
isize param_count = pt->Proc.param_count;
if (pt->Proc.c_vararg) {
GB_ASSERT(param_count-1 <= arg_count);
@@ -1500,11 +1526,11 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, irValue **args, isize arg_
if (pt->Proc.return_by_pointer) {
irValue *return_ptr = ir_add_local_generated(p, rt);
GB_ASSERT(is_type_pointer(ir_type(return_ptr)));
- ir_emit(p, ir_instr_call(p, value, return_ptr, args, arg_count, NULL));
+ ir_emit(p, ir_instr_call(p, value, return_ptr, args, arg_count, NULL, context_ptr));
return ir_emit_load(p, return_ptr);
}
- irValue *result = ir_emit(p, ir_instr_call(p, value, NULL, args, arg_count, abi_rt));
+ irValue *result = ir_emit(p, ir_instr_call(p, value, NULL, args, arg_count, abi_rt, context_ptr));
if (abi_rt != results) {
result = ir_emit_transmute(p, result, rt);
}
@@ -4865,7 +4891,8 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
irValue *v = NULL;
switch (i->kind) {
case Token_context:
- v = ir_find_global_variable(proc, str_lit("__context"));
+ v = ir_find_or_generate_context_ptr(proc);
+ // v = ir_find_global_variable(proc, str_lit("__context"));
break;
}
@@ -6716,13 +6743,13 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
ir_emit_comment(proc, str_lit("PushAllocator"));
ir_open_scope(proc);
- irValue *context_ptr = ir_find_global_variable(proc, str_lit("__context"));
- irValue *prev_context = ir_add_local_generated(proc, t_context);
- ir_emit_store(proc, prev_context, ir_emit_load(proc, context_ptr));
+ irValue *prev = ir_find_or_generate_context_ptr(proc);
+ irValue *next = ir_add_local_generated(proc, t_context);
+ ir_emit_store(proc, next, ir_emit_load(proc, prev));
+ array_add(&proc->context_stack, next);
+ defer (array_pop(&proc->context_stack));
- ir_add_defer_instr(proc, proc->scope_index, ir_instr_store(proc, context_ptr, ir_emit_load(proc, prev_context), false));
-
- irValue *gep = ir_emit_struct_ep(proc, context_ptr, 1);
+ irValue *gep = ir_emit_struct_ep(proc, next, 1);
ir_emit_store(proc, gep, ir_build_expr(proc, pa->expr));
ir_build_stmt(proc, pa->body);
@@ -6735,13 +6762,12 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
ir_emit_comment(proc, str_lit("PushContext"));
ir_open_scope(proc);
- irValue *context_ptr = ir_find_global_variable(proc, str_lit("__context"));
- irValue *prev_context = ir_add_local_generated(proc, t_context);
- ir_emit_store(proc, prev_context, ir_emit_load(proc, context_ptr));
-
- ir_add_defer_instr(proc, proc->scope_index, ir_instr_store(proc, context_ptr, ir_emit_load(proc, prev_context), false));
+ irValue *prev = ir_find_or_generate_context_ptr(proc);
+ irValue *next = ir_add_local_generated(proc, t_context);
+ array_add(&proc->context_stack, next);
+ defer (array_pop(&proc->context_stack));
- ir_emit_store(proc, context_ptr, ir_build_expr(proc, pc->expr));
+ ir_emit_store(proc, next, ir_build_expr(proc, pc->expr));
ir_build_stmt(proc, pc->body);
@@ -6785,12 +6811,14 @@ void ir_number_proc_registers(irProcedure *proc) {
}
void ir_begin_procedure_body(irProcedure *proc) {
+ gbAllocator a = proc->module->allocator;
array_add(&proc->module->procs, proc);
array_init(&proc->blocks, heap_allocator());
array_init(&proc->defer_stmts, heap_allocator());
array_init(&proc->children, heap_allocator());
array_init(&proc->branch_blocks, heap_allocator());
+ array_init(&proc->context_stack, heap_allocator());
DeclInfo *decl = decl_info_of_entity(proc->module->info, proc->entity);
if (decl != NULL) {
@@ -6808,7 +6836,6 @@ void ir_begin_procedure_body(irProcedure *proc) {
if (proc->type->Proc.return_by_pointer) {
// NOTE(bill): this must be the first parameter stored
- gbAllocator a = proc->module->allocator;
Type *ptr_type = make_type_pointer(a, reduce_tuple_to_single_type(proc->type->Proc.results));
Entity *e = make_entity_param(a, NULL, make_token_ident(str_lit("agg.result")), ptr_type, false, false);
e->flags |= EntityFlag_Sret | EntityFlag_NoAlias;
@@ -6848,6 +6875,13 @@ void ir_begin_procedure_body(irProcedure *proc) {
}
+ if (proc->type->Proc.calling_convention == ProcCC_Odin) {
+ Entity *e = make_entity_param(a, NULL, make_token_ident(str_lit("__.context_ptr")), t_context_ptr, false, false);
+ e->flags |= EntityFlag_NoAlias;
+ irValue *param = ir_value_param(a, proc, e, e->type);
+ ir_module_add_value(proc->module, e, param);
+ array_add(&proc->context_stack, param);
+ }
}
@@ -7222,6 +7256,9 @@ void ir_gen_tree(irGen *s) {
}
}
+ { // Add global default context
+ m->global_default_context = ir_add_global_generated(m, t_context, NULL);
+ }
struct irGlobalVariable {
irValue *var, *init;
DeclInfo *decl;
@@ -7478,7 +7515,7 @@ void ir_gen_tree(irGen *s) {
String name = str_lit(IR_STARTUP_RUNTIME_PROC_NAME);
Type *proc_type = make_type_proc(a, gb_alloc_item(a, Scope),
NULL, 0,
- NULL, 0, false, ProcCC_Odin);
+ NULL, 0, false, ProcCC_Contextless);
AstNode *body = gb_alloc_item(a, AstNode);
Entity *e = make_entity_procedure(a, NULL, make_token_ident(name), proc_type, 0);
irValue *p = ir_value_procedure(a, m, e, proc_type, NULL, body, name);
@@ -7492,6 +7529,12 @@ void ir_gen_tree(irGen *s) {
ir_begin_procedure_body(proc);
+ {
+ irValue **args = gb_alloc_array(a, irValue *, 1);
+ args[0] = m->global_default_context;
+ ir_emit_global_call(proc, "__init_context", args, 1);
+ }
+
// TODO(bill): Should do a dependency graph do check which order to initialize them in?
for_array(i, global_variables) {
irGlobalVariable *var = &global_variables[i];
diff --git a/src/ir_print.cpp b/src/ir_print.cpp
index c39fc6acf..a3af21b6d 100644
--- a/src/ir_print.cpp
+++ b/src/ir_print.cpp
@@ -199,6 +199,12 @@ void ir_print_proc_type_without_pointer(irFileBuffer *f, irModule *m, Type *t) {
ir_print_type(f, m, t->Proc.abi_compat_params[i]);
}
}
+ if (t->Proc.calling_convention == ProcCC_Odin) {
+ if (param_count > 0) {
+ ir_fprintf(f, ", ");
+ }
+ ir_print_type(f, m, t_context_ptr);
+ }
ir_fprintf(f, ")");
}
@@ -737,10 +743,11 @@ void ir_print_value(irFileBuffer *f, irModule *m, irValue *value, Type *type_hin
void ir_print_calling_convention(irFileBuffer *f, irModule *m, ProcCallingConvention cc) {
switch (cc) {
- case ProcCC_Odin: ir_fprintf(f, ""); break;
- case ProcCC_C: ir_fprintf(f, "ccc "); break;
- case ProcCC_Std: ir_fprintf(f, "cc 64 "); break;
- case ProcCC_Fast: ir_fprintf(f, "cc 65 "); break;
+ case ProcCC_Odin: ir_fprintf(f, ""); break;
+ case ProcCC_Contextless: ir_fprintf(f, ""); break;
+ case ProcCC_C: ir_fprintf(f, "ccc "); break;
+ case ProcCC_Std: ir_fprintf(f, "cc 64 "); break;
+ case ProcCC_Fast: ir_fprintf(f, "cc 65 "); break;
default: GB_PANIC("unknown calling convention: %d", cc);
}
}
@@ -1261,8 +1268,6 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
if (call->arg_count > 0) {
- Type *proc_type = base_type(ir_type(call->value));
- GB_ASSERT(proc_type->kind == Type_Proc);
TypeTuple *params = &proc_type->Proc.params->Tuple;
if (proc_type->Proc.c_vararg) {
isize i = 0;
@@ -1293,7 +1298,9 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
ir_print_value(f, m, arg, t);
}
} else {
- for (isize i = 0; i < call->arg_count; i++) {
+ GB_ASSERT(call->arg_count == params->variable_count);
+ isize param_count = params->variable_count;
+ for (isize i = 0; i < param_count; i++) {
Entity *e = params->variables[i];
GB_ASSERT(e != NULL);
irValue *arg = call->args[i];
@@ -1310,6 +1317,14 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
}
}
}
+ if (proc_type->Proc.calling_convention == ProcCC_Odin) {
+ if (proc_type->Proc.param_count > 0) {
+ ir_fprintf(f, ", ");
+ }
+ ir_print_type(f, m, t_context_ptr);
+ ir_fprintf(f, " noalias nonnull");
+ ir_print_value(f, m, call->context_ptr, t_context_ptr);
+ }
ir_fprintf(f, ")\n");
} break;
@@ -1538,7 +1553,7 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) {
if (param_count > 0) {
TypeTuple *params = &proc_type->params->Tuple;
- for (isize i = 0; i < params->variable_count; i++) {
+ for (isize i = 0; i < param_count; i++) {
Entity *e = params->variables[i];
Type *original_type = e->type;
Type *abi_type = proc_type->abi_compat_params[i];
@@ -1564,6 +1579,13 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) {
}
}
}
+ if (proc_type->calling_convention == ProcCC_Odin) {
+ if (param_count > 0) {
+ ir_fprintf(f, ", ");
+ }
+ ir_print_type(f, m, t_context_ptr);
+ ir_fprintf(f, " noalias nonnull %%__.context_ptr");
+ }
ir_fprintf(f, ") ");
diff --git a/src/parser.cpp b/src/parser.cpp
index d09db81d2..1b1bfcdaf 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -91,11 +91,12 @@ enum ProcTag {
};
enum ProcCallingConvention {
- ProcCC_Invalid = 0,
- ProcCC_Odin = 1,
- ProcCC_C = 2,
- ProcCC_Std = 3,
- ProcCC_Fast = 4,
+ ProcCC_Invalid = 0,
+ ProcCC_Odin = 1,
+ ProcCC_Contextless = 2,
+ ProcCC_C = 3,
+ ProcCC_Std = 4,
+ ProcCC_Fast = 5,
};
enum VarDeclFlag {
@@ -2070,14 +2071,18 @@ void parse_proc_tags(AstFile *f, u64 *tags, String *link_name, ProcCallingConven
ELSE_IF_ADD_TAG(no_bounds_check)
ELSE_IF_ADD_TAG(inline)
ELSE_IF_ADD_TAG(no_inline)
- // ELSE_IF_ADD_TAG(dll_import)
- // ELSE_IF_ADD_TAG(dll_export)
else if (tag_name == "cc_odin") {
if (cc == ProcCC_Invalid) {
cc = ProcCC_Odin;
} else {
syntax_error(tag_expr, "Multiple calling conventions for procedure type");
}
+ } else if (tag_name == "cc_contextless") {
+ if (cc == ProcCC_Invalid) {
+ cc = ProcCC_Contextless;
+ } else {
+ syntax_error(tag_expr, "Multiple calling conventions for procedure type");
+ }
} else if (tag_name == "cc_c") {
if (cc == ProcCC_Invalid) {
cc = ProcCC_C;