aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGinger Bill <bill@gingerbill.org>2017-04-16 10:38:42 +0100
committerGinger Bill <bill@gingerbill.org>2017-04-16 10:38:42 +0100
commitabb9930725c10d8bf8cb5560bca9afe6aad204e1 (patch)
tree812ffced8e15d7e6615d4425b9670d6d4a3ece0c /src
parent169310a9f61f3d9a9d420fd3a73fe3115d995595 (diff)
IR emit C ABI compatible types for calling conventions (Only for x86/amd64 like processors at the moment)
Diffstat (limited to 'src')
-rw-r--r--src/check_expr.c58
-rw-r--r--src/ir.c101
-rw-r--r--src/ir_print.c54
-rw-r--r--src/types.c2
4 files changed, 176 insertions, 39 deletions
diff --git a/src/check_expr.c b/src/check_expr.c
index 1dba6dbbd..9d4eb0905 100644
--- a/src/check_expr.c
+++ b/src/check_expr.c
@@ -1014,6 +1014,50 @@ Type *check_get_results(Checker *c, Scope *scope, AstNode *_results) {
return tuple;
}
+Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type) {
+ Type *new_type = original_type;
+ // NOTE(bill): Changing the passing parameter value type is to match C's ABI
+ // IMPORTANT TODO(bill): This only matches the ABI on MSVC at the moment
+ Type *bt = core_type(original_type);
+ switch (bt->kind) {
+ // Okay to pass by value
+ // Especially the only Odin types
+ case Type_Basic: break;
+ case Type_Pointer: break;
+ case Type_Proc: break; // NOTE(bill): Just a pointer
+
+ // Odin only types
+ case Type_Slice:
+ case Type_DynamicArray:
+ case Type_Map:
+ break;
+
+ // Odin specific
+ case Type_Array:
+ case Type_Vector:
+ // Could be in C too
+ case Type_Record: {
+ i64 size = type_size_of(a, original_type);
+ switch (8*size) {
+ case 8: new_type = t_u8; break;
+ case 16: new_type = t_u16; break;
+ case 32: new_type = t_u32; break;
+ case 64: new_type = t_u64; break;
+ default:
+ // NOTE(bill): It could be an empty struct that is passed
+ // and if that is the case, no need to pass by pointer
+ // (I think..)
+ if (size > 0) {
+ new_type = make_type_pointer(a, original_type);
+ }
+ break;
+ }
+ } break;
+ }
+
+ return new_type;
+}
+
void check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node) {
ast_node(pt, ProcType, proc_type_node);
@@ -1034,6 +1078,20 @@ void check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node) {
type->Proc.result_count = result_count;
type->Proc.variadic = variadic;
type->Proc.calling_convention = pt->calling_convention;
+
+
+ type->Proc.abi_compat_params = gb_alloc_array(c->allocator, Type *, param_count);
+ for (isize i = 0; i < param_count; i++) {
+ Type *original_type = type->Proc.params->Tuple.variables[i]->type;
+ Type *new_type = type_to_abi_compat_param_type(c->allocator, original_type);
+ type->Proc.abi_compat_params[i] = new_type;
+ }
+
+ // NOTE(bill): The types are the same
+ type->Proc.abi_compat_results = gb_alloc_array(c->allocator, Type *, result_count);
+ for (isize i = 0; i < result_count; i++) {
+ type->Proc.abi_compat_results[i] = type->Proc.results->Tuple.variables[i]->type;
+ }
}
diff --git a/src/ir.c b/src/ir.c
index e76503af2..446343c28 100644
--- a/src/ir.c
+++ b/src/ir.c
@@ -351,11 +351,20 @@ typedef struct irValueGlobal {
bool is_unnamed_addr;
} irValueGlobal;
+
+typedef enum irParamPasskind {
+ irParamPass_Value, // Pass by value
+ irParamPass_Pointer, // Pass as a pointer rather than by value
+ irParamPass_Integer, // Pass as an integer of the same size
+} irParamPasskind;
+
typedef struct irValueParam {
- irProcedure *parent;
- Entity * entity;
- Type * type;
- irValueArray referrers;
+ irParamPasskind kind;
+ irProcedure * parent;
+ Entity * entity;
+ Type * type;
+ Type * original_type;
+ irValueArray referrers;
} irValueParam;
typedef struct irValue {
@@ -755,11 +764,23 @@ irValue *ir_value_global(gbAllocator a, Entity *e, irValue *value) {
array_init(&v->Global.referrers, heap_allocator()); // TODO(bill): Replace heap allocator here
return v;
}
-irValue *ir_value_param(gbAllocator a, irProcedure *parent, Entity *e) {
+irValue *ir_value_param(gbAllocator a, irProcedure *parent, Entity *e, Type *abi_type) {
irValue *v = ir_alloc_value(a, irValue_Param);
- v->Param.parent = parent;
- v->Param.entity = e;
- v->Param.type = e->type;
+ v->Param.kind = irParamPass_Value;
+ v->Param.parent = parent;
+ v->Param.entity = e;
+ v->Param.original_type = e->type;
+ v->Param.type = abi_type;
+
+ if (abi_type != e->type) {
+ if (is_type_pointer(abi_type)) {
+ v->Param.kind = irParamPass_Pointer;
+ } else if (is_type_integer(abi_type)) {
+ v->Param.kind = irParamPass_Integer;
+ } else {
+ GB_PANIC("Invalid abi type pass kind");
+ }
+ }
array_init(&v->Param.referrers, heap_allocator()); // TODO(bill): Replace heap allocator here
return v;
}
@@ -1280,16 +1301,30 @@ irValue *ir_add_local_generated(irProcedure *proc, Type *type) {
}
-irValue *ir_add_param(irProcedure *proc, Entity *e, AstNode *expr) {
- irValue *v = ir_value_param(proc->module->allocator, proc, e);
-#if 1
- irValue *l = ir_add_local(proc, e, expr);
- ir_emit_store(proc, l, v);
+irValue *ir_add_param(irProcedure *proc, Entity *e, AstNode *expr, Type *abi_type) {
+ irValue *v = ir_value_param(proc->module->allocator, proc, e, abi_type);
+ irValueParam *p = &v->Param;
-#else
- ir_module_add_value(proc->module, e, v);
-#endif
- return v;
+ switch (p->kind) {
+ case irParamPass_Value: {
+ irValue *l = ir_add_local(proc, e, expr);
+ ir_emit_store(proc, l, v);
+ return v;
+ }
+ case irParamPass_Pointer: {
+ ir_module_add_value(proc->module, e, v);
+ return ir_emit_load(proc, v);
+ }
+ case irParamPass_Integer: {
+ irValue *l = ir_add_local(proc, e, expr);
+ irValue *iptr = ir_emit_conv(proc, l, make_type_pointer(proc->module->allocator, p->type));
+ ir_emit_store(proc, iptr, v);
+ return ir_emit_load(proc, l);
+ }
+ }
+
+ GB_PANIC("Unreachable");
+ return NULL;
}
@@ -1383,11 +1418,36 @@ irValue *ir_emit_comment(irProcedure *p, String text) {
return ir_emit(p, ir_instr_comment(p, text));
}
+irValue *ir_copy_value_to_ptr(irProcedure *proc, irValue *val) {
+ Type *t = ir_type(val);
+ irValue *ptr = ir_add_local_generated(proc, t);
+ ir_emit_store(proc, ptr, val);
+ return ptr;
+}
+
+irValue *ir_emit_bitcast(irProcedure *proc, irValue *data, Type *type) {
+ return ir_emit(proc, ir_instr_conv(proc, irConv_bitcast, data, ir_type(data), type));
+}
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;
+
+ isize param_count = pt->Proc.param_count;
+ GB_ASSERT(param_count == arg_count);
+ for (isize i = 0; i < param_count; i++) {
+ Type *original_type = pt->Proc.params->Tuple.variables[i]->type;
+ Type *new_type = pt->Proc.abi_compat_params[i];
+ if (original_type != new_type) {
+ if (is_type_pointer(new_type)) {
+ args[i] = ir_copy_value_to_ptr(p, args[i]);
+ } else if (is_type_integer(new_type)) {
+ args[i] = ir_emit_bitcast(p, args[i], new_type);
+ }
+ }
+ }
+
return ir_emit(p, ir_instr_call(p, value, args, arg_count, results));
}
@@ -1475,9 +1535,7 @@ void ir_emit_startup_runtime(irProcedure *proc) {
ir_emit(proc, ir_alloc_instr(proc, irInstr_StartupRuntime));
}
-irValue *ir_emit_bitcast(irProcedure *proc, irValue *data, Type *type) {
- return ir_emit(proc, ir_instr_conv(proc, irConv_bitcast, data, ir_type(data), type));
-}
+
irValue *ir_emit_struct_ep(irProcedure *proc, irValue *s, i32 index);
@@ -6436,9 +6494,10 @@ void ir_begin_procedure_body(irProcedure *proc) {
AstNode *name = field->names.e[q_index++];
Entity *e = params->variables[i];
+ Type *abi_type = proc->type->Proc.abi_compat_params[i];
if (!str_eq(e->token.string, str_lit("")) &&
!str_eq(e->token.string, str_lit("_"))) {
- irValue *param = ir_add_param(proc, e, name);
+ irValue *param = ir_add_param(proc, e, name, abi_type);
array_add(&proc->params, param);
}
}
diff --git a/src/ir_print.c b/src/ir_print.c
index 560983537..a80cf73c9 100644
--- a/src/ir_print.c
+++ b/src/ir_print.c
@@ -135,6 +135,28 @@ void ir_print_encoded_global(irFileBuffer *f, String name, bool remove_prefix) {
ir_print_escape_string(f, name, true);
}
+void ir_print_type(irFileBuffer *f, irModule *m, Type *t);
+
+void ir_print_proc_results(irFileBuffer *f, irModule *m, Type *t) {
+ GB_ASSERT(is_type_proc(t));
+ t = base_type(t);
+ isize result_count = t->Proc.result_count;
+ if (result_count == 0) {
+ ir_fprintf(f, "void");
+ } else if (result_count == 1) {
+ ir_print_type(f, m, t->Proc.abi_compat_results[0]);
+ } else {
+ ir_fprintf(f, "{");
+ for (isize i = 0; i < result_count; i++) {
+ if (i > 0) {
+ ir_fprintf(f, ", ");
+ }
+ ir_print_type(f, m, t->Proc.abi_compat_results[i]);
+ }
+ ir_fprintf(f, "}");
+ }
+}
+
void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
i64 word_bits = 8*build_context.word_size;
@@ -273,18 +295,15 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
}
return;
case Type_Proc: {
- if (t->Proc.result_count == 0) {
- ir_fprintf(f, "void");
- } else {
- ir_print_type(f, m, t->Proc.results);
- }
+ isize param_count = t->Proc.param_count;
+ isize result_count = t->Proc.result_count;
+ ir_print_proc_results(f, m, t);
ir_fprintf(f, " (");
- TypeTuple *params = &t->Proc.params->Tuple;
- for (isize i = 0; i < t->Proc.param_count; i++) {
+ for (isize i = 0; i < param_count; i++) {
if (i > 0) {
ir_fprintf(f, ", ");
}
- ir_print_type(f, m, params->variables[i]->type);
+ ir_print_type(f, m, t->Proc.abi_compat_params[i]);
}
ir_fprintf(f, ")*");
} return;
@@ -1176,7 +1195,7 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
ir_fprintf(f, "call ");
ir_print_calling_convention(f, m, proc_type->Proc.calling_convention);
if (result_type) {
- ir_print_type(f, m, result_type);
+ ir_print_proc_results(f, m, proc_type);
} else {
ir_fprintf(f, "void");
}
@@ -1192,7 +1211,7 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
for (isize i = 0; i < call->arg_count; i++) {
Entity *e = params->variables[i];
GB_ASSERT(e != NULL);
- Type *t = e->type;
+ Type *t = proc_type->Proc.abi_compat_params[i];
if (i > 0) {
ir_fprintf(f, ", ");
}
@@ -1405,12 +1424,9 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) {
ir_print_calling_convention(f, m, proc_type->calling_convention);
- if (proc_type->result_count == 0) {
- ir_fprintf(f, "void");
- } else {
- ir_print_type(f, m, proc_type->results);
- }
-
+ isize param_count = proc_type->param_count;
+ isize result_count = proc_type->result_count;
+ ir_print_proc_results(f, m, proc->type);
ir_fprintf(f, " ");
// #ifndef GB_SYSTEM_WINDOWS
@@ -1423,14 +1439,16 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) {
ir_fprintf(f, "(");
- if (proc_type->param_count > 0) {
+ if (param_count > 0) {
TypeTuple *params = &proc_type->params->Tuple;
for (isize i = 0; i < params->variable_count; i++) {
Entity *e = params->variables[i];
+ Type *original_type = e->type;
+ Type *abi_type = proc_type->abi_compat_params[i];
if (i > 0) {
ir_fprintf(f, ", ");
}
- ir_print_type(f, m, e->type);
+ ir_print_type(f, m, abi_type);
if (e->flags&EntityFlag_NoAlias) {
ir_fprintf(f, " noalias");
}
diff --git a/src/types.c b/src/types.c
index 02c01d4c9..0dc91f246 100644
--- a/src/types.c
+++ b/src/types.c
@@ -132,6 +132,8 @@ typedef struct TypeRecord {
Type * results; /* Type_Tuple */ \
i32 param_count; \
i32 result_count; \
+ Type **abi_compat_params; \
+ Type **abi_compat_results; \
bool variadic; \
ProcCallingConvention calling_convention; \
}) \