diff options
| author | gingerBill <bill@gingerbill.org> | 2021-02-24 16:49:19 +0000 |
|---|---|---|
| committer | gingerBill <bill@gingerbill.org> | 2021-02-24 16:49:19 +0000 |
| commit | 2d88c6c6a552563634aba23e35b6578f6230ad87 (patch) | |
| tree | 4e5176a6253ebe189bb81c12d05f212019c2f4b4 /src/llvm_abi.cpp | |
| parent | a6fdb5eb5e1b4d37d4617e4dcf7cfaa0c3789121 (diff) | |
Begin work on aarch64 ABI for `-llvm-api`
Diffstat (limited to 'src/llvm_abi.cpp')
| -rw-r--r-- | src/llvm_abi.cpp | 181 |
1 files changed, 178 insertions, 3 deletions
diff --git a/src/llvm_abi.cpp b/src/llvm_abi.cpp index 587dd6203..4dd48fbcc 100644 --- a/src/llvm_abi.cpp +++ b/src/llvm_abi.cpp @@ -910,14 +910,187 @@ namespace lbAbiAmd64SysV { namespace lbAbiAarch64 { + 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); + bool is_homogenous_aggregate(LLVMContextRef c, LLVMTypeRef type, LLVMTypeRef *base_type_, unsigned *member_count_); + LB_ABI_INFO(abi_info) { lbFunctionType *ft = gb_alloc_item(heap_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->calling_convention = calling_convention; + ft->ret = compute_return_type(c, return_type, return_is_defined); + ft -> args = compute_arg_types(c, arg_types, arg_count); + ft->calling_convention = calling_convention; return ft; } + + bool is_register(LLVMTypeRef type) { + LLVMTypeKind kind = LLVMGetTypeKind(type); + switch (kind) { + case LLVMIntegerTypeKind: + case LLVMFloatTypeKind: + case LLVMDoubleTypeKind: + case LLVMPointerTypeKind: + return true; + } + return false; + } + + lbArgType non_struct(LLVMContextRef c, LLVMTypeRef type) { + LLVMAttributeRef attr = nullptr; + LLVMTypeRef i1 = LLVMInt1TypeInContext(c); + if (type == i1) { + attr = lb_create_enum_attribute(c, "zeroext", true); + } + return lb_arg_type_direct(type, nullptr, nullptr, attr); + } + + bool is_homogenous_array(LLVMContextRef c, LLVMTypeRef type, LLVMTypeRef *base_type_, unsigned *member_count_) { + GB_ASSERT(lb_is_type_kind(type, LLVMArrayTypeKind)); + unsigned len = LLVMGetArrayLength(type); + if (len == 0) { + return false; + } + LLVMTypeRef elem = LLVMGetElementType(type); + LLVMTypeRef base_type = nullptr; + unsigned member_count = 0; + if (is_homogenous_aggregate(c, elem, &base_type, &member_count)) { + if (base_type_) *base_type_ = base_type; + if (member_count_) *member_count_ = member_count * len; + return true; + + } + return false; + } + bool is_homogenous_struct(LLVMContextRef c, LLVMTypeRef type, LLVMTypeRef *base_type_, unsigned *member_count_) { + GB_ASSERT(lb_is_type_kind(type, LLVMStructTypeKind)); + unsigned elem_count = LLVMCountStructElementTypes(type); + if (elem_count == 0) { + return false; + } + LLVMTypeRef base_type = nullptr; + unsigned member_count = 0; + + for (unsigned i = 0; i < elem_count; i++) { + LLVMTypeRef field_type = nullptr; + unsigned field_member_count = 0; + + LLVMTypeRef elem = LLVMStructGetTypeAtIndex(type, i); + if (!is_homogenous_aggregate(c, elem, &field_type, &field_member_count)) { + return false; + } + + if (base_type == nullptr) { + base_type = field_type; + member_count = field_member_count; + } else { + if (base_type != field_type) { + return false; + } + member_count += field_member_count; + } + } + + if (base_type == nullptr) { + return false; + } + + if (lb_sizeof(type) == lb_sizeof(base_type) * member_count) { + if (base_type_) *base_type_ = base_type; + if (member_count_) *member_count_ = member_count; + return true; + } + + return false; + } + + + bool is_homogenous_aggregate(LLVMContextRef c, LLVMTypeRef type, LLVMTypeRef *base_type_, unsigned *member_count_) { + LLVMTypeKind kind = LLVMGetTypeKind(type); + switch (kind) { + case LLVMFloatTypeKind: + case LLVMDoubleTypeKind: + if (base_type_) *base_type_ = type; + if (member_count_) *member_count_ = 1; + return true; + case LLVMArrayTypeKind: + return is_homogenous_array(c, type, base_type_, member_count_); + case LLVMStructTypeKind: + return is_homogenous_struct(c, type, base_type_, member_count_); + } + return false; + } + + lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef type, bool return_is_defined) { + LLVMTypeRef homo_base_type = {}; + 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)) { + return lb_arg_type_direct(type, LLVMArrayType(homo_base_type, homo_member_count), nullptr, nullptr); + } else { + i64 size = lb_sizeof(type); + if (size <= 16) { + LLVMTypeRef cast_type = nullptr; + if (size <= 1) { + cast_type = LLVMIntTypeInContext(c, 8); + } else if (size <= 2) { + cast_type = LLVMIntTypeInContext(c, 16); + } else if (size <= 4) { + cast_type = LLVMIntTypeInContext(c, 32); + } else if (size <= 8) { + cast_type = LLVMIntTypeInContext(c, 64); + } else { + unsigned count = cast(unsigned)((size+7)/8); + cast_type = LLVMArrayType(LLVMIntTypeInContext(c, 64), count); + } + return lb_arg_type_direct(type, cast_type, nullptr, nullptr); + } else { + LLVMAttributeRef attr = lb_create_enum_attribute(c, "sret", true); + return lb_arg_type_indirect(type, attr); + } + } + } + + Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count) { + auto args = array_make<lbArgType>(heap_allocator(), arg_count); + + for (unsigned i = 0; i < arg_count; i++) { + LLVMTypeRef type = arg_types[i]; + + LLVMTypeRef homo_base_type = {}; + unsigned homo_member_count = 0; + + if (is_register(type)) { + args[i] = non_struct(c, type); + } else if (is_homogenous_aggregate(c, type, &homo_base_type, &homo_member_count)) { + args[i] = lb_arg_type_direct(type, LLVMArrayType(homo_base_type, homo_member_count), nullptr, nullptr); + } else { + i64 size = lb_sizeof(type); + if (size <= 16) { + LLVMTypeRef cast_type = nullptr; + if (size <= 1) { + cast_type = LLVMIntTypeInContext(c, 8); + } else if (size <= 2) { + cast_type = LLVMIntTypeInContext(c, 16); + } else if (size <= 4) { + cast_type = LLVMIntTypeInContext(c, 32); + } else if (size <= 8) { + cast_type = LLVMIntTypeInContext(c, 64); + } else { + unsigned count = cast(unsigned)((size+7)/8); + cast_type = LLVMArrayType(LLVMIntTypeInContext(c, 64), count); + } + args[i] = lb_arg_type_direct(type, cast_type, nullptr, nullptr); + } else { + args[i] = lb_arg_type_indirect(type, nullptr); + } + } + } + return args; + } } @@ -950,6 +1123,8 @@ LB_ABI_INFO(lb_get_abi_info) { } } else if (build_context.metrics.arch == TargetArch_386) { return lbAbi386::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention); + } else if (build_context.metrics.arch == TargetArch_aarch64) { + return lbAbiAarch64::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention); } else if (build_context.metrics.arch == TargetArch_wasm32) { return lbAbi386::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention); } |