diff options
| author | Raph <raphfl.dev@gmail.com> | 2025-06-20 16:50:00 -0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-06-20 16:50:00 -0100 |
| commit | a7e89e1324f64346b201aea8ac6205e0bc85eb21 (patch) | |
| tree | 612abe74fa630e7cddad4d37ca5a04e18ff81471 /src/llvm_abi.cpp | |
| parent | 0b5be6ad6a3c40ced071c89bb066dfd326b72943 (diff) | |
| parent | d9e08bc5d8a1292e3eccdb325bde4d180ebb4749 (diff) | |
Merge branch 'master' into tiocgwinsz_time
Diffstat (limited to 'src/llvm_abi.cpp')
| -rw-r--r-- | src/llvm_abi.cpp | 137 |
1 files changed, 100 insertions, 37 deletions
diff --git a/src/llvm_abi.cpp b/src/llvm_abi.cpp index 0b2bb7956..af08722c3 100644 --- a/src/llvm_abi.cpp +++ b/src/llvm_abi.cpp @@ -256,8 +256,10 @@ gb_internal i64 lb_sizeof(LLVMTypeRef type) { } break; +#if LLVM_VERSION_MAJOR < 20 case LLVMX86_MMXTypeKind: return 8; +#endif case LLVMVectorTypeKind: { LLVMTypeRef elem = OdinLLVMGetVectorElementType(type); @@ -310,8 +312,10 @@ gb_internal i64 lb_alignof(LLVMTypeRef type) { case LLVMArrayTypeKind: return lb_alignof(OdinLLVMGetArrayElementType(type)); +#if LLVM_VERSION_MAJOR < 20 case LLVMX86_MMXTypeKind: return 8; +#endif case LLVMVectorTypeKind: { // TODO(bill): This appears to be correct but LLVM isn't necessarily "great" with regards to documentation @@ -569,7 +573,9 @@ namespace lbAbiAmd64SysV { gb_internal void classify_with(LLVMTypeRef t, Array<RegClass> *cls, i64 ix, i64 off); gb_internal void fixup(LLVMTypeRef t, Array<RegClass> *cls); - gb_internal lbArgType amd64_type(LLVMContextRef c, LLVMTypeRef type, Amd64TypeAttributeKind attribute_kind, ProcCallingConvention calling_convention); + gb_internal lbArgType amd64_type(LLVMContextRef c, LLVMTypeRef type, Amd64TypeAttributeKind attribute_kind, ProcCallingConvention calling_convention, + bool is_arg, + i32 *int_regs, i32 *sse_regs); gb_internal Array<RegClass> classify(LLVMTypeRef t); gb_internal LLVMTypeRef llreg(LLVMContextRef c, Array<RegClass> const ®_classes, LLVMTypeRef type); @@ -579,7 +585,9 @@ namespace lbAbiAmd64SysV { } LB_ABI_MODIFY_RETURN_IF_TUPLE_MACRO(); - return amd64_type(c, return_type, Amd64TypeAttribute_StructRect, ft->calling_convention); + return amd64_type(c, return_type, Amd64TypeAttribute_StructRect, ft->calling_convention, + false, + nullptr, nullptr); } gb_internal LB_ABI_INFO(abi_info) { @@ -588,10 +596,16 @@ namespace lbAbiAmd64SysV { ft->ctx = c; ft->calling_convention = calling_convention; + i32 int_regs = 6; // rdi, rsi, rdx, rcx, r8, r9 + i32 sse_regs = 8; // xmm0-xmm7 + ft->args = array_make<lbArgType>(lb_function_type_args_allocator(), arg_count); for (unsigned i = 0; i < arg_count; i++) { - ft->args[i] = amd64_type(c, arg_types[i], Amd64TypeAttribute_ByVal, calling_convention); + ft->args[i] = amd64_type(c, arg_types[i], Amd64TypeAttribute_ByVal, calling_convention, + true, + &int_regs, &sse_regs); } + ft->ret = compute_return_type(ft, c, return_type, return_is_defined, return_is_tuple); return ft; @@ -650,17 +664,79 @@ namespace lbAbiAmd64SysV { } - gb_internal lbArgType amd64_type(LLVMContextRef c, LLVMTypeRef type, Amd64TypeAttributeKind attribute_kind, ProcCallingConvention calling_convention) { + + gb_internal bool is_aggregate(LLVMTypeRef type) { + LLVMTypeKind kind = LLVMGetTypeKind(type); + switch (kind) { + case LLVMStructTypeKind: + if (LLVMCountStructElementTypes(type) == 1) { + return is_aggregate(LLVMStructGetTypeAtIndex(type, 0)); + } + return true; + case LLVMArrayTypeKind: + if (LLVMGetArrayLength(type) == 1) { + return is_aggregate(LLVMGetElementType(type)); + } + return true; + } + return false; + }; + + gb_internal lbArgType amd64_type(LLVMContextRef c, LLVMTypeRef type, Amd64TypeAttributeKind attribute_kind, ProcCallingConvention calling_convention, + bool is_arg, + i32 *int_regs, i32 *sse_regs) { + auto cls = classify(type); + i32 needed_int = 0; + i32 needed_sse = 0; + for (auto c : cls) { + switch (c) { + case RegClass_Int: + needed_int += 1; + break; + case RegClass_SSEFs: + case RegClass_SSEFv: + case RegClass_SSEDs: + case RegClass_SSEDv: + case RegClass_SSEInt8: + case RegClass_SSEInt16: + case RegClass_SSEInt32: + case RegClass_SSEInt64: + case RegClass_SSEInt128: + case RegClass_SSEUp: + needed_sse += 1; + break; + } + } + + bool ran_out_of_regs = false; + if (int_regs && sse_regs) { + *int_regs -= needed_int; + *sse_regs -= needed_sse; + bool int_ok = *int_regs >= 0; + bool sse_ok = *sse_regs >= 0; + + *int_regs = gb_max(*int_regs, 0); + *sse_regs = gb_max(*sse_regs, 0); + + if ((!int_ok || !sse_ok) && is_aggregate(type)) { + ran_out_of_regs = true; + } + } + if (is_register(type)) { LLVMAttributeRef attribute = nullptr; if (type == LLVMInt1TypeInContext(c)) { attribute = lb_create_enum_attribute(c, "zeroext"); } return lb_arg_type_direct(type, nullptr, nullptr, attribute); - } - - auto cls = classify(type); - if (is_mem_cls(cls, attribute_kind)) { + } else if (ran_out_of_regs) { + if (is_arg) { + return lb_arg_type_indirect_byval(c, type); + } else { + LLVMAttributeRef attribute = lb_create_enum_attribute_with_type(c, "sret", type); + return lb_arg_type_indirect(type, attribute); + } + } else if (is_mem_cls(cls, attribute_kind)) { LLVMAttributeRef attribute = nullptr; if (attribute_kind == Amd64TypeAttribute_ByVal) { if (is_calling_convention_odin(calling_convention)) { @@ -901,7 +977,7 @@ namespace lbAbiAmd64SysV { return types[0]; } - return LLVMStructTypeInContext(c, types.data, cast(unsigned)types.count, sz == 0); + return LLVMStructTypeInContext(c, types.data, cast(unsigned)types.count, false); } gb_internal void classify_with(LLVMTypeRef t, Array<RegClass> *cls, i64 ix, i64 off) { @@ -1155,38 +1231,24 @@ namespace lbAbiArm64 { } } else { i64 size = lb_sizeof(return_type); - if (size <= 16) { - LLVMTypeRef cast_type = nullptr; - - if (size == 0) { - cast_type = LLVMStructTypeInContext(c, nullptr, 0, false); - } else if (size <= 8) { - cast_type = LLVMIntTypeInContext(c, cast(unsigned)(size*8)); - } else { - unsigned count = cast(unsigned)((size+7)/8); - - LLVMTypeRef llvm_i64 = LLVMIntTypeInContext(c, 64); - LLVMTypeRef *types = gb_alloc_array(temporary_allocator(), LLVMTypeRef, count); - - i64 size_copy = size; - for (unsigned i = 0; i < count; i++) { - if (size_copy >= 8) { - types[i] = llvm_i64; - } else { - types[i] = LLVMIntTypeInContext(c, 8*cast(unsigned)size_copy); - } - size_copy -= 8; - } - GB_ASSERT(size_copy <= 0); - cast_type = LLVMStructTypeInContext(c, types, count, true); - } - return lb_arg_type_direct(return_type, cast_type, nullptr, nullptr); - } else { + if (size > 16) { LB_ABI_MODIFY_RETURN_IF_TUPLE_MACRO(); LLVMAttributeRef attr = lb_create_enum_attribute_with_type(c, "sret", return_type); return lb_arg_type_indirect(return_type, attr); } + + GB_ASSERT(size <= 16); + LLVMTypeRef cast_type = nullptr; + if (size == 0) { + cast_type = LLVMStructTypeInContext(c, nullptr, 0, false); + } else if (size <= 8) { + cast_type = LLVMIntTypeInContext(c, cast(unsigned)(size*8)); + } else { + LLVMTypeRef llvm_i64 = LLVMIntTypeInContext(c, 64); + cast_type = llvm_array_type(llvm_i64, 2); + } + return lb_arg_type_direct(return_type, cast_type, nullptr, nullptr); } } @@ -1814,7 +1876,8 @@ gb_internal LB_ABI_INFO(lb_get_abi_info) { return_type, return_is_defined, ALLOW_SPLIT_MULTI_RETURNS && return_is_tuple && is_calling_convention_odin(calling_convention), calling_convention, - base_type(original_type)); + base_type(original_type) + ); // NOTE(bill): this is handled here rather than when developing the type in `lb_type_internal_for_procedures_raw` |