From dcf2edbd19f88ea2e682592a5a845ecc1f5538eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomek=20Sowi=C5=84ski?= Date: Tue, 25 Jun 2024 08:19:36 +0200 Subject: [PATCH 01/35] Replace StructFloatFieldInfoFlags with FpStructInRegistersInfo which carries also exact field sizes and offsets --- src/coreclr/inc/corinfo.h | 113 ++++++- src/coreclr/inc/icorjitinfoimpl_generated.h | 2 +- src/coreclr/inc/jiteeversionguid.h | 10 +- src/coreclr/jit/ICorJitInfo_names_generated.h | 2 +- .../jit/ICorJitInfo_wrapper_generated.hpp | 8 +- src/coreclr/jit/buildstring.cpp | 12 +- src/coreclr/jit/compiler.cpp | 51 ++- src/coreclr/jit/compiler.h | 16 +- src/coreclr/jit/gentree.cpp | 34 +- src/coreclr/jit/gentree.h | 2 +- src/coreclr/jit/lclvars.cpp | 37 +-- src/coreclr/jit/morph.cpp | 1 - src/coreclr/jit/targetriscv64.cpp | 34 +- src/coreclr/jit/utils.h | 3 + .../tools/Common/JitInterface/CorInfoImpl.cs | 4 +- .../JitInterface/CorInfoImpl_generated.cs | 6 +- .../tools/Common/JitInterface/CorInfoTypes.cs | 68 ++++ .../RISCV64PassStructInRegister.cs | 203 +++++++++++- .../ThunkGenerator/ThunkInput.txt | 3 +- .../ReadyToRun/ArgIterator.cs | 52 ++- .../ReadyToRun/TransitionBlock.cs | 2 +- .../aot/jitinterface/jitinterface_generated.h | 6 +- .../tools/superpmi/superpmi-shared/lwmlist.h | 2 +- .../superpmi-shared/methodcontext.cpp | 23 +- .../superpmi/superpmi-shared/methodcontext.h | 7 +- .../superpmi-shim-collector/icorjitinfo.cpp | 8 +- .../icorjitinfo_generated.cpp | 6 +- .../icorjitinfo_generated.cpp | 4 +- .../tools/superpmi/superpmi/icorjitinfo.cpp | 6 +- src/coreclr/vm/argdestination.h | 21 +- src/coreclr/vm/callhelpers.cpp | 6 + src/coreclr/vm/callingconvention.h | 45 +-- src/coreclr/vm/comdelegate.cpp | 2 +- src/coreclr/vm/jitinterface.cpp | 8 +- src/coreclr/vm/methodtable.cpp | 312 +++++++++++++++++- src/coreclr/vm/methodtable.h | 2 +- src/coreclr/vm/reflectioninvocation.cpp | 7 +- src/coreclr/vm/riscv64/profiler.cpp | 15 +- 38 files changed, 929 insertions(+), 214 deletions(-) diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index 89c61ebeac690..4142cd85cc480 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -356,6 +356,117 @@ enum StructFloatFieldInfoFlags STRUCT_HAS_8BYTES_FIELDS_MASK = (STRUCT_FIRST_FIELD_SIZE_IS8 | STRUCT_SECOND_FIELD_SIZE_IS8), }; +// Bitfields for FpStructInRegistersInfo::flags +namespace FpStruct +{ + enum class IntKind + { + Signed, + Unsigned, + GcRef, + GcByRef, + }; + + enum Flags + { + // Positions of flags and bitfields + PosOnlyOne = 0, + PosBothFloat = 1, + PosFloatInt = 2, + PosIntFloat = 3, + PosSizeShift1st = 4, // 2 bits + PosSizeShift2nd = 6, // 2 bits + PosIntFieldKind = 8, // 2 bits + + UseIntCallConv = 0, // struct is passed according to integer calling convention + + // The flags and bitfields + OnlyOne = 1 << PosOnlyOne, // has only one field, which is floating-point + BothFloat = 1 << PosBothFloat, // has two fields, both are floating-point + FloatInt = 1 << PosFloatInt, // has two fields, 1st is floating and 2nd is integer + IntFloat = 1 << PosIntFloat, // has two fields, 2nd is floating and 1st is integer + SizeShift1stMask = 0b11 << PosSizeShift1st, // log2(size) of 1st field + SizeShift2ndMask = 0b11 << PosSizeShift2nd, // log2(size) of 2nd field + IntFieldKindMask = 0b11 << PosIntFieldKind, // the kind of the integer field (FpStruct::IntKind) + // Note: flags OnlyOne, BothFloat, FloatInt, and IntFloat are mutually exclusive + }; +} + +// On RISC-V and LoongArch a struct with up to two non-empty fields, at least one of them floating-point, +// can be passed in registers according to hardware FP calling convention. FpStructInRegistersInfo represents +// passing information for such parameters. +struct FpStructInRegistersInfo +{ + FpStruct::Flags flags; + uint32_t offset1st; + uint32_t offset2nd; + + unsigned SizeShift1st() const { return (flags >> FpStruct::PosSizeShift1st) & 0b11; } + unsigned SizeShift2nd() const { return (flags >> FpStruct::PosSizeShift2nd) & 0b11; } + + unsigned Size1st() const { return 1u << SizeShift1st(); } + unsigned Size2nd() const { return 1u << SizeShift2nd(); } + + FpStruct::IntKind IntFieldKind() const + { + return (FpStruct::IntKind)((flags >> FpStruct::PosIntFieldKind) & 0b11); + } + + const char* IntFieldKindName() const + { + static const char* intKindNames[] = { "Signed", "Unsigned", "GcRef", "GcByRef" }; + return (flags & (FpStruct::FloatInt | FpStruct::IntFloat)) + ? intKindNames[(int)IntFieldKind()] + : "None"; + } + + const char* FlagName() const + { + switch (flags & (FpStruct::OnlyOne | FpStruct::BothFloat | FpStruct::FloatInt | FpStruct::IntFloat)) + { + case FpStruct::OnlyOne: return "OnlyOne"; + case FpStruct::BothFloat: return "BothFloat"; + case FpStruct::FloatInt: return "FloatInt"; + case FpStruct::IntFloat: return "IntFloat"; + default: return "?"; + } + } + + StructFloatFieldInfoFlags ToOldFlags() const + { + return StructFloatFieldInfoFlags( + ((flags & FpStruct::OnlyOne) ? STRUCT_FLOAT_FIELD_ONLY_ONE : 0) | + ((flags & FpStruct::BothFloat) ? STRUCT_FLOAT_FIELD_ONLY_TWO : 0) | + ((flags & FpStruct::FloatInt) ? STRUCT_FLOAT_FIELD_FIRST : 0) | + ((flags & FpStruct::IntFloat) ? STRUCT_FLOAT_FIELD_SECOND : 0) | + ((SizeShift1st() == 3) ? STRUCT_FIRST_FIELD_SIZE_IS8 : 0) | + ((SizeShift2nd() == 3) ? STRUCT_SECOND_FIELD_SIZE_IS8 : 0)); + } + + static FpStructInRegistersInfo FromOldFlags(StructFloatFieldInfoFlags flags) + { + unsigned sizeShift1st = (flags & STRUCT_FIRST_FIELD_SIZE_IS8) ? 3 : 2; + unsigned sizeShift2nd = (flags & STRUCT_SECOND_FIELD_SIZE_IS8) ? 3 : 2; + bool hasTwo = !(flags & STRUCT_FLOAT_FIELD_ONLY_ONE); + return { + FpStruct::Flags( + ((flags & STRUCT_FLOAT_FIELD_ONLY_ONE) ? FpStruct::OnlyOne : 0) | + ((flags & STRUCT_FLOAT_FIELD_ONLY_TWO) ? FpStruct::BothFloat : 0) | + ((flags & STRUCT_FLOAT_FIELD_FIRST) ? FpStruct::FloatInt : 0) | + ((flags & STRUCT_FLOAT_FIELD_SECOND) ? FpStruct::IntFloat : 0) | + (sizeShift1st << FpStruct::PosSizeShift1st) | + (hasTwo ? (sizeShift2nd << FpStruct::PosSizeShift2nd) : 0) + // No GC ref info in old flags + ), + // Lacking actual field offsets, assume fields are naturally aligned without empty fields or padding + 0, + hasTwo ? (1u << (sizeShift1st > sizeShift2nd ? sizeShift1st : sizeShift2nd)) : 0, + }; + } +}; + +static_assert(sizeof(FpStructInRegistersInfo) == 3 * sizeof(uint32_t), ""); + #include "corinfoinstructionset.h" // CorInfoHelpFunc defines the set of helpers (accessed via the ICorDynamicInfo::getHelperFtn()) @@ -3075,7 +3186,7 @@ class ICorStaticInfo virtual void getSwiftLowering(CORINFO_CLASS_HANDLE structHnd, CORINFO_SWIFT_LOWERING* pLowering) = 0; virtual uint32_t getLoongArch64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE cls) = 0; - virtual uint32_t getRISCV64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE cls) = 0; + virtual FpStructInRegistersInfo getRiscV64PassFpStructInRegistersInfo(CORINFO_CLASS_HANDLE cls) = 0; }; /***************************************************************************** diff --git a/src/coreclr/inc/icorjitinfoimpl_generated.h b/src/coreclr/inc/icorjitinfoimpl_generated.h index 38f9dac0e2e4d..3f3e1a750c38c 100644 --- a/src/coreclr/inc/icorjitinfoimpl_generated.h +++ b/src/coreclr/inc/icorjitinfoimpl_generated.h @@ -520,7 +520,7 @@ void getSwiftLowering( uint32_t getLoongArch64PassStructInRegisterFlags( CORINFO_CLASS_HANDLE structHnd) override; -uint32_t getRISCV64PassStructInRegisterFlags( +FpStructInRegistersInfo getRiscV64PassFpStructInRegistersInfo( CORINFO_CLASS_HANDLE structHnd) override; uint32_t getThreadTLSIndex( diff --git a/src/coreclr/inc/jiteeversionguid.h b/src/coreclr/inc/jiteeversionguid.h index 76a1bbc466d79..9830b3a181878 100644 --- a/src/coreclr/inc/jiteeversionguid.h +++ b/src/coreclr/inc/jiteeversionguid.h @@ -43,11 +43,11 @@ typedef const GUID *LPCGUID; #define GUID_DEFINED #endif // !GUID_DEFINED -constexpr GUID JITEEVersionIdentifier = { /* e428e66d-5e0e-4320-ad8a-fa5a50f6da07 */ - 0xe428e66d, - 0x5e0e, - 0x4320, - {0xad, 0x8a, 0xfa, 0x5a, 0x50, 0xf6, 0xda, 0x07} +constexpr GUID JITEEVersionIdentifier = { /* 1907f831-d9c8-4b42-a549-0cdce990d1c6 */ + 0x1907f831, + 0xd9c8, + 0x4b42, + {0xa5, 0x49, 0x0c, 0xdc, 0xe9, 0x90, 0xd1, 0xc6} }; ////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/coreclr/jit/ICorJitInfo_names_generated.h b/src/coreclr/jit/ICorJitInfo_names_generated.h index a2bfe1de9c80c..f027a85c22ba3 100644 --- a/src/coreclr/jit/ICorJitInfo_names_generated.h +++ b/src/coreclr/jit/ICorJitInfo_names_generated.h @@ -130,7 +130,7 @@ DEF_CLR_API(getMethodHash) DEF_CLR_API(getSystemVAmd64PassStructInRegisterDescriptor) DEF_CLR_API(getSwiftLowering) DEF_CLR_API(getLoongArch64PassStructInRegisterFlags) -DEF_CLR_API(getRISCV64PassStructInRegisterFlags) +DEF_CLR_API(getRiscV64PassFpStructInRegistersInfo) DEF_CLR_API(getThreadTLSIndex) DEF_CLR_API(getAddrOfCaptureThreadGlobal) DEF_CLR_API(getHelperFtn) diff --git a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp index ff54b778f2a2c..19e075c781337 100644 --- a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp +++ b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp @@ -1238,12 +1238,12 @@ uint32_t WrapICorJitInfo::getLoongArch64PassStructInRegisterFlags( return temp; } -uint32_t WrapICorJitInfo::getRISCV64PassStructInRegisterFlags( +FpStructInRegistersInfo WrapICorJitInfo::getRiscV64PassFpStructInRegistersInfo( CORINFO_CLASS_HANDLE structHnd) { - API_ENTER(getRISCV64PassStructInRegisterFlags); - uint32_t temp = wrapHnd->getRISCV64PassStructInRegisterFlags(structHnd); - API_LEAVE(getRISCV64PassStructInRegisterFlags); + API_ENTER(getRiscV64PassFpStructInRegistersInfo); + FpStructInRegistersInfo temp = wrapHnd->getRiscV64PassFpStructInRegistersInfo(structHnd); + API_LEAVE(getRiscV64PassFpStructInRegistersInfo); return temp; } diff --git a/src/coreclr/jit/buildstring.cpp b/src/coreclr/jit/buildstring.cpp index 3f0222ad2649a..f51e262c517ef 100644 --- a/src/coreclr/jit/buildstring.cpp +++ b/src/coreclr/jit/buildstring.cpp @@ -1,17 +1,13 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -#define STRINGIFY(L) #L -#define MAKESTRING(M, L) M(L) -#define STRINGIZE(X) MAKESTRING(STRINGIFY, X) - #if defined(__clang__) #define BUILD_COMPILER \ - "Clang " STRINGIZE(__clang_major__) "." STRINGIZE(__clang_minor__) "." STRINGIZE(__clang_patchlevel__) + "Clang " STRINGIFY(__clang_major__) "." STRINGIFY(__clang_minor__) "." STRINGIFY(__clang_patchlevel__) #elif defined(_MSC_VER) -#define BUILD_COMPILER "MSVC " STRINGIZE(_MSC_FULL_VER) +#define BUILD_COMPILER "MSVC " STRINGIFY(_MSC_FULL_VER) #elif defined(__GNUC__) -#define BUILD_COMPILER "GCC " STRINGIZE(__GNUC__) "." STRINGIZE(__GNUC_MINOR__) "." STRINGIZE(__GNUC_PATCHLEVEL__) +#define BUILD_COMPILER "GCC " STRINGIFY(__GNUC__) "." STRINGIFY(__GNUC_MINOR__) "." STRINGIFY(__GNUC_PATCHLEVEL__) #else #define BUILD_COMPILER "Unknown" #endif @@ -26,6 +22,8 @@ #define TARGET_ARCH_STRING "arm64" #elif defined(TARGET_LOONGARCH64) #define TARGET_ARCH_STRING "loongarch64" +#elif defined(TARGET_RISCV64) +#define TARGET_ARCH_STRING "riscv64" #else #define TARGET_ARCH_STRING "Unknown" #endif diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp index 9b035278d66d5..b8bd18c5d3a5a 100644 --- a/src/coreclr/jit/compiler.cpp +++ b/src/coreclr/jit/compiler.cpp @@ -947,15 +947,15 @@ var_types Compiler::getReturnTypeForStruct(CORINFO_CLASS_HANDLE clsHnd, #elif defined(TARGET_RISCV64) if (structSize <= (TARGET_POINTER_SIZE * 2)) { - uint32_t floatFieldFlags = info.compCompHnd->getRISCV64PassStructInRegisterFlags(clsHnd); - - if ((floatFieldFlags & STRUCT_FLOAT_FIELD_ONLY_ONE) != 0) + FpStructInRegistersInfo info = GetPassFpStructInRegistersInfo(clsHnd); + if ((info.flags & FpStruct::OnlyOne) != 0) { howToReturnStruct = SPK_PrimitiveType; useType = (structSize > 4) ? TYP_DOUBLE : TYP_FLOAT; } - else if (floatFieldFlags & (STRUCT_HAS_FLOAT_FIELDS_MASK ^ STRUCT_FLOAT_FIELD_ONLY_ONE)) + else if (info.flags != FpStruct::UseIntCallConv) { + assert((info.flags & (FpStruct::BothFloat | FpStruct::FloatInt | FpStruct::IntFloat)) != 0); howToReturnStruct = SPK_ByValue; useType = TYP_STRUCT; } @@ -8300,6 +8300,49 @@ void Compiler::GetStructTypeOffset( GetStructTypeOffset(structDesc, type0, type1, offset0, offset1); } +#elif defined(TARGET_RISCV64) || defined(TARGET_LOONGARCH64) +//------------------------------------------------------------------------ +// GetPassFpStructInRegistersInfo: Gets the information on passing of a struct according to hardware floating-point +// calling convention. +// +// Arguments: +// structHandle - type handle +// +// Return value: +// The passing info +FpStructInRegistersInfo Compiler::GetPassFpStructInRegistersInfo(CORINFO_CLASS_HANDLE structHandle) +{ +#ifdef TARGET_RISCV64 +#define getInfoFunc getRiscV64PassFpStructInRegistersInfo +#else +#define getInfoFunc getLoongArchPassFpStructInRegistersInfo +#endif + + FpStructInRegistersInfo ret = info.compCompHnd->getInfoFunc(structHandle); +#ifdef DEBUG + if (VERBOSE) + { + logf("**** " STRINGIFY(getInfoFunc) "(0x%x (%s, %u bytes)) =>\n", dspPtr(structHandle), + eeGetClassName(structHandle), info.compCompHnd->getClassSize(structHandle)); +#undef getInfoFunc + if (ret.flags == FpStruct::UseIntCallConv) + { + logf(" pass by integer calling convention\n"); + } + else + { + bool hasOne = ((ret.flags & FpStruct::OnlyOne) != 0); + long size2nd = hasOne ? -1l : ret.Size2nd(); + long offset2nd = hasOne ? -1l : ret.offset2nd; + logf(" may be passed by floating-point calling convention:\n" + " flags=%#03x; %s, field sizes={%u, %li}, field offsets={%u, %li}, IntFieldKind=%s\n", + ret.flags, ret.FlagName(), ret.Size1st(), size2nd, ret.offset1st, offset2nd, ret.IntFieldKindName()); + } + } +#endif // DEBUG + return ret; +} + #endif // defined(UNIX_AMD64_ABI) /*****************************************************************************/ diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 6136c97d5d47b..730f345bd54f9 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -554,17 +554,9 @@ class LclVarDsc unsigned char lvIsLastUseCopyOmissionCandidate : 1; #endif // FEATURE_IMPLICIT_BYREFS -#if defined(TARGET_LOONGARCH64) - unsigned char lvIs4Field1 : 1; // Set if the 1st field is int or float within struct for LA-ABI64. - unsigned char lvIs4Field2 : 1; // Set if the 2nd field is int or float within struct for LA-ABI64. - unsigned char lvIsSplit : 1; // Set if the argument is splited. -#endif // defined(TARGET_LOONGARCH64) - -#if defined(TARGET_RISCV64) - unsigned char lvIs4Field1 : 1; // Set if the 1st field is int or float within struct for RISCV64. - unsigned char lvIs4Field2 : 1; // Set if the 2nd field is int or float within struct for RISCV64. - unsigned char lvIsSplit : 1; // Set if the argument is splited. -#endif // defined(TARGET_RISCV64) +#if defined(TARGET_RISCV64) || defined(TARGET_LOONGARCH64) + unsigned char lvIsSplit : 1; // Set if the argument is split across last integer register and stack. +#endif // defined(TARGET_RISCV64) || defined(TARGET_LOONGARCH64) unsigned char lvSingleDef : 1; // variable has a single def. Used to identify ref type locals that can get type // updates @@ -11377,6 +11369,8 @@ class Compiler void GetStructTypeOffset( CORINFO_CLASS_HANDLE typeHnd, var_types* type0, var_types* type1, uint8_t* offset0, uint8_t* offset1); +#elif defined(TARGET_RISCV64) || defined(TARGET_LOONGARCH64) + FpStructInRegistersInfo GetPassFpStructInRegistersInfo(CORINFO_CLASS_HANDLE structHandle); #endif // defined(UNIX_AMD64_ABI) void fgMorphMultiregStructArgs(GenTreeCall* call); diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 3f2ace8415866..627bc2a6efcff 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -28690,36 +28690,30 @@ void ReturnTypeDesc::InitializeStructReturnType(Compiler* comp, #elif defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) assert((structSize >= TARGET_POINTER_SIZE) && (structSize <= (2 * TARGET_POINTER_SIZE))); -#ifdef TARGET_LOONGARCH64 - uint32_t floatFieldFlags = comp->info.compCompHnd->getLoongArch64PassStructInRegisterFlags(retClsHnd); -#else - uint32_t floatFieldFlags = comp->info.compCompHnd->getRISCV64PassStructInRegisterFlags(retClsHnd); -#endif - BYTE gcPtrs[2] = {TYPE_GC_NONE, TYPE_GC_NONE}; + FpStructInRegistersInfo fpInfo = comp->GetPassFpStructInRegistersInfo(retClsHnd); + BYTE gcPtrs[2] = {TYPE_GC_NONE, TYPE_GC_NONE}; comp->info.compCompHnd->getClassGClayout(retClsHnd, &gcPtrs[0]); - if (floatFieldFlags & STRUCT_FLOAT_FIELD_ONLY_TWO) + if ((fpInfo.flags & FpStruct::BothFloat) != 0) { comp->compFloatingPointUsed = true; - assert((structSize > 8) == ((floatFieldFlags & STRUCT_HAS_8BYTES_FIELDS_MASK) > 0)); - m_regType[0] = (floatFieldFlags & STRUCT_FIRST_FIELD_SIZE_IS8) ? TYP_DOUBLE : TYP_FLOAT; - m_regType[1] = (floatFieldFlags & STRUCT_SECOND_FIELD_SIZE_IS8) ? TYP_DOUBLE : TYP_FLOAT; + assert((structSize > 8) == ((fpInfo.SizeShift1st() == 3) || (fpInfo.SizeShift2nd() == 3))); + m_regType[0] = (fpInfo.SizeShift1st() == 3) ? TYP_DOUBLE : TYP_FLOAT; + m_regType[1] = (fpInfo.SizeShift2nd() == 3) ? TYP_DOUBLE : TYP_FLOAT; } - else if (floatFieldFlags & STRUCT_FLOAT_FIELD_FIRST) + else if ((fpInfo.flags & FpStruct::FloatInt) != 0) { comp->compFloatingPointUsed = true; - assert((structSize > 8) == ((floatFieldFlags & STRUCT_HAS_8BYTES_FIELDS_MASK) > 0)); - m_regType[0] = (floatFieldFlags & STRUCT_FIRST_FIELD_SIZE_IS8) ? TYP_DOUBLE : TYP_FLOAT; - m_regType[1] = - (floatFieldFlags & STRUCT_SECOND_FIELD_SIZE_IS8) ? comp->getJitGCType(gcPtrs[1]) : TYP_INT; + assert((structSize > 8) == ((fpInfo.SizeShift1st() == 3) || (fpInfo.SizeShift2nd() == 3))); + m_regType[0] = (fpInfo.SizeShift1st() == 3) ? TYP_DOUBLE : TYP_FLOAT; + m_regType[1] = (fpInfo.SizeShift2nd() == 3) ? comp->getJitGCType(gcPtrs[1]) : TYP_INT; } - else if (floatFieldFlags & STRUCT_FLOAT_FIELD_SECOND) + else if ((fpInfo.flags & FpStruct::IntFloat) != 0) { comp->compFloatingPointUsed = true; - assert((structSize > 8) == ((floatFieldFlags & STRUCT_HAS_8BYTES_FIELDS_MASK) > 0)); - m_regType[0] = - (floatFieldFlags & STRUCT_FIRST_FIELD_SIZE_IS8) ? comp->getJitGCType(gcPtrs[0]) : TYP_INT; - m_regType[1] = (floatFieldFlags & STRUCT_SECOND_FIELD_SIZE_IS8) ? TYP_DOUBLE : TYP_FLOAT; + assert((structSize > 8) == ((fpInfo.SizeShift1st() == 3) || (fpInfo.SizeShift2nd() == 3))); + m_regType[0] = (fpInfo.SizeShift1st() == 3) ? comp->getJitGCType(gcPtrs[0]) : TYP_INT; + m_regType[1] = (fpInfo.SizeShift2nd() == 3) ? TYP_DOUBLE : TYP_FLOAT; } else { diff --git a/src/coreclr/jit/gentree.h b/src/coreclr/jit/gentree.h index 4092f40e7d2a6..4f9e9d5f95a4e 100644 --- a/src/coreclr/jit/gentree.h +++ b/src/coreclr/jit/gentree.h @@ -4530,7 +4530,7 @@ struct CallArgABIInformation SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR StructDesc; #endif // UNIX_AMD64_ABI #if defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) - // For LoongArch64's ABI, the struct which has float field(s) and no more than two fields + // For LoongArch64's and RISC-V 64's ABI, the struct which has float field(s) and no more than two fields // may be passed by float register(s). // e.g `struct {int a; float b;}` passed by an integer register and a float register. var_types StructFloatFieldType[2]; diff --git a/src/coreclr/jit/lclvars.cpp b/src/coreclr/jit/lclvars.cpp index 84d4de9046e6b..ca886a0856065 100644 --- a/src/coreclr/jit/lclvars.cpp +++ b/src/coreclr/jit/lclvars.cpp @@ -898,24 +898,21 @@ void Compiler::lvaInitUserArgs(InitVarDscInfo* varDscInfo, unsigned skipArgs, un } else #elif defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) - uint32_t floatFlags = STRUCT_NO_FLOAT_FIELD; + FpStructInRegistersInfo fpInfo = {}; + var_types argRegTypeInStruct1 = TYP_UNKNOWN; var_types argRegTypeInStruct2 = TYP_UNKNOWN; if ((strip(corInfoType) == CORINFO_TYPE_VALUECLASS) && (argSize <= MAX_PASS_MULTIREG_BYTES)) { -#if defined(TARGET_LOONGARCH64) - floatFlags = info.compCompHnd->getLoongArch64PassStructInRegisterFlags(typeHnd); -#else - floatFlags = info.compCompHnd->getRISCV64PassStructInRegisterFlags(typeHnd); -#endif + fpInfo = GetPassFpStructInRegistersInfo(typeHnd); } - if ((floatFlags & STRUCT_HAS_FLOAT_FIELDS_MASK) != 0) + if (fpInfo.flags != FpStruct::UseIntCallConv) { assert(varTypeIsStruct(argType)); int floatNum = 0; - if ((floatFlags & STRUCT_FLOAT_FIELD_ONLY_ONE) != 0) + if ((fpInfo.flags & FpStruct::OnlyOne) != 0) { assert(argSize <= 8); assert(varDsc->lvExactSize() <= argSize); @@ -925,31 +922,31 @@ void Compiler::lvaInitUserArgs(InitVarDscInfo* varDscInfo, unsigned skipArgs, un argRegTypeInStruct1 = (varDsc->lvExactSize() == 8) ? TYP_DOUBLE : TYP_FLOAT; } - else if ((floatFlags & STRUCT_FLOAT_FIELD_ONLY_TWO) != 0) + else if ((fpInfo.flags & FpStruct::BothFloat) != 0) { floatNum = 2; canPassArgInRegisters = varDscInfo->canEnreg(TYP_DOUBLE, 2); - argRegTypeInStruct1 = (floatFlags & STRUCT_FIRST_FIELD_SIZE_IS8) ? TYP_DOUBLE : TYP_FLOAT; - argRegTypeInStruct2 = (floatFlags & STRUCT_SECOND_FIELD_SIZE_IS8) ? TYP_DOUBLE : TYP_FLOAT; + argRegTypeInStruct1 = (fpInfo.SizeShift1st() == 3) ? TYP_DOUBLE : TYP_FLOAT; + argRegTypeInStruct2 = (fpInfo.SizeShift2nd() == 3) ? TYP_DOUBLE : TYP_FLOAT; } - else if ((floatFlags & STRUCT_FLOAT_FIELD_FIRST) != 0) + else if ((fpInfo.flags & FpStruct::FloatInt) != 0) { floatNum = 1; canPassArgInRegisters = varDscInfo->canEnreg(TYP_DOUBLE, 1); canPassArgInRegisters = canPassArgInRegisters && varDscInfo->canEnreg(TYP_I_IMPL, 1); - argRegTypeInStruct1 = (floatFlags & STRUCT_FIRST_FIELD_SIZE_IS8) ? TYP_DOUBLE : TYP_FLOAT; - argRegTypeInStruct2 = (floatFlags & STRUCT_SECOND_FIELD_SIZE_IS8) ? TYP_LONG : TYP_INT; + argRegTypeInStruct1 = (fpInfo.SizeShift1st() == 3) ? TYP_DOUBLE : TYP_FLOAT; + argRegTypeInStruct2 = (fpInfo.SizeShift2nd() == 3) ? TYP_LONG : TYP_INT; } - else if ((floatFlags & STRUCT_FLOAT_FIELD_SECOND) != 0) + else if ((fpInfo.flags & FpStruct::IntFloat) != 0) { floatNum = 1; canPassArgInRegisters = varDscInfo->canEnreg(TYP_DOUBLE, 1); canPassArgInRegisters = canPassArgInRegisters && varDscInfo->canEnreg(TYP_I_IMPL, 1); - argRegTypeInStruct1 = (floatFlags & STRUCT_FIRST_FIELD_SIZE_IS8) ? TYP_LONG : TYP_INT; - argRegTypeInStruct2 = (floatFlags & STRUCT_SECOND_FIELD_SIZE_IS8) ? TYP_DOUBLE : TYP_FLOAT; + argRegTypeInStruct1 = (fpInfo.SizeShift1st() == 3) ? TYP_LONG : TYP_INT; + argRegTypeInStruct2 = (fpInfo.SizeShift2nd() == 3) ? TYP_DOUBLE : TYP_FLOAT; } assert((floatNum == 1) || (floatNum == 2)); @@ -1091,13 +1088,11 @@ void Compiler::lvaInitUserArgs(InitVarDscInfo* varDscInfo, unsigned skipArgs, un { varDsc->SetArgReg( genMapRegArgNumToRegNum(firstAllocatedRegArgNum, argRegTypeInStruct1, info.compCallConv)); - varDsc->lvIs4Field1 = (genTypeSize(argRegTypeInStruct1) == 4) ? 1 : 0; if (argRegTypeInStruct2 != TYP_UNKNOWN) { secondAllocatedRegArgNum = varDscInfo->allocRegArg(argRegTypeInStruct2, 1); varDsc->SetOtherArgReg( genMapRegArgNumToRegNum(secondAllocatedRegArgNum, argRegTypeInStruct2, info.compCallConv)); - varDsc->lvIs4Field2 = (genTypeSize(argRegTypeInStruct2) == 4) ? 1 : 0; } else if (cSlots > 1) { @@ -1675,9 +1670,7 @@ void Compiler::lvaInitVarDsc(LclVarDsc* varDsc, varDsc->lvIsImplicitByRef = 0; #endif // FEATURE_IMPLICIT_BYREFS #if defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) - varDsc->lvIs4Field1 = 0; - varDsc->lvIs4Field2 = 0; - varDsc->lvIsSplit = 0; + varDsc->lvIsSplit = 0; #endif // TARGET_LOONGARCH64 || TARGET_RISCV64 // Set the lvType (before this point it is TYP_UNDEF). diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index 1d2c876779bd4..4823e53d1c868 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -2129,7 +2129,6 @@ void CallArgs::AddFinalArgsAndDetermineABIInfo(Compiler* comp, GenTreeCall* call if (arg.NewAbiInfo.HasAnyFloatingRegisterSegment()) { // Struct passed according to hardware floating-point calling convention - assert(arg.NewAbiInfo.NumSegments <= 2); assert(!arg.NewAbiInfo.HasAnyStackSegment()); if (arg.NewAbiInfo.NumSegments == 2) { diff --git a/src/coreclr/jit/targetriscv64.cpp b/src/coreclr/jit/targetriscv64.cpp index 6adb2b7b91ea1..0e5e40bd63fcf 100644 --- a/src/coreclr/jit/targetriscv64.cpp +++ b/src/coreclr/jit/targetriscv64.cpp @@ -58,10 +58,11 @@ ABIPassingInformation RiscV64Classifier::Classify(Compiler* comp, ClassLayout* structLayout, WellKnownArg /*wellKnownParam*/) { - StructFloatFieldInfoFlags flags = STRUCT_NO_FLOAT_FIELD; - unsigned intFields = 0, floatFields = 0; - unsigned passedSize; + FpStructInRegistersInfo info = {}; + unsigned intFields = 0, floatFields = 0; + unsigned passedSize; + using namespace FpStruct; if (varTypeIsStruct(type)) { passedSize = structLayout->GetSize(); @@ -71,20 +72,19 @@ ABIPassingInformation RiscV64Classifier::Classify(Compiler* comp, } else if (!structLayout->IsBlockLayout()) { - flags = (StructFloatFieldInfoFlags)comp->info.compCompHnd->getRISCV64PassStructInRegisterFlags( - structLayout->GetClassHandle()); + info = comp->GetPassFpStructInRegistersInfo(structLayout->GetClassHandle()); - if ((flags & STRUCT_FLOAT_FIELD_ONLY_ONE) != 0) + if ((info.flags & OnlyOne) != 0) { floatFields = 1; } - else if ((flags & STRUCT_FLOAT_FIELD_ONLY_TWO) != 0) + else if ((info.flags & BothFloat) != 0) { floatFields = 2; } - else if (flags != STRUCT_NO_FLOAT_FIELD) + else if (info.flags != UseIntCallConv) { - assert((flags & (STRUCT_FLOAT_FIELD_FIRST | STRUCT_FLOAT_FIELD_SECOND)) != 0); + assert((info.flags & (FloatInt | IntFloat)) != 0); floatFields = 1; intFields = 1; } @@ -104,10 +104,10 @@ ABIPassingInformation RiscV64Classifier::Classify(Compiler* comp, // Hardware floating-point calling convention if ((floatFields == 1) && (intFields == 0)) { - if (flags == STRUCT_NO_FLOAT_FIELD) + if (info.flags == UseIntCallConv) assert(varTypeIsFloating(type)); // standalone floating-point real else - assert((flags & STRUCT_FLOAT_FIELD_ONLY_ONE) != 0); // struct containing just one FP real + assert((info.flags & OnlyOne) != 0); // struct containing just one FP real return ABIPassingInformation::FromSegment(comp, ABIPassingSegment::InRegister(m_floatRegs.Dequeue(), 0, passedSize)); @@ -116,15 +116,15 @@ ABIPassingInformation RiscV64Classifier::Classify(Compiler* comp, { assert(varTypeIsStruct(type)); assert((floatFields + intFields) == 2); - assert(flags != STRUCT_NO_FLOAT_FIELD); - assert((flags & STRUCT_FLOAT_FIELD_ONLY_ONE) == 0); + assert(info.flags != UseIntCallConv); + assert((info.flags & OnlyOne) == 0); - unsigned firstSize = ((flags & STRUCT_FIRST_FIELD_SIZE_IS8) != 0) ? 8 : 4; - unsigned secondSize = ((flags & STRUCT_SECOND_FIELD_SIZE_IS8) != 0) ? 8 : 4; + unsigned firstSize = (info.SizeShift1st() == 3) ? 8 : 4; + unsigned secondSize = (info.SizeShift2nd() == 3) ? 8 : 4; unsigned offset = max(firstSize, secondSize); // TODO: cover empty fields and custom offsets / alignments - bool isFirstFloat = (flags & (STRUCT_FLOAT_FIELD_ONLY_TWO | STRUCT_FLOAT_FIELD_FIRST)) != 0; - bool isSecondFloat = (flags & (STRUCT_FLOAT_FIELD_ONLY_TWO | STRUCT_FLOAT_FIELD_SECOND)) != 0; + bool isFirstFloat = (info.flags & (BothFloat | FloatInt)) != 0; + bool isSecondFloat = (info.flags & (BothFloat | IntFloat)) != 0; assert(isFirstFloat || isSecondFloat); regNumber firstReg = (isFirstFloat ? m_floatRegs : m_intRegs).Dequeue(); diff --git a/src/coreclr/jit/utils.h b/src/coreclr/jit/utils.h index f665a4e813eff..1a28ba7b8dee5 100644 --- a/src/coreclr/jit/utils.h +++ b/src/coreclr/jit/utils.h @@ -1174,4 +1174,7 @@ bool CastFromFloatOverflows(float fromValue, var_types toType); bool CastFromDoubleOverflows(double fromValue, var_types toType); } // namespace CheckedOps +#define STRINGIFY_(x) #x +#define STRINGIFY(x) STRINGIFY_(x) + #endif // _UTILS_H_ diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index a695d07be6fcf..6c31276783f73 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -3453,10 +3453,10 @@ private uint getLoongArch64PassStructInRegisterFlags(CORINFO_CLASS_STRUCT_* cls) return LoongArch64PassStructInRegister.GetLoongArch64PassStructInRegisterFlags(typeDesc); } - private uint getRISCV64PassStructInRegisterFlags(CORINFO_CLASS_STRUCT_* cls) + private FpStructInRegistersInfo getRiscV64PassFpStructInRegistersInfo(CORINFO_CLASS_STRUCT_* cls) { TypeDesc typeDesc = HandleToObject(cls); - return RISCV64PassStructInRegister.GetRISCV64PassStructInRegisterFlags(typeDesc); + return RISCV64PassStructInRegister.GetRiscV64PassFpStructInRegistersInfo(typeDesc); } private uint getThreadTLSIndex(ref void* ppIndirection) diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs index 950ce7f4a1223..71cd542838a59 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs @@ -1874,12 +1874,12 @@ private static uint _getLoongArch64PassStructInRegisterFlags(IntPtr thisHandle, } [UnmanagedCallersOnly] - private static uint _getRISCV64PassStructInRegisterFlags(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* structHnd) + private static FpStructInRegistersInfo _getRiscV64PassFpStructInRegistersInfo(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* structHnd) { var _this = GetThis(thisHandle); try { - return _this.getRISCV64PassStructInRegisterFlags(structHnd); + return _this.getRiscV64PassFpStructInRegistersInfo(structHnd); } catch (Exception ex) { @@ -2737,7 +2737,7 @@ private static IntPtr GetUnmanagedCallbacks() callbacks[123] = (delegate* unmanaged)&_getSystemVAmd64PassStructInRegisterDescriptor; callbacks[124] = (delegate* unmanaged)&_getSwiftLowering; callbacks[125] = (delegate* unmanaged)&_getLoongArch64PassStructInRegisterFlags; - callbacks[126] = (delegate* unmanaged)&_getRISCV64PassStructInRegisterFlags; + callbacks[126] = (delegate* unmanaged)&_getRiscV64PassFpStructInRegistersInfo; callbacks[127] = (delegate* unmanaged)&_getThreadTLSIndex; callbacks[128] = (delegate* unmanaged)&_getAddrOfCaptureThreadGlobal; callbacks[129] = (delegate* unmanaged)&_getHelperFtn; diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs index b7062fc766035..58c987db0a417 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs @@ -1262,6 +1262,74 @@ public enum StructFloatFieldInfoFlags STRUCT_HAS_8BYTES_FIELDS_MASK = (STRUCT_FIRST_FIELD_SIZE_IS8 | STRUCT_SECOND_FIELD_SIZE_IS8), }; + + public enum FpStruct_IntKind + { + Signed, + Unsigned, + GcRef, + GcByRef, + } + + // Bitfields for FpStructInRegistersInfo.flags + [Flags] + public enum FpStruct + { + // Positions of flags and bitfields + PosOnlyOne = 0, + PosBothFloat = 1, + PosFloatInt = 2, + PosIntFloat = 3, + PosSizeShift1st = 4, // 2 bits + PosSizeShift2nd = 6, // 2 bits + PosIntFieldKind = 8, // 2 bits + + UseIntCallConv = 0, // struct is passed according to integer calling convention + + // The flags and bitfields + OnlyOne = 1 << PosOnlyOne, // has only one field, which is floating-point + BothFloat = 1 << PosBothFloat, // has two fields, both are floating-point + FloatInt = 1 << PosFloatInt, // has two fields, 1st is floating and 2nd is integer + IntFloat = 1 << PosIntFloat, // has two fields, 2nd is floating and 1st is integer + SizeShift1stMask = 0b11 << PosSizeShift1st, // log2(size) of 1st field + SizeShift2ndMask = 0b11 << PosSizeShift2nd, // log2(size) of 2nd field + IntFieldKindMask = 0b11 << PosIntFieldKind, // the kind of the integer field (FpStruct::IntKind) + // Note: flags OnlyOne, BothFloat, FloatInt, and IntFloat are mutually exclusive + } + + // On RISC-V and LoongArch a struct with up to two non-empty fields, at least one of them floating-point, + // can be passed in registers according to hardware FP calling convention. FpStructInRegistersInfo represents + // passing information for such parameters. + public struct FpStructInRegistersInfo + { + public FpStruct flags; + public uint offset1st; + public uint offset2nd; + + public uint SizeShift1st() { return (uint)((int)flags >> (int)FpStruct.PosSizeShift1st) & 0b11; } + + public uint SizeShift2nd() { return (uint)((int)flags >> (int)FpStruct.PosSizeShift2nd) & 0b11; } + + public uint Size1st() { return 1u << (int)SizeShift1st(); } + public uint Size2nd() { return 1u << (int)SizeShift2nd(); } + + public FpStruct_IntKind IntFieldKind() + { + return (FpStruct_IntKind)(((int)flags >> (int)FpStruct.PosIntFieldKind) & 0b11); + } + + public StructFloatFieldInfoFlags ToOldFlags() + { + return + ((flags & FpStruct.OnlyOne) != 0 ? StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_ONLY_ONE : 0) | + ((flags & FpStruct.BothFloat) != 0 ? StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_ONLY_TWO : 0) | + ((flags & FpStruct.FloatInt) != 0 ? StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_FIRST : 0) | + ((flags & FpStruct.IntFloat) != 0 ? StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_SECOND : 0) | + ((SizeShift1st() == 3) ? StructFloatFieldInfoFlags.STRUCT_FIRST_FIELD_SIZE_IS8 : 0) | + ((SizeShift2nd() == 3) ? StructFloatFieldInfoFlags.STRUCT_SECOND_FIELD_SIZE_IS8 : 0); + } + } + // DEBUGGER DATA public enum MappingTypes { diff --git a/src/coreclr/tools/Common/JitInterface/RISCV64PassStructInRegister.cs b/src/coreclr/tools/Common/JitInterface/RISCV64PassStructInRegister.cs index fae694f8768fc..1d60ae3c533cc 100644 --- a/src/coreclr/tools/Common/JitInterface/RISCV64PassStructInRegister.cs +++ b/src/coreclr/tools/Common/JitInterface/RISCV64PassStructInRegister.cs @@ -5,6 +5,7 @@ using System.Diagnostics; using ILCompiler; using Internal.TypeSystem; +using static Internal.JitInterface.FpStruct; using static Internal.JitInterface.StructFloatFieldInfoFlags; namespace Internal.JitInterface @@ -15,7 +16,7 @@ private const int ENREGISTERED_PARAMTYPE_MAXSIZE = 16, TARGET_POINTER_SIZE = 8; - private static bool HandleInlineArray(int elementTypeIndex, int nElements, Span types, ref int typeIndex) + private static bool HandleInlineArrayOld(int elementTypeIndex, int nElements, Span types, ref int typeIndex) { int nFlattenedFieldsPerElement = typeIndex - elementTypeIndex; if (nFlattenedFieldsPerElement == 0) @@ -38,7 +39,7 @@ private static bool HandleInlineArray(int elementTypeIndex, int nElements, Span< return true; } - private static bool FlattenFieldTypes(TypeDesc td, Span types, ref int typeIndex) + private static bool FlattenFieldTypesOld(TypeDesc td, Span types, ref int typeIndex) { IEnumerable fields = td.GetFields(); int nFields = 0; @@ -59,7 +60,7 @@ private static bool FlattenFieldTypes(TypeDesc td, Span ENREGISTERED_PARAMTYPE_MAXSIZE) return (uint)STRUCT_NO_FLOAT_FIELD; @@ -97,7 +98,7 @@ public static uint GetRISCV64PassStructInRegisterFlags(TypeDesc td) STRUCT_NO_FLOAT_FIELD, STRUCT_NO_FLOAT_FIELD }; int nFields = 0; - if (!FlattenFieldTypes(td, types, ref nFields) || nFields == 0) + if (!FlattenFieldTypesOld(td, types, ref nFields) || nFields == 0) return (uint)STRUCT_NO_FLOAT_FIELD; Debug.Assert(nFields == 1 || nFields == 2); @@ -123,5 +124,195 @@ public static uint GetRISCV64PassStructInRegisterFlags(TypeDesc td) } return (uint)flags; } + + + private static void SetFpStructInRegistersInfoField(ref FpStructInRegistersInfo info, int index, + bool isFloating, FpStruct_IntKind intKind, uint size, uint offset) + { + Debug.Assert(index < 2); + if (isFloating) + { + Debug.Assert(size == sizeof(float) || size == sizeof(double)); + Debug.Assert(intKind == FpStruct_IntKind.Signed); + Debug.Assert((int)FpStruct_IntKind.Signed == 0, + "IntKind for floating fields should not clobber IntKind for int fields"); + } + + Debug.Assert(size >= 1 && size <= 8); + Debug.Assert((size & (size - 1)) == 0, "size needs to be a power of 2"); + const int sizeShiftLUT = (0 << (1*2)) | (1 << (2*2)) | (2 << (4*2)) | (3 << (8*2)); + int sizeShift = (sizeShiftLUT >> ((int)size * 2)) & 0b11; + + // Use FloatInt and IntFloat as marker flags for 1st and 2nd field respectively being floating. + // Fix to real flags (with OnlyOne and BothFloat) after flattening is complete. + Debug.Assert((int)PosIntFloat == (int)PosFloatInt + 1, "FloatInt and IntFloat need to be adjacent"); + Debug.Assert((int)PosSizeShift2nd == (int)PosSizeShift1st + 2, "SizeShift1st and 2nd need to be adjacent"); + int floatFlag = Convert.ToInt32(isFloating) << ((int)PosFloatInt + index); + int sizeShiftMask = sizeShift << ((int)PosSizeShift1st + 2 * index); + + info.flags |= (FpStruct)(floatFlag | sizeShiftMask | ((int)intKind << (int)PosIntFieldKind)); + (index == 0 ? ref info.offset1st : ref info.offset2nd) = offset; + } + + private static bool HandleInlineArray(int elementTypeIndex, int nElements, ref FpStructInRegistersInfo info, ref int typeIndex) + { + int nFlattenedFieldsPerElement = typeIndex - elementTypeIndex; + if (nFlattenedFieldsPerElement == 0) + { + Debug.Assert(nElements == 1, "HasImpliedRepeatedFields must have returned a false positive"); + return true; // ignoring empty struct + } + + Debug.Assert(nFlattenedFieldsPerElement == 1 || nFlattenedFieldsPerElement == 2); + + if (nElements > 2) + return false; // array has too many elements + + if (nElements == 2) + { + if (typeIndex + nFlattenedFieldsPerElement > 2) + return false; // array has too many fields per element + + Debug.Assert(elementTypeIndex == 0); + Debug.Assert(typeIndex == 1); + + // duplicate the array element info + const int typeSize = (int)PosIntFloat - (int)PosFloatInt; + info.flags |= (FpStruct)((int)info.flags << typeSize); + info.offset2nd = info.offset1st + info.Size1st(); + } + return true; + } + + private static bool FlattenFields(TypeDesc td, uint offset, ref FpStructInRegistersInfo info, ref int typeIndex) + { + IEnumerable fields = td.GetFields(); + int nFields = 0; + int elementTypeIndex = typeIndex; + FieldDesc prevField = null; + foreach (FieldDesc field in fields) + { + if (field.IsStatic) + continue; + nFields++; + + if (prevField != null && prevField.Offset.AsInt + prevField.FieldType.GetElementSize().AsInt > field.Offset.AsInt) + return false; // fields overlap, treat as union + + prevField = field; + + TypeFlags category = field.FieldType.Category; + if (category == TypeFlags.ValueType) + { + TypeDesc nested = field.FieldType; + if (!FlattenFields(nested, offset + (uint)field.Offset.AsInt, ref info, ref typeIndex)) + return false; + } + else if (field.FieldType.GetElementSize().AsInt <= TARGET_POINTER_SIZE) + { + if (typeIndex >= 2) + return false; // too many fields + + bool isFloating = category is TypeFlags.Single or TypeFlags.Double; + bool isSignedInt = category is + TypeFlags.SByte or + TypeFlags.Int16 or + TypeFlags.Int32 or + TypeFlags.Int64 or + TypeFlags.IntPtr; + bool isGcRef = category is + TypeFlags.Class or + TypeFlags.Interface or + TypeFlags.Array or + TypeFlags.SzArray; + + FpStruct_IntKind intKind = + isGcRef ? FpStruct_IntKind.GcRef : + (category is TypeFlags.ByRef) ? FpStruct_IntKind.GcByRef : + (isSignedInt || isFloating) ? FpStruct_IntKind.Signed : FpStruct_IntKind.Unsigned; + + SetFpStructInRegistersInfoField(ref info, typeIndex++, + isFloating, intKind, (uint)field.FieldType.GetElementSize().AsInt, offset + (uint)field.Offset.AsInt); + } + else + { + return false; // field is too big + } + } + + if ((td as MetadataType).HasImpliedRepeatedFields()) + { + Debug.Assert(nFields == 1); + int nElements = td.GetElementSize().AsInt / prevField.FieldType.GetElementSize().AsInt; + if (!HandleInlineArray(elementTypeIndex, nElements, ref info, ref typeIndex)) + return false; + } + return true; + } + + private static bool IsAligned(uint val, uint alignment) => 0 == (val & (alignment - 1)); + + private static FpStructInRegistersInfo GetRiscV64PassFpStructInRegistersInfoImpl(TypeDesc td) + { + FpStructInRegistersInfo info = new FpStructInRegistersInfo{}; + int nFields = 0; + if (!FlattenFields(td, 0, ref info, ref nFields)) + return new FpStructInRegistersInfo{}; + + if ((info.flags & (FloatInt | IntFloat)) == 0) + return new FpStructInRegistersInfo{}; // struct has no floating fields + + Debug.Assert(nFields == 1 || nFields == 2); + + if ((info.flags & (FloatInt | IntFloat)) == (FloatInt | IntFloat)) + { + Debug.Assert(nFields == 2); + info.flags ^= (FloatInt | IntFloat | BothFloat); // replace (FloatInt | IntFloat) with BothFloat + } + else if (nFields == 1) + { + Debug.Assert((info.flags & FloatInt) != 0); + Debug.Assert((info.flags & (IntFloat | SizeShift2ndMask)) == 0); + Debug.Assert(info.offset2nd == 0); + info.flags ^= (FloatInt | OnlyOne); // replace FloatInt with OnlyOne + } + Debug.Assert(nFields == ((info.flags & OnlyOne) != 0 ? 1 : 2)); + FpStruct floatFlags = info.flags & (OnlyOne | BothFloat | FloatInt | IntFloat); + Debug.Assert(floatFlags != 0); + Debug.Assert(((uint)floatFlags & ((uint)floatFlags - 1)) == 0, + "there can be only one of (OnlyOne | BothFloat | FloatInt | IntFloat)"); + if (nFields == 2) + { + uint end1st = info.offset1st + info.Size1st(); + uint end2nd = info.offset2nd + info.Size2nd(); + Debug.Assert(end1st <= info.offset2nd || end2nd <= info.offset1st, "fields must not overlap"); + } + Debug.Assert(info.offset1st + info.Size1st() <= td.GetElementSize().AsInt); + Debug.Assert(info.offset2nd + info.Size2nd() <= td.GetElementSize().AsInt); + if (info.IntFieldKind() != FpStruct_IntKind.Signed) + { + Debug.Assert((info.flags & (FloatInt | IntFloat)) != 0); + if (info.IntFieldKind() >= FpStruct_IntKind.GcRef) + { + Debug.Assert((info.flags & IntFloat) != 0 + ? ((info.SizeShift1st() == 3) && IsAligned(info.offset1st, TARGET_POINTER_SIZE)) + : ((info.SizeShift2nd() == 3) && IsAligned(info.offset2nd, TARGET_POINTER_SIZE))); + } + } + if ((info.flags & (OnlyOne | BothFloat)) != 0) + Debug.Assert(info.IntFieldKind() == FpStruct_IntKind.Signed); + + return info; + } + + public static FpStructInRegistersInfo GetRiscV64PassFpStructInRegistersInfo(TypeDesc td) + { + FpStructInRegistersInfo info = GetRiscV64PassFpStructInRegistersInfoImpl(td); + uint flags = GetRISCV64PassStructInRegisterFlags(td); + + Debug.Assert(flags == (uint)info.ToOldFlags()); + + return info; + } } } diff --git a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt index 9fc314fe56a37..e0d13ac19a8ef 100644 --- a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt +++ b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt @@ -100,6 +100,7 @@ CORINFO_HELPER_DESC*,ref CORINFO_HELPER_DESC const CORINFO_HELPER_DESC*,ref CORINFO_HELPER_DESC int*,ref int unsigned int*,ref uint +FpStructInRegistersInfo,FpStructInRegistersInfo CORINFO_JUST_MY_CODE_HANDLE**,ref CORINFO_JUST_MY_CODE_HANDLE_* @@ -289,7 +290,7 @@ FUNCTIONS bool getSystemVAmd64PassStructInRegisterDescriptor(CORINFO_CLASS_HANDLE structHnd, SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structPassInRegDescPtr); void getSwiftLowering(CORINFO_CLASS_HANDLE structHnd, CORINFO_SWIFT_LOWERING* pLowering); uint32_t getLoongArch64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE structHnd); - uint32_t getRISCV64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE structHnd); + FpStructInRegistersInfo getRiscV64PassFpStructInRegistersInfo(CORINFO_CLASS_HANDLE structHnd); uint32_t getThreadTLSIndex(void **ppIndirection); int32_t * getAddrOfCaptureThreadGlobal(void **ppIndirection); void* getHelperFtn (CorInfoHelpFunc ftnNum, void **ppIndirection); diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ArgIterator.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ArgIterator.cs index 16736aef48853..2e9e66fc4b71c 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ArgIterator.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ArgIterator.cs @@ -234,6 +234,8 @@ internal struct ArgLocDesc public int m_byteStackSize; // Stack size in bytes public uint m_floatFlags; // struct with two-fields can be passed by registers. + public FpStructInRegistersInfo m_structFields; // RISC-V - Struct field info when using floating-point register(s) + // Initialize to represent a non-placed argument (no register or stack slots referenced). public void Init() { @@ -244,6 +246,7 @@ public void Init() m_byteStackIndex = -1; m_byteStackSize = 0; m_floatFlags = 0; + m_structFields = new FpStructInRegistersInfo(); m_fRequires64BitAlignment = false; } @@ -1458,19 +1461,18 @@ public int GetNextOffset() case TargetArchitecture.RiscV64: { + if (IsVarArg) + throw new NotImplementedException("Varargs on RISC-V not supported yet"); + int cFPRegs = 0; - uint floatFieldFlags = (uint)StructFloatFieldInfoFlags.STRUCT_NO_FLOAT_FIELD; + FpStructInRegistersInfo info = new FpStructInRegistersInfo{}; _hasArgLocDescForStructInRegs = false; switch (argType) { case CorElementType.ELEMENT_TYPE_R4: - // 32-bit floating point argument. - cFPRegs = 1; - break; - case CorElementType.ELEMENT_TYPE_R8: - // 64-bit floating point argument. + // Floating point argument cFPRegs = 1; break; @@ -1483,14 +1485,10 @@ public int GetNextOffset() } else { - floatFieldFlags = RISCV64PassStructInRegister.GetRISCV64PassStructInRegisterFlags(_argTypeHandle.GetRuntimeTypeHandle()); - if ((floatFieldFlags & (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_ONLY_TWO) != 0) - { - cFPRegs = 2; - } - else if ((floatFieldFlags & (uint)StructFloatFieldInfoFlags.STRUCT_HAS_FLOAT_FIELDS_MASK) != 0) + info = RISCV64PassStructInRegister.GetRiscV64PassFpStructInRegistersInfo(_argTypeHandle.GetRuntimeTypeHandle()); + if (info.flags != FpStruct.UseIntCallConv) { - cFPRegs = 1; + cFPRegs = ((info.flags & FpStruct.BothFloat) != 0) ? 2 : 1; } } @@ -1506,36 +1504,40 @@ public int GetNextOffset() if (cFPRegs > 0 && !IsVarArg) { - if (isValueType && ((floatFieldFlags & (uint)StructFloatFieldInfoFlags.STRUCT_HAS_ONE_FLOAT_MASK) != 0)) + if ((info.flags & (FpStruct.FloatInt | FpStruct.IntFloat)) != 0) { Debug.Assert(cFPRegs == 1); - if ((_riscv64IdxFPReg < 8) && (_riscv64IdxGenReg < 8)) + + if ((1 + _riscv64IdxFPReg <= _transitionBlock.NumArgumentRegisters) && (1 + _riscv64IdxGenReg <= _transitionBlock.NumArgumentRegisters)) { _argLocDescForStructInRegs = new ArgLocDesc(); _argLocDescForStructInRegs.m_idxFloatReg = _riscv64IdxFPReg; _argLocDescForStructInRegs.m_cFloatReg = 1; + _argLocDescForStructInRegs.m_structFields = info; + _argLocDescForStructInRegs.m_idxGenReg = _riscv64IdxGenReg; _argLocDescForStructInRegs.m_cGenReg = 1; _hasArgLocDescForStructInRegs = true; - _argLocDescForStructInRegs.m_floatFlags = floatFieldFlags; - int argOfsInner = - ((floatFieldFlags & (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_SECOND) != 0) - ? _transitionBlock.OffsetOfArgumentRegisters + _riscv64IdxGenReg * 8 - : _transitionBlock.OffsetOfFloatArgumentRegisters + _riscv64IdxFPReg * 8; + int argOfsInner = ((info.flags & FpStruct.IntFloat) != 0) + ? _transitionBlock.OffsetOfArgumentRegisters + _riscv64IdxGenReg * _transitionBlock.PointerSize + : _transitionBlock.OffsetOfFloatArgumentRegisters + _riscv64IdxFPReg * _transitionBlock.FloatRegisterSize; _riscv64IdxFPReg++; _riscv64IdxGenReg++; return argOfsInner; } } - else if (cFPRegs + _riscv64IdxFPReg <= 8) + else if (cFPRegs + _riscv64IdxFPReg <= _transitionBlock.NumArgumentRegisters) { // Each floating point register in the argument area is 8 bytes. int argOfsInner = _transitionBlock.OffsetOfFloatArgumentRegisters + _riscv64IdxFPReg * 8; - if (floatFieldFlags == (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_ONLY_TWO) + const FpStruct twoFloats = FpStruct.BothFloat + | (FpStruct)(2 << (int)FpStruct.PosSizeShift1st) + | (FpStruct)(2 << (int)FpStruct.PosSizeShift2nd); + if (info.flags == twoFloats) { // struct with two single-float fields. _argLocDescForStructInRegs = new ArgLocDesc(); @@ -1545,15 +1547,11 @@ public int GetNextOffset() Debug.Assert(argSize == 8); _hasArgLocDescForStructInRegs = true; - _argLocDescForStructInRegs.m_floatFlags = (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_ONLY_TWO; + _argLocDescForStructInRegs.m_structFields = info; } _riscv64IdxFPReg += cFPRegs; return argOfsInner; } - else - { - _riscv64IdxFPReg = 8; - } } { diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/TransitionBlock.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/TransitionBlock.cs index 7f2b1fd25ee4f..e2d02cf8dfaa9 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/TransitionBlock.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/TransitionBlock.cs @@ -391,7 +391,7 @@ public void ComputeReturnValueTreatment(CorElementType type, TypeHandle thRetTyp if (IsLoongArch64) fpReturnSize = LoongArch64PassStructInRegister.GetLoongArch64PassStructInRegisterFlags(thRetType.GetRuntimeTypeHandle()) & 0xff; else if (IsRiscV64) - fpReturnSize = RISCV64PassStructInRegister.GetRISCV64PassStructInRegisterFlags(thRetType.GetRuntimeTypeHandle()) & 0xff; + fpReturnSize = (uint)RISCV64PassStructInRegister.GetRiscV64PassFpStructInRegistersInfo(thRetType.GetRuntimeTypeHandle()).flags & 0xff; break; } diff --git a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h index 75722274d9e9b..c61ec8e0c0cfb 100644 --- a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h +++ b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h @@ -137,7 +137,7 @@ struct JitInterfaceCallbacks bool (* getSystemVAmd64PassStructInRegisterDescriptor)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE structHnd, SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structPassInRegDescPtr); void (* getSwiftLowering)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE structHnd, CORINFO_SWIFT_LOWERING* pLowering); uint32_t (* getLoongArch64PassStructInRegisterFlags)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE structHnd); - uint32_t (* getRISCV64PassStructInRegisterFlags)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE structHnd); + FpStructInRegistersInfo (* getRiscV64PassFpStructInRegistersInfo)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE structHnd); uint32_t (* getThreadTLSIndex)(void * thisHandle, CorInfoExceptionClass** ppException, void** ppIndirection); int32_t* (* getAddrOfCaptureThreadGlobal)(void * thisHandle, CorInfoExceptionClass** ppException, void** ppIndirection); void* (* getHelperFtn)(void * thisHandle, CorInfoExceptionClass** ppException, CorInfoHelpFunc ftnNum, void** ppIndirection); @@ -1416,11 +1416,11 @@ class JitInterfaceWrapper : public ICorJitInfo return temp; } - virtual uint32_t getRISCV64PassStructInRegisterFlags( + virtual FpStructInRegistersInfo getRiscV64PassFpStructInRegistersInfo( CORINFO_CLASS_HANDLE structHnd) { CorInfoExceptionClass* pException = nullptr; - uint32_t temp = _callbacks->getRISCV64PassStructInRegisterFlags(_thisHandle, &pException, structHnd); + FpStructInRegistersInfo temp = _callbacks->getRiscV64PassFpStructInRegistersInfo(_thisHandle, &pException, structHnd); if (pException != nullptr) throw pException; return temp; } diff --git a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h index fd85fdd97e892..b180f48ffcb0a 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h @@ -128,7 +128,7 @@ LWM(GetStringConfigValue, DWORD, DWORD) LWM(GetSystemVAmd64PassStructInRegisterDescriptor, DWORDLONG, Agnostic_GetSystemVAmd64PassStructInRegisterDescriptor) LWM(GetSwiftLowering, DWORDLONG, Agnostic_GetSwiftLowering) LWM(GetLoongArch64PassStructInRegisterFlags, DWORDLONG, DWORD) -LWM(GetRISCV64PassStructInRegisterFlags, DWORDLONG, DWORD) +LWM(GetRiscV64PassFpStructInRegistersInfo, DWORDLONG, FpStructInRegistersInfo) LWM(GetTailCallHelpers, Agnostic_GetTailCallHelpers, Agnostic_CORINFO_TAILCALL_HELPERS) LWM(UpdateEntryPointForTailCall, Agnostic_CORINFO_CONST_LOOKUP, Agnostic_CORINFO_CONST_LOOKUP) LWM(GetThreadTLSIndex, DWORD, DLD) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp index 0e0fa438e727a..d0e8ac4d35d52 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp @@ -6360,28 +6360,31 @@ DWORD MethodContext::repGetLoongArch64PassStructInRegisterFlags(CORINFO_CLASS_HA return value; } -void MethodContext::recGetRISCV64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE structHnd, DWORD value) +void MethodContext::recGetRiscV64PassFpStructInRegistersInfo(CORINFO_CLASS_HANDLE structHnd, FpStructInRegistersInfo value) { - if (GetRISCV64PassStructInRegisterFlags == nullptr) - GetRISCV64PassStructInRegisterFlags = new LightWeightMap(); + if (GetRiscV64PassFpStructInRegistersInfo == nullptr) + GetRiscV64PassFpStructInRegistersInfo = new LightWeightMap(); DWORDLONG key = CastHandle(structHnd); - GetRISCV64PassStructInRegisterFlags->Add(key, value); - DEBUG_REC(dmpGetRISCV64PassStructInRegisterFlags(key, value)); + GetRiscV64PassFpStructInRegistersInfo->Add(key, value); + DEBUG_REC(dmpGetRiscV64PassFpStructInRegistersInfo(key, value)); } -void MethodContext::dmpGetRISCV64PassStructInRegisterFlags(DWORDLONG key, DWORD value) +void MethodContext::dmpGetRiscV64PassFpStructInRegistersInfo(DWORDLONG key, FpStructInRegistersInfo value) { - printf("GetRISCV64PassStructInRegisterFlags key %016" PRIX64 " value-%08X", key, value); + printf("GetRiscV64PassFpStructInRegistersInfo key %016" PRIX64 " value-%#03x-" + "{%s, sizes={%u, %u}, offsets={%u, %u}, IntFieldKind=%s}\n", + key, value.flags, + value.FlagName(), value.Size1st(), value.Size2nd(), value.offset1st, value.offset2nd, value.IntFieldKindName()); } -DWORD MethodContext::repGetRISCV64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE structHnd) +FpStructInRegistersInfo MethodContext::repGetRiscV64PassFpStructInRegistersInfo(CORINFO_CLASS_HANDLE structHnd) { DWORDLONG key = CastHandle(structHnd); - DWORD value = LookupByKeyOrMissNoMessage(GetRISCV64PassStructInRegisterFlags, key); - DEBUG_REP(dmpGetRISCV64PassStructInRegisterFlags(key, value)); + FpStructInRegistersInfo value = LookupByKeyOrMissNoMessage(GetRiscV64PassFpStructInRegistersInfo, key); + DEBUG_REP(dmpGetRiscV64PassFpStructInRegistersInfo(key, value)); return value; } diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h index c970dd9a7b226..25f64095adeb4 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h @@ -787,6 +787,10 @@ class MethodContext void dmpGetRISCV64PassStructInRegisterFlags(DWORDLONG key, DWORD value); DWORD repGetRISCV64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE structHnd); + void recGetRiscV64PassFpStructInRegistersInfo(CORINFO_CLASS_HANDLE structHnd, FpStructInRegistersInfo value); + void dmpGetRiscV64PassFpStructInRegistersInfo(DWORDLONG key, FpStructInRegistersInfo value); + FpStructInRegistersInfo repGetRiscV64PassFpStructInRegistersInfo(CORINFO_CLASS_HANDLE structHnd); + void recGetRelocTypeHint(void* target, WORD result); void dmpGetRelocTypeHint(DWORDLONG key, DWORD value); WORD repGetRelocTypeHint(void* target); @@ -1170,7 +1174,7 @@ enum mcPackets Packet_GetThreadLocalFieldInfo = 207, Packet_GetThreadLocalStaticBlocksInfo = 208, Packet_GetThreadLocalStaticInfo_NativeAOT = 209, - Packet_GetRISCV64PassStructInRegisterFlags = 210, + // Packet_GetRISCV64PassStructInRegisterFlags = 210, Packet_GetObjectContent = 211, Packet_GetTypeLayout = 212, Packet_HaveSameMethodDefinition = 213, @@ -1181,6 +1185,7 @@ enum mcPackets Packet_GetClassStaticDynamicInfo = 218, Packet_GetClassThreadStaticDynamicInfo = 219, Packet_IsGenericType = 220, + Packet_GetRiscV64PassFpStructInRegistersInfo = 221, }; void SetDebugDumpVariables(); diff --git a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp index 84ad616c28eb9..9cc74d8946a94 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp @@ -1418,11 +1418,11 @@ uint32_t interceptor_ICJI::getLoongArch64PassStructInRegisterFlags(CORINFO_CLASS return temp; } -uint32_t interceptor_ICJI::getRISCV64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE structHnd) +FpStructInRegistersInfo interceptor_ICJI::getRiscV64PassFpStructInRegistersInfo(CORINFO_CLASS_HANDLE structHnd) { - mc->cr->AddCall("getRISCV64PassStructInRegisterFlags"); - uint32_t temp = original_ICorJitInfo->getRISCV64PassStructInRegisterFlags(structHnd); - mc->recGetRISCV64PassStructInRegisterFlags(structHnd, temp); + mc->cr->AddCall("getRiscV64PassFpStructInRegistersInfo"); + FpStructInRegistersInfo temp = original_ICorJitInfo->getRiscV64PassFpStructInRegistersInfo(structHnd); + mc->recGetRiscV64PassFpStructInRegistersInfo(structHnd, temp); return temp; } diff --git a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp index 2d6faf2c65728..400b8a4cdbc8d 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp @@ -1015,11 +1015,11 @@ uint32_t interceptor_ICJI::getLoongArch64PassStructInRegisterFlags( return original_ICorJitInfo->getLoongArch64PassStructInRegisterFlags(structHnd); } -uint32_t interceptor_ICJI::getRISCV64PassStructInRegisterFlags( +FpStructInRegistersInfo interceptor_ICJI::getRiscV64PassFpStructInRegistersInfo( CORINFO_CLASS_HANDLE structHnd) { - mcs->AddCall("getRISCV64PassStructInRegisterFlags"); - return original_ICorJitInfo->getRISCV64PassStructInRegisterFlags(structHnd); + mcs->AddCall("getRiscV64PassFpStructInRegistersInfo"); + return original_ICorJitInfo->getRiscV64PassFpStructInRegistersInfo(structHnd); } uint32_t interceptor_ICJI::getThreadTLSIndex( diff --git a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp index 210485e727c9b..b9678e5170e09 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp @@ -889,10 +889,10 @@ uint32_t interceptor_ICJI::getLoongArch64PassStructInRegisterFlags( return original_ICorJitInfo->getLoongArch64PassStructInRegisterFlags(structHnd); } -uint32_t interceptor_ICJI::getRISCV64PassStructInRegisterFlags( +FpStructInRegistersInfo interceptor_ICJI::getRiscV64PassFpStructInRegistersInfo( CORINFO_CLASS_HANDLE structHnd) { - return original_ICorJitInfo->getRISCV64PassStructInRegisterFlags(structHnd); + return original_ICorJitInfo->getRiscV64PassFpStructInRegistersInfo(structHnd); } uint32_t interceptor_ICJI::getThreadTLSIndex( diff --git a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp index 9e29f43e03ec3..ecd7630d293c4 100644 --- a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp @@ -1257,10 +1257,10 @@ uint32_t MyICJI::getLoongArch64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE st return jitInstance->mc->repGetLoongArch64PassStructInRegisterFlags(structHnd); } -uint32_t MyICJI::getRISCV64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE structHnd) +FpStructInRegistersInfo MyICJI::getRiscV64PassFpStructInRegistersInfo(CORINFO_CLASS_HANDLE structHnd) { - jitInstance->mc->cr->AddCall("getRISCV64PassStructInRegisterFlags"); - return jitInstance->mc->repGetRISCV64PassStructInRegisterFlags(structHnd); + jitInstance->mc->cr->AddCall("getRiscV64PassFpStructInRegistersInfo"); + return jitInstance->mc->repGetRiscV64PassFpStructInRegistersInfo(structHnd); } // Stuff on ICorDynamicInfo diff --git a/src/coreclr/vm/argdestination.h b/src/coreclr/vm/argdestination.h index 57df032664816..1160b26556890 100644 --- a/src/coreclr/vm/argdestination.h +++ b/src/coreclr/vm/argdestination.h @@ -110,20 +110,23 @@ class ArgDestination int argOfs = TransitionBlock::GetOffsetOfFloatArgumentRegisters() + m_argLocDescForStructInRegs->m_idxFloatReg * 8; - if (m_argLocDescForStructInRegs->m_structFields == STRUCT_FLOAT_FIELD_ONLY_TWO) + static const FpStruct::Flags twoFloats = FpStruct::Flags(FpStruct::BothFloat + | (2 << FpStruct::PosSizeShift1st) + | (2 << FpStruct::PosSizeShift2nd)); + if (m_argLocDescForStructInRegs->m_structFields.flags == twoFloats) { // struct with two floats. _ASSERTE(m_argLocDescForStructInRegs->m_cFloatReg == 2); _ASSERTE(m_argLocDescForStructInRegs->m_cGenReg == 0); *(INT64*)((char*)m_base + argOfs) = NanBox | *(INT32*)src; *(INT64*)((char*)m_base + argOfs + 8) = NanBox | *((INT32*)src + 1); } - else if ((m_argLocDescForStructInRegs->m_structFields & STRUCT_FLOAT_FIELD_FIRST) != 0) + else if ((m_argLocDescForStructInRegs->m_structFields.flags & FpStruct::FloatInt) != 0) { // the first field is float or double. _ASSERTE(m_argLocDescForStructInRegs->m_cFloatReg == 1); _ASSERTE(m_argLocDescForStructInRegs->m_cGenReg == 1); - _ASSERTE((m_argLocDescForStructInRegs->m_structFields & STRUCT_FLOAT_FIELD_SECOND) == 0);//the second field is integer. + _ASSERTE((m_argLocDescForStructInRegs->m_structFields.flags & FpStruct::IntFloat) == 0);//the second field is integer. - if ((m_argLocDescForStructInRegs->m_structFields & STRUCT_FIRST_FIELD_SIZE_IS8) == 0) + if (m_argLocDescForStructInRegs->m_structFields.SizeShift1st() == 3) { *(INT64*)((char*)m_base + argOfs) = NanBox | *(INT32*)src; // the first field is float } @@ -133,7 +136,8 @@ class ArgDestination } argOfs = TransitionBlock::GetOffsetOfArgumentRegisters() + m_argLocDescForStructInRegs->m_idxGenReg * 8; - if ((m_argLocDescForStructInRegs->m_structFields & STRUCT_HAS_8BYTES_FIELDS_MASK) != 0) + if (m_argLocDescForStructInRegs->m_structFields.SizeShift1st() == 3 || + m_argLocDescForStructInRegs->m_structFields.SizeShift2nd() == 3) { *(UINT64*)((char*)m_base + argOfs) = *((UINT64*)src + 1); } @@ -142,15 +146,16 @@ class ArgDestination *(INT64*)((char*)m_base + argOfs) = *((INT32*)src + 1); // the second field is int32. } } - else if ((m_argLocDescForStructInRegs->m_structFields & STRUCT_FLOAT_FIELD_SECOND) != 0) + else if ((m_argLocDescForStructInRegs->m_structFields.flags & FpStruct::IntFloat) != 0) { // the second field is float or double. _ASSERTE(m_argLocDescForStructInRegs->m_cFloatReg == 1); _ASSERTE(m_argLocDescForStructInRegs->m_cGenReg == 1); - _ASSERTE((m_argLocDescForStructInRegs->m_structFields & STRUCT_FLOAT_FIELD_FIRST) == 0);//the first field is integer. + _ASSERTE((m_argLocDescForStructInRegs->m_structFields.flags & FpStruct::FloatInt) == 0);//the first field is integer. // destOffset - nonzero when copying values into Nullable, it is the offset of the T value inside of the Nullable. // here the first field maybe Nullable. - if ((m_argLocDescForStructInRegs->m_structFields & STRUCT_HAS_8BYTES_FIELDS_MASK) == 0) + if (m_argLocDescForStructInRegs->m_structFields.SizeShift1st() < 3 && + m_argLocDescForStructInRegs->m_structFields.SizeShift2nd() < 3) { // the second field is float. *(INT64*)((char*)m_base + argOfs) = NanBox | (destOffset == 0 ? *((INT32*)src + 1) : *(INT32*)src); diff --git a/src/coreclr/vm/callhelpers.cpp b/src/coreclr/vm/callhelpers.cpp index 3125c21ea3d13..e869af831fc82 100644 --- a/src/coreclr/vm/callhelpers.cpp +++ b/src/coreclr/vm/callhelpers.cpp @@ -534,7 +534,13 @@ void MethodDescCallSite::CallTargetWorker(const ARG_SLOT *pArguments, ARG_SLOT * #ifdef CALLDESCR_REGTYPEMAP callDescrData.dwRegTypeMap = dwRegTypeMap; #endif +#if defined(TARGET_RISCV64) || defined(TARGET_LOONGARCH) + // Temporary conversion to old flags, CallDescrWorker needs to be overhauled anyway + // to work with arbitrary field offsets and sizes, and support struct size > 16 on RISC-V. + callDescrData.fpReturnSize = FpStructInRegistersInfo{FpStruct::Flags(fpReturnSize)}.ToOldFlags(); +#else callDescrData.fpReturnSize = fpReturnSize; +#endif callDescrData.pTarget = m_pCallTarget; #ifdef FEATURE_INTERPRETER diff --git a/src/coreclr/vm/callingconvention.h b/src/coreclr/vm/callingconvention.h index 59a3e0eb6c869..920854b0011a1 100644 --- a/src/coreclr/vm/callingconvention.h +++ b/src/coreclr/vm/callingconvention.h @@ -42,7 +42,7 @@ struct ArgLocDesc int m_byteStackIndex; // Stack offset in bytes (or -1) int m_byteStackSize; // Stack size in bytes #if defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) - int m_structFields; // Struct field info when using Float-register except two-doubles case. + FpStructInRegistersInfo m_structFields; // Struct field info when using floating-point register(s) #endif #if defined(UNIX_AMD64_ABI) @@ -97,7 +97,7 @@ struct ArgLocDesc m_hfaFieldSize = 0; #endif // defined(TARGET_ARM64) #if defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) - m_structFields = STRUCT_NO_FLOAT_FIELD; + m_structFields = {}; #endif #if defined(UNIX_AMD64_ABI) m_eeClass = NULL; @@ -909,6 +909,11 @@ class ArgIteratorTemplate : public ARGITERATOR_BASE protected: DWORD m_dwFlags; // Cached flags int m_nSizeOfArgStack; // Cached value of SizeOfArgStack +#if defined(TARGET_RISCV64) + // Offsets of fields returned according to hardware floating-point calling convention + // (FpStruct::Flags are embedded in m_dwFlags) + unsigned m_returnedFpFieldOffsets[2]; +#endif DWORD m_argNum; @@ -1790,20 +1795,15 @@ int ArgIteratorTemplate::GetNextOffset() return argOfs; #elif defined(TARGET_RISCV64) - + assert(!this->IsVarArg()); // Varargs on RISC-V not supported yet int cFPRegs = 0; - int flags = 0; + FpStructInRegistersInfo info = {}; switch (argType) { - case ELEMENT_TYPE_R4: - // 32-bit floating point argument. - cFPRegs = 1; - break; - case ELEMENT_TYPE_R8: - // 64-bit floating point argument. + // Floating point argument cFPRegs = 1; break; @@ -1819,10 +1819,10 @@ int ArgIteratorTemplate::GetNextOffset() } else { - flags = MethodTable::GetRiscV64PassStructInRegisterFlags(thValueType); - if (flags & STRUCT_HAS_FLOAT_FIELDS_MASK) + info = MethodTable::GetRiscV64PassFpStructInRegistersInfo(thValueType); + if (info.flags != FpStruct::UseIntCallConv) { - cFPRegs = (flags & STRUCT_FLOAT_FIELD_ONLY_TWO) ? 2 : 1; + cFPRegs = (info.flags & FpStruct::BothFloat) ? 2 : 1; } } @@ -1839,22 +1839,22 @@ int ArgIteratorTemplate::GetNextOffset() if (cFPRegs > 0 && !this->IsVarArg()) { - if (flags & (STRUCT_FLOAT_FIELD_FIRST | STRUCT_FLOAT_FIELD_SECOND)) + if (info.flags & (FpStruct::FloatInt | FpStruct::IntFloat)) { assert(cFPRegs == 1); - assert((STRUCT_FLOAT_FIELD_FIRST == (flags & STRUCT_HAS_FLOAT_FIELDS_MASK)) || (STRUCT_FLOAT_FIELD_SECOND == (flags & STRUCT_HAS_FLOAT_FIELDS_MASK))); + assert((info.flags & (FpStruct::OnlyOne | FpStruct::BothFloat)) == 0); - if ((1 + m_idxFPReg <= NUM_ARGUMENT_REGISTERS) && (m_idxGenReg + 1 <= NUM_ARGUMENT_REGISTERS)) + if ((1 + m_idxFPReg <= NUM_ARGUMENT_REGISTERS) && (1 + m_idxGenReg <= NUM_ARGUMENT_REGISTERS)) { m_argLocDescForStructInRegs.Init(); m_argLocDescForStructInRegs.m_idxFloatReg = m_idxFPReg; m_argLocDescForStructInRegs.m_cFloatReg = 1; - int argOfs = (flags & STRUCT_FLOAT_FIELD_SECOND) + int argOfs = (info.flags & FpStruct::IntFloat) ? TransitionBlock::GetOffsetOfArgumentRegisters() + m_idxGenReg * 8 : TransitionBlock::GetOffsetOfFloatArgumentRegisters() + m_idxFPReg * 8; m_idxFPReg += 1; - m_argLocDescForStructInRegs.m_structFields = flags; + m_argLocDescForStructInRegs.m_structFields = info; m_argLocDescForStructInRegs.m_idxGenReg = m_idxGenReg; m_argLocDescForStructInRegs.m_cGenReg = 1; @@ -1868,7 +1868,10 @@ int ArgIteratorTemplate::GetNextOffset() else if (cFPRegs + m_idxFPReg <= NUM_ARGUMENT_REGISTERS) { int argOfs = TransitionBlock::GetOffsetOfFloatArgumentRegisters() + m_idxFPReg * 8; - if (flags == STRUCT_FLOAT_FIELD_ONLY_TWO) // struct with two float-fields. + static const FpStruct::Flags twoFloats = FpStruct::Flags(FpStruct::BothFloat + | (2 << FpStruct::PosSizeShift1st) + | (2 << FpStruct::PosSizeShift2nd)); + if (info.flags == twoFloats) // struct with two float-fields. { m_argLocDescForStructInRegs.Init(); m_hasArgLocDescForStructInRegs = true; @@ -1876,7 +1879,7 @@ int ArgIteratorTemplate::GetNextOffset() assert(cFPRegs == 2); m_argLocDescForStructInRegs.m_cFloatReg = 2; assert(argSize == 8); - m_argLocDescForStructInRegs.m_structFields = STRUCT_FLOAT_FIELD_ONLY_TWO; + m_argLocDescForStructInRegs.m_structFields = info; } m_idxFPReg += cFPRegs; return argOfs; @@ -2031,7 +2034,7 @@ void ArgIteratorTemplate::ComputeReturnFlags() if (size <= ENREGISTERED_RETURNTYPE_INTEGER_MAXSIZE) { assert(!thValueType.IsTypeDesc()); - flags = (MethodTable::GetRiscV64PassStructInRegisterFlags(thValueType) & 0xff) << RETURN_FP_SIZE_SHIFT; + flags = (MethodTable::GetRiscV64PassFpStructInRegistersInfo(thValueType).flags & 0xff) << RETURN_FP_SIZE_SHIFT; break; } #else diff --git a/src/coreclr/vm/comdelegate.cpp b/src/coreclr/vm/comdelegate.cpp index 51d29277a383c..ed5ddb8b544c4 100644 --- a/src/coreclr/vm/comdelegate.cpp +++ b/src/coreclr/vm/comdelegate.cpp @@ -172,7 +172,7 @@ class ShuffleIterator if (m_currentFloatRegIndex < m_argLocDesc->m_cFloatReg) { #if defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) - if ((m_argLocDesc->m_structFields & STRUCT_FLOAT_FIELD_SECOND) && (m_currentGenRegIndex < m_argLocDesc->m_cGenReg)) + if ((m_argLocDesc->m_structFields.flags & FpStruct::IntFloat) && (m_currentGenRegIndex < m_argLocDesc->m_cGenReg)) { // the first field is integer so just skip this. } diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 54ce75255eeaf..388241b404a7c 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -9486,7 +9486,7 @@ uint32_t CEEInfo::getLoongArch64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE c return size; } -uint32_t CEEInfo::getRISCV64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE cls) +FpStructInRegistersInfo CEEInfo::getRiscV64PassFpStructInRegistersInfo(CORINFO_CLASS_HANDLE cls) { CONTRACTL { NOTHROW; @@ -9496,15 +9496,15 @@ uint32_t CEEInfo::getRISCV64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE cls) JIT_TO_EE_TRANSITION_LEAF(); - uint32_t size = STRUCT_NO_FLOAT_FIELD; + FpStructInRegistersInfo info = {}; #if defined(TARGET_RISCV64) - size = (uint32_t)MethodTable::GetRiscV64PassStructInRegisterFlags(TypeHandle(cls)); + info = MethodTable::GetRiscV64PassFpStructInRegistersInfo(TypeHandle(cls)); #endif // TARGET_RISCV64 EE_TO_JIT_TRANSITION_LEAF(); - return size; + return info; } /*********************************************************************/ diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index a3e9641bc73e1..31083c32713ae 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -2716,7 +2716,7 @@ void MethodTable::AssignClassifiedEightByteTypes(SystemVStructRegisterPassingHe #endif // defined(UNIX_AMD64_ABI_ITF) #if defined(TARGET_RISCV64) || defined(TARGET_LOONGARCH64) -static bool HandleInlineArray(int elementTypeIndex, int nElements, StructFloatFieldInfoFlags types[2], int& typeIndex) +static bool HandleInlineArrayOld(int elementTypeIndex, int nElements, StructFloatFieldInfoFlags types[2], int& typeIndex) { int nFlattenedFieldsPerElement = typeIndex - elementTypeIndex; if (nFlattenedFieldsPerElement == 0) @@ -2739,7 +2739,7 @@ static bool HandleInlineArray(int elementTypeIndex, int nElements, StructFloatFi return true; } -static bool FlattenFieldTypes(TypeHandle th, StructFloatFieldInfoFlags types[2], int& typeIndex) +static bool FlattenFieldTypesOld(TypeHandle th, StructFloatFieldInfoFlags types[2], int& typeIndex) { bool isManaged = !th.IsTypeDesc(); MethodTable* pMT = isManaged ? th.AsMethodTable() : th.AsNativeValueType(); @@ -2760,7 +2760,7 @@ static bool FlattenFieldTypes(TypeHandle th, StructFloatFieldInfoFlags types[2], if (type == ELEMENT_TYPE_VALUETYPE) { MethodTable* nested = fields[i].GetApproxFieldTypeHandleThrowing().GetMethodTable(); - if (!FlattenFieldTypes(TypeHandle(nested), types, typeIndex)) + if (!FlattenFieldTypesOld(TypeHandle(nested), types, typeIndex)) return false; } else if (fields[i].GetSize() <= TARGET_POINTER_SIZE) @@ -2783,7 +2783,7 @@ static bool FlattenFieldTypes(TypeHandle th, StructFloatFieldInfoFlags types[2], { assert(nFields == 1); int nElements = pMT->GetNumInstanceFieldBytes() / fields[0].GetSize(); - if (!HandleInlineArray(elementTypeIndex, nElements, types, typeIndex)) + if (!HandleInlineArrayOld(elementTypeIndex, nElements, types, typeIndex)) return false; } } @@ -2801,12 +2801,12 @@ static bool FlattenFieldTypes(TypeHandle th, StructFloatFieldInfoFlags types[2], int elementTypeIndex = typeIndex; MethodTable* nested = fields[i].GetNestedNativeMethodTable(); - if (!FlattenFieldTypes(TypeHandle(nested), types, typeIndex)) + if (!FlattenFieldTypesOld(TypeHandle(nested), types, typeIndex)) return false; // In native layout fixed arrays are marked as NESTED just like structs int nElements = fields[i].GetNumElements(); - if (!HandleInlineArray(elementTypeIndex, nElements, types, typeIndex)) + if (!HandleInlineArrayOld(elementTypeIndex, nElements, types, typeIndex)) return false; } else if (fields[i].NativeSize() <= TARGET_POINTER_SIZE) @@ -2837,7 +2837,7 @@ int MethodTable::GetLoongArch64PassStructInRegisterFlags(TypeHandle th) StructFloatFieldInfoFlags types[2] = {STRUCT_NO_FLOAT_FIELD, STRUCT_NO_FLOAT_FIELD}; int nFields = 0; - if (!FlattenFieldTypes(th, types, nFields) || nFields == 0) + if (!FlattenFieldTypesOld(th, types, nFields) || nFields == 0) return STRUCT_NO_FLOAT_FIELD; assert(nFields == 1 || nFields == 2); @@ -2867,14 +2867,14 @@ int MethodTable::GetLoongArch64PassStructInRegisterFlags(TypeHandle th) #endif #if defined(TARGET_RISCV64) -int MethodTable::GetRiscV64PassStructInRegisterFlags(TypeHandle th) +static int GetRiscV64PassStructInRegisterFlags(TypeHandle th) { if (th.GetSize() > ENREGISTERED_PARAMTYPE_MAXSIZE) return STRUCT_NO_FLOAT_FIELD; StructFloatFieldInfoFlags types[2] = {STRUCT_NO_FLOAT_FIELD, STRUCT_NO_FLOAT_FIELD}; int nFields = 0; - if (!FlattenFieldTypes(th, types, nFields) || nFields == 0) + if (!FlattenFieldTypesOld(th, types, nFields) || nFields == 0) return STRUCT_NO_FLOAT_FIELD; assert(nFields == 1 || nFields == 2); @@ -2903,6 +2903,300 @@ int MethodTable::GetRiscV64PassStructInRegisterFlags(TypeHandle th) } #endif +#if defined(TARGET_RISCV64) || defined(TARGET_LOONGARCH64) +static void SetFpStructInRegistersInfoField(FpStructInRegistersInfo& info, int index, + bool isFloating, FpStruct::IntKind intKind, unsigned size, uint32_t offset) +{ + assert(index < 2); + if (isFloating) + { + assert(size == sizeof(float) || size == sizeof(double)); + assert(intKind == FpStruct::IntKind::Signed); + static_assert((int)FpStruct::IntKind::Signed == 0, + "IntKind for floating fields should not clobber IntKind for int fields"); + } + + assert(size >= 1 && size <= 8); + assert((size & (size - 1)) == 0); // size needs to be a power of 2 + static const int sizeShiftLUT = (0 << (1*2)) | (1 << (2*2)) | (2 << (4*2)) | (3 << (8*2)); + int sizeShift = (sizeShiftLUT >> (size * 2)) & 0b11; + + using namespace FpStruct; + // Use FloatInt and IntFloat as marker flags for 1st and 2nd field respectively being floating. + // Fix to real flags (with OnlyOne and BothFloat) after flattening is complete. + static_assert(PosIntFloat == PosFloatInt + 1, "FloatInt and IntFloat need to be adjacent"); + static_assert(PosSizeShift2nd == PosSizeShift1st + 2, "SizeShift1st and 2nd need to be adjacent"); + int floatFlag = isFloating << (PosFloatInt + index); + int sizeShiftMask = sizeShift << (PosSizeShift1st + 2 * index); + + info.flags = FpStruct::Flags(info.flags | floatFlag | sizeShiftMask | ((int)intKind << PosIntFieldKind)); + (index == 0 ? info.offset1st : info.offset2nd) = offset; +} + +static bool HandleInlineArray(int elementTypeIndex, int nElements, FpStructInRegistersInfo& info, int& typeIndex + DEBUG_ARG(int nestingLevel)) +{ + int nFlattenedFieldsPerElement = typeIndex - elementTypeIndex; + if (nFlattenedFieldsPerElement == 0) + { + assert(nElements == 1); // HasImpliedRepeatedFields must have returned a false positive + LOG((LF_JIT, LL_EVERYTHING, "FpStructInRegistersInfo:%*s * ignoring empty struct\n", + nestingLevel * 4, "")); + return true; + } + + assert(nFlattenedFieldsPerElement == 1 || nFlattenedFieldsPerElement == 2); + + if (nElements > 2) + { + LOG((LF_JIT, LL_EVERYTHING, "FpStructInRegistersInfo:%*s * array has too many elements: %i\n", + nestingLevel * 4, "", nElements)); + return false; + } + + if (nElements == 2) + { + if (typeIndex + nFlattenedFieldsPerElement > 2) + { + LOG((LF_JIT, LL_EVERYTHING, "FpStructInRegistersInfo:%*s * array has too many fields per element: %i, fields already found: %i\n", + nestingLevel * 4, "", nFlattenedFieldsPerElement, typeIndex)); + return false; + } + + assert(elementTypeIndex == 0); + assert(typeIndex == 1); + + // duplicate the array element info + static const int typeSize = FpStruct::PosIntFloat - FpStruct::PosFloatInt; + info.flags = FpStruct::Flags(info.flags | (info.flags << typeSize)); + info.offset2nd = info.offset1st + info.Size1st(); + LOG((LF_JIT, LL_EVERYTHING, "FpStructInRegistersInfo:%*s * duplicated array element type\n", + nestingLevel * 4, "")); + } + return true; +} + +static bool FlattenFields(TypeHandle th, uint32_t offset, FpStructInRegistersInfo& info, int& typeIndex + DEBUG_ARG(int nestingLevel)) +{ + bool isManaged = !th.IsTypeDesc(); + MethodTable* pMT = isManaged ? th.AsMethodTable() : th.AsNativeValueType(); + int nFields = isManaged ? pMT->GetNumIntroducedInstanceFields() : pMT->GetNativeLayoutInfo()->GetNumFields(); + + LOG((LF_JIT, LL_EVERYTHING, "FpStructInRegistersInfo:%*s flattening %s (%s, %i fields)\n", + nestingLevel * 4, "", pMT->GetDebugClassName(), (isManaged ? "managed" : "native"), nFields)); + + // TODO: templatize isManaged and use if constexpr for differences when we migrate to C++17 + // because the logic for both branches is nearly the same. + if (isManaged) + { + FieldDesc* fields = pMT->GetApproxFieldDescListRaw(); + int elementTypeIndex = typeIndex; + for (int i = 0; i < nFields; ++i) + { + if (i > 0 && fields[i-1].GetOffset() + fields[i-1].GetSize() > fields[i].GetOffset()) + { + LOG((LF_JIT, LL_EVERYTHING, "FpStructInRegistersInfo:%*s " + " * fields %s [%i..%i) and %s [%i..%i) overlap, treat as union\n", + nestingLevel * 4, "", + fields[i-1].GetDebugName(), fields[i-1].GetOffset(), fields[i-1].GetOffset() + fields[i-1].GetSize(), + fields[i].GetDebugName(), fields[i].GetOffset(), fields[i].GetOffset() + fields[i].GetSize())); + return false; + } + + CorElementType type = fields[i].GetFieldType(); + if (type == ELEMENT_TYPE_VALUETYPE) + { + MethodTable* nested = fields[i].GetApproxFieldTypeHandleThrowing().GetMethodTable(); + if (!FlattenFields(TypeHandle(nested), offset + fields[i].GetOffset(), info, typeIndex DEBUG_ARG(nestingLevel + 1))) + return false; + } + else if (fields[i].GetSize() <= TARGET_POINTER_SIZE) + { + if (typeIndex >= 2) + { + LOG((LF_JIT, LL_EVERYTHING, "FpStructInRegistersInfo:%*s * too many fields\n", + nestingLevel * 4, "")); + return false; + } + + bool isFloating = CorTypeInfo::IsFloat_NoThrow(type); + bool isSignedInt = ( + type == ELEMENT_TYPE_I1 || + type == ELEMENT_TYPE_I2 || + type == ELEMENT_TYPE_I4 || + type == ELEMENT_TYPE_I8 || + type == ELEMENT_TYPE_I); + CorInfoGCType gcType = CorTypeInfo::GetGCType_NoThrow(type); + + FpStruct::IntKind intKind = + (gcType == TYPE_GC_REF) ? FpStruct::IntKind::GcRef : + (gcType == TYPE_GC_BYREF) ? FpStruct::IntKind::GcByRef : + (isSignedInt || isFloating) ? FpStruct::IntKind::Signed : FpStruct::IntKind::Unsigned; + + SetFpStructInRegistersInfoField(info, typeIndex++, + isFloating, intKind, CorTypeInfo::Size_NoThrow(type), offset + fields[i].GetOffset()); + + LOG((LF_JIT, LL_EVERYTHING, "FpStructInRegistersInfo:%*s * found field %s [%i..%i), type: %s\n", + nestingLevel * 4, "", fields[i].GetDebugName(), + fields[i].GetOffset(), fields[i].GetOffset() + fields[i].GetSize(), CorTypeInfo::GetName(type))); + } + else + { + LOG((LF_JIT, LL_EVERYTHING, "FpStructInRegistersInfo:%*s " + " * field %s, type: %s, is too big (%i bytes)\n", + nestingLevel * 4, "", fields[i].GetDebugName(), + CorTypeInfo::GetName(type), fields[i].GetSize())); + return false; + } + } + + if (HasImpliedRepeatedFields(pMT)) // inline array or fixed buffer + { + assert(nFields == 1); + int nElements = pMT->GetNumInstanceFieldBytes() / fields[0].GetSize(); + if (!HandleInlineArray(elementTypeIndex, nElements, info, typeIndex DEBUG_ARG(nestingLevel + 1))) + return false; + } + } + else // native layout + { + const NativeFieldDescriptor* fields = pMT->GetNativeLayoutInfo()->GetNativeFieldDescriptors(); + for (int i = 0; i < nFields; ++i) + { + if (i > 0 && fields[i-1].GetExternalOffset() + fields[i-1].NativeSize() > fields[i].GetExternalOffset()) + { + LOG((LF_JIT, LL_EVERYTHING, "FpStructInRegistersInfo:%*s " + " * fields %s [%i..%i) and %s [%i..%i) overlap, treat as union\n", + nestingLevel * 4, "", + fields[i-1].GetFieldDesc()->GetDebugName(), fields[i-1].GetExternalOffset(), fields[i-1].GetExternalOffset() + fields[i-1].NativeSize(), + fields[i].GetFieldDesc()->GetDebugName(), fields[i].GetExternalOffset(), fields[i].GetExternalOffset() + fields[i].NativeSize())); + return false; + } + + static const char* categoryNames[] = {"FLOAT", "NESTED", "INTEGER", "ILLEGAL"}; + NativeFieldCategory category = fields[i].GetCategory(); + if (category == NativeFieldCategory::NESTED) + { + int elementTypeIndex = typeIndex; + + MethodTable* nested = fields[i].GetNestedNativeMethodTable(); + if (!FlattenFields(TypeHandle(nested), offset + fields[i].GetExternalOffset(), info, typeIndex DEBUG_ARG(nestingLevel + 1))) + return false; + + // In native layout fixed arrays are marked as NESTED just like structs + int nElements = fields[i].GetNumElements(); + if (!HandleInlineArray(elementTypeIndex, nElements, info, typeIndex DEBUG_ARG(nestingLevel + 1))) + return false; + } + else if (fields[i].NativeSize() <= TARGET_POINTER_SIZE) + { + if (typeIndex >= 2) + { + LOG((LF_JIT, LL_EVERYTHING, "FpStructInRegistersInfo:%*s * too many fields\n", + nestingLevel * 4, "")); + return false; + } + + SetFpStructInRegistersInfoField(info, typeIndex++, + (category == NativeFieldCategory::FLOAT), + FpStruct::IntKind::Signed, // NativeFieldDescriptor doesn't save signedness, TODO: should it? + fields[i].NativeSize(), + offset + fields[i].GetExternalOffset()); + LOG((LF_JIT, LL_EVERYTHING, "FpStructInRegistersInfo:%*s * found field %s [%i..%i), type: %s\n", + nestingLevel * 4, "", fields[i].GetFieldDesc()->GetDebugName(), + fields[i].GetExternalOffset(), fields[i].GetExternalOffset() + fields[i].NativeSize(), categoryNames[(int)category])); + } + else + { + LOG((LF_JIT, LL_EVERYTHING, "FpStructInRegistersInfo:%*s " + " * field %s, type: %s, is too big (%i bytes)\n", + nestingLevel * 4, "", fields[i].GetFieldDesc()->GetDebugName(), + categoryNames[(int)category], fields[i].NativeSize())); + return false; + } + } + } + return true; +} +#endif + +#if defined(TARGET_RISCV64) + +static FpStructInRegistersInfo GetRiscV64PassFpStructInRegistersInfoImpl(TypeHandle th) +{ + FpStructInRegistersInfo info = {}; + int nFields = 0; + if (!FlattenFields(th, 0, info, nFields DEBUG_ARG(0))) + return FpStructInRegistersInfo{}; + + using namespace FpStruct; + if ((info.flags & (FloatInt | IntFloat)) == 0) + { + LOG((LF_JIT, LL_EVERYTHING, "FpStructInRegistersInfo: struct %s (%u bytes) has no floating fields\n", + (!th.IsTypeDesc() ? th.AsMethodTable() : th.AsNativeValueType())->GetDebugClassName(), th.GetSize())); + return FpStructInRegistersInfo{}; + } + + assert(nFields == 1 || nFields == 2); + + if ((info.flags & (FloatInt | IntFloat)) == (FloatInt | IntFloat)) + { + assert(nFields == 2); + info.flags = FpStruct::Flags(info.flags ^ (FloatInt | IntFloat | BothFloat)); // replace (FloatInt | IntFloat) with BothFloat + } + else if (nFields == 1) + { + assert((info.flags & FloatInt) != 0); + assert((info.flags & (IntFloat | SizeShift2ndMask)) == 0); + assert(info.offset2nd == 0); + info.flags = FpStruct::Flags(info.flags ^ (FloatInt | OnlyOne)); // replace FloatInt with OnlyOne + } + assert(nFields == ((info.flags & OnlyOne) != 0 ? 1 : 2)); + int floatFlags = info.flags & (OnlyOne | BothFloat | FloatInt | IntFloat); + assert(floatFlags != 0); + assert((floatFlags & (floatFlags - 1)) == 0); // there can be only one of (OnlyOne | BothFloat | FloatInt | IntFloat) + if (nFields == 2) + { + unsigned end1st = info.offset1st + info.Size1st(); + unsigned end2nd = info.offset2nd + info.Size2nd(); + assert(end1st <= info.offset2nd || end2nd <= info.offset1st); // fields must not overlap + } + assert(info.offset1st + info.Size1st() <= th.GetSize()); + assert(info.offset2nd + info.Size2nd() <= th.GetSize()); + if (info.IntFieldKind() != FpStruct::IntKind::Signed) + { + assert(info.flags & (FloatInt | IntFloat)); + if (info.IntFieldKind() >= FpStruct::IntKind::GcRef) + { + assert((info.flags & IntFloat) != 0 + ? ((info.SizeShift1st() == 3) && IS_ALIGNED(info.offset1st, TARGET_POINTER_SIZE)) + : ((info.SizeShift2nd() == 3) && IS_ALIGNED(info.offset2nd, TARGET_POINTER_SIZE))); + } + } + if (info.flags & (OnlyOne | BothFloat)) + assert(info.IntFieldKind() == FpStruct::IntKind::Signed); + + LOG((LF_JIT, LL_EVERYTHING, "FpStructInRegistersInfo: " + "struct %s (%u bytes) can be passed with floating-point calling convention, flags=%#03x; " + "%s, sizes={%u, %u}, offsets={%u, %u}, IntFieldKindMask=%s\n", + (!th.IsTypeDesc() ? th.AsMethodTable() : th.AsNativeValueType())->GetDebugClassName(), th.GetSize(), info.flags, + info.FlagName(), info.Size1st(), info.Size2nd(), info.offset1st, info.offset2nd, info.IntFieldKindName() + )); + return info; +} + +FpStructInRegistersInfo MethodTable::GetRiscV64PassFpStructInRegistersInfo(TypeHandle th) +{ + FpStructInRegistersInfo info = GetRiscV64PassFpStructInRegistersInfoImpl(th); + int flags = GetRiscV64PassStructInRegisterFlags(th); + + assert(flags == info.ToOldFlags()); + + return info; +} +#endif // TARGET_RISCV64 + #if !defined(DACCESS_COMPILE) namespace { diff --git a/src/coreclr/vm/methodtable.h b/src/coreclr/vm/methodtable.h index be663a43067ff..44d2ce7c9c37a 100644 --- a/src/coreclr/vm/methodtable.h +++ b/src/coreclr/vm/methodtable.h @@ -1014,7 +1014,7 @@ class MethodTable #if defined(TARGET_LOONGARCH64) static int GetLoongArch64PassStructInRegisterFlags(TypeHandle th); #elif defined(TARGET_RISCV64) - static int GetRiscV64PassStructInRegisterFlags(TypeHandle th); + static FpStructInRegistersInfo GetRiscV64PassFpStructInRegistersInfo(TypeHandle th); #endif #if defined(UNIX_AMD64_ABI_ITF) diff --git a/src/coreclr/vm/reflectioninvocation.cpp b/src/coreclr/vm/reflectioninvocation.cpp index a98dafd62a558..803253631854c 100644 --- a/src/coreclr/vm/reflectioninvocation.cpp +++ b/src/coreclr/vm/reflectioninvocation.cpp @@ -497,7 +497,13 @@ FCIMPL4(Object*, RuntimeMethodHandle::InvokeMethod, #ifdef CALLDESCR_REGTYPEMAP callDescrData.dwRegTypeMap = 0; #endif +#if defined(TARGET_RISCV64) || defined(TARGET_LOONGARCH) + // Temporary conversion to old flags, CallDescrWorker needs to be overhauled anyway + // to work with arbitrary field offsets and sizes, and support struct size > 16 on RISC-V. + callDescrData.fpReturnSize = FpStructInRegistersInfo{FpStruct::Flags(argit.GetFPReturnSize())}.ToOldFlags(); +#else callDescrData.fpReturnSize = argit.GetFPReturnSize(); +#endif // This is duplicated logic from MethodDesc::GetCallTarget PCODE pTarget; @@ -632,7 +638,6 @@ FCIMPL4(Object*, RuntimeMethodHandle::InvokeMethod, UINT structSize = argit.GetArgSize(); - bool needsStackCopy = false; ArgDestination argDest(pTransitionBlock, ofs, argit.GetArgLocDescForStructInRegs()); #ifdef ENREGISTERED_PARAMTYPE_MAXSIZE diff --git a/src/coreclr/vm/riscv64/profiler.cpp b/src/coreclr/vm/riscv64/profiler.cpp index fc8eff4845638..785344d043768 100644 --- a/src/coreclr/vm/riscv64/profiler.cpp +++ b/src/coreclr/vm/riscv64/profiler.cpp @@ -111,13 +111,14 @@ LPVOID ProfileArgIterator::CopyStructFromRegisters(const ArgLocDesc* sir) _ASSERTE(m_handle); PROFILE_PLATFORM_SPECIFIC_DATA* pData = reinterpret_cast(m_handle); + StructFloatFieldInfoFlags flags = sir->m_structFields.ToOldFlags(); struct { bool isFloat, is8; } fields[] = { - { (bool) (sir->m_structFields & (STRUCT_FLOAT_FIELD_FIRST | STRUCT_FLOAT_FIELD_ONLY_TWO | STRUCT_FLOAT_FIELD_ONLY_ONE)), - (bool) (sir->m_structFields & STRUCT_FIRST_FIELD_SIZE_IS8) }, - { (bool) (sir->m_structFields & (STRUCT_FLOAT_FIELD_SECOND | STRUCT_FLOAT_FIELD_ONLY_TWO)), - (bool) (sir->m_structFields & STRUCT_SECOND_FIELD_SIZE_IS8) }, + { (bool) (flags & (STRUCT_FLOAT_FIELD_FIRST | STRUCT_FLOAT_FIELD_ONLY_TWO | STRUCT_FLOAT_FIELD_ONLY_ONE)), + (bool) (flags & STRUCT_FIRST_FIELD_SIZE_IS8) }, + { (bool) (flags & (STRUCT_FLOAT_FIELD_SECOND | STRUCT_FLOAT_FIELD_ONLY_TWO)), + (bool) (flags & STRUCT_SECOND_FIELD_SIZE_IS8) }, }; - int fieldCount = (sir->m_structFields & STRUCT_FLOAT_FIELD_ONLY_ONE) ? 1 : 2; + int fieldCount = (flags & STRUCT_FLOAT_FIELD_ONLY_ONE) ? 1 : 2; UINT64 bufferPosBegin = m_bufferPos; const double *fRegBegin = &pData->floatArgumentRegisters.f[sir->m_idxFloatReg], *fReg = fRegBegin; const double *fRegEnd = &pData->floatArgumentRegisters.f[0] + NUM_FLOAT_ARGUMENT_REGISTERS; @@ -185,7 +186,7 @@ LPVOID ProfileArgIterator::GetNextArgAddr() // If both fields are in registers of same kind (either float or general) and both are 8 bytes, no need to copy. // We can get away with returning a ptr to argumentRegisters since the struct would have the same layout. if ((sir->m_cFloatReg ^ sir->m_cGenReg) != 2 || - (sir->m_structFields & STRUCT_HAS_8BYTES_FIELDS_MASK) != STRUCT_HAS_8BYTES_FIELDS_MASK) + (sir->m_structFields.ToOldFlags() & STRUCT_HAS_8BYTES_FIELDS_MASK) != STRUCT_HAS_8BYTES_FIELDS_MASK) { return CopyStructFromRegisters(sir); } @@ -317,7 +318,7 @@ LPVOID ProfileArgIterator::GetReturnBufferAddr(void) sir.m_cGenReg = -1; sir.m_byteStackIndex = 0; sir.m_byteStackSize = -1; - sir.m_structFields = fpReturnSize; + sir.m_structFields = FpStructInRegistersInfo::FromOldFlags((StructFloatFieldInfoFlags)fpReturnSize); return CopyStructFromRegisters(&sir); } From 48caa9cb91d211fda164f75c8df2b37bc7dce8be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomek=20Sowi=C5=84ski?= Date: Tue, 25 Jun 2024 08:19:36 +0200 Subject: [PATCH 02/35] Replace StructFloatFieldInfoFlags with FpStruct::Flags in profiler --- src/coreclr/vm/riscv64/profiler.cpp | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/coreclr/vm/riscv64/profiler.cpp b/src/coreclr/vm/riscv64/profiler.cpp index 785344d043768..b4dd3e7152b78 100644 --- a/src/coreclr/vm/riscv64/profiler.cpp +++ b/src/coreclr/vm/riscv64/profiler.cpp @@ -111,14 +111,13 @@ LPVOID ProfileArgIterator::CopyStructFromRegisters(const ArgLocDesc* sir) _ASSERTE(m_handle); PROFILE_PLATFORM_SPECIFIC_DATA* pData = reinterpret_cast(m_handle); - StructFloatFieldInfoFlags flags = sir->m_structFields.ToOldFlags(); struct { bool isFloat, is8; } fields[] = { - { (bool) (flags & (STRUCT_FLOAT_FIELD_FIRST | STRUCT_FLOAT_FIELD_ONLY_TWO | STRUCT_FLOAT_FIELD_ONLY_ONE)), - (bool) (flags & STRUCT_FIRST_FIELD_SIZE_IS8) }, - { (bool) (flags & (STRUCT_FLOAT_FIELD_SECOND | STRUCT_FLOAT_FIELD_ONLY_TWO)), - (bool) (flags & STRUCT_SECOND_FIELD_SIZE_IS8) }, + { (bool) (sir->m_structFields.flags & (FpStruct::FloatInt | FpStruct::BothFloat | FpStruct::OnlyOne)), + (sir->m_structFields.SizeShift1st() == 3) }, + { (bool) (sir->m_structFields.flags & (FpStruct::IntFloat | FpStruct::BothFloat)), + (sir->m_structFields.SizeShift2nd() == 3) }, }; - int fieldCount = (flags & STRUCT_FLOAT_FIELD_ONLY_ONE) ? 1 : 2; + int fieldCount = (sir->m_structFields.flags & FpStruct::OnlyOne) ? 1 : 2; UINT64 bufferPosBegin = m_bufferPos; const double *fRegBegin = &pData->floatArgumentRegisters.f[sir->m_idxFloatReg], *fReg = fRegBegin; const double *fRegEnd = &pData->floatArgumentRegisters.f[0] + NUM_FLOAT_ARGUMENT_REGISTERS; @@ -186,7 +185,7 @@ LPVOID ProfileArgIterator::GetNextArgAddr() // If both fields are in registers of same kind (either float or general) and both are 8 bytes, no need to copy. // We can get away with returning a ptr to argumentRegisters since the struct would have the same layout. if ((sir->m_cFloatReg ^ sir->m_cGenReg) != 2 || - (sir->m_structFields.ToOldFlags() & STRUCT_HAS_8BYTES_FIELDS_MASK) != STRUCT_HAS_8BYTES_FIELDS_MASK) + (sir->m_structFields.SizeShift1st() < 3 || sir->m_structFields.SizeShift2nd() < 3)) { return CopyStructFromRegisters(sir); } @@ -303,11 +302,11 @@ LPVOID ProfileArgIterator::GetReturnBufferAddr(void) return (LPVOID)pData->argumentRegisters.a[0]; } - UINT fpReturnSize = m_argIterator.GetFPReturnSize(); - if (fpReturnSize) + FpStructInRegistersInfo info = {(FpStruct::Flags)m_argIterator.GetFPReturnSize()}; + if (info.flags != FpStruct::UseIntCallConv) { - if ((fpReturnSize & STRUCT_HAS_8BYTES_FIELDS_MASK) == STRUCT_HAS_8BYTES_FIELDS_MASK || - (fpReturnSize & STRUCT_FLOAT_FIELD_ONLY_ONE)) + if (((info.flags & FpStruct::BothFloat) && info.SizeShift1st() == 3 && info.SizeShift2nd() == 3) || + (info.flags & FpStruct::OnlyOne)) { return &pData->floatArgumentRegisters.f[0]; } @@ -318,7 +317,7 @@ LPVOID ProfileArgIterator::GetReturnBufferAddr(void) sir.m_cGenReg = -1; sir.m_byteStackIndex = 0; sir.m_byteStackSize = -1; - sir.m_structFields = FpStructInRegistersInfo::FromOldFlags((StructFloatFieldInfoFlags)fpReturnSize); + sir.m_structFields = info; return CopyStructFromRegisters(&sir); } From 853bd9914318a9d841ccf2add69d95eb3ebb05c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomek=20Sowi=C5=84ski?= Date: Tue, 25 Jun 2024 08:19:36 +0200 Subject: [PATCH 03/35] Remove FpStructInRegistersInfo::FromOldFlags() --- src/coreclr/inc/corinfo.h | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index 4142cd85cc480..3b641ca3a967c 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -442,27 +442,6 @@ struct FpStructInRegistersInfo ((SizeShift1st() == 3) ? STRUCT_FIRST_FIELD_SIZE_IS8 : 0) | ((SizeShift2nd() == 3) ? STRUCT_SECOND_FIELD_SIZE_IS8 : 0)); } - - static FpStructInRegistersInfo FromOldFlags(StructFloatFieldInfoFlags flags) - { - unsigned sizeShift1st = (flags & STRUCT_FIRST_FIELD_SIZE_IS8) ? 3 : 2; - unsigned sizeShift2nd = (flags & STRUCT_SECOND_FIELD_SIZE_IS8) ? 3 : 2; - bool hasTwo = !(flags & STRUCT_FLOAT_FIELD_ONLY_ONE); - return { - FpStruct::Flags( - ((flags & STRUCT_FLOAT_FIELD_ONLY_ONE) ? FpStruct::OnlyOne : 0) | - ((flags & STRUCT_FLOAT_FIELD_ONLY_TWO) ? FpStruct::BothFloat : 0) | - ((flags & STRUCT_FLOAT_FIELD_FIRST) ? FpStruct::FloatInt : 0) | - ((flags & STRUCT_FLOAT_FIELD_SECOND) ? FpStruct::IntFloat : 0) | - (sizeShift1st << FpStruct::PosSizeShift1st) | - (hasTwo ? (sizeShift2nd << FpStruct::PosSizeShift2nd) : 0) - // No GC ref info in old flags - ), - // Lacking actual field offsets, assume fields are naturally aligned without empty fields or padding - 0, - hasTwo ? (1u << (sizeShift1st > sizeShift2nd ? sizeShift1st : sizeShift2nd)) : 0, - }; - } }; static_assert(sizeof(FpStructInRegistersInfo) == 3 * sizeof(uint32_t), ""); From 0e80ccf9aa0e15a15ee7fbd39b1bdbc9fc9f6530 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomek=20Sowi=C5=84ski?= Date: Tue, 25 Jun 2024 08:19:37 +0200 Subject: [PATCH 04/35] Fix duplicating types in HandleInlineArray --- .../JitInterface/RISCV64PassStructInRegister.cs | 14 ++++++++++---- src/coreclr/vm/methodtable.cpp | 14 ++++++++++---- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/src/coreclr/tools/Common/JitInterface/RISCV64PassStructInRegister.cs b/src/coreclr/tools/Common/JitInterface/RISCV64PassStructInRegister.cs index 1d60ae3c533cc..71e8816636b13 100644 --- a/src/coreclr/tools/Common/JitInterface/RISCV64PassStructInRegister.cs +++ b/src/coreclr/tools/Common/JitInterface/RISCV64PassStructInRegister.cs @@ -176,10 +176,16 @@ private static bool HandleInlineArray(int elementTypeIndex, int nElements, ref F Debug.Assert(elementTypeIndex == 0); Debug.Assert(typeIndex == 1); - // duplicate the array element info - const int typeSize = (int)PosIntFloat - (int)PosFloatInt; - info.flags |= (FpStruct)((int)info.flags << typeSize); - info.offset2nd = info.offset1st + info.Size1st(); + // Duplicate the array element info + Debug.Assert((int)FpStruct.IntFloat == ((int)FpStruct.FloatInt << 1), + "FloatInt and IntFloat need to be adjacent"); + Debug.Assert((int)FpStruct.SizeShift2ndMask == ((int)FpStruct.SizeShift1stMask << 2), + "SizeShift1st and 2nd need to be adjacent"); + // Take the 1st field info and shift up to the 2nd field's positions + int floatFlag = (int)(info.flags & FpStruct.FloatInt) << 1; + int sizeShiftMask = (int)(info.flags & FpStruct.SizeShift1stMask) << 2; + info.flags |= (FpStruct)(floatFlag | sizeShiftMask); // merge with 1st field + info.offset2nd = info.offset1st + info.Size1st(); // bump up the field offset } return true; } diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index 31083c32713ae..afec27e378294 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -2966,10 +2966,16 @@ static bool HandleInlineArray(int elementTypeIndex, int nElements, FpStructInReg assert(elementTypeIndex == 0); assert(typeIndex == 1); - // duplicate the array element info - static const int typeSize = FpStruct::PosIntFloat - FpStruct::PosFloatInt; - info.flags = FpStruct::Flags(info.flags | (info.flags << typeSize)); - info.offset2nd = info.offset1st + info.Size1st(); + // Duplicate the array element info + static_assert(FpStruct::IntFloat == (FpStruct::FloatInt << 1), + "FloatInt and IntFloat need to be adjacent"); + static_assert(FpStruct::SizeShift2ndMask == (FpStruct::SizeShift1stMask << 2), + "SizeShift1st and 2nd need to be adjacent"); + // Take the 1st field info and shift up to the 2nd field's positions + int floatFlag = (info.flags & FpStruct::FloatInt) << 1; + int sizeShiftMask = (info.flags & FpStruct::SizeShift1stMask) << 2; + info.flags = FpStruct::Flags(info.flags | floatFlag | sizeShiftMask); // merge with 1st field + info.offset2nd = info.offset1st + info.Size1st(); // bump up the field offset LOG((LF_JIT, LL_EVERYTHING, "FpStructInRegistersInfo:%*s * duplicated array element type\n", nestingLevel * 4, "")); } From 3d139ac46d1efb8efd9e89962ab0d068d628483e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomek=20Sowi=C5=84ski?= Date: Tue, 25 Jun 2024 08:19:37 +0200 Subject: [PATCH 05/35] Remove signedness from FpStruct::IntKind because most probably we won't need it --- src/coreclr/inc/corinfo.h | 5 +-- .../tools/Common/JitInterface/CorInfoTypes.cs | 3 +- .../RISCV64PassStructInRegister.cs | 29 ++++++--------- src/coreclr/vm/methodtable.cpp | 37 ++++++++----------- 4 files changed, 30 insertions(+), 44 deletions(-) diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index 3b641ca3a967c..c0503d117d8da 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -361,8 +361,7 @@ namespace FpStruct { enum class IntKind { - Signed, - Unsigned, + Integer, GcRef, GcByRef, }; @@ -414,7 +413,7 @@ struct FpStructInRegistersInfo const char* IntFieldKindName() const { - static const char* intKindNames[] = { "Signed", "Unsigned", "GcRef", "GcByRef" }; + static const char* intKindNames[] = { "Integer", "GcRef", "GcByRef" }; return (flags & (FpStruct::FloatInt | FpStruct::IntFloat)) ? intKindNames[(int)IntFieldKind()] : "None"; diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs index 58c987db0a417..71ecda3d7cc74 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs @@ -1265,8 +1265,7 @@ public enum StructFloatFieldInfoFlags public enum FpStruct_IntKind { - Signed, - Unsigned, + Integer, GcRef, GcByRef, } diff --git a/src/coreclr/tools/Common/JitInterface/RISCV64PassStructInRegister.cs b/src/coreclr/tools/Common/JitInterface/RISCV64PassStructInRegister.cs index 71e8816636b13..14685174d02c8 100644 --- a/src/coreclr/tools/Common/JitInterface/RISCV64PassStructInRegister.cs +++ b/src/coreclr/tools/Common/JitInterface/RISCV64PassStructInRegister.cs @@ -133,8 +133,8 @@ private static void SetFpStructInRegistersInfoField(ref FpStructInRegistersInfo if (isFloating) { Debug.Assert(size == sizeof(float) || size == sizeof(double)); - Debug.Assert(intKind == FpStruct_IntKind.Signed); - Debug.Assert((int)FpStruct_IntKind.Signed == 0, + Debug.Assert(intKind == FpStruct_IntKind.Integer); + Debug.Assert((int)FpStruct_IntKind.Integer == 0, "IntKind for floating fields should not clobber IntKind for int fields"); } @@ -220,12 +220,6 @@ private static bool FlattenFields(TypeDesc td, uint offset, ref FpStructInRegist return false; // too many fields bool isFloating = category is TypeFlags.Single or TypeFlags.Double; - bool isSignedInt = category is - TypeFlags.SByte or - TypeFlags.Int16 or - TypeFlags.Int32 or - TypeFlags.Int64 or - TypeFlags.IntPtr; bool isGcRef = category is TypeFlags.Class or TypeFlags.Interface or @@ -235,7 +229,7 @@ TypeFlags.Array or FpStruct_IntKind intKind = isGcRef ? FpStruct_IntKind.GcRef : (category is TypeFlags.ByRef) ? FpStruct_IntKind.GcByRef : - (isSignedInt || isFloating) ? FpStruct_IntKind.Signed : FpStruct_IntKind.Unsigned; + FpStruct_IntKind.Integer; SetFpStructInRegistersInfoField(ref info, typeIndex++, isFloating, intKind, (uint)field.FieldType.GetElementSize().AsInt, offset + (uint)field.Offset.AsInt); @@ -295,18 +289,19 @@ private static FpStructInRegistersInfo GetRiscV64PassFpStructInRegistersInfoImpl } Debug.Assert(info.offset1st + info.Size1st() <= td.GetElementSize().AsInt); Debug.Assert(info.offset2nd + info.Size2nd() <= td.GetElementSize().AsInt); - if (info.IntFieldKind() != FpStruct_IntKind.Signed) + + FpStruct_IntKind intKind = info.IntFieldKind(); + if (intKind != FpStruct_IntKind.Integer) { Debug.Assert((info.flags & (FloatInt | IntFloat)) != 0); - if (info.IntFieldKind() >= FpStruct_IntKind.GcRef) - { - Debug.Assert((info.flags & IntFloat) != 0 - ? ((info.SizeShift1st() == 3) && IsAligned(info.offset1st, TARGET_POINTER_SIZE)) - : ((info.SizeShift2nd() == 3) && IsAligned(info.offset2nd, TARGET_POINTER_SIZE))); - } + + Debug.Assert(intKind == FpStruct_IntKind.GcRef || intKind == FpStruct_IntKind.GcByRef); + Debug.Assert((info.flags & IntFloat) != 0 + ? ((info.SizeShift1st() == 3) && IsAligned(info.offset1st, TARGET_POINTER_SIZE)) + : ((info.SizeShift2nd() == 3) && IsAligned(info.offset2nd, TARGET_POINTER_SIZE))); } if ((info.flags & (OnlyOne | BothFloat)) != 0) - Debug.Assert(info.IntFieldKind() == FpStruct_IntKind.Signed); + Debug.Assert(intKind == FpStruct_IntKind.Integer); return info; } diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index afec27e378294..c0e81cde40199 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -2911,8 +2911,8 @@ static void SetFpStructInRegistersInfoField(FpStructInRegistersInfo& info, int i if (isFloating) { assert(size == sizeof(float) || size == sizeof(double)); - assert(intKind == FpStruct::IntKind::Signed); - static_assert((int)FpStruct::IntKind::Signed == 0, + assert(intKind == FpStruct::IntKind::Integer); + static_assert((int)FpStruct::IntKind::Integer == 0, "IntKind for floating fields should not clobber IntKind for int fields"); } @@ -3027,18 +3027,11 @@ static bool FlattenFields(TypeHandle th, uint32_t offset, FpStructInRegistersInf } bool isFloating = CorTypeInfo::IsFloat_NoThrow(type); - bool isSignedInt = ( - type == ELEMENT_TYPE_I1 || - type == ELEMENT_TYPE_I2 || - type == ELEMENT_TYPE_I4 || - type == ELEMENT_TYPE_I8 || - type == ELEMENT_TYPE_I); CorInfoGCType gcType = CorTypeInfo::GetGCType_NoThrow(type); - FpStruct::IntKind intKind = (gcType == TYPE_GC_REF) ? FpStruct::IntKind::GcRef : (gcType == TYPE_GC_BYREF) ? FpStruct::IntKind::GcByRef : - (isSignedInt || isFloating) ? FpStruct::IntKind::Signed : FpStruct::IntKind::Unsigned; + FpStruct::IntKind::Integer; SetFpStructInRegistersInfoField(info, typeIndex++, isFloating, intKind, CorTypeInfo::Size_NoThrow(type), offset + fields[i].GetOffset()); @@ -3104,11 +3097,11 @@ static bool FlattenFields(TypeHandle th, uint32_t offset, FpStructInRegistersInf return false; } + bool isFloating = (category == NativeFieldCategory::FLOAT); + SetFpStructInRegistersInfoField(info, typeIndex++, - (category == NativeFieldCategory::FLOAT), - FpStruct::IntKind::Signed, // NativeFieldDescriptor doesn't save signedness, TODO: should it? - fields[i].NativeSize(), - offset + fields[i].GetExternalOffset()); + isFloating, FpStruct::IntKind::Integer, fields[i].NativeSize(), offset + fields[i].GetExternalOffset()); + LOG((LF_JIT, LL_EVERYTHING, "FpStructInRegistersInfo:%*s * found field %s [%i..%i), type: %s\n", nestingLevel * 4, "", fields[i].GetFieldDesc()->GetDebugName(), fields[i].GetExternalOffset(), fields[i].GetExternalOffset() + fields[i].NativeSize(), categoryNames[(int)category])); @@ -3170,18 +3163,18 @@ static FpStructInRegistersInfo GetRiscV64PassFpStructInRegistersInfoImpl(TypeHan } assert(info.offset1st + info.Size1st() <= th.GetSize()); assert(info.offset2nd + info.Size2nd() <= th.GetSize()); - if (info.IntFieldKind() != FpStruct::IntKind::Signed) + + FpStruct::IntKind intKind = info.IntFieldKind(); + if (intKind != FpStruct::IntKind::Integer) { assert(info.flags & (FloatInt | IntFloat)); - if (info.IntFieldKind() >= FpStruct::IntKind::GcRef) - { - assert((info.flags & IntFloat) != 0 - ? ((info.SizeShift1st() == 3) && IS_ALIGNED(info.offset1st, TARGET_POINTER_SIZE)) - : ((info.SizeShift2nd() == 3) && IS_ALIGNED(info.offset2nd, TARGET_POINTER_SIZE))); - } + assert(intKind == FpStruct::IntKind::GcRef || intKind == FpStruct::IntKind::GcByRef); + assert((info.flags & IntFloat) != 0 + ? ((info.SizeShift1st() == 3) && IS_ALIGNED(info.offset1st, TARGET_POINTER_SIZE)) + : ((info.SizeShift2nd() == 3) && IS_ALIGNED(info.offset2nd, TARGET_POINTER_SIZE))); } if (info.flags & (OnlyOne | BothFloat)) - assert(info.IntFieldKind() == FpStruct::IntKind::Signed); + assert(intKind == FpStruct::IntKind::Integer); LOG((LF_JIT, LL_EVERYTHING, "FpStructInRegistersInfo: " "struct %s (%u bytes) can be passed with floating-point calling convention, flags=%#03x; " From 89cc1480f3fc4993c473cc342576586a536d8c38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomek=20Sowi=C5=84ski?= Date: Tue, 25 Jun 2024 09:07:17 +0200 Subject: [PATCH 06/35] Remove old StructFloatFieldInfoFlags calculating routine --- .../RISCV64PassStructInRegister.cs | 122 +---------- src/coreclr/vm/methodtable.cpp | 207 +----------------- src/coreclr/vm/methodtable.h | 2 +- 3 files changed, 7 insertions(+), 324 deletions(-) diff --git a/src/coreclr/tools/Common/JitInterface/RISCV64PassStructInRegister.cs b/src/coreclr/tools/Common/JitInterface/RISCV64PassStructInRegister.cs index 14685174d02c8..43b20475571eb 100644 --- a/src/coreclr/tools/Common/JitInterface/RISCV64PassStructInRegister.cs +++ b/src/coreclr/tools/Common/JitInterface/RISCV64PassStructInRegister.cs @@ -16,116 +16,6 @@ private const int ENREGISTERED_PARAMTYPE_MAXSIZE = 16, TARGET_POINTER_SIZE = 8; - private static bool HandleInlineArrayOld(int elementTypeIndex, int nElements, Span types, ref int typeIndex) - { - int nFlattenedFieldsPerElement = typeIndex - elementTypeIndex; - if (nFlattenedFieldsPerElement == 0) - return true; - - Debug.Assert(nFlattenedFieldsPerElement == 1 || nFlattenedFieldsPerElement == 2); - - if (nElements > 2) - return false; - - if (nElements == 2) - { - if (typeIndex + nFlattenedFieldsPerElement > 2) - return false; - - Debug.Assert(elementTypeIndex == 0); - Debug.Assert(typeIndex == 1); - types[typeIndex++] = types[elementTypeIndex]; // duplicate the array element type - } - return true; - } - - private static bool FlattenFieldTypesOld(TypeDesc td, Span types, ref int typeIndex) - { - IEnumerable fields = td.GetFields(); - int nFields = 0; - int elementTypeIndex = typeIndex; - FieldDesc prevField = null; - foreach (FieldDesc field in fields) - { - if (field.IsStatic) - continue; - nFields++; - - if (prevField != null && prevField.Offset.AsInt + prevField.FieldType.GetElementSize().AsInt > field.Offset.AsInt) - return false; // overlapping fields - - prevField = field; - - TypeFlags category = field.FieldType.Category; - if (category == TypeFlags.ValueType) - { - TypeDesc nested = field.FieldType; - if (!FlattenFieldTypesOld(nested, types, ref typeIndex)) - return false; - } - else if (field.FieldType.GetElementSize().AsInt <= TARGET_POINTER_SIZE) - { - if (typeIndex >= 2) - return false; - - StructFloatFieldInfoFlags type = - (category is TypeFlags.Single or TypeFlags.Double ? STRUCT_FLOAT_FIELD_FIRST : (StructFloatFieldInfoFlags)0) | - (field.FieldType.GetElementSize().AsInt == TARGET_POINTER_SIZE ? STRUCT_FIRST_FIELD_SIZE_IS8 : (StructFloatFieldInfoFlags)0); - types[typeIndex++] = type; - } - else - { - return false; - } - } - - if ((td as MetadataType).HasImpliedRepeatedFields()) - { - Debug.Assert(nFields == 1); - int nElements = td.GetElementSize().AsInt / prevField.FieldType.GetElementSize().AsInt; - if (!HandleInlineArrayOld(elementTypeIndex, nElements, types, ref typeIndex)) - return false; - } - return true; - } - - private static uint GetRISCV64PassStructInRegisterFlags(TypeDesc td) - { - if (td.GetElementSize().AsInt > ENREGISTERED_PARAMTYPE_MAXSIZE) - return (uint)STRUCT_NO_FLOAT_FIELD; - - Span types = stackalloc StructFloatFieldInfoFlags[] { - STRUCT_NO_FLOAT_FIELD, STRUCT_NO_FLOAT_FIELD - }; - int nFields = 0; - if (!FlattenFieldTypesOld(td, types, ref nFields) || nFields == 0) - return (uint)STRUCT_NO_FLOAT_FIELD; - - Debug.Assert(nFields == 1 || nFields == 2); - - Debug.Assert((uint)(STRUCT_FLOAT_FIELD_SECOND | STRUCT_SECOND_FIELD_SIZE_IS8) - == (uint)(STRUCT_FLOAT_FIELD_FIRST | STRUCT_FIRST_FIELD_SIZE_IS8) << 1, - "SECOND flags need to be FIRST shifted by 1"); - StructFloatFieldInfoFlags flags = types[0] | (StructFloatFieldInfoFlags)((uint)types[1] << 1); - - const StructFloatFieldInfoFlags bothFloat = STRUCT_FLOAT_FIELD_FIRST | STRUCT_FLOAT_FIELD_SECOND; - if ((flags & bothFloat) == 0) - return (uint)STRUCT_NO_FLOAT_FIELD; - - if ((flags & bothFloat) == bothFloat) - { - Debug.Assert(nFields == 2); - flags ^= (bothFloat | STRUCT_FLOAT_FIELD_ONLY_TWO); // replace bothFloat with ONLY_TWO - } - else if (nFields == 1) - { - Debug.Assert((flags & STRUCT_FLOAT_FIELD_FIRST) != 0); - flags ^= (STRUCT_FLOAT_FIELD_FIRST | STRUCT_FLOAT_FIELD_ONLY_ONE); // replace FIRST with ONLY_ONE - } - return (uint)flags; - } - - private static void SetFpStructInRegistersInfoField(ref FpStructInRegistersInfo info, int index, bool isFloating, FpStruct_IntKind intKind, uint size, uint offset) { @@ -252,7 +142,7 @@ TypeFlags.Array or private static bool IsAligned(uint val, uint alignment) => 0 == (val & (alignment - 1)); - private static FpStructInRegistersInfo GetRiscV64PassFpStructInRegistersInfoImpl(TypeDesc td) + public static FpStructInRegistersInfo GetRiscV64PassFpStructInRegistersInfo(TypeDesc td) { FpStructInRegistersInfo info = new FpStructInRegistersInfo{}; int nFields = 0; @@ -305,15 +195,5 @@ private static FpStructInRegistersInfo GetRiscV64PassFpStructInRegistersInfoImpl return info; } - - public static FpStructInRegistersInfo GetRiscV64PassFpStructInRegistersInfo(TypeDesc td) - { - FpStructInRegistersInfo info = GetRiscV64PassFpStructInRegistersInfoImpl(td); - uint flags = GetRISCV64PassStructInRegisterFlags(td); - - Debug.Assert(flags == (uint)info.ToOldFlags()); - - return info; - } } } diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index c0e81cde40199..c018f1945db01 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -2715,194 +2715,6 @@ void MethodTable::AssignClassifiedEightByteTypes(SystemVStructRegisterPassingHe #endif // defined(UNIX_AMD64_ABI_ITF) -#if defined(TARGET_RISCV64) || defined(TARGET_LOONGARCH64) -static bool HandleInlineArrayOld(int elementTypeIndex, int nElements, StructFloatFieldInfoFlags types[2], int& typeIndex) -{ - int nFlattenedFieldsPerElement = typeIndex - elementTypeIndex; - if (nFlattenedFieldsPerElement == 0) - return true; - - assert(nFlattenedFieldsPerElement == 1 || nFlattenedFieldsPerElement == 2); - - if (nElements > 2) - return false; - - if (nElements == 2) - { - if (typeIndex + nFlattenedFieldsPerElement > 2) - return false; - - assert(elementTypeIndex == 0); - assert(typeIndex == 1); - types[typeIndex] = types[elementTypeIndex]; // duplicate the array element type - } - return true; -} - -static bool FlattenFieldTypesOld(TypeHandle th, StructFloatFieldInfoFlags types[2], int& typeIndex) -{ - bool isManaged = !th.IsTypeDesc(); - MethodTable* pMT = isManaged ? th.AsMethodTable() : th.AsNativeValueType(); - int nFields = isManaged ? pMT->GetNumIntroducedInstanceFields() : pMT->GetNativeLayoutInfo()->GetNumFields(); - - // TODO: templatize isManaged and use if constexpr for differences when we migrate to C++17 - // because the logic for both branches is nearly the same. - if (isManaged) - { - FieldDesc* fields = pMT->GetApproxFieldDescListRaw(); - int elementTypeIndex = typeIndex; - for (int i = 0; i < nFields; ++i) - { - if (i > 0 && fields[i-1].GetOffset() + fields[i-1].GetSize() > fields[i].GetOffset()) - return false; // overlapping fields - - CorElementType type = fields[i].GetFieldType(); - if (type == ELEMENT_TYPE_VALUETYPE) - { - MethodTable* nested = fields[i].GetApproxFieldTypeHandleThrowing().GetMethodTable(); - if (!FlattenFieldTypesOld(TypeHandle(nested), types, typeIndex)) - return false; - } - else if (fields[i].GetSize() <= TARGET_POINTER_SIZE) - { - if (typeIndex >= 2) - return false; - - StructFloatFieldInfoFlags retType = StructFloatFieldInfoFlags( - (CorTypeInfo::IsFloat_NoThrow(type) ? STRUCT_FLOAT_FIELD_FIRST : 0) | - (CorTypeInfo::Size_NoThrow(type) == TARGET_POINTER_SIZE ? STRUCT_FIRST_FIELD_SIZE_IS8 : 0)); - types[typeIndex++] = retType; - } - else - { - return false; - } - } - - if (HasImpliedRepeatedFields(pMT)) // inline array or fixed buffer - { - assert(nFields == 1); - int nElements = pMT->GetNumInstanceFieldBytes() / fields[0].GetSize(); - if (!HandleInlineArrayOld(elementTypeIndex, nElements, types, typeIndex)) - return false; - } - } - else // native layout - { - const NativeFieldDescriptor* fields = pMT->GetNativeLayoutInfo()->GetNativeFieldDescriptors(); - for (int i = 0; i < nFields; ++i) - { - if (i > 0 && fields[i-1].GetExternalOffset() + fields[i-1].NativeSize() > fields[i].GetExternalOffset()) - return false; // overlapping fields - - NativeFieldCategory category = fields[i].GetCategory(); - if (category == NativeFieldCategory::NESTED) - { - int elementTypeIndex = typeIndex; - - MethodTable* nested = fields[i].GetNestedNativeMethodTable(); - if (!FlattenFieldTypesOld(TypeHandle(nested), types, typeIndex)) - return false; - - // In native layout fixed arrays are marked as NESTED just like structs - int nElements = fields[i].GetNumElements(); - if (!HandleInlineArrayOld(elementTypeIndex, nElements, types, typeIndex)) - return false; - } - else if (fields[i].NativeSize() <= TARGET_POINTER_SIZE) - { - if (typeIndex >= 2) - return false; - - StructFloatFieldInfoFlags type = StructFloatFieldInfoFlags( - (category == NativeFieldCategory::FLOAT ? STRUCT_FLOAT_FIELD_FIRST : 0) | - (fields[i].NativeSize() == TARGET_POINTER_SIZE ? STRUCT_FIRST_FIELD_SIZE_IS8 : 0)); - types[typeIndex++] = type; - } - else - { - return false; - } - } - } - return true; -} -#endif - -#if defined(TARGET_LOONGARCH64) -int MethodTable::GetLoongArch64PassStructInRegisterFlags(TypeHandle th) -{ - if (th.GetSize() > ENREGISTERED_PARAMTYPE_MAXSIZE) - return STRUCT_NO_FLOAT_FIELD; - - StructFloatFieldInfoFlags types[2] = {STRUCT_NO_FLOAT_FIELD, STRUCT_NO_FLOAT_FIELD}; - int nFields = 0; - if (!FlattenFieldTypesOld(th, types, nFields) || nFields == 0) - return STRUCT_NO_FLOAT_FIELD; - - assert(nFields == 1 || nFields == 2); - - static_assert((STRUCT_FLOAT_FIELD_SECOND | STRUCT_SECOND_FIELD_SIZE_IS8) - == (STRUCT_FLOAT_FIELD_FIRST | STRUCT_FIRST_FIELD_SIZE_IS8) << 1, - "SECOND flags need to be FIRST shifted by 1"); - int flags = types[0] | (types[1] << 1); - - static const int bothFloat = STRUCT_FLOAT_FIELD_FIRST | STRUCT_FLOAT_FIELD_SECOND; - if ((flags & bothFloat) == 0) - return STRUCT_NO_FLOAT_FIELD; - - if ((flags & bothFloat) == bothFloat) - { - assert(nFields == 2); - flags ^= (bothFloat | STRUCT_FLOAT_FIELD_ONLY_TWO); // replace bothFloat with ONLY_TWO - } - else if (nFields == 1) - { - assert((flags & STRUCT_FLOAT_FIELD_FIRST) != 0); - flags ^= (STRUCT_FLOAT_FIELD_FIRST | STRUCT_FLOAT_FIELD_ONLY_ONE); // replace FIRST with ONLY_ONE - } - - return flags; -} -#endif - -#if defined(TARGET_RISCV64) -static int GetRiscV64PassStructInRegisterFlags(TypeHandle th) -{ - if (th.GetSize() > ENREGISTERED_PARAMTYPE_MAXSIZE) - return STRUCT_NO_FLOAT_FIELD; - - StructFloatFieldInfoFlags types[2] = {STRUCT_NO_FLOAT_FIELD, STRUCT_NO_FLOAT_FIELD}; - int nFields = 0; - if (!FlattenFieldTypesOld(th, types, nFields) || nFields == 0) - return STRUCT_NO_FLOAT_FIELD; - - assert(nFields == 1 || nFields == 2); - - static_assert((STRUCT_FLOAT_FIELD_SECOND | STRUCT_SECOND_FIELD_SIZE_IS8) - == (STRUCT_FLOAT_FIELD_FIRST | STRUCT_FIRST_FIELD_SIZE_IS8) << 1, - "SECOND flags need to be FIRST shifted by 1"); - int flags = types[0] | (types[1] << 1); - - static const int bothFloat = STRUCT_FLOAT_FIELD_FIRST | STRUCT_FLOAT_FIELD_SECOND; - if ((flags & bothFloat) == 0) - return STRUCT_NO_FLOAT_FIELD; - - if ((flags & bothFloat) == bothFloat) - { - assert(nFields == 2); - flags ^= (bothFloat | STRUCT_FLOAT_FIELD_ONLY_TWO); // replace bothFloat with ONLY_TWO - } - else if (nFields == 1) - { - assert((flags & STRUCT_FLOAT_FIELD_FIRST) != 0); - flags ^= (STRUCT_FLOAT_FIELD_FIRST | STRUCT_FLOAT_FIELD_ONLY_ONE); // replace FIRST with ONLY_ONE - } - - return flags; -} -#endif - #if defined(TARGET_RISCV64) || defined(TARGET_LOONGARCH64) static void SetFpStructInRegistersInfoField(FpStructInRegistersInfo& info, int index, bool isFloating, FpStruct::IntKind intKind, unsigned size, uint32_t offset) @@ -3118,11 +2930,12 @@ static bool FlattenFields(TypeHandle th, uint32_t offset, FpStructInRegistersInf } return true; } -#endif #if defined(TARGET_RISCV64) - -static FpStructInRegistersInfo GetRiscV64PassFpStructInRegistersInfoImpl(TypeHandle th) +FpStructInRegistersInfo MethodTable::GetRiscV64PassFpStructInRegistersInfo(TypeHandle th) +#elif defined(TARGET_LOONGARCH64) +FpStructInRegistersInfo MethodTable::GetLoongArch64PassFpStructInRegistersInfo(TypeHandle th) +#endif { FpStructInRegistersInfo info = {}; int nFields = 0; @@ -3184,17 +2997,7 @@ static FpStructInRegistersInfo GetRiscV64PassFpStructInRegistersInfoImpl(TypeHan )); return info; } - -FpStructInRegistersInfo MethodTable::GetRiscV64PassFpStructInRegistersInfo(TypeHandle th) -{ - FpStructInRegistersInfo info = GetRiscV64PassFpStructInRegistersInfoImpl(th); - int flags = GetRiscV64PassStructInRegisterFlags(th); - - assert(flags == info.ToOldFlags()); - - return info; -} -#endif // TARGET_RISCV64 +#endif // defined(TARGET_RISCV64) || defined(TARGET_LOONGARCH64) #if !defined(DACCESS_COMPILE) namespace diff --git a/src/coreclr/vm/methodtable.h b/src/coreclr/vm/methodtable.h index 44d2ce7c9c37a..1786fb0ab5897 100644 --- a/src/coreclr/vm/methodtable.h +++ b/src/coreclr/vm/methodtable.h @@ -1012,7 +1012,7 @@ class MethodTable void CheckRunClassInitAsIfConstructingThrowing(); #if defined(TARGET_LOONGARCH64) - static int GetLoongArch64PassStructInRegisterFlags(TypeHandle th); + static FpStructInRegistersInfo GetLoongArch64PassFpStructInRegistersInfo(TypeHandle th); #elif defined(TARGET_RISCV64) static FpStructInRegistersInfo GetRiscV64PassFpStructInRegistersInfo(TypeHandle th); #endif From c2984a2985c5d3c2c488f276920026dc690f07fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomek=20Sowi=C5=84ski?= Date: Tue, 25 Jun 2024 09:30:08 +0200 Subject: [PATCH 07/35] Typo in TARGET_LOONGARCH64 --- src/coreclr/vm/callhelpers.cpp | 2 +- src/coreclr/vm/reflectioninvocation.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreclr/vm/callhelpers.cpp b/src/coreclr/vm/callhelpers.cpp index e869af831fc82..15da119d9f6d2 100644 --- a/src/coreclr/vm/callhelpers.cpp +++ b/src/coreclr/vm/callhelpers.cpp @@ -534,7 +534,7 @@ void MethodDescCallSite::CallTargetWorker(const ARG_SLOT *pArguments, ARG_SLOT * #ifdef CALLDESCR_REGTYPEMAP callDescrData.dwRegTypeMap = dwRegTypeMap; #endif -#if defined(TARGET_RISCV64) || defined(TARGET_LOONGARCH) +#if defined(TARGET_RISCV64) || defined(TARGET_LOONGARCH64) // Temporary conversion to old flags, CallDescrWorker needs to be overhauled anyway // to work with arbitrary field offsets and sizes, and support struct size > 16 on RISC-V. callDescrData.fpReturnSize = FpStructInRegistersInfo{FpStruct::Flags(fpReturnSize)}.ToOldFlags(); diff --git a/src/coreclr/vm/reflectioninvocation.cpp b/src/coreclr/vm/reflectioninvocation.cpp index 803253631854c..dfb882eb84e39 100644 --- a/src/coreclr/vm/reflectioninvocation.cpp +++ b/src/coreclr/vm/reflectioninvocation.cpp @@ -497,7 +497,7 @@ FCIMPL4(Object*, RuntimeMethodHandle::InvokeMethod, #ifdef CALLDESCR_REGTYPEMAP callDescrData.dwRegTypeMap = 0; #endif -#if defined(TARGET_RISCV64) || defined(TARGET_LOONGARCH) +#if defined(TARGET_RISCV64) || defined(TARGET_LOONGARCH64) // Temporary conversion to old flags, CallDescrWorker needs to be overhauled anyway // to work with arbitrary field offsets and sizes, and support struct size > 16 on RISC-V. callDescrData.fpReturnSize = FpStructInRegistersInfo{FpStruct::Flags(argit.GetFPReturnSize())}.ToOldFlags(); From a22983143853e4845f82afe1a035655841bf9f14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomek=20Sowi=C5=84ski?= Date: Tue, 25 Jun 2024 09:38:38 +0200 Subject: [PATCH 08/35] Remove m_returnedFpFieldOffsets from ArgIterator --- src/coreclr/vm/callingconvention.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/coreclr/vm/callingconvention.h b/src/coreclr/vm/callingconvention.h index 920854b0011a1..4c139e2759e97 100644 --- a/src/coreclr/vm/callingconvention.h +++ b/src/coreclr/vm/callingconvention.h @@ -909,11 +909,6 @@ class ArgIteratorTemplate : public ARGITERATOR_BASE protected: DWORD m_dwFlags; // Cached flags int m_nSizeOfArgStack; // Cached value of SizeOfArgStack -#if defined(TARGET_RISCV64) - // Offsets of fields returned according to hardware floating-point calling convention - // (FpStruct::Flags are embedded in m_dwFlags) - unsigned m_returnedFpFieldOffsets[2]; -#endif DWORD m_argNum; From f2b38f8dc60e040113cbfb704b63cd4d5b446038 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomek=20Sowi=C5=84ski?= Date: Tue, 25 Jun 2024 09:56:50 +0200 Subject: [PATCH 09/35] Add missing ENREGISTERED_PARAMTYPE_MAXSIZE condition to C# version of FpStruct info calculation --- .../tools/Common/JitInterface/RISCV64PassStructInRegister.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/coreclr/tools/Common/JitInterface/RISCV64PassStructInRegister.cs b/src/coreclr/tools/Common/JitInterface/RISCV64PassStructInRegister.cs index 43b20475571eb..72cb1aa24cc7f 100644 --- a/src/coreclr/tools/Common/JitInterface/RISCV64PassStructInRegister.cs +++ b/src/coreclr/tools/Common/JitInterface/RISCV64PassStructInRegister.cs @@ -6,7 +6,6 @@ using ILCompiler; using Internal.TypeSystem; using static Internal.JitInterface.FpStruct; -using static Internal.JitInterface.StructFloatFieldInfoFlags; namespace Internal.JitInterface { @@ -144,6 +143,9 @@ TypeFlags.Array or public static FpStructInRegistersInfo GetRiscV64PassFpStructInRegistersInfo(TypeDesc td) { + if (td.GetElementSize().AsInt > ENREGISTERED_PARAMTYPE_MAXSIZE) + return new FpStructInRegistersInfo{}; + FpStructInRegistersInfo info = new FpStructInRegistersInfo{}; int nFields = 0; if (!FlattenFields(td, 0, ref info, ref nFields)) From 54816931fc39de9cc39504f3803b0dcaa193238e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomek=20Sowi=C5=84ski?= Date: Wed, 26 Jun 2024 08:43:16 +0200 Subject: [PATCH 10/35] Rename RISCV64PassStructInRegister to match settled casing for RiscV in class names --- src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs | 2 +- ...assStructInRegister.cs => RiscV64PassFpStructInRegisters.cs} | 2 +- .../Compiler/DependencyAnalysis/ReadyToRun/ArgIterator.cs | 2 +- .../Compiler/DependencyAnalysis/ReadyToRun/TransitionBlock.cs | 2 +- .../aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) rename src/coreclr/tools/Common/JitInterface/{RISCV64PassStructInRegister.cs => RiscV64PassFpStructInRegisters.cs} (99%) diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index 6c31276783f73..8ccec69957670 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -3456,7 +3456,7 @@ private uint getLoongArch64PassStructInRegisterFlags(CORINFO_CLASS_STRUCT_* cls) private FpStructInRegistersInfo getRiscV64PassFpStructInRegistersInfo(CORINFO_CLASS_STRUCT_* cls) { TypeDesc typeDesc = HandleToObject(cls); - return RISCV64PassStructInRegister.GetRiscV64PassFpStructInRegistersInfo(typeDesc); + return RiscV64PassFpStructInRegisters.GetRiscV64PassFpStructInRegistersInfo(typeDesc); } private uint getThreadTLSIndex(ref void* ppIndirection) diff --git a/src/coreclr/tools/Common/JitInterface/RISCV64PassStructInRegister.cs b/src/coreclr/tools/Common/JitInterface/RiscV64PassFpStructInRegisters.cs similarity index 99% rename from src/coreclr/tools/Common/JitInterface/RISCV64PassStructInRegister.cs rename to src/coreclr/tools/Common/JitInterface/RiscV64PassFpStructInRegisters.cs index 72cb1aa24cc7f..961477fa55983 100644 --- a/src/coreclr/tools/Common/JitInterface/RISCV64PassStructInRegister.cs +++ b/src/coreclr/tools/Common/JitInterface/RiscV64PassFpStructInRegisters.cs @@ -9,7 +9,7 @@ namespace Internal.JitInterface { - internal static class RISCV64PassStructInRegister + internal static class RiscV64PassFpStructInRegisters { private const int ENREGISTERED_PARAMTYPE_MAXSIZE = 16, diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ArgIterator.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ArgIterator.cs index 2e9e66fc4b71c..b1aa54a9a7268 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ArgIterator.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ArgIterator.cs @@ -1485,7 +1485,7 @@ public int GetNextOffset() } else { - info = RISCV64PassStructInRegister.GetRiscV64PassFpStructInRegistersInfo(_argTypeHandle.GetRuntimeTypeHandle()); + info = RiscV64PassFpStructInRegisters.GetRiscV64PassFpStructInRegistersInfo(_argTypeHandle.GetRuntimeTypeHandle()); if (info.flags != FpStruct.UseIntCallConv) { cFPRegs = ((info.flags & FpStruct.BothFloat) != 0) ? 2 : 1; diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/TransitionBlock.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/TransitionBlock.cs index e2d02cf8dfaa9..23c5970cc100e 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/TransitionBlock.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/TransitionBlock.cs @@ -391,7 +391,7 @@ public void ComputeReturnValueTreatment(CorElementType type, TypeHandle thRetTyp if (IsLoongArch64) fpReturnSize = LoongArch64PassStructInRegister.GetLoongArch64PassStructInRegisterFlags(thRetType.GetRuntimeTypeHandle()) & 0xff; else if (IsRiscV64) - fpReturnSize = (uint)RISCV64PassStructInRegister.GetRiscV64PassFpStructInRegistersInfo(thRetType.GetRuntimeTypeHandle()).flags & 0xff; + fpReturnSize = (uint)RiscV64PassFpStructInRegisters.GetRiscV64PassFpStructInRegistersInfo(thRetType.GetRuntimeTypeHandle()).flags & 0xff; break; } diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj index 96e6df9805eb0..e4de279ec885f 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj @@ -134,7 +134,7 @@ - + From 4250bf461c613e2f9c9793f79eecf27e3d152bfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomek=20Sowi=C5=84ski?= Date: Wed, 26 Jun 2024 08:49:23 +0200 Subject: [PATCH 11/35] Update hardcoded flags for float and double in ArgIteratorTemplate::ComputeReturnFlags() This fixes JIT/HardwareIntrinsics/General/Vector* tests. --- .../ReadyToRun/TransitionBlock.cs | 14 +++++++++++--- src/coreclr/vm/callingconvention.h | 7 ++++--- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/TransitionBlock.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/TransitionBlock.cs index 23c5970cc100e..2939e2cde5640 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/TransitionBlock.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/TransitionBlock.cs @@ -314,14 +314,22 @@ public void ComputeReturnValueTreatment(CorElementType type, TypeHandle thRetTyp throw new NotSupportedException(); case CorElementType.ELEMENT_TYPE_R4: - if (!IsArmelABI) + if (IsRiscV64 || IsLoongArch64) + { + fpReturnSize = (uint)FpStruct.OnlyOne | (2 << (int)FpStruct.PosSizeShift1st); + } + else if (!IsArmelABI) { fpReturnSize = sizeof(float); } break; case CorElementType.ELEMENT_TYPE_R8: - if (!IsArmelABI) + if (IsRiscV64 || IsLoongArch64) + { + fpReturnSize = (uint)FpStruct.OnlyOne | (3 << (int)FpStruct.PosSizeShift1st); + } + else if (!IsArmelABI) { fpReturnSize = sizeof(double); } @@ -391,7 +399,7 @@ public void ComputeReturnValueTreatment(CorElementType type, TypeHandle thRetTyp if (IsLoongArch64) fpReturnSize = LoongArch64PassStructInRegister.GetLoongArch64PassStructInRegisterFlags(thRetType.GetRuntimeTypeHandle()) & 0xff; else if (IsRiscV64) - fpReturnSize = (uint)RiscV64PassFpStructInRegisters.GetRiscV64PassFpStructInRegistersInfo(thRetType.GetRuntimeTypeHandle()).flags & 0xff; + fpReturnSize = (uint)RiscV64PassFpStructInRegisters.GetRiscV64PassFpStructInRegistersInfo(thRetType.GetRuntimeTypeHandle()).flags; break; } diff --git a/src/coreclr/vm/callingconvention.h b/src/coreclr/vm/callingconvention.h index 4c139e2759e97..eb89f6cef4970 100644 --- a/src/coreclr/vm/callingconvention.h +++ b/src/coreclr/vm/callingconvention.h @@ -1939,7 +1939,7 @@ void ArgIteratorTemplate::ComputeReturnFlags() case ELEMENT_TYPE_R4: #if defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) - flags |= STRUCT_FLOAT_FIELD_ONLY_ONE << RETURN_FP_SIZE_SHIFT; + flags |= (FpStruct::OnlyOne | (2 << FpStruct::PosSizeShift1st)) << RETURN_FP_SIZE_SHIFT; #else #ifndef ARM_SOFTFP flags |= sizeof(float) << RETURN_FP_SIZE_SHIFT; @@ -1949,7 +1949,7 @@ void ArgIteratorTemplate::ComputeReturnFlags() case ELEMENT_TYPE_R8: #if defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) - flags |= (STRUCT_FLOAT_FIELD_ONLY_ONE | STRUCT_FIRST_FIELD_SIZE_IS8) << RETURN_FP_SIZE_SHIFT; + flags |= (FpStruct::OnlyOne | (3 << FpStruct::PosSizeShift1st)) << RETURN_FP_SIZE_SHIFT; #else #ifndef ARM_SOFTFP flags |= sizeof(double) << RETURN_FP_SIZE_SHIFT; @@ -2029,7 +2029,8 @@ void ArgIteratorTemplate::ComputeReturnFlags() if (size <= ENREGISTERED_RETURNTYPE_INTEGER_MAXSIZE) { assert(!thValueType.IsTypeDesc()); - flags = (MethodTable::GetRiscV64PassFpStructInRegistersInfo(thValueType).flags & 0xff) << RETURN_FP_SIZE_SHIFT; + FpStructInRegistersInfo info = MethodTable::GetRiscV64PassFpStructInRegistersInfo(thValueType); + flags |= info.flags << RETURN_FP_SIZE_SHIFT; break; } #else From 0f03a8877c67f8c28b6842772e7e9683ac73df10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomek=20Sowi=C5=84ski?= Date: Wed, 26 Jun 2024 09:37:42 +0200 Subject: [PATCH 12/35] Fix build on other platforms --- .../tools/aot/ILCompiler.RyuJit/ILCompiler.RyuJit.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreclr/tools/aot/ILCompiler.RyuJit/ILCompiler.RyuJit.csproj b/src/coreclr/tools/aot/ILCompiler.RyuJit/ILCompiler.RyuJit.csproj index 3ddf3e46a13cb..c980efdb95442 100644 --- a/src/coreclr/tools/aot/ILCompiler.RyuJit/ILCompiler.RyuJit.csproj +++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/ILCompiler.RyuJit.csproj @@ -85,8 +85,8 @@ JitInterface\LoongArch64PassStructInRegister.cs - - JitInterface\RISCV64PassStructInRegister.cs + + JitInterface\RiscV64PassFpStructInRegisters.cs JitInterface\SwiftPhysicalLowering.cs From f485362f4f1faa942b98e4c5688065d49783ef41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomek=20Sowi=C5=84ski?= Date: Wed, 26 Jun 2024 11:42:10 +0200 Subject: [PATCH 13/35] Update LoongArch to use FpStructInRegistersInfo --- src/coreclr/inc/corinfo.h | 4 +- src/coreclr/inc/corinfoinstructionset.h | 24 +-- src/coreclr/inc/icorjitinfoimpl_generated.h | 2 +- src/coreclr/inc/jiteeversionguid.h | 10 +- src/coreclr/jit/ICorJitInfo_names_generated.h | 2 +- .../jit/ICorJitInfo_wrapper_generated.hpp | 8 +- src/coreclr/jit/compiler.cpp | 19 +-- src/coreclr/jit/targetloongarch64.cpp | 28 ++-- .../tools/Common/JitInterface/CorInfoImpl.cs | 4 +- .../JitInterface/CorInfoImpl_generated.cs | 6 +- .../JitInterface/CorInfoInstructionSet.cs | 48 +++--- .../LoongArch64PassStructInRegister.cs | 150 +++++++++++++----- .../ThunkGenerator/ThunkInput.txt | 2 +- .../ReadyToRun/ArgIterator.cs | 45 +++--- .../ReadyToRun/TransitionBlock.cs | 2 +- .../aot/jitinterface/jitinterface_generated.h | 6 +- .../tools/superpmi/superpmi-shared/lwmlist.h | 2 +- .../superpmi-shared/methodcontext.cpp | 23 +-- .../superpmi/superpmi-shared/methodcontext.h | 15 +- .../superpmi-shim-collector/icorjitinfo.cpp | 8 +- .../icorjitinfo_generated.cpp | 6 +- .../icorjitinfo_generated.cpp | 4 +- .../tools/superpmi/superpmi/icorjitinfo.cpp | 6 +- src/coreclr/vm/callingconvention.h | 34 ++-- src/coreclr/vm/jitinterface.cpp | 10 +- src/coreclr/vm/loongarch64/profiler.cpp | 16 +- src/coreclr/vm/methodtable.cpp | 7 + 27 files changed, 275 insertions(+), 216 deletions(-) diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index c0503d117d8da..9054214396be5 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -317,7 +317,7 @@ struct SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR } }; -// StructFloadFieldInfoFlags: used on LoongArch64 architecture by `getLoongArch64PassStructInRegisterFlags` and +// StructFloatFieldInfoFlags: used on LoongArch64 architecture by `getLoongArch64PassStructInRegisterFlags` and // `getRISCV64PassStructInRegisterFlags` API to convey struct argument passing information. // // `STRUCT_NO_FLOAT_FIELD` means structs are not passed using the float register(s). @@ -3163,7 +3163,7 @@ class ICorStaticInfo // Classifies a swift structure into primitives or an implicit byref for ABI purposes. virtual void getSwiftLowering(CORINFO_CLASS_HANDLE structHnd, CORINFO_SWIFT_LOWERING* pLowering) = 0; - virtual uint32_t getLoongArch64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE cls) = 0; + virtual FpStructInRegistersInfo getLoongArch64PassFpStructInRegistersInfo(CORINFO_CLASS_HANDLE cls) = 0; virtual FpStructInRegistersInfo getRiscV64PassFpStructInRegistersInfo(CORINFO_CLASS_HANDLE cls) = 0; }; diff --git a/src/coreclr/inc/corinfoinstructionset.h b/src/coreclr/inc/corinfoinstructionset.h index 9a3c0efc70927..43f2be795314f 100644 --- a/src/coreclr/inc/corinfoinstructionset.h +++ b/src/coreclr/inc/corinfoinstructionset.h @@ -608,18 +608,18 @@ inline CORINFO_InstructionSetFlags EnsureInstructionSetFlagsAreValid(CORINFO_Ins resultflags.RemoveInstructionSet(InstructionSet_AVX512F); if (resultflags.HasInstructionSet(InstructionSet_AVX512F_VL) && !resultflags.HasInstructionSet(InstructionSet_AVX512F)) resultflags.RemoveInstructionSet(InstructionSet_AVX512F_VL); - if (resultflags.HasInstructionSet(InstructionSet_AVX512CD) && !resultflags.HasInstructionSet(InstructionSet_AVX512F)) - resultflags.RemoveInstructionSet(InstructionSet_AVX512CD); - if (resultflags.HasInstructionSet(InstructionSet_AVX512CD_VL) && !resultflags.HasInstructionSet(InstructionSet_AVX512CD)) - resultflags.RemoveInstructionSet(InstructionSet_AVX512CD_VL); - if (resultflags.HasInstructionSet(InstructionSet_AVX512CD_VL) && !resultflags.HasInstructionSet(InstructionSet_AVX512F_VL)) - resultflags.RemoveInstructionSet(InstructionSet_AVX512CD_VL); if (resultflags.HasInstructionSet(InstructionSet_AVX512BW) && !resultflags.HasInstructionSet(InstructionSet_AVX512F)) resultflags.RemoveInstructionSet(InstructionSet_AVX512BW); if (resultflags.HasInstructionSet(InstructionSet_AVX512BW_VL) && !resultflags.HasInstructionSet(InstructionSet_AVX512BW)) resultflags.RemoveInstructionSet(InstructionSet_AVX512BW_VL); if (resultflags.HasInstructionSet(InstructionSet_AVX512BW_VL) && !resultflags.HasInstructionSet(InstructionSet_AVX512F_VL)) resultflags.RemoveInstructionSet(InstructionSet_AVX512BW_VL); + if (resultflags.HasInstructionSet(InstructionSet_AVX512CD) && !resultflags.HasInstructionSet(InstructionSet_AVX512F)) + resultflags.RemoveInstructionSet(InstructionSet_AVX512CD); + if (resultflags.HasInstructionSet(InstructionSet_AVX512CD_VL) && !resultflags.HasInstructionSet(InstructionSet_AVX512CD)) + resultflags.RemoveInstructionSet(InstructionSet_AVX512CD_VL); + if (resultflags.HasInstructionSet(InstructionSet_AVX512CD_VL) && !resultflags.HasInstructionSet(InstructionSet_AVX512F_VL)) + resultflags.RemoveInstructionSet(InstructionSet_AVX512CD_VL); if (resultflags.HasInstructionSet(InstructionSet_AVX512DQ) && !resultflags.HasInstructionSet(InstructionSet_AVX512F)) resultflags.RemoveInstructionSet(InstructionSet_AVX512DQ); if (resultflags.HasInstructionSet(InstructionSet_AVX512DQ_VL) && !resultflags.HasInstructionSet(InstructionSet_AVX512DQ)) @@ -714,18 +714,18 @@ inline CORINFO_InstructionSetFlags EnsureInstructionSetFlagsAreValid(CORINFO_Ins resultflags.RemoveInstructionSet(InstructionSet_AVX512F); if (resultflags.HasInstructionSet(InstructionSet_AVX512F_VL) && !resultflags.HasInstructionSet(InstructionSet_AVX512F)) resultflags.RemoveInstructionSet(InstructionSet_AVX512F_VL); - if (resultflags.HasInstructionSet(InstructionSet_AVX512CD) && !resultflags.HasInstructionSet(InstructionSet_AVX512F)) - resultflags.RemoveInstructionSet(InstructionSet_AVX512CD); - if (resultflags.HasInstructionSet(InstructionSet_AVX512CD_VL) && !resultflags.HasInstructionSet(InstructionSet_AVX512CD)) - resultflags.RemoveInstructionSet(InstructionSet_AVX512CD_VL); - if (resultflags.HasInstructionSet(InstructionSet_AVX512CD_VL) && !resultflags.HasInstructionSet(InstructionSet_AVX512F_VL)) - resultflags.RemoveInstructionSet(InstructionSet_AVX512CD_VL); if (resultflags.HasInstructionSet(InstructionSet_AVX512BW) && !resultflags.HasInstructionSet(InstructionSet_AVX512F)) resultflags.RemoveInstructionSet(InstructionSet_AVX512BW); if (resultflags.HasInstructionSet(InstructionSet_AVX512BW_VL) && !resultflags.HasInstructionSet(InstructionSet_AVX512BW)) resultflags.RemoveInstructionSet(InstructionSet_AVX512BW_VL); if (resultflags.HasInstructionSet(InstructionSet_AVX512BW_VL) && !resultflags.HasInstructionSet(InstructionSet_AVX512F_VL)) resultflags.RemoveInstructionSet(InstructionSet_AVX512BW_VL); + if (resultflags.HasInstructionSet(InstructionSet_AVX512CD) && !resultflags.HasInstructionSet(InstructionSet_AVX512F)) + resultflags.RemoveInstructionSet(InstructionSet_AVX512CD); + if (resultflags.HasInstructionSet(InstructionSet_AVX512CD_VL) && !resultflags.HasInstructionSet(InstructionSet_AVX512CD)) + resultflags.RemoveInstructionSet(InstructionSet_AVX512CD_VL); + if (resultflags.HasInstructionSet(InstructionSet_AVX512CD_VL) && !resultflags.HasInstructionSet(InstructionSet_AVX512F_VL)) + resultflags.RemoveInstructionSet(InstructionSet_AVX512CD_VL); if (resultflags.HasInstructionSet(InstructionSet_AVX512DQ) && !resultflags.HasInstructionSet(InstructionSet_AVX512F)) resultflags.RemoveInstructionSet(InstructionSet_AVX512DQ); if (resultflags.HasInstructionSet(InstructionSet_AVX512DQ_VL) && !resultflags.HasInstructionSet(InstructionSet_AVX512DQ)) diff --git a/src/coreclr/inc/icorjitinfoimpl_generated.h b/src/coreclr/inc/icorjitinfoimpl_generated.h index 3f3e1a750c38c..edb826215ee68 100644 --- a/src/coreclr/inc/icorjitinfoimpl_generated.h +++ b/src/coreclr/inc/icorjitinfoimpl_generated.h @@ -517,7 +517,7 @@ void getSwiftLowering( CORINFO_CLASS_HANDLE structHnd, CORINFO_SWIFT_LOWERING* pLowering) override; -uint32_t getLoongArch64PassStructInRegisterFlags( +FpStructInRegistersInfo getLoongArch64PassFpStructInRegistersInfo( CORINFO_CLASS_HANDLE structHnd) override; FpStructInRegistersInfo getRiscV64PassFpStructInRegistersInfo( diff --git a/src/coreclr/inc/jiteeversionguid.h b/src/coreclr/inc/jiteeversionguid.h index 9830b3a181878..de127b30eaad2 100644 --- a/src/coreclr/inc/jiteeversionguid.h +++ b/src/coreclr/inc/jiteeversionguid.h @@ -43,11 +43,11 @@ typedef const GUID *LPCGUID; #define GUID_DEFINED #endif // !GUID_DEFINED -constexpr GUID JITEEVersionIdentifier = { /* 1907f831-d9c8-4b42-a549-0cdce990d1c6 */ - 0x1907f831, - 0xd9c8, - 0x4b42, - {0xa5, 0x49, 0x0c, 0xdc, 0xe9, 0x90, 0xd1, 0xc6} +constexpr GUID JITEEVersionIdentifier = { /* 03acedb5-e1cc-4fdd-87f4-0693668124d6 */ + 0x03acedb5, + 0xe1cc, + 0x4fdd, + {0x87, 0xf4, 0x06, 0x93, 0x66, 0x81, 0x24, 0xd6} }; ////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/coreclr/jit/ICorJitInfo_names_generated.h b/src/coreclr/jit/ICorJitInfo_names_generated.h index f027a85c22ba3..8f3a4a10f9ff1 100644 --- a/src/coreclr/jit/ICorJitInfo_names_generated.h +++ b/src/coreclr/jit/ICorJitInfo_names_generated.h @@ -129,7 +129,7 @@ DEF_CLR_API(getMethodNameFromMetadata) DEF_CLR_API(getMethodHash) DEF_CLR_API(getSystemVAmd64PassStructInRegisterDescriptor) DEF_CLR_API(getSwiftLowering) -DEF_CLR_API(getLoongArch64PassStructInRegisterFlags) +DEF_CLR_API(getLoongArch64PassFpStructInRegistersInfo) DEF_CLR_API(getRiscV64PassFpStructInRegistersInfo) DEF_CLR_API(getThreadTLSIndex) DEF_CLR_API(getAddrOfCaptureThreadGlobal) diff --git a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp index 19e075c781337..b1384825756c5 100644 --- a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp +++ b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp @@ -1229,12 +1229,12 @@ void WrapICorJitInfo::getSwiftLowering( API_LEAVE(getSwiftLowering); } -uint32_t WrapICorJitInfo::getLoongArch64PassStructInRegisterFlags( +FpStructInRegistersInfo WrapICorJitInfo::getLoongArch64PassFpStructInRegistersInfo( CORINFO_CLASS_HANDLE structHnd) { - API_ENTER(getLoongArch64PassStructInRegisterFlags); - uint32_t temp = wrapHnd->getLoongArch64PassStructInRegisterFlags(structHnd); - API_LEAVE(getLoongArch64PassStructInRegisterFlags); + API_ENTER(getLoongArch64PassFpStructInRegistersInfo); + FpStructInRegistersInfo temp = wrapHnd->getLoongArch64PassFpStructInRegistersInfo(structHnd); + API_LEAVE(getLoongArch64PassFpStructInRegistersInfo); return temp; } diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp index b8bd18c5d3a5a..c03360c8d16b4 100644 --- a/src/coreclr/jit/compiler.cpp +++ b/src/coreclr/jit/compiler.cpp @@ -927,24 +927,7 @@ var_types Compiler::getReturnTypeForStruct(CORINFO_CLASS_HANDLE clsHnd, howToReturnStruct = SPK_ByReference; useType = TYP_UNKNOWN; } -#elif defined(TARGET_LOONGARCH64) - if (structSize <= (TARGET_POINTER_SIZE * 2)) - { - uint32_t floatFieldFlags = info.compCompHnd->getLoongArch64PassStructInRegisterFlags(clsHnd); - - if ((floatFieldFlags & STRUCT_FLOAT_FIELD_ONLY_ONE) != 0) - { - howToReturnStruct = SPK_PrimitiveType; - useType = (structSize > 4) ? TYP_DOUBLE : TYP_FLOAT; - } - else if (floatFieldFlags & (STRUCT_HAS_FLOAT_FIELDS_MASK ^ STRUCT_FLOAT_FIELD_ONLY_ONE)) - { - howToReturnStruct = SPK_ByValue; - useType = TYP_STRUCT; - } - } - -#elif defined(TARGET_RISCV64) +#elif defined(TARGET_RISCV64) | defined(TARGET_LOONGARCH64) if (structSize <= (TARGET_POINTER_SIZE * 2)) { FpStructInRegistersInfo info = GetPassFpStructInRegistersInfo(clsHnd); diff --git a/src/coreclr/jit/targetloongarch64.cpp b/src/coreclr/jit/targetloongarch64.cpp index 3b8ee6e677cbb..d2e8447d0d5f8 100644 --- a/src/coreclr/jit/targetloongarch64.cpp +++ b/src/coreclr/jit/targetloongarch64.cpp @@ -78,14 +78,14 @@ ABIPassingInformation LoongArch64Classifier::Classify(Compiler* comp, { assert(!structLayout->IsBlockLayout()); - uint32_t floatFlags; - CORINFO_CLASS_HANDLE typeHnd = structLayout->GetClassHandle(); + FpStructInRegistersInfo fpInfo; + CORINFO_CLASS_HANDLE typeHnd = structLayout->GetClassHandle(); - floatFlags = comp->info.compCompHnd->getLoongArch64PassStructInRegisterFlags(typeHnd); + fpInfo = comp->GetPassFpStructInRegistersInfo(typeHnd); - if ((floatFlags & STRUCT_HAS_FLOAT_FIELDS_MASK) != 0) + if (fpInfo.flags != UseIntCallConv) { - if ((floatFlags & STRUCT_FLOAT_FIELD_ONLY_ONE) != 0) + if ((fpInfo.flags & FpStruct::OnlyOne) != 0) { assert(passedSize <= TARGET_POINTER_SIZE); @@ -94,29 +94,29 @@ ABIPassingInformation LoongArch64Classifier::Classify(Compiler* comp, argRegTypeInStruct1 = (passedSize == 8) ? TYP_DOUBLE : TYP_FLOAT; } - else if ((floatFlags & STRUCT_FLOAT_FIELD_ONLY_TWO) != 0) + else if ((fpInfo.flags & FpStruct::BothFloat) != 0) { slots = 2; canPassArgInRegisters = m_floatRegs.Count() >= 2; - argRegTypeInStruct1 = (floatFlags & STRUCT_FIRST_FIELD_SIZE_IS8) ? TYP_DOUBLE : TYP_FLOAT; - argRegTypeInStruct2 = (floatFlags & STRUCT_SECOND_FIELD_SIZE_IS8) ? TYP_DOUBLE : TYP_FLOAT; + argRegTypeInStruct1 = (fpInfo.SizeShift1st() == 3) ? TYP_DOUBLE : TYP_FLOAT; + argRegTypeInStruct2 = (fpInfo.SizeShift2nd() == 3) ? TYP_DOUBLE : TYP_FLOAT; } - else if ((floatFlags & STRUCT_FLOAT_FIELD_FIRST) != 0) + else if ((fpInfo.flags & FpStruct::FloatInt) != 0) { slots = 2; canPassArgInRegisters = (m_floatRegs.Count() > 0) && (m_intRegs.Count() > 0); - argRegTypeInStruct1 = (floatFlags & STRUCT_FIRST_FIELD_SIZE_IS8) ? TYP_DOUBLE : TYP_FLOAT; - argRegTypeInStruct2 = (floatFlags & STRUCT_SECOND_FIELD_SIZE_IS8) ? TYP_LONG : TYP_INT; + argRegTypeInStruct1 = (fpInfo.SizeShift1st() == 3) ? TYP_DOUBLE : TYP_FLOAT; + argRegTypeInStruct2 = (fpInfo.SizeShift2nd() == 3) ? TYP_LONG : TYP_INT; } - else if ((floatFlags & STRUCT_FLOAT_FIELD_SECOND) != 0) + else if ((fpInfo.flags & FpStruct::IntFloat) != 0) { slots = 2; canPassArgInRegisters = (m_floatRegs.Count() > 0) && (m_intRegs.Count() > 0); - argRegTypeInStruct1 = (floatFlags & STRUCT_FIRST_FIELD_SIZE_IS8) ? TYP_LONG : TYP_INT; - argRegTypeInStruct2 = (floatFlags & STRUCT_SECOND_FIELD_SIZE_IS8) ? TYP_DOUBLE : TYP_FLOAT; + argRegTypeInStruct1 = (fpInfo.SizeShift1st() == 3) ? TYP_LONG : TYP_INT; + argRegTypeInStruct2 = (fpInfo.SizeShift2nd() == 3) ? TYP_DOUBLE : TYP_FLOAT; } assert((slots == 1) || (slots == 2)); diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index 8ccec69957670..c10d22c04f8fc 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -3447,10 +3447,10 @@ private void getSwiftLowering(CORINFO_CLASS_STRUCT_* structHnd, ref CORINFO_SWIF lowering = SwiftPhysicalLowering.LowerTypeForSwiftSignature(HandleToObject(structHnd)); } - private uint getLoongArch64PassStructInRegisterFlags(CORINFO_CLASS_STRUCT_* cls) + private FpStructInRegistersInfo getLoongArch64PassFpStructInRegistersInfo(CORINFO_CLASS_STRUCT_* cls) { TypeDesc typeDesc = HandleToObject(cls); - return LoongArch64PassStructInRegister.GetLoongArch64PassStructInRegisterFlags(typeDesc); + return LoongArch64PassStructInRegister.GetLoongArch64PassFpStructInRegistersInfo(typeDesc); } private FpStructInRegistersInfo getRiscV64PassFpStructInRegistersInfo(CORINFO_CLASS_STRUCT_* cls) diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs index 71cd542838a59..2f17c4705b493 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs @@ -1859,12 +1859,12 @@ private static void _getSwiftLowering(IntPtr thisHandle, IntPtr* ppException, CO } [UnmanagedCallersOnly] - private static uint _getLoongArch64PassStructInRegisterFlags(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* structHnd) + private static FpStructInRegistersInfo _getLoongArch64PassFpStructInRegistersInfo(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* structHnd) { var _this = GetThis(thisHandle); try { - return _this.getLoongArch64PassStructInRegisterFlags(structHnd); + return _this.getLoongArch64PassFpStructInRegistersInfo(structHnd); } catch (Exception ex) { @@ -2736,7 +2736,7 @@ private static IntPtr GetUnmanagedCallbacks() callbacks[122] = (delegate* unmanaged)&_getMethodHash; callbacks[123] = (delegate* unmanaged)&_getSystemVAmd64PassStructInRegisterDescriptor; callbacks[124] = (delegate* unmanaged)&_getSwiftLowering; - callbacks[125] = (delegate* unmanaged)&_getLoongArch64PassStructInRegisterFlags; + callbacks[125] = (delegate* unmanaged)&_getLoongArch64PassFpStructInRegistersInfo; callbacks[126] = (delegate* unmanaged)&_getRiscV64PassFpStructInRegistersInfo; callbacks[127] = (delegate* unmanaged)&_getThreadTLSIndex; callbacks[128] = (delegate* unmanaged)&_getAddrOfCaptureThreadGlobal; diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoInstructionSet.cs b/src/coreclr/tools/Common/JitInterface/CorInfoInstructionSet.cs index 9971accb07818..42807bfcec1d9 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoInstructionSet.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoInstructionSet.cs @@ -746,18 +746,18 @@ public static InstructionSetFlags ExpandInstructionSetByImplicationHelper(Target resultflags.AddInstructionSet(InstructionSet.X64_EVEX); if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512F_VL)) resultflags.AddInstructionSet(InstructionSet.X64_AVX512F); - if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512CD)) - resultflags.AddInstructionSet(InstructionSet.X64_AVX512F); - if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512CD_VL)) - resultflags.AddInstructionSet(InstructionSet.X64_AVX512CD); - if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512CD_VL)) - resultflags.AddInstructionSet(InstructionSet.X64_AVX512F_VL); if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512BW)) resultflags.AddInstructionSet(InstructionSet.X64_AVX512F); if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512BW_VL)) resultflags.AddInstructionSet(InstructionSet.X64_AVX512BW); if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512BW_VL)) resultflags.AddInstructionSet(InstructionSet.X64_AVX512F_VL); + if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512CD)) + resultflags.AddInstructionSet(InstructionSet.X64_AVX512F); + if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512CD_VL)) + resultflags.AddInstructionSet(InstructionSet.X64_AVX512CD); + if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512CD_VL)) + resultflags.AddInstructionSet(InstructionSet.X64_AVX512F_VL); if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512DQ)) resultflags.AddInstructionSet(InstructionSet.X64_AVX512F); if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512DQ_VL)) @@ -853,18 +853,18 @@ public static InstructionSetFlags ExpandInstructionSetByImplicationHelper(Target resultflags.AddInstructionSet(InstructionSet.X86_EVEX); if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512F_VL)) resultflags.AddInstructionSet(InstructionSet.X86_AVX512F); - if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512CD)) - resultflags.AddInstructionSet(InstructionSet.X86_AVX512F); - if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512CD_VL)) - resultflags.AddInstructionSet(InstructionSet.X86_AVX512CD); - if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512CD_VL)) - resultflags.AddInstructionSet(InstructionSet.X86_AVX512F_VL); if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512BW)) resultflags.AddInstructionSet(InstructionSet.X86_AVX512F); if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512BW_VL)) resultflags.AddInstructionSet(InstructionSet.X86_AVX512BW); if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512BW_VL)) resultflags.AddInstructionSet(InstructionSet.X86_AVX512F_VL); + if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512CD)) + resultflags.AddInstructionSet(InstructionSet.X86_AVX512F); + if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512CD_VL)) + resultflags.AddInstructionSet(InstructionSet.X86_AVX512CD); + if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512CD_VL)) + resultflags.AddInstructionSet(InstructionSet.X86_AVX512F_VL); if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512DQ)) resultflags.AddInstructionSet(InstructionSet.X86_AVX512F); if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512DQ_VL)) @@ -1087,18 +1087,18 @@ private static InstructionSetFlags ExpandInstructionSetByReverseImplicationHelpe resultflags.AddInstructionSet(InstructionSet.X64_AVX512F); if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512F)) resultflags.AddInstructionSet(InstructionSet.X64_AVX512F_VL); - if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512F)) - resultflags.AddInstructionSet(InstructionSet.X64_AVX512CD); - if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512CD)) - resultflags.AddInstructionSet(InstructionSet.X64_AVX512CD_VL); - if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512F_VL)) - resultflags.AddInstructionSet(InstructionSet.X64_AVX512CD_VL); if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512F)) resultflags.AddInstructionSet(InstructionSet.X64_AVX512BW); if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512BW)) resultflags.AddInstructionSet(InstructionSet.X64_AVX512BW_VL); if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512F_VL)) resultflags.AddInstructionSet(InstructionSet.X64_AVX512BW_VL); + if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512F)) + resultflags.AddInstructionSet(InstructionSet.X64_AVX512CD); + if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512CD)) + resultflags.AddInstructionSet(InstructionSet.X64_AVX512CD_VL); + if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512F_VL)) + resultflags.AddInstructionSet(InstructionSet.X64_AVX512CD_VL); if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512F)) resultflags.AddInstructionSet(InstructionSet.X64_AVX512DQ); if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512DQ)) @@ -1194,18 +1194,18 @@ private static InstructionSetFlags ExpandInstructionSetByReverseImplicationHelpe resultflags.AddInstructionSet(InstructionSet.X86_AVX512F); if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512F)) resultflags.AddInstructionSet(InstructionSet.X86_AVX512F_VL); - if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512F)) - resultflags.AddInstructionSet(InstructionSet.X86_AVX512CD); - if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512CD)) - resultflags.AddInstructionSet(InstructionSet.X86_AVX512CD_VL); - if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512F_VL)) - resultflags.AddInstructionSet(InstructionSet.X86_AVX512CD_VL); if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512F)) resultflags.AddInstructionSet(InstructionSet.X86_AVX512BW); if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512BW)) resultflags.AddInstructionSet(InstructionSet.X86_AVX512BW_VL); if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512F_VL)) resultflags.AddInstructionSet(InstructionSet.X86_AVX512BW_VL); + if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512F)) + resultflags.AddInstructionSet(InstructionSet.X86_AVX512CD); + if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512CD)) + resultflags.AddInstructionSet(InstructionSet.X86_AVX512CD_VL); + if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512F_VL)) + resultflags.AddInstructionSet(InstructionSet.X86_AVX512CD_VL); if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512F)) resultflags.AddInstructionSet(InstructionSet.X86_AVX512DQ); if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512DQ)) diff --git a/src/coreclr/tools/Common/JitInterface/LoongArch64PassStructInRegister.cs b/src/coreclr/tools/Common/JitInterface/LoongArch64PassStructInRegister.cs index 250ea428c44d9..5d83392312a80 100644 --- a/src/coreclr/tools/Common/JitInterface/LoongArch64PassStructInRegister.cs +++ b/src/coreclr/tools/Common/JitInterface/LoongArch64PassStructInRegister.cs @@ -5,7 +5,7 @@ using System.Diagnostics; using ILCompiler; using Internal.TypeSystem; -using static Internal.JitInterface.StructFloatFieldInfoFlags; +using static Internal.JitInterface.FpStruct; namespace Internal.JitInterface { @@ -15,30 +15,71 @@ private const int ENREGISTERED_PARAMTYPE_MAXSIZE = 16, TARGET_POINTER_SIZE = 8; - private static bool HandleInlineArray(int elementTypeIndex, int nElements, Span types, ref int typeIndex) + private static void SetFpStructInRegistersInfoField(ref FpStructInRegistersInfo info, int index, + bool isFloating, FpStruct_IntKind intKind, uint size, uint offset) + { + Debug.Assert(index < 2); + if (isFloating) + { + Debug.Assert(size == sizeof(float) || size == sizeof(double)); + Debug.Assert(intKind == FpStruct_IntKind.Integer); + Debug.Assert((int)FpStruct_IntKind.Integer == 0, + "IntKind for floating fields should not clobber IntKind for int fields"); + } + + Debug.Assert(size >= 1 && size <= 8); + Debug.Assert((size & (size - 1)) == 0, "size needs to be a power of 2"); + const int sizeShiftLUT = (0 << (1*2)) | (1 << (2*2)) | (2 << (4*2)) | (3 << (8*2)); + int sizeShift = (sizeShiftLUT >> ((int)size * 2)) & 0b11; + + // Use FloatInt and IntFloat as marker flags for 1st and 2nd field respectively being floating. + // Fix to real flags (with OnlyOne and BothFloat) after flattening is complete. + Debug.Assert((int)PosIntFloat == (int)PosFloatInt + 1, "FloatInt and IntFloat need to be adjacent"); + Debug.Assert((int)PosSizeShift2nd == (int)PosSizeShift1st + 2, "SizeShift1st and 2nd need to be adjacent"); + int floatFlag = Convert.ToInt32(isFloating) << ((int)PosFloatInt + index); + int sizeShiftMask = sizeShift << ((int)PosSizeShift1st + 2 * index); + + info.flags |= (FpStruct)(floatFlag | sizeShiftMask | ((int)intKind << (int)PosIntFieldKind)); + (index == 0 ? ref info.offset1st : ref info.offset2nd) = offset; + } + + private static bool HandleInlineArray(int elementTypeIndex, int nElements, ref FpStructInRegistersInfo info, ref int typeIndex) { int nFlattenedFieldsPerElement = typeIndex - elementTypeIndex; if (nFlattenedFieldsPerElement == 0) - return true; + { + Debug.Assert(nElements == 1, "HasImpliedRepeatedFields must have returned a false positive"); + return true; // ignoring empty struct + } Debug.Assert(nFlattenedFieldsPerElement == 1 || nFlattenedFieldsPerElement == 2); if (nElements > 2) - return false; + return false; // array has too many elements if (nElements == 2) { if (typeIndex + nFlattenedFieldsPerElement > 2) - return false; + return false; // array has too many fields per element Debug.Assert(elementTypeIndex == 0); Debug.Assert(typeIndex == 1); - types[typeIndex++] = types[elementTypeIndex]; // duplicate the array element type + + // Duplicate the array element info + Debug.Assert((int)FpStruct.IntFloat == ((int)FpStruct.FloatInt << 1), + "FloatInt and IntFloat need to be adjacent"); + Debug.Assert((int)FpStruct.SizeShift2ndMask == ((int)FpStruct.SizeShift1stMask << 2), + "SizeShift1st and 2nd need to be adjacent"); + // Take the 1st field info and shift up to the 2nd field's positions + int floatFlag = (int)(info.flags & FpStruct.FloatInt) << 1; + int sizeShiftMask = (int)(info.flags & FpStruct.SizeShift1stMask) << 2; + info.flags |= (FpStruct)(floatFlag | sizeShiftMask); // merge with 1st field + info.offset2nd = info.offset1st + info.Size1st(); // bump up the field offset } return true; } - private static bool FlattenFieldTypes(TypeDesc td, Span types, ref int typeIndex) + private static bool FlattenFields(TypeDesc td, uint offset, ref FpStructInRegistersInfo info, ref int typeIndex) { IEnumerable fields = td.GetFields(); int nFields = 0; @@ -51,7 +92,7 @@ private static bool FlattenFieldTypes(TypeDesc td, Span field.Offset.AsInt) - return false; // overlapping fields + return false; // fields overlap, treat as union prevField = field; @@ -59,22 +100,32 @@ private static bool FlattenFieldTypes(TypeDesc td, Span= 2) - return false; - - StructFloatFieldInfoFlags type = - (category is TypeFlags.Single or TypeFlags.Double ? STRUCT_FLOAT_FIELD_FIRST : (StructFloatFieldInfoFlags)0) | - (field.FieldType.GetElementSize().AsInt == TARGET_POINTER_SIZE ? STRUCT_FIRST_FIELD_SIZE_IS8 : (StructFloatFieldInfoFlags)0); - types[typeIndex++] = type; + return false; // too many fields + + bool isFloating = category is TypeFlags.Single or TypeFlags.Double; + bool isGcRef = category is + TypeFlags.Class or + TypeFlags.Interface or + TypeFlags.Array or + TypeFlags.SzArray; + + FpStruct_IntKind intKind = + isGcRef ? FpStruct_IntKind.GcRef : + (category is TypeFlags.ByRef) ? FpStruct_IntKind.GcByRef : + FpStruct_IntKind.Integer; + + SetFpStructInRegistersInfoField(ref info, typeIndex++, + isFloating, intKind, (uint)field.FieldType.GetElementSize().AsInt, offset + (uint)field.Offset.AsInt); } else { - return false; + return false; // field is too big } } @@ -82,46 +133,69 @@ private static bool FlattenFieldTypes(TypeDesc td, Span 0 == (val & (alignment - 1)); + + public static FpStructInRegistersInfo GetLoongArch64PassFpStructInRegistersInfo(TypeDesc td) { if (td.GetElementSize().AsInt > ENREGISTERED_PARAMTYPE_MAXSIZE) - return (uint)STRUCT_NO_FLOAT_FIELD; + return new FpStructInRegistersInfo{}; - Span types = stackalloc StructFloatFieldInfoFlags[] { - STRUCT_NO_FLOAT_FIELD, STRUCT_NO_FLOAT_FIELD - }; + FpStructInRegistersInfo info = new FpStructInRegistersInfo{}; int nFields = 0; - if (!FlattenFieldTypes(td, types, ref nFields) || nFields == 0) - return (uint)STRUCT_NO_FLOAT_FIELD; + if (!FlattenFields(td, 0, ref info, ref nFields)) + return new FpStructInRegistersInfo{}; - Debug.Assert(nFields == 1 || nFields == 2); + if ((info.flags & (FloatInt | IntFloat)) == 0) + return new FpStructInRegistersInfo{}; // struct has no floating fields - Debug.Assert((uint)(STRUCT_FLOAT_FIELD_SECOND | STRUCT_SECOND_FIELD_SIZE_IS8) - == (uint)(STRUCT_FLOAT_FIELD_FIRST | STRUCT_FIRST_FIELD_SIZE_IS8) << 1, - "SECOND flags need to be FIRST shifted by 1"); - StructFloatFieldInfoFlags flags = types[0] | (StructFloatFieldInfoFlags)((uint)types[1] << 1); - - const StructFloatFieldInfoFlags bothFloat = STRUCT_FLOAT_FIELD_FIRST | STRUCT_FLOAT_FIELD_SECOND; - if ((flags & bothFloat) == 0) - return (uint)STRUCT_NO_FLOAT_FIELD; + Debug.Assert(nFields == 1 || nFields == 2); - if ((flags & bothFloat) == bothFloat) + if ((info.flags & (FloatInt | IntFloat)) == (FloatInt | IntFloat)) { Debug.Assert(nFields == 2); - flags ^= (bothFloat | STRUCT_FLOAT_FIELD_ONLY_TWO); // replace bothFloat with ONLY_TWO + info.flags ^= (FloatInt | IntFloat | BothFloat); // replace (FloatInt | IntFloat) with BothFloat } else if (nFields == 1) { - Debug.Assert((flags & STRUCT_FLOAT_FIELD_FIRST) != 0); - flags ^= (STRUCT_FLOAT_FIELD_FIRST | STRUCT_FLOAT_FIELD_ONLY_ONE); // replace FIRST with ONLY_ONE + Debug.Assert((info.flags & FloatInt) != 0); + Debug.Assert((info.flags & (IntFloat | SizeShift2ndMask)) == 0); + Debug.Assert(info.offset2nd == 0); + info.flags ^= (FloatInt | OnlyOne); // replace FloatInt with OnlyOne } - return (uint)flags; + Debug.Assert(nFields == ((info.flags & OnlyOne) != 0 ? 1 : 2)); + FpStruct floatFlags = info.flags & (OnlyOne | BothFloat | FloatInt | IntFloat); + Debug.Assert(floatFlags != 0); + Debug.Assert(((uint)floatFlags & ((uint)floatFlags - 1)) == 0, + "there can be only one of (OnlyOne | BothFloat | FloatInt | IntFloat)"); + if (nFields == 2) + { + uint end1st = info.offset1st + info.Size1st(); + uint end2nd = info.offset2nd + info.Size2nd(); + Debug.Assert(end1st <= info.offset2nd || end2nd <= info.offset1st, "fields must not overlap"); + } + Debug.Assert(info.offset1st + info.Size1st() <= td.GetElementSize().AsInt); + Debug.Assert(info.offset2nd + info.Size2nd() <= td.GetElementSize().AsInt); + + FpStruct_IntKind intKind = info.IntFieldKind(); + if (intKind != FpStruct_IntKind.Integer) + { + Debug.Assert((info.flags & (FloatInt | IntFloat)) != 0); + + Debug.Assert(intKind == FpStruct_IntKind.GcRef || intKind == FpStruct_IntKind.GcByRef); + Debug.Assert((info.flags & IntFloat) != 0 + ? ((info.SizeShift1st() == 3) && IsAligned(info.offset1st, TARGET_POINTER_SIZE)) + : ((info.SizeShift2nd() == 3) && IsAligned(info.offset2nd, TARGET_POINTER_SIZE))); + } + if ((info.flags & (OnlyOne | BothFloat)) != 0) + Debug.Assert(intKind == FpStruct_IntKind.Integer); + + return info; } } } diff --git a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt index e0d13ac19a8ef..feff1d07736b9 100644 --- a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt +++ b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt @@ -289,7 +289,7 @@ FUNCTIONS unsigned getMethodHash(CORINFO_METHOD_HANDLE ftn); bool getSystemVAmd64PassStructInRegisterDescriptor(CORINFO_CLASS_HANDLE structHnd, SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structPassInRegDescPtr); void getSwiftLowering(CORINFO_CLASS_HANDLE structHnd, CORINFO_SWIFT_LOWERING* pLowering); - uint32_t getLoongArch64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE structHnd); + FpStructInRegistersInfo getLoongArch64PassFpStructInRegistersInfo(CORINFO_CLASS_HANDLE structHnd); FpStructInRegistersInfo getRiscV64PassFpStructInRegistersInfo(CORINFO_CLASS_HANDLE structHnd); uint32_t getThreadTLSIndex(void **ppIndirection); int32_t * getAddrOfCaptureThreadGlobal(void **ppIndirection); diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ArgIterator.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ArgIterator.cs index b1aa54a9a7268..584866dd4ce4b 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ArgIterator.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ArgIterator.cs @@ -234,7 +234,7 @@ internal struct ArgLocDesc public int m_byteStackSize; // Stack size in bytes public uint m_floatFlags; // struct with two-fields can be passed by registers. - public FpStructInRegistersInfo m_structFields; // RISC-V - Struct field info when using floating-point register(s) + public FpStructInRegistersInfo m_structFields; // RISC-V and LoongArch - Struct field info when using floating-point register(s) // Initialize to represent a non-placed argument (no register or stack slots referenced). public void Init() @@ -1331,18 +1331,14 @@ public int GetNextOffset() case TargetArchitecture.LoongArch64: { int cFPRegs = 0; - uint floatFieldFlags = (uint)StructFloatFieldInfoFlags.STRUCT_NO_FLOAT_FIELD; + FpStructInRegistersInfo info = new FpStructInRegistersInfo{}; _hasArgLocDescForStructInRegs = false; switch (argType) { case CorElementType.ELEMENT_TYPE_R4: - // 32-bit floating point argument. - cFPRegs = 1; - break; - case CorElementType.ELEMENT_TYPE_R8: - // 64-bit floating point argument. + // Floating point argument cFPRegs = 1; break; @@ -1355,14 +1351,10 @@ public int GetNextOffset() } else { - floatFieldFlags = LoongArch64PassStructInRegister.GetLoongArch64PassStructInRegisterFlags(_argTypeHandle.GetRuntimeTypeHandle()); - if ((floatFieldFlags & (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_ONLY_TWO) != 0) - { - cFPRegs = 2; - } - else if ((floatFieldFlags & (uint)StructFloatFieldInfoFlags.STRUCT_HAS_FLOAT_FIELDS_MASK) != 0) + info = LoongArch64PassStructInRegister.GetLoongArch64PassFpStructInRegistersInfo(_argTypeHandle.GetRuntimeTypeHandle()); + if (info.flags != FpStruct.UseIntCallConv) { - cFPRegs = 1; + cFPRegs = ((info.flags & FpStruct.BothFloat) != 0) ? 2 : 1; } } @@ -1378,10 +1370,10 @@ public int GetNextOffset() if (cFPRegs > 0 && !IsVarArg) { - if (isValueType && ((floatFieldFlags & (uint)StructFloatFieldInfoFlags.STRUCT_HAS_ONE_FLOAT_MASK) != 0)) + if ((info.flags & (FpStruct.FloatInt | FpStruct.IntFloat)) != 0) { Debug.Assert(cFPRegs == 1); - if ((_loongarch64IdxFPReg < 8) && (_loongarch64IdxGenReg < 8)) + if ((_loongarch64IdxFPReg < _transitionBlock.NumArgumentRegisters) && (_loongarch64IdxGenReg < _transitionBlock.NumArgumentRegisters)) { _argLocDescForStructInRegs = new ArgLocDesc(); _argLocDescForStructInRegs.m_idxFloatReg = _loongarch64IdxFPReg; @@ -1391,16 +1383,16 @@ public int GetNextOffset() _argLocDescForStructInRegs.m_cGenReg = 1; _hasArgLocDescForStructInRegs = true; - _argLocDescForStructInRegs.m_floatFlags = floatFieldFlags; + _argLocDescForStructInRegs.m_structFields = info; int argOfsInner = 0; - if ((floatFieldFlags & (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_SECOND) != 0) + if ((info.flags & FpStruct.IntFloat) != 0) { - argOfsInner = _transitionBlock.OffsetOfArgumentRegisters + _loongarch64IdxGenReg * 8; + argOfsInner = _transitionBlock.OffsetOfArgumentRegisters + _loongarch64IdxGenReg * _transitionBlock.PointerSize; } else { - argOfsInner = _transitionBlock.OffsetOfFloatArgumentRegisters + _loongarch64IdxFPReg * 8; + argOfsInner = _transitionBlock.OffsetOfFloatArgumentRegisters + _loongarch64IdxFPReg * _transitionBlock.FloatRegisterSize; } _loongarch64IdxFPReg++; @@ -1408,11 +1400,14 @@ public int GetNextOffset() return argOfsInner; } } - else if (cFPRegs + _loongarch64IdxFPReg <= 8) + else if (cFPRegs + _loongarch64IdxFPReg <= _transitionBlock.NumArgumentRegisters) { // Each floating point register in the argument area is 8 bytes. - int argOfsInner = _transitionBlock.OffsetOfFloatArgumentRegisters + _loongarch64IdxFPReg * 8; - if (floatFieldFlags == (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_ONLY_TWO) + int argOfsInner = _transitionBlock.OffsetOfFloatArgumentRegisters + _loongarch64IdxFPReg * _transitionBlock.FloatRegisterSize; + const FpStruct twoFloats = FpStruct.BothFloat + | (FpStruct)(2 << (int)FpStruct.PosSizeShift1st) + | (FpStruct)(2 << (int)FpStruct.PosSizeShift2nd); + if (info.flags == twoFloats) { // struct with two single-float fields. _argLocDescForStructInRegs = new ArgLocDesc(); @@ -1422,7 +1417,7 @@ public int GetNextOffset() Debug.Assert(argSize == 8); _hasArgLocDescForStructInRegs = true; - _argLocDescForStructInRegs.m_floatFlags = (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_ONLY_TWO; + _argLocDescForStructInRegs.m_structFields = info; } _loongarch64IdxFPReg += cFPRegs; return argOfsInner; @@ -1533,7 +1528,7 @@ public int GetNextOffset() else if (cFPRegs + _riscv64IdxFPReg <= _transitionBlock.NumArgumentRegisters) { // Each floating point register in the argument area is 8 bytes. - int argOfsInner = _transitionBlock.OffsetOfFloatArgumentRegisters + _riscv64IdxFPReg * 8; + int argOfsInner = _transitionBlock.OffsetOfFloatArgumentRegisters + _riscv64IdxFPReg * _transitionBlock.FloatRegisterSize; const FpStruct twoFloats = FpStruct.BothFloat | (FpStruct)(2 << (int)FpStruct.PosSizeShift1st) | (FpStruct)(2 << (int)FpStruct.PosSizeShift2nd); diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/TransitionBlock.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/TransitionBlock.cs index 2939e2cde5640..5092f59dd6bf1 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/TransitionBlock.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/TransitionBlock.cs @@ -397,7 +397,7 @@ public void ComputeReturnValueTreatment(CorElementType type, TypeHandle thRetTyp if (size <= EnregisteredReturnTypeIntegerMaxSize) { if (IsLoongArch64) - fpReturnSize = LoongArch64PassStructInRegister.GetLoongArch64PassStructInRegisterFlags(thRetType.GetRuntimeTypeHandle()) & 0xff; + fpReturnSize = (uint)LoongArch64PassStructInRegister.GetLoongArch64PassFpStructInRegistersInfo(thRetType.GetRuntimeTypeHandle()).flags; else if (IsRiscV64) fpReturnSize = (uint)RiscV64PassFpStructInRegisters.GetRiscV64PassFpStructInRegistersInfo(thRetType.GetRuntimeTypeHandle()).flags; break; diff --git a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h index c61ec8e0c0cfb..8419074d79b5b 100644 --- a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h +++ b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h @@ -136,7 +136,7 @@ struct JitInterfaceCallbacks unsigned (* getMethodHash)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_METHOD_HANDLE ftn); bool (* getSystemVAmd64PassStructInRegisterDescriptor)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE structHnd, SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structPassInRegDescPtr); void (* getSwiftLowering)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE structHnd, CORINFO_SWIFT_LOWERING* pLowering); - uint32_t (* getLoongArch64PassStructInRegisterFlags)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE structHnd); + FpStructInRegistersInfo (* getLoongArch64PassFpStructInRegistersInfo)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE structHnd); FpStructInRegistersInfo (* getRiscV64PassFpStructInRegistersInfo)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE structHnd); uint32_t (* getThreadTLSIndex)(void * thisHandle, CorInfoExceptionClass** ppException, void** ppIndirection); int32_t* (* getAddrOfCaptureThreadGlobal)(void * thisHandle, CorInfoExceptionClass** ppException, void** ppIndirection); @@ -1407,11 +1407,11 @@ class JitInterfaceWrapper : public ICorJitInfo if (pException != nullptr) throw pException; } - virtual uint32_t getLoongArch64PassStructInRegisterFlags( + virtual FpStructInRegistersInfo getLoongArch64PassFpStructInRegistersInfo( CORINFO_CLASS_HANDLE structHnd) { CorInfoExceptionClass* pException = nullptr; - uint32_t temp = _callbacks->getLoongArch64PassStructInRegisterFlags(_thisHandle, &pException, structHnd); + FpStructInRegistersInfo temp = _callbacks->getLoongArch64PassFpStructInRegistersInfo(_thisHandle, &pException, structHnd); if (pException != nullptr) throw pException; return temp; } diff --git a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h index b180f48ffcb0a..c7433eaebfea2 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h @@ -127,7 +127,7 @@ LWM(GetSharedCCtorHelper, DWORDLONG, DWORD) LWM(GetStringConfigValue, DWORD, DWORD) LWM(GetSystemVAmd64PassStructInRegisterDescriptor, DWORDLONG, Agnostic_GetSystemVAmd64PassStructInRegisterDescriptor) LWM(GetSwiftLowering, DWORDLONG, Agnostic_GetSwiftLowering) -LWM(GetLoongArch64PassStructInRegisterFlags, DWORDLONG, DWORD) +LWM(GetLoongArch64PassFpStructInRegistersInfo, DWORDLONG, FpStructInRegistersInfo) LWM(GetRiscV64PassFpStructInRegistersInfo, DWORDLONG, FpStructInRegistersInfo) LWM(GetTailCallHelpers, Agnostic_GetTailCallHelpers, Agnostic_CORINFO_TAILCALL_HELPERS) LWM(UpdateEntryPointForTailCall, Agnostic_CORINFO_CONST_LOOKUP, Agnostic_CORINFO_CONST_LOOKUP) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp index d0e8ac4d35d52..2f9ddb2a6070d 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp @@ -6335,28 +6335,31 @@ void MethodContext::repGetSwiftLowering(CORINFO_CLASS_HANDLE structHnd, CORINFO_ } } -void MethodContext::recGetLoongArch64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE structHnd, DWORD value) +void MethodContext::recGetLoongArch64PassFpStructInRegistersInfo(CORINFO_CLASS_HANDLE structHnd, FpStructInRegistersInfo value) { - if (GetLoongArch64PassStructInRegisterFlags == nullptr) - GetLoongArch64PassStructInRegisterFlags = new LightWeightMap(); + if (GetLoongArch64PassFpStructInRegistersInfo == nullptr) + GetLoongArch64PassFpStructInRegistersInfo = new LightWeightMap(); DWORDLONG key = CastHandle(structHnd); - GetLoongArch64PassStructInRegisterFlags->Add(key, value); - DEBUG_REC(dmpGetLoongArch64PassStructInRegisterFlags(key, value)); + GetLoongArch64PassFpStructInRegistersInfo->Add(key, value); + DEBUG_REC(dmpGetLoongArch64PassFpStructInRegistersInfo(key, value)); } -void MethodContext::dmpGetLoongArch64PassStructInRegisterFlags(DWORDLONG key, DWORD value) +void MethodContext::dmpGetLoongArch64PassFpStructInRegistersInfo(DWORDLONG key, FpStructInRegistersInfo value) { - printf("GetLoongArch64PassStructInRegisterFlags key %016" PRIX64 " value-%08X", key, value); + printf("GetLoongArch64PassFpStructInRegistersInfo key %016" PRIX64 " value-%#03x-" + "{%s, sizes={%u, %u}, offsets={%u, %u}, IntFieldKind=%s}\n", + key, value.flags, + value.FlagName(), value.Size1st(), value.Size2nd(), value.offset1st, value.offset2nd, value.IntFieldKindName()); } -DWORD MethodContext::repGetLoongArch64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE structHnd) +FpStructInRegistersInfo MethodContext::repGetLoongArch64PassFpStructInRegistersInfo(CORINFO_CLASS_HANDLE structHnd) { DWORDLONG key = CastHandle(structHnd); - DWORD value = LookupByKeyOrMissNoMessage(GetLoongArch64PassStructInRegisterFlags, key); - DEBUG_REP(dmpGetLoongArch64PassStructInRegisterFlags(key, value)); + FpStructInRegistersInfo value = LookupByKeyOrMissNoMessage(GetLoongArch64PassFpStructInRegistersInfo, key); + DEBUG_REP(dmpGetLoongArch64PassFpStructInRegistersInfo(key, value)); return value; } diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h index 25f64095adeb4..faf7f8b2d7a9e 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h @@ -779,13 +779,9 @@ class MethodContext void dmpGetSwiftLowering(DWORDLONG key, const Agnostic_GetSwiftLowering& value); void repGetSwiftLowering(CORINFO_CLASS_HANDLE structHnd, CORINFO_SWIFT_LOWERING* pLowering); - void recGetLoongArch64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE structHnd, DWORD value); - void dmpGetLoongArch64PassStructInRegisterFlags(DWORDLONG key, DWORD value); - DWORD repGetLoongArch64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE structHnd); - - void recGetRISCV64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE structHnd, DWORD value); - void dmpGetRISCV64PassStructInRegisterFlags(DWORDLONG key, DWORD value); - DWORD repGetRISCV64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE structHnd); + void recGetLoongArch64PassFpStructInRegistersInfo(CORINFO_CLASS_HANDLE structHnd, FpStructInRegistersInfo value); + void dmpGetLoongArch64PassFpStructInRegistersInfo(DWORDLONG key, FpStructInRegistersInfo value); + FpStructInRegistersInfo repGetLoongArch64PassFpStructInRegistersInfo(CORINFO_CLASS_HANDLE structHnd); void recGetRiscV64PassFpStructInRegistersInfo(CORINFO_CLASS_HANDLE structHnd, FpStructInRegistersInfo value); void dmpGetRiscV64PassFpStructInRegistersInfo(DWORDLONG key, FpStructInRegistersInfo value); @@ -1158,7 +1154,7 @@ enum mcPackets Packet_GetAssemblyName = 191, Packet_IsIntrinsic = 192, Packet_UpdateEntryPointForTailCall = 193, - Packet_GetLoongArch64PassStructInRegisterFlags = 194, + //Packet_GetLoongArch64PassStructInRegisterFlags = 194, Packet_GetExactClasses = 195, Packet_GetRuntimeTypePointer = 196, Packet_PrintObjectDescription = 197, @@ -1174,7 +1170,7 @@ enum mcPackets Packet_GetThreadLocalFieldInfo = 207, Packet_GetThreadLocalStaticBlocksInfo = 208, Packet_GetThreadLocalStaticInfo_NativeAOT = 209, - // Packet_GetRISCV64PassStructInRegisterFlags = 210, + //Packet_GetRISCV64PassStructInRegisterFlags = 210, Packet_GetObjectContent = 211, Packet_GetTypeLayout = 212, Packet_HaveSameMethodDefinition = 213, @@ -1186,6 +1182,7 @@ enum mcPackets Packet_GetClassThreadStaticDynamicInfo = 219, Packet_IsGenericType = 220, Packet_GetRiscV64PassFpStructInRegistersInfo = 221, + Packet_GetLoongArch64PassFpStructInRegistersInfo = 222, }; void SetDebugDumpVariables(); diff --git a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp index 9cc74d8946a94..803ebfbd9109d 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp @@ -1410,11 +1410,11 @@ void interceptor_ICJI::getSwiftLowering(CORINFO_CLASS_HANDLE structHnd, CORINFO_ mc->recGetSwiftLowering(structHnd, pLowering); } -uint32_t interceptor_ICJI::getLoongArch64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE structHnd) +FpStructInRegistersInfo interceptor_ICJI::getLoongArch64PassFpStructInRegistersInfo(CORINFO_CLASS_HANDLE structHnd) { - mc->cr->AddCall("getLoongArch64PassStructInRegisterFlags"); - uint32_t temp = original_ICorJitInfo->getLoongArch64PassStructInRegisterFlags(structHnd); - mc->recGetLoongArch64PassStructInRegisterFlags(structHnd, temp); + mc->cr->AddCall("getLoongArch64PassFpStructInRegistersInfo"); + FpStructInRegistersInfo temp = original_ICorJitInfo->getLoongArch64PassFpStructInRegistersInfo(structHnd); + mc->recGetLoongArch64PassFpStructInRegistersInfo(structHnd, temp); return temp; } diff --git a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp index 400b8a4cdbc8d..9a3054244109b 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp @@ -1008,11 +1008,11 @@ void interceptor_ICJI::getSwiftLowering( original_ICorJitInfo->getSwiftLowering(structHnd, pLowering); } -uint32_t interceptor_ICJI::getLoongArch64PassStructInRegisterFlags( +FpStructInRegistersInfo interceptor_ICJI::getLoongArch64PassFpStructInRegistersInfo( CORINFO_CLASS_HANDLE structHnd) { - mcs->AddCall("getLoongArch64PassStructInRegisterFlags"); - return original_ICorJitInfo->getLoongArch64PassStructInRegisterFlags(structHnd); + mcs->AddCall("getLoongArch64PassFpStructInRegistersInfo"); + return original_ICorJitInfo->getLoongArch64PassFpStructInRegistersInfo(structHnd); } FpStructInRegistersInfo interceptor_ICJI::getRiscV64PassFpStructInRegistersInfo( diff --git a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp index b9678e5170e09..58077aec069d8 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp @@ -883,10 +883,10 @@ void interceptor_ICJI::getSwiftLowering( original_ICorJitInfo->getSwiftLowering(structHnd, pLowering); } -uint32_t interceptor_ICJI::getLoongArch64PassStructInRegisterFlags( +FpStructInRegistersInfo interceptor_ICJI::getLoongArch64PassFpStructInRegistersInfo( CORINFO_CLASS_HANDLE structHnd) { - return original_ICorJitInfo->getLoongArch64PassStructInRegisterFlags(structHnd); + return original_ICorJitInfo->getLoongArch64PassFpStructInRegistersInfo(structHnd); } FpStructInRegistersInfo interceptor_ICJI::getRiscV64PassFpStructInRegistersInfo( diff --git a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp index ecd7630d293c4..b78a784149415 100644 --- a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp @@ -1251,10 +1251,10 @@ void MyICJI::getSwiftLowering(CORINFO_CLASS_HANDLE structHnd, CORINFO_SWIFT_LOWE jitInstance->mc->repGetSwiftLowering(structHnd, pLowering); } -uint32_t MyICJI::getLoongArch64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE structHnd) +FpStructInRegistersInfo MyICJI::getLoongArch64PassFpStructInRegistersInfo(CORINFO_CLASS_HANDLE structHnd) { - jitInstance->mc->cr->AddCall("getLoongArch64PassStructInRegisterFlags"); - return jitInstance->mc->repGetLoongArch64PassStructInRegisterFlags(structHnd); + jitInstance->mc->cr->AddCall("getLoongArch64PassFpStructInRegistersInfo"); + return jitInstance->mc->repGetLoongArch64PassFpStructInRegistersInfo(structHnd); } FpStructInRegistersInfo MyICJI::getRiscV64PassFpStructInRegistersInfo(CORINFO_CLASS_HANDLE structHnd) diff --git a/src/coreclr/vm/callingconvention.h b/src/coreclr/vm/callingconvention.h index eb89f6cef4970..54fbea3dd66eb 100644 --- a/src/coreclr/vm/callingconvention.h +++ b/src/coreclr/vm/callingconvention.h @@ -1670,18 +1670,14 @@ int ArgIteratorTemplate::GetNextOffset() #elif defined(TARGET_LOONGARCH64) int cFPRegs = 0; - int flags = 0; + FpStructInRegistersInfo info = {}; switch (argType) { case ELEMENT_TYPE_R4: - // 32-bit floating point argument. - cFPRegs = 1; - break; - case ELEMENT_TYPE_R8: - // 64-bit floating point argument. + // Floating point argument cFPRegs = 1; break; @@ -1697,10 +1693,10 @@ int ArgIteratorTemplate::GetNextOffset() } else { - flags = MethodTable::GetLoongArch64PassStructInRegisterFlags(thValueType); - if (flags & STRUCT_HAS_FLOAT_FIELDS_MASK) + info = MethodTable::GetLoongArch64PassFpStructInRegistersInfo(thValueType); + if (info.flags != FpStruct::UseIntCallConv) { - cFPRegs = (flags & STRUCT_FLOAT_FIELD_ONLY_TWO) ? 2 : 1; + cFPRegs = (info.flags & FpStruct::BothFloat) ? 2 : 1; } } @@ -1717,12 +1713,12 @@ int ArgIteratorTemplate::GetNextOffset() if (cFPRegs > 0 && !this->IsVarArg()) { - if (flags & (STRUCT_FLOAT_FIELD_FIRST | STRUCT_FLOAT_FIELD_SECOND)) + if (info.flags & (FpStruct::FloatInt | FpStruct::IntFloat)) { assert(cFPRegs == 1); - assert((STRUCT_FLOAT_FIELD_FIRST == (flags & STRUCT_HAS_FLOAT_FIELDS_MASK)) || (STRUCT_FLOAT_FIELD_SECOND == (flags & STRUCT_HAS_FLOAT_FIELDS_MASK))); + assert((info.flags & (FpStruct::OnlyOne | FpStruct::BothFloat)) == 0); - if ((1 + m_idxFPReg <= NUM_ARGUMENT_REGISTERS) && (m_idxGenReg + 1 <= NUM_ARGUMENT_REGISTERS)) + if ((1 + m_idxFPReg <= NUM_ARGUMENT_REGISTERS) && (1 + m_idxGenReg <= NUM_ARGUMENT_REGISTERS)) { int argOfs = 0; m_argLocDescForStructInRegs.Init(); @@ -1730,9 +1726,9 @@ int ArgIteratorTemplate::GetNextOffset() m_argLocDescForStructInRegs.m_cFloatReg = 1; m_argLocDescForStructInRegs.m_idxGenReg = m_idxGenReg; m_argLocDescForStructInRegs.m_cGenReg = 1; - m_argLocDescForStructInRegs.m_structFields = flags; + m_argLocDescForStructInRegs.m_structFields = info; - if (flags & STRUCT_FLOAT_FIELD_SECOND) + if (info.flags & FpStruct::IntFloat) { argOfs = TransitionBlock::GetOffsetOfArgumentRegisters() + m_idxGenReg * 8; } @@ -1752,7 +1748,10 @@ int ArgIteratorTemplate::GetNextOffset() else if (cFPRegs + m_idxFPReg <= NUM_ARGUMENT_REGISTERS) { int argOfs = TransitionBlock::GetOffsetOfFloatArgumentRegisters() + m_idxFPReg * 8; - if (flags == STRUCT_FLOAT_FIELD_ONLY_TWO) // struct with two float-fields. + static const FpStruct::Flags twoFloats = FpStruct::Flags(FpStruct::BothFloat + | (2 << FpStruct::PosSizeShift1st) + | (2 << FpStruct::PosSizeShift2nd)); + if (info.flags == twoFloats) // struct with two float-fields. { m_argLocDescForStructInRegs.Init(); m_hasArgLocDescForStructInRegs = true; @@ -1760,7 +1759,7 @@ int ArgIteratorTemplate::GetNextOffset() assert(cFPRegs == 2); m_argLocDescForStructInRegs.m_cFloatReg = 2; assert(argSize == 8); - m_argLocDescForStructInRegs.m_structFields = STRUCT_FLOAT_FIELD_ONLY_TWO; + m_argLocDescForStructInRegs.m_structFields = info; } m_idxFPReg += cFPRegs; return argOfs; @@ -2022,7 +2021,8 @@ void ArgIteratorTemplate::ComputeReturnFlags() if (size <= ENREGISTERED_RETURNTYPE_INTEGER_MAXSIZE) { assert(!thValueType.IsTypeDesc()); - flags = (MethodTable::GetLoongArch64PassStructInRegisterFlags(thValueType) & 0xff) << RETURN_FP_SIZE_SHIFT; + FpStructInRegistersInfo info = MethodTable::GetLoongArch64PassFpStructInRegistersInfo(thValueType); + flags |= info.flags << RETURN_FP_SIZE_SHIFT; break; } #elif defined(TARGET_RISCV64) diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 388241b404a7c..4d86fe912eceb 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -9465,7 +9465,7 @@ CorInfoTypeWithMod CEEInfo::getArgType ( // // The returned value's encoding details how a struct argument uses float registers: // see the enum `StructFloatFieldInfoFlags`. -uint32_t CEEInfo::getLoongArch64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE cls) +FpStructInRegistersInfo CEEInfo::getLoongArch64PassFpStructInRegistersInfo(CORINFO_CLASS_HANDLE cls) { CONTRACTL { NOTHROW; @@ -9475,15 +9475,15 @@ uint32_t CEEInfo::getLoongArch64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE c JIT_TO_EE_TRANSITION_LEAF(); - uint32_t size = STRUCT_NO_FLOAT_FIELD; + FpStructInRegistersInfo info = {}; #if defined(TARGET_LOONGARCH64) - size = (uint32_t)MethodTable::GetLoongArch64PassStructInRegisterFlags(TypeHandle(cls)); -#endif + info = MethodTable::GetLoongArch64PassFpStructInRegistersInfo(TypeHandle(cls)); +#endif // TARGET_LOONGARCH64 EE_TO_JIT_TRANSITION_LEAF(); - return size; + return info; } FpStructInRegistersInfo CEEInfo::getRiscV64PassFpStructInRegistersInfo(CORINFO_CLASS_HANDLE cls) diff --git a/src/coreclr/vm/loongarch64/profiler.cpp b/src/coreclr/vm/loongarch64/profiler.cpp index 0d056d5797c8d..8da4c3d5137c0 100644 --- a/src/coreclr/vm/loongarch64/profiler.cpp +++ b/src/coreclr/vm/loongarch64/profiler.cpp @@ -134,14 +134,14 @@ LPVOID ProfileArgIterator::GetNextArgAddr() UINT64* dst = (UINT64*)&pData->buffer[bufferPos]; m_bufferPos += 16; - if (pArgLocDesc->m_structFields & STRUCT_FLOAT_FIELD_FIRST) + if (pArgLocDesc->m_structFields.flags & FpStruct::FloatInt) { *dst++ = *(UINT64*)pArg; *dst = pData->argumentRegisters.a[pArgLocDesc->m_idxGenReg]; } else { - _ASSERTE(pArgLocDesc->m_structFields & STRUCT_FLOAT_FIELD_SECOND); + _ASSERTE(pArgLocDesc->m_structFields.flags & FpStruct::IntFloat); *dst++ = pData->argumentRegisters.a[pArgLocDesc->m_idxGenReg]; *dst = *(UINT64*)pArg; } @@ -163,8 +163,8 @@ LPVOID ProfileArgIterator::GetNextArgAddr() { if (pArgLocDesc->m_cFloatReg == 1) { - _ASSERTE(!(pArgLocDesc->m_structFields & STRUCT_FLOAT_FIELD_FIRST)); - _ASSERTE(pArgLocDesc->m_structFields & STRUCT_FLOAT_FIELD_SECOND); + _ASSERTE(!(pArgLocDesc->m_structFields.flags & FpStruct::FloatInt)); + _ASSERTE(pArgLocDesc->m_structFields.flags & FpStruct::IntFloat); UINT32 bufferPos = m_bufferPos; UINT64* dst = (UINT64*)&pData->buffer[bufferPos]; @@ -258,11 +258,11 @@ LPVOID ProfileArgIterator::GetReturnBufferAddr(void) return (LPVOID)pData->argumentRegisters.a[0]; } - UINT fpReturnSize = m_argIterator.GetFPReturnSize(); + FpStruct::Flags fpReturnSize = FpStruct::Flags(m_argIterator.GetFPReturnSize()); if (fpReturnSize != 0) { - if ((fpReturnSize & (UINT)STRUCT_FLOAT_FIELD_ONLY_ONE) || (fpReturnSize & (UINT)STRUCT_FLOAT_FIELD_ONLY_TWO)) + if (fpReturnSize & (FpStruct::OnlyOne | FpStruct::BothFloat)) { return &pData->floatArgumentRegisters.f[0]; } @@ -275,14 +275,14 @@ LPVOID ProfileArgIterator::GetReturnBufferAddr(void) // using the tail 16 bytes for return structure. UINT64* dst = (UINT64*)&pData->buffer[sizeof(pData->buffer) - 16]; - if (fpReturnSize & (UINT)STRUCT_FLOAT_FIELD_FIRST) + if (fpReturnSize & FpStruct::FloatInt) { *(double*)dst = pData->floatArgumentRegisters.f[0]; *(dst + 1) = pData->argumentRegisters.a[0]; } else { - _ASSERTE(fpReturnSize & (UINT)STRUCT_FLOAT_FIELD_SECOND); + _ASSERTE(fpReturnSize & FpStruct::IntFloat); *dst = pData->argumentRegisters.a[0]; *(double*)(dst + 1) = pData->floatArgumentRegisters.f[0]; } diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index c018f1945db01..662589a4b91cc 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -2937,6 +2937,13 @@ FpStructInRegistersInfo MethodTable::GetRiscV64PassFpStructInRegistersInfo(TypeH FpStructInRegistersInfo MethodTable::GetLoongArch64PassFpStructInRegistersInfo(TypeHandle th) #endif { + if (th.GetSize() > ENREGISTERED_PARAMTYPE_MAXSIZE) + { + LOG((LF_JIT, LL_EVERYTHING, "FpStructInRegistersInfo: struct %s (%u bytes) is too big\n", + (!th.IsTypeDesc() ? th.AsMethodTable() : th.AsNativeValueType())->GetDebugClassName(), th.GetSize())); + return FpStructInRegistersInfo{}; + } + FpStructInRegistersInfo info = {}; int nFields = 0; if (!FlattenFields(th, 0, info, nFields DEBUG_ARG(0))) From 9967e2e4ed76db44b1ed23420709d3dda5745c77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomek=20Sowi=C5=84ski?= Date: Wed, 26 Jun 2024 12:09:20 +0200 Subject: [PATCH 14/35] Remove unused old flag masks --- src/coreclr/inc/corinfo.h | 10 ---------- src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs | 11 ----------- 2 files changed, 21 deletions(-) diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index 9054214396be5..76f40f4dfb582 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -344,16 +344,6 @@ enum StructFloatFieldInfoFlags STRUCT_FLOAT_FIELD_SECOND = 0x4, STRUCT_FIRST_FIELD_SIZE_IS8 = 0x10, STRUCT_SECOND_FIELD_SIZE_IS8 = 0x20, - - STRUCT_FIRST_FIELD_DOUBLE = (STRUCT_FLOAT_FIELD_FIRST | STRUCT_FIRST_FIELD_SIZE_IS8), - STRUCT_SECOND_FIELD_DOUBLE = (STRUCT_FLOAT_FIELD_SECOND | STRUCT_SECOND_FIELD_SIZE_IS8), - STRUCT_FIELD_TWO_DOUBLES = (STRUCT_FIRST_FIELD_SIZE_IS8 | STRUCT_SECOND_FIELD_SIZE_IS8 | STRUCT_FLOAT_FIELD_ONLY_TWO), - - STRUCT_MERGE_FIRST_SECOND = (STRUCT_FLOAT_FIELD_FIRST | STRUCT_FLOAT_FIELD_ONLY_TWO), - STRUCT_MERGE_FIRST_SECOND_8 = (STRUCT_FLOAT_FIELD_FIRST | STRUCT_FLOAT_FIELD_ONLY_TWO | STRUCT_SECOND_FIELD_SIZE_IS8), - - STRUCT_HAS_FLOAT_FIELDS_MASK = (STRUCT_FLOAT_FIELD_FIRST | STRUCT_FLOAT_FIELD_SECOND | STRUCT_FLOAT_FIELD_ONLY_TWO | STRUCT_FLOAT_FIELD_ONLY_ONE), - STRUCT_HAS_8BYTES_FIELDS_MASK = (STRUCT_FIRST_FIELD_SIZE_IS8 | STRUCT_SECOND_FIELD_SIZE_IS8), }; // Bitfields for FpStructInRegistersInfo::flags diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs index 71ecda3d7cc74..8c94d4b2b6068 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs @@ -1249,17 +1249,6 @@ public enum StructFloatFieldInfoFlags STRUCT_FLOAT_FIELD_SECOND = 0x4, STRUCT_FIRST_FIELD_SIZE_IS8 = 0x10, STRUCT_SECOND_FIELD_SIZE_IS8 = 0x20, - - STRUCT_FIRST_FIELD_DOUBLE = (STRUCT_FLOAT_FIELD_FIRST | STRUCT_FIRST_FIELD_SIZE_IS8), - STRUCT_SECOND_FIELD_DOUBLE = (STRUCT_FLOAT_FIELD_SECOND | STRUCT_SECOND_FIELD_SIZE_IS8), - STRUCT_FIELD_TWO_DOUBLES = (STRUCT_FIRST_FIELD_SIZE_IS8 | STRUCT_SECOND_FIELD_SIZE_IS8 | STRUCT_FLOAT_FIELD_ONLY_TWO), - - STRUCT_MERGE_FIRST_SECOND = (STRUCT_FLOAT_FIELD_FIRST | STRUCT_FLOAT_FIELD_ONLY_TWO), - STRUCT_MERGE_FIRST_SECOND_8 = (STRUCT_FLOAT_FIELD_FIRST | STRUCT_FLOAT_FIELD_ONLY_TWO | STRUCT_SECOND_FIELD_SIZE_IS8), - - STRUCT_HAS_ONE_FLOAT_MASK = (STRUCT_FLOAT_FIELD_FIRST | STRUCT_FLOAT_FIELD_SECOND), - STRUCT_HAS_FLOAT_FIELDS_MASK = (STRUCT_FLOAT_FIELD_FIRST | STRUCT_FLOAT_FIELD_SECOND | STRUCT_FLOAT_FIELD_ONLY_TWO | STRUCT_FLOAT_FIELD_ONLY_ONE), - STRUCT_HAS_8BYTES_FIELDS_MASK = (STRUCT_FIRST_FIELD_SIZE_IS8 | STRUCT_SECOND_FIELD_SIZE_IS8), }; From 6bc28d103533b279efba940762d2c8be0238b4e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Sowi=C5=84ski?= Date: Thu, 27 Jun 2024 09:07:13 +0200 Subject: [PATCH 15/35] LoongArch64 typo Co-authored-by: Qiao Pengcheng --- src/coreclr/jit/compiler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp index c03360c8d16b4..f064c008ebdfb 100644 --- a/src/coreclr/jit/compiler.cpp +++ b/src/coreclr/jit/compiler.cpp @@ -8298,7 +8298,7 @@ FpStructInRegistersInfo Compiler::GetPassFpStructInRegistersInfo(CORINFO_CLASS_H #ifdef TARGET_RISCV64 #define getInfoFunc getRiscV64PassFpStructInRegistersInfo #else -#define getInfoFunc getLoongArchPassFpStructInRegistersInfo +#define getInfoFunc getLoongArch64PassFpStructInRegistersInfo #endif FpStructInRegistersInfo ret = info.compCompHnd->getInfoFunc(structHandle); From 33a6aee3d9085d693ccbe32d929ba4f57936f65c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Sowi=C5=84ski?= Date: Thu, 27 Jun 2024 09:10:56 +0200 Subject: [PATCH 16/35] Missing FpStruct namespace Co-authored-by: Qiao Pengcheng --- src/coreclr/jit/targetloongarch64.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/jit/targetloongarch64.cpp b/src/coreclr/jit/targetloongarch64.cpp index d2e8447d0d5f8..35e1a986ed73f 100644 --- a/src/coreclr/jit/targetloongarch64.cpp +++ b/src/coreclr/jit/targetloongarch64.cpp @@ -83,7 +83,7 @@ ABIPassingInformation LoongArch64Classifier::Classify(Compiler* comp, fpInfo = comp->GetPassFpStructInRegistersInfo(typeHnd); - if (fpInfo.flags != UseIntCallConv) + if (fpInfo.flags != FpStruct::UseIntCallConv) { if ((fpInfo.flags & FpStruct::OnlyOne) != 0) { From 1e951bdd3d95b17b790bf0822f94a459ee92525a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Sowi=C5=84ski?= Date: Thu, 27 Jun 2024 09:11:30 +0200 Subject: [PATCH 17/35] Missing FpStruct namespace Co-authored-by: Qiao Pengcheng --- src/coreclr/jit/targetriscv64.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/jit/targetriscv64.cpp b/src/coreclr/jit/targetriscv64.cpp index 0e5e40bd63fcf..f113b29e4b19b 100644 --- a/src/coreclr/jit/targetriscv64.cpp +++ b/src/coreclr/jit/targetriscv64.cpp @@ -82,7 +82,7 @@ ABIPassingInformation RiscV64Classifier::Classify(Compiler* comp, { floatFields = 2; } - else if (info.flags != UseIntCallConv) + else if (info.flags != FpStruct::UseIntCallConv) { assert((info.flags & (FloatInt | IntFloat)) != 0); floatFields = 1; From fd49a254e917b1859674178f807bf16bd58a9fc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Sowi=C5=84ski?= Date: Thu, 27 Jun 2024 09:11:49 +0200 Subject: [PATCH 18/35] Missing FpStruct namespace Co-authored-by: Qiao Pengcheng --- src/coreclr/jit/targetriscv64.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/jit/targetriscv64.cpp b/src/coreclr/jit/targetriscv64.cpp index f113b29e4b19b..937423ca2b3dc 100644 --- a/src/coreclr/jit/targetriscv64.cpp +++ b/src/coreclr/jit/targetriscv64.cpp @@ -104,7 +104,7 @@ ABIPassingInformation RiscV64Classifier::Classify(Compiler* comp, // Hardware floating-point calling convention if ((floatFields == 1) && (intFields == 0)) { - if (info.flags == UseIntCallConv) + if (info.flags == FpStruct::UseIntCallConv) assert(varTypeIsFloating(type)); // standalone floating-point real else assert((info.flags & OnlyOne) != 0); // struct containing just one FP real From 214b94f53e09c68075394b987df4be834dd2378f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomek=20Sowi=C5=84ski?= Date: Thu, 27 Jun 2024 09:49:17 +0200 Subject: [PATCH 19/35] Use FpStruct namespace everywhere in JIT --- src/coreclr/jit/targetriscv64.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/coreclr/jit/targetriscv64.cpp b/src/coreclr/jit/targetriscv64.cpp index 937423ca2b3dc..45cbf0f547043 100644 --- a/src/coreclr/jit/targetriscv64.cpp +++ b/src/coreclr/jit/targetriscv64.cpp @@ -62,7 +62,6 @@ ABIPassingInformation RiscV64Classifier::Classify(Compiler* comp, unsigned intFields = 0, floatFields = 0; unsigned passedSize; - using namespace FpStruct; if (varTypeIsStruct(type)) { passedSize = structLayout->GetSize(); @@ -74,17 +73,17 @@ ABIPassingInformation RiscV64Classifier::Classify(Compiler* comp, { info = comp->GetPassFpStructInRegistersInfo(structLayout->GetClassHandle()); - if ((info.flags & OnlyOne) != 0) + if ((info.flags & FpStruct::OnlyOne) != 0) { floatFields = 1; } - else if ((info.flags & BothFloat) != 0) + else if ((info.flags & FpStruct::BothFloat) != 0) { floatFields = 2; } else if (info.flags != FpStruct::UseIntCallConv) { - assert((info.flags & (FloatInt | IntFloat)) != 0); + assert((info.flags & (FpStruct::FloatInt | FpStruct::IntFloat)) != 0); floatFields = 1; intFields = 1; } @@ -107,7 +106,7 @@ ABIPassingInformation RiscV64Classifier::Classify(Compiler* comp, if (info.flags == FpStruct::UseIntCallConv) assert(varTypeIsFloating(type)); // standalone floating-point real else - assert((info.flags & OnlyOne) != 0); // struct containing just one FP real + assert((info.flags & FpStruct::OnlyOne) != 0); // struct containing just one FP real return ABIPassingInformation::FromSegment(comp, ABIPassingSegment::InRegister(m_floatRegs.Dequeue(), 0, passedSize)); @@ -116,15 +115,15 @@ ABIPassingInformation RiscV64Classifier::Classify(Compiler* comp, { assert(varTypeIsStruct(type)); assert((floatFields + intFields) == 2); - assert(info.flags != UseIntCallConv); - assert((info.flags & OnlyOne) == 0); + assert(info.flags != FpStruct::UseIntCallConv); + assert((info.flags & FpStruct::OnlyOne) == 0); unsigned firstSize = (info.SizeShift1st() == 3) ? 8 : 4; unsigned secondSize = (info.SizeShift2nd() == 3) ? 8 : 4; unsigned offset = max(firstSize, secondSize); // TODO: cover empty fields and custom offsets / alignments - bool isFirstFloat = (info.flags & (BothFloat | FloatInt)) != 0; - bool isSecondFloat = (info.flags & (BothFloat | IntFloat)) != 0; + bool isFirstFloat = (info.flags & (FpStruct::BothFloat | FpStruct::FloatInt)) != 0; + bool isSecondFloat = (info.flags & (FpStruct::BothFloat | FpStruct::IntFloat)) != 0; assert(isFirstFloat || isSecondFloat); regNumber firstReg = (isFirstFloat ? m_floatRegs : m_intRegs).Dequeue(); From 08c638599889f0015e70de725d160f379bff784a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomek=20Sowi=C5=84ski?= Date: Tue, 2 Jul 2024 15:22:49 +0200 Subject: [PATCH 20/35] JIT review --- src/coreclr/inc/corinfo.h | 2 -- src/coreclr/jit/buildstring.cpp | 2 ++ src/coreclr/jit/compiler.cpp | 16 ++++++++-------- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index a237d79465bf3..88912e489f32d 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -433,8 +433,6 @@ struct FpStructInRegistersInfo } }; -static_assert(sizeof(FpStructInRegistersInfo) == 3 * sizeof(uint32_t), ""); - #include "corinfoinstructionset.h" // CorInfoHelpFunc defines the set of helpers (accessed via the ICorDynamicInfo::getHelperFtn()) diff --git a/src/coreclr/jit/buildstring.cpp b/src/coreclr/jit/buildstring.cpp index f51e262c517ef..9843c9fcf516f 100644 --- a/src/coreclr/jit/buildstring.cpp +++ b/src/coreclr/jit/buildstring.cpp @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +#include "utils.h" + #if defined(__clang__) #define BUILD_COMPILER \ "Clang " STRINGIFY(__clang_major__) "." STRINGIFY(__clang_minor__) "." STRINGIFY(__clang_patchlevel__) diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp index c0ac24051441c..b6f5803bc6ed7 100644 --- a/src/coreclr/jit/compiler.cpp +++ b/src/coreclr/jit/compiler.cpp @@ -927,7 +927,7 @@ var_types Compiler::getReturnTypeForStruct(CORINFO_CLASS_HANDLE clsHnd, howToReturnStruct = SPK_ByReference; useType = TYP_UNKNOWN; } -#elif defined(TARGET_RISCV64) | defined(TARGET_LOONGARCH64) +#elif defined(TARGET_RISCV64) || defined(TARGET_LOONGARCH64) if (structSize <= (TARGET_POINTER_SIZE * 2)) { FpStructInRegistersInfo info = GetPassFpStructInRegistersInfo(clsHnd); @@ -8303,23 +8303,23 @@ FpStructInRegistersInfo Compiler::GetPassFpStructInRegistersInfo(CORINFO_CLASS_H FpStructInRegistersInfo ret = info.compCompHnd->getInfoFunc(structHandle); #ifdef DEBUG - if (VERBOSE) + if (verbose) { - logf("**** " STRINGIFY(getInfoFunc) "(0x%x (%s, %u bytes)) =>\n", dspPtr(structHandle), - eeGetClassName(structHandle), info.compCompHnd->getClassSize(structHandle)); + printf("**** " STRINGIFY(getInfoFunc) "(0x%x (%s, %u bytes)) =>\n", dspPtr(structHandle), + eeGetClassName(structHandle), info.compCompHnd->getClassSize(structHandle)); #undef getInfoFunc if (ret.flags == FpStruct::UseIntCallConv) { - logf(" pass by integer calling convention\n"); + printf(" pass by integer calling convention\n"); } else { bool hasOne = ((ret.flags & FpStruct::OnlyOne) != 0); long size2nd = hasOne ? -1l : ret.Size2nd(); long offset2nd = hasOne ? -1l : ret.offset2nd; - logf(" may be passed by floating-point calling convention:\n" - " flags=%#03x; %s, field sizes={%u, %li}, field offsets={%u, %li}, IntFieldKind=%s\n", - ret.flags, ret.FlagName(), ret.Size1st(), size2nd, ret.offset1st, offset2nd, ret.IntFieldKindName()); + printf(" may be passed by floating-point calling convention:\n" + " flags=%#03x; %s, field sizes={%u, %li}, field offsets={%u, %li}, IntFieldKind=%s\n", + ret.flags, ret.FlagName(), ret.Size1st(), size2nd, ret.offset1st, offset2nd, ret.IntFieldKindName()); } } #endif // DEBUG From e23c0ab88e056c1ba655cedc9ed4932e0cdbf4d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomek=20Sowi=C5=84ski?= Date: Wed, 3 Jul 2024 12:03:42 +0200 Subject: [PATCH 21/35] Update StructFloatFieldInfoFlags description --- src/coreclr/inc/corinfo.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index 88912e489f32d..30451432fcb5f 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -317,8 +317,8 @@ struct SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR } }; -// StructFloatFieldInfoFlags: used on LoongArch64 architecture by `getLoongArch64PassStructInRegisterFlags` and -// `getRISCV64PassStructInRegisterFlags` API to convey struct argument passing information. +// StructFloatFieldInfoFlags: used on LoongArch64 and RISC-V architecture as a legacy representation of +// FpStructInRegistersInfo, returned by FpStructInRegistersInfo::ToOldFlags() // // `STRUCT_NO_FLOAT_FIELD` means structs are not passed using the float register(s). // From ef5a6d4a46a9b84653d054dccce4dedc8314eaab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomek=20Sowi=C5=84ski?= Date: Wed, 3 Jul 2024 12:07:49 +0200 Subject: [PATCH 22/35] Revert to hitherto instruction set order as it's not the point of this PR --- src/coreclr/inc/corinfoinstructionset.h | 24 +++++----- .../JitInterface/CorInfoInstructionSet.cs | 48 +++++++++---------- 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/src/coreclr/inc/corinfoinstructionset.h b/src/coreclr/inc/corinfoinstructionset.h index 43f2be795314f..9a3c0efc70927 100644 --- a/src/coreclr/inc/corinfoinstructionset.h +++ b/src/coreclr/inc/corinfoinstructionset.h @@ -608,18 +608,18 @@ inline CORINFO_InstructionSetFlags EnsureInstructionSetFlagsAreValid(CORINFO_Ins resultflags.RemoveInstructionSet(InstructionSet_AVX512F); if (resultflags.HasInstructionSet(InstructionSet_AVX512F_VL) && !resultflags.HasInstructionSet(InstructionSet_AVX512F)) resultflags.RemoveInstructionSet(InstructionSet_AVX512F_VL); - if (resultflags.HasInstructionSet(InstructionSet_AVX512BW) && !resultflags.HasInstructionSet(InstructionSet_AVX512F)) - resultflags.RemoveInstructionSet(InstructionSet_AVX512BW); - if (resultflags.HasInstructionSet(InstructionSet_AVX512BW_VL) && !resultflags.HasInstructionSet(InstructionSet_AVX512BW)) - resultflags.RemoveInstructionSet(InstructionSet_AVX512BW_VL); - if (resultflags.HasInstructionSet(InstructionSet_AVX512BW_VL) && !resultflags.HasInstructionSet(InstructionSet_AVX512F_VL)) - resultflags.RemoveInstructionSet(InstructionSet_AVX512BW_VL); if (resultflags.HasInstructionSet(InstructionSet_AVX512CD) && !resultflags.HasInstructionSet(InstructionSet_AVX512F)) resultflags.RemoveInstructionSet(InstructionSet_AVX512CD); if (resultflags.HasInstructionSet(InstructionSet_AVX512CD_VL) && !resultflags.HasInstructionSet(InstructionSet_AVX512CD)) resultflags.RemoveInstructionSet(InstructionSet_AVX512CD_VL); if (resultflags.HasInstructionSet(InstructionSet_AVX512CD_VL) && !resultflags.HasInstructionSet(InstructionSet_AVX512F_VL)) resultflags.RemoveInstructionSet(InstructionSet_AVX512CD_VL); + if (resultflags.HasInstructionSet(InstructionSet_AVX512BW) && !resultflags.HasInstructionSet(InstructionSet_AVX512F)) + resultflags.RemoveInstructionSet(InstructionSet_AVX512BW); + if (resultflags.HasInstructionSet(InstructionSet_AVX512BW_VL) && !resultflags.HasInstructionSet(InstructionSet_AVX512BW)) + resultflags.RemoveInstructionSet(InstructionSet_AVX512BW_VL); + if (resultflags.HasInstructionSet(InstructionSet_AVX512BW_VL) && !resultflags.HasInstructionSet(InstructionSet_AVX512F_VL)) + resultflags.RemoveInstructionSet(InstructionSet_AVX512BW_VL); if (resultflags.HasInstructionSet(InstructionSet_AVX512DQ) && !resultflags.HasInstructionSet(InstructionSet_AVX512F)) resultflags.RemoveInstructionSet(InstructionSet_AVX512DQ); if (resultflags.HasInstructionSet(InstructionSet_AVX512DQ_VL) && !resultflags.HasInstructionSet(InstructionSet_AVX512DQ)) @@ -714,18 +714,18 @@ inline CORINFO_InstructionSetFlags EnsureInstructionSetFlagsAreValid(CORINFO_Ins resultflags.RemoveInstructionSet(InstructionSet_AVX512F); if (resultflags.HasInstructionSet(InstructionSet_AVX512F_VL) && !resultflags.HasInstructionSet(InstructionSet_AVX512F)) resultflags.RemoveInstructionSet(InstructionSet_AVX512F_VL); - if (resultflags.HasInstructionSet(InstructionSet_AVX512BW) && !resultflags.HasInstructionSet(InstructionSet_AVX512F)) - resultflags.RemoveInstructionSet(InstructionSet_AVX512BW); - if (resultflags.HasInstructionSet(InstructionSet_AVX512BW_VL) && !resultflags.HasInstructionSet(InstructionSet_AVX512BW)) - resultflags.RemoveInstructionSet(InstructionSet_AVX512BW_VL); - if (resultflags.HasInstructionSet(InstructionSet_AVX512BW_VL) && !resultflags.HasInstructionSet(InstructionSet_AVX512F_VL)) - resultflags.RemoveInstructionSet(InstructionSet_AVX512BW_VL); if (resultflags.HasInstructionSet(InstructionSet_AVX512CD) && !resultflags.HasInstructionSet(InstructionSet_AVX512F)) resultflags.RemoveInstructionSet(InstructionSet_AVX512CD); if (resultflags.HasInstructionSet(InstructionSet_AVX512CD_VL) && !resultflags.HasInstructionSet(InstructionSet_AVX512CD)) resultflags.RemoveInstructionSet(InstructionSet_AVX512CD_VL); if (resultflags.HasInstructionSet(InstructionSet_AVX512CD_VL) && !resultflags.HasInstructionSet(InstructionSet_AVX512F_VL)) resultflags.RemoveInstructionSet(InstructionSet_AVX512CD_VL); + if (resultflags.HasInstructionSet(InstructionSet_AVX512BW) && !resultflags.HasInstructionSet(InstructionSet_AVX512F)) + resultflags.RemoveInstructionSet(InstructionSet_AVX512BW); + if (resultflags.HasInstructionSet(InstructionSet_AVX512BW_VL) && !resultflags.HasInstructionSet(InstructionSet_AVX512BW)) + resultflags.RemoveInstructionSet(InstructionSet_AVX512BW_VL); + if (resultflags.HasInstructionSet(InstructionSet_AVX512BW_VL) && !resultflags.HasInstructionSet(InstructionSet_AVX512F_VL)) + resultflags.RemoveInstructionSet(InstructionSet_AVX512BW_VL); if (resultflags.HasInstructionSet(InstructionSet_AVX512DQ) && !resultflags.HasInstructionSet(InstructionSet_AVX512F)) resultflags.RemoveInstructionSet(InstructionSet_AVX512DQ); if (resultflags.HasInstructionSet(InstructionSet_AVX512DQ_VL) && !resultflags.HasInstructionSet(InstructionSet_AVX512DQ)) diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoInstructionSet.cs b/src/coreclr/tools/Common/JitInterface/CorInfoInstructionSet.cs index 42807bfcec1d9..9971accb07818 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoInstructionSet.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoInstructionSet.cs @@ -746,18 +746,18 @@ public static InstructionSetFlags ExpandInstructionSetByImplicationHelper(Target resultflags.AddInstructionSet(InstructionSet.X64_EVEX); if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512F_VL)) resultflags.AddInstructionSet(InstructionSet.X64_AVX512F); - if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512BW)) - resultflags.AddInstructionSet(InstructionSet.X64_AVX512F); - if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512BW_VL)) - resultflags.AddInstructionSet(InstructionSet.X64_AVX512BW); - if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512BW_VL)) - resultflags.AddInstructionSet(InstructionSet.X64_AVX512F_VL); if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512CD)) resultflags.AddInstructionSet(InstructionSet.X64_AVX512F); if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512CD_VL)) resultflags.AddInstructionSet(InstructionSet.X64_AVX512CD); if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512CD_VL)) resultflags.AddInstructionSet(InstructionSet.X64_AVX512F_VL); + if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512BW)) + resultflags.AddInstructionSet(InstructionSet.X64_AVX512F); + if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512BW_VL)) + resultflags.AddInstructionSet(InstructionSet.X64_AVX512BW); + if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512BW_VL)) + resultflags.AddInstructionSet(InstructionSet.X64_AVX512F_VL); if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512DQ)) resultflags.AddInstructionSet(InstructionSet.X64_AVX512F); if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512DQ_VL)) @@ -853,18 +853,18 @@ public static InstructionSetFlags ExpandInstructionSetByImplicationHelper(Target resultflags.AddInstructionSet(InstructionSet.X86_EVEX); if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512F_VL)) resultflags.AddInstructionSet(InstructionSet.X86_AVX512F); - if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512BW)) - resultflags.AddInstructionSet(InstructionSet.X86_AVX512F); - if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512BW_VL)) - resultflags.AddInstructionSet(InstructionSet.X86_AVX512BW); - if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512BW_VL)) - resultflags.AddInstructionSet(InstructionSet.X86_AVX512F_VL); if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512CD)) resultflags.AddInstructionSet(InstructionSet.X86_AVX512F); if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512CD_VL)) resultflags.AddInstructionSet(InstructionSet.X86_AVX512CD); if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512CD_VL)) resultflags.AddInstructionSet(InstructionSet.X86_AVX512F_VL); + if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512BW)) + resultflags.AddInstructionSet(InstructionSet.X86_AVX512F); + if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512BW_VL)) + resultflags.AddInstructionSet(InstructionSet.X86_AVX512BW); + if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512BW_VL)) + resultflags.AddInstructionSet(InstructionSet.X86_AVX512F_VL); if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512DQ)) resultflags.AddInstructionSet(InstructionSet.X86_AVX512F); if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512DQ_VL)) @@ -1087,18 +1087,18 @@ private static InstructionSetFlags ExpandInstructionSetByReverseImplicationHelpe resultflags.AddInstructionSet(InstructionSet.X64_AVX512F); if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512F)) resultflags.AddInstructionSet(InstructionSet.X64_AVX512F_VL); - if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512F)) - resultflags.AddInstructionSet(InstructionSet.X64_AVX512BW); - if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512BW)) - resultflags.AddInstructionSet(InstructionSet.X64_AVX512BW_VL); - if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512F_VL)) - resultflags.AddInstructionSet(InstructionSet.X64_AVX512BW_VL); if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512F)) resultflags.AddInstructionSet(InstructionSet.X64_AVX512CD); if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512CD)) resultflags.AddInstructionSet(InstructionSet.X64_AVX512CD_VL); if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512F_VL)) resultflags.AddInstructionSet(InstructionSet.X64_AVX512CD_VL); + if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512F)) + resultflags.AddInstructionSet(InstructionSet.X64_AVX512BW); + if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512BW)) + resultflags.AddInstructionSet(InstructionSet.X64_AVX512BW_VL); + if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512F_VL)) + resultflags.AddInstructionSet(InstructionSet.X64_AVX512BW_VL); if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512F)) resultflags.AddInstructionSet(InstructionSet.X64_AVX512DQ); if (resultflags.HasInstructionSet(InstructionSet.X64_AVX512DQ)) @@ -1194,18 +1194,18 @@ private static InstructionSetFlags ExpandInstructionSetByReverseImplicationHelpe resultflags.AddInstructionSet(InstructionSet.X86_AVX512F); if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512F)) resultflags.AddInstructionSet(InstructionSet.X86_AVX512F_VL); - if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512F)) - resultflags.AddInstructionSet(InstructionSet.X86_AVX512BW); - if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512BW)) - resultflags.AddInstructionSet(InstructionSet.X86_AVX512BW_VL); - if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512F_VL)) - resultflags.AddInstructionSet(InstructionSet.X86_AVX512BW_VL); if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512F)) resultflags.AddInstructionSet(InstructionSet.X86_AVX512CD); if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512CD)) resultflags.AddInstructionSet(InstructionSet.X86_AVX512CD_VL); if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512F_VL)) resultflags.AddInstructionSet(InstructionSet.X86_AVX512CD_VL); + if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512F)) + resultflags.AddInstructionSet(InstructionSet.X86_AVX512BW); + if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512BW)) + resultflags.AddInstructionSet(InstructionSet.X86_AVX512BW_VL); + if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512F_VL)) + resultflags.AddInstructionSet(InstructionSet.X86_AVX512BW_VL); if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512F)) resultflags.AddInstructionSet(InstructionSet.X86_AVX512DQ); if (resultflags.HasInstructionSet(InstructionSet.X86_AVX512DQ)) From 100ecedc09908d9b77c874b90b8c7ee80b6f6c8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomek=20Sowi=C5=84ski?= Date: Thu, 4 Jul 2024 15:36:22 +0200 Subject: [PATCH 23/35] Unify get{LoongArch,RiscV}64PassFpStructInRegistersInfo JIT interfaces --- src/coreclr/inc/corinfo.h | 5 +- src/coreclr/inc/icorjitinfoimpl_generated.h | 5 +- src/coreclr/inc/jiteeversionguid.h | 10 +- src/coreclr/jit/ICorJitInfo_names_generated.h | 3 +- .../jit/ICorJitInfo_wrapper_generated.hpp | 17 +-- src/coreclr/jit/compiler.cpp | 10 +- .../tools/Common/JitInterface/CorInfoImpl.cs | 23 ++-- .../JitInterface/CorInfoImpl_generated.cs | 122 ++++++++---------- .../ThunkGenerator/ThunkInput.txt | 3 +- .../aot/jitinterface/jitinterface_generated.h | 16 +-- .../tools/superpmi/superpmi-shared/lwmlist.h | 3 +- .../superpmi-shared/methodcontext.cpp | 48 ++----- .../superpmi/superpmi-shared/methodcontext.h | 13 +- .../superpmi-shim-collector/icorjitinfo.cpp | 16 +-- .../icorjitinfo_generated.cpp | 13 +- .../icorjitinfo_generated.cpp | 10 +- .../tools/superpmi/superpmi/icorjitinfo.cpp | 12 +- src/coreclr/vm/callingconvention.h | 8 +- src/coreclr/vm/jitinterface.cpp | 31 +---- src/coreclr/vm/methodtable.cpp | 6 +- src/coreclr/vm/methodtable.h | 6 +- 21 files changed, 127 insertions(+), 253 deletions(-) diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index 30451432fcb5f..0ac854dae862c 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -3160,8 +3160,9 @@ class ICorStaticInfo // Classifies a swift structure into primitives or an implicit byref for ABI purposes. virtual void getSwiftLowering(CORINFO_CLASS_HANDLE structHnd, CORINFO_SWIFT_LOWERING* pLowering) = 0; - virtual FpStructInRegistersInfo getLoongArch64PassFpStructInRegistersInfo(CORINFO_CLASS_HANDLE cls) = 0; - virtual FpStructInRegistersInfo getRiscV64PassFpStructInRegistersInfo(CORINFO_CLASS_HANDLE cls) = 0; + // Returns passing info for a RISC-V/LoongArch struct passed in registers according to + // hardware floating-point calling convention. + virtual FpStructInRegistersInfo getFpStructInRegistersInfo(CORINFO_CLASS_HANDLE cls) = 0; }; /***************************************************************************** diff --git a/src/coreclr/inc/icorjitinfoimpl_generated.h b/src/coreclr/inc/icorjitinfoimpl_generated.h index 54eae28b3c8cf..d05a544c9636a 100644 --- a/src/coreclr/inc/icorjitinfoimpl_generated.h +++ b/src/coreclr/inc/icorjitinfoimpl_generated.h @@ -520,10 +520,7 @@ void getSwiftLowering( CORINFO_CLASS_HANDLE structHnd, CORINFO_SWIFT_LOWERING* pLowering) override; -FpStructInRegistersInfo getLoongArch64PassFpStructInRegistersInfo( - CORINFO_CLASS_HANDLE structHnd) override; - -FpStructInRegistersInfo getRiscV64PassFpStructInRegistersInfo( +FpStructInRegistersInfo getFpStructInRegistersInfo( CORINFO_CLASS_HANDLE structHnd) override; uint32_t getThreadTLSIndex( diff --git a/src/coreclr/inc/jiteeversionguid.h b/src/coreclr/inc/jiteeversionguid.h index 7d159ef5ca86e..aeb9577a41159 100644 --- a/src/coreclr/inc/jiteeversionguid.h +++ b/src/coreclr/inc/jiteeversionguid.h @@ -43,11 +43,11 @@ typedef const GUID *LPCGUID; #define GUID_DEFINED #endif // !GUID_DEFINED -constexpr GUID JITEEVersionIdentifier = { /* d59be607-3a63-435d-885e-6a4e9265461d */ - 0xd59be607, - 0x3a63, - 0x435d, - {0x88, 0x5e, 0x6a, 0x4e, 0x92, 0x65, 0x46, 0x1d} +constexpr GUID JITEEVersionIdentifier = { /* 78d1a298-7336-42d2-b1ae-47d38f69034b */ + 0x78d1a298, + 0x7336, + 0x42d2, + {0xb1, 0xae, 0x47, 0xd3, 0x8f, 0x69, 0x03, 0x4b} }; ////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/coreclr/jit/ICorJitInfo_names_generated.h b/src/coreclr/jit/ICorJitInfo_names_generated.h index 4240489cebcb5..a7a0c7dc39f98 100644 --- a/src/coreclr/jit/ICorJitInfo_names_generated.h +++ b/src/coreclr/jit/ICorJitInfo_names_generated.h @@ -130,8 +130,7 @@ DEF_CLR_API(getMethodNameFromMetadata) DEF_CLR_API(getMethodHash) DEF_CLR_API(getSystemVAmd64PassStructInRegisterDescriptor) DEF_CLR_API(getSwiftLowering) -DEF_CLR_API(getLoongArch64PassFpStructInRegistersInfo) -DEF_CLR_API(getRiscV64PassFpStructInRegistersInfo) +DEF_CLR_API(getFpStructInRegistersInfo) DEF_CLR_API(getThreadTLSIndex) DEF_CLR_API(getAddrOfCaptureThreadGlobal) DEF_CLR_API(getHelperFtn) diff --git a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp index cd54760d3192b..d3071cea2b48c 100644 --- a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp +++ b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp @@ -1238,21 +1238,12 @@ void WrapICorJitInfo::getSwiftLowering( API_LEAVE(getSwiftLowering); } -FpStructInRegistersInfo WrapICorJitInfo::getLoongArch64PassFpStructInRegistersInfo( +FpStructInRegistersInfo WrapICorJitInfo::getFpStructInRegistersInfo( CORINFO_CLASS_HANDLE structHnd) { - API_ENTER(getLoongArch64PassFpStructInRegistersInfo); - FpStructInRegistersInfo temp = wrapHnd->getLoongArch64PassFpStructInRegistersInfo(structHnd); - API_LEAVE(getLoongArch64PassFpStructInRegistersInfo); - return temp; -} - -FpStructInRegistersInfo WrapICorJitInfo::getRiscV64PassFpStructInRegistersInfo( - CORINFO_CLASS_HANDLE structHnd) -{ - API_ENTER(getRiscV64PassFpStructInRegistersInfo); - FpStructInRegistersInfo temp = wrapHnd->getRiscV64PassFpStructInRegistersInfo(structHnd); - API_LEAVE(getRiscV64PassFpStructInRegistersInfo); + API_ENTER(getFpStructInRegistersInfo); + FpStructInRegistersInfo temp = wrapHnd->getFpStructInRegistersInfo(structHnd); + API_LEAVE(getFpStructInRegistersInfo); return temp; } diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp index b6f5803bc6ed7..0dff2cc8dc31f 100644 --- a/src/coreclr/jit/compiler.cpp +++ b/src/coreclr/jit/compiler.cpp @@ -8295,17 +8295,11 @@ void Compiler::GetStructTypeOffset( // The passing info FpStructInRegistersInfo Compiler::GetPassFpStructInRegistersInfo(CORINFO_CLASS_HANDLE structHandle) { -#ifdef TARGET_RISCV64 -#define getInfoFunc getRiscV64PassFpStructInRegistersInfo -#else -#define getInfoFunc getLoongArch64PassFpStructInRegistersInfo -#endif - - FpStructInRegistersInfo ret = info.compCompHnd->getInfoFunc(structHandle); + FpStructInRegistersInfo ret = info.compCompHnd->getFpStructInRegistersInfo(structHandle); #ifdef DEBUG if (verbose) { - printf("**** " STRINGIFY(getInfoFunc) "(0x%x (%s, %u bytes)) =>\n", dspPtr(structHandle), + printf("**** getFpStructInRegistersInfo(0x%x (%s, %u bytes)) =>\n", dspPtr(structHandle), eeGetClassName(structHandle), info.compCompHnd->getClassSize(structHandle)); #undef getInfoFunc if (ret.flags == FpStruct::UseIntCallConv) diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index 440aff1c67664..0d335d5b0d26e 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -3454,16 +3454,23 @@ private void getSwiftLowering(CORINFO_CLASS_STRUCT_* structHnd, ref CORINFO_SWIF lowering = SwiftPhysicalLowering.LowerTypeForSwiftSignature(HandleToObject(structHnd)); } - private FpStructInRegistersInfo getLoongArch64PassFpStructInRegistersInfo(CORINFO_CLASS_STRUCT_* cls) + private FpStructInRegistersInfo getFpStructInRegistersInfo(CORINFO_CLASS_STRUCT_* cls) { TypeDesc typeDesc = HandleToObject(cls); - return LoongArch64PassStructInRegister.GetLoongArch64PassFpStructInRegistersInfo(typeDesc); - } - - private FpStructInRegistersInfo getRiscV64PassFpStructInRegistersInfo(CORINFO_CLASS_STRUCT_* cls) - { - TypeDesc typeDesc = HandleToObject(cls); - return RiscV64PassFpStructInRegisters.GetRiscV64PassFpStructInRegistersInfo(typeDesc); + var target = _compilation.TypeSystemContext.Target; + if (target.Architecture is TargetArchitecture.RiscV64) + { + return RiscV64PassFpStructInRegisters.GetRiscV64PassFpStructInRegistersInfo(typeDesc); + } + else if (target.Architecture is TargetArchitecture.LoongArch64) + { + return LoongArch64PassStructInRegister.GetLoongArch64PassFpStructInRegistersInfo(typeDesc); + } + else + { + Debug.Assert(false, "Unsupported architecture for getFpStructInRegistersInfo"); + return new FpStructInRegistersInfo{}; + } } private uint getThreadTLSIndex(ref void* ppIndirection) diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs index 2a1e380eafe2b..979cec116ccff 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs @@ -1874,27 +1874,12 @@ private static void _getSwiftLowering(IntPtr thisHandle, IntPtr* ppException, CO } [UnmanagedCallersOnly] - private static FpStructInRegistersInfo _getLoongArch64PassFpStructInRegistersInfo(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* structHnd) + private static FpStructInRegistersInfo _getFpStructInRegistersInfo(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* structHnd) { var _this = GetThis(thisHandle); try { - return _this.getLoongArch64PassFpStructInRegistersInfo(structHnd); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default; - } - } - - [UnmanagedCallersOnly] - private static FpStructInRegistersInfo _getRiscV64PassFpStructInRegistersInfo(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* structHnd) - { - var _this = GetThis(thisHandle); - try - { - return _this.getRiscV64PassFpStructInRegistersInfo(structHnd); + return _this.getFpStructInRegistersInfo(structHnd); } catch (Exception ex) { @@ -2624,7 +2609,7 @@ private static uint _getJitFlags(IntPtr thisHandle, IntPtr* ppException, CORJIT_ private static IntPtr GetUnmanagedCallbacks() { - void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 177); + void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 176); callbacks[0] = (delegate* unmanaged)&_isIntrinsic; callbacks[1] = (delegate* unmanaged)&_notifyMethodInfoUsage; @@ -2752,57 +2737,56 @@ private static IntPtr GetUnmanagedCallbacks() callbacks[123] = (delegate* unmanaged)&_getMethodHash; callbacks[124] = (delegate* unmanaged)&_getSystemVAmd64PassStructInRegisterDescriptor; callbacks[125] = (delegate* unmanaged)&_getSwiftLowering; - callbacks[126] = (delegate* unmanaged)&_getLoongArch64PassFpStructInRegistersInfo; - callbacks[127] = (delegate* unmanaged)&_getRiscV64PassFpStructInRegistersInfo; - callbacks[128] = (delegate* unmanaged)&_getThreadTLSIndex; - callbacks[129] = (delegate* unmanaged)&_getAddrOfCaptureThreadGlobal; - callbacks[130] = (delegate* unmanaged)&_getHelperFtn; - callbacks[131] = (delegate* unmanaged)&_getFunctionEntryPoint; - callbacks[132] = (delegate* unmanaged)&_getFunctionFixedEntryPoint; - callbacks[133] = (delegate* unmanaged)&_getMethodSync; - callbacks[134] = (delegate* unmanaged)&_getLazyStringLiteralHelper; - callbacks[135] = (delegate* unmanaged)&_embedModuleHandle; - callbacks[136] = (delegate* unmanaged)&_embedClassHandle; - callbacks[137] = (delegate* unmanaged)&_embedMethodHandle; - callbacks[138] = (delegate* unmanaged)&_embedFieldHandle; - callbacks[139] = (delegate* unmanaged)&_embedGenericHandle; - callbacks[140] = (delegate* unmanaged)&_getLocationOfThisType; - callbacks[141] = (delegate* unmanaged)&_getAddressOfPInvokeTarget; - callbacks[142] = (delegate* unmanaged)&_GetCookieForPInvokeCalliSig; - callbacks[143] = (delegate* unmanaged)&_canGetCookieForPInvokeCalliSig; - callbacks[144] = (delegate* unmanaged)&_getJustMyCodeHandle; - callbacks[145] = (delegate* unmanaged)&_GetProfilingHandle; - callbacks[146] = (delegate* unmanaged)&_getCallInfo; - callbacks[147] = (delegate* unmanaged)&_getStaticFieldContent; - callbacks[148] = (delegate* unmanaged)&_getObjectContent; - callbacks[149] = (delegate* unmanaged)&_getStaticFieldCurrentClass; - callbacks[150] = (delegate* unmanaged)&_getVarArgsHandle; - callbacks[151] = (delegate* unmanaged)&_canGetVarArgsHandle; - callbacks[152] = (delegate* unmanaged)&_constructStringLiteral; - callbacks[153] = (delegate* unmanaged)&_emptyStringLiteral; - callbacks[154] = (delegate* unmanaged)&_getFieldThreadLocalStoreID; - callbacks[155] = (delegate* unmanaged)&_GetDelegateCtor; - callbacks[156] = (delegate* unmanaged)&_MethodCompileComplete; - callbacks[157] = (delegate* unmanaged)&_getTailCallHelpers; - callbacks[158] = (delegate* unmanaged)&_convertPInvokeCalliToCall; - callbacks[159] = (delegate* unmanaged)&_notifyInstructionSetUsage; - callbacks[160] = (delegate* unmanaged)&_updateEntryPointForTailCall; - callbacks[161] = (delegate* unmanaged)&_allocMem; - callbacks[162] = (delegate* unmanaged)&_reserveUnwindInfo; - callbacks[163] = (delegate* unmanaged)&_allocUnwindInfo; - callbacks[164] = (delegate* unmanaged)&_allocGCInfo; - callbacks[165] = (delegate* unmanaged)&_setEHcount; - callbacks[166] = (delegate* unmanaged)&_setEHinfo; - callbacks[167] = (delegate* unmanaged)&_logMsg; - callbacks[168] = (delegate* unmanaged)&_doAssert; - callbacks[169] = (delegate* unmanaged)&_reportFatalError; - callbacks[170] = (delegate* unmanaged)&_getPgoInstrumentationResults; - callbacks[171] = (delegate* unmanaged)&_allocPgoInstrumentationBySchema; - callbacks[172] = (delegate* unmanaged)&_recordCallSite; - callbacks[173] = (delegate* unmanaged)&_recordRelocation; - callbacks[174] = (delegate* unmanaged)&_getRelocTypeHint; - callbacks[175] = (delegate* unmanaged)&_getExpectedTargetArchitecture; - callbacks[176] = (delegate* unmanaged)&_getJitFlags; + callbacks[126] = (delegate* unmanaged)&_getFpStructInRegistersInfo; + callbacks[127] = (delegate* unmanaged)&_getThreadTLSIndex; + callbacks[128] = (delegate* unmanaged)&_getAddrOfCaptureThreadGlobal; + callbacks[129] = (delegate* unmanaged)&_getHelperFtn; + callbacks[130] = (delegate* unmanaged)&_getFunctionEntryPoint; + callbacks[131] = (delegate* unmanaged)&_getFunctionFixedEntryPoint; + callbacks[132] = (delegate* unmanaged)&_getMethodSync; + callbacks[133] = (delegate* unmanaged)&_getLazyStringLiteralHelper; + callbacks[134] = (delegate* unmanaged)&_embedModuleHandle; + callbacks[135] = (delegate* unmanaged)&_embedClassHandle; + callbacks[136] = (delegate* unmanaged)&_embedMethodHandle; + callbacks[137] = (delegate* unmanaged)&_embedFieldHandle; + callbacks[138] = (delegate* unmanaged)&_embedGenericHandle; + callbacks[139] = (delegate* unmanaged)&_getLocationOfThisType; + callbacks[140] = (delegate* unmanaged)&_getAddressOfPInvokeTarget; + callbacks[141] = (delegate* unmanaged)&_GetCookieForPInvokeCalliSig; + callbacks[142] = (delegate* unmanaged)&_canGetCookieForPInvokeCalliSig; + callbacks[143] = (delegate* unmanaged)&_getJustMyCodeHandle; + callbacks[144] = (delegate* unmanaged)&_GetProfilingHandle; + callbacks[145] = (delegate* unmanaged)&_getCallInfo; + callbacks[146] = (delegate* unmanaged)&_getStaticFieldContent; + callbacks[147] = (delegate* unmanaged)&_getObjectContent; + callbacks[148] = (delegate* unmanaged)&_getStaticFieldCurrentClass; + callbacks[149] = (delegate* unmanaged)&_getVarArgsHandle; + callbacks[150] = (delegate* unmanaged)&_canGetVarArgsHandle; + callbacks[151] = (delegate* unmanaged)&_constructStringLiteral; + callbacks[152] = (delegate* unmanaged)&_emptyStringLiteral; + callbacks[153] = (delegate* unmanaged)&_getFieldThreadLocalStoreID; + callbacks[154] = (delegate* unmanaged)&_GetDelegateCtor; + callbacks[155] = (delegate* unmanaged)&_MethodCompileComplete; + callbacks[156] = (delegate* unmanaged)&_getTailCallHelpers; + callbacks[157] = (delegate* unmanaged)&_convertPInvokeCalliToCall; + callbacks[158] = (delegate* unmanaged)&_notifyInstructionSetUsage; + callbacks[159] = (delegate* unmanaged)&_updateEntryPointForTailCall; + callbacks[160] = (delegate* unmanaged)&_allocMem; + callbacks[161] = (delegate* unmanaged)&_reserveUnwindInfo; + callbacks[162] = (delegate* unmanaged)&_allocUnwindInfo; + callbacks[163] = (delegate* unmanaged)&_allocGCInfo; + callbacks[164] = (delegate* unmanaged)&_setEHcount; + callbacks[165] = (delegate* unmanaged)&_setEHinfo; + callbacks[166] = (delegate* unmanaged)&_logMsg; + callbacks[167] = (delegate* unmanaged)&_doAssert; + callbacks[168] = (delegate* unmanaged)&_reportFatalError; + callbacks[169] = (delegate* unmanaged)&_getPgoInstrumentationResults; + callbacks[170] = (delegate* unmanaged)&_allocPgoInstrumentationBySchema; + callbacks[171] = (delegate* unmanaged)&_recordCallSite; + callbacks[172] = (delegate* unmanaged)&_recordRelocation; + callbacks[173] = (delegate* unmanaged)&_getRelocTypeHint; + callbacks[174] = (delegate* unmanaged)&_getExpectedTargetArchitecture; + callbacks[175] = (delegate* unmanaged)&_getJitFlags; return (IntPtr)callbacks; } diff --git a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt index 67293f084f1c2..9943fb814a260 100644 --- a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt +++ b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt @@ -290,8 +290,7 @@ FUNCTIONS unsigned getMethodHash(CORINFO_METHOD_HANDLE ftn); bool getSystemVAmd64PassStructInRegisterDescriptor(CORINFO_CLASS_HANDLE structHnd, SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structPassInRegDescPtr); void getSwiftLowering(CORINFO_CLASS_HANDLE structHnd, CORINFO_SWIFT_LOWERING* pLowering); - FpStructInRegistersInfo getLoongArch64PassFpStructInRegistersInfo(CORINFO_CLASS_HANDLE structHnd); - FpStructInRegistersInfo getRiscV64PassFpStructInRegistersInfo(CORINFO_CLASS_HANDLE structHnd); + FpStructInRegistersInfo getFpStructInRegistersInfo(CORINFO_CLASS_HANDLE structHnd); uint32_t getThreadTLSIndex(void **ppIndirection); int32_t * getAddrOfCaptureThreadGlobal(void **ppIndirection); void* getHelperFtn (CorInfoHelpFunc ftnNum, void **ppIndirection); diff --git a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h index 8394d63d4385a..31dc0f4a7cb43 100644 --- a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h +++ b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h @@ -137,8 +137,7 @@ struct JitInterfaceCallbacks unsigned (* getMethodHash)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_METHOD_HANDLE ftn); bool (* getSystemVAmd64PassStructInRegisterDescriptor)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE structHnd, SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structPassInRegDescPtr); void (* getSwiftLowering)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE structHnd, CORINFO_SWIFT_LOWERING* pLowering); - FpStructInRegistersInfo (* getLoongArch64PassFpStructInRegistersInfo)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE structHnd); - FpStructInRegistersInfo (* getRiscV64PassFpStructInRegistersInfo)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE structHnd); + FpStructInRegistersInfo (* getFpStructInRegistersInfo)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE structHnd); uint32_t (* getThreadTLSIndex)(void * thisHandle, CorInfoExceptionClass** ppException, void** ppIndirection); int32_t* (* getAddrOfCaptureThreadGlobal)(void * thisHandle, CorInfoExceptionClass** ppException, void** ppIndirection); void* (* getHelperFtn)(void * thisHandle, CorInfoExceptionClass** ppException, CorInfoHelpFunc ftnNum, void** ppIndirection); @@ -1417,20 +1416,11 @@ class JitInterfaceWrapper : public ICorJitInfo if (pException != nullptr) throw pException; } - virtual FpStructInRegistersInfo getLoongArch64PassFpStructInRegistersInfo( + virtual FpStructInRegistersInfo getFpStructInRegistersInfo( CORINFO_CLASS_HANDLE structHnd) { CorInfoExceptionClass* pException = nullptr; - FpStructInRegistersInfo temp = _callbacks->getLoongArch64PassFpStructInRegistersInfo(_thisHandle, &pException, structHnd); - if (pException != nullptr) throw pException; - return temp; -} - - virtual FpStructInRegistersInfo getRiscV64PassFpStructInRegistersInfo( - CORINFO_CLASS_HANDLE structHnd) -{ - CorInfoExceptionClass* pException = nullptr; - FpStructInRegistersInfo temp = _callbacks->getRiscV64PassFpStructInRegistersInfo(_thisHandle, &pException, structHnd); + FpStructInRegistersInfo temp = _callbacks->getFpStructInRegistersInfo(_thisHandle, &pException, structHnd); if (pException != nullptr) throw pException; return temp; } diff --git a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h index 8b88425c2e899..10210541061db 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h @@ -127,8 +127,7 @@ LWM(GetSharedCCtorHelper, DWORDLONG, DWORD) LWM(GetStringConfigValue, DWORD, DWORD) LWM(GetSystemVAmd64PassStructInRegisterDescriptor, DWORDLONG, Agnostic_GetSystemVAmd64PassStructInRegisterDescriptor) LWM(GetSwiftLowering, DWORDLONG, Agnostic_GetSwiftLowering) -LWM(GetLoongArch64PassFpStructInRegistersInfo, DWORDLONG, FpStructInRegistersInfo) -LWM(GetRiscV64PassFpStructInRegistersInfo, DWORDLONG, FpStructInRegistersInfo) +LWM(GetFpStructInRegistersInfo, DWORDLONG, FpStructInRegistersInfo) LWM(GetTailCallHelpers, Agnostic_GetTailCallHelpers, Agnostic_CORINFO_TAILCALL_HELPERS) LWM(UpdateEntryPointForTailCall, Agnostic_CORINFO_CONST_LOOKUP, Agnostic_CORINFO_CONST_LOOKUP) LWM(GetThreadTLSIndex, DWORD, DLD) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp index a1349147e0ab6..d6fcb852f050c 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp @@ -6359,59 +6359,31 @@ void MethodContext::repGetSwiftLowering(CORINFO_CLASS_HANDLE structHnd, CORINFO_ } } -void MethodContext::recGetLoongArch64PassFpStructInRegistersInfo(CORINFO_CLASS_HANDLE structHnd, FpStructInRegistersInfo value) +void MethodContext::recGetFpStructInRegistersInfo(CORINFO_CLASS_HANDLE structHnd, FpStructInRegistersInfo value) { - if (GetLoongArch64PassFpStructInRegistersInfo == nullptr) - GetLoongArch64PassFpStructInRegistersInfo = new LightWeightMap(); + if (GetFpStructInRegistersInfo == nullptr) + GetFpStructInRegistersInfo = new LightWeightMap(); DWORDLONG key = CastHandle(structHnd); - GetLoongArch64PassFpStructInRegistersInfo->Add(key, value); - DEBUG_REC(dmpGetLoongArch64PassFpStructInRegistersInfo(key, value)); + GetFpStructInRegistersInfo->Add(key, value); + DEBUG_REC(dmpGetFpStructInRegistersInfo(key, value)); } -void MethodContext::dmpGetLoongArch64PassFpStructInRegistersInfo(DWORDLONG key, FpStructInRegistersInfo value) +void MethodContext::dmpGetFpStructInRegistersInfo(DWORDLONG key, FpStructInRegistersInfo value) { - printf("GetLoongArch64PassFpStructInRegistersInfo key %016" PRIX64 " value-%#03x-" + printf("GetFpStructInRegistersInfo key %016" PRIX64 " value-%#03x-" "{%s, sizes={%u, %u}, offsets={%u, %u}, IntFieldKind=%s}\n", key, value.flags, value.FlagName(), value.Size1st(), value.Size2nd(), value.offset1st, value.offset2nd, value.IntFieldKindName()); } -FpStructInRegistersInfo MethodContext::repGetLoongArch64PassFpStructInRegistersInfo(CORINFO_CLASS_HANDLE structHnd) +FpStructInRegistersInfo MethodContext::repGetFpStructInRegistersInfo(CORINFO_CLASS_HANDLE structHnd) { DWORDLONG key = CastHandle(structHnd); - FpStructInRegistersInfo value = LookupByKeyOrMissNoMessage(GetLoongArch64PassFpStructInRegistersInfo, key); - DEBUG_REP(dmpGetLoongArch64PassFpStructInRegistersInfo(key, value)); - return value; -} - -void MethodContext::recGetRiscV64PassFpStructInRegistersInfo(CORINFO_CLASS_HANDLE structHnd, FpStructInRegistersInfo value) -{ - if (GetRiscV64PassFpStructInRegistersInfo == nullptr) - GetRiscV64PassFpStructInRegistersInfo = new LightWeightMap(); - - DWORDLONG key = CastHandle(structHnd); - - GetRiscV64PassFpStructInRegistersInfo->Add(key, value); - DEBUG_REC(dmpGetRiscV64PassFpStructInRegistersInfo(key, value)); -} - -void MethodContext::dmpGetRiscV64PassFpStructInRegistersInfo(DWORDLONG key, FpStructInRegistersInfo value) -{ - printf("GetRiscV64PassFpStructInRegistersInfo key %016" PRIX64 " value-%#03x-" - "{%s, sizes={%u, %u}, offsets={%u, %u}, IntFieldKind=%s}\n", - key, value.flags, - value.FlagName(), value.Size1st(), value.Size2nd(), value.offset1st, value.offset2nd, value.IntFieldKindName()); -} - -FpStructInRegistersInfo MethodContext::repGetRiscV64PassFpStructInRegistersInfo(CORINFO_CLASS_HANDLE structHnd) -{ - DWORDLONG key = CastHandle(structHnd); - - FpStructInRegistersInfo value = LookupByKeyOrMissNoMessage(GetRiscV64PassFpStructInRegistersInfo, key); - DEBUG_REP(dmpGetRiscV64PassFpStructInRegistersInfo(key, value)); + FpStructInRegistersInfo value = LookupByKeyOrMissNoMessage(GetFpStructInRegistersInfo, key); + DEBUG_REP(dmpGetFpStructInRegistersInfo(key, value)); return value; } diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h index dda645efcab7e..1d1998b54c31d 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h @@ -783,13 +783,9 @@ class MethodContext void dmpGetSwiftLowering(DWORDLONG key, const Agnostic_GetSwiftLowering& value); void repGetSwiftLowering(CORINFO_CLASS_HANDLE structHnd, CORINFO_SWIFT_LOWERING* pLowering); - void recGetLoongArch64PassFpStructInRegistersInfo(CORINFO_CLASS_HANDLE structHnd, FpStructInRegistersInfo value); - void dmpGetLoongArch64PassFpStructInRegistersInfo(DWORDLONG key, FpStructInRegistersInfo value); - FpStructInRegistersInfo repGetLoongArch64PassFpStructInRegistersInfo(CORINFO_CLASS_HANDLE structHnd); - - void recGetRiscV64PassFpStructInRegistersInfo(CORINFO_CLASS_HANDLE structHnd, FpStructInRegistersInfo value); - void dmpGetRiscV64PassFpStructInRegistersInfo(DWORDLONG key, FpStructInRegistersInfo value); - FpStructInRegistersInfo repGetRiscV64PassFpStructInRegistersInfo(CORINFO_CLASS_HANDLE structHnd); + void recGetFpStructInRegistersInfo(CORINFO_CLASS_HANDLE structHnd, FpStructInRegistersInfo value); + void dmpGetFpStructInRegistersInfo(DWORDLONG key, FpStructInRegistersInfo value); + FpStructInRegistersInfo repGetFpStructInRegistersInfo(CORINFO_CLASS_HANDLE structHnd); void recGetRelocTypeHint(void* target, WORD result); void dmpGetRelocTypeHint(DWORDLONG key, DWORD value); @@ -1186,8 +1182,7 @@ enum mcPackets Packet_GetClassThreadStaticDynamicInfo = 219, Packet_IsGenericType = 220, Packet_GetTypeForBoxOnStack = 221, - Packet_GetRiscV64PassFpStructInRegistersInfo = 222, - Packet_GetLoongArch64PassFpStructInRegistersInfo = 223, + Packet_GetFpStructInRegistersInfo = 222, }; void SetDebugDumpVariables(); diff --git a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp index ece088f3fc64d..1c192d4c445ee 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp @@ -1427,19 +1427,11 @@ void interceptor_ICJI::getSwiftLowering(CORINFO_CLASS_HANDLE structHnd, CORINFO_ mc->recGetSwiftLowering(structHnd, pLowering); } -FpStructInRegistersInfo interceptor_ICJI::getLoongArch64PassFpStructInRegistersInfo(CORINFO_CLASS_HANDLE structHnd) +FpStructInRegistersInfo interceptor_ICJI::getFpStructInRegistersInfo(CORINFO_CLASS_HANDLE structHnd) { - mc->cr->AddCall("getLoongArch64PassFpStructInRegistersInfo"); - FpStructInRegistersInfo temp = original_ICorJitInfo->getLoongArch64PassFpStructInRegistersInfo(structHnd); - mc->recGetLoongArch64PassFpStructInRegistersInfo(structHnd, temp); - return temp; -} - -FpStructInRegistersInfo interceptor_ICJI::getRiscV64PassFpStructInRegistersInfo(CORINFO_CLASS_HANDLE structHnd) -{ - mc->cr->AddCall("getRiscV64PassFpStructInRegistersInfo"); - FpStructInRegistersInfo temp = original_ICorJitInfo->getRiscV64PassFpStructInRegistersInfo(structHnd); - mc->recGetRiscV64PassFpStructInRegistersInfo(structHnd, temp); + mc->cr->AddCall("getFpStructInRegistersInfo"); + FpStructInRegistersInfo temp = original_ICorJitInfo->getFpStructInRegistersInfo(structHnd); + mc->recGetFpStructInRegistersInfo(structHnd, temp); return temp; } diff --git a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp index b1d7fe32fa2a7..873b96a9f3938 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp @@ -1015,18 +1015,11 @@ void interceptor_ICJI::getSwiftLowering( original_ICorJitInfo->getSwiftLowering(structHnd, pLowering); } -FpStructInRegistersInfo interceptor_ICJI::getLoongArch64PassFpStructInRegistersInfo( +FpStructInRegistersInfo interceptor_ICJI::getFpStructInRegistersInfo( CORINFO_CLASS_HANDLE structHnd) { - mcs->AddCall("getLoongArch64PassFpStructInRegistersInfo"); - return original_ICorJitInfo->getLoongArch64PassFpStructInRegistersInfo(structHnd); -} - -FpStructInRegistersInfo interceptor_ICJI::getRiscV64PassFpStructInRegistersInfo( - CORINFO_CLASS_HANDLE structHnd) -{ - mcs->AddCall("getRiscV64PassFpStructInRegistersInfo"); - return original_ICorJitInfo->getRiscV64PassFpStructInRegistersInfo(structHnd); + mcs->AddCall("getFpStructInRegistersInfo"); + return original_ICorJitInfo->getFpStructInRegistersInfo(structHnd); } uint32_t interceptor_ICJI::getThreadTLSIndex( diff --git a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp index 68591bad24aa7..6ab922b2906ce 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp @@ -889,16 +889,10 @@ void interceptor_ICJI::getSwiftLowering( original_ICorJitInfo->getSwiftLowering(structHnd, pLowering); } -FpStructInRegistersInfo interceptor_ICJI::getLoongArch64PassFpStructInRegistersInfo( +FpStructInRegistersInfo interceptor_ICJI::getFpStructInRegistersInfo( CORINFO_CLASS_HANDLE structHnd) { - return original_ICorJitInfo->getLoongArch64PassFpStructInRegistersInfo(structHnd); -} - -FpStructInRegistersInfo interceptor_ICJI::getRiscV64PassFpStructInRegistersInfo( - CORINFO_CLASS_HANDLE structHnd) -{ - return original_ICorJitInfo->getRiscV64PassFpStructInRegistersInfo(structHnd); + return original_ICorJitInfo->getFpStructInRegistersInfo(structHnd); } uint32_t interceptor_ICJI::getThreadTLSIndex( diff --git a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp index 7fc98ac548ef5..7915ccdf3c242 100644 --- a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp @@ -1258,16 +1258,10 @@ void MyICJI::getSwiftLowering(CORINFO_CLASS_HANDLE structHnd, CORINFO_SWIFT_LOWE jitInstance->mc->repGetSwiftLowering(structHnd, pLowering); } -FpStructInRegistersInfo MyICJI::getLoongArch64PassFpStructInRegistersInfo(CORINFO_CLASS_HANDLE structHnd) +FpStructInRegistersInfo MyICJI::getFpStructInRegistersInfo(CORINFO_CLASS_HANDLE structHnd) { - jitInstance->mc->cr->AddCall("getLoongArch64PassFpStructInRegistersInfo"); - return jitInstance->mc->repGetLoongArch64PassFpStructInRegistersInfo(structHnd); -} - -FpStructInRegistersInfo MyICJI::getRiscV64PassFpStructInRegistersInfo(CORINFO_CLASS_HANDLE structHnd) -{ - jitInstance->mc->cr->AddCall("getRiscV64PassFpStructInRegistersInfo"); - return jitInstance->mc->repGetRiscV64PassFpStructInRegistersInfo(structHnd); + jitInstance->mc->cr->AddCall("getFpStructInRegistersInfo"); + return jitInstance->mc->repGetFpStructInRegistersInfo(structHnd); } // Stuff on ICorDynamicInfo diff --git a/src/coreclr/vm/callingconvention.h b/src/coreclr/vm/callingconvention.h index 54fbea3dd66eb..e2bf88af122f8 100644 --- a/src/coreclr/vm/callingconvention.h +++ b/src/coreclr/vm/callingconvention.h @@ -1693,7 +1693,7 @@ int ArgIteratorTemplate::GetNextOffset() } else { - info = MethodTable::GetLoongArch64PassFpStructInRegistersInfo(thValueType); + info = MethodTable::GetFpStructInRegistersInfo(thValueType); if (info.flags != FpStruct::UseIntCallConv) { cFPRegs = (info.flags & FpStruct::BothFloat) ? 2 : 1; @@ -1813,7 +1813,7 @@ int ArgIteratorTemplate::GetNextOffset() } else { - info = MethodTable::GetRiscV64PassFpStructInRegistersInfo(thValueType); + info = MethodTable::GetFpStructInRegistersInfo(thValueType); if (info.flags != FpStruct::UseIntCallConv) { cFPRegs = (info.flags & FpStruct::BothFloat) ? 2 : 1; @@ -2021,7 +2021,7 @@ void ArgIteratorTemplate::ComputeReturnFlags() if (size <= ENREGISTERED_RETURNTYPE_INTEGER_MAXSIZE) { assert(!thValueType.IsTypeDesc()); - FpStructInRegistersInfo info = MethodTable::GetLoongArch64PassFpStructInRegistersInfo(thValueType); + FpStructInRegistersInfo info = MethodTable::GetFpStructInRegistersInfo(thValueType); flags |= info.flags << RETURN_FP_SIZE_SHIFT; break; } @@ -2029,7 +2029,7 @@ void ArgIteratorTemplate::ComputeReturnFlags() if (size <= ENREGISTERED_RETURNTYPE_INTEGER_MAXSIZE) { assert(!thValueType.IsTypeDesc()); - FpStructInRegistersInfo info = MethodTable::GetRiscV64PassFpStructInRegistersInfo(thValueType); + FpStructInRegistersInfo info = MethodTable::GetFpStructInRegistersInfo(thValueType); flags |= info.flags << RETURN_FP_SIZE_SHIFT; break; } diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index ef060cf1dbc21..97a33b47b9257 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -9520,8 +9520,8 @@ CorInfoTypeWithMod CEEInfo::getArgType ( // These depends on the platform's ABI rules. // // The returned value's encoding details how a struct argument uses float registers: -// see the enum `StructFloatFieldInfoFlags`. -FpStructInRegistersInfo CEEInfo::getLoongArch64PassFpStructInRegistersInfo(CORINFO_CLASS_HANDLE cls) +// see the struct `FpStructInRegistersInfo`. +FpStructInRegistersInfo CEEInfo::getFpStructInRegistersInfo(CORINFO_CLASS_HANDLE cls) { CONTRACTL { NOTHROW; @@ -9533,30 +9533,9 @@ FpStructInRegistersInfo CEEInfo::getLoongArch64PassFpStructInRegistersInfo(CORIN FpStructInRegistersInfo info = {}; -#if defined(TARGET_LOONGARCH64) - info = MethodTable::GetLoongArch64PassFpStructInRegistersInfo(TypeHandle(cls)); -#endif // TARGET_LOONGARCH64 - - EE_TO_JIT_TRANSITION_LEAF(); - - return info; -} - -FpStructInRegistersInfo CEEInfo::getRiscV64PassFpStructInRegistersInfo(CORINFO_CLASS_HANDLE cls) -{ - CONTRACTL { - NOTHROW; - GC_NOTRIGGER; - MODE_PREEMPTIVE; - } CONTRACTL_END; - - JIT_TO_EE_TRANSITION_LEAF(); - - FpStructInRegistersInfo info = {}; - -#if defined(TARGET_RISCV64) - info = MethodTable::GetRiscV64PassFpStructInRegistersInfo(TypeHandle(cls)); -#endif // TARGET_RISCV64 +#if defined(TARGET_RISCV64) || defined(TARGET_LOONGARCH64) + info = MethodTable::GetFpStructInRegistersInfo(TypeHandle(cls)); +#endif // TARGET_RISCV64 || TARGET_LOONGARCH64 EE_TO_JIT_TRANSITION_LEAF(); diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index b9fb1aedee8f5..68c0d145a12af 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -2948,11 +2948,7 @@ static bool FlattenFields(TypeHandle th, uint32_t offset, FpStructInRegistersInf return true; } -#if defined(TARGET_RISCV64) -FpStructInRegistersInfo MethodTable::GetRiscV64PassFpStructInRegistersInfo(TypeHandle th) -#elif defined(TARGET_LOONGARCH64) -FpStructInRegistersInfo MethodTable::GetLoongArch64PassFpStructInRegistersInfo(TypeHandle th) -#endif +FpStructInRegistersInfo MethodTable::GetFpStructInRegistersInfo(TypeHandle th) { if (th.GetSize() > ENREGISTERED_PARAMTYPE_MAXSIZE) { diff --git a/src/coreclr/vm/methodtable.h b/src/coreclr/vm/methodtable.h index 1786fb0ab5897..8d549084c4146 100644 --- a/src/coreclr/vm/methodtable.h +++ b/src/coreclr/vm/methodtable.h @@ -1011,10 +1011,8 @@ class MethodTable // during object construction. void CheckRunClassInitAsIfConstructingThrowing(); -#if defined(TARGET_LOONGARCH64) - static FpStructInRegistersInfo GetLoongArch64PassFpStructInRegistersInfo(TypeHandle th); -#elif defined(TARGET_RISCV64) - static FpStructInRegistersInfo GetRiscV64PassFpStructInRegistersInfo(TypeHandle th); +#if defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) + static FpStructInRegistersInfo GetFpStructInRegistersInfo(TypeHandle th); #endif #if defined(UNIX_AMD64_ABI_ITF) From 5c9e5acc9a6ddb08988ff2b33b4a764fa53320ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomek=20Sowi=C5=84ski?= Date: Thu, 4 Jul 2024 15:41:04 +0200 Subject: [PATCH 24/35] Use JIT_TO_EE_TRANSITION instead of _LEAF because MethodTable::GetFpStructInRegistersInfo may throw --- src/coreclr/vm/jitinterface.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 97a33b47b9257..3c855b0e78ac3 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -9529,15 +9529,15 @@ FpStructInRegistersInfo CEEInfo::getFpStructInRegistersInfo(CORINFO_CLASS_HANDLE MODE_PREEMPTIVE; } CONTRACTL_END; - JIT_TO_EE_TRANSITION_LEAF(); - FpStructInRegistersInfo info = {}; + JIT_TO_EE_TRANSITION(); + #if defined(TARGET_RISCV64) || defined(TARGET_LOONGARCH64) info = MethodTable::GetFpStructInRegistersInfo(TypeHandle(cls)); #endif // TARGET_RISCV64 || TARGET_LOONGARCH64 - EE_TO_JIT_TRANSITION_LEAF(); + EE_TO_JIT_TRANSITION(); return info; } From 1d5ad91db86c628ba5aa84a2cfd40091a4f0445c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomek=20Sowi=C5=84ski?= Date: Thu, 4 Jul 2024 16:06:58 +0200 Subject: [PATCH 25/35] Remove FpStruct::IntKind, we should have similar info in ClassLayout in JIT --- src/coreclr/inc/corinfo.h | 22 ------------ src/coreclr/jit/compiler.cpp | 4 +-- .../tools/Common/JitInterface/CorInfoTypes.cs | 14 -------- .../LoongArch64PassStructInRegister.cs | 35 ++----------------- .../RiscV64PassFpStructInRegisters.cs | 35 ++----------------- .../superpmi-shared/methodcontext.cpp | 4 +-- src/coreclr/vm/methodtable.cpp | 35 ++++--------------- 7 files changed, 16 insertions(+), 133 deletions(-) diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index 0ac854dae862c..ba16c9405c14c 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -349,13 +349,6 @@ enum StructFloatFieldInfoFlags // Bitfields for FpStructInRegistersInfo::flags namespace FpStruct { - enum class IntKind - { - Integer, - GcRef, - GcByRef, - }; - enum Flags { // Positions of flags and bitfields @@ -365,7 +358,6 @@ namespace FpStruct PosIntFloat = 3, PosSizeShift1st = 4, // 2 bits PosSizeShift2nd = 6, // 2 bits - PosIntFieldKind = 8, // 2 bits UseIntCallConv = 0, // struct is passed according to integer calling convention @@ -376,7 +368,6 @@ namespace FpStruct IntFloat = 1 << PosIntFloat, // has two fields, 2nd is floating and 1st is integer SizeShift1stMask = 0b11 << PosSizeShift1st, // log2(size) of 1st field SizeShift2ndMask = 0b11 << PosSizeShift2nd, // log2(size) of 2nd field - IntFieldKindMask = 0b11 << PosIntFieldKind, // the kind of the integer field (FpStruct::IntKind) // Note: flags OnlyOne, BothFloat, FloatInt, and IntFloat are mutually exclusive }; } @@ -396,19 +387,6 @@ struct FpStructInRegistersInfo unsigned Size1st() const { return 1u << SizeShift1st(); } unsigned Size2nd() const { return 1u << SizeShift2nd(); } - FpStruct::IntKind IntFieldKind() const - { - return (FpStruct::IntKind)((flags >> FpStruct::PosIntFieldKind) & 0b11); - } - - const char* IntFieldKindName() const - { - static const char* intKindNames[] = { "Integer", "GcRef", "GcByRef" }; - return (flags & (FpStruct::FloatInt | FpStruct::IntFloat)) - ? intKindNames[(int)IntFieldKind()] - : "None"; - } - const char* FlagName() const { switch (flags & (FpStruct::OnlyOne | FpStruct::BothFloat | FpStruct::FloatInt | FpStruct::IntFloat)) diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp index 0dff2cc8dc31f..572898117142c 100644 --- a/src/coreclr/jit/compiler.cpp +++ b/src/coreclr/jit/compiler.cpp @@ -8312,8 +8312,8 @@ FpStructInRegistersInfo Compiler::GetPassFpStructInRegistersInfo(CORINFO_CLASS_H long size2nd = hasOne ? -1l : ret.Size2nd(); long offset2nd = hasOne ? -1l : ret.offset2nd; printf(" may be passed by floating-point calling convention:\n" - " flags=%#03x; %s, field sizes={%u, %li}, field offsets={%u, %li}, IntFieldKind=%s\n", - ret.flags, ret.FlagName(), ret.Size1st(), size2nd, ret.offset1st, offset2nd, ret.IntFieldKindName()); + " flags=%#03x; %s, field sizes={%u, %li}, field offsets={%u, %li}\n", + ret.flags, ret.FlagName(), ret.Size1st(), size2nd, ret.offset1st, offset2nd); } } #endif // DEBUG diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs index 8c94d4b2b6068..17cedca046e33 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs @@ -1252,13 +1252,6 @@ public enum StructFloatFieldInfoFlags }; - public enum FpStruct_IntKind - { - Integer, - GcRef, - GcByRef, - } - // Bitfields for FpStructInRegistersInfo.flags [Flags] public enum FpStruct @@ -1270,7 +1263,6 @@ public enum FpStruct PosIntFloat = 3, PosSizeShift1st = 4, // 2 bits PosSizeShift2nd = 6, // 2 bits - PosIntFieldKind = 8, // 2 bits UseIntCallConv = 0, // struct is passed according to integer calling convention @@ -1281,7 +1273,6 @@ public enum FpStruct IntFloat = 1 << PosIntFloat, // has two fields, 2nd is floating and 1st is integer SizeShift1stMask = 0b11 << PosSizeShift1st, // log2(size) of 1st field SizeShift2ndMask = 0b11 << PosSizeShift2nd, // log2(size) of 2nd field - IntFieldKindMask = 0b11 << PosIntFieldKind, // the kind of the integer field (FpStruct::IntKind) // Note: flags OnlyOne, BothFloat, FloatInt, and IntFloat are mutually exclusive } @@ -1301,11 +1292,6 @@ public struct FpStructInRegistersInfo public uint Size1st() { return 1u << (int)SizeShift1st(); } public uint Size2nd() { return 1u << (int)SizeShift2nd(); } - public FpStruct_IntKind IntFieldKind() - { - return (FpStruct_IntKind)(((int)flags >> (int)FpStruct.PosIntFieldKind) & 0b11); - } - public StructFloatFieldInfoFlags ToOldFlags() { return diff --git a/src/coreclr/tools/Common/JitInterface/LoongArch64PassStructInRegister.cs b/src/coreclr/tools/Common/JitInterface/LoongArch64PassStructInRegister.cs index 5d83392312a80..7db7743db4f10 100644 --- a/src/coreclr/tools/Common/JitInterface/LoongArch64PassStructInRegister.cs +++ b/src/coreclr/tools/Common/JitInterface/LoongArch64PassStructInRegister.cs @@ -16,16 +16,11 @@ private const int TARGET_POINTER_SIZE = 8; private static void SetFpStructInRegistersInfoField(ref FpStructInRegistersInfo info, int index, - bool isFloating, FpStruct_IntKind intKind, uint size, uint offset) + bool isFloating, uint size, uint offset) { Debug.Assert(index < 2); if (isFloating) - { Debug.Assert(size == sizeof(float) || size == sizeof(double)); - Debug.Assert(intKind == FpStruct_IntKind.Integer); - Debug.Assert((int)FpStruct_IntKind.Integer == 0, - "IntKind for floating fields should not clobber IntKind for int fields"); - } Debug.Assert(size >= 1 && size <= 8); Debug.Assert((size & (size - 1)) == 0, "size needs to be a power of 2"); @@ -39,7 +34,7 @@ private static void SetFpStructInRegistersInfoField(ref FpStructInRegistersInfo int floatFlag = Convert.ToInt32(isFloating) << ((int)PosFloatInt + index); int sizeShiftMask = sizeShift << ((int)PosSizeShift1st + 2 * index); - info.flags |= (FpStruct)(floatFlag | sizeShiftMask | ((int)intKind << (int)PosIntFieldKind)); + info.flags |= (FpStruct)(floatFlag | sizeShiftMask); (index == 0 ? ref info.offset1st : ref info.offset2nd) = offset; } @@ -109,19 +104,8 @@ private static bool FlattenFields(TypeDesc td, uint offset, ref FpStructInRegist return false; // too many fields bool isFloating = category is TypeFlags.Single or TypeFlags.Double; - bool isGcRef = category is - TypeFlags.Class or - TypeFlags.Interface or - TypeFlags.Array or - TypeFlags.SzArray; - - FpStruct_IntKind intKind = - isGcRef ? FpStruct_IntKind.GcRef : - (category is TypeFlags.ByRef) ? FpStruct_IntKind.GcByRef : - FpStruct_IntKind.Integer; - SetFpStructInRegistersInfoField(ref info, typeIndex++, - isFloating, intKind, (uint)field.FieldType.GetElementSize().AsInt, offset + (uint)field.Offset.AsInt); + isFloating, (uint)field.FieldType.GetElementSize().AsInt, offset + (uint)field.Offset.AsInt); } else { @@ -182,19 +166,6 @@ public static FpStructInRegistersInfo GetLoongArch64PassFpStructInRegistersInfo( Debug.Assert(info.offset1st + info.Size1st() <= td.GetElementSize().AsInt); Debug.Assert(info.offset2nd + info.Size2nd() <= td.GetElementSize().AsInt); - FpStruct_IntKind intKind = info.IntFieldKind(); - if (intKind != FpStruct_IntKind.Integer) - { - Debug.Assert((info.flags & (FloatInt | IntFloat)) != 0); - - Debug.Assert(intKind == FpStruct_IntKind.GcRef || intKind == FpStruct_IntKind.GcByRef); - Debug.Assert((info.flags & IntFloat) != 0 - ? ((info.SizeShift1st() == 3) && IsAligned(info.offset1st, TARGET_POINTER_SIZE)) - : ((info.SizeShift2nd() == 3) && IsAligned(info.offset2nd, TARGET_POINTER_SIZE))); - } - if ((info.flags & (OnlyOne | BothFloat)) != 0) - Debug.Assert(intKind == FpStruct_IntKind.Integer); - return info; } } diff --git a/src/coreclr/tools/Common/JitInterface/RiscV64PassFpStructInRegisters.cs b/src/coreclr/tools/Common/JitInterface/RiscV64PassFpStructInRegisters.cs index 961477fa55983..7dfba63e1d836 100644 --- a/src/coreclr/tools/Common/JitInterface/RiscV64PassFpStructInRegisters.cs +++ b/src/coreclr/tools/Common/JitInterface/RiscV64PassFpStructInRegisters.cs @@ -16,16 +16,11 @@ private const int TARGET_POINTER_SIZE = 8; private static void SetFpStructInRegistersInfoField(ref FpStructInRegistersInfo info, int index, - bool isFloating, FpStruct_IntKind intKind, uint size, uint offset) + bool isFloating, uint size, uint offset) { Debug.Assert(index < 2); if (isFloating) - { Debug.Assert(size == sizeof(float) || size == sizeof(double)); - Debug.Assert(intKind == FpStruct_IntKind.Integer); - Debug.Assert((int)FpStruct_IntKind.Integer == 0, - "IntKind for floating fields should not clobber IntKind for int fields"); - } Debug.Assert(size >= 1 && size <= 8); Debug.Assert((size & (size - 1)) == 0, "size needs to be a power of 2"); @@ -39,7 +34,7 @@ private static void SetFpStructInRegistersInfoField(ref FpStructInRegistersInfo int floatFlag = Convert.ToInt32(isFloating) << ((int)PosFloatInt + index); int sizeShiftMask = sizeShift << ((int)PosSizeShift1st + 2 * index); - info.flags |= (FpStruct)(floatFlag | sizeShiftMask | ((int)intKind << (int)PosIntFieldKind)); + info.flags |= (FpStruct)(floatFlag | sizeShiftMask); (index == 0 ? ref info.offset1st : ref info.offset2nd) = offset; } @@ -109,19 +104,8 @@ private static bool FlattenFields(TypeDesc td, uint offset, ref FpStructInRegist return false; // too many fields bool isFloating = category is TypeFlags.Single or TypeFlags.Double; - bool isGcRef = category is - TypeFlags.Class or - TypeFlags.Interface or - TypeFlags.Array or - TypeFlags.SzArray; - - FpStruct_IntKind intKind = - isGcRef ? FpStruct_IntKind.GcRef : - (category is TypeFlags.ByRef) ? FpStruct_IntKind.GcByRef : - FpStruct_IntKind.Integer; - SetFpStructInRegistersInfoField(ref info, typeIndex++, - isFloating, intKind, (uint)field.FieldType.GetElementSize().AsInt, offset + (uint)field.Offset.AsInt); + isFloating, (uint)field.FieldType.GetElementSize().AsInt, offset + (uint)field.Offset.AsInt); } else { @@ -182,19 +166,6 @@ public static FpStructInRegistersInfo GetRiscV64PassFpStructInRegistersInfo(Type Debug.Assert(info.offset1st + info.Size1st() <= td.GetElementSize().AsInt); Debug.Assert(info.offset2nd + info.Size2nd() <= td.GetElementSize().AsInt); - FpStruct_IntKind intKind = info.IntFieldKind(); - if (intKind != FpStruct_IntKind.Integer) - { - Debug.Assert((info.flags & (FloatInt | IntFloat)) != 0); - - Debug.Assert(intKind == FpStruct_IntKind.GcRef || intKind == FpStruct_IntKind.GcByRef); - Debug.Assert((info.flags & IntFloat) != 0 - ? ((info.SizeShift1st() == 3) && IsAligned(info.offset1st, TARGET_POINTER_SIZE)) - : ((info.SizeShift2nd() == 3) && IsAligned(info.offset2nd, TARGET_POINTER_SIZE))); - } - if ((info.flags & (OnlyOne | BothFloat)) != 0) - Debug.Assert(intKind == FpStruct_IntKind.Integer); - return info; } } diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp index d6fcb852f050c..f301f143d44e3 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp @@ -6373,9 +6373,9 @@ void MethodContext::recGetFpStructInRegistersInfo(CORINFO_CLASS_HANDLE structHnd void MethodContext::dmpGetFpStructInRegistersInfo(DWORDLONG key, FpStructInRegistersInfo value) { printf("GetFpStructInRegistersInfo key %016" PRIX64 " value-%#03x-" - "{%s, sizes={%u, %u}, offsets={%u, %u}, IntFieldKind=%s}\n", + "{%s, sizes={%u, %u}, offsets={%u, %u}}\n", key, value.flags, - value.FlagName(), value.Size1st(), value.Size2nd(), value.offset1st, value.offset2nd, value.IntFieldKindName()); + value.FlagName(), value.Size1st(), value.Size2nd(), value.offset1st, value.offset2nd); } FpStructInRegistersInfo MethodContext::repGetFpStructInRegistersInfo(CORINFO_CLASS_HANDLE structHnd) diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index 68c0d145a12af..3c1618134fde0 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -2734,16 +2734,11 @@ void MethodTable::AssignClassifiedEightByteTypes(SystemVStructRegisterPassingHe #if defined(TARGET_RISCV64) || defined(TARGET_LOONGARCH64) static void SetFpStructInRegistersInfoField(FpStructInRegistersInfo& info, int index, - bool isFloating, FpStruct::IntKind intKind, unsigned size, uint32_t offset) + bool isFloating, unsigned size, uint32_t offset) { assert(index < 2); if (isFloating) - { assert(size == sizeof(float) || size == sizeof(double)); - assert(intKind == FpStruct::IntKind::Integer); - static_assert((int)FpStruct::IntKind::Integer == 0, - "IntKind for floating fields should not clobber IntKind for int fields"); - } assert(size >= 1 && size <= 8); assert((size & (size - 1)) == 0); // size needs to be a power of 2 @@ -2758,7 +2753,7 @@ static void SetFpStructInRegistersInfoField(FpStructInRegistersInfo& info, int i int floatFlag = isFloating << (PosFloatInt + index); int sizeShiftMask = sizeShift << (PosSizeShift1st + 2 * index); - info.flags = FpStruct::Flags(info.flags | floatFlag | sizeShiftMask | ((int)intKind << PosIntFieldKind)); + info.flags = FpStruct::Flags(info.flags | floatFlag | sizeShiftMask); (index == 0 ? info.offset1st : info.offset2nd) = offset; } @@ -2856,14 +2851,8 @@ static bool FlattenFields(TypeHandle th, uint32_t offset, FpStructInRegistersInf } bool isFloating = CorTypeInfo::IsFloat_NoThrow(type); - CorInfoGCType gcType = CorTypeInfo::GetGCType_NoThrow(type); - FpStruct::IntKind intKind = - (gcType == TYPE_GC_REF) ? FpStruct::IntKind::GcRef : - (gcType == TYPE_GC_BYREF) ? FpStruct::IntKind::GcByRef : - FpStruct::IntKind::Integer; - SetFpStructInRegistersInfoField(info, typeIndex++, - isFloating, intKind, CorTypeInfo::Size_NoThrow(type), offset + fields[i].GetOffset()); + isFloating, CorTypeInfo::Size_NoThrow(type), offset + fields[i].GetOffset()); LOG((LF_JIT, LL_EVERYTHING, "FpStructInRegistersInfo:%*s * found field %s [%i..%i), type: %s\n", nestingLevel * 4, "", fields[i].GetDebugName(), @@ -2929,7 +2918,7 @@ static bool FlattenFields(TypeHandle th, uint32_t offset, FpStructInRegistersInf bool isFloating = (category == NativeFieldCategory::FLOAT); SetFpStructInRegistersInfoField(info, typeIndex++, - isFloating, FpStruct::IntKind::Integer, fields[i].NativeSize(), offset + fields[i].GetExternalOffset()); + isFloating, fields[i].NativeSize(), offset + fields[i].GetExternalOffset()); LOG((LF_JIT, LL_EVERYTHING, "FpStructInRegistersInfo:%*s * found field %s [%i..%i), type: %s\n", nestingLevel * 4, "", fields[i].GetFieldDesc()->GetDebugName(), @@ -2997,23 +2986,11 @@ FpStructInRegistersInfo MethodTable::GetFpStructInRegistersInfo(TypeHandle th) assert(info.offset1st + info.Size1st() <= th.GetSize()); assert(info.offset2nd + info.Size2nd() <= th.GetSize()); - FpStruct::IntKind intKind = info.IntFieldKind(); - if (intKind != FpStruct::IntKind::Integer) - { - assert(info.flags & (FloatInt | IntFloat)); - assert(intKind == FpStruct::IntKind::GcRef || intKind == FpStruct::IntKind::GcByRef); - assert((info.flags & IntFloat) != 0 - ? ((info.SizeShift1st() == 3) && IS_ALIGNED(info.offset1st, TARGET_POINTER_SIZE)) - : ((info.SizeShift2nd() == 3) && IS_ALIGNED(info.offset2nd, TARGET_POINTER_SIZE))); - } - if (info.flags & (OnlyOne | BothFloat)) - assert(intKind == FpStruct::IntKind::Integer); - LOG((LF_JIT, LL_EVERYTHING, "FpStructInRegistersInfo: " "struct %s (%u bytes) can be passed with floating-point calling convention, flags=%#03x; " - "%s, sizes={%u, %u}, offsets={%u, %u}, IntFieldKindMask=%s\n", + "%s, sizes={%u, %u}, offsets={%u, %u}\n", (!th.IsTypeDesc() ? th.AsMethodTable() : th.AsNativeValueType())->GetDebugClassName(), th.GetSize(), info.flags, - info.FlagName(), info.Size1st(), info.Size2nd(), info.offset1st, info.offset2nd, info.IntFieldKindName() + info.FlagName(), info.Size1st(), info.Size2nd(), info.offset1st, info.offset2nd )); return info; } From 7b1587ba96823d7c6d809b5a3e22051d5d053344 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomek=20Sowi=C5=84ski?= Date: Mon, 8 Jul 2024 08:39:31 +0200 Subject: [PATCH 26/35] Change JIT interface to return a struct similar to CORINFO_SWIFT_LOWERING to facilitate code unification in the future --- src/coreclr/inc/corinfo.h | 16 +++++- src/coreclr/inc/icorjitinfoimpl_generated.h | 5 +- src/coreclr/inc/jiteeversionguid.h | 10 ++-- src/coreclr/jit/ICorJitInfo_names_generated.h | 2 +- .../jit/ICorJitInfo_wrapper_generated.hpp | 12 ++--- src/coreclr/jit/compiler.cpp | 18 +++---- .../tools/Common/JitInterface/CorInfoImpl.cs | 22 ++++++-- .../JitInterface/CorInfoImpl_generated.cs | 7 ++- .../tools/Common/JitInterface/CorInfoTypes.cs | 54 +++++++++++++++++++ .../ThunkGenerator/ThunkInput.txt | 4 +- .../aot/jitinterface/jitinterface_generated.h | 10 ++-- .../tools/superpmi/superpmi-shared/agnostic.h | 8 +++ .../tools/superpmi/superpmi-shared/lwmlist.h | 2 +- .../superpmi-shared/methodcontext.cpp | 54 +++++++++++++------ .../superpmi/superpmi-shared/methodcontext.h | 8 +-- .../superpmi-shim-collector/icorjitinfo.cpp | 9 ++-- .../icorjitinfo_generated.cpp | 9 ++-- .../icorjitinfo_generated.cpp | 7 +-- .../tools/superpmi/superpmi/icorjitinfo.cpp | 6 +-- src/coreclr/vm/jitinterface.cpp | 49 +++++++++++++---- 20 files changed, 226 insertions(+), 86 deletions(-) diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index ba16c9405c14c..ba44b7ae0681d 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -2025,6 +2025,18 @@ struct CORINFO_SWIFT_LOWERING size_t numLoweredElements; }; +#define MAX_FPSTRUCT_LOWERED_ELEMENTS 2 + +// Lowering information on fields of a struct passed by hardware floating-point calling convention +// on RISC-V and LoongArch +struct CORINFO_FPSTRUCT_LOWERING +{ + bool byIntegerCallConv; + CorInfoType loweredElements[MAX_FPSTRUCT_LOWERED_ELEMENTS]; + uint32_t offsets[MAX_FPSTRUCT_LOWERED_ELEMENTS]; + size_t numLoweredElements; +}; + #define SIZEOF__CORINFO_Object TARGET_POINTER_SIZE /* methTable */ #define CORINFO_Array_MaxLength 0x7FFFFFC7 @@ -3138,9 +3150,9 @@ class ICorStaticInfo // Classifies a swift structure into primitives or an implicit byref for ABI purposes. virtual void getSwiftLowering(CORINFO_CLASS_HANDLE structHnd, CORINFO_SWIFT_LOWERING* pLowering) = 0; - // Returns passing info for a RISC-V/LoongArch struct passed in registers according to + // Returns lowering info for fields of a RISC-V/LoongArch struct passed in registers according to // hardware floating-point calling convention. - virtual FpStructInRegistersInfo getFpStructInRegistersInfo(CORINFO_CLASS_HANDLE cls) = 0; + virtual void getFpStructLowering(CORINFO_CLASS_HANDLE structHnd, CORINFO_FPSTRUCT_LOWERING* pLowering) = 0; }; /***************************************************************************** diff --git a/src/coreclr/inc/icorjitinfoimpl_generated.h b/src/coreclr/inc/icorjitinfoimpl_generated.h index d05a544c9636a..17b8d0850e116 100644 --- a/src/coreclr/inc/icorjitinfoimpl_generated.h +++ b/src/coreclr/inc/icorjitinfoimpl_generated.h @@ -520,8 +520,9 @@ void getSwiftLowering( CORINFO_CLASS_HANDLE structHnd, CORINFO_SWIFT_LOWERING* pLowering) override; -FpStructInRegistersInfo getFpStructInRegistersInfo( - CORINFO_CLASS_HANDLE structHnd) override; +void getFpStructLowering( + CORINFO_CLASS_HANDLE structHnd, + CORINFO_FPSTRUCT_LOWERING* pLowering) override; uint32_t getThreadTLSIndex( void** ppIndirection) override; diff --git a/src/coreclr/inc/jiteeversionguid.h b/src/coreclr/inc/jiteeversionguid.h index aeb9577a41159..7da2a191374ef 100644 --- a/src/coreclr/inc/jiteeversionguid.h +++ b/src/coreclr/inc/jiteeversionguid.h @@ -43,11 +43,11 @@ typedef const GUID *LPCGUID; #define GUID_DEFINED #endif // !GUID_DEFINED -constexpr GUID JITEEVersionIdentifier = { /* 78d1a298-7336-42d2-b1ae-47d38f69034b */ - 0x78d1a298, - 0x7336, - 0x42d2, - {0xb1, 0xae, 0x47, 0xd3, 0x8f, 0x69, 0x03, 0x4b} +constexpr GUID JITEEVersionIdentifier = { /* aecacf5a-be3e-4504-b16f-5913736f1716 */ + 0xaecacf5a, + 0xbe3e, + 0x4504, + {0xb1, 0x6f, 0x59, 0x13, 0x73, 0x6f, 0x17, 0x16} }; ////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/coreclr/jit/ICorJitInfo_names_generated.h b/src/coreclr/jit/ICorJitInfo_names_generated.h index a7a0c7dc39f98..fcd7335649de4 100644 --- a/src/coreclr/jit/ICorJitInfo_names_generated.h +++ b/src/coreclr/jit/ICorJitInfo_names_generated.h @@ -130,7 +130,7 @@ DEF_CLR_API(getMethodNameFromMetadata) DEF_CLR_API(getMethodHash) DEF_CLR_API(getSystemVAmd64PassStructInRegisterDescriptor) DEF_CLR_API(getSwiftLowering) -DEF_CLR_API(getFpStructInRegistersInfo) +DEF_CLR_API(getFpStructLowering) DEF_CLR_API(getThreadTLSIndex) DEF_CLR_API(getAddrOfCaptureThreadGlobal) DEF_CLR_API(getHelperFtn) diff --git a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp index d3071cea2b48c..fd87534b6030e 100644 --- a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp +++ b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp @@ -1238,13 +1238,13 @@ void WrapICorJitInfo::getSwiftLowering( API_LEAVE(getSwiftLowering); } -FpStructInRegistersInfo WrapICorJitInfo::getFpStructInRegistersInfo( - CORINFO_CLASS_HANDLE structHnd) +void WrapICorJitInfo::getFpStructLowering( + CORINFO_CLASS_HANDLE structHnd, + CORINFO_FPSTRUCT_LOWERING* pLowering) { - API_ENTER(getFpStructInRegistersInfo); - FpStructInRegistersInfo temp = wrapHnd->getFpStructInRegistersInfo(structHnd); - API_LEAVE(getFpStructInRegistersInfo); - return temp; + API_ENTER(getFpStructLowering); + wrapHnd->getFpStructLowering(structHnd, pLowering); + API_LEAVE(getFpStructLowering); } uint32_t WrapICorJitInfo::getThreadTLSIndex( diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp index 572898117142c..794a2fff5d06d 100644 --- a/src/coreclr/jit/compiler.cpp +++ b/src/coreclr/jit/compiler.cpp @@ -8295,29 +8295,29 @@ void Compiler::GetStructTypeOffset( // The passing info FpStructInRegistersInfo Compiler::GetPassFpStructInRegistersInfo(CORINFO_CLASS_HANDLE structHandle) { - FpStructInRegistersInfo ret = info.compCompHnd->getFpStructInRegistersInfo(structHandle); + CORINFO_FPSTRUCT_LOWERING lowering; + info.compCompHnd->getFpStructLowering(structHandle, &lowering); #ifdef DEBUG if (verbose) { printf("**** getFpStructInRegistersInfo(0x%x (%s, %u bytes)) =>\n", dspPtr(structHandle), eeGetClassName(structHandle), info.compCompHnd->getClassSize(structHandle)); #undef getInfoFunc - if (ret.flags == FpStruct::UseIntCallConv) + if (lowering.byIntegerCallConv) { printf(" pass by integer calling convention\n"); } else { - bool hasOne = ((ret.flags & FpStruct::OnlyOne) != 0); - long size2nd = hasOne ? -1l : ret.Size2nd(); - long offset2nd = hasOne ? -1l : ret.offset2nd; - printf(" may be passed by floating-point calling convention:\n" - " flags=%#03x; %s, field sizes={%u, %li}, field offsets={%u, %li}\n", - ret.flags, ret.FlagName(), ret.Size1st(), size2nd, ret.offset1st, offset2nd); + printf(" may be passed by floating-point calling convention (%zu fields):\n", lowering.numLoweredElements); + for (size_t i = 0; i < lowering.numLoweredElements; ++i) + { + printf(" * field[%zu]: type %i at offset %u\n", i, lowering.loweredElements[i], lowering.offsets[i]); + } } } #endif // DEBUG - return ret; + return {}; } #endif // defined(UNIX_AMD64_ABI) diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index 0d335d5b0d26e..3dbd27aa2c045 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -3454,22 +3454,34 @@ private void getSwiftLowering(CORINFO_CLASS_STRUCT_* structHnd, ref CORINFO_SWIF lowering = SwiftPhysicalLowering.LowerTypeForSwiftSignature(HandleToObject(structHnd)); } - private FpStructInRegistersInfo getFpStructInRegistersInfo(CORINFO_CLASS_STRUCT_* cls) + private void getFpStructLowering(CORINFO_CLASS_STRUCT_* structHnd, ref CORINFO_FPSTRUCT_LOWERING lowering) { - TypeDesc typeDesc = HandleToObject(cls); + TypeDesc typeDesc = HandleToObject(structHnd); var target = _compilation.TypeSystemContext.Target; + FpStructInRegistersInfo info; if (target.Architecture is TargetArchitecture.RiscV64) { - return RiscV64PassFpStructInRegisters.GetRiscV64PassFpStructInRegistersInfo(typeDesc); + info = RiscV64PassFpStructInRegisters.GetRiscV64PassFpStructInRegistersInfo(typeDesc); } else if (target.Architecture is TargetArchitecture.LoongArch64) { - return LoongArch64PassStructInRegister.GetLoongArch64PassFpStructInRegistersInfo(typeDesc); + info = LoongArch64PassStructInRegister.GetLoongArch64PassFpStructInRegistersInfo(typeDesc); } else { Debug.Assert(false, "Unsupported architecture for getFpStructInRegistersInfo"); - return new FpStructInRegistersInfo{}; + return; + } + + if (info.flags != FpStruct.UseIntCallConv) + { + lowering.byIntegerCallConv = false; + lowering.numLoweredElements = (info.flags & FpStruct.OnlyOne) != 0 ? 1 : 2; + // TODO convert types + } + else + { + lowering = new CORINFO_FPSTRUCT_LOWERING{ byIntegerCallConv = true }; } } diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs index 979cec116ccff..5415aed3c6bfb 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs @@ -1874,17 +1874,16 @@ private static void _getSwiftLowering(IntPtr thisHandle, IntPtr* ppException, CO } [UnmanagedCallersOnly] - private static FpStructInRegistersInfo _getFpStructInRegistersInfo(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* structHnd) + private static void _getFpStructLowering(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* structHnd, CORINFO_FPSTRUCT_LOWERING* pLowering) { var _this = GetThis(thisHandle); try { - return _this.getFpStructInRegistersInfo(structHnd); + _this.getFpStructLowering(structHnd, ref *pLowering); } catch (Exception ex) { *ppException = _this.AllocException(ex); - return default; } } @@ -2737,7 +2736,7 @@ private static IntPtr GetUnmanagedCallbacks() callbacks[123] = (delegate* unmanaged)&_getMethodHash; callbacks[124] = (delegate* unmanaged)&_getSystemVAmd64PassStructInRegisterDescriptor; callbacks[125] = (delegate* unmanaged)&_getSwiftLowering; - callbacks[126] = (delegate* unmanaged)&_getFpStructInRegistersInfo; + callbacks[126] = (delegate* unmanaged)&_getFpStructLowering; callbacks[127] = (delegate* unmanaged)&_getThreadTLSIndex; callbacks[128] = (delegate* unmanaged)&_getAddrOfCaptureThreadGlobal; callbacks[129] = (delegate* unmanaged)&_getHelperFtn; diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs index 17cedca046e33..02d0e52ade52e 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs @@ -1597,4 +1597,58 @@ public override string ToString() return stringBuilder.ToString(); } } + + public struct CORINFO_FPSTRUCT_LOWERING + { + private byte _byIntegerCallConv; + public bool byIntegerCallConv { get => _byIntegerCallConv != 0; set => _byIntegerCallConv = value ? (byte)1 : (byte)0; } + + [InlineArray(4)] + private struct FpStructLoweredTypes + { + public CorInfoType type; + } + + [InlineArray(4)] + private struct LoweredOffsets + { + public uint offset; + } + + private FpStructLoweredTypes _loweredElements; + + [UnscopedRef] + public Span LoweredElements => _loweredElements; + + private LoweredOffsets _offsets; + + [UnscopedRef] + public Span Offsets => _offsets; + + public nint numLoweredElements; + + // Override for a better unit test experience + public override string ToString() + { + if (byIntegerCallConv) + { + return "byIntegerCallConv"; + } + + var stringBuilder = new StringBuilder(); + stringBuilder.Append('{'); + for (int i = 0; i < numLoweredElements; i++) + { + if (i != 0) + { + stringBuilder.Append(", "); + } + stringBuilder.Append(LoweredElements[i]); + stringBuilder.Append(": "); + stringBuilder.Append(Offsets[i]); + } + stringBuilder.Append('}'); + return stringBuilder.ToString(); + } + } } diff --git a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt index 9943fb814a260..815b8a9ed1d35 100644 --- a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt +++ b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt @@ -84,6 +84,7 @@ CORINFO_RESOLVED_TOKEN_PTR,CORINFO_RESOLVED_TOKEN*,CORINFO_RESOLVED_TOKEN*,CORIN CORINFO_EE_INFO*,ref CORINFO_EE_INFO CORINFO_TAILCALL_HELPERS*,ref CORINFO_TAILCALL_HELPERS CORINFO_SWIFT_LOWERING*,ref CORINFO_SWIFT_LOWERING +CORINFO_FPSTRUCT_LOWERING*,ref CORINFO_FPSTRUCT_LOWERING CORINFO_GENERICHANDLE_RESULT*,ref CORINFO_GENERICHANDLE_RESULT CORINFO_METHOD_INFO*,CORINFO_METHOD_INFO* CORINFO_FIELD_INFO*,CORINFO_FIELD_INFO* @@ -100,7 +101,6 @@ CORINFO_HELPER_DESC*,ref CORINFO_HELPER_DESC const CORINFO_HELPER_DESC*,ref CORINFO_HELPER_DESC int*,ref int unsigned int*,ref uint -FpStructInRegistersInfo,FpStructInRegistersInfo CORINFO_JUST_MY_CODE_HANDLE**,ref CORINFO_JUST_MY_CODE_HANDLE_* @@ -290,7 +290,7 @@ FUNCTIONS unsigned getMethodHash(CORINFO_METHOD_HANDLE ftn); bool getSystemVAmd64PassStructInRegisterDescriptor(CORINFO_CLASS_HANDLE structHnd, SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structPassInRegDescPtr); void getSwiftLowering(CORINFO_CLASS_HANDLE structHnd, CORINFO_SWIFT_LOWERING* pLowering); - FpStructInRegistersInfo getFpStructInRegistersInfo(CORINFO_CLASS_HANDLE structHnd); + void getFpStructLowering(CORINFO_CLASS_HANDLE structHnd, CORINFO_FPSTRUCT_LOWERING* pLowering); uint32_t getThreadTLSIndex(void **ppIndirection); int32_t * getAddrOfCaptureThreadGlobal(void **ppIndirection); void* getHelperFtn (CorInfoHelpFunc ftnNum, void **ppIndirection); diff --git a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h index 31dc0f4a7cb43..a8101f2b50330 100644 --- a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h +++ b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h @@ -137,7 +137,7 @@ struct JitInterfaceCallbacks unsigned (* getMethodHash)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_METHOD_HANDLE ftn); bool (* getSystemVAmd64PassStructInRegisterDescriptor)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE structHnd, SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structPassInRegDescPtr); void (* getSwiftLowering)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE structHnd, CORINFO_SWIFT_LOWERING* pLowering); - FpStructInRegistersInfo (* getFpStructInRegistersInfo)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE structHnd); + void (* getFpStructLowering)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE structHnd, CORINFO_FPSTRUCT_LOWERING* pLowering); uint32_t (* getThreadTLSIndex)(void * thisHandle, CorInfoExceptionClass** ppException, void** ppIndirection); int32_t* (* getAddrOfCaptureThreadGlobal)(void * thisHandle, CorInfoExceptionClass** ppException, void** ppIndirection); void* (* getHelperFtn)(void * thisHandle, CorInfoExceptionClass** ppException, CorInfoHelpFunc ftnNum, void** ppIndirection); @@ -1416,13 +1416,13 @@ class JitInterfaceWrapper : public ICorJitInfo if (pException != nullptr) throw pException; } - virtual FpStructInRegistersInfo getFpStructInRegistersInfo( - CORINFO_CLASS_HANDLE structHnd) + virtual void getFpStructLowering( + CORINFO_CLASS_HANDLE structHnd, + CORINFO_FPSTRUCT_LOWERING* pLowering) { CorInfoExceptionClass* pException = nullptr; - FpStructInRegistersInfo temp = _callbacks->getFpStructInRegistersInfo(_thisHandle, &pException, structHnd); + _callbacks->getFpStructLowering(_thisHandle, &pException, structHnd, pLowering); if (pException != nullptr) throw pException; - return temp; } virtual uint32_t getThreadTLSIndex( diff --git a/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h b/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h index 8daff9f0882a5..419880ec2dbc4 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h @@ -633,6 +633,14 @@ struct Agnostic_GetSwiftLowering DWORD numLoweredElements; }; +struct Agnostic_GetFpStructLowering +{ + DWORD byIntegerCallConv; + DWORD loweredElements[MAX_FPSTRUCT_LOWERED_ELEMENTS]; + DWORD offsets[MAX_FPSTRUCT_LOWERED_ELEMENTS]; + DWORD numLoweredElements; +}; + struct Agnostic_ResolveVirtualMethodKey { DWORDLONG virtualMethod; diff --git a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h index 10210541061db..1341e7b9c08d5 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h @@ -127,7 +127,7 @@ LWM(GetSharedCCtorHelper, DWORDLONG, DWORD) LWM(GetStringConfigValue, DWORD, DWORD) LWM(GetSystemVAmd64PassStructInRegisterDescriptor, DWORDLONG, Agnostic_GetSystemVAmd64PassStructInRegisterDescriptor) LWM(GetSwiftLowering, DWORDLONG, Agnostic_GetSwiftLowering) -LWM(GetFpStructInRegistersInfo, DWORDLONG, FpStructInRegistersInfo) +LWM(GetFpStructLowering, DWORDLONG, Agnostic_GetFpStructLowering) LWM(GetTailCallHelpers, Agnostic_GetTailCallHelpers, Agnostic_CORINFO_TAILCALL_HELPERS) LWM(UpdateEntryPointForTailCall, Agnostic_CORINFO_CONST_LOOKUP, Agnostic_CORINFO_CONST_LOOKUP) LWM(GetThreadTLSIndex, DWORD, DLD) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp index f301f143d44e3..280e0664b4725 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp @@ -6359,32 +6359,54 @@ void MethodContext::repGetSwiftLowering(CORINFO_CLASS_HANDLE structHnd, CORINFO_ } } -void MethodContext::recGetFpStructInRegistersInfo(CORINFO_CLASS_HANDLE structHnd, FpStructInRegistersInfo value) +void MethodContext::recGetFpStructLowering(CORINFO_CLASS_HANDLE structHnd, CORINFO_FPSTRUCT_LOWERING* pLowering) { - if (GetFpStructInRegistersInfo == nullptr) - GetFpStructInRegistersInfo = new LightWeightMap(); + if (GetFpStructLowering == nullptr) + GetFpStructLowering = new LightWeightMap(); DWORDLONG key = CastHandle(structHnd); - GetFpStructInRegistersInfo->Add(key, value); - DEBUG_REC(dmpGetFpStructInRegistersInfo(key, value)); -} + Agnostic_GetFpStructLowering value; + ZeroMemory(&value, sizeof(value)); + value.byIntegerCallConv = pLowering->byIntegerCallConv ? 1 : 0; + if (!pLowering->byIntegerCallConv) + { + value.numLoweredElements = static_cast(pLowering->numLoweredElements); + for (size_t i = 0; i < pLowering->numLoweredElements; i++) + { + value.loweredElements[i] = static_cast(pLowering->loweredElements[i]); + value.offsets[i] = pLowering->offsets[i]; + } + } -void MethodContext::dmpGetFpStructInRegistersInfo(DWORDLONG key, FpStructInRegistersInfo value) + GetFpStructLowering->Add(key, value); + DEBUG_REC(dmpGetFpStructLowering(key, value)); +} +void MethodContext::dmpGetFpStructLowering( + DWORDLONG key, const Agnostic_GetFpStructLowering& value) { - printf("GetFpStructInRegistersInfo key %016" PRIX64 " value-%#03x-" - "{%s, sizes={%u, %u}, offsets={%u, %u}}\n", - key, value.flags, - value.FlagName(), value.Size1st(), value.Size2nd(), value.offset1st, value.offset2nd); + printf("GetFpStructLowering key structHnd-%016" PRIX64 ", value byIntegerCallConv-%u numLoweredElements-%u", key, + value.byIntegerCallConv, value.numLoweredElements); + for (size_t i = 0; i < value.numLoweredElements; i++) + { + printf(" [%zu] %u", i, value.loweredElements[i]); + } } - -FpStructInRegistersInfo MethodContext::repGetFpStructInRegistersInfo(CORINFO_CLASS_HANDLE structHnd) +void MethodContext::repGetFpStructLowering(CORINFO_CLASS_HANDLE structHnd, CORINFO_FPSTRUCT_LOWERING* pLowering) { DWORDLONG key = CastHandle(structHnd); + Agnostic_GetFpStructLowering value = LookupByKeyOrMiss(GetFpStructLowering, key, ": key %016" PRIX64 "", key); - FpStructInRegistersInfo value = LookupByKeyOrMissNoMessage(GetFpStructInRegistersInfo, key); - DEBUG_REP(dmpGetFpStructInRegistersInfo(key, value)); - return value; + DEBUG_REP(dmpGetFpStructLowering(key, value)); + + pLowering->byIntegerCallConv = value.byIntegerCallConv != 0; + pLowering->numLoweredElements = value.numLoweredElements; + + for (size_t i = 0; i < pLowering->numLoweredElements; i++) + { + pLowering->loweredElements[i] = static_cast(value.loweredElements[i]); + pLowering->offsets[i] = value.offsets[i]; + } } void MethodContext::recGetRelocTypeHint(void* target, WORD result) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h index 1d1998b54c31d..01f04b16a4c3c 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h @@ -783,9 +783,9 @@ class MethodContext void dmpGetSwiftLowering(DWORDLONG key, const Agnostic_GetSwiftLowering& value); void repGetSwiftLowering(CORINFO_CLASS_HANDLE structHnd, CORINFO_SWIFT_LOWERING* pLowering); - void recGetFpStructInRegistersInfo(CORINFO_CLASS_HANDLE structHnd, FpStructInRegistersInfo value); - void dmpGetFpStructInRegistersInfo(DWORDLONG key, FpStructInRegistersInfo value); - FpStructInRegistersInfo repGetFpStructInRegistersInfo(CORINFO_CLASS_HANDLE structHnd); + void recGetFpStructLowering(CORINFO_CLASS_HANDLE structHnd, CORINFO_FPSTRUCT_LOWERING* pLowering); + void dmpGetFpStructLowering(DWORDLONG key, const Agnostic_GetFpStructLowering& value); + void repGetFpStructLowering(CORINFO_CLASS_HANDLE structHnd, CORINFO_FPSTRUCT_LOWERING* pLowering); void recGetRelocTypeHint(void* target, WORD result); void dmpGetRelocTypeHint(DWORDLONG key, DWORD value); @@ -1182,7 +1182,7 @@ enum mcPackets Packet_GetClassThreadStaticDynamicInfo = 219, Packet_IsGenericType = 220, Packet_GetTypeForBoxOnStack = 221, - Packet_GetFpStructInRegistersInfo = 222, + Packet_GetFpStructLowering = 222, }; void SetDebugDumpVariables(); diff --git a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp index 1c192d4c445ee..4e6d192354e0b 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp @@ -1427,12 +1427,11 @@ void interceptor_ICJI::getSwiftLowering(CORINFO_CLASS_HANDLE structHnd, CORINFO_ mc->recGetSwiftLowering(structHnd, pLowering); } -FpStructInRegistersInfo interceptor_ICJI::getFpStructInRegistersInfo(CORINFO_CLASS_HANDLE structHnd) +void interceptor_ICJI::getFpStructLowering(CORINFO_CLASS_HANDLE structHnd, CORINFO_FPSTRUCT_LOWERING* pLowering) { - mc->cr->AddCall("getFpStructInRegistersInfo"); - FpStructInRegistersInfo temp = original_ICorJitInfo->getFpStructInRegistersInfo(structHnd); - mc->recGetFpStructInRegistersInfo(structHnd, temp); - return temp; + mc->cr->AddCall("getFpStructLowering"); + original_ICorJitInfo->getFpStructLowering(structHnd, pLowering); + mc->recGetFpStructLowering(structHnd, pLowering); } // Stuff on ICorDynamicInfo diff --git a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp index 873b96a9f3938..48143fb8b789d 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp @@ -1015,11 +1015,12 @@ void interceptor_ICJI::getSwiftLowering( original_ICorJitInfo->getSwiftLowering(structHnd, pLowering); } -FpStructInRegistersInfo interceptor_ICJI::getFpStructInRegistersInfo( - CORINFO_CLASS_HANDLE structHnd) +void interceptor_ICJI::getFpStructLowering( + CORINFO_CLASS_HANDLE structHnd, + CORINFO_FPSTRUCT_LOWERING* pLowering) { - mcs->AddCall("getFpStructInRegistersInfo"); - return original_ICorJitInfo->getFpStructInRegistersInfo(structHnd); + mcs->AddCall("getFpStructLowering"); + original_ICorJitInfo->getFpStructLowering(structHnd, pLowering); } uint32_t interceptor_ICJI::getThreadTLSIndex( diff --git a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp index 6ab922b2906ce..3462afdcdacff 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp @@ -889,10 +889,11 @@ void interceptor_ICJI::getSwiftLowering( original_ICorJitInfo->getSwiftLowering(structHnd, pLowering); } -FpStructInRegistersInfo interceptor_ICJI::getFpStructInRegistersInfo( - CORINFO_CLASS_HANDLE structHnd) +void interceptor_ICJI::getFpStructLowering( + CORINFO_CLASS_HANDLE structHnd, + CORINFO_FPSTRUCT_LOWERING* pLowering) { - return original_ICorJitInfo->getFpStructInRegistersInfo(structHnd); + original_ICorJitInfo->getFpStructLowering(structHnd, pLowering); } uint32_t interceptor_ICJI::getThreadTLSIndex( diff --git a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp index 7915ccdf3c242..124783c842c7c 100644 --- a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp @@ -1258,10 +1258,10 @@ void MyICJI::getSwiftLowering(CORINFO_CLASS_HANDLE structHnd, CORINFO_SWIFT_LOWE jitInstance->mc->repGetSwiftLowering(structHnd, pLowering); } -FpStructInRegistersInfo MyICJI::getFpStructInRegistersInfo(CORINFO_CLASS_HANDLE structHnd) +void MyICJI::getFpStructLowering(CORINFO_CLASS_HANDLE structHnd, CORINFO_FPSTRUCT_LOWERING* pLowering) { - jitInstance->mc->cr->AddCall("getFpStructInRegistersInfo"); - return jitInstance->mc->repGetFpStructInRegistersInfo(structHnd); + jitInstance->mc->cr->AddCall("getFpStructLowering"); + jitInstance->mc->repGetFpStructLowering(structHnd, pLowering); } // Stuff on ICorDynamicInfo diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 3c855b0e78ac3..7df29963ae402 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -9515,13 +9515,13 @@ CorInfoTypeWithMod CEEInfo::getArgType ( return result; } -// Now the implementation is only focused on the float fields info, +// Now the implementation is only focused on the float and int fields info, // while a struct-arg has no more than two fields and total size is no larger than two-pointer-size. // These depends on the platform's ABI rules. // -// The returned value's encoding details how a struct argument uses float registers: -// see the struct `FpStructInRegistersInfo`. -FpStructInRegistersInfo CEEInfo::getFpStructInRegistersInfo(CORINFO_CLASS_HANDLE cls) +// The returned value's encoding details how a struct argument uses float and int registers: +// see the struct `CORINFO_FPSTRUCT_LOWERING`. +void CEEInfo::getFpStructLowering(CORINFO_CLASS_HANDLE structHnd, CORINFO_FPSTRUCT_LOWERING* pLowering) { CONTRACTL { NOTHROW; @@ -9529,17 +9529,48 @@ FpStructInRegistersInfo CEEInfo::getFpStructInRegistersInfo(CORINFO_CLASS_HANDLE MODE_PREEMPTIVE; } CONTRACTL_END; - FpStructInRegistersInfo info = {}; - JIT_TO_EE_TRANSITION(); #if defined(TARGET_RISCV64) || defined(TARGET_LOONGARCH64) - info = MethodTable::GetFpStructInRegistersInfo(TypeHandle(cls)); + FpStructInRegistersInfo info = MethodTable::GetFpStructInRegistersInfo(TypeHandle(structHnd)); + if (info.flags != FpStruct::UseIntCallConv) + { + pLowering->byIntegerCallConv = false; + pLowering->numLoweredElements = (info.flags & FpStruct::OnlyOne) ? 1 : 2; + pLowering->offsets[0] = info.offset1st; + pLowering->offsets[1] = info.offset2nd; + + if (info.flags & (FpStruct::BothFloat | FpStruct::FloatInt | FpStruct::OnlyOne)) + pLowering->loweredElements[0] = (info.SizeShift1st() == 3) ? CORINFO_TYPE_DOUBLE : CORINFO_TYPE_FLOAT; + + if (info.flags & (FpStruct::BothFloat | FpStruct::IntFloat)) + pLowering->loweredElements[1] = (info.SizeShift2nd() == 3) ? CORINFO_TYPE_DOUBLE : CORINFO_TYPE_FLOAT; + + if (info.flags & (FpStruct::FloatInt | FpStruct::IntFloat)) + { + size_t index = ((info.flags & FpStruct::IntFloat) != 0) ? 0 : 1; + unsigned sizeShift = (index == 0) ? info.SizeShift1st() : info.SizeShift2nd(); + pLowering->loweredElements[index] = (CorInfoType)(CORINFO_TYPE_BYTE + sizeShift * 2); + + // unittests + static_assert(CORINFO_TYPE_BYTE + 0 * 2 == CORINFO_TYPE_BYTE, ""); + static_assert(CORINFO_TYPE_BYTE + 1 * 2 == CORINFO_TYPE_SHORT, ""); + static_assert(CORINFO_TYPE_BYTE + 2 * 2 == CORINFO_TYPE_INT, ""); + static_assert(CORINFO_TYPE_BYTE + 3 * 2 == CORINFO_TYPE_LONG, ""); + } + +#ifdef _DEBUG + if (info.flags & FpStruct::OnlyOne) + pLowering->loweredElements[1] = CORINFO_TYPE_UNDEF; +#endif // _DEBUG + } + else + { + *pLowering = { .byIntegerCallConv = true }; + } #endif // TARGET_RISCV64 || TARGET_LOONGARCH64 EE_TO_JIT_TRANSITION(); - - return info; } /*********************************************************************/ From e37e9848eb2b7c4c577644f72aea977eae0cd9df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomek=20Sowi=C5=84ski?= Date: Tue, 9 Jul 2024 08:20:21 +0200 Subject: [PATCH 27/35] Change JIT to use new Swift-like getFpStructLowering --- src/coreclr/inc/corinfo.h | 9 ++- src/coreclr/jit/compiler.cpp | 37 ++++++------ src/coreclr/jit/compiler.h | 2 +- src/coreclr/jit/gentree.cpp | 42 +++++++------- src/coreclr/jit/lclvars.cpp | 47 +++++---------- src/coreclr/jit/targetriscv64.cpp | 58 ++++++++++--------- .../tools/Common/JitInterface/CorInfoImpl.cs | 28 ++++++++- .../tools/Common/JitInterface/CorInfoTypes.cs | 4 +- src/coreclr/vm/jitinterface.cpp | 16 ++--- 9 files changed, 129 insertions(+), 114 deletions(-) diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index ba44b7ae0681d..23a98a37a526d 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -2027,13 +2027,18 @@ struct CORINFO_SWIFT_LOWERING #define MAX_FPSTRUCT_LOWERED_ELEMENTS 2 -// Lowering information on fields of a struct passed by hardware floating-point calling convention -// on RISC-V and LoongArch +// Lowering information on fields of a struct passed by hardware floating-point calling convention on RISC-V and LoongArch +// NOTE: all array elements past numLoweredElements are zero-initialized struct CORINFO_FPSTRUCT_LOWERING { + // Whether the struct should be passed by integer calling convention (cannot be passed by FP calling convention). + // If true, all other fields of CORINFO_FPSTRUCT_LOWERING are zeroed. bool byIntegerCallConv; + // Types of lowered struct fields. CorInfoType loweredElements[MAX_FPSTRUCT_LOWERED_ELEMENTS]; + // Offsets of lowered struct fields. uint32_t offsets[MAX_FPSTRUCT_LOWERED_ELEMENTS]; + // Number of lowered struct fields. size_t numLoweredElements; }; diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp index 794a2fff5d06d..1a4921083681b 100644 --- a/src/coreclr/jit/compiler.cpp +++ b/src/coreclr/jit/compiler.cpp @@ -930,15 +930,17 @@ var_types Compiler::getReturnTypeForStruct(CORINFO_CLASS_HANDLE clsHnd, #elif defined(TARGET_RISCV64) || defined(TARGET_LOONGARCH64) if (structSize <= (TARGET_POINTER_SIZE * 2)) { - FpStructInRegistersInfo info = GetPassFpStructInRegistersInfo(clsHnd); - if ((info.flags & FpStruct::OnlyOne) != 0) + CORINFO_FPSTRUCT_LOWERING lowering; + GetFpStructLowering(clsHnd, &lowering); + if (lowering.numLoweredElements == 1) { + useType = JITtype2varType(lowering.loweredElements[0]); + assert(varTypeIsFloating(useType)); howToReturnStruct = SPK_PrimitiveType; - useType = (structSize > 4) ? TYP_DOUBLE : TYP_FLOAT; } - else if (info.flags != FpStruct::UseIntCallConv) + else if (!lowering.byIntegerCallConv) { - assert((info.flags & (FpStruct::BothFloat | FpStruct::FloatInt | FpStruct::IntFloat)) != 0); + assert(lowering.numLoweredElements == 2); howToReturnStruct = SPK_ByValue; useType = TYP_STRUCT; } @@ -8285,39 +8287,40 @@ void Compiler::GetStructTypeOffset( #elif defined(TARGET_RISCV64) || defined(TARGET_LOONGARCH64) //------------------------------------------------------------------------ -// GetPassFpStructInRegistersInfo: Gets the information on passing of a struct according to hardware floating-point -// calling convention. +// GetFpStructLowering: Gets the information on passing of a struct according to hardware floating-point +// calling convention, i.e. the types and offsets of struct fields lowered for passing. // // Arguments: // structHandle - type handle +// pLowering - out param; returns the lowering info for the struct fields // // Return value: -// The passing info -FpStructInRegistersInfo Compiler::GetPassFpStructInRegistersInfo(CORINFO_CLASS_HANDLE structHandle) +// None +void Compiler::GetFpStructLowering(CORINFO_CLASS_HANDLE structHandle, CORINFO_FPSTRUCT_LOWERING* pLowering) { - CORINFO_FPSTRUCT_LOWERING lowering; - info.compCompHnd->getFpStructLowering(structHandle, &lowering); + info.compCompHnd->getFpStructLowering(structHandle, pLowering); #ifdef DEBUG if (verbose) { printf("**** getFpStructInRegistersInfo(0x%x (%s, %u bytes)) =>\n", dspPtr(structHandle), eeGetClassName(structHandle), info.compCompHnd->getClassSize(structHandle)); -#undef getInfoFunc - if (lowering.byIntegerCallConv) + + if (pLowering->byIntegerCallConv) { printf(" pass by integer calling convention\n"); } else { - printf(" may be passed by floating-point calling convention (%zu fields):\n", lowering.numLoweredElements); - for (size_t i = 0; i < lowering.numLoweredElements; ++i) + printf(" may be passed by floating-point calling convention (%zu fields):\n", + pLowering->numLoweredElements); + for (size_t i = 0; i < pLowering->numLoweredElements; ++i) { - printf(" * field[%zu]: type %i at offset %u\n", i, lowering.loweredElements[i], lowering.offsets[i]); + const char* type = varTypeName(JITtype2varType(pLowering->loweredElements[i])); + printf(" * field[%zu]: type %s at offset %u\n", i, type, pLowering->offsets[i]); } } } #endif // DEBUG - return {}; } #endif // defined(UNIX_AMD64_ABI) diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 02d6a226644e5..6683c40ad5a70 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -11365,7 +11365,7 @@ class Compiler CORINFO_CLASS_HANDLE typeHnd, var_types* type0, var_types* type1, uint8_t* offset0, uint8_t* offset1); #elif defined(TARGET_RISCV64) || defined(TARGET_LOONGARCH64) - FpStructInRegistersInfo GetPassFpStructInRegistersInfo(CORINFO_CLASS_HANDLE structHandle); + void GetFpStructLowering(CORINFO_CLASS_HANDLE structHandle, CORINFO_FPSTRUCT_LOWERING* pLowering); #endif // defined(UNIX_AMD64_ABI) void fgMorphMultiregStructArgs(GenTreeCall* call); diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index ad8dec4bbfda8..2a97c4cb108c6 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -28942,30 +28942,30 @@ void ReturnTypeDesc::InitializeStructReturnType(Compiler* comp, #elif defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) assert((structSize >= TARGET_POINTER_SIZE) && (structSize <= (2 * TARGET_POINTER_SIZE))); - FpStructInRegistersInfo fpInfo = comp->GetPassFpStructInRegistersInfo(retClsHnd); - BYTE gcPtrs[2] = {TYPE_GC_NONE, TYPE_GC_NONE}; + CORINFO_FPSTRUCT_LOWERING lowering; + comp->GetFpStructLowering(retClsHnd, &lowering); + BYTE gcPtrs[2] = {TYPE_GC_NONE, TYPE_GC_NONE}; comp->info.compCompHnd->getClassGClayout(retClsHnd, &gcPtrs[0]); - - if ((fpInfo.flags & FpStruct::BothFloat) != 0) - { - comp->compFloatingPointUsed = true; - assert((structSize > 8) == ((fpInfo.SizeShift1st() == 3) || (fpInfo.SizeShift2nd() == 3))); - m_regType[0] = (fpInfo.SizeShift1st() == 3) ? TYP_DOUBLE : TYP_FLOAT; - m_regType[1] = (fpInfo.SizeShift2nd() == 3) ? TYP_DOUBLE : TYP_FLOAT; - } - else if ((fpInfo.flags & FpStruct::FloatInt) != 0) - { - comp->compFloatingPointUsed = true; - assert((structSize > 8) == ((fpInfo.SizeShift1st() == 3) || (fpInfo.SizeShift2nd() == 3))); - m_regType[0] = (fpInfo.SizeShift1st() == 3) ? TYP_DOUBLE : TYP_FLOAT; - m_regType[1] = (fpInfo.SizeShift2nd() == 3) ? comp->getJitGCType(gcPtrs[1]) : TYP_INT; - } - else if ((fpInfo.flags & FpStruct::IntFloat) != 0) + if (!lowering.byIntegerCallConv) { comp->compFloatingPointUsed = true; - assert((structSize > 8) == ((fpInfo.SizeShift1st() == 3) || (fpInfo.SizeShift2nd() == 3))); - m_regType[0] = (fpInfo.SizeShift1st() == 3) ? comp->getJitGCType(gcPtrs[0]) : TYP_INT; - m_regType[1] = (fpInfo.SizeShift2nd() == 3) ? TYP_DOUBLE : TYP_FLOAT; + assert(lowering.numLoweredElements == MAX_RET_REG_COUNT); + var_types types[MAX_RET_REG_COUNT] = {JITtype2varType(lowering.loweredElements[0]), + JITtype2varType(lowering.loweredElements[1])}; + assert(varTypeIsFloating(types[0]) || varTypeIsFloating(types[1])); + assert((structSize > 8) == ((genTypeSize(types[0]) == 8) || (genTypeSize(types[1]) == 8))); + for (unsigned i = 0; i < MAX_RET_REG_COUNT; ++i) + { + if (varTypeIsFloating(types[i])) + { + m_regType[i] = types[i]; + } + else + { + assert(varTypeIsIntegralOrI(types[i])); + m_regType[i] = (genTypeSize(types[i]) == 8) ? comp->getJitGCType(gcPtrs[i]) : TYP_INT; + } + } } else { diff --git a/src/coreclr/jit/lclvars.cpp b/src/coreclr/jit/lclvars.cpp index 55f5ee7be8344..658109caaf6d0 100644 --- a/src/coreclr/jit/lclvars.cpp +++ b/src/coreclr/jit/lclvars.cpp @@ -898,21 +898,21 @@ void Compiler::lvaInitUserArgs(InitVarDscInfo* varDscInfo, unsigned skipArgs, un } else #elif defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) - FpStructInRegistersInfo fpInfo = {}; + CORINFO_FPSTRUCT_LOWERING lowering = {.byIntegerCallConv = true}; var_types argRegTypeInStruct1 = TYP_UNKNOWN; var_types argRegTypeInStruct2 = TYP_UNKNOWN; if ((strip(corInfoType) == CORINFO_TYPE_VALUECLASS) && (argSize <= MAX_PASS_MULTIREG_BYTES)) { - fpInfo = GetPassFpStructInRegistersInfo(typeHnd); + GetFpStructLowering(typeHnd, &lowering); } - if (fpInfo.flags != FpStruct::UseIntCallConv) + if (!lowering.byIntegerCallConv) { assert(varTypeIsStruct(argType)); int floatNum = 0; - if ((fpInfo.flags & FpStruct::OnlyOne) != 0) + if (lowering.numLoweredElements == 1) { assert(argSize <= 8); assert(varDsc->lvExactSize() <= argSize); @@ -920,41 +920,26 @@ void Compiler::lvaInitUserArgs(InitVarDscInfo* varDscInfo, unsigned skipArgs, un floatNum = 1; canPassArgInRegisters = varDscInfo->canEnreg(TYP_DOUBLE, 1); - argRegTypeInStruct1 = (varDsc->lvExactSize() == 8) ? TYP_DOUBLE : TYP_FLOAT; + argRegTypeInStruct1 = JITtype2varType(lowering.loweredElements[0]); + assert(varTypeIsFloating(argRegTypeInStruct1)); } - else if ((fpInfo.flags & FpStruct::BothFloat) != 0) - { - floatNum = 2; - canPassArgInRegisters = varDscInfo->canEnreg(TYP_DOUBLE, 2); - - argRegTypeInStruct1 = (fpInfo.SizeShift1st() == 3) ? TYP_DOUBLE : TYP_FLOAT; - argRegTypeInStruct2 = (fpInfo.SizeShift2nd() == 3) ? TYP_DOUBLE : TYP_FLOAT; - } - else if ((fpInfo.flags & FpStruct::FloatInt) != 0) - { - floatNum = 1; - canPassArgInRegisters = varDscInfo->canEnreg(TYP_DOUBLE, 1); - canPassArgInRegisters = canPassArgInRegisters && varDscInfo->canEnreg(TYP_I_IMPL, 1); - - argRegTypeInStruct1 = (fpInfo.SizeShift1st() == 3) ? TYP_DOUBLE : TYP_FLOAT; - argRegTypeInStruct2 = (fpInfo.SizeShift2nd() == 3) ? TYP_LONG : TYP_INT; - } - else if ((fpInfo.flags & FpStruct::IntFloat) != 0) + else { - floatNum = 1; - canPassArgInRegisters = varDscInfo->canEnreg(TYP_DOUBLE, 1); - canPassArgInRegisters = canPassArgInRegisters && varDscInfo->canEnreg(TYP_I_IMPL, 1); - - argRegTypeInStruct1 = (fpInfo.SizeShift1st() == 3) ? TYP_LONG : TYP_INT; - argRegTypeInStruct2 = (fpInfo.SizeShift2nd() == 3) ? TYP_DOUBLE : TYP_FLOAT; + assert(lowering.numLoweredElements == 2); + argRegTypeInStruct1 = genActualType(JITtype2varType(lowering.loweredElements[0])); + argRegTypeInStruct2 = genActualType(JITtype2varType(lowering.loweredElements[1])); + floatNum = (int)varTypeIsFloating(argRegTypeInStruct1) + (int)varTypeIsFloating(argRegTypeInStruct2); + canPassArgInRegisters = varDscInfo->canEnreg(TYP_DOUBLE, floatNum); + if (floatNum == 1) + canPassArgInRegisters = canPassArgInRegisters && varDscInfo->canEnreg(TYP_I_IMPL, 1); } assert((floatNum == 1) || (floatNum == 2)); if (!canPassArgInRegisters) { - // On LoongArch64, if there aren't any remaining floating-point registers to pass the argument, - // integer registers (if any) are used instead. + // On LoongArch64 and RISCV64, if there aren't any remaining floating-point registers to pass the + // argument, integer registers (if any) are used instead. canPassArgInRegisters = varDscInfo->canEnreg(argType, cSlotsToEnregister); argRegTypeInStruct1 = TYP_UNKNOWN; diff --git a/src/coreclr/jit/targetriscv64.cpp b/src/coreclr/jit/targetriscv64.cpp index 45cbf0f547043..74a9c12ccd44b 100644 --- a/src/coreclr/jit/targetriscv64.cpp +++ b/src/coreclr/jit/targetriscv64.cpp @@ -58,9 +58,9 @@ ABIPassingInformation RiscV64Classifier::Classify(Compiler* comp, ClassLayout* structLayout, WellKnownArg /*wellKnownParam*/) { - FpStructInRegistersInfo info = {}; - unsigned intFields = 0, floatFields = 0; - unsigned passedSize; + CORINFO_FPSTRUCT_LOWERING lowering = {.byIntegerCallConv = true}; + unsigned intFields = 0, floatFields = 0; + unsigned passedSize; if (varTypeIsStruct(type)) { @@ -71,22 +71,18 @@ ABIPassingInformation RiscV64Classifier::Classify(Compiler* comp, } else if (!structLayout->IsBlockLayout()) { - info = comp->GetPassFpStructInRegistersInfo(structLayout->GetClassHandle()); - - if ((info.flags & FpStruct::OnlyOne) != 0) - { - floatFields = 1; - } - else if ((info.flags & FpStruct::BothFloat) != 0) + comp->GetFpStructLowering(structLayout->GetClassHandle(), &lowering); + assert((lowering.numLoweredElements > 0) == !lowering.byIntegerCallConv); + assert(lowering.numLoweredElements <= 2); + INDEBUG(unsigned debugIntFields = 0;) + for (size_t i = 0; i < lowering.numLoweredElements; ++i) { - floatFields = 2; - } - else if (info.flags != FpStruct::UseIntCallConv) - { - assert((info.flags & (FpStruct::FloatInt | FpStruct::IntFloat)) != 0); - floatFields = 1; - intFields = 1; + var_types type = JITtype2varType(lowering.loweredElements[i]); + floatFields += (unsigned)varTypeIsFloating(type); + INDEBUG(debugIntFields += (unsigned)varTypeIsIntegralOrI(type);) } + intFields = lowering.numLoweredElements - floatFields; + assert(debugIntFields == intFields); } } else @@ -103,11 +99,15 @@ ABIPassingInformation RiscV64Classifier::Classify(Compiler* comp, // Hardware floating-point calling convention if ((floatFields == 1) && (intFields == 0)) { - if (info.flags == FpStruct::UseIntCallConv) + if (lowering.byIntegerCallConv) + { assert(varTypeIsFloating(type)); // standalone floating-point real + } else - assert((info.flags & FpStruct::OnlyOne) != 0); // struct containing just one FP real - + { + assert(lowering.numLoweredElements == 1); // struct containing just one FP real + assert(varTypeIsFloating(JITtype2varType(lowering.loweredElements[0]))); + } return ABIPassingInformation::FromSegment(comp, ABIPassingSegment::InRegister(m_floatRegs.Dequeue(), 0, passedSize)); } @@ -115,15 +115,19 @@ ABIPassingInformation RiscV64Classifier::Classify(Compiler* comp, { assert(varTypeIsStruct(type)); assert((floatFields + intFields) == 2); - assert(info.flags != FpStruct::UseIntCallConv); - assert((info.flags & FpStruct::OnlyOne) == 0); - - unsigned firstSize = (info.SizeShift1st() == 3) ? 8 : 4; - unsigned secondSize = (info.SizeShift2nd() == 3) ? 8 : 4; + assert(!lowering.byIntegerCallConv); + assert(lowering.numLoweredElements == 2); + + var_types types[] = { + JITtype2varType(lowering.loweredElements[0]), + JITtype2varType(lowering.loweredElements[1]), + }; + unsigned firstSize = (genTypeSize(types[0]) == 8) ? 8 : 4; + unsigned secondSize = (genTypeSize(types[1]) == 8) ? 8 : 4; unsigned offset = max(firstSize, secondSize); // TODO: cover empty fields and custom offsets / alignments - bool isFirstFloat = (info.flags & (FpStruct::BothFloat | FpStruct::FloatInt)) != 0; - bool isSecondFloat = (info.flags & (FpStruct::BothFloat | FpStruct::IntFloat)) != 0; + bool isFirstFloat = varTypeIsFloating(types[0]); + bool isSecondFloat = varTypeIsFloating(types[1]); assert(isFirstFloat || isSecondFloat); regNumber firstReg = (isFirstFloat ? m_floatRegs : m_intRegs).Dequeue(); diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index 3dbd27aa2c045..fea3cfee54806 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -3475,9 +3475,31 @@ private void getFpStructLowering(CORINFO_CLASS_STRUCT_* structHnd, ref CORINFO_F if (info.flags != FpStruct.UseIntCallConv) { - lowering.byIntegerCallConv = false; - lowering.numLoweredElements = (info.flags & FpStruct.OnlyOne) != 0 ? 1 : 2; - // TODO convert types + lowering = new CORINFO_FPSTRUCT_LOWERING { + byIntegerCallConv = false, + numLoweredElements = ((info.flags & FpStruct.OnlyOne) != 0) ? 1 : 2, + }; + lowering.Offsets[0] = info.offset1st; + lowering.Offsets[1] = info.offset2nd; + + if ((info.flags & (FpStruct.BothFloat | FpStruct.FloatInt | FpStruct.OnlyOne)) != 0) + lowering.LoweredElements[0] = (info.SizeShift1st() == 3) ? CorInfoType.CORINFO_TYPE_DOUBLE : CorInfoType.CORINFO_TYPE_FLOAT; + + if ((info.flags & (FpStruct.BothFloat | FpStruct.IntFloat)) != 0) + lowering.LoweredElements[1] = (info.SizeShift2nd() == 3) ? CorInfoType.CORINFO_TYPE_DOUBLE : CorInfoType.CORINFO_TYPE_FLOAT; + + if ((info.flags & (FpStruct.FloatInt | FpStruct.IntFloat)) != 0) + { + int index = ((info.flags & FpStruct.FloatInt) != 0) ? 1 : 0; + uint sizeShift = (index == 0) ? info.SizeShift1st() : info.SizeShift2nd(); + lowering.LoweredElements[index] = (CorInfoType)((int)CorInfoType.CORINFO_TYPE_BYTE + sizeShift * 2); + + // unittests + Debug.Assert((int)CorInfoType.CORINFO_TYPE_BYTE + 0 * 2 == (int)CorInfoType.CORINFO_TYPE_BYTE); + Debug.Assert((int)CorInfoType.CORINFO_TYPE_BYTE + 1 * 2 == (int)CorInfoType.CORINFO_TYPE_SHORT); + Debug.Assert((int)CorInfoType.CORINFO_TYPE_BYTE + 2 * 2 == (int)CorInfoType.CORINFO_TYPE_INT); + Debug.Assert((int)CorInfoType.CORINFO_TYPE_BYTE + 3 * 2 == (int)CorInfoType.CORINFO_TYPE_LONG); + } } else { diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs index 02d0e52ade52e..7b006501d87fc 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs @@ -1603,13 +1603,13 @@ public struct CORINFO_FPSTRUCT_LOWERING private byte _byIntegerCallConv; public bool byIntegerCallConv { get => _byIntegerCallConv != 0; set => _byIntegerCallConv = value ? (byte)1 : (byte)0; } - [InlineArray(4)] + [InlineArray(2)] private struct FpStructLoweredTypes { public CorInfoType type; } - [InlineArray(4)] + [InlineArray(2)] private struct LoweredOffsets { public uint offset; diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 7df29963ae402..76e123a6404ce 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -9535,10 +9535,11 @@ void CEEInfo::getFpStructLowering(CORINFO_CLASS_HANDLE structHnd, CORINFO_FPSTRU FpStructInRegistersInfo info = MethodTable::GetFpStructInRegistersInfo(TypeHandle(structHnd)); if (info.flags != FpStruct::UseIntCallConv) { - pLowering->byIntegerCallConv = false; - pLowering->numLoweredElements = (info.flags & FpStruct::OnlyOne) ? 1 : 2; - pLowering->offsets[0] = info.offset1st; - pLowering->offsets[1] = info.offset2nd; + *pLowering = { + .byIntegerCallConv = false, + .offsets = { info.offset1st, info.offset2nd }, + .numLoweredElements = (info.flags & FpStruct::OnlyOne) ? 1ul : 2ul, + }; if (info.flags & (FpStruct::BothFloat | FpStruct::FloatInt | FpStruct::OnlyOne)) pLowering->loweredElements[0] = (info.SizeShift1st() == 3) ? CORINFO_TYPE_DOUBLE : CORINFO_TYPE_FLOAT; @@ -9548,7 +9549,7 @@ void CEEInfo::getFpStructLowering(CORINFO_CLASS_HANDLE structHnd, CORINFO_FPSTRU if (info.flags & (FpStruct::FloatInt | FpStruct::IntFloat)) { - size_t index = ((info.flags & FpStruct::IntFloat) != 0) ? 0 : 1; + size_t index = ((info.flags & FpStruct::FloatInt) != 0) ? 1 : 0; unsigned sizeShift = (index == 0) ? info.SizeShift1st() : info.SizeShift2nd(); pLowering->loweredElements[index] = (CorInfoType)(CORINFO_TYPE_BYTE + sizeShift * 2); @@ -9558,11 +9559,6 @@ void CEEInfo::getFpStructLowering(CORINFO_CLASS_HANDLE structHnd, CORINFO_FPSTRU static_assert(CORINFO_TYPE_BYTE + 2 * 2 == CORINFO_TYPE_INT, ""); static_assert(CORINFO_TYPE_BYTE + 3 * 2 == CORINFO_TYPE_LONG, ""); } - -#ifdef _DEBUG - if (info.flags & FpStruct::OnlyOne) - pLowering->loweredElements[1] = CORINFO_TYPE_UNDEF; -#endif // _DEBUG } else { From c7c88e01ab5bb32de048bef7cfd4329e895cc79d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomek=20Sowi=C5=84ski?= Date: Tue, 9 Jul 2024 08:50:25 +0200 Subject: [PATCH 28/35] Cache CORINFO_FPSTRUCT_LOWERING --- src/coreclr/jit/compiler.cpp | 63 ++++++++++++++++++------------- src/coreclr/jit/compiler.h | 5 ++- src/coreclr/jit/gentree.cpp | 12 +++--- src/coreclr/jit/lclvars.cpp | 16 ++++---- src/coreclr/jit/targetriscv64.cpp | 34 +++++++++-------- 5 files changed, 72 insertions(+), 58 deletions(-) diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp index 1a4921083681b..2d250b315a01f 100644 --- a/src/coreclr/jit/compiler.cpp +++ b/src/coreclr/jit/compiler.cpp @@ -930,17 +930,16 @@ var_types Compiler::getReturnTypeForStruct(CORINFO_CLASS_HANDLE clsHnd, #elif defined(TARGET_RISCV64) || defined(TARGET_LOONGARCH64) if (structSize <= (TARGET_POINTER_SIZE * 2)) { - CORINFO_FPSTRUCT_LOWERING lowering; - GetFpStructLowering(clsHnd, &lowering); - if (lowering.numLoweredElements == 1) + const CORINFO_FPSTRUCT_LOWERING* lowering = GetFpStructLowering(clsHnd); + if (lowering->numLoweredElements == 1) { - useType = JITtype2varType(lowering.loweredElements[0]); + useType = JITtype2varType(lowering->loweredElements[0]); assert(varTypeIsFloating(useType)); howToReturnStruct = SPK_PrimitiveType; } - else if (!lowering.byIntegerCallConv) + else if (!lowering->byIntegerCallConv) { - assert(lowering.numLoweredElements == 2); + assert(lowering->numLoweredElements == 2); howToReturnStruct = SPK_ByValue; useType = TYP_STRUCT; } @@ -1982,6 +1981,9 @@ void Compiler::compInit(ArenaAllocator* pAlloc, #ifdef SWIFT_SUPPORT m_swiftLoweringCache = nullptr; #endif +#if defined(TARGET_RISCV64) || defined(TARGET_LOONGARCH64) + m_fpStructLoweringCache = nullptr; +#endif // check that HelperCallProperties are initialized @@ -8292,35 +8294,44 @@ void Compiler::GetStructTypeOffset( // // Arguments: // structHandle - type handle -// pLowering - out param; returns the lowering info for the struct fields // // Return value: -// None -void Compiler::GetFpStructLowering(CORINFO_CLASS_HANDLE structHandle, CORINFO_FPSTRUCT_LOWERING* pLowering) +// Lowering info for the struct fields +const CORINFO_FPSTRUCT_LOWERING* Compiler::GetFpStructLowering(CORINFO_CLASS_HANDLE structHandle) { - info.compCompHnd->getFpStructLowering(structHandle, pLowering); -#ifdef DEBUG - if (verbose) - { - printf("**** getFpStructInRegistersInfo(0x%x (%s, %u bytes)) =>\n", dspPtr(structHandle), - eeGetClassName(structHandle), info.compCompHnd->getClassSize(structHandle)); + if (m_fpStructLoweringCache == nullptr) + m_fpStructLoweringCache = new (this, CMK_CallArgs) FpStructLoweringMap(getAllocator(CMK_CallArgs)); - if (pLowering->byIntegerCallConv) - { - printf(" pass by integer calling convention\n"); - } - else + CORINFO_FPSTRUCT_LOWERING* lowering; + if (!m_fpStructLoweringCache->Lookup(structHandle, &lowering)) + { + lowering = new (this, CMK_CallArgs) CORINFO_FPSTRUCT_LOWERING; + info.compCompHnd->getFpStructLowering(structHandle, lowering); + m_fpStructLoweringCache->Set(structHandle, lowering); +#ifdef DEBUG + if (verbose) { - printf(" may be passed by floating-point calling convention (%zu fields):\n", - pLowering->numLoweredElements); - for (size_t i = 0; i < pLowering->numLoweredElements; ++i) + printf("**** getFpStructInRegistersInfo(0x%x (%s, %u bytes)) =>\n", dspPtr(structHandle), + eeGetClassName(structHandle), info.compCompHnd->getClassSize(structHandle)); + + if (lowering->byIntegerCallConv) { - const char* type = varTypeName(JITtype2varType(pLowering->loweredElements[i])); - printf(" * field[%zu]: type %s at offset %u\n", i, type, pLowering->offsets[i]); + printf(" pass by integer calling convention\n"); + } + else + { + printf(" may be passed by floating-point calling convention (%zu fields):\n", + lowering->numLoweredElements); + for (size_t i = 0; i < lowering->numLoweredElements; ++i) + { + const char* type = varTypeName(JITtype2varType(lowering->loweredElements[i])); + printf(" * field[%zu]: type %s at offset %u\n", i, type, lowering->offsets[i]); + } } } - } #endif // DEBUG + } + return lowering; } #endif // defined(UNIX_AMD64_ABI) diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 6683c40ad5a70..09870bcea6a62 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -11365,7 +11365,10 @@ class Compiler CORINFO_CLASS_HANDLE typeHnd, var_types* type0, var_types* type1, uint8_t* offset0, uint8_t* offset1); #elif defined(TARGET_RISCV64) || defined(TARGET_LOONGARCH64) - void GetFpStructLowering(CORINFO_CLASS_HANDLE structHandle, CORINFO_FPSTRUCT_LOWERING* pLowering); + typedef JitHashTable, CORINFO_FPSTRUCT_LOWERING*> + FpStructLoweringMap; + FpStructLoweringMap* m_fpStructLoweringCache; + const CORINFO_FPSTRUCT_LOWERING* GetFpStructLowering(CORINFO_CLASS_HANDLE structHandle); #endif // defined(UNIX_AMD64_ABI) void fgMorphMultiregStructArgs(GenTreeCall* call); diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 2a97c4cb108c6..39b87b0a2a59c 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -28941,17 +28941,15 @@ void ReturnTypeDesc::InitializeStructReturnType(Compiler* comp, #elif defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) assert((structSize >= TARGET_POINTER_SIZE) && (structSize <= (2 * TARGET_POINTER_SIZE))); - - CORINFO_FPSTRUCT_LOWERING lowering; - comp->GetFpStructLowering(retClsHnd, &lowering); BYTE gcPtrs[2] = {TYPE_GC_NONE, TYPE_GC_NONE}; comp->info.compCompHnd->getClassGClayout(retClsHnd, &gcPtrs[0]); - if (!lowering.byIntegerCallConv) + const CORINFO_FPSTRUCT_LOWERING* lowering = comp->GetFpStructLowering(retClsHnd); + if (!lowering->byIntegerCallConv) { comp->compFloatingPointUsed = true; - assert(lowering.numLoweredElements == MAX_RET_REG_COUNT); - var_types types[MAX_RET_REG_COUNT] = {JITtype2varType(lowering.loweredElements[0]), - JITtype2varType(lowering.loweredElements[1])}; + assert(lowering->numLoweredElements == MAX_RET_REG_COUNT); + var_types types[MAX_RET_REG_COUNT] = {JITtype2varType(lowering->loweredElements[0]), + JITtype2varType(lowering->loweredElements[1])}; assert(varTypeIsFloating(types[0]) || varTypeIsFloating(types[1])); assert((structSize > 8) == ((genTypeSize(types[0]) == 8) || (genTypeSize(types[1]) == 8))); for (unsigned i = 0; i < MAX_RET_REG_COUNT; ++i) diff --git a/src/coreclr/jit/lclvars.cpp b/src/coreclr/jit/lclvars.cpp index 658109caaf6d0..dca18bfe73d74 100644 --- a/src/coreclr/jit/lclvars.cpp +++ b/src/coreclr/jit/lclvars.cpp @@ -898,21 +898,21 @@ void Compiler::lvaInitUserArgs(InitVarDscInfo* varDscInfo, unsigned skipArgs, un } else #elif defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) - CORINFO_FPSTRUCT_LOWERING lowering = {.byIntegerCallConv = true}; + const CORINFO_FPSTRUCT_LOWERING* lowering = nullptr; var_types argRegTypeInStruct1 = TYP_UNKNOWN; var_types argRegTypeInStruct2 = TYP_UNKNOWN; if ((strip(corInfoType) == CORINFO_TYPE_VALUECLASS) && (argSize <= MAX_PASS_MULTIREG_BYTES)) { - GetFpStructLowering(typeHnd, &lowering); + lowering = GetFpStructLowering(typeHnd); } - if (!lowering.byIntegerCallConv) + if ((lowering != nullptr) && !lowering->byIntegerCallConv) { assert(varTypeIsStruct(argType)); int floatNum = 0; - if (lowering.numLoweredElements == 1) + if (lowering->numLoweredElements == 1) { assert(argSize <= 8); assert(varDsc->lvExactSize() <= argSize); @@ -920,14 +920,14 @@ void Compiler::lvaInitUserArgs(InitVarDscInfo* varDscInfo, unsigned skipArgs, un floatNum = 1; canPassArgInRegisters = varDscInfo->canEnreg(TYP_DOUBLE, 1); - argRegTypeInStruct1 = JITtype2varType(lowering.loweredElements[0]); + argRegTypeInStruct1 = JITtype2varType(lowering->loweredElements[0]); assert(varTypeIsFloating(argRegTypeInStruct1)); } else { - assert(lowering.numLoweredElements == 2); - argRegTypeInStruct1 = genActualType(JITtype2varType(lowering.loweredElements[0])); - argRegTypeInStruct2 = genActualType(JITtype2varType(lowering.loweredElements[1])); + assert(lowering->numLoweredElements == 2); + argRegTypeInStruct1 = genActualType(JITtype2varType(lowering->loweredElements[0])); + argRegTypeInStruct2 = genActualType(JITtype2varType(lowering->loweredElements[1])); floatNum = (int)varTypeIsFloating(argRegTypeInStruct1) + (int)varTypeIsFloating(argRegTypeInStruct2); canPassArgInRegisters = varDscInfo->canEnreg(TYP_DOUBLE, floatNum); if (floatNum == 1) diff --git a/src/coreclr/jit/targetriscv64.cpp b/src/coreclr/jit/targetriscv64.cpp index 74a9c12ccd44b..3711fb661c48e 100644 --- a/src/coreclr/jit/targetriscv64.cpp +++ b/src/coreclr/jit/targetriscv64.cpp @@ -58,9 +58,10 @@ ABIPassingInformation RiscV64Classifier::Classify(Compiler* comp, ClassLayout* structLayout, WellKnownArg /*wellKnownParam*/) { - CORINFO_FPSTRUCT_LOWERING lowering = {.byIntegerCallConv = true}; - unsigned intFields = 0, floatFields = 0; - unsigned passedSize; + const CORINFO_FPSTRUCT_LOWERING* lowering = nullptr; + + unsigned intFields = 0, floatFields = 0; + unsigned passedSize; if (varTypeIsStruct(type)) { @@ -71,17 +72,17 @@ ABIPassingInformation RiscV64Classifier::Classify(Compiler* comp, } else if (!structLayout->IsBlockLayout()) { - comp->GetFpStructLowering(structLayout->GetClassHandle(), &lowering); - assert((lowering.numLoweredElements > 0) == !lowering.byIntegerCallConv); - assert(lowering.numLoweredElements <= 2); + lowering = comp->GetFpStructLowering(structLayout->GetClassHandle()); + assert((lowering->numLoweredElements > 0) == !lowering->byIntegerCallConv); + assert(lowering->numLoweredElements <= 2); INDEBUG(unsigned debugIntFields = 0;) - for (size_t i = 0; i < lowering.numLoweredElements; ++i) + for (size_t i = 0; i < lowering->numLoweredElements; ++i) { - var_types type = JITtype2varType(lowering.loweredElements[i]); + var_types type = JITtype2varType(lowering->loweredElements[i]); floatFields += (unsigned)varTypeIsFloating(type); INDEBUG(debugIntFields += (unsigned)varTypeIsIntegralOrI(type);) } - intFields = lowering.numLoweredElements - floatFields; + intFields = lowering->numLoweredElements - floatFields; assert(debugIntFields == intFields); } } @@ -99,14 +100,14 @@ ABIPassingInformation RiscV64Classifier::Classify(Compiler* comp, // Hardware floating-point calling convention if ((floatFields == 1) && (intFields == 0)) { - if (lowering.byIntegerCallConv) + if (lowering == nullptr) { assert(varTypeIsFloating(type)); // standalone floating-point real } else { - assert(lowering.numLoweredElements == 1); // struct containing just one FP real - assert(varTypeIsFloating(JITtype2varType(lowering.loweredElements[0]))); + assert(lowering->numLoweredElements == 1); // struct containing just one FP real + assert(varTypeIsFloating(JITtype2varType(lowering->loweredElements[0]))); } return ABIPassingInformation::FromSegment(comp, ABIPassingSegment::InRegister(m_floatRegs.Dequeue(), 0, passedSize)); @@ -115,12 +116,13 @@ ABIPassingInformation RiscV64Classifier::Classify(Compiler* comp, { assert(varTypeIsStruct(type)); assert((floatFields + intFields) == 2); - assert(!lowering.byIntegerCallConv); - assert(lowering.numLoweredElements == 2); + assert(lowering != nullptr); + assert(!lowering->byIntegerCallConv); + assert(lowering->numLoweredElements == 2); var_types types[] = { - JITtype2varType(lowering.loweredElements[0]), - JITtype2varType(lowering.loweredElements[1]), + JITtype2varType(lowering->loweredElements[0]), + JITtype2varType(lowering->loweredElements[1]), }; unsigned firstSize = (genTypeSize(types[0]) == 8) ? 8 : 4; unsigned secondSize = (genTypeSize(types[1]) == 8) ? 8 : 4; From 5c478d794e8ead3e7d111f29688a126060be332d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomek=20Sowi=C5=84ski?= Date: Tue, 9 Jul 2024 09:21:02 +0200 Subject: [PATCH 29/35] Update LoongArch classifier to use CORINFO_FPSTRUCT_LOWERING --- src/coreclr/jit/targetloongarch64.cpp | 68 +++++++++++++++------------ 1 file changed, 37 insertions(+), 31 deletions(-) diff --git a/src/coreclr/jit/targetloongarch64.cpp b/src/coreclr/jit/targetloongarch64.cpp index df176458a35e4..e31e06d5d3399 100644 --- a/src/coreclr/jit/targetloongarch64.cpp +++ b/src/coreclr/jit/targetloongarch64.cpp @@ -78,45 +78,51 @@ ABIPassingInformation LoongArch64Classifier::Classify(Compiler* comp, { assert(!structLayout->IsBlockLayout()); - FpStructInRegistersInfo fpInfo; - CORINFO_CLASS_HANDLE typeHnd = structLayout->GetClassHandle(); + CORINFO_CLASS_HANDLE typeHnd = structLayout->GetClassHandle(); + const CORINFO_FPSTRUCT_LOWERING* lowering = comp->GetFpStructLowering(typeHnd); - fpInfo = comp->GetPassFpStructInRegistersInfo(typeHnd); - - if (fpInfo.flags != FpStruct::UseIntCallConv) + if (!lowering->byIntegerCallConv) { - if ((fpInfo.flags & FpStruct::OnlyOne) != 0) + slots = lowering->numLoweredElements; + if (lowering->numLoweredElements == 1) { assert(passedSize <= TARGET_POINTER_SIZE); + assert(varTypeIsFloating(JITtype2varType(lowering->loweredElements[0]))); - slots = 1; canPassArgInRegisters = m_floatRegs.Count() > 0; - - argRegTypeInStruct1 = (passedSize == 8) ? TYP_DOUBLE : TYP_FLOAT; - } - else if ((fpInfo.flags & FpStruct::BothFloat) != 0) - { - slots = 2; - canPassArgInRegisters = m_floatRegs.Count() >= 2; - - argRegTypeInStruct1 = (fpInfo.SizeShift1st() == 3) ? TYP_DOUBLE : TYP_FLOAT; - argRegTypeInStruct2 = (fpInfo.SizeShift2nd() == 3) ? TYP_DOUBLE : TYP_FLOAT; + argRegTypeInStruct1 = (passedSize == 8) ? TYP_DOUBLE : TYP_FLOAT; } - else if ((fpInfo.flags & FpStruct::FloatInt) != 0) - { - slots = 2; - canPassArgInRegisters = (m_floatRegs.Count() > 0) && (m_intRegs.Count() > 0); - - argRegTypeInStruct1 = (fpInfo.SizeShift1st() == 3) ? TYP_DOUBLE : TYP_FLOAT; - argRegTypeInStruct2 = (fpInfo.SizeShift2nd() == 3) ? TYP_LONG : TYP_INT; - } - else if ((fpInfo.flags & FpStruct::IntFloat) != 0) + else { - slots = 2; - canPassArgInRegisters = (m_floatRegs.Count() > 0) && (m_intRegs.Count() > 0); - - argRegTypeInStruct1 = (fpInfo.SizeShift1st() == 3) ? TYP_LONG : TYP_INT; - argRegTypeInStruct2 = (fpInfo.SizeShift2nd() == 3) ? TYP_DOUBLE : TYP_FLOAT; + assert(lowering->numLoweredElements == 2); + var_types types[] = { + JITtype2varType(lowering->loweredElements[0]), + JITtype2varType(lowering->loweredElements[1]), + }; + if (varTypeIsFloating(types[0]) && varTypeIsFloating(types[1])) + { + canPassArgInRegisters = m_floatRegs.Count() >= 2; + + argRegTypeInStruct1 = types[0]; + argRegTypeInStruct2 = types[1]; + } + else if (!varTypeIsFloating(types[1])) + { + assert(varTypeIsFloating(types[0])); + canPassArgInRegisters = (m_floatRegs.Count() > 0) && (m_intRegs.Count() > 0); + + argRegTypeInStruct1 = types[0]; + argRegTypeInStruct2 = (genTypeSize(types[1]) == 8) ? TYP_LONG : TYP_INT; + } + else + { + assert(!varTypeIsFloating(types[0])); + assert(varTypeIsFloating(types[1])); + canPassArgInRegisters = (m_floatRegs.Count() > 0) && (m_intRegs.Count() > 0); + + argRegTypeInStruct1 = (genTypeSize(types[0]) == 8) ? TYP_LONG : TYP_INT; + argRegTypeInStruct2 = types[1]; + } } assert((slots == 1) || (slots == 2)); From 1f16783b12da31dfea739f62f571878db45cb241 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomek=20Sowi=C5=84ski?= Date: Tue, 9 Jul 2024 15:16:08 +0200 Subject: [PATCH 30/35] Update StructFloatInfoFlags doc comment on C# --- src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs index 7b006501d87fc..5c20e921ea439 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs @@ -1221,8 +1221,8 @@ public struct SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR public byte eightByteOffsets1; }; - // StructFloadFieldInfoFlags: used on LoongArch64 architecture by `getLoongArch64PassStructInRegisterFlags` and - // `getRISCV64PassStructInRegisterFlags` API to convey struct argument passing information. + // StructFloatFieldInfoFlags: used on LoongArch64 and RISC-V architecture as a legacy representation of + // FpStructInRegistersInfo, returned by FpStructInRegistersInfo.ToOldFlags() // // `STRUCT_NO_FLOAT_FIELD` means structs are not passed using the float register(s). // From f064eb681b5fe5ea70d99872bddcb0bb2ab11590 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomek=20Sowi=C5=84ski?= Date: Thu, 11 Jul 2024 08:48:17 +0200 Subject: [PATCH 31/35] Move StructFloatFieldInfoFlags and FpStructInRegistersInfo out of the JIT interface --- src/coreclr/inc/corinfo.h | 94 ----------------------------------- src/coreclr/vm/methodtable.h | 96 ++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+), 94 deletions(-) diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index 23a98a37a526d..9d778743cd26e 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -317,100 +317,6 @@ struct SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR } }; -// StructFloatFieldInfoFlags: used on LoongArch64 and RISC-V architecture as a legacy representation of -// FpStructInRegistersInfo, returned by FpStructInRegistersInfo::ToOldFlags() -// -// `STRUCT_NO_FLOAT_FIELD` means structs are not passed using the float register(s). -// -// Otherwise, and only for structs with no more than two fields and a total struct size no larger -// than two pointers: -// -// The lowest four bits denote the floating-point info: -// bit 0: `1` means there is only one float or double field within the struct. -// bit 1: `1` means only the first field is floating-point type. -// bit 2: `1` means only the second field is floating-point type. -// bit 3: `1` means the two fields are both floating-point type. -// The bits[5:4] denoting whether the field size is 8-bytes: -// bit 4: `1` means the first field's size is 8. -// bit 5: `1` means the second field's size is 8. -// -// Note that bit 0 and 3 cannot both be set. -enum StructFloatFieldInfoFlags -{ - STRUCT_NO_FLOAT_FIELD = 0x0, - STRUCT_FLOAT_FIELD_ONLY_ONE = 0x1, - STRUCT_FLOAT_FIELD_ONLY_TWO = 0x8, - STRUCT_FLOAT_FIELD_FIRST = 0x2, - STRUCT_FLOAT_FIELD_SECOND = 0x4, - STRUCT_FIRST_FIELD_SIZE_IS8 = 0x10, - STRUCT_SECOND_FIELD_SIZE_IS8 = 0x20, -}; - -// Bitfields for FpStructInRegistersInfo::flags -namespace FpStruct -{ - enum Flags - { - // Positions of flags and bitfields - PosOnlyOne = 0, - PosBothFloat = 1, - PosFloatInt = 2, - PosIntFloat = 3, - PosSizeShift1st = 4, // 2 bits - PosSizeShift2nd = 6, // 2 bits - - UseIntCallConv = 0, // struct is passed according to integer calling convention - - // The flags and bitfields - OnlyOne = 1 << PosOnlyOne, // has only one field, which is floating-point - BothFloat = 1 << PosBothFloat, // has two fields, both are floating-point - FloatInt = 1 << PosFloatInt, // has two fields, 1st is floating and 2nd is integer - IntFloat = 1 << PosIntFloat, // has two fields, 2nd is floating and 1st is integer - SizeShift1stMask = 0b11 << PosSizeShift1st, // log2(size) of 1st field - SizeShift2ndMask = 0b11 << PosSizeShift2nd, // log2(size) of 2nd field - // Note: flags OnlyOne, BothFloat, FloatInt, and IntFloat are mutually exclusive - }; -} - -// On RISC-V and LoongArch a struct with up to two non-empty fields, at least one of them floating-point, -// can be passed in registers according to hardware FP calling convention. FpStructInRegistersInfo represents -// passing information for such parameters. -struct FpStructInRegistersInfo -{ - FpStruct::Flags flags; - uint32_t offset1st; - uint32_t offset2nd; - - unsigned SizeShift1st() const { return (flags >> FpStruct::PosSizeShift1st) & 0b11; } - unsigned SizeShift2nd() const { return (flags >> FpStruct::PosSizeShift2nd) & 0b11; } - - unsigned Size1st() const { return 1u << SizeShift1st(); } - unsigned Size2nd() const { return 1u << SizeShift2nd(); } - - const char* FlagName() const - { - switch (flags & (FpStruct::OnlyOne | FpStruct::BothFloat | FpStruct::FloatInt | FpStruct::IntFloat)) - { - case FpStruct::OnlyOne: return "OnlyOne"; - case FpStruct::BothFloat: return "BothFloat"; - case FpStruct::FloatInt: return "FloatInt"; - case FpStruct::IntFloat: return "IntFloat"; - default: return "?"; - } - } - - StructFloatFieldInfoFlags ToOldFlags() const - { - return StructFloatFieldInfoFlags( - ((flags & FpStruct::OnlyOne) ? STRUCT_FLOAT_FIELD_ONLY_ONE : 0) | - ((flags & FpStruct::BothFloat) ? STRUCT_FLOAT_FIELD_ONLY_TWO : 0) | - ((flags & FpStruct::FloatInt) ? STRUCT_FLOAT_FIELD_FIRST : 0) | - ((flags & FpStruct::IntFloat) ? STRUCT_FLOAT_FIELD_SECOND : 0) | - ((SizeShift1st() == 3) ? STRUCT_FIRST_FIELD_SIZE_IS8 : 0) | - ((SizeShift2nd() == 3) ? STRUCT_SECOND_FIELD_SIZE_IS8 : 0)); - } -}; - #include "corinfoinstructionset.h" // CorInfoHelpFunc defines the set of helpers (accessed via the ICorDynamicInfo::getHelperFtn()) diff --git a/src/coreclr/vm/methodtable.h b/src/coreclr/vm/methodtable.h index 8d549084c4146..a92fd8a9dc68c 100644 --- a/src/coreclr/vm/methodtable.h +++ b/src/coreclr/vm/methodtable.h @@ -754,6 +754,102 @@ typedef DPTR(SystemVStructRegisterPassingHelper) SystemVStructRegisterPassingHel #endif // UNIX_AMD64_ABI_ITF +#if defined(TARGET_RISCV64) || defined(TARGET_LOONGARCH64) +// StructFloatFieldInfoFlags: used on LoongArch64 and RISC-V architecture as a legacy representation of +// FpStructInRegistersInfo, returned by FpStructInRegistersInfo::ToOldFlags() +// +// `STRUCT_NO_FLOAT_FIELD` means structs are not passed using the float register(s). +// +// Otherwise, and only for structs with no more than two fields and a total struct size no larger +// than two pointers: +// +// The lowest four bits denote the floating-point info: +// bit 0: `1` means there is only one float or double field within the struct. +// bit 1: `1` means only the first field is floating-point type. +// bit 2: `1` means only the second field is floating-point type. +// bit 3: `1` means the two fields are both floating-point type. +// The bits[5:4] denoting whether the field size is 8-bytes: +// bit 4: `1` means the first field's size is 8. +// bit 5: `1` means the second field's size is 8. +// +// Note that bit 0 and 3 cannot both be set. +enum StructFloatFieldInfoFlags +{ + STRUCT_NO_FLOAT_FIELD = 0x0, + STRUCT_FLOAT_FIELD_ONLY_ONE = 0x1, + STRUCT_FLOAT_FIELD_ONLY_TWO = 0x8, + STRUCT_FLOAT_FIELD_FIRST = 0x2, + STRUCT_FLOAT_FIELD_SECOND = 0x4, + STRUCT_FIRST_FIELD_SIZE_IS8 = 0x10, + STRUCT_SECOND_FIELD_SIZE_IS8 = 0x20, +}; + +// Bitfields for FpStructInRegistersInfo::flags +namespace FpStruct +{ + enum Flags + { + // Positions of flags and bitfields + PosOnlyOne = 0, + PosBothFloat = 1, + PosFloatInt = 2, + PosIntFloat = 3, + PosSizeShift1st = 4, // 2 bits + PosSizeShift2nd = 6, // 2 bits + + UseIntCallConv = 0, // struct is passed according to integer calling convention + + // The flags and bitfields + OnlyOne = 1 << PosOnlyOne, // has only one field, which is floating-point + BothFloat = 1 << PosBothFloat, // has two fields, both are floating-point + FloatInt = 1 << PosFloatInt, // has two fields, 1st is floating and 2nd is integer + IntFloat = 1 << PosIntFloat, // has two fields, 2nd is floating and 1st is integer + SizeShift1stMask = 0b11 << PosSizeShift1st, // log2(size) of 1st field + SizeShift2ndMask = 0b11 << PosSizeShift2nd, // log2(size) of 2nd field + // Note: flags OnlyOne, BothFloat, FloatInt, and IntFloat are mutually exclusive + }; +} + +// On RISC-V and LoongArch a struct with up to two non-empty fields, at least one of them floating-point, +// can be passed in registers according to hardware FP calling convention. FpStructInRegistersInfo represents +// passing information for such parameters. +struct FpStructInRegistersInfo +{ + FpStruct::Flags flags; + uint32_t offset1st; + uint32_t offset2nd; + + unsigned SizeShift1st() const { return (flags >> FpStruct::PosSizeShift1st) & 0b11; } + unsigned SizeShift2nd() const { return (flags >> FpStruct::PosSizeShift2nd) & 0b11; } + + unsigned Size1st() const { return 1u << SizeShift1st(); } + unsigned Size2nd() const { return 1u << SizeShift2nd(); } + + const char* FlagName() const + { + switch (flags & (FpStruct::OnlyOne | FpStruct::BothFloat | FpStruct::FloatInt | FpStruct::IntFloat)) + { + case FpStruct::OnlyOne: return "OnlyOne"; + case FpStruct::BothFloat: return "BothFloat"; + case FpStruct::FloatInt: return "FloatInt"; + case FpStruct::IntFloat: return "IntFloat"; + default: return "?"; + } + } + + StructFloatFieldInfoFlags ToOldFlags() const + { + return StructFloatFieldInfoFlags( + ((flags & FpStruct::OnlyOne) ? STRUCT_FLOAT_FIELD_ONLY_ONE : 0) | + ((flags & FpStruct::BothFloat) ? STRUCT_FLOAT_FIELD_ONLY_TWO : 0) | + ((flags & FpStruct::FloatInt) ? STRUCT_FLOAT_FIELD_FIRST : 0) | + ((flags & FpStruct::IntFloat) ? STRUCT_FLOAT_FIELD_SECOND : 0) | + ((SizeShift1st() == 3) ? STRUCT_FIRST_FIELD_SIZE_IS8 : 0) | + ((SizeShift2nd() == 3) ? STRUCT_SECOND_FIELD_SIZE_IS8 : 0)); + } +}; +#endif // defined(TARGET_RISCV64) || defined(TARGET_LOONGARCH64) + //=============================================================================================== // // GC data appears before the beginning of the MethodTable From d4be92c28b9295a67306c6347f9648f0579a1a6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomek=20Sowi=C5=84ski?= Date: Thu, 11 Jul 2024 10:50:47 +0200 Subject: [PATCH 32/35] Merge LoongArch and RISC-V AOT calculation of FpStructInRegistersInfo because they were identical. Move it to Common\Internal/Runtime because it's no longer exposed in JIT interface. --- .../Runtime/RiscVLoongArch64FpStruct.cs} | 89 ++++++++- .../tools/Common/JitInterface/CorInfoImpl.cs | 19 +- .../tools/Common/JitInterface/CorInfoTypes.cs | 83 --------- .../RiscV64PassFpStructInRegisters.cs | 172 ------------------ .../ReadyToRun/ArgIterator.cs | 6 +- .../ReadyToRun/TransitionBlock.cs | 8 +- .../ILCompiler.ReadyToRun.csproj | 3 +- .../ILCompiler.RyuJit.csproj | 7 +- 8 files changed, 99 insertions(+), 288 deletions(-) rename src/coreclr/tools/Common/{JitInterface/LoongArch64PassStructInRegister.cs => Internal/Runtime/RiscVLoongArch64FpStruct.cs} (64%) delete mode 100644 src/coreclr/tools/Common/JitInterface/RiscV64PassFpStructInRegisters.cs diff --git a/src/coreclr/tools/Common/JitInterface/LoongArch64PassStructInRegister.cs b/src/coreclr/tools/Common/Internal/Runtime/RiscVLoongArch64FpStruct.cs similarity index 64% rename from src/coreclr/tools/Common/JitInterface/LoongArch64PassStructInRegister.cs rename to src/coreclr/tools/Common/Internal/Runtime/RiscVLoongArch64FpStruct.cs index 7db7743db4f10..ba76758241bf5 100644 --- a/src/coreclr/tools/Common/JitInterface/LoongArch64PassStructInRegister.cs +++ b/src/coreclr/tools/Common/Internal/Runtime/RiscVLoongArch64FpStruct.cs @@ -9,7 +9,90 @@ namespace Internal.JitInterface { - internal static class LoongArch64PassStructInRegister + // StructFloatFieldInfoFlags: used on LoongArch64 and RISC-V architecture as a legacy representation of + // FpStructInRegistersInfo, returned by FpStructInRegistersInfo.ToOldFlags() + // + // `STRUCT_NO_FLOAT_FIELD` means structs are not passed using the float register(s). + // + // Otherwise, and only for structs with no more than two fields and a total struct size no larger + // than two pointers: + // + // The lowest four bits denote the floating-point info: + // bit 0: `1` means there is only one float or double field within the struct. + // bit 1: `1` means only the first field is floating-point type. + // bit 2: `1` means only the second field is floating-point type. + // bit 3: `1` means the two fields are both floating-point type. + // The bits[5:4] denoting whether the field size is 8-bytes: + // bit 4: `1` means the first field's size is 8. + // bit 5: `1` means the second field's size is 8. + // + // Note that bit 0 and 3 cannot both be set. + [Flags] + public enum StructFloatFieldInfoFlags + { + STRUCT_NO_FLOAT_FIELD = 0x0, + STRUCT_FLOAT_FIELD_ONLY_ONE = 0x1, + STRUCT_FLOAT_FIELD_ONLY_TWO = 0x8, + STRUCT_FLOAT_FIELD_FIRST = 0x2, + STRUCT_FLOAT_FIELD_SECOND = 0x4, + STRUCT_FIRST_FIELD_SIZE_IS8 = 0x10, + STRUCT_SECOND_FIELD_SIZE_IS8 = 0x20, + }; + + + // Bitfields for FpStructInRegistersInfo.flags + [Flags] + public enum FpStruct + { + // Positions of flags and bitfields + PosOnlyOne = 0, + PosBothFloat = 1, + PosFloatInt = 2, + PosIntFloat = 3, + PosSizeShift1st = 4, // 2 bits + PosSizeShift2nd = 6, // 2 bits + + UseIntCallConv = 0, // struct is passed according to integer calling convention + + // The flags and bitfields + OnlyOne = 1 << PosOnlyOne, // has only one field, which is floating-point + BothFloat = 1 << PosBothFloat, // has two fields, both are floating-point + FloatInt = 1 << PosFloatInt, // has two fields, 1st is floating and 2nd is integer + IntFloat = 1 << PosIntFloat, // has two fields, 2nd is floating and 1st is integer + SizeShift1stMask = 0b11 << PosSizeShift1st, // log2(size) of 1st field + SizeShift2ndMask = 0b11 << PosSizeShift2nd, // log2(size) of 2nd field + // Note: flags OnlyOne, BothFloat, FloatInt, and IntFloat are mutually exclusive + } + + // On RISC-V and LoongArch a struct with up to two non-empty fields, at least one of them floating-point, + // can be passed in registers according to hardware FP calling convention. FpStructInRegistersInfo represents + // passing information for such parameters. + public struct FpStructInRegistersInfo + { + public FpStruct flags; + public uint offset1st; + public uint offset2nd; + + public uint SizeShift1st() { return (uint)((int)flags >> (int)FpStruct.PosSizeShift1st) & 0b11; } + + public uint SizeShift2nd() { return (uint)((int)flags >> (int)FpStruct.PosSizeShift2nd) & 0b11; } + + public uint Size1st() { return 1u << (int)SizeShift1st(); } + public uint Size2nd() { return 1u << (int)SizeShift2nd(); } + + public StructFloatFieldInfoFlags ToOldFlags() + { + return + ((flags & FpStruct.OnlyOne) != 0 ? StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_ONLY_ONE : 0) | + ((flags & FpStruct.BothFloat) != 0 ? StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_ONLY_TWO : 0) | + ((flags & FpStruct.FloatInt) != 0 ? StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_FIRST : 0) | + ((flags & FpStruct.IntFloat) != 0 ? StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_SECOND : 0) | + ((SizeShift1st() == 3) ? StructFloatFieldInfoFlags.STRUCT_FIRST_FIELD_SIZE_IS8 : 0) | + ((SizeShift2nd() == 3) ? StructFloatFieldInfoFlags.STRUCT_SECOND_FIELD_SIZE_IS8 : 0); + } + } + + internal static class RiscVLoongArch64FpStruct { private const int ENREGISTERED_PARAMTYPE_MAXSIZE = 16, @@ -125,8 +208,10 @@ private static bool FlattenFields(TypeDesc td, uint offset, ref FpStructInRegist private static bool IsAligned(uint val, uint alignment) => 0 == (val & (alignment - 1)); - public static FpStructInRegistersInfo GetLoongArch64PassFpStructInRegistersInfo(TypeDesc td) + public static FpStructInRegistersInfo GetFpStructInRegistersInfo(TypeDesc td, TargetArchitecture arch) { + Debug.Assert(arch is TargetArchitecture.RiscV64 or TargetArchitecture.LoongArch64); + if (td.GetElementSize().AsInt > ENREGISTERED_PARAMTYPE_MAXSIZE) return new FpStructInRegistersInfo{}; diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index fea3cfee54806..a0d2702f33cf3 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -3456,23 +3456,8 @@ private void getSwiftLowering(CORINFO_CLASS_STRUCT_* structHnd, ref CORINFO_SWIF private void getFpStructLowering(CORINFO_CLASS_STRUCT_* structHnd, ref CORINFO_FPSTRUCT_LOWERING lowering) { - TypeDesc typeDesc = HandleToObject(structHnd); - var target = _compilation.TypeSystemContext.Target; - FpStructInRegistersInfo info; - if (target.Architecture is TargetArchitecture.RiscV64) - { - info = RiscV64PassFpStructInRegisters.GetRiscV64PassFpStructInRegistersInfo(typeDesc); - } - else if (target.Architecture is TargetArchitecture.LoongArch64) - { - info = LoongArch64PassStructInRegister.GetLoongArch64PassFpStructInRegistersInfo(typeDesc); - } - else - { - Debug.Assert(false, "Unsupported architecture for getFpStructInRegistersInfo"); - return; - } - + FpStructInRegistersInfo info = RiscVLoongArch64FpStruct.GetFpStructInRegistersInfo( + HandleToObject(structHnd), _compilation.TypeSystemContext.Target.Architecture); if (info.flags != FpStruct.UseIntCallConv) { lowering = new CORINFO_FPSTRUCT_LOWERING { diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs index 5c20e921ea439..205221c2dff7c 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs @@ -1221,89 +1221,6 @@ public struct SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR public byte eightByteOffsets1; }; - // StructFloatFieldInfoFlags: used on LoongArch64 and RISC-V architecture as a legacy representation of - // FpStructInRegistersInfo, returned by FpStructInRegistersInfo.ToOldFlags() - // - // `STRUCT_NO_FLOAT_FIELD` means structs are not passed using the float register(s). - // - // Otherwise, and only for structs with no more than two fields and a total struct size no larger - // than two pointers: - // - // The lowest four bits denote the floating-point info: - // bit 0: `1` means there is only one float or double field within the struct. - // bit 1: `1` means only the first field is floating-point type. - // bit 2: `1` means only the second field is floating-point type. - // bit 3: `1` means the two fields are both floating-point type. - // The bits[5:4] denoting whether the field size is 8-bytes: - // bit 4: `1` means the first field's size is 8. - // bit 5: `1` means the second field's size is 8. - // - // Note that bit 0 and 3 cannot both be set. - [Flags] - public enum StructFloatFieldInfoFlags - { - STRUCT_NO_FLOAT_FIELD = 0x0, - STRUCT_FLOAT_FIELD_ONLY_ONE = 0x1, - STRUCT_FLOAT_FIELD_ONLY_TWO = 0x8, - STRUCT_FLOAT_FIELD_FIRST = 0x2, - STRUCT_FLOAT_FIELD_SECOND = 0x4, - STRUCT_FIRST_FIELD_SIZE_IS8 = 0x10, - STRUCT_SECOND_FIELD_SIZE_IS8 = 0x20, - }; - - - // Bitfields for FpStructInRegistersInfo.flags - [Flags] - public enum FpStruct - { - // Positions of flags and bitfields - PosOnlyOne = 0, - PosBothFloat = 1, - PosFloatInt = 2, - PosIntFloat = 3, - PosSizeShift1st = 4, // 2 bits - PosSizeShift2nd = 6, // 2 bits - - UseIntCallConv = 0, // struct is passed according to integer calling convention - - // The flags and bitfields - OnlyOne = 1 << PosOnlyOne, // has only one field, which is floating-point - BothFloat = 1 << PosBothFloat, // has two fields, both are floating-point - FloatInt = 1 << PosFloatInt, // has two fields, 1st is floating and 2nd is integer - IntFloat = 1 << PosIntFloat, // has two fields, 2nd is floating and 1st is integer - SizeShift1stMask = 0b11 << PosSizeShift1st, // log2(size) of 1st field - SizeShift2ndMask = 0b11 << PosSizeShift2nd, // log2(size) of 2nd field - // Note: flags OnlyOne, BothFloat, FloatInt, and IntFloat are mutually exclusive - } - - // On RISC-V and LoongArch a struct with up to two non-empty fields, at least one of them floating-point, - // can be passed in registers according to hardware FP calling convention. FpStructInRegistersInfo represents - // passing information for such parameters. - public struct FpStructInRegistersInfo - { - public FpStruct flags; - public uint offset1st; - public uint offset2nd; - - public uint SizeShift1st() { return (uint)((int)flags >> (int)FpStruct.PosSizeShift1st) & 0b11; } - - public uint SizeShift2nd() { return (uint)((int)flags >> (int)FpStruct.PosSizeShift2nd) & 0b11; } - - public uint Size1st() { return 1u << (int)SizeShift1st(); } - public uint Size2nd() { return 1u << (int)SizeShift2nd(); } - - public StructFloatFieldInfoFlags ToOldFlags() - { - return - ((flags & FpStruct.OnlyOne) != 0 ? StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_ONLY_ONE : 0) | - ((flags & FpStruct.BothFloat) != 0 ? StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_ONLY_TWO : 0) | - ((flags & FpStruct.FloatInt) != 0 ? StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_FIRST : 0) | - ((flags & FpStruct.IntFloat) != 0 ? StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_SECOND : 0) | - ((SizeShift1st() == 3) ? StructFloatFieldInfoFlags.STRUCT_FIRST_FIELD_SIZE_IS8 : 0) | - ((SizeShift2nd() == 3) ? StructFloatFieldInfoFlags.STRUCT_SECOND_FIELD_SIZE_IS8 : 0); - } - } - // DEBUGGER DATA public enum MappingTypes { diff --git a/src/coreclr/tools/Common/JitInterface/RiscV64PassFpStructInRegisters.cs b/src/coreclr/tools/Common/JitInterface/RiscV64PassFpStructInRegisters.cs deleted file mode 100644 index 7dfba63e1d836..0000000000000 --- a/src/coreclr/tools/Common/JitInterface/RiscV64PassFpStructInRegisters.cs +++ /dev/null @@ -1,172 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -using System; -using System.Collections.Generic; -using System.Diagnostics; -using ILCompiler; -using Internal.TypeSystem; -using static Internal.JitInterface.FpStruct; - -namespace Internal.JitInterface -{ - internal static class RiscV64PassFpStructInRegisters - { - private const int - ENREGISTERED_PARAMTYPE_MAXSIZE = 16, - TARGET_POINTER_SIZE = 8; - - private static void SetFpStructInRegistersInfoField(ref FpStructInRegistersInfo info, int index, - bool isFloating, uint size, uint offset) - { - Debug.Assert(index < 2); - if (isFloating) - Debug.Assert(size == sizeof(float) || size == sizeof(double)); - - Debug.Assert(size >= 1 && size <= 8); - Debug.Assert((size & (size - 1)) == 0, "size needs to be a power of 2"); - const int sizeShiftLUT = (0 << (1*2)) | (1 << (2*2)) | (2 << (4*2)) | (3 << (8*2)); - int sizeShift = (sizeShiftLUT >> ((int)size * 2)) & 0b11; - - // Use FloatInt and IntFloat as marker flags for 1st and 2nd field respectively being floating. - // Fix to real flags (with OnlyOne and BothFloat) after flattening is complete. - Debug.Assert((int)PosIntFloat == (int)PosFloatInt + 1, "FloatInt and IntFloat need to be adjacent"); - Debug.Assert((int)PosSizeShift2nd == (int)PosSizeShift1st + 2, "SizeShift1st and 2nd need to be adjacent"); - int floatFlag = Convert.ToInt32(isFloating) << ((int)PosFloatInt + index); - int sizeShiftMask = sizeShift << ((int)PosSizeShift1st + 2 * index); - - info.flags |= (FpStruct)(floatFlag | sizeShiftMask); - (index == 0 ? ref info.offset1st : ref info.offset2nd) = offset; - } - - private static bool HandleInlineArray(int elementTypeIndex, int nElements, ref FpStructInRegistersInfo info, ref int typeIndex) - { - int nFlattenedFieldsPerElement = typeIndex - elementTypeIndex; - if (nFlattenedFieldsPerElement == 0) - { - Debug.Assert(nElements == 1, "HasImpliedRepeatedFields must have returned a false positive"); - return true; // ignoring empty struct - } - - Debug.Assert(nFlattenedFieldsPerElement == 1 || nFlattenedFieldsPerElement == 2); - - if (nElements > 2) - return false; // array has too many elements - - if (nElements == 2) - { - if (typeIndex + nFlattenedFieldsPerElement > 2) - return false; // array has too many fields per element - - Debug.Assert(elementTypeIndex == 0); - Debug.Assert(typeIndex == 1); - - // Duplicate the array element info - Debug.Assert((int)FpStruct.IntFloat == ((int)FpStruct.FloatInt << 1), - "FloatInt and IntFloat need to be adjacent"); - Debug.Assert((int)FpStruct.SizeShift2ndMask == ((int)FpStruct.SizeShift1stMask << 2), - "SizeShift1st and 2nd need to be adjacent"); - // Take the 1st field info and shift up to the 2nd field's positions - int floatFlag = (int)(info.flags & FpStruct.FloatInt) << 1; - int sizeShiftMask = (int)(info.flags & FpStruct.SizeShift1stMask) << 2; - info.flags |= (FpStruct)(floatFlag | sizeShiftMask); // merge with 1st field - info.offset2nd = info.offset1st + info.Size1st(); // bump up the field offset - } - return true; - } - - private static bool FlattenFields(TypeDesc td, uint offset, ref FpStructInRegistersInfo info, ref int typeIndex) - { - IEnumerable fields = td.GetFields(); - int nFields = 0; - int elementTypeIndex = typeIndex; - FieldDesc prevField = null; - foreach (FieldDesc field in fields) - { - if (field.IsStatic) - continue; - nFields++; - - if (prevField != null && prevField.Offset.AsInt + prevField.FieldType.GetElementSize().AsInt > field.Offset.AsInt) - return false; // fields overlap, treat as union - - prevField = field; - - TypeFlags category = field.FieldType.Category; - if (category == TypeFlags.ValueType) - { - TypeDesc nested = field.FieldType; - if (!FlattenFields(nested, offset + (uint)field.Offset.AsInt, ref info, ref typeIndex)) - return false; - } - else if (field.FieldType.GetElementSize().AsInt <= TARGET_POINTER_SIZE) - { - if (typeIndex >= 2) - return false; // too many fields - - bool isFloating = category is TypeFlags.Single or TypeFlags.Double; - SetFpStructInRegistersInfoField(ref info, typeIndex++, - isFloating, (uint)field.FieldType.GetElementSize().AsInt, offset + (uint)field.Offset.AsInt); - } - else - { - return false; // field is too big - } - } - - if ((td as MetadataType).HasImpliedRepeatedFields()) - { - Debug.Assert(nFields == 1); - int nElements = td.GetElementSize().AsInt / prevField.FieldType.GetElementSize().AsInt; - if (!HandleInlineArray(elementTypeIndex, nElements, ref info, ref typeIndex)) - return false; - } - return true; - } - - private static bool IsAligned(uint val, uint alignment) => 0 == (val & (alignment - 1)); - - public static FpStructInRegistersInfo GetRiscV64PassFpStructInRegistersInfo(TypeDesc td) - { - if (td.GetElementSize().AsInt > ENREGISTERED_PARAMTYPE_MAXSIZE) - return new FpStructInRegistersInfo{}; - - FpStructInRegistersInfo info = new FpStructInRegistersInfo{}; - int nFields = 0; - if (!FlattenFields(td, 0, ref info, ref nFields)) - return new FpStructInRegistersInfo{}; - - if ((info.flags & (FloatInt | IntFloat)) == 0) - return new FpStructInRegistersInfo{}; // struct has no floating fields - - Debug.Assert(nFields == 1 || nFields == 2); - - if ((info.flags & (FloatInt | IntFloat)) == (FloatInt | IntFloat)) - { - Debug.Assert(nFields == 2); - info.flags ^= (FloatInt | IntFloat | BothFloat); // replace (FloatInt | IntFloat) with BothFloat - } - else if (nFields == 1) - { - Debug.Assert((info.flags & FloatInt) != 0); - Debug.Assert((info.flags & (IntFloat | SizeShift2ndMask)) == 0); - Debug.Assert(info.offset2nd == 0); - info.flags ^= (FloatInt | OnlyOne); // replace FloatInt with OnlyOne - } - Debug.Assert(nFields == ((info.flags & OnlyOne) != 0 ? 1 : 2)); - FpStruct floatFlags = info.flags & (OnlyOne | BothFloat | FloatInt | IntFloat); - Debug.Assert(floatFlags != 0); - Debug.Assert(((uint)floatFlags & ((uint)floatFlags - 1)) == 0, - "there can be only one of (OnlyOne | BothFloat | FloatInt | IntFloat)"); - if (nFields == 2) - { - uint end1st = info.offset1st + info.Size1st(); - uint end2nd = info.offset2nd + info.Size2nd(); - Debug.Assert(end1st <= info.offset2nd || end2nd <= info.offset1st, "fields must not overlap"); - } - Debug.Assert(info.offset1st + info.Size1st() <= td.GetElementSize().AsInt); - Debug.Assert(info.offset2nd + info.Size2nd() <= td.GetElementSize().AsInt); - - return info; - } - } -} diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ArgIterator.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ArgIterator.cs index 584866dd4ce4b..cd945116e3e9c 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ArgIterator.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ArgIterator.cs @@ -1351,7 +1351,8 @@ public int GetNextOffset() } else { - info = LoongArch64PassStructInRegister.GetLoongArch64PassFpStructInRegistersInfo(_argTypeHandle.GetRuntimeTypeHandle()); + info = RiscVLoongArch64FpStruct.GetFpStructInRegistersInfo( + _argTypeHandle.GetRuntimeTypeHandle(), TargetArchitecture.LoongArch64); if (info.flags != FpStruct.UseIntCallConv) { cFPRegs = ((info.flags & FpStruct.BothFloat) != 0) ? 2 : 1; @@ -1480,7 +1481,8 @@ public int GetNextOffset() } else { - info = RiscV64PassFpStructInRegisters.GetRiscV64PassFpStructInRegistersInfo(_argTypeHandle.GetRuntimeTypeHandle()); + info = RiscVLoongArch64FpStruct.GetFpStructInRegistersInfo( + _argTypeHandle.GetRuntimeTypeHandle(), TargetArchitecture.RiscV64); if (info.flags != FpStruct.UseIntCallConv) { cFPRegs = ((info.flags & FpStruct.BothFloat) != 0) ? 2 : 1; diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/TransitionBlock.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/TransitionBlock.cs index 5092f59dd6bf1..621168ecd66eb 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/TransitionBlock.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/TransitionBlock.cs @@ -396,12 +396,10 @@ public void ComputeReturnValueTreatment(CorElementType type, TypeHandle thRetTyp if (size <= EnregisteredReturnTypeIntegerMaxSize) { - if (IsLoongArch64) - fpReturnSize = (uint)LoongArch64PassStructInRegister.GetLoongArch64PassFpStructInRegistersInfo(thRetType.GetRuntimeTypeHandle()).flags; - else if (IsRiscV64) - fpReturnSize = (uint)RiscV64PassFpStructInRegisters.GetRiscV64PassFpStructInRegistersInfo(thRetType.GetRuntimeTypeHandle()).flags; + if (IsLoongArch64 || IsRiscV64) + fpReturnSize = (uint)RiscVLoongArch64FpStruct.GetFpStructInRegistersInfo( + thRetType.GetRuntimeTypeHandle(), Architecture).flags; break; - } } diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj index e4de279ec885f..da8f861c4dba5 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj @@ -133,8 +133,7 @@ - - + diff --git a/src/coreclr/tools/aot/ILCompiler.RyuJit/ILCompiler.RyuJit.csproj b/src/coreclr/tools/aot/ILCompiler.RyuJit/ILCompiler.RyuJit.csproj index c980efdb95442..4ba7b607e0bde 100644 --- a/src/coreclr/tools/aot/ILCompiler.RyuJit/ILCompiler.RyuJit.csproj +++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/ILCompiler.RyuJit.csproj @@ -82,11 +82,8 @@ JitInterface\SystemVStructClassificator.cs - - JitInterface\LoongArch64PassStructInRegister.cs - - - JitInterface\RiscV64PassFpStructInRegisters.cs + + Common\RiscVLoongArch64FpStruct.cs JitInterface\SwiftPhysicalLowering.cs From 823df8b83d07fce189226834a4d50438d6b0ce5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomek=20Sowi=C5=84ski?= Date: Fri, 12 Jul 2024 10:49:35 +0200 Subject: [PATCH 33/35] Don't zero-initialize CORINFO_FPSTRUCT_LOWERING --- src/coreclr/inc/corinfo.h | 2 -- src/coreclr/jit/compiler.cpp | 23 +++++++++++-------- src/coreclr/jit/targetriscv64.cpp | 20 ++++++++-------- .../tools/Common/JitInterface/CorInfoImpl.cs | 8 +++---- .../superpmi-shared/methodcontext.cpp | 14 +++++++---- src/coreclr/vm/jitinterface.cpp | 11 ++++----- 6 files changed, 42 insertions(+), 36 deletions(-) diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index 9d778743cd26e..b5850a625fd14 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -1934,11 +1934,9 @@ struct CORINFO_SWIFT_LOWERING #define MAX_FPSTRUCT_LOWERED_ELEMENTS 2 // Lowering information on fields of a struct passed by hardware floating-point calling convention on RISC-V and LoongArch -// NOTE: all array elements past numLoweredElements are zero-initialized struct CORINFO_FPSTRUCT_LOWERING { // Whether the struct should be passed by integer calling convention (cannot be passed by FP calling convention). - // If true, all other fields of CORINFO_FPSTRUCT_LOWERING are zeroed. bool byIntegerCallConv; // Types of lowered struct fields. CorInfoType loweredElements[MAX_FPSTRUCT_LOWERED_ELEMENTS]; diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp index 2d250b315a01f..78fde7f2d3d84 100644 --- a/src/coreclr/jit/compiler.cpp +++ b/src/coreclr/jit/compiler.cpp @@ -931,17 +931,20 @@ var_types Compiler::getReturnTypeForStruct(CORINFO_CLASS_HANDLE clsHnd, if (structSize <= (TARGET_POINTER_SIZE * 2)) { const CORINFO_FPSTRUCT_LOWERING* lowering = GetFpStructLowering(clsHnd); - if (lowering->numLoweredElements == 1) + if (!lowering->byIntegerCallConv) { - useType = JITtype2varType(lowering->loweredElements[0]); - assert(varTypeIsFloating(useType)); - howToReturnStruct = SPK_PrimitiveType; - } - else if (!lowering->byIntegerCallConv) - { - assert(lowering->numLoweredElements == 2); - howToReturnStruct = SPK_ByValue; - useType = TYP_STRUCT; + if (lowering->numLoweredElements == 1) + { + useType = JITtype2varType(lowering->loweredElements[0]); + assert(varTypeIsFloating(useType)); + howToReturnStruct = SPK_PrimitiveType; + } + else + { + assert(lowering->numLoweredElements == 2); + howToReturnStruct = SPK_ByValue; + useType = TYP_STRUCT; + } } } diff --git a/src/coreclr/jit/targetriscv64.cpp b/src/coreclr/jit/targetriscv64.cpp index 3711fb661c48e..308df8c980f8d 100644 --- a/src/coreclr/jit/targetriscv64.cpp +++ b/src/coreclr/jit/targetriscv64.cpp @@ -73,17 +73,19 @@ ABIPassingInformation RiscV64Classifier::Classify(Compiler* comp, else if (!structLayout->IsBlockLayout()) { lowering = comp->GetFpStructLowering(structLayout->GetClassHandle()); - assert((lowering->numLoweredElements > 0) == !lowering->byIntegerCallConv); - assert(lowering->numLoweredElements <= 2); - INDEBUG(unsigned debugIntFields = 0;) - for (size_t i = 0; i < lowering->numLoweredElements; ++i) + if (!lowering->byIntegerCallConv) { - var_types type = JITtype2varType(lowering->loweredElements[i]); - floatFields += (unsigned)varTypeIsFloating(type); - INDEBUG(debugIntFields += (unsigned)varTypeIsIntegralOrI(type);) + assert((lowering->numLoweredElements == 1) || (lowering->numLoweredElements == 2)); + INDEBUG(unsigned debugIntFields = 0;) + for (size_t i = 0; i < lowering->numLoweredElements; ++i) + { + var_types type = JITtype2varType(lowering->loweredElements[i]); + floatFields += (unsigned)varTypeIsFloating(type); + INDEBUG(debugIntFields += (unsigned)varTypeIsIntegralOrI(type);) + } + intFields = lowering->numLoweredElements - floatFields; + assert(debugIntFields == intFields); } - intFields = lowering->numLoweredElements - floatFields; - assert(debugIntFields == intFields); } } else diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index a0d2702f33cf3..e0c1130de1889 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -3460,12 +3460,10 @@ private void getFpStructLowering(CORINFO_CLASS_STRUCT_* structHnd, ref CORINFO_F HandleToObject(structHnd), _compilation.TypeSystemContext.Target.Architecture); if (info.flags != FpStruct.UseIntCallConv) { - lowering = new CORINFO_FPSTRUCT_LOWERING { - byIntegerCallConv = false, - numLoweredElements = ((info.flags & FpStruct.OnlyOne) != 0) ? 1 : 2, - }; + lowering.byIntegerCallConv = false; lowering.Offsets[0] = info.offset1st; lowering.Offsets[1] = info.offset2nd; + lowering.numLoweredElements = ((info.flags & FpStruct.OnlyOne) != 0) ? 1 : 2; if ((info.flags & (FpStruct.BothFloat | FpStruct.FloatInt | FpStruct.OnlyOne)) != 0) lowering.LoweredElements[0] = (info.SizeShift1st() == 3) ? CorInfoType.CORINFO_TYPE_DOUBLE : CorInfoType.CORINFO_TYPE_FLOAT; @@ -3488,7 +3486,7 @@ private void getFpStructLowering(CORINFO_CLASS_STRUCT_* structHnd, ref CORINFO_F } else { - lowering = new CORINFO_FPSTRUCT_LOWERING{ byIntegerCallConv = true }; + lowering.byIntegerCallConv = true; } } diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp index 280e0664b4725..3caa10d11474a 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp @@ -6337,9 +6337,12 @@ void MethodContext::dmpGetSwiftLowering( { printf("GetSwiftLowering key structHnd-%016" PRIX64 ", value byReference-%u numLoweredElements-%u", key, value.byReference, value.numLoweredElements); - for (size_t i = 0; i < value.numLoweredElements; i++) + if (!value.byReference) { - printf(" [%zu] %u", i, value.loweredElements[i]); + for (size_t i = 0; i < value.numLoweredElements; i++) + { + printf(" [%zu] %u", i, value.loweredElements[i]); + } } } void MethodContext::repGetSwiftLowering(CORINFO_CLASS_HANDLE structHnd, CORINFO_SWIFT_LOWERING* pLowering) @@ -6387,9 +6390,12 @@ void MethodContext::dmpGetFpStructLowering( { printf("GetFpStructLowering key structHnd-%016" PRIX64 ", value byIntegerCallConv-%u numLoweredElements-%u", key, value.byIntegerCallConv, value.numLoweredElements); - for (size_t i = 0; i < value.numLoweredElements; i++) + if (!value.byIntegerCallConv) { - printf(" [%zu] %u", i, value.loweredElements[i]); + for (size_t i = 0; i < value.numLoweredElements; i++) + { + printf(" [%zu] %u", i, value.loweredElements[i]); + } } } void MethodContext::repGetFpStructLowering(CORINFO_CLASS_HANDLE structHnd, CORINFO_FPSTRUCT_LOWERING* pLowering) diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 76e123a6404ce..31782c0c2375c 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -9535,11 +9535,10 @@ void CEEInfo::getFpStructLowering(CORINFO_CLASS_HANDLE structHnd, CORINFO_FPSTRU FpStructInRegistersInfo info = MethodTable::GetFpStructInRegistersInfo(TypeHandle(structHnd)); if (info.flags != FpStruct::UseIntCallConv) { - *pLowering = { - .byIntegerCallConv = false, - .offsets = { info.offset1st, info.offset2nd }, - .numLoweredElements = (info.flags & FpStruct::OnlyOne) ? 1ul : 2ul, - }; + pLowering->byIntegerCallConv = false; + pLowering->offsets[0] = info.offset1st; + pLowering->offsets[1] = info.offset2nd; + pLowering->numLoweredElements = (info.flags & FpStruct::OnlyOne) ? 1ul : 2ul; if (info.flags & (FpStruct::BothFloat | FpStruct::FloatInt | FpStruct::OnlyOne)) pLowering->loweredElements[0] = (info.SizeShift1st() == 3) ? CORINFO_TYPE_DOUBLE : CORINFO_TYPE_FLOAT; @@ -9562,7 +9561,7 @@ void CEEInfo::getFpStructLowering(CORINFO_CLASS_HANDLE structHnd, CORINFO_FPSTRU } else { - *pLowering = { .byIntegerCallConv = true }; + pLowering->byIntegerCallConv = true; } #endif // TARGET_RISCV64 || TARGET_LOONGARCH64 From 8ddd349fe55b0d43a3d9fdf6969619778151ab9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomek=20Sowi=C5=84ski?= Date: Thu, 25 Jul 2024 09:41:37 +0200 Subject: [PATCH 34/35] Add note for CORINFO_FPSTRUCT_LOWERING::loweredElements type --- src/coreclr/inc/corinfo.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index 715c506c963c9..0574719eac863 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -1909,6 +1909,8 @@ struct CORINFO_FPSTRUCT_LOWERING // Whether the struct should be passed by integer calling convention (cannot be passed by FP calling convention). bool byIntegerCallConv; // Types of lowered struct fields. + // Note: the integer field is denoted with a signed type reflecting size only so e.g. ushort is reported + // as CORINFO_TYPE_SHORT and Object or string is reported as CORINFO_TYPE_LONG. CorInfoType loweredElements[MAX_FPSTRUCT_LOWERED_ELEMENTS]; // Offsets of lowered struct fields. uint32_t offsets[MAX_FPSTRUCT_LOWERED_ELEMENTS]; From 9dc5ed54b56da3fc56cf9719afa05ea85c10011b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomek=20Sowi=C5=84ski?= Date: Thu, 25 Jul 2024 10:47:58 +0200 Subject: [PATCH 35/35] object is lowercase --- src/coreclr/inc/corinfo.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index 0574719eac863..172bd1f878c79 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -1910,7 +1910,7 @@ struct CORINFO_FPSTRUCT_LOWERING bool byIntegerCallConv; // Types of lowered struct fields. // Note: the integer field is denoted with a signed type reflecting size only so e.g. ushort is reported - // as CORINFO_TYPE_SHORT and Object or string is reported as CORINFO_TYPE_LONG. + // as CORINFO_TYPE_SHORT and object or string is reported as CORINFO_TYPE_LONG. CorInfoType loweredElements[MAX_FPSTRUCT_LOWERED_ELEMENTS]; // Offsets of lowered struct fields. uint32_t offsets[MAX_FPSTRUCT_LOWERED_ELEMENTS];