aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/llvm_abi.cpp54
1 files changed, 36 insertions, 18 deletions
diff --git a/src/llvm_abi.cpp b/src/llvm_abi.cpp
index c6ff12f95..f4ee46386 100644
--- a/src/llvm_abi.cpp
+++ b/src/llvm_abi.cpp
@@ -1057,9 +1057,17 @@ namespace lbAbiArm64 {
}
namespace lbAbiWasm32 {
+ /*
+ NOTE(bill): All of this is custom since there is not an "official"
+ ABI definition for WASM, especially for Odin.
+ The approach taken optimizes for passing things in multiple
+ 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);
+ enum {MAX_DIRECT_STRUCT_SIZE = 32};
+
LB_ABI_INFO(abi_info) {
lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType);
ft->ctx = c;
@@ -1087,7 +1095,7 @@ namespace lbAbiWasm32 {
return lb_arg_type_direct(type, nullptr, nullptr, attr);
}
- bool is_struct_valid_elem_type(LLVMTypeRef type) {
+ bool is_basic_register_type(LLVMTypeRef type) {
switch (LLVMGetTypeKind(type)) {
case LLVMHalfTypeKind:
case LLVMFloatTypeKind:
@@ -1099,38 +1107,44 @@ namespace lbAbiWasm32 {
}
return false;
}
-
- lbArgType is_struct(LLVMContextRef c, LLVMTypeRef type) {
+
+ bool type_can_be_direct(LLVMTypeRef type) {
LLVMTypeKind kind = LLVMGetTypeKind(type);
- GB_ASSERT(kind == LLVMArrayTypeKind || kind == LLVMStructTypeKind);
-
i64 sz = lb_sizeof(type);
if (sz == 0) {
- return lb_arg_type_ignore(type);
+ return false;
}
- if (sz <= 16) {
+ if (sz <= MAX_DIRECT_STRUCT_SIZE) {
if (kind == LLVMArrayTypeKind) {
- LLVMTypeRef elem = LLVMGetElementType(type);
- if (is_struct_valid_elem_type(elem)) {
- return lb_arg_type_direct(type);
+ if (is_basic_register_type(LLVMGetElementType(type))) {
+ return true;
}
} else if (kind == LLVMStructTypeKind) {
- bool can_be_direct = true;
unsigned count = LLVMCountStructElementTypes(type);
for (unsigned i = 0; i < count; i++) {
LLVMTypeRef elem = LLVMStructGetTypeAtIndex(type, i);
- if (!is_struct_valid_elem_type(elem)) {
- can_be_direct = false;
- break;
+ if (!is_basic_register_type(elem)) {
+ return false;
}
-
- }
- if (can_be_direct) {
- return lb_arg_type_direct(type);
+
}
+ return true;
}
}
+ return false;
+ }
+
+ lbArgType is_struct(LLVMContextRef c, LLVMTypeRef type) {
+ LLVMTypeKind kind = LLVMGetTypeKind(type);
+ GB_ASSERT(kind == LLVMArrayTypeKind || kind == LLVMStructTypeKind);
+ i64 sz = lb_sizeof(type);
+ if (sz == 0) {
+ return lb_arg_type_ignore(type);
+ }
+ if (type_can_be_direct(type)) {
+ return lb_arg_type_direct(type);
+ }
return lb_arg_type_indirect(type, nullptr);
}
@@ -1154,6 +1168,10 @@ namespace lbAbiWasm32 {
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)) {
+ if (type_can_be_direct(return_type)) {
+ return lb_arg_type_direct(return_type);
+ }
+
i64 sz = lb_sizeof(return_type);
switch (sz) {
case 1: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 8), nullptr, nullptr);