Browse Source

Modify llvm_abi.cpp to work correctly for win64 abi of `i128` types. (it's a pain)

gingerBill 4 years ago
parent
commit
a2461bdf6b
4 changed files with 202 additions and 160 deletions
  1. 5 1
      src/check_type.cpp
  2. 40 22
      src/llvm_abi.cpp
  3. 156 137
      src/llvm_backend.cpp
  4. 1 0
      src/llvm_backend.hpp

+ 5 - 1
src/check_type.cpp

@@ -2279,7 +2279,11 @@ Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type, ProcCall
 		return new_type;
 	}
 	if (build_context.ODIN_ARCH == "amd64") {
-		if (is_type_integer_128bit(original_type)) {
+		bool is_128 = is_type_integer_128bit(original_type);
+		if (!is_128 && is_type_bit_set(original_type) && type_size_of(original_type) == 16) {
+			// is_128 = true;
+		}
+		if (is_128) {
 			if (build_context.ODIN_OS == "windows") {
 				return alloc_type_simd_vector(2, t_u64);
 			} else {

+ 40 - 22
src/llvm_abi.cpp

@@ -40,6 +40,9 @@ i64 llvm_align_formula(i64 off, i64 a) {
 
 
 bool lb_is_type_kind(LLVMTypeRef type, LLVMTypeKind kind) {
+	if (type == nullptr) {
+		return false;
+	}
 	return LLVMGetTypeKind(type) == kind;
 }
 
@@ -124,6 +127,7 @@ void lb_add_function_type_attributes(LLVMValueRef fn, lbFunctionType *ft, ProcCa
 
 	if (offset != 0 && ft->ret.kind == lbArg_Indirect && ft->ret.attribute != nullptr) {
 		LLVMAddAttributeAtIndex(fn, offset, ft->ret.attribute);
+		LLVMAddAttributeAtIndex(fn, offset, noalias_attr);
 	}
 
 	lbCallingConventionKind cc_kind = lbCallingConvention_C;
@@ -313,7 +317,14 @@ Type *alloc_type_proc_from_types(Type **param_types, unsigned param_count, Type
 	return t;
 }
 
-Type *lb_abi_to_odin_type(LLVMTypeRef type, bool is_return, u32 level = 0) {
+#if 0
+Type *lb_abi_to_odin_type(lbModule *m, LLVMTypeRef type, bool is_return, u32 level = 0) {
+	Type **found = map_get(&m->llvm_types, hash_pointer(type));
+	if (found) {
+		return *found;
+	}
+	GB_ASSERT_MSG(level < 64, "%s %d", LLVMPrintTypeToString(type), is_return);
+
 	LLVMTypeKind kind = LLVMGetTypeKind(type);
 	switch (kind) {
 	case LLVMVoidTypeKind:
@@ -351,16 +362,16 @@ Type *lb_abi_to_odin_type(LLVMTypeRef type, bool is_return, u32 level = 0) {
 				defer (gb_free(heap_allocator(), param_types));
 
 				for (unsigned i = 0; i < param_count; i++) {
-					param_types[i] = lb_abi_to_odin_type(params[i], false, /*level*/0);
+					param_types[i] = lb_abi_to_odin_type(m, params[i], false, level+1);
 				}
 
 				LLVMTypeRef ret = LLVMGetReturnType(elem);
-				Type *ret_type = lb_abi_to_odin_type(ret, true, /*level*/0);
+				Type *ret_type = lb_abi_to_odin_type(m, ret, true, level+1);
 
 				bool is_c_vararg = !!LLVMIsFunctionVarArg(elem);
 				return alloc_type_proc_from_types(param_types, param_count, ret_type, is_c_vararg);
 			}
-			return alloc_type_pointer(lb_abi_to_odin_type(elem, false, level));
+			return alloc_type_pointer(lb_abi_to_odin_type(m, elem, false, level+1));
 		}
 	case LLVMFunctionTypeKind:
 		GB_PANIC("LLVMFunctionTypeKind should not be seen on its own");
@@ -371,7 +382,12 @@ Type *lb_abi_to_odin_type(LLVMTypeRef type, bool is_return, u32 level = 0) {
 			unsigned field_count = LLVMCountStructElementTypes(type);
 			Type **fields = gb_alloc_array(heap_allocator(), Type *, field_count);
 			for (unsigned i = 0; i < field_count; i++) {
-				fields[i] = lb_abi_to_odin_type(LLVMStructGetTypeAtIndex(type, i), false, level+1);
+				LLVMTypeRef field_type = LLVMStructGetTypeAtIndex(type, i);
+				if (lb_is_type_kind(field_type, LLVMPointerTypeKind) && level > 0) {
+					fields[i] = t_rawptr;
+				} else {
+					fields[i] = lb_abi_to_odin_type(m, field_type, false, level+1);
+				}
 			}
 			if (is_return) {
 				return alloc_type_tuple_from_field_types(fields, field_count, !!LLVMIsPackedStruct(type), false);
@@ -384,7 +400,7 @@ Type *lb_abi_to_odin_type(LLVMTypeRef type, bool is_return, u32 level = 0) {
 		{
 
 			i64 count = LLVMGetArrayLength(type);
-			Type *elem = lb_abi_to_odin_type(LLVMGetElementType(type), false, level+1);
+			Type *elem = lb_abi_to_odin_type(m, LLVMGetElementType(type), false, level+1);
 			return alloc_type_array(elem, count);
 		}
 		break;
@@ -394,7 +410,7 @@ Type *lb_abi_to_odin_type(LLVMTypeRef type, bool is_return, u32 level = 0) {
 	case LLVMVectorTypeKind:
 		{
 			i64 count = LLVMGetVectorSize(type);
-			Type *elem = lb_abi_to_odin_type(LLVMGetElementType(type), false, level+1);
+			Type *elem = lb_abi_to_odin_type(m, LLVMGetElementType(type), false, level+1);
 			return alloc_type_simd_vector(count, elem);
 		}
 
@@ -403,7 +419,7 @@ Type *lb_abi_to_odin_type(LLVMTypeRef type, bool is_return, u32 level = 0) {
 
 	return 0;
 }
-
+#endif
 
 
 #define LB_ABI_INFO(name) lbFunctionType *name(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count, LLVMTypeRef return_type, bool return_is_defined, ProcCallingConvention calling_convention)
@@ -424,22 +440,24 @@ namespace lbAbi386 {
 		return ft;
 	}
 
-	lbArgType non_struct(LLVMContextRef c, LLVMTypeRef type) {
-		if (build_context.metrics.os == TargetOs_windows &&
-		           build_context.word_size == 8 &&
-		           lb_is_type_kind(type, LLVMIntegerTypeKind) &&
-		           lb_sizeof(type) == 16) {
+	lbArgType non_struct(LLVMContextRef c, LLVMTypeRef type, bool is_return) {
+		if (!is_return && lb_sizeof(type) > 8) {
+			return lb_arg_type_indirect(type, nullptr);
+		}
 
+		if (build_context.metrics.os == TargetOs_windows &&
+		    build_context.word_size == 8 &&
+		    lb_is_type_kind(type, LLVMIntegerTypeKind) &&
+		    type == LLVMIntTypeInContext(c, 128)) {
+		    	// NOTE(bill): Because Windows AMD64 is weird
 			LLVMTypeRef cast_type = LLVMVectorType(LLVMInt64TypeInContext(c), 2);
 			return lb_arg_type_direct(type, cast_type, nullptr, nullptr);
 		}
 
-
-
 		LLVMAttributeRef attr = nullptr;
 		LLVMTypeRef i1 = LLVMInt1TypeInContext(c);
 		if (type == i1) {
-			attr = lb_create_enum_attribute(c, "zeroext", true);
+			// attr = lb_create_enum_attribute(c, "zeroext", true);
 			// return lb_arg_type_direct(type, i1, nullptr, attr);
 		}
 		return lb_arg_type_direct(type, nullptr, nullptr, attr);
@@ -451,15 +469,15 @@ namespace lbAbi386 {
 		for (unsigned i = 0; i < arg_count; i++) {
 			LLVMTypeRef t = arg_types[i];
 			LLVMTypeKind kind = LLVMGetTypeKind(t);
+			i64 sz = lb_sizeof(t);
 			if (kind == LLVMStructTypeKind) {
-				i64 sz = lb_sizeof(t);
 				if (sz == 0) {
 					args[i] = lb_arg_type_ignore(t);
 				} else {
 					args[i] = lb_arg_type_indirect(t, lb_create_enum_attribute(c, "byval", true));
 				}
 			} else {
-				args[i] = non_struct(c, t);
+				args[i] = non_struct(c, t, false);
 			}
 		}
 		return args;
@@ -478,7 +496,7 @@ namespace lbAbi386 {
 			}
 			return lb_arg_type_indirect(return_type, lb_create_enum_attribute(c, "sret", true));
 		}
-		return non_struct(c, return_type);
+		return non_struct(c, return_type, true);
 	}
 };
 
@@ -515,7 +533,7 @@ namespace lbAbiAmd64Win64 {
 					break;
 				}
 			} else {
-				args[i] = lbAbi386::non_struct(c, t);
+				args[i] = lbAbi386::non_struct(c, t, false);
 			}
 		}
 		return args;
@@ -623,7 +641,7 @@ namespace lbAbiAmd64SysV {
 		if (is_register(type)) {
 			LLVMAttributeRef attribute = nullptr;
 			if (type == LLVMInt1TypeInContext(c)) {
-				attribute = lb_create_enum_attribute(c, "zeroext", true);
+				// attribute = lb_create_enum_attribute(c, "zeroext", true);
 			}
 			return lb_arg_type_direct(type, nullptr, nullptr, attribute);
 		}
@@ -646,7 +664,7 @@ namespace lbAbiAmd64SysV {
 		LLVMAttributeRef attr = nullptr;
 		LLVMTypeRef i1 = LLVMInt1TypeInContext(c);
 		if (type == i1) {
-			attr = lb_create_enum_attribute(c, "zeroext", true);
+			// attr = lb_create_enum_attribute(c, "zeroext", true);
 		}
 		return lb_arg_type_direct(type, nullptr, nullptr, attr);
 	}

+ 156 - 137
src/llvm_backend.cpp

@@ -1114,7 +1114,7 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
 				return type;
 			}
 
-		case Basic_typeid: return LLVMIntType(8*cast(unsigned)build_context.word_size);
+		case Basic_typeid: return LLVMIntTypeInContext(m->ctx, 8*cast(unsigned)build_context.word_size);
 
 		// Endian Specific Types
 		case Basic_i16le:  return LLVMInt16TypeInContext(ctx);
@@ -1353,130 +1353,144 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
 		}
 
 	case Type_Proc:
-		if (USE_LLVM_ABI) {
-			if (m->internal_type_level > 1) {
-				return LLVMPointerType(LLVMIntTypeInContext(m->ctx, 8), 0);
-			} else {
-				unsigned param_count = 0;
-				if (type->Proc.calling_convention == ProcCC_Odin) {
-					param_count += 1;
-				}
-
-				if (type->Proc.param_count != 0) {
-					GB_ASSERT(type->Proc.params->kind == Type_Tuple);
-					for_array(i, type->Proc.params->Tuple.variables) {
-						Entity *e = type->Proc.params->Tuple.variables[i];
-						if (e->kind != Entity_Variable) {
-							continue;
-						}
+		{
+			if (USE_LLVM_ABI) {
+				if (m->internal_type_level > 5) { // TODO HACK(bill): is this really enough?
+					return LLVMPointerType(LLVMIntTypeInContext(m->ctx, 8), 0);
+				} else {
+					unsigned param_count = 0;
+					if (type->Proc.calling_convention == ProcCC_Odin) {
 						param_count += 1;
 					}
-				}
 
-				LLVMTypeRef ret = nullptr;
-				LLVMTypeRef *params = gb_alloc_array(heap_allocator(), LLVMTypeRef, param_count);
-				if (type->Proc.result_count != 0) {
-					Type *single_ret = reduce_tuple_to_single_type(type->Proc.results);
-					ret = lb_type(m, single_ret);
-					if (ret != nullptr) {
-						if (is_calling_convention_none(type->Proc.calling_convention) &&
-						    is_type_boolean(single_ret) &&
-						    type_size_of(single_ret) <= 1) {
-							ret = LLVMInt1TypeInContext(m->ctx);
+					if (type->Proc.param_count != 0) {
+						GB_ASSERT(type->Proc.params->kind == Type_Tuple);
+						for_array(i, type->Proc.params->Tuple.variables) {
+							Entity *e = type->Proc.params->Tuple.variables[i];
+							if (e->kind != Entity_Variable) {
+								continue;
+							}
+							param_count += 1;
 						}
 					}
-				}
-
-				isize param_index = 0;
-				if (type->Proc.param_count != 0) {
-					GB_ASSERT(type->Proc.params->kind == Type_Tuple);
-					for_array(i, type->Proc.params->Tuple.variables) {
-						Entity *e = type->Proc.params->Tuple.variables[i];
-						if (e->kind != Entity_Variable) {
-							continue;
+					m->internal_type_level += 1;
+					defer (m->internal_type_level -= 1);
+
+					LLVMTypeRef ret = nullptr;
+					LLVMTypeRef *params = gb_alloc_array(heap_allocator(), LLVMTypeRef, param_count);
+					if (type->Proc.result_count != 0) {
+						Type *single_ret = reduce_tuple_to_single_type(type->Proc.results);
+						ret = lb_type(m, single_ret);
+						if (ret != nullptr) {
+							if (is_type_boolean(single_ret) &&
+							    is_calling_convention_none(type->Proc.calling_convention) &&
+							    type_size_of(single_ret) <= 1) {
+								ret = LLVMInt1TypeInContext(m->ctx);
+							}
 						}
+					}
 
-						Type *e_type = reduce_tuple_to_single_type(e->type);
+					isize param_index = 0;
+					if (type->Proc.param_count != 0) {
+						GB_ASSERT(type->Proc.params->kind == Type_Tuple);
+						for_array(i, type->Proc.params->Tuple.variables) {
+							Entity *e = type->Proc.params->Tuple.variables[i];
+							if (e->kind != Entity_Variable) {
+								continue;
+							}
 
-						LLVMTypeRef param_type = nullptr;
-						if (is_calling_convention_none(type->Proc.calling_convention) &&
-						    is_type_boolean(e_type) &&
-						    type_size_of(e_type) <= 1) {
-							param_type = LLVMInt1TypeInContext(m->ctx);
-						} else {
-							param_type = lb_type(m, e_type);
+							Type *e_type = reduce_tuple_to_single_type(e->type);
+
+							LLVMTypeRef param_type = nullptr;
+							if (is_type_boolean(e_type) &&
+							    type_size_of(e_type) <= 1) {
+								param_type = LLVMInt1TypeInContext(m->ctx);
+							} else {
+								param_type = lb_type(m, e_type);
+							}
+							params[param_index++] = param_type;
 						}
-						params[param_index++] =	param_type;
 					}
-				}
-				if (param_index < param_count) {
-					params[param_index++] = lb_type(m, t_context_ptr);
-				}
-				GB_ASSERT(param_index == param_count);
+					if (param_index < param_count) {
+						params[param_index++] = lb_type(m, t_context_ptr);
+					}
+					GB_ASSERT(param_index == param_count);
 
 
-				lbFunctionType *ft = lb_get_abi_info(m->ctx, params, param_count, ret, ret != nullptr, type->Proc.calling_convention);
-				map_set(&m->function_type_map, hash_type(type), ft);
-				return lb_function_type_to_llvm_ptr(ft, type->Proc.c_vararg);
-			}
-		} else {
-			set_procedure_abi_types(type);
-			LLVMTypeRef return_type = LLVMVoidTypeInContext(ctx);
-			if (type->Proc.return_by_pointer) {
-				// Void
-			} else if (type->Proc.abi_compat_result_type != nullptr) {
-				return_type = lb_type(m, type->Proc.abi_compat_result_type);
-			}
+					lbFunctionType *ft = lb_get_abi_info(m->ctx, params, param_count, ret, ret != nullptr, type->Proc.calling_convention);
+					map_set(&m->function_type_map, hash_type(type), ft);
+					LLVMTypeRef new_abi_fn_ptr_type = lb_function_type_to_llvm_ptr(ft, type->Proc.c_vararg);
+					LLVMTypeRef new_abi_fn_type = LLVMGetElementType(new_abi_fn_ptr_type);
 
-			isize extra_param_count = 0;
-			if (type->Proc.return_by_pointer) {
-				extra_param_count += 1;
-			}
-			if (type->Proc.calling_convention == ProcCC_Odin) {
-				extra_param_count += 1;
-			}
+					// LLVMTypeRef new_ret = LLVMGetReturnType(new_abi_fn_type);
+					// LLVMTypeRef old_ret = LLVMGetReturnType(old_abi_fn_type);
+					// unsigned new_count = LLVMCountParamTypes(new_abi_fn_type);
+					// unsigned old_count = LLVMCountParamTypes(old_abi_fn_type);
+					// GB_ASSERT_MSG(new_count == old_count, "%u %u, %s %s", new_count, old_count, LLVMPrintTypeToString(new_abi_fn_type), LLVMPrintTypeToString(old_abi_fn_type));
+					return new_abi_fn_ptr_type;
+				}
+			} else {
+					LLVMTypeRef old_abi_fn_type = nullptr;
+
+					set_procedure_abi_types(type);
+					LLVMTypeRef return_type = LLVMVoidTypeInContext(ctx);
+					if (type->Proc.return_by_pointer) {
+						// Void
+					} else if (type->Proc.abi_compat_result_type != nullptr) {
+						return_type = lb_type(m, type->Proc.abi_compat_result_type);
+					}
 
-			isize param_count = type->Proc.abi_compat_params.count + extra_param_count;
-			auto param_types = array_make<LLVMTypeRef>(temporary_allocator(), 0, param_count);
+					isize extra_param_count = 0;
+					if (type->Proc.return_by_pointer) {
+						extra_param_count += 1;
+					}
+					if (type->Proc.calling_convention == ProcCC_Odin) {
+						extra_param_count += 1;
+					}
 
-			if (type->Proc.return_by_pointer) {
-				array_add(&param_types, LLVMPointerType(lb_type(m, type->Proc.abi_compat_result_type), 0));
-			}
+					isize param_count = type->Proc.abi_compat_params.count + extra_param_count;
+					auto param_types = array_make<LLVMTypeRef>(temporary_allocator(), 0, param_count);
 
-			for_array(i, type->Proc.abi_compat_params) {
-				Type *param = type->Proc.abi_compat_params[i];
-				if (param == nullptr) {
-					continue;
-				}
-				if (type->Proc.params->Tuple.variables[i]->flags & EntityFlag_CVarArg) {
-					GB_ASSERT(i+1 == type->Proc.abi_compat_params.count);
-					break;
-				}
-				if (is_type_tuple(param)) {
-					param = base_type(param);
-					for_array(j, param->Tuple.variables) {
-						Entity *v = param->Tuple.variables[j];
-						if (v->kind != Entity_Variable) {
-							// Sanity check
+					if (type->Proc.return_by_pointer) {
+						array_add(&param_types, LLVMPointerType(lb_type(m, type->Proc.abi_compat_result_type), 0));
+					}
+
+					for_array(i, type->Proc.abi_compat_params) {
+						Type *param = type->Proc.abi_compat_params[i];
+						if (param == nullptr) {
 							continue;
 						}
-						LLVMTypeRef t = lb_type(m, v->type);
-						array_add(&param_types, t);
+						if (type->Proc.params->Tuple.variables[i]->flags & EntityFlag_CVarArg) {
+							GB_ASSERT(i+1 == type->Proc.abi_compat_params.count);
+							break;
+						}
+						if (is_type_tuple(param)) {
+							param = base_type(param);
+							for_array(j, param->Tuple.variables) {
+								Entity *v = param->Tuple.variables[j];
+								if (v->kind != Entity_Variable) {
+									// Sanity check
+									continue;
+								}
+								LLVMTypeRef t = lb_type(m, v->type);
+								array_add(&param_types, t);
+							}
+						} else {
+							array_add(&param_types, lb_type(m, param));
+						}
+					}
+					if (type->Proc.calling_convention == ProcCC_Odin) {
+						array_add(&param_types, lb_type(m, t_context_ptr));
 					}
-				} else {
-					array_add(&param_types, lb_type(m, param));
-				}
-			}
-			if (type->Proc.calling_convention == ProcCC_Odin) {
-				array_add(&param_types, lb_type(m, t_context_ptr));
-			}
 
-			LLVMTypeRef t = LLVMFunctionType(return_type, param_types.data, cast(unsigned)param_types.count, type->Proc.c_vararg);
-			return LLVMPointerType(t, 0);
+					old_abi_fn_type = LLVMFunctionType(return_type, param_types.data, cast(unsigned)param_types.count, type->Proc.c_vararg);
+					return LLVMPointerType(old_abi_fn_type, 0);
+				}
 		}
+
 		break;
 	case Type_BitFieldValue:
-		return LLVMIntType(type->BitFieldValue.bits);
+		return LLVMIntTypeInContext(m->ctx, type->BitFieldValue.bits);
 
 	case Type_BitField:
 		{
@@ -1488,7 +1502,7 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
 
 				for_array(i, type->BitField.sizes) {
 					u32 size = type->BitField.sizes[i];
-					fields[i] = LLVMIntType(size);
+					fields[i] = LLVMIntTypeInContext(m->ctx, size);
 				}
 
 				internal_type = LLVMStructTypeInContext(ctx, fields, field_count, true);
@@ -1507,7 +1521,11 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
 		}
 		break;
 	case Type_BitSet:
-		return LLVMIntType(8*cast(unsigned)type_size_of(type));
+		{
+			Type *ut = bit_set_to_int(type);
+			return lb_type(m, ut);
+		}
+
 	case Type_SimdVector:
 		if (type->SimdVector.is_x86_mmx) {
 			return LLVMX86MMXTypeInContext(ctx);
@@ -1548,6 +1566,9 @@ LLVMTypeRef lb_type(lbModule *m, Type *type) {
 	m->internal_type_level -= 1;
 	if (USE_LLVM_ABI && m->internal_type_level == 0) {
 		map_set(&m->types, hash_type(type), llvm_type);
+		if (is_type_named(type)) {
+			map_set(&m->llvm_types, hash_pointer(llvm_type), type);
+		}
 	}
 	return llvm_type;
 }
@@ -1989,7 +2010,7 @@ LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) {
 		break;
 	case Type_BitFieldValue:
 		return nullptr;
-		// return LLVMIntType(type->BitFieldValue.bits);
+		// return LLVMIntTypeInContext(m->ctx, type->BitFieldValue.bits);
 
 	case Type_BitField:
 		{
@@ -2003,7 +2024,7 @@ LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) {
 
 			// 	for_array(i, type->BitField.sizes) {
 			// 		u32 size = type->BitField.sizes[i];
-			// 		fields[i] = LLVMIntType(size);
+			// 		fields[i] = LLVMIntTypeInContext(m->ctx, size);
 			// 	}
 
 			// 	internal_type = LLVMStructTypeInContext(ctx, fields, field_count, true);
@@ -2023,7 +2044,7 @@ LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) {
 		break;
 	case Type_BitSet:
 		return nullptr;
-		// return LLVMIntType(8*cast(unsigned)type_size_of(type));
+		// return LLVMIntTypeInContext(m->ctx, 8*cast(unsigned)type_size_of(type));
 	case Type_SimdVector:
 		return nullptr;
 		// if (type->SimdVector.is_x86_mmx) {
@@ -2507,9 +2528,25 @@ void lb_start_block(lbProcedure *p, lbBlock *b) {
 }
 
 LLVMValueRef OdinLLVMBuildTransmute(lbProcedure *p, LLVMValueRef val, LLVMTypeRef dst_type) {
+	LLVMContextRef ctx = p->module->ctx;
+
 	LLVMTypeRef src_type = LLVMTypeOf(val);
+
+	if (src_type == dst_type) {
+		return val;
+	}
+
 	i64 src_size = lb_sizeof(src_type);
 	i64 dst_size = lb_sizeof(dst_type);
+
+	if (dst_type == LLVMInt1TypeInContext(ctx)) {
+		GB_ASSERT(lb_is_type_kind(src_type, LLVMIntegerTypeKind));
+		return LLVMBuildICmp(p->builder, LLVMIntNE, val, LLVMConstNull(src_type), "");
+	} else if (src_type == LLVMInt1TypeInContext(ctx)) {
+		GB_ASSERT(lb_is_type_kind(src_type, LLVMIntegerTypeKind));
+		return LLVMBuildZExtOrBitCast(p->builder, val, dst_type, "");
+	}
+
 	if (src_size != dst_size && (lb_is_type_kind(src_type, LLVMVectorTypeKind) ^ lb_is_type_kind(dst_type, LLVMVectorTypeKind))) {
 		// Okay
 	} else {
@@ -2627,11 +2664,7 @@ void lb_begin_procedure_body(lbProcedure *p) {
 					}
 					LLVMValueRef value = LLVMGetParam(p->value, param_offset+param_index);
 
-					if (USE_LLVM_ABI && LLVMTypeOf(value) == LLVMInt1TypeInContext(p->module->ctx)) {
-						value = LLVMBuildZExtOrBitCast(p->builder, value, param_type, "");
-					} else {
-						value = OdinLLVMBuildTransmute(p, value, param_type);
-					}
+					value = OdinLLVMBuildTransmute(p, value, param_type);
 
 					lbValue param = {};
 					param.value = value;
@@ -4554,9 +4587,11 @@ void lb_build_stmt(lbProcedure *p, Ast *node) {
 				LLVMBuildRetVoid(p->builder);
 			} else {
 				LLVMValueRef ret_val = res.value;
+				ret_val = OdinLLVMBuildTransmute(p, ret_val, p->abi_function_type->ret.type);
 				if (p->abi_function_type->ret.cast_type != nullptr) {
 					ret_val = OdinLLVMBuildTransmute(p, ret_val, p->abi_function_type->ret.cast_type);
 				}
+
 				lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr);
 				LLVMBuildRet(p->builder, ret_val);
 			}
@@ -7458,18 +7493,7 @@ lbValue lb_emit_call(lbProcedure *p, lbValue value, Array<lbValue> const &args,
 				if (xt == abi_type) {
 					array_add(&processed_args, x);
 				} else {
-					Type *at = lb_abi_to_odin_type(abi_type, false);
-					if (at == t_llvm_bool) {
-						x = lb_emit_conv(p, x, at);
-					} else if (is_type_simd_vector(at) && lb_sizeof(abi_type) > lb_sizeof(xt)) {
-						lbAddr v = lb_add_local_generated(p, at, false);
-						lbValue ptr = lb_addr_get_ptr(p, v);
-						ptr = lb_emit_conv(p, ptr, alloc_type_pointer(x.type));
-						lb_emit_store(p, ptr, x);
-						x = lb_addr_load(p, v);
-					} else {
-						x = lb_emit_transmute(p, x, at);
-					}
+					x.value = OdinLLVMBuildTransmute(p, x.value, abi_type);
 					array_add(&processed_args, x);
 				}
 
@@ -7509,20 +7533,14 @@ lbValue lb_emit_call(lbProcedure *p, lbValue value, Array<lbValue> const &args,
 			lb_emit_call_internal(p, value, return_ptr, processed_args, nullptr, context_ptr, inlining);
 			result = lb_emit_load(p, return_ptr);
 		} else if (rt != nullptr) {
-			LLVMTypeRef ret_type = ft->ret.cast_type;
-			if (!ret_type) {
-				ret_type = ft->ret.type;
+			result = lb_emit_call_internal(p, value, {}, processed_args, rt, context_ptr, inlining);
+			if (ft->ret.cast_type) {
+				result.value = OdinLLVMBuildTransmute(p, result.value, ft->ret.cast_type);
 			}
-			Type *abi_rt = lb_abi_to_odin_type(ret_type, true);
-			result = lb_emit_call_internal(p, value, {}, processed_args, abi_rt, context_ptr, inlining);
-			if (ret_type != lb_type(m, rt)) {
-				if (is_type_simd_vector(abi_rt) && lb_sizeof(ret_type) > type_size_of(rt)) {
-					lbValue ptr = lb_address_from_load_or_generate_local(p, result);
-					ptr = lb_emit_conv(p, ptr, alloc_type_pointer(rt));
-					result = lb_emit_load(p, ptr);
-				} else {
-					result = lb_emit_transmute(p, result, rt);
-				}
+			result.value = OdinLLVMBuildTransmute(p, result.value, ft->ret.type);
+			result.type = rt;
+			if (LLVMTypeOf(result.value) == LLVMInt1TypeInContext(p->module->ctx)) {
+				result.type = t_llvm_bool;
 			}
 			if (!is_type_tuple(rt)) {
 				result = lb_emit_conv(p, result, rt);
@@ -11416,6 +11434,7 @@ void lb_init_module(lbModule *m, Checker *c) {
 	gb_mutex_init(&m->mutex);
 	gbAllocator a = heap_allocator();
 	map_init(&m->types, a);
+	map_init(&m->llvm_types, a);
 	map_init(&m->values, a);
 	string_map_init(&m->members, a);
 	map_init(&m->procedure_values, a);

+ 1 - 0
src/llvm_backend.hpp

@@ -74,6 +74,7 @@ struct lbModule {
 	gbMutex mutex;
 
 	Map<LLVMTypeRef> types; // Key: Type *
+	Map<Type *> llvm_types; // Key: LLVMTypeRef
 	i32 internal_type_level;
 
 	Map<lbValue>  values;           // Key: Entity *