From b92e8af434e852a2e0513ef21638b5518b804411 Mon Sep 17 00:00:00 2001 From: kalsprite Date: Wed, 12 Aug 2026 23:29:48 -0700 Subject: [PATCH] i128 unwrap aggregate single member structs --- src/llvm_abi.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/llvm_abi.cpp b/src/llvm_abi.cpp index 326e9c50f..da72ecd67 100644 --- a/src/llvm_abi.cpp +++ b/src/llvm_abi.cpp @@ -724,16 +724,22 @@ namespace lbAbiAmd64SysV { } gb_internal bool is_aggregate(LLVMTypeRef type) { + // A single-member wrapper is passed like its member, but only while that + // member still fits one eightbyte. `struct{i128}` needs two registers and + // goes to memory when they are gone, where a bare `i128` does not -- clang + // emits `byval align 16` for the struct and a plain `i128` for the scalar. LLVMTypeKind kind = LLVMGetTypeKind(type); switch (kind) { case LLVMStructTypeKind: if (LLVMCountStructElementTypes(type) == 1) { - return is_aggregate(LLVMStructGetTypeAtIndex(type, 0)); + LLVMTypeRef elem = LLVMStructGetTypeAtIndex(type, 0); + return lb_sizeof(elem) > 8 || is_aggregate(elem); } return true; case LLVMArrayTypeKind: if (LLVMGetArrayLength(type) == 1) { - return is_aggregate(LLVMGetElementType(type)); + LLVMTypeRef elem = OdinLLVMGetArrayElementType(type); + return lb_sizeof(elem) > 8 || is_aggregate(elem); } return true; }