From 6480504e397384e6a354c74127232e343069baf8 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 7 Apr 2026 16:04:07 +0100 Subject: [PATCH] Default to "vectorcall" calling convention for Windows AMD64 if "odin"/"contextless" --- src/llvm_abi.cpp | 56 +++++++++++++++++++++++++++------------ src/llvm_backend_proc.cpp | 6 +---- src/parser.cpp | 2 ++ src/parser.hpp | 3 +++ 4 files changed, 45 insertions(+), 22 deletions(-) diff --git a/src/llvm_abi.cpp b/src/llvm_abi.cpp index 6aabe456f..6e0c8bf3b 100644 --- a/src/llvm_abi.cpp +++ b/src/llvm_abi.cpp @@ -131,6 +131,25 @@ gb_internal LLVMTypeRef lb_function_type_to_llvm_raw(lbFunctionType *ft, bool is // } +gb_internal void lb_add_function_calling_convention(LLVMValueRef fn, ProcCallingConvention calling_convention) { + lbCallingConventionKind cc_kind = lbCallingConvention_C; + // TODO(bill): Clean up this logic + if (!is_arch_wasm()) { + cc_kind = lb_calling_convention_map[calling_convention]; + } + if (build_context.metrics.os == TargetOs_windows && + build_context.metrics.arch == TargetArch_amd64) { + switch (calling_convention) { + case ProcCC_Odin: + case ProcCC_Contextless: + cc_kind = lbCallingConvention_X86_VectorCall; + break; + } + } + LLVMSetFunctionCallConv(fn, cc_kind); +} + + gb_internal void lb_add_function_type_attributes(LLVMValueRef fn, lbFunctionType *ft, ProcCallingConvention calling_convention) { if (ft == nullptr) { return; @@ -184,23 +203,7 @@ gb_internal void lb_add_function_type_attributes(LLVMValueRef fn, lbFunctionType LLVMAddAttributeAtIndex(fn, offset, noalias_attr); } - lbCallingConventionKind cc_kind = lbCallingConvention_C; - // TODO(bill): Clean up this logic - if (!is_arch_wasm()) { - cc_kind = lb_calling_convention_map[calling_convention]; - } - // if (build_context.metrics.arch == TargetArch_amd64) { - // if (build_context.metrics.os == TargetOs_windows) { - // if (cc_kind == lbCallingConvention_C) { - // cc_kind = lbCallingConvention_Win64; - // } - // } else { - // if (cc_kind == lbCallingConvention_C) { - // cc_kind = lbCallingConvention_X86_64_SysV; - // } - // } - // } - LLVMSetFunctionCallConv(fn, cc_kind); + lb_add_function_calling_convention(fn, calling_convention); if (calling_convention == ProcCC_Odin) { unsigned context_index = arg_index; LLVMAddAttributeAtIndex(fn, context_index, noalias_attr); @@ -498,6 +501,15 @@ namespace lbAbiAmd64Win64 { args[i] = lb_arg_type_indirect(t, nullptr); break; } + } + + if (kind == LLVMVectorTypeKind) { + i64 sz = lb_sizeof(t); + if (sz <= 32) { + args[i] = lb_arg_type_direct(t, t, nullptr, nullptr); + } else { + args[i] = lbAbi386::non_struct(c, t, false); + } } else { args[i] = lbAbi386::non_struct(c, t, false); } @@ -522,6 +534,16 @@ namespace lbAbiAmd64Win64 { LLVMAttributeRef attr = lb_create_enum_attribute_with_type(c, "sret", return_type); return lb_arg_type_indirect(return_type, attr); } + + if (lb_is_type_kind(return_type, LLVMVectorTypeKind)) { + i64 sz = lb_sizeof(return_type); + if (sz <= 32) { + return lb_arg_type_direct(return_type, return_type, nullptr, nullptr); + } + + return lb_arg_type_indirect(return_type, nullptr); + } + return lbAbi386::non_struct(c, return_type, true); } }; diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 13e2e6485..06144fde3 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -429,11 +429,7 @@ gb_internal lbProcedure *lb_create_dummy_procedure(lbModule *m, String link_name p->value = LLVMAddFunction(m->mod, c_link_name, func_type); Type *pt = p->type; - lbCallingConventionKind cc_kind = lbCallingConvention_C; - if (!is_arch_wasm()) { - cc_kind = lb_calling_convention_map[pt->Proc.calling_convention]; - } - LLVMSetFunctionCallConv(p->value, cc_kind); + lb_add_function_calling_convention(p->value, pt->Proc.calling_convention); lbValue proc_value = {p->value, p->type}; lb_add_member(m, p->name, proc_value); lb_add_procedure_value(m, p); diff --git a/src/parser.cpp b/src/parser.cpp index 8fe33d2b8..b39cbfa09 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -4088,6 +4088,8 @@ gb_internal ProcCallingConvention string_to_calling_convention(String const &s) if (s == "none") return ProcCC_None; if (s == "naked") return ProcCC_Naked; + if (s == "vectorcall") return ProcCC_VectorCall; + if (s == "win64") return ProcCC_Win64; if (s == "sysv") return ProcCC_SysV; diff --git a/src/parser.hpp b/src/parser.hpp index 149cf6330..e712c136a 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -305,6 +305,8 @@ enum ProcCallingConvention : i32 { ProcCC_PreserveMost = 12, ProcCC_PreserveAll = 13, + ProcCC_VectorCall = 14, + ProcCC_MAX, @@ -326,6 +328,7 @@ gb_global char const *proc_calling_convention_strings[ProcCC_MAX] = { "preserve/none", "preserve/most", "preserve/all", + "vectorcall", }; gb_internal ProcCallingConvention default_calling_convention(void) {