aboutsummaryrefslogtreecommitdiff
path: root/src/llvm_abi.cpp
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2022-05-01 23:15:06 +0100
committergingerBill <bill@gingerbill.org>2022-05-01 23:15:06 +0100
commit10a311092b3a025921bdf62710972bcd91b57730 (patch)
tree6698ddaffeb7591ecf24a5c8fb582b790e03ef72 /src/llvm_abi.cpp
parent18463d68d492443e2a9a35ca0921e3994f567384 (diff)
Add basic arm32 ABI support (linux_arm32)
Diffstat (limited to 'src/llvm_abi.cpp')
-rw-r--r--src/llvm_abi.cpp88
1 files changed, 88 insertions, 0 deletions
diff --git a/src/llvm_abi.cpp b/src/llvm_abi.cpp
index 07d2dd6e3..c6ff12f95 100644
--- a/src/llvm_abi.cpp
+++ b/src/llvm_abi.cpp
@@ -516,6 +516,10 @@ namespace lbAbiAmd64SysV {
bool is_register(LLVMTypeRef type) {
LLVMTypeKind kind = LLVMGetTypeKind(type);
+ i64 sz = lb_sizeof(type);
+ if (sz == 0) {
+ return false;
+ }
switch (kind) {
case LLVMIntegerTypeKind:
case LLVMHalfTypeKind:
@@ -1164,6 +1168,88 @@ namespace lbAbiWasm32 {
}
}
+namespace lbAbiArm32 {
+ Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count, ProcCallingConvention calling_convention);
+ lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined);
+
+ 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, calling_convention);
+ ft->ret = compute_return_type(c, return_type, return_is_defined);
+ ft->calling_convention = calling_convention;
+ return ft;
+ }
+
+ bool is_register(LLVMTypeRef type, bool is_return) {
+ LLVMTypeKind kind = LLVMGetTypeKind(type);
+ switch (kind) {
+ case LLVMHalfTypeKind:
+ case LLVMFloatTypeKind:
+ case LLVMDoubleTypeKind:
+ return true;
+ case LLVMIntegerTypeKind:
+ return lb_sizeof(type) <= 8;
+ case LLVMFunctionTypeKind:
+ return true;
+ case LLVMPointerTypeKind:
+ return true;
+ case LLVMVectorTypeKind:
+ return true;
+ }
+ return false;
+ }
+
+ lbArgType non_struct(LLVMContextRef c, LLVMTypeRef type, bool is_return) {
+ LLVMAttributeRef attr = nullptr;
+ LLVMTypeRef i1 = LLVMInt1TypeInContext(c);
+ if (type == i1) {
+ attr = lb_create_enum_attribute(c, "zeroext");
+ }
+ return lb_arg_type_direct(type, nullptr, nullptr, attr);
+ }
+
+ 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);
+
+ for (unsigned i = 0; i < arg_count; i++) {
+ LLVMTypeRef t = arg_types[i];
+ if (is_register(t, false)) {
+ args[i] = non_struct(c, t, false);
+ } else {
+ i64 sz = lb_sizeof(t);
+ i64 a = lb_alignof(t);
+ if (is_calling_convention_odin(calling_convention) && sz > 8) {
+ // Minor change to improve performance using the Odin calling conventions
+ args[i] = lb_arg_type_indirect(t, nullptr);
+ } else if (a <= 4) {
+ unsigned n = cast(unsigned)((sz + 3) / 4);
+ args[i] = lb_arg_type_direct(LLVMArrayType(LLVMIntTypeInContext(c, 32), n));
+ } else {
+ unsigned n = cast(unsigned)((sz + 7) / 8);
+ args[i] = lb_arg_type_direct(LLVMArrayType(LLVMIntTypeInContext(c, 64), n));
+ }
+ }
+ }
+ return args;
+ }
+
+ lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined) {
+ if (!return_is_defined) {
+ return lb_arg_type_direct(LLVMVoidTypeInContext(c));
+ } else if (!is_register(return_type, true)) {
+ switch (lb_sizeof(return_type)) {
+ case 1: return lb_arg_type_direct(LLVMIntTypeInContext(c, 8), return_type, nullptr, nullptr);
+ case 2: return lb_arg_type_direct(LLVMIntTypeInContext(c, 16), return_type, nullptr, nullptr);
+ case 3: case 4: return lb_arg_type_direct(LLVMIntTypeInContext(c, 32), return_type, nullptr, nullptr);
+ }
+ LLVMAttributeRef attr = lb_create_enum_attribute_with_type(c, "sret", return_type);
+ return lb_arg_type_indirect(return_type, attr);
+ }
+ return non_struct(c, return_type, true);
+ }
+};
+
LB_ABI_INFO(lb_get_abi_info) {
switch (calling_convention) {
@@ -1203,6 +1289,8 @@ LB_ABI_INFO(lb_get_abi_info) {
}
case TargetArch_i386:
return lbAbi386::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention);
+ case TargetArch_arm32:
+ return lbAbiArm32::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention);
case TargetArch_arm64:
return lbAbiArm64::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention);
case TargetArch_wasm32: