mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 15:48:51 +00:00
Begin work on aarch64 ABI for -llvm-api
This commit is contained in:
+37
-14
@@ -23,6 +23,7 @@ enum TargetArchKind {
|
|||||||
|
|
||||||
TargetArch_amd64,
|
TargetArch_amd64,
|
||||||
TargetArch_386,
|
TargetArch_386,
|
||||||
|
TargetArch_aarch64,
|
||||||
TargetArch_wasm32,
|
TargetArch_wasm32,
|
||||||
|
|
||||||
TargetArch_COUNT,
|
TargetArch_COUNT,
|
||||||
@@ -53,6 +54,7 @@ String target_arch_names[TargetArch_COUNT] = {
|
|||||||
str_lit(""),
|
str_lit(""),
|
||||||
str_lit("amd64"),
|
str_lit("amd64"),
|
||||||
str_lit("386"),
|
str_lit("386"),
|
||||||
|
str_lit("aarch64"),
|
||||||
str_lit("wasm32"),
|
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"),
|
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 = {
|
gb_global TargetMetrics target_freebsd_386 = {
|
||||||
TargetOs_freebsd,
|
TargetOs_freebsd,
|
||||||
TargetArch_386,
|
TargetArch_386,
|
||||||
@@ -303,21 +314,23 @@ gb_global TargetMetrics target_js_wasm32 = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct NamedTargetMetrics {
|
struct NamedTargetMetrics {
|
||||||
String name;
|
String name;
|
||||||
TargetMetrics *metrics;
|
TargetMetrics *metrics;
|
||||||
};
|
};
|
||||||
|
|
||||||
gb_global NamedTargetMetrics named_targets[] = {
|
gb_global NamedTargetMetrics named_targets[] = {
|
||||||
{ str_lit("darwin_amd64"), &target_darwin_amd64 },
|
{ str_lit("darwin_amd64"), &target_darwin_amd64 },
|
||||||
{ str_lit("essence_amd64"), &target_essence_amd64 },
|
{ str_lit("darwin_aarch64"), &target_darwin_aarch64 },
|
||||||
{ str_lit("js_wasm32"), &target_js_wasm32 },
|
{ str_lit("essence_amd64"), &target_essence_amd64 },
|
||||||
{ str_lit("linux_386"), &target_linux_386 },
|
{ str_lit("js_wasm32"), &target_js_wasm32 },
|
||||||
{ str_lit("linux_amd64"), &target_linux_amd64 },
|
{ str_lit("linux_386"), &target_linux_386 },
|
||||||
{ str_lit("windows_386"), &target_windows_386 },
|
{ str_lit("linux_amd64"), &target_linux_amd64 },
|
||||||
{ str_lit("windows_amd64"), &target_windows_amd64 },
|
{ str_lit("windows_386"), &target_windows_386 },
|
||||||
{ str_lit("freebsd_386"), &target_freebsd_386 },
|
{ str_lit("windows_amd64"), &target_windows_amd64 },
|
||||||
{ str_lit("freebsd_amd64"), &target_freebsd_amd64 },
|
{ str_lit("freebsd_386"), &target_freebsd_386 },
|
||||||
|
{ str_lit("freebsd_amd64"), &target_freebsd_amd64 },
|
||||||
};
|
};
|
||||||
|
|
||||||
NamedTargetMetrics *selected_target_metrics;
|
NamedTargetMetrics *selected_target_metrics;
|
||||||
@@ -807,6 +820,21 @@ void init_build_context(TargetMetrics *cross_target) {
|
|||||||
bc->link_flags = str_lit("-arch x86 ");
|
bc->link_flags = str_lit("-arch x86 ");
|
||||||
break;
|
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) {
|
} else if (bc->metrics.arch == TargetArch_wasm32) {
|
||||||
bc->link_flags = str_lit("--no-entry --export-table --export-all --allow-undefined ");
|
bc->link_flags = str_lit("--no-entry --export-table --export-all --allow-undefined ");
|
||||||
} else {
|
} else {
|
||||||
@@ -820,10 +848,6 @@ void init_build_context(TargetMetrics *cross_target) {
|
|||||||
|
|
||||||
gbString opt_flags = gb_string_make_reserve(heap_allocator(), 64);
|
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) {
|
if (bc->microarch.len != 0) {
|
||||||
opt_flags = gb_string_appendc(opt_flags, "-march=");
|
opt_flags = gb_string_appendc(opt_flags, "-march=");
|
||||||
opt_flags = gb_string_append_length(opt_flags, bc->microarch.text, bc->microarch.len);
|
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
|
// 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
|
// 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.
|
// is resolved and confirmed by Bill. Maybe it should be readded in non-debug builds.
|
||||||
|
|||||||
+178
-3
@@ -910,14 +910,187 @@ namespace lbAbiAmd64SysV {
|
|||||||
|
|
||||||
|
|
||||||
namespace lbAbiAarch64 {
|
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) {
|
LB_ABI_INFO(abi_info) {
|
||||||
lbFunctionType *ft = gb_alloc_item(heap_allocator(), lbFunctionType);
|
lbFunctionType *ft = gb_alloc_item(heap_allocator(), lbFunctionType);
|
||||||
ft->ctx = c;
|
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 = lbAbi386::compute_return_type(c, return_type, return_is_defined);
|
ft -> args = compute_arg_types(c, arg_types, arg_count);
|
||||||
// ft->calling_convention = calling_convention;
|
ft->calling_convention = calling_convention;
|
||||||
return ft;
|
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) {
|
} else if (build_context.metrics.arch == TargetArch_386) {
|
||||||
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, 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) {
|
} else if (build_context.metrics.arch == TargetArch_wasm32) {
|
||||||
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, calling_convention);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2423,6 +2423,8 @@ LLVMValueRef OdinLLVMBuildTransmute(lbProcedure *p, LLVMValueRef val, LLVMTypeRe
|
|||||||
if (src_kind == dst_kind) {
|
if (src_kind == dst_kind) {
|
||||||
if (src_kind == LLVMPointerTypeKind) {
|
if (src_kind == LLVMPointerTypeKind) {
|
||||||
return LLVMBuildPointerCast(p->builder, val, dst_type, "");
|
return LLVMBuildPointerCast(p->builder, val, dst_type, "");
|
||||||
|
} else if (src_kind == LLVMArrayTypeKind) {
|
||||||
|
// ignore
|
||||||
} else if (src_kind != LLVMStructTypeKind) {
|
} else if (src_kind != LLVMStructTypeKind) {
|
||||||
return LLVMBuildBitCast(p->builder, val, dst_type, "");
|
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:
|
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);
|
LLVMTypeRef func_type = LLVMFunctionType(LLVMVoidTypeInContext(p->module->ctx), nullptr, 0, false);
|
||||||
LLVMValueRef the_asm = LLVMGetInlineAsm(func_type,
|
LLVMValueRef the_asm = LLVMGetInlineAsm(func_type,
|
||||||
cast(char *)"pause", 5,
|
cast(char *)"pause", 5,
|
||||||
|
|||||||
@@ -446,10 +446,10 @@ lbCallingConventionKind const lb_calling_convention_map[ProcCC_MAX] = {
|
|||||||
lbCallingConvention_C, // ProcCC_Invalid,
|
lbCallingConvention_C, // ProcCC_Invalid,
|
||||||
lbCallingConvention_C, // ProcCC_Odin,
|
lbCallingConvention_C, // ProcCC_Odin,
|
||||||
lbCallingConvention_C, // ProcCC_Contextless,
|
lbCallingConvention_C, // ProcCC_Contextless,
|
||||||
lbCallingConvention_C, // ProcCC_Pure,
|
|
||||||
lbCallingConvention_C, // ProcCC_CDecl,
|
lbCallingConvention_C, // ProcCC_CDecl,
|
||||||
lbCallingConvention_X86_StdCall, // ProcCC_StdCall,
|
lbCallingConvention_X86_StdCall, // ProcCC_StdCall,
|
||||||
lbCallingConvention_X86_FastCall, // ProcCC_FastCall,
|
lbCallingConvention_X86_FastCall, // ProcCC_FastCall,
|
||||||
|
|
||||||
lbCallingConvention_C, // ProcCC_None,
|
lbCallingConvention_C, // ProcCC_None,
|
||||||
|
lbCallingConvention_C, // ProcCC_InlineAsm,
|
||||||
};
|
};
|
||||||
|
|||||||
+1
-1
@@ -213,7 +213,7 @@ enum ProcCallingConvention {
|
|||||||
|
|
||||||
ProcCC_None = 6,
|
ProcCC_None = 6,
|
||||||
|
|
||||||
ProcCC_InlineAsm = 9,
|
ProcCC_InlineAsm = 7,
|
||||||
|
|
||||||
ProcCC_MAX,
|
ProcCC_MAX,
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user