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] 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;