Browse Source

Mock out `cg_emit_conv`

gingerBill 2 years ago
parent
commit
d2d243cca8
5 changed files with 562 additions and 40 deletions
  1. 2 2
      src/tilde_backend.hpp
  2. 415 29
      src/tilde_expr.cpp
  3. 140 9
      src/tilde_proc.cpp
  4. 4 0
      src/tilde_stmt.cpp
  5. 1 0
      src/types.cpp

+ 2 - 2
src/tilde_backend.hpp

@@ -9,8 +9,8 @@
 
 #define TB_TYPE_F16    TB_DataType{ { TB_INT, 0, 16 } }
 #define TB_TYPE_I128   TB_DataType{ { TB_INT, 0, 128 } }
-#define TB_TYPE_INT    TB_TYPE_INTN(cast(u16)build_context.int_size)
-#define TB_TYPE_INTPTR TB_TYPE_INTN(cast(u16)build_context.ptr_size)
+#define TB_TYPE_INT    TB_TYPE_INTN(cast(u16)(8*build_context.int_size))
+#define TB_TYPE_INTPTR TB_TYPE_INTN(cast(u16)(8*build_context.ptr_size))
 
 #if defined(GB_SYSTEM_WINDOWS)
 	#pragma warning(pop)

+ 415 - 29
src/tilde_expr.cpp

@@ -115,16 +115,19 @@ gb_internal cgValue cg_correct_endianness(cgProcedure *p, cgValue value) {
 	return value;
 }
 
-gb_internal cgValue cg_emit_conv(cgProcedure *p, cgValue value, Type *type) {
-	// TODO(bill): cg_emit_conv
-	return value;
-}
-
 gb_internal cgValue cg_emit_transmute(cgProcedure *p, cgValue value, Type *type) {
 	GB_ASSERT(type_size_of(value.type) == type_size_of(type));
 
 	value = cg_flatten_value(p, value);
 
+	if (are_types_identical(value.type, type)) {
+		return value;
+	}
+	if (are_types_identical(core_type(value.type), core_type(type))) {
+		value.type = type;
+		return value;
+	}
+
 	i64 src_align = type_align_of(value.type);
 	i64 dst_align = type_align_of(type);
 
@@ -153,6 +156,380 @@ gb_internal cgValue cg_emit_transmute(cgProcedure *p, cgValue value, Type *type)
 	return value;
 
 }
+gb_internal cgValue cg_emit_byte_swap(cgProcedure *p, cgValue value, Type *end_type) {
+	GB_ASSERT(type_size_of(value.type) == type_size_of(end_type));
+
+	if (type_size_of(value.type) < 2) {
+		return value;
+	}
+
+	if (is_type_float(value.type)) {
+		i64 sz = type_size_of(value.type);
+		Type *integer_type = nullptr;
+		switch (sz) {
+		case 2: integer_type = t_u16; break;
+		case 4: integer_type = t_u32; break;
+		case 8: integer_type = t_u64; break;
+		}
+		GB_ASSERT(integer_type != nullptr);
+		value = cg_emit_transmute(p, value, integer_type);
+	}
+
+	GB_ASSERT(value.kind == cgValue_Value);
+
+	value.node = tb_inst_bswap(p->func, value.node);
+	return cg_emit_transmute(p, value, end_type);
+}
+
+gb_internal cgValue cg_emit_conv(cgProcedure *p, cgValue value, Type *t) {
+	t = reduce_tuple_to_single_type(t);
+
+	value = cg_flatten_value(p, value);
+
+	Type *src_type = value.type;
+	if (are_types_identical(t, src_type)) {
+		return value;
+	}
+
+	Type *src = core_type(src_type);
+	Type *dst = core_type(t);
+	GB_ASSERT(src != nullptr);
+	GB_ASSERT(dst != nullptr);
+
+	if (are_types_identical(src, dst)) {
+		return cg_emit_transmute(p, value, t);
+	}
+
+	TB_DataType st = cg_data_type(src);
+	TB_DataType dt = cg_data_type(t);
+
+	if (is_type_integer(src) && is_type_integer(dst)) {
+		GB_ASSERT(src->kind == Type_Basic &&
+		          dst->kind == Type_Basic);
+		GB_ASSERT(value.kind == cgValue_Value);
+
+		i64 sz = type_size_of(default_type(src));
+		i64 dz = type_size_of(default_type(dst));
+
+		if (sz == dz) {
+			if (dz > 1 && !types_have_same_internal_endian(src, dst)) {
+				return cg_emit_byte_swap(p, value, t);
+			}
+			value.type = t;
+			return value;
+		}
+
+		if (sz > 1 && is_type_different_to_arch_endianness(src)) {
+			Type *platform_src_type = integer_endian_type_to_platform_type(src);
+			value = cg_emit_byte_swap(p, value, platform_src_type);
+		}
+
+		TB_Node* (*op)(TB_Function* f, TB_Node* src, TB_DataType dt) = tb_inst_trunc;
+
+		if (dz < sz) {
+			op = tb_inst_trunc;
+		} else if (dz == sz) {
+			op = tb_inst_bitcast;
+		} else if (dz > sz) {
+			op = is_type_unsigned(src) ? tb_inst_zxt : tb_inst_sxt; // zero extent
+		}
+
+		if (dz > 1 && is_type_different_to_arch_endianness(dst)) {
+			Type *platform_dst_type = integer_endian_type_to_platform_type(dst);
+
+			cgValue res = cg_value(op(p->func, value.node, cg_data_type(platform_dst_type)), platform_dst_type);
+			return cg_emit_byte_swap(p, res, t);
+		} else {
+			return cg_value(op(p->func, value.node, dt), t);
+		}
+	}
+
+	// boolean -> boolean/integer
+	if (is_type_boolean(src) && (is_type_boolean(dst) || is_type_integer(dst))) {
+		TB_Node *v = tb_inst_cmp_ne(p->func, value.node, tb_inst_uint(p->func, st, 0));
+		return cg_value(tb_inst_zxt(p->func, v, dt), t);
+	}
+
+	// integer -> boolean
+	if (is_type_integer(src) && is_type_boolean(dst)) {
+		TB_Node *v = tb_inst_cmp_ne(p->func, value.node, tb_inst_uint(p->func, st, 0));
+		return cg_value(tb_inst_zxt(p->func, v, dt), t);
+	}
+
+	if (is_type_cstring(src) && is_type_u8_ptr(dst)) {
+		return cg_emit_transmute(p, value, dst);
+	}
+	if (is_type_u8_ptr(src) && is_type_cstring(dst)) {
+		return cg_emit_transmute(p, value, dst);
+	}
+	if (is_type_cstring(src) && is_type_u8_multi_ptr(dst)) {
+		return cg_emit_transmute(p, value, dst);
+	}
+	if (is_type_u8_multi_ptr(src) && is_type_cstring(dst)) {
+		return cg_emit_transmute(p, value, dst);
+	}
+	if (is_type_cstring(src) && is_type_rawptr(dst)) {
+		return cg_emit_transmute(p, value, dst);
+	}
+	if (is_type_rawptr(src) && is_type_cstring(dst)) {
+		return cg_emit_transmute(p, value, dst);
+	}
+
+
+	if (are_types_identical(src, t_cstring) && are_types_identical(dst, t_string)) {
+		GB_PANIC("TODO(bill): cstring_to_string call");
+		// TEMPORARY_ALLOCATOR_GUARD();
+		// lbValue c = lb_emit_conv(p, value, t_cstring);
+		// auto args = array_make<lbValue>(temporary_allocator(), 1);
+		// args[0] = c;
+		// lbValue s = lb_emit_runtime_call(p, "cstring_to_string", args);
+		// return lb_emit_conv(p, s, dst);
+	}
+
+	// float -> float
+	if (is_type_float(src) && is_type_float(dst)) {
+		i64 sz = type_size_of(src);
+		i64 dz = type_size_of(dst);
+
+		if (sz == 2 || dz == 2) {
+			GB_PANIC("TODO(bill): f16 conversions");
+		}
+
+
+		if (dz == sz) {
+			if (types_have_same_internal_endian(src, dst)) {
+				return cg_value(value.node, t);
+			} else {
+				return cg_emit_byte_swap(p, value, t);
+			}
+		}
+
+		if (is_type_different_to_arch_endianness(src) || is_type_different_to_arch_endianness(dst)) {
+			Type *platform_src_type = integer_endian_type_to_platform_type(src);
+			Type *platform_dst_type = integer_endian_type_to_platform_type(dst);
+			cgValue res = {};
+			res = cg_emit_conv(p, value, platform_src_type);
+			res = cg_emit_conv(p, res, platform_dst_type);
+			if (is_type_different_to_arch_endianness(dst)) {
+				res = cg_emit_byte_swap(p, res, t);
+			}
+			return cg_emit_conv(p, res, t);
+		}
+
+
+		if (dz >= sz) {
+			return cg_value(tb_inst_fpxt(p->func, value.node, dt), t);
+		}
+		return cg_value(tb_inst_trunc(p->func, value.node, dt), t);
+	}
+
+	if (is_type_complex(src) && is_type_complex(dst)) {
+		GB_PANIC("TODO(bill): complex -> complex");
+	}
+
+	if (is_type_quaternion(src) && is_type_quaternion(dst)) {
+		// @QuaternionLayout
+		GB_PANIC("TODO(bill): quaternion -> quaternion");
+	}
+	if (is_type_integer(src) && is_type_complex(dst)) {
+		GB_PANIC("TODO(bill): int -> complex");
+	}
+	if (is_type_float(src) && is_type_complex(dst)) {
+		GB_PANIC("TODO(bill): float -> complex");
+	}
+	if (is_type_integer(src) && is_type_quaternion(dst)) {
+		GB_PANIC("TODO(bill): int -> quaternion");
+	}
+	if (is_type_float(src) && is_type_quaternion(dst)) {
+		GB_PANIC("TODO(bill): float -> quaternion");
+	}
+	if (is_type_complex(src) && is_type_quaternion(dst)) {
+		GB_PANIC("TODO(bill): complex -> quaternion");
+	}
+
+
+	// float <-> integer
+	if (is_type_float(src) && is_type_integer(dst)) {
+		if (is_type_different_to_arch_endianness(src) || is_type_different_to_arch_endianness(dst)) {
+			Type *platform_src_type = integer_endian_type_to_platform_type(src);
+			Type *platform_dst_type = integer_endian_type_to_platform_type(dst);
+			cgValue res = {};
+			res = cg_emit_conv(p, value, platform_src_type);
+			res = cg_emit_conv(p, res, platform_dst_type);
+			return cg_emit_conv(p, res, t);
+		}
+
+		// if (is_type_integer_128bit(dst)) {
+		// 	TEMPORARY_ALLOCATOR_GUARD();
+
+		// 	auto args = array_make<lbValue>(temporary_allocator(), 1);
+		// 	args[0] = value;
+		// 	char const *call = "fixunsdfdi";
+		// 	if (is_type_unsigned(dst)) {
+		// 		call = "fixunsdfti";
+		// 	}
+		// 	lbValue res_i128 = lb_emit_runtime_call(p, call, args);
+		// 	return lb_emit_conv(p, res_i128, t);
+		// }
+
+		bool is_signed = !is_type_unsigned(dst);
+		return cg_value(tb_inst_float2int(p->func, value.node, dt, is_signed), t);
+	}
+	if (is_type_integer(src) && is_type_float(dst)) {
+		if (is_type_different_to_arch_endianness(src) || is_type_different_to_arch_endianness(dst)) {
+			Type *platform_src_type = integer_endian_type_to_platform_type(src);
+			Type *platform_dst_type = integer_endian_type_to_platform_type(dst);
+			cgValue res = {};
+			res = cg_emit_conv(p, value, platform_src_type);
+			res = cg_emit_conv(p, res, platform_dst_type);
+			if (is_type_different_to_arch_endianness(dst)) {
+				res = cg_emit_byte_swap(p, res, t);
+			}
+			return cg_emit_conv(p, res, t);
+		}
+
+		// if (is_type_integer_128bit(src)) {
+		// 	TEMPORARY_ALLOCATOR_GUARD();
+
+		// 	auto args = array_make<lbValue>(temporary_allocator(), 1);
+		// 	args[0] = value;
+		// 	char const *call = "floattidf";
+		// 	if (is_type_unsigned(src)) {
+		// 		call = "floattidf_unsigned";
+		// 	}
+		// 	lbValue res_f64 = lb_emit_runtime_call(p, call, args);
+		// 	return lb_emit_conv(p, res_f64, t);
+		// }
+
+		bool is_signed = !is_type_unsigned(dst);
+		return cg_value(tb_inst_int2float(p->func, value.node, dt, is_signed), t);
+	}
+
+	if (is_type_simd_vector(dst)) {
+		GB_PANIC("TODO(bill): ? -> #simd vector");
+	}
+
+
+	// Pointer <-> uintptr
+	if (is_type_pointer(src) && is_type_uintptr(dst)) {
+		return cg_value(tb_inst_ptr2int(p->func, value.node, dt), t);
+	}
+	if (is_type_uintptr(src) && is_type_pointer(dst)) {
+		return cg_value(tb_inst_int2ptr(p->func, value.node), t);
+	}
+	if (is_type_multi_pointer(src) && is_type_uintptr(dst)) {
+		return cg_value(tb_inst_ptr2int(p->func, value.node, dt), t);
+	}
+	if (is_type_uintptr(src) && is_type_multi_pointer(dst)) {
+		return cg_value(tb_inst_int2ptr(p->func, value.node), t);
+	}
+
+	if (is_type_union(dst)) {
+		GB_PANIC("TODO(bill): ? -> union");
+	}
+
+	// NOTE(bill): This has to be done before 'Pointer <-> Pointer' as it's
+	// subtype polymorphism casting
+	if (check_is_assignable_to_using_subtype(src_type, t)) {
+		GB_PANIC("TODO(bill): ? -> subtyping");
+	}
+
+	// Pointer <-> Pointer
+	if (is_type_pointer(src) && is_type_pointer(dst)) {
+		return cg_value(tb_inst_bitcast(p->func, value.node, dt), t);
+	}
+	if (is_type_multi_pointer(src) && is_type_pointer(dst)) {
+		return cg_value(tb_inst_bitcast(p->func, value.node, dt), t);
+	}
+	if (is_type_pointer(src) && is_type_multi_pointer(dst)) {
+		return cg_value(tb_inst_bitcast(p->func, value.node, dt), t);
+	}
+	if (is_type_multi_pointer(src) && is_type_multi_pointer(dst)) {
+		return cg_value(tb_inst_bitcast(p->func, value.node, dt), t);
+	}
+
+	// proc <-> proc
+	if (is_type_proc(src) && is_type_proc(dst)) {
+		return cg_value(tb_inst_bitcast(p->func, value.node, dt), t);
+	}
+
+	// pointer -> proc
+	if (is_type_pointer(src) && is_type_proc(dst)) {
+		return cg_value(tb_inst_bitcast(p->func, value.node, dt), t);
+	}
+	// proc -> pointer
+	if (is_type_proc(src) && is_type_pointer(dst)) {
+		return cg_value(tb_inst_bitcast(p->func, value.node, dt), t);
+	}
+
+	// []byte/[]u8 <-> string
+	if (is_type_u8_slice(src) && is_type_string(dst)) {
+		return cg_emit_transmute(p, value, t);
+	}
+	if (is_type_string(src) && is_type_u8_slice(dst)) {
+		return cg_emit_transmute(p, value, t);
+	}
+
+	if (is_type_matrix(dst) && !is_type_matrix(src)) {
+		GB_PANIC("TODO(bill): !matrix -> matrix");
+	}
+
+	if (is_type_matrix(dst) && is_type_matrix(src)) {
+		GB_PANIC("TODO(bill): matrix -> matrix");
+	}
+
+	if (is_type_any(dst)) {
+		GB_PANIC("TODO(bill): ? -> any");
+	}
+
+	i64 src_sz = type_size_of(src);
+	i64 dst_sz = type_size_of(dst);
+
+	if (src_sz == dst_sz) {
+		// bit_set <-> integer
+		if (is_type_integer(src) && is_type_bit_set(dst)) {
+			cgValue v = cg_emit_conv(p, value, bit_set_to_int(dst));
+			return cg_emit_transmute(p, v, t);
+		}
+		if (is_type_bit_set(src) && is_type_integer(dst)) {
+			cgValue bs = cg_emit_transmute(p, value, bit_set_to_int(src));
+			return cg_emit_conv(p, bs, dst);
+		}
+
+		// typeid <-> integer
+		if (is_type_integer(src) && is_type_typeid(dst)) {
+			return cg_emit_transmute(p, value, dst);
+		}
+		if (is_type_typeid(src) && is_type_integer(dst)) {
+			return cg_emit_transmute(p, value, dst);
+		}
+	}
+
+
+	if (is_type_untyped(src)) {
+		if (is_type_string(src) && is_type_string(dst)) {
+			cgAddr result = cg_add_local(p, t, nullptr, false);
+			cg_addr_store(p, result, value);
+			return cg_addr_load(p, result);
+		}
+	}
+
+
+	gb_printf_err("%.*s\n", LIT(p->name));
+	gb_printf_err("cg_emit_conv: src -> dst\n");
+	gb_printf_err("Not Identical %s != %s\n", type_to_string(src_type), type_to_string(t));
+	gb_printf_err("Not Identical %s != %s\n", type_to_string(src), type_to_string(dst));
+	gb_printf_err("Not Identical %p != %p\n", src_type, t);
+	gb_printf_err("Not Identical %p != %p\n", src, dst);
+
+
+	GB_PANIC("Invalid type conversion: '%s' to '%s' for procedure '%.*s'",
+	         type_to_string(src_type), type_to_string(t),
+	         LIT(p->name));
+
+	return {};
+}
+
 
 
 gb_internal cgAddr cg_build_addr_slice_expr(cgProcedure *p, Ast *expr) {
@@ -227,30 +604,39 @@ gb_internal cgAddr cg_build_addr_slice_expr(cgProcedure *p, Ast *expr) {
 	}
 
 	case Type_MultiPointer: {
-		// lbAddr res = lb_add_local_generated(p, type_of_expr(expr), false);
-		// if (se->high == nullptr) {
-		// 	lbValue offset = base;
-		// 	LLVMValueRef indices[1] = {low.value};
-		// 	offset.value = LLVMBuildGEP2(p->builder, lb_type(p->module, offset.type->MultiPointer.elem), offset.value, indices, 1, "");
-		// 	lb_addr_store(p, res, offset);
-		// } else {
-		// 	low = lb_emit_conv(p, low, t_int);
-		// 	high = lb_emit_conv(p, high, t_int);
-
-		// 	lb_emit_multi_pointer_slice_bounds_check(p, se->open, low, high);
-
-		// 	LLVMValueRef indices[1] = {low.value};
-		// 	LLVMValueRef ptr = LLVMBuildGEP2(p->builder, lb_type(p->module, base.type->MultiPointer.elem), base.value, indices, 1, "");
-		// 	LLVMValueRef len = LLVMBuildSub(p->builder, high.value, low.value, "");
-
-		// 	LLVMValueRef gep0 = lb_emit_struct_ep(p, res.addr, 0).value;
-		// 	LLVMValueRef gep1 = lb_emit_struct_ep(p, res.addr, 1).value;
-		// 	LLVMBuildStore(p->builder, ptr, gep0);
-		// 	LLVMBuildStore(p->builder, len, gep1);
-		// }
-		// return res;
-		GB_PANIC("cg_build_addr_slice_expr Type_MultiPointer");
-		break;
+		Type *res_type = type_of_expr(expr);
+		if (se->high == nullptr) {
+			cgAddr res = cg_add_local(p, res_type, nullptr, false);
+			GB_ASSERT(base.kind == cgValue_Value);
+			GB_ASSERT(low.kind == cgValue_Value);
+
+			i64 stride = type_size_of(type->MultiPointer.elem);
+			cgValue offset = cg_value(tb_inst_array_access(p->func, base.node, low.node, stride), base.type);
+			cg_addr_store(p, res, offset);
+			return res;
+		} else {
+			cgAddr res = cg_add_local(p, res_type, nullptr, true);
+			low  = cg_emit_conv(p, low,  t_int);
+			high = cg_emit_conv(p, high, t_int);
+
+			// cg_emit_multi_pointer_slice_bounds_check(p, se->open, low, high);
+
+			i64 stride = type_size_of(type->MultiPointer.elem);
+			TB_Node *offset = tb_inst_array_access(p->func, base.node, low.node, stride);
+			TB_Node *len = tb_inst_sub(p->func, high.node, low.node, cast(TB_ArithmeticBehavior)0);
+
+			TB_Node *data_ptr = tb_inst_member_access(p->func, res.addr.node, type_offset_of(res_type, 0));
+			TB_Node *len_ptr  = tb_inst_member_access(p->func, res.addr.node, type_offset_of(res_type, 1));
+
+			tb_inst_store(p->func, TB_TYPE_PTR, data_ptr, offset, cast(TB_CharUnits)build_context.ptr_size, false);
+			tb_inst_store(p->func, TB_TYPE_INT, len_ptr,  len,    cast(TB_CharUnits)build_context.int_size, false);
+
+			// LLVMValueRef gep0 = cg_emit_struct_ep(p, res.addr, 0).value;
+			// LLVMValueRef gep1 = cg_emit_struct_ep(p, res.addr, 1).value;
+			// LLVMBuildStore(p->builder, ptr, gep0);
+			// LLVMBuildStore(p->builder, len, gep1);
+			return res;
+		}
 	}
 
 	case Type_Array: {

+ 140 - 9
src/tilde_proc.cpp

@@ -1,4 +1,7 @@
 gb_internal TB_FunctionPrototype *cg_procedure_type_as_prototype(cgModule *m, Type *type) {
+	// TODO(bill): cache the procedure type generation
+	GB_ASSERT(build_context.metrics.os == TargetOs_windows);
+
 	GB_ASSERT(type != nullptr);
 	type = base_type(type);
 	GB_ASSERT(type->kind == Type_Proc);
@@ -35,7 +38,7 @@ gb_internal TB_FunctionPrototype *cg_procedure_type_as_prototype(cgModule *m, Ty
 				param.dt = TB_TYPE_INTN(cast(u16)(8*sz));
 				break;
 
-			case Basic_f16: param.dt = TB_TYPE_I16; break;
+			case Basic_f16: param.dt = TB_TYPE_F16; break;
 			case Basic_f32: param.dt = TB_TYPE_F32; break;
 			case Basic_f64: param.dt = TB_TYPE_F64; break;
 
@@ -86,11 +89,11 @@ gb_internal TB_FunctionPrototype *cg_procedure_type_as_prototype(cgModule *m, Ty
 				param.dt = TB_TYPE_INTN(cast(u16)(8*sz));
 				break;
 
-			case Basic_f16le: param.dt = TB_TYPE_I16; break;
+			case Basic_f16le: param.dt = TB_TYPE_F16; break;
 			case Basic_f32le: param.dt = TB_TYPE_F32; break;
 			case Basic_f64le: param.dt = TB_TYPE_F64; break;
 
-			case Basic_f16be: param.dt = TB_TYPE_I16; break;
+			case Basic_f16be: param.dt = TB_TYPE_F16; break;
 			case Basic_f32be: param.dt = TB_TYPE_F32; break;
 			case Basic_f64be: param.dt = TB_TYPE_F64; break;
 			}
@@ -117,15 +120,139 @@ gb_internal TB_FunctionPrototype *cg_procedure_type_as_prototype(cgModule *m, Ty
 			if (is_blank_ident(e->token)) {
 				param.name = alloc_cstring(temporary_allocator(), e->token.string);
 			}
+			param.debug_type = cg_debug_type(m, e->type);
 			array_add(&params, param);
 		}
 	}
 
-	auto results = array_make<TB_PrototypeParam>(heap_allocator(), 0, pt->result_count);
-	// if (pt->results) for (Entity *e : pt->params->Tuple.variables) {
-	// 	// TODO(bill):
-	// }
+	auto results = array_make<TB_PrototypeParam>(heap_allocator(), 0, 1);
+
+	Type *result_type = reduce_tuple_to_single_type(pt->results);
+
+	if (result_type) {
+		bool return_is_tuple = result_type->kind == Type_Tuple && is_calling_convention_odin(pt->calling_convention);
 
+		if (return_is_tuple) {
+			for (isize i = 0; i < result_type->Tuple.variables.count-1; i++) {
+				Entity *e = result_type->Tuple.variables[i];
+				TB_PrototypeParam param = {};
+				param.dt = TB_TYPE_PTR;
+				param.debug_type = cg_debug_type(m, alloc_type_pointer(e->type));
+				array_add(&params, param);
+			}
+
+			result_type = result_type->Tuple.variables[result_type->Tuple.variables.count-1]->type;
+		}
+
+		Type *rt = core_type(result_type);
+		i64 sz = type_size_of(rt);
+
+		TB_PrototypeParam result = {};
+
+		switch (rt->kind) {
+		case Type_Basic:
+			switch (rt->Basic.kind) {
+			case Basic_bool:
+			case Basic_b8:
+			case Basic_b16:
+			case Basic_b32:
+			case Basic_b64:
+			case Basic_i8:
+			case Basic_u8:
+			case Basic_i16:
+			case Basic_u16:
+			case Basic_i32:
+			case Basic_u32:
+			case Basic_i64:
+			case Basic_u64:
+			case Basic_i128:
+			case Basic_u128:
+			case Basic_rune:
+			case Basic_int:
+			case Basic_uint:
+			case Basic_uintptr:
+				result.dt = TB_TYPE_INTN(cast(u16)(8*sz));
+				break;
+
+			case Basic_f16: result.dt = TB_TYPE_I16; break;
+			case Basic_f32: result.dt = TB_TYPE_F32; break;
+			case Basic_f64: result.dt = TB_TYPE_F64; break;
+
+			case Basic_rawptr:
+				result.dt = TB_TYPE_PTR;
+				break;
+			case Basic_cstring: // ^u8
+				result.dt = TB_TYPE_PTR;
+				break;
+
+			case Basic_typeid:
+				result.dt = TB_TYPE_INTN(cast(u16)(8*sz));
+				break;
+
+			// Endian Specific Types
+			case Basic_i16le:
+			case Basic_u16le:
+			case Basic_i32le:
+			case Basic_u32le:
+			case Basic_i64le:
+			case Basic_u64le:
+			case Basic_i128le:
+			case Basic_u128le:
+			case Basic_i16be:
+			case Basic_u16be:
+			case Basic_i32be:
+			case Basic_u32be:
+			case Basic_i64be:
+			case Basic_u64be:
+			case Basic_i128be:
+			case Basic_u128be:
+				result.dt = TB_TYPE_INTN(cast(u16)(8*sz));
+				break;
+
+			case Basic_f16le: result.dt = TB_TYPE_I16; break;
+			case Basic_f32le: result.dt = TB_TYPE_F32; break;
+			case Basic_f64le: result.dt = TB_TYPE_F64; break;
+
+			case Basic_f16be: result.dt = TB_TYPE_I16; break;
+			case Basic_f32be: result.dt = TB_TYPE_F32; break;
+			case Basic_f64be: result.dt = TB_TYPE_F64; break;
+			}
+
+		case Type_Pointer:
+		case Type_MultiPointer:
+		case Type_Proc:
+			result.dt = TB_TYPE_PTR;
+			break;
+
+		default:
+			switch (sz) {
+			case 1: result.dt = TB_TYPE_I8;  break;
+			case 2: result.dt = TB_TYPE_I16; break;
+			case 4: result.dt = TB_TYPE_I32; break;
+			case 8: result.dt = TB_TYPE_I64; break;
+			}
+		}
+
+		if (result.dt.raw != 0) {
+			result.debug_type = cg_debug_type(m, result_type);
+			array_add(&results, result);
+		} else {
+			result.debug_type = cg_debug_type(m, alloc_type_pointer(result_type));
+			result.dt = TB_TYPE_PTR;
+
+			array_resize(&params, params.count+1);
+			array_copy(&params, params, 1);
+			params[0] = result;
+		}
+	}
+
+	if (pt->calling_convention == ProcCC_Odin) {
+		TB_PrototypeParam param = {};
+		param.dt = TB_TYPE_PTR;
+		param.debug_type = cg_debug_type(m, t_context_ptr);
+		param.name = "__.context_ptr";
+		array_add(&params, param);
+	}
 
 	return tb_prototype_create(m->mod, TB_CDECL, params.count, params.data, results.count, results.data, pt->c_vararg);
 }
@@ -408,12 +535,16 @@ gb_internal cgValue cg_emit_call(cgProcedure * p, cgValue value, Slice<cgValue>
 	}
 	GB_ASSERT(value.kind == cgValue_Value);
 
+	// TODO(bill): abstract out the function prototype stuff so that you handle the ABI correctly (at least for win64 at the moment)
 	TB_FunctionPrototype *proto = cg_procedure_type_as_prototype(p->module, value.type);
 	TB_Node *target = value.node;
-	auto params = slice_make<TB_Node *>(temporary_allocator(), 0);
+	auto params = slice_make<TB_Node *>(temporary_allocator(), 0 /*proto->param_count*/);
+	for_array(i, params) {
+		// params[i] = proto
+	}
 
 	GB_ASSERT(target != nullptr);
-	TB_MultiOutput multi_output = tb_inst_call(p->func, proto, target, 0, nullptr);
+	TB_MultiOutput multi_output = tb_inst_call(p->func, proto, target, params.count, params.data);
 	gb_unused(multi_output);
 	return {};
 }

+ 4 - 0
src/tilde_stmt.cpp

@@ -376,6 +376,10 @@ gb_internal void cg_build_assignment(cgProcedure *p, Array<cgAddr> const &lvals,
 	for_array(i, inits) {
 		cgAddr lval = lvals[i];
 		cgValue init = inits[i];
+		if (init.type == nullptr) {
+			// TODO(bill): figure out how to do this
+			continue;
+		}
 		cg_addr_store(p, lval, init);
 	}
 

+ 1 - 0
src/types.cpp

@@ -3952,6 +3952,7 @@ gb_internal i64 type_offset_of(Type *t, i32 index) {
 		case -1: return align_formula(t->Union.variant_block_size, build_context.ptr_size); // __type_info
 		}
 	}
+	GB_ASSERT(index == 0);
 	return 0;
 }