Browse Source

Try a different ABI type for return values on Windows

Ginger Bill 8 years ago
parent
commit
06185e1769
4 changed files with 101 additions and 18 deletions
  1. 64 4
      src/check_expr.c
  2. 22 5
      src/ir.c
  3. 14 8
      src/ir_print.c
  4. 1 1
      src/types.c

+ 64 - 4
src/check_expr.c

@@ -1154,6 +1154,69 @@ Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type) {
 	return new_type;
 }
 
+Type *reduce_tuple_to_single_type(Type *original_type) {
+	if (original_type != NULL) {
+		Type *t = core_type(original_type);
+		if (t->kind == Type_Tuple && t->Tuple.variable_count == 1) {
+			return t->Tuple.variables[0]->type;
+		}
+	}
+	return original_type;
+}
+
+Type *type_to_abi_compat_result_type(gbAllocator a, Type *original_type) {
+	Type *new_type = original_type;
+	if (new_type == NULL) {
+		return NULL;
+	}
+	GB_ASSERT(is_type_tuple(original_type));
+
+
+
+	if (str_eq(build_context.ODIN_OS, str_lit("windows"))) {
+		Type *bt = core_type(reduce_tuple_to_single_type(original_type));
+		// NOTE(bill): This is just reversed engineered from LLVM IR output
+		switch (bt->kind) {
+		// Okay to pass by value
+		// Especially the only Odin types
+		case Type_Pointer: break;
+		case Type_Proc:    break; // NOTE(bill): Just a pointer
+		case Type_Basic:   break;
+
+
+		default: {
+			i64 align = type_align_of(a, original_type);
+			i64 size  = type_size_of(a, original_type);
+			switch (8*size) {
+#if 1
+			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;
+#endif
+			}
+		} break;
+		}
+	} else if (str_eq(build_context.ODIN_OS, str_lit("linux"))) {
+
+	} else {
+		// IMPORTANT TODO(bill): figure out the ABI settings for Linux, OSX etc. for
+		// their architectures
+	}
+
+	if (new_type != original_type) {
+		Type *tuple = make_type_tuple(a);
+		tuple->Tuple.variable_count = 1;
+		tuple->Tuple.variables = gb_alloc_array(a, Entity *, 1);
+		tuple->Tuple.variables[0] = make_entity_param(a, original_type->Tuple.variables[0]->scope, empty_token, new_type, false, false);
+		new_type = tuple;
+	}
+
+
+	// return reduce_tuple_to_single_type(new_type);
+	return new_type;
+}
+
 
 void check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node) {
 	ast_node(pt, ProcType, proc_type_node);
@@ -1184,10 +1247,7 @@ void check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node) {
 	}
 
 	// 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;
-	}
+	type->Proc.abi_compat_result_type = type_to_abi_compat_result_type(c->allocator, type->Proc.results);
 }
 
 

+ 22 - 5
src/ir.c

@@ -1489,7 +1489,14 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, irValue **args, isize arg_
 		}
 	}
 
-	return ir_emit(p, ir_instr_call(p, value, args, arg_count, results));
+	Type *abi_rt = pt->Proc.abi_compat_result_type;
+	Type *rt = reduce_tuple_to_single_type(results);
+
+	irValue *result = ir_emit(p, ir_instr_call(p, value, args, arg_count, abi_rt));
+	if (abi_rt != results) {
+		result = ir_emit_transmute(p, result, rt);
+	}
+	return result;
 }
 
 irValue *ir_emit_global_call(irProcedure *proc, char *name_, irValue **args, isize arg_count) {
@@ -1547,6 +1554,12 @@ void ir_emit_unreachable(irProcedure *proc) {
 
 void ir_emit_return(irProcedure *proc, irValue *v) {
 	ir_emit_defer_stmts(proc, irDeferExit_Return, NULL);
+
+	Type *abi_rt = proc->type->Proc.abi_compat_result_type;
+	if (abi_rt != proc->type->Proc.results) {
+		v = ir_emit_transmute(proc, v, abi_rt);
+	}
+
 	ir_emit(proc, ir_instr_return(proc, v));
 }
 
@@ -2970,7 +2983,9 @@ irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) {
 	gb_printf_err("Not Identical %s != %s\n", type_to_string(src), type_to_string(dst));
 
 
-	GB_PANIC("Invalid type conversion: `%s` to `%s`", type_to_string(src_type), type_to_string(t));
+	GB_PANIC("Invalid type conversion: `%s` to `%s` for procedure `%.*s`",
+	         type_to_string(src_type), type_to_string(t),
+	         LIT(proc->name));
 
 	return NULL;
 }
@@ -3019,10 +3034,11 @@ irValue *ir_emit_transmute(irProcedure *proc, irValue *value, Type *t) {
 
 	Type *src = base_type(src_type);
 	Type *dst = base_type(t);
+#if 0
 	if (are_types_identical(t, src_type)) {
 		return value;
 	}
-
+#endif
 	irModule *m = proc->module;
 
 	i64 sz = type_size_of(m->allocator, src);
@@ -3032,7 +3048,7 @@ irValue *ir_emit_transmute(irProcedure *proc, irValue *value, Type *t) {
 
 	if (ir_is_type_aggregate(src) || ir_is_type_aggregate(dst)) {
 		irValue *s = ir_address_from_load_or_generate_local(proc, value);
-		irValue *d = ir_emit_bitcast(proc, s, make_type_pointer(m->allocator, dst));
+		irValue *d = ir_emit_bitcast(proc, s, make_type_pointer(m->allocator, t));
 		return ir_emit_load(proc, d);
 	}
 
@@ -5214,7 +5230,7 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
 						elem = fv->value;
 					} else {
 						TypeAndValue tav = type_and_value_of_expr(proc->module->info, elem);
-						Selection sel = lookup_field(proc->module->allocator, bt, st->fields_in_src_order[field_index]->token.string, false);
+						Selection sel = lookup_field_from_index(proc->module->allocator, bt, st->fields_in_src_order[field_index]->Variable.field_index);
 						index = sel.index.e[0];
 					}
 
@@ -6061,6 +6077,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
 
 			gb_temp_arena_memory_end(tmp);
 		}
+
 		ir_emit_return(proc, v);
 
 	case_end;

+ 14 - 8
src/ir_print.c

@@ -144,17 +144,23 @@ void ir_print_proc_results(irFileBuffer *f, irModule *m, 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, ", ");
+		Type *rt = t->Proc.abi_compat_result_type;
+		if (!is_type_tuple(rt)) {
+			ir_print_type(f, m, rt);
+		} else if (rt->Tuple.variable_count == 1) {
+			ir_print_type(f, m, rt->Tuple.variables[0]->type);
+		} else {
+			isize count = rt->Tuple.variable_count;
+			ir_fprintf(f, "{");
+			for (isize i = 0; i < count; i++) {
+				if (i > 0) {
+					ir_fprintf(f, ", ");
+				}
+				ir_print_type(f, m, rt->Tuple.variables[i]->type);
 			}
-			ir_print_type(f, m, t->Proc.abi_compat_results[i]);
+			ir_fprintf(f, "}");
 		}
-		ir_fprintf(f, "}");
 	}
 }
 

+ 1 - 1
src/types.c

@@ -138,7 +138,7 @@ typedef struct TypeRecord {
 		i32    param_count;                               \
 		i32    result_count;                              \
 		Type **abi_compat_params;                         \
-		Type **abi_compat_results;                        \
+		Type * abi_compat_result_type;                    \
 		bool   variadic;                                  \
 		bool   require_results;                           \
 		ProcCallingConvention calling_convention;         \