diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 351a3b303..041016772 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -23,6 +23,7 @@ enum TargetArchKind { TargetArch_amd64, TargetArch_386, + TargetArch_aarch64, TargetArch_wasm32, TargetArch_COUNT, @@ -53,6 +54,7 @@ String target_arch_names[TargetArch_COUNT] = { str_lit(""), str_lit("amd64"), str_lit("386"), + str_lit("aarch64"), str_lit("wasm32"), }; @@ -268,6 +270,15 @@ gb_global TargetMetrics target_darwin_amd64 = { str_lit("e-m:o-i64:64-f80:128-n8:16:32:64-S128"), }; +gb_global TargetMetrics target_darwin_aarch64 = { + TargetOs_darwin, + TargetArch_aarch64, + 8, + 16, + str_lit("aarch64-apple-darwin"), + str_lit("e-m:o-i64:64-f64:128-n8:16:32:64-S128"), // TODO(bill): Is this correct? +}; + gb_global TargetMetrics target_freebsd_386 = { TargetOs_freebsd, TargetArch_386, @@ -303,21 +314,23 @@ gb_global TargetMetrics target_js_wasm32 = { }; + struct NamedTargetMetrics { String name; TargetMetrics *metrics; }; gb_global NamedTargetMetrics named_targets[] = { - { str_lit("darwin_amd64"), &target_darwin_amd64 }, - { str_lit("essence_amd64"), &target_essence_amd64 }, - { str_lit("js_wasm32"), &target_js_wasm32 }, - { str_lit("linux_386"), &target_linux_386 }, - { str_lit("linux_amd64"), &target_linux_amd64 }, - { str_lit("windows_386"), &target_windows_386 }, - { str_lit("windows_amd64"), &target_windows_amd64 }, - { str_lit("freebsd_386"), &target_freebsd_386 }, - { str_lit("freebsd_amd64"), &target_freebsd_amd64 }, + { str_lit("darwin_amd64"), &target_darwin_amd64 }, + { str_lit("darwin_aarch64"), &target_darwin_aarch64 }, + { str_lit("essence_amd64"), &target_essence_amd64 }, + { str_lit("js_wasm32"), &target_js_wasm32 }, + { str_lit("linux_386"), &target_linux_386 }, + { str_lit("linux_amd64"), &target_linux_amd64 }, + { str_lit("windows_386"), &target_windows_386 }, + { str_lit("windows_amd64"), &target_windows_amd64 }, + { str_lit("freebsd_386"), &target_freebsd_386 }, + { str_lit("freebsd_amd64"), &target_freebsd_amd64 }, }; NamedTargetMetrics *selected_target_metrics; @@ -807,6 +820,21 @@ void init_build_context(TargetMetrics *cross_target) { bc->link_flags = str_lit("-arch x86 "); break; } + } else if (bc->metrics.arch == TargetArch_aarch64) { + if (bc->microarch.len == 0) { + llc_flags = gb_string_appendc(llc_flags, "-march=aarch64 "); + } + + switch (bc->metrics.os) { + case TargetOs_darwin: + bc->link_flags = str_lit("-arch aarch64 "); + break; + } + if (!bc->use_llvm_api) { + gb_printf_err("The aarch64 architecture is only supported with -llvm-api\n");; + gb_exit(1); + } + } else if (bc->metrics.arch == TargetArch_wasm32) { bc->link_flags = str_lit("--no-entry --export-table --export-all --allow-undefined "); } else { @@ -820,10 +848,6 @@ void init_build_context(TargetMetrics *cross_target) { gbString opt_flags = gb_string_make_reserve(heap_allocator(), 64); - if (bc->microarch.len == 0) { - bc->microarch = str_lit("generic"); - } - if (bc->microarch.len != 0) { opt_flags = gb_string_appendc(opt_flags, "-march="); opt_flags = gb_string_append_length(opt_flags, bc->microarch.text, bc->microarch.len); @@ -850,7 +874,6 @@ void init_build_context(TargetMetrics *cross_target) { - // NOTE(lachsinc): This optimization option was previously required to get // around an issue in fmt.odin. Thank bp for tracking it down! Leaving for now until the issue // is resolved and confirmed by Bill. Maybe it should be readded in non-debug builds. 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 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 compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count) { + auto args = array_make(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); } diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index c842e2e49..d4b4fd7f2 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -2423,6 +2423,8 @@ LLVMValueRef OdinLLVMBuildTransmute(lbProcedure *p, LLVMValueRef val, LLVMTypeRe if (src_kind == dst_kind) { if (src_kind == LLVMPointerTypeKind) { return LLVMBuildPointerCast(p->builder, val, dst_type, ""); + } else if (src_kind == LLVMArrayTypeKind) { + // ignore } else if (src_kind != LLVMStructTypeKind) { return LLVMBuildBitCast(p->builder, val, dst_type, ""); } @@ -8203,7 +8205,8 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, } case BuiltinProc_cpu_relax: - { + if (build_context.metrics.arch == TargetArch_386 || + build_context.metrics.arch == TargetArch_amd64) { LLVMTypeRef func_type = LLVMFunctionType(LLVMVoidTypeInContext(p->module->ctx), nullptr, 0, false); LLVMValueRef the_asm = LLVMGetInlineAsm(func_type, cast(char *)"pause", 5, diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index 7f84b13ad..465258b73 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -446,10 +446,10 @@ lbCallingConventionKind const lb_calling_convention_map[ProcCC_MAX] = { lbCallingConvention_C, // ProcCC_Invalid, lbCallingConvention_C, // ProcCC_Odin, lbCallingConvention_C, // ProcCC_Contextless, - lbCallingConvention_C, // ProcCC_Pure, lbCallingConvention_C, // ProcCC_CDecl, lbCallingConvention_X86_StdCall, // ProcCC_StdCall, lbCallingConvention_X86_FastCall, // ProcCC_FastCall, lbCallingConvention_C, // ProcCC_None, + lbCallingConvention_C, // ProcCC_InlineAsm, }; diff --git a/src/parser.hpp b/src/parser.hpp index abc4cc625..6ce337352 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -213,7 +213,7 @@ enum ProcCallingConvention { ProcCC_None = 6, - ProcCC_InlineAsm = 9, + ProcCC_InlineAsm = 7, ProcCC_MAX,