@@ -1313,7 +1313,7 @@ namespace lbAbiWasm {
13131313 registers/arguments if possible rather than by pointer.
13141314 */
13151315 gb_internal Array<lbArgType> compute_arg_types (LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count, ProcCallingConvention calling_convention, Type *original_type);
1316- gb_internal LB_ABI_COMPUTE_RETURN_TYPE ( compute_return_type);
1316+ gb_internal lbArgType compute_return_type (lbFunctionType *ft, LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined, bool return_is_tuple, Type* original_type );
13171317
13181318 enum {MAX_DIRECT_STRUCT_SIZE = 32 };
13191319
@@ -1323,7 +1323,9 @@ namespace lbAbiWasm {
13231323 ft->ctx = c;
13241324 ft->calling_convention = calling_convention;
13251325 ft->args = compute_arg_types (c, arg_types, arg_count, calling_convention, original_type);
1326- ft->ret = compute_return_type (ft, c, return_type, return_is_defined, return_is_tuple);
1326+
1327+ GB_ASSERT (original_type->kind == Type_Proc);
1328+ ft->ret = compute_return_type (ft, c, return_type, return_is_defined, return_is_tuple, original_type->Proc .results );
13271329 return ft;
13281330 }
13291331
@@ -1359,7 +1361,7 @@ namespace lbAbiWasm {
13591361 return false ;
13601362 }
13611363
1362- gb_internal bool type_can_be_direct (LLVMTypeRef type, ProcCallingConvention calling_convention) {
1364+ gb_internal bool type_can_be_direct (LLVMTypeRef type, Type *original_type, ProcCallingConvention calling_convention) {
13631365 LLVMTypeKind kind = LLVMGetTypeKind (type);
13641366 i64 sz = lb_sizeof (type);
13651367 if (sz == 0 ) {
@@ -1372,9 +1374,21 @@ namespace lbAbiWasm {
13721374 return false ;
13731375 } else if (kind == LLVMStructTypeKind) {
13741376 unsigned count = LLVMCountStructElementTypes (type);
1377+
1378+ // NOTE(laytan): raw unions are always structs with 1 field in LLVM, need to check our own def.
1379+ Type *bt = base_type (original_type);
1380+ if (bt->kind == Type_Struct && bt->Struct .is_raw_union ) {
1381+ count = bt->Struct .fields .count ;
1382+ }
1383+
13751384 if (count == 1 ) {
1376- return type_can_be_direct (LLVMStructGetTypeAtIndex (type, 0 ), calling_convention);
1385+ return type_can_be_direct (
1386+ LLVMStructGetTypeAtIndex (type, 0 ),
1387+ type_internal_index (original_type, 0 ),
1388+ calling_convention
1389+ );
13771390 }
1391+
13781392 } else if (is_basic_register_type (type)) {
13791393 return true ;
13801394 }
@@ -1398,23 +1412,23 @@ namespace lbAbiWasm {
13981412 return false ;
13991413 }
14001414
1401- gb_internal lbArgType is_struct (LLVMContextRef c, LLVMTypeRef type, ProcCallingConvention calling_convention) {
1415+ gb_internal lbArgType is_struct (LLVMContextRef c, LLVMTypeRef type, Type *original_type, ProcCallingConvention calling_convention) {
14021416 LLVMTypeKind kind = LLVMGetTypeKind (type);
14031417 GB_ASSERT (kind == LLVMArrayTypeKind || kind == LLVMStructTypeKind);
14041418
14051419 i64 sz = lb_sizeof (type);
14061420 if (sz == 0 ) {
14071421 return lb_arg_type_ignore (type);
14081422 }
1409- if (type_can_be_direct (type, calling_convention)) {
1423+ if (type_can_be_direct (type, original_type, calling_convention)) {
14101424 return lb_arg_type_direct (type);
14111425 }
14121426 return lb_arg_type_indirect (type, nullptr );
14131427 }
14141428
1415- gb_internal lbArgType pseudo_slice (LLVMContextRef c, LLVMTypeRef type, ProcCallingConvention calling_convention) {
1429+ gb_internal lbArgType pseudo_slice (LLVMContextRef c, LLVMTypeRef type, Type *original_type, ProcCallingConvention calling_convention) {
14161430 if (build_context.metrics .ptr_size < build_context.metrics .int_size &&
1417- type_can_be_direct (type, calling_convention)) {
1431+ type_can_be_direct (type, original_type, calling_convention)) {
14181432 LLVMTypeRef types[2 ] = {
14191433 LLVMStructGetTypeAtIndex (type, 0 ),
14201434 // ignore padding
@@ -1423,7 +1437,7 @@ namespace lbAbiWasm {
14231437 LLVMTypeRef new_type = LLVMStructTypeInContext (c, types, gb_count_of (types), false );
14241438 return lb_arg_type_direct (type, new_type, nullptr , nullptr );
14251439 } else {
1426- return is_struct (c, type, calling_convention);
1440+ return is_struct (c, type, original_type, calling_convention);
14271441 }
14281442 }
14291443
@@ -1444,9 +1458,9 @@ namespace lbAbiWasm {
14441458 LLVMTypeKind kind = LLVMGetTypeKind (t);
14451459 if (kind == LLVMStructTypeKind || kind == LLVMArrayTypeKind) {
14461460 if (is_type_slice (ptype) || is_type_string (ptype)) {
1447- args[i] = pseudo_slice (c, t, calling_convention);
1461+ args[i] = pseudo_slice (c, t, ptype, calling_convention);
14481462 } else {
1449- args[i] = is_struct (c, t, calling_convention);
1463+ args[i] = is_struct (c, t, ptype, calling_convention);
14501464 }
14511465 } else {
14521466 args[i] = non_struct (c, t, false );
@@ -1455,11 +1469,11 @@ namespace lbAbiWasm {
14551469 return args;
14561470 }
14571471
1458- gb_internal LB_ABI_COMPUTE_RETURN_TYPE ( compute_return_type) {
1472+ gb_internal lbArgType compute_return_type (lbFunctionType *ft, LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined, bool return_is_tuple, Type* original_type ) {
14591473 if (!return_is_defined) {
14601474 return lb_arg_type_direct (LLVMVoidTypeInContext (c));
14611475 } else if (lb_is_type_kind (return_type, LLVMStructTypeKind) || lb_is_type_kind (return_type, LLVMArrayTypeKind)) {
1462- if (type_can_be_direct (return_type, ft->calling_convention )) {
1476+ if (type_can_be_direct (return_type, original_type, ft->calling_convention )) {
14631477 return lb_arg_type_direct (return_type);
14641478 } else if (ft->calling_convention != ProcCC_CDecl) {
14651479 i64 sz = lb_sizeof (return_type);
@@ -1471,7 +1485,36 @@ namespace lbAbiWasm {
14711485 }
14721486 }
14731487
1474- LB_ABI_MODIFY_RETURN_IF_TUPLE_MACRO ();
1488+ // Multiple returns.
1489+ if (return_is_tuple) { \
1490+ lbArgType return_arg = {};
1491+ if (lb_is_type_kind (return_type, LLVMStructTypeKind)) {
1492+ unsigned field_count = LLVMCountStructElementTypes (return_type);
1493+ if (field_count > 1 ) {
1494+ ft->original_arg_count = ft->args .count ;
1495+ ft->multiple_return_original_type = return_type;
1496+
1497+ for (unsigned i = 0 ; i < field_count-1 ; i++) {
1498+ LLVMTypeRef field_type = LLVMStructGetTypeAtIndex (return_type, i);
1499+ LLVMTypeRef field_pointer_type = LLVMPointerType (field_type, 0 );
1500+ lbArgType ret_partial = lb_arg_type_direct (field_pointer_type);
1501+ array_add (&ft->args , ret_partial);
1502+ }
1503+
1504+ LLVMTypeRef new_return_type = LLVMStructGetTypeAtIndex (return_type, field_count-1 );
1505+ return_arg = compute_return_type (
1506+ ft,
1507+ c,
1508+ LLVMStructGetTypeAtIndex (return_type, field_count-1 ),
1509+ true , false ,
1510+ type_internal_index (original_type, field_count-1 )
1511+ );
1512+ }
1513+ }
1514+ if (return_arg.type != nullptr ) {
1515+ return return_arg;
1516+ }
1517+ }
14751518
14761519 LLVMAttributeRef attr = lb_create_enum_attribute_with_type (c, " sret" , return_type);
14771520 return lb_arg_type_indirect (return_type, attr);
0 commit comments