|
@@ -1,3 +1,5 @@
|
|
|
+#define ALLOW_SPLIT_MULTI_RETURNS true
|
|
|
+
|
|
|
enum lbArgKind {
|
|
|
lbArg_Direct,
|
|
|
lbArg_Indirect,
|
|
@@ -48,8 +50,16 @@ struct lbFunctionType {
|
|
|
ProcCallingConvention calling_convention;
|
|
|
Array<lbArgType> args;
|
|
|
lbArgType ret;
|
|
|
+
|
|
|
+ LLVMTypeRef multiple_return_original_type; // nullptr if not used
|
|
|
+ isize original_arg_count;
|
|
|
};
|
|
|
|
|
|
+gbAllocator lb_function_type_args_allocator(void) {
|
|
|
+ return heap_allocator();
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
i64 llvm_align_formula(i64 off, i64 a) {
|
|
|
return (off + a - 1) / a * a;
|
|
|
}
|
|
@@ -100,7 +110,9 @@ LLVMTypeRef lb_function_type_to_llvm_raw(lbFunctionType *ft, bool is_var_arg) {
|
|
|
}
|
|
|
args[arg_index++] = arg_type;
|
|
|
} else if (arg->kind == lbArg_Indirect) {
|
|
|
- GB_ASSERT(!lb_is_type_kind(arg->type, LLVMPointerTypeKind));
|
|
|
+ if (ft->multiple_return_original_type == nullptr || i < ft->original_arg_count) {
|
|
|
+ GB_ASSERT(!lb_is_type_kind(arg->type, LLVMPointerTypeKind));
|
|
|
+ }
|
|
|
args[arg_index++] = LLVMPointerType(arg->type, 0);
|
|
|
} else if (arg->kind == lbArg_Ignore) {
|
|
|
// ignore
|
|
@@ -147,6 +159,13 @@ void lb_add_function_type_attributes(LLVMValueRef fn, lbFunctionType *ft, ProcCa
|
|
|
LLVMAddAttributeAtIndex(fn, arg_index+1, arg->align_attribute);
|
|
|
}
|
|
|
|
|
|
+ if (ft->multiple_return_original_type) {
|
|
|
+ if (ft->original_arg_count <= i) {
|
|
|
+ LLVMAddAttributeAtIndex(fn, arg_index+1, noalias_attr);
|
|
|
+ LLVMAddAttributeAtIndex(fn, arg_index+1, nonnull_attr);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
arg_index++;
|
|
|
}
|
|
|
|
|
@@ -307,20 +326,58 @@ i64 lb_alignof(LLVMTypeRef type) {
|
|
|
}
|
|
|
|
|
|
|
|
|
-#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)
|
|
|
+#define LB_ABI_INFO(name) lbFunctionType *name(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count, LLVMTypeRef return_type, bool return_is_defined, bool return_is_tuple, ProcCallingConvention calling_convention)
|
|
|
typedef LB_ABI_INFO(lbAbiInfoType);
|
|
|
|
|
|
+#define LB_ABI_COMPUTE_RETURN_TYPE(name) lbArgType name(lbFunctionType *ft, LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined, bool return_is_tuple)
|
|
|
+typedef LB_ABI_COMPUTE_RETURN_TYPE(lbAbiComputeReturnType);
|
|
|
+
|
|
|
+
|
|
|
+lbArgType lb_abi_modify_return_is_tuple(lbFunctionType *ft, LLVMContextRef c, LLVMTypeRef return_type, lbAbiComputeReturnType *compute_return_type) {
|
|
|
+ GB_ASSERT(return_type != nullptr);
|
|
|
+ GB_ASSERT(compute_return_type != nullptr);
|
|
|
+
|
|
|
+ lbArgType return_arg = {};
|
|
|
+ if (lb_is_type_kind(return_type, LLVMStructTypeKind)) {
|
|
|
+ unsigned field_count = LLVMCountStructElementTypes(return_type);
|
|
|
+ if (field_count > 1) {
|
|
|
+ ft->original_arg_count = ft->args.count;
|
|
|
+ ft->multiple_return_original_type = return_type;
|
|
|
+
|
|
|
+ for (unsigned i = 0; i < field_count-1; i++) {
|
|
|
+ LLVMTypeRef field_type = LLVMStructGetTypeAtIndex(return_type, i);
|
|
|
+ LLVMTypeRef field_pointer_type = LLVMPointerType(field_type, 0);
|
|
|
+ lbArgType ret_partial = lb_arg_type_direct(field_pointer_type);
|
|
|
+ array_add(&ft->args, ret_partial);
|
|
|
+ }
|
|
|
+
|
|
|
+ // override the return type for the last field
|
|
|
+ LLVMTypeRef new_return_type = LLVMStructGetTypeAtIndex(return_type, field_count-1);
|
|
|
+ return_arg = compute_return_type(ft, c, new_return_type, true, false);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return return_arg;
|
|
|
+}
|
|
|
+
|
|
|
+#define LB_ABI_MODIFY_RETURN_IF_TUPLE_MACRO() do { \
|
|
|
+ if (return_is_tuple) { \
|
|
|
+ lbArgType new_return_type = lb_abi_modify_return_is_tuple(ft, c, return_type, compute_return_type); \
|
|
|
+ if (new_return_type.type != nullptr) { \
|
|
|
+ return new_return_type; \
|
|
|
+ } \
|
|
|
+ } \
|
|
|
+} while (0)
|
|
|
|
|
|
// NOTE(bill): I hate `namespace` in C++ but this is just because I don't want to prefix everything
|
|
|
namespace lbAbi386 {
|
|
|
Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count);
|
|
|
- lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined);
|
|
|
+ LB_ABI_COMPUTE_RETURN_TYPE(compute_return_type);
|
|
|
|
|
|
LB_ABI_INFO(abi_info) {
|
|
|
lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType);
|
|
|
ft->ctx = c;
|
|
|
ft->args = compute_arg_types(c, arg_types, arg_count);
|
|
|
- ft->ret = compute_return_type(c, return_type, return_is_defined);
|
|
|
+ ft->ret = compute_return_type(ft, c, return_type, return_is_defined, return_is_tuple);
|
|
|
ft->calling_convention = calling_convention;
|
|
|
return ft;
|
|
|
}
|
|
@@ -353,7 +410,7 @@ namespace lbAbi386 {
|
|
|
}
|
|
|
|
|
|
Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count) {
|
|
|
- auto args = array_make<lbArgType>(heap_allocator(), arg_count);
|
|
|
+ auto args = array_make<lbArgType>(lb_function_type_args_allocator(), arg_count);
|
|
|
|
|
|
for (unsigned i = 0; i < arg_count; i++) {
|
|
|
LLVMTypeRef t = arg_types[i];
|
|
@@ -372,7 +429,7 @@ namespace lbAbi386 {
|
|
|
return args;
|
|
|
}
|
|
|
|
|
|
- lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined) {
|
|
|
+ LB_ABI_COMPUTE_RETURN_TYPE(compute_return_type) {
|
|
|
if (!return_is_defined) {
|
|
|
return lb_arg_type_direct(LLVMVoidTypeInContext(c));
|
|
|
} else if (lb_is_type_kind(return_type, LLVMStructTypeKind) || lb_is_type_kind(return_type, LLVMArrayTypeKind)) {
|
|
@@ -383,6 +440,9 @@ namespace lbAbi386 {
|
|
|
case 4: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 32), nullptr, nullptr);
|
|
|
case 8: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 64), nullptr, nullptr);
|
|
|
}
|
|
|
+
|
|
|
+ LB_ABI_MODIFY_RETURN_IF_TUPLE_MACRO();
|
|
|
+
|
|
|
LLVMAttributeRef attr = lb_create_enum_attribute_with_type(c, "sret", return_type);
|
|
|
return lb_arg_type_indirect(return_type, attr);
|
|
|
}
|
|
@@ -392,19 +452,19 @@ namespace lbAbi386 {
|
|
|
|
|
|
namespace lbAbiAmd64Win64 {
|
|
|
Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count);
|
|
|
-
|
|
|
+ LB_ABI_COMPUTE_RETURN_TYPE(compute_return_type);
|
|
|
|
|
|
LB_ABI_INFO(abi_info) {
|
|
|
lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType);
|
|
|
ft->ctx = c;
|
|
|
ft->args = compute_arg_types(c, arg_types, arg_count);
|
|
|
- ft->ret = lbAbi386::compute_return_type(c, return_type, return_is_defined);
|
|
|
+ ft->ret = compute_return_type(ft, c, return_type, return_is_defined, return_is_tuple);
|
|
|
ft->calling_convention = calling_convention;
|
|
|
return ft;
|
|
|
}
|
|
|
|
|
|
Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count) {
|
|
|
- auto args = array_make<lbArgType>(heap_allocator(), arg_count);
|
|
|
+ auto args = array_make<lbArgType>(lb_function_type_args_allocator(), arg_count);
|
|
|
|
|
|
for (unsigned i = 0; i < arg_count; i++) {
|
|
|
LLVMTypeRef t = arg_types[i];
|
|
@@ -428,6 +488,26 @@ namespace lbAbiAmd64Win64 {
|
|
|
}
|
|
|
return args;
|
|
|
}
|
|
|
+
|
|
|
+ LB_ABI_COMPUTE_RETURN_TYPE(compute_return_type) {
|
|
|
+ if (!return_is_defined) {
|
|
|
+ return lb_arg_type_direct(LLVMVoidTypeInContext(c));
|
|
|
+ } else if (lb_is_type_kind(return_type, LLVMStructTypeKind) || lb_is_type_kind(return_type, LLVMArrayTypeKind)) {
|
|
|
+ i64 sz = lb_sizeof(return_type);
|
|
|
+ switch (sz) {
|
|
|
+ case 1: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 8), nullptr, nullptr);
|
|
|
+ case 2: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 16), nullptr, nullptr);
|
|
|
+ case 4: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 32), nullptr, nullptr);
|
|
|
+ case 8: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 64), nullptr, nullptr);
|
|
|
+ }
|
|
|
+
|
|
|
+ LB_ABI_MODIFY_RETURN_IF_TUPLE_MACRO();
|
|
|
+
|
|
|
+ LLVMAttributeRef attr = lb_create_enum_attribute_with_type(c, "sret", return_type);
|
|
|
+ return lb_arg_type_indirect(return_type, attr);
|
|
|
+ }
|
|
|
+ return lbAbi386::non_struct(c, return_type, true);
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
// NOTE(bill): I hate `namespace` in C++ but this is just because I don't want to prefix everything
|
|
@@ -478,7 +558,7 @@ namespace lbAbiAmd64SysV {
|
|
|
Amd64TypeAttribute_StructRect,
|
|
|
};
|
|
|
|
|
|
- lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined);
|
|
|
+ LB_ABI_COMPUTE_RETURN_TYPE(compute_return_type);
|
|
|
void classify_with(LLVMTypeRef t, Array<RegClass> *cls, i64 ix, i64 off);
|
|
|
void fixup(LLVMTypeRef t, Array<RegClass> *cls);
|
|
|
lbArgType amd64_type(LLVMContextRef c, LLVMTypeRef type, Amd64TypeAttributeKind attribute_kind, ProcCallingConvention calling_convention);
|
|
@@ -490,7 +570,7 @@ namespace lbAbiAmd64SysV {
|
|
|
ft->ctx = c;
|
|
|
ft->calling_convention = calling_convention;
|
|
|
|
|
|
- ft->args = array_make<lbArgType>(heap_allocator(), arg_count);
|
|
|
+ ft->args = array_make<lbArgType>(lb_function_type_args_allocator(), arg_count);
|
|
|
for (unsigned i = 0; i < arg_count; i++) {
|
|
|
ft->args[i] = amd64_type(c, arg_types[i], Amd64TypeAttribute_ByVal, calling_convention);
|
|
|
}
|
|
@@ -875,7 +955,7 @@ namespace lbAbiAmd64SysV {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined) {
|
|
|
+ LB_ABI_COMPUTE_RETURN_TYPE(compute_return_type) {
|
|
|
if (!return_is_defined) {
|
|
|
return lb_arg_type_direct(LLVMVoidTypeInContext(c));
|
|
|
} else if (lb_is_type_kind(return_type, LLVMStructTypeKind)) {
|
|
@@ -886,6 +966,9 @@ namespace lbAbiAmd64SysV {
|
|
|
case 4: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 32), nullptr, nullptr);
|
|
|
case 8: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 64), nullptr, nullptr);
|
|
|
}
|
|
|
+
|
|
|
+ LB_ABI_MODIFY_RETURN_IF_TUPLE_MACRO();
|
|
|
+
|
|
|
LLVMAttributeRef attr = lb_create_enum_attribute_with_type(c, "sret", return_type);
|
|
|
return lb_arg_type_indirect(return_type, attr);
|
|
|
} else if (build_context.metrics.os == TargetOs_windows && lb_is_type_kind(return_type, LLVMIntegerTypeKind) && lb_sizeof(return_type) == 16) {
|
|
@@ -898,13 +981,13 @@ namespace lbAbiAmd64SysV {
|
|
|
|
|
|
namespace lbAbiArm64 {
|
|
|
Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count);
|
|
|
- lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined);
|
|
|
+ LB_ABI_COMPUTE_RETURN_TYPE(compute_return_type);
|
|
|
bool is_homogenous_aggregate(LLVMContextRef c, LLVMTypeRef type, LLVMTypeRef *base_type_, unsigned *member_count_);
|
|
|
|
|
|
LB_ABI_INFO(abi_info) {
|
|
|
lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType);
|
|
|
ft->ctx = c;
|
|
|
- ft->ret = compute_return_type(c, return_type, return_is_defined);
|
|
|
+ ft->ret = compute_return_type(ft, c, return_type, return_is_defined, return_is_tuple);
|
|
|
ft -> args = compute_arg_types(c, arg_types, arg_count);
|
|
|
ft->calling_convention = calling_convention;
|
|
|
return ft;
|
|
@@ -1012,27 +1095,29 @@ namespace lbAbiArm64 {
|
|
|
return (member_count <= 4);
|
|
|
}
|
|
|
|
|
|
- lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef type, bool return_is_defined) {
|
|
|
+ LB_ABI_COMPUTE_RETURN_TYPE(compute_return_type) {
|
|
|
LLVMTypeRef homo_base_type = nullptr;
|
|
|
unsigned homo_member_count = 0;
|
|
|
|
|
|
if (!return_is_defined) {
|
|
|
return lb_arg_type_direct(LLVMVoidTypeInContext(c));
|
|
|
- } else if (is_register(type)) {
|
|
|
- return non_struct(c, type);
|
|
|
- } else if (is_homogenous_aggregate(c, type, &homo_base_type, &homo_member_count)) {
|
|
|
+ } else if (is_register(return_type)) {
|
|
|
+ return non_struct(c, return_type);
|
|
|
+ } else if (is_homogenous_aggregate(c, return_type, &homo_base_type, &homo_member_count)) {
|
|
|
if (is_homogenous_aggregate_small_enough(homo_base_type, homo_member_count)) {
|
|
|
- return lb_arg_type_direct(type, LLVMArrayType(homo_base_type, homo_member_count), nullptr, nullptr);
|
|
|
+ return lb_arg_type_direct(return_type, LLVMArrayType(homo_base_type, homo_member_count), nullptr, nullptr);
|
|
|
} else {
|
|
|
//TODO(Platin): do i need to create stuff that can handle the diffrent return type?
|
|
|
// else this needs a fix in llvm_backend_proc as we would need to cast it to the correct array type
|
|
|
|
|
|
+ LB_ABI_MODIFY_RETURN_IF_TUPLE_MACRO();
|
|
|
+
|
|
|
//LLVMTypeRef array_type = LLVMArrayType(homo_base_type, homo_member_count);
|
|
|
- LLVMAttributeRef attr = lb_create_enum_attribute_with_type(c, "sret", type);
|
|
|
- return lb_arg_type_indirect(type, attr);
|
|
|
+ LLVMAttributeRef attr = lb_create_enum_attribute_with_type(c, "sret", return_type);
|
|
|
+ return lb_arg_type_indirect(return_type, attr);
|
|
|
}
|
|
|
} else {
|
|
|
- i64 size = lb_sizeof(type);
|
|
|
+ i64 size = lb_sizeof(return_type);
|
|
|
if (size <= 16) {
|
|
|
LLVMTypeRef cast_type = nullptr;
|
|
|
if (size <= 1) {
|
|
@@ -1047,16 +1132,18 @@ namespace lbAbiArm64 {
|
|
|
unsigned count = cast(unsigned)((size+7)/8);
|
|
|
cast_type = LLVMArrayType(LLVMInt64TypeInContext(c), count);
|
|
|
}
|
|
|
- return lb_arg_type_direct(type, cast_type, nullptr, nullptr);
|
|
|
+ return lb_arg_type_direct(return_type, cast_type, nullptr, nullptr);
|
|
|
} else {
|
|
|
- LLVMAttributeRef attr = lb_create_enum_attribute_with_type(c, "sret", type);
|
|
|
- return lb_arg_type_indirect(type, attr);
|
|
|
+ LB_ABI_MODIFY_RETURN_IF_TUPLE_MACRO();
|
|
|
+
|
|
|
+ LLVMAttributeRef attr = lb_create_enum_attribute_with_type(c, "sret", return_type);
|
|
|
+ return lb_arg_type_indirect(return_type, attr);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count) {
|
|
|
- auto args = array_make<lbArgType>(heap_allocator(), arg_count);
|
|
|
+ auto args = array_make<lbArgType>(lb_function_type_args_allocator(), arg_count);
|
|
|
|
|
|
for (unsigned i = 0; i < arg_count; i++) {
|
|
|
LLVMTypeRef type = arg_types[i];
|
|
@@ -1102,7 +1189,7 @@ namespace lbAbiWasm {
|
|
|
registers/arguments if possible rather than by pointer.
|
|
|
*/
|
|
|
Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count);
|
|
|
- lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined);
|
|
|
+ LB_ABI_COMPUTE_RETURN_TYPE(compute_return_type);
|
|
|
|
|
|
enum {MAX_DIRECT_STRUCT_SIZE = 32};
|
|
|
|
|
@@ -1110,7 +1197,7 @@ namespace lbAbiWasm {
|
|
|
lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType);
|
|
|
ft->ctx = c;
|
|
|
ft->args = compute_arg_types(c, arg_types, arg_count);
|
|
|
- ft->ret = compute_return_type(c, return_type, return_is_defined);
|
|
|
+ ft->ret = compute_return_type(ft, c, return_type, return_is_defined, return_is_tuple);
|
|
|
ft->calling_convention = calling_convention;
|
|
|
return ft;
|
|
|
}
|
|
@@ -1188,7 +1275,7 @@ namespace lbAbiWasm {
|
|
|
|
|
|
|
|
|
Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count) {
|
|
|
- auto args = array_make<lbArgType>(heap_allocator(), arg_count);
|
|
|
+ auto args = array_make<lbArgType>(lb_function_type_args_allocator(), arg_count);
|
|
|
|
|
|
for (unsigned i = 0; i < arg_count; i++) {
|
|
|
LLVMTypeRef t = arg_types[i];
|
|
@@ -1202,7 +1289,7 @@ namespace lbAbiWasm {
|
|
|
return args;
|
|
|
}
|
|
|
|
|
|
- lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined) {
|
|
|
+ LB_ABI_COMPUTE_RETURN_TYPE(compute_return_type) {
|
|
|
if (!return_is_defined) {
|
|
|
return lb_arg_type_direct(LLVMVoidTypeInContext(c));
|
|
|
} else if (lb_is_type_kind(return_type, LLVMStructTypeKind) || lb_is_type_kind(return_type, LLVMArrayTypeKind)) {
|
|
@@ -1217,6 +1304,9 @@ namespace lbAbiWasm {
|
|
|
case 4: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 32), nullptr, nullptr);
|
|
|
case 8: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 64), nullptr, nullptr);
|
|
|
}
|
|
|
+
|
|
|
+ LB_ABI_MODIFY_RETURN_IF_TUPLE_MACRO();
|
|
|
+
|
|
|
LLVMAttributeRef attr = lb_create_enum_attribute_with_type(c, "sret", return_type);
|
|
|
return lb_arg_type_indirect(return_type, attr);
|
|
|
}
|
|
@@ -1266,7 +1356,7 @@ namespace lbAbiArm32 {
|
|
|
}
|
|
|
|
|
|
Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count, ProcCallingConvention calling_convention) {
|
|
|
- auto args = array_make<lbArgType>(heap_allocator(), arg_count);
|
|
|
+ auto args = array_make<lbArgType>(lb_function_type_args_allocator(), arg_count);
|
|
|
|
|
|
for (unsigned i = 0; i < arg_count; i++) {
|
|
|
LLVMTypeRef t = arg_types[i];
|
|
@@ -1307,14 +1397,14 @@ namespace lbAbiArm32 {
|
|
|
};
|
|
|
|
|
|
|
|
|
-LB_ABI_INFO(lb_get_abi_info) {
|
|
|
+LB_ABI_INFO(lb_get_abi_info_internal) {
|
|
|
switch (calling_convention) {
|
|
|
case ProcCC_None:
|
|
|
case ProcCC_InlineAsm:
|
|
|
{
|
|
|
lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType);
|
|
|
ft->ctx = c;
|
|
|
- ft->args = array_make<lbArgType>(heap_allocator(), arg_count);
|
|
|
+ ft->args = array_make<lbArgType>(lb_function_type_args_allocator(), arg_count);
|
|
|
for (unsigned i = 0; i < arg_count; i++) {
|
|
|
ft->args[i] = lb_arg_type_direct(arg_types[i]);
|
|
|
}
|
|
@@ -1328,32 +1418,55 @@ LB_ABI_INFO(lb_get_abi_info) {
|
|
|
}
|
|
|
case ProcCC_Win64:
|
|
|
GB_ASSERT(build_context.metrics.arch == TargetArch_amd64);
|
|
|
- return lbAbiAmd64Win64::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention);
|
|
|
+ return lbAbiAmd64Win64::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention);
|
|
|
case ProcCC_SysV:
|
|
|
GB_ASSERT(build_context.metrics.arch == TargetArch_amd64);
|
|
|
- return lbAbiAmd64SysV::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention);
|
|
|
+ return lbAbiAmd64SysV::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention);
|
|
|
}
|
|
|
|
|
|
switch (build_context.metrics.arch) {
|
|
|
case TargetArch_amd64:
|
|
|
- if (build_context.metrics.os == TargetOs_windows || build_context.metrics.abi == TargetABI_Win64) {
|
|
|
- return lbAbiAmd64Win64::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention);
|
|
|
+ if (build_context.metrics.os == TargetOs_windows) {
|
|
|
+ return lbAbiAmd64Win64::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention);
|
|
|
+ } else if (build_context.metrics.abi == TargetABI_Win64) {
|
|
|
+ return lbAbiAmd64Win64::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention);
|
|
|
} else if (build_context.metrics.abi == TargetABI_SysV) {
|
|
|
- return lbAbiAmd64SysV::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention);
|
|
|
+ return lbAbiAmd64SysV::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention);
|
|
|
} else {
|
|
|
- return lbAbiAmd64SysV::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention);
|
|
|
+ return lbAbiAmd64SysV::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention);
|
|
|
}
|
|
|
case TargetArch_i386:
|
|
|
- return lbAbi386::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention);
|
|
|
+ return lbAbi386::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention);
|
|
|
case TargetArch_arm32:
|
|
|
- return lbAbiArm32::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention);
|
|
|
+ return lbAbiArm32::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention);
|
|
|
case TargetArch_arm64:
|
|
|
- return lbAbiArm64::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention);
|
|
|
+ return lbAbiArm64::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention);
|
|
|
case TargetArch_wasm32:
|
|
|
case TargetArch_wasm64:
|
|
|
- return lbAbiWasm::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention);
|
|
|
+ return lbAbiWasm::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention);
|
|
|
}
|
|
|
|
|
|
GB_PANIC("Unsupported ABI");
|
|
|
return {};
|
|
|
}
|
|
|
+
|
|
|
+
|
|
|
+LB_ABI_INFO(lb_get_abi_info) {
|
|
|
+ lbFunctionType *ft = lb_get_abi_info_internal(
|
|
|
+ c,
|
|
|
+ arg_types, arg_count,
|
|
|
+ return_type, return_is_defined,
|
|
|
+ ALLOW_SPLIT_MULTI_RETURNS && return_is_tuple && is_calling_convention_odin(calling_convention),
|
|
|
+ calling_convention);
|
|
|
+
|
|
|
+
|
|
|
+ // NOTE(bill): this is handled here rather than when developing the type in `lb_type_internal_for_procedures_raw`
|
|
|
+ // This is to make it consistent when and how it is handled
|
|
|
+ if (calling_convention == ProcCC_Odin) {
|
|
|
+ // append the `context` pointer
|
|
|
+ lbArgType context_param = lb_arg_type_direct(LLVMPointerType(LLVMInt8TypeInContext(c), 0));
|
|
|
+ array_add(&ft->args, context_param);
|
|
|
+ }
|
|
|
+
|
|
|
+ return ft;
|
|
|
+}
|