diff --git a/src/coreclr/jit/codegenriscv64.cpp b/src/coreclr/jit/codegenriscv64.cpp index 39d25e316e529..4b9c4119854cd 100644 --- a/src/coreclr/jit/codegenriscv64.cpp +++ b/src/coreclr/jit/codegenriscv64.cpp @@ -816,8 +816,8 @@ void CodeGen::genCaptureFuncletPrologEpilogInfo() if (compiler->lvaPSPSym != BAD_VAR_NUM) { - if (CallerSP_to_PSP_slot_delta != - compiler->lvaGetCallerSPRelativeOffset(compiler->lvaPSPSym)) // for debugging + if (CallerSP_to_PSP_slot_delta != compiler->lvaGetCallerSPRelativeOffset(compiler->lvaPSPSym)) // for + // debugging { printf("lvaGetCallerSPRelativeOffset(lvaPSPSym): %d\n", compiler->lvaGetCallerSPRelativeOffset(compiler->lvaPSPSym)); @@ -7162,35 +7162,6 @@ void CodeGen::instGen_MemoryBarrier(BarrierKind barrierKind) GetEmitter()->emitIns_I(INS_fence, EA_4BYTE, INS_BARRIER_FULL); } -//----------------------------------------------------------------------------------- -// genProfilingLeaveCallback: Generate the profiling function leave or tailcall callback. -// Technically, this is not part of the epilog; it is called when we are generating code for a GT_RETURN node. -// -// Arguments: -// helper - which helper to call. Either CORINFO_HELP_PROF_FCN_LEAVE or CORINFO_HELP_PROF_FCN_TAILCALL -// -// Return Value: -// None -// -void CodeGen::genProfilingLeaveCallback(unsigned helper /*= CORINFO_HELP_PROF_FCN_LEAVE*/) -{ - assert((helper == CORINFO_HELP_PROF_FCN_LEAVE) || (helper == CORINFO_HELP_PROF_FCN_TAILCALL)); - - // Only hook if profiler says it's okay. - if (!compiler->compIsProfilerHookNeeded()) - { - return; - } - - compiler->info.compProfilerCallback = true; - - // Need to save on to the stack level, since the helper call will pop the argument - unsigned saveStackLvl2 = genStackLevel; - - /* Restore the stack level */ - SetStackLevel(saveStackLvl2); -} - /*----------------------------------------------------------------------------- * * Push/Pop any callee-saved registers we have used @@ -8102,6 +8073,7 @@ void CodeGen::genFnPrologCalleeRegArgs() assert(!regArgMaskLive); } +#ifdef PROFILING_SUPPORTED //----------------------------------------------------------------------------------- // genProfilingEnterCallback: Generate the profiling function enter callback. // @@ -8110,17 +8082,79 @@ void CodeGen::genFnPrologCalleeRegArgs() // pInitRegZeroed - OUT parameter. *pInitRegZeroed set to 'false' if 'initReg' is // set to non-zero value after this call. // -// Return Value: -// None -// void CodeGen::genProfilingEnterCallback(regNumber initReg, bool* pInitRegZeroed) { assert(compiler->compGeneratingProlog); - // Give profiler a chance to back out of hooking this method if (!compiler->compIsProfilerHookNeeded()) { return; } + + ssize_t methHnd = (ssize_t)compiler->compProfilerMethHnd; + if (compiler->compProfilerMethHndIndirected) + { + instGen_Set_Reg_To_Imm(EA_PTR_DSP_RELOC, REG_PROFILER_ENTER_ARG_FUNC_ID, methHnd); + GetEmitter()->emitIns_R_R_I(INS_ld, EA_PTRSIZE, REG_PROFILER_ENTER_ARG_FUNC_ID, REG_PROFILER_ENTER_ARG_FUNC_ID, + 0); + } + else + { + instGen_Set_Reg_To_Imm(EA_PTRSIZE, REG_PROFILER_ENTER_ARG_FUNC_ID, methHnd); + } + + ssize_t callerSPOffset = -compiler->lvaToCallerSPRelativeOffset(0, isFramePointerUsed()); + genInstrWithConstant(INS_addi, EA_PTRSIZE, REG_PROFILER_ENTER_ARG_CALLER_SP, genFramePointerReg(), callerSPOffset, + REG_PROFILER_ENTER_ARG_CALLER_SP); + + genEmitHelperCall(CORINFO_HELP_PROF_FCN_ENTER, 0, EA_UNKNOWN); + + if ((genRegMask(initReg) & RBM_PROFILER_ENTER_TRASH)) + { + *pInitRegZeroed = false; + } } + +//----------------------------------------------------------------------------------- +// genProfilingLeaveCallback: Generate the profiling function leave or tailcall callback. +// Technically, this is not part of the epilog; it is called when we are generating code for a GT_RETURN node. +// +// Arguments: +// helper - which helper to call. Either CORINFO_HELP_PROF_FCN_LEAVE or CORINFO_HELP_PROF_FCN_TAILCALL +// +void CodeGen::genProfilingLeaveCallback(unsigned helper /*= CORINFO_HELP_PROF_FCN_LEAVE*/) +{ + assert((helper == CORINFO_HELP_PROF_FCN_LEAVE) || (helper == CORINFO_HELP_PROF_FCN_TAILCALL)); + + if (!compiler->compIsProfilerHookNeeded()) + { + return; + } + + compiler->info.compProfilerCallback = true; + + ssize_t methHnd = (ssize_t)compiler->compProfilerMethHnd; + if (compiler->compProfilerMethHndIndirected) + { + instGen_Set_Reg_To_Imm(EA_PTR_DSP_RELOC, REG_PROFILER_LEAVE_ARG_FUNC_ID, methHnd); + GetEmitter()->emitIns_R_R_I(INS_ld, EA_PTRSIZE, REG_PROFILER_LEAVE_ARG_FUNC_ID, REG_PROFILER_LEAVE_ARG_FUNC_ID, + 0); + } + else + { + instGen_Set_Reg_To_Imm(EA_PTRSIZE, REG_PROFILER_LEAVE_ARG_FUNC_ID, methHnd); + } + + gcInfo.gcMarkRegSetNpt(RBM_PROFILER_LEAVE_ARG_FUNC_ID); + + ssize_t callerSPOffset = -compiler->lvaToCallerSPRelativeOffset(0, isFramePointerUsed()); + genInstrWithConstant(INS_addi, EA_PTRSIZE, REG_PROFILER_LEAVE_ARG_CALLER_SP, genFramePointerReg(), callerSPOffset, + REG_PROFILER_LEAVE_ARG_CALLER_SP); + + gcInfo.gcMarkRegSetNpt(RBM_PROFILER_LEAVE_ARG_CALLER_SP); + + genEmitHelperCall(helper, 0, EA_UNKNOWN); +} +#endif // PROFILING_SUPPORTED + #endif // TARGET_RISCV64 diff --git a/src/coreclr/jit/targetriscv64.h b/src/coreclr/jit/targetriscv64.h index fb0f487e47476..a12bcc0498640 100644 --- a/src/coreclr/jit/targetriscv64.h +++ b/src/coreclr/jit/targetriscv64.h @@ -192,18 +192,18 @@ #define REG_PREV(reg) ((regNumber)((unsigned)(reg) - 1)) // The following registers are used in emitting Enter/Leave/Tailcall profiler callbacks - #define REG_PROFILER_ENTER_ARG_FUNC_ID REG_R16 - #define RBM_PROFILER_ENTER_ARG_FUNC_ID RBM_R16 - #define REG_PROFILER_ENTER_ARG_CALLER_SP REG_R17 - #define RBM_PROFILER_ENTER_ARG_CALLER_SP RBM_R17 - #define REG_PROFILER_LEAVE_ARG_FUNC_ID REG_R16 - #define RBM_PROFILER_LEAVE_ARG_FUNC_ID RBM_R16 - #define REG_PROFILER_LEAVE_ARG_CALLER_SP REG_R17 - #define RBM_PROFILER_LEAVE_ARG_CALLER_SP RBM_R17 + #define REG_PROFILER_ENTER_ARG_FUNC_ID REG_T0 + #define RBM_PROFILER_ENTER_ARG_FUNC_ID RBM_T0 + #define REG_PROFILER_ENTER_ARG_CALLER_SP REG_T1 + #define RBM_PROFILER_ENTER_ARG_CALLER_SP RBM_T1 + #define REG_PROFILER_LEAVE_ARG_FUNC_ID REG_PROFILER_ENTER_ARG_FUNC_ID + #define RBM_PROFILER_LEAVE_ARG_FUNC_ID RBM_PROFILER_ENTER_ARG_FUNC_ID + #define REG_PROFILER_LEAVE_ARG_CALLER_SP REG_PROFILER_ENTER_ARG_CALLER_SP + #define RBM_PROFILER_LEAVE_ARG_CALLER_SP RBM_PROFILER_ENTER_ARG_CALLER_SP // The registers trashed by profiler enter/leave/tailcall hook #define RBM_PROFILER_ENTER_TRASH (RBM_CALLEE_TRASH & ~(RBM_ARG_REGS|RBM_FLTARG_REGS|RBM_FP)) - #define RBM_PROFILER_LEAVE_TRASH (RBM_CALLEE_TRASH & ~(RBM_ARG_REGS|RBM_FLTARG_REGS|RBM_FP)) + #define RBM_PROFILER_LEAVE_TRASH RBM_PROFILER_ENTER_TRASH #define RBM_PROFILER_TAILCALL_TRASH RBM_PROFILER_LEAVE_TRASH // Which register are int and long values returned in ? diff --git a/src/coreclr/vm/proftoeeinterfaceimpl.h b/src/coreclr/vm/proftoeeinterfaceimpl.h index 83fe29b641eef..0ab307197b11a 100644 --- a/src/coreclr/vm/proftoeeinterfaceimpl.h +++ b/src/coreclr/vm/proftoeeinterfaceimpl.h @@ -56,14 +56,18 @@ class ProfileArgIterator private: void *m_handle; ArgIterator m_argIterator; -#if defined(UNIX_AMD64_ABI) || defined(TARGET_ARM64) +#if defined(UNIX_AMD64_ABI) || defined(TARGET_ARM64) || defined(TARGET_RISCV64) UINT64 m_bufferPos; -#if defined(UNIX_AMD64_ABI) +#if defined(UNIX_AMD64_ABI) || defined(TARGET_RISCV64) // On certain architectures we can pass args in non-sequential registers, // this function will copy the struct so it is laid out as it would be in memory // so it can be passed to the profiler - LPVOID CopyStructFromRegisters(); + LPVOID CopyStructFromRegisters( +#ifdef TARGET_RISCV64 + const ArgLocDesc* argLocDesc +#endif + ); #endif #if defined(TARGET_ARM64) diff --git a/src/coreclr/vm/riscv64/asmconstants.h b/src/coreclr/vm/riscv64/asmconstants.h index 1089bfe9fecb4..cf5cd285c2d6b 100644 --- a/src/coreclr/vm/riscv64/asmconstants.h +++ b/src/coreclr/vm/riscv64/asmconstants.h @@ -250,5 +250,34 @@ ASMCONSTANTS_C_ASSERT(CallCountingStubData__TargetForMethod == offsetof(CallCoun #define CallCountingStubData__TargetForThresholdReached 0x10 ASMCONSTANTS_C_ASSERT(CallCountingStubData__TargetForThresholdReached == offsetof(CallCountingStubData, TargetForThresholdReached)) +#ifdef PROFILING_SUPPORTED +#define PROFILE_ENTER 1 +#define PROFILE_LEAVE 2 +#define PROFILE_TAILCALL 4 + +#define SIZEOF__PROFILE_PLATFORM_SPECIFIC_DATA 312 +#define PROFILE_PLATFORM_SPECIFIC_DATA__argumentRegisters 16 +#define PROFILE_PLATFORM_SPECIFIC_DATA__functionId 80 +#define PROFILE_PLATFORM_SPECIFIC_DATA__floatArgumentRegisters 88 +#define PROFILE_PLATFORM_SPECIFIC_DATA__probeSp 152 +#define PROFILE_PLATFORM_SPECIFIC_DATA__profiledSp 160 +#define PROFILE_PLATFORM_SPECIFIC_DATA__hiddenArg 168 +#define PROFILE_PLATFORM_SPECIFIC_DATA__flags 176 + +ASMCONSTANTS_C_ASSERT(SIZEOF__PROFILE_PLATFORM_SPECIFIC_DATA == sizeof(PROFILE_PLATFORM_SPECIFIC_DATA)) + +#define ASMCONSTANTS_C_ASSERT_OFFSET(type, field) \ + ASMCONSTANTS_C_ASSERT(type##__##field == offsetof(type, field)) +ASMCONSTANTS_C_ASSERT_OFFSET(PROFILE_PLATFORM_SPECIFIC_DATA, argumentRegisters) +ASMCONSTANTS_C_ASSERT_OFFSET(PROFILE_PLATFORM_SPECIFIC_DATA, functionId) +ASMCONSTANTS_C_ASSERT_OFFSET(PROFILE_PLATFORM_SPECIFIC_DATA, floatArgumentRegisters) +ASMCONSTANTS_C_ASSERT_OFFSET(PROFILE_PLATFORM_SPECIFIC_DATA, probeSp) +ASMCONSTANTS_C_ASSERT_OFFSET(PROFILE_PLATFORM_SPECIFIC_DATA, profiledSp) +ASMCONSTANTS_C_ASSERT_OFFSET(PROFILE_PLATFORM_SPECIFIC_DATA, hiddenArg) +ASMCONSTANTS_C_ASSERT_OFFSET(PROFILE_PLATFORM_SPECIFIC_DATA, flags) +#undef ASMCONSTANTS_C_ASSERT_OFFSET + +#endif // PROFILING_SUPPORTED + #undef ASMCONSTANTS_RUNTIME_ASSERT #undef ASMCONSTANTS_C_ASSERT diff --git a/src/coreclr/vm/riscv64/asmhelpers.S b/src/coreclr/vm/riscv64/asmhelpers.S index 85ee7c30dbb64..49729c2ad6d35 100644 --- a/src/coreclr/vm/riscv64/asmhelpers.S +++ b/src/coreclr/vm/riscv64/asmhelpers.S @@ -894,43 +894,36 @@ LEAF_ENTRY JIT_ProfilerEnterLeaveTailcallStub, _TEXT ret LEAF_END JIT_ProfilerEnterLeaveTailcallStub, _TEXT -// ------------------------------------------------------------------ -#define PROFILE_ENTER 1 -#define PROFILE_LEAVE 2 -#define PROFILE_TAILCALL 4 -#define SIZEOF__PROFILE_PLATFORM_SPECIFIC_DATA 272 - // ------------------------------------------------------------------ .macro GenerateProfileHelper helper, flags NESTED_ENTRY \helper\()Naked, _TEXT, NoHandler // On entry: - // t1 = functionIDOrClientID - // t2 = profiledSp + // t0 = functionIDOrClientID + // t1 = profiledSp // t6 = throwable // // On exit: // Values of a0-a7, fa0-fa7, fp are preserved. // Values of other volatile registers are not preserved. + // Fill in PROFILE_PLATFORM_SPECIFIC_DATA struct PROLOG_SAVE_REG_PAIR_INDEXED fp, ra, SIZEOF__PROFILE_PLATFORM_SPECIFIC_DATA // Allocate space and save Fp, Pc. - SAVE_ARGUMENT_REGISTERS sp, 16 // Save t0 and argument registers (a0-a7). - sd zero, 88(sp) // Clear functionId. - SAVE_FLOAT_ARGUMENT_REGISTERS sp, 96 // Save floating-point/SIMD registers (fa0-fa7). - addi t6, fp, SIZEOF__PROFILE_PLATFORM_SPECIFIC_DATA // Compute probeSp - initial value of Sp on entry to the helper. - sd t6, 224(sp) // Save probeSp. - sd t2, 232(sp) // Save profiledSp. - - sd zero, 240(sp) // Clear hiddenArg. + SAVE_ARGUMENT_REGISTERS sp, PROFILE_PLATFORM_SPECIFIC_DATA__argumentRegisters + sd zero, PROFILE_PLATFORM_SPECIFIC_DATA__functionId(sp) + SAVE_FLOAT_ARGUMENT_REGISTERS sp, PROFILE_PLATFORM_SPECIFIC_DATA__floatArgumentRegisters + addi t6, sp, SIZEOF__PROFILE_PLATFORM_SPECIFIC_DATA // Compute probeSp - initial value of Sp on entry to the helper. + sd t6, PROFILE_PLATFORM_SPECIFIC_DATA__probeSp(sp) + sd t1, PROFILE_PLATFORM_SPECIFIC_DATA__profiledSp(sp) + sd zero, PROFILE_PLATFORM_SPECIFIC_DATA__hiddenArg(sp) addi t6, zero, \flags - sw t6, 248(sp) // Save flags. - sw zero, 252(sp) // clear unused field. + sd t6, PROFILE_PLATFORM_SPECIFIC_DATA__flags(sp) - addi a1, t1, 0 - addi a2, sp, 0 + addi a0, t0, 0 + addi a1, sp, 0 call C_FUNC(\helper) - RESTORE_ARGUMENT_REGISTERS sp, 16 // Restore t0 and argument registers. - RESTORE_FLOAT_ARGUMENT_REGISTERS sp, 96 // Restore floating-point/SIMD registers. + RESTORE_ARGUMENT_REGISTERS sp, PROFILE_PLATFORM_SPECIFIC_DATA__argumentRegisters + RESTORE_FLOAT_ARGUMENT_REGISTERS sp, PROFILE_PLATFORM_SPECIFIC_DATA__floatArgumentRegisters EPILOG_RESTORE_REG_PAIR_INDEXED fp, ra, SIZEOF__PROFILE_PLATFORM_SPECIFIC_DATA EPILOG_RETURN diff --git a/src/coreclr/vm/riscv64/cgencpu.h b/src/coreclr/vm/riscv64/cgencpu.h index 0d98092ec2021..25d2efbc4dedb 100644 --- a/src/coreclr/vm/riscv64/cgencpu.h +++ b/src/coreclr/vm/riscv64/cgencpu.h @@ -107,7 +107,7 @@ struct CalleeSavedRegisters { #define NUM_ARGUMENT_REGISTERS 8 typedef DPTR(struct ArgumentRegisters) PTR_ArgumentRegisters; struct ArgumentRegisters { - INT64 a[8]; // a0 ....a7 + INT64 a[NUM_ARGUMENT_REGISTERS]; // a0 ....a7 }; #define ARGUMENTREGISTERS_SIZE sizeof(ArgumentRegisters) @@ -124,9 +124,30 @@ struct ArgumentRegisters { typedef DPTR(struct FloatArgumentRegisters) PTR_FloatArgumentRegisters; struct FloatArgumentRegisters { //TODO: not supports RISCV64-SIMD. - double f[8]; // f0-f7 + double f[NUM_FLOAT_ARGUMENT_REGISTERS]; // f0-f7 }; +//********************************************************************** +// Profiling +//********************************************************************** + +#ifdef PROFILING_SUPPORTED + +struct PROFILE_PLATFORM_SPECIFIC_DATA +{ + void* Fp; + void* Pc; + ArgumentRegisters argumentRegisters; + FunctionID functionId; + FloatArgumentRegisters floatArgumentRegisters; + void* probeSp; + void* profiledSp; + void* hiddenArg; + UINT64 flags; + // Scratch space to reconstruct struct passed in registers + BYTE buffer[sizeof(ArgumentRegisters) + sizeof(FloatArgumentRegisters)]; +}; +#endif // PROFILING_SUPPORTED //********************************************************************** // Exception handling @@ -359,8 +380,6 @@ class StubLinkerCPU : public StubLinker void EmitLoad(FloatReg dest, IntReg srcAddr, int offset = 0); void EmitStore(IntReg src, IntReg destAddr, int offset = 0); void EmitStore(FloatReg src, IntReg destAddr, int offset = 0); - - void EmitRet(IntReg reg); }; extern "C" void SinglecastDelegateInvokeStub(); diff --git a/src/coreclr/vm/riscv64/profiler.cpp b/src/coreclr/vm/riscv64/profiler.cpp index 5b9feb0e4ebdd..d3e05ccd867ff 100644 --- a/src/coreclr/vm/riscv64/profiler.cpp +++ b/src/coreclr/vm/riscv64/profiler.cpp @@ -4,35 +4,11 @@ #include "common.h" #ifdef PROFILING_SUPPORTED +#include "asmconstants.h" #include "proftoeeinterfaceimpl.h" -#define PROFILE_ENTER 1 -#define PROFILE_LEAVE 2 -#define PROFILE_TAILCALL 4 - -// Scratch space to store HFA return values (max 16 bytes) -#define PROFILE_PLATFORM_SPECIFIC_DATA_BUFFER_SIZE 16 - -typedef struct _PROFILE_PLATFORM_SPECIFIC_DATA -{ - void* Fp; - void* Pc; - void* x8; - ArgumentRegisters argumentRegisters; - FunctionID functionId; - FloatArgumentRegisters floatArgumentRegisters; - void* probeSp; - void* profiledSp; - void* hiddenArg; - UINT32 flags; - UINT32 unused; - BYTE buffer[PROFILE_PLATFORM_SPECIFIC_DATA_BUFFER_SIZE]; -} PROFILE_PLATFORM_SPECIFIC_DATA, *PPROFILE_PLATFORM_SPECIFIC_DATA; - UINT_PTR ProfileGetIPFromPlatformSpecificHandle(void* pPlatformSpecificHandle) { - // TODO-RISCV64-CQ: copied codes from loongarch however not yet tested. - _ASSERTE(!"RISCV64:NYI"); LIMITED_METHOD_CONTRACT; PROFILE_PLATFORM_SPECIFIC_DATA* pData = reinterpret_cast(pPlatformSpecificHandle); @@ -41,8 +17,6 @@ UINT_PTR ProfileGetIPFromPlatformSpecificHandle(void* pPlatformSpecificHandle) void ProfileSetFunctionIDInPlatformSpecificHandle(void* pPlatformSpecificHandle, FunctionID functionId) { - // TODO-RISCV64-CQ: copied codes from loongarch however not yet tested. - _ASSERTE(!"RISCV64:NYI"); LIMITED_METHOD_CONTRACT; _ASSERTE(pPlatformSpecificHandle != nullptr); @@ -53,15 +27,12 @@ void ProfileSetFunctionIDInPlatformSpecificHandle(void* pPlatformSpecificHandle, } ProfileArgIterator::ProfileArgIterator(MetaSig* pSig, void* pPlatformSpecificHandle) - : m_argIterator(pSig) + : m_argIterator(pSig), m_bufferPos(0) { - // TODO-RISCV64-CQ: copied codes from loongarch however not yet tested. - _ASSERTE(!"RISCV64:NYI"); WRAPPER_NO_CONTRACT; _ASSERTE(pSig != nullptr); _ASSERTE(pPlatformSpecificHandle != nullptr); - m_handle = pPlatformSpecificHandle; PROFILE_PLATFORM_SPECIFIC_DATA* pData = reinterpret_cast(pPlatformSpecificHandle); @@ -119,17 +90,77 @@ ProfileArgIterator::ProfileArgIterator(MetaSig* pSig, void* pPlatformSpecificHan ProfileArgIterator::~ProfileArgIterator() { - // TODO-RISCV64-CQ: copied codes from loongarch however not yet tested. - _ASSERTE(!"RISCV64:NYI"); LIMITED_METHOD_CONTRACT; m_handle = nullptr; } +LPVOID ProfileArgIterator::CopyStructFromRegisters(const ArgLocDesc* sir) +{ + struct Func + { + static inline const BYTE* postIncrement(const BYTE *&p, int offset) + { + const BYTE* orig = p; + p += offset; + return orig; + } + }; + + WRAPPER_NO_CONTRACT; + _ASSERTE(m_handle); + PROFILE_PLATFORM_SPECIFIC_DATA* pData = reinterpret_cast(m_handle); + + struct { bool isFloat, is8; } fields[] = { + { sir->m_structFields & (STRUCT_FLOAT_FIELD_FIRST | STRUCT_FLOAT_FIELD_ONLY_TWO | STRUCT_FLOAT_FIELD_ONLY_ONE), + sir->m_structFields & STRUCT_FIRST_FIELD_SIZE_IS8 }, + { sir->m_structFields & (STRUCT_FLOAT_FIELD_SECOND | STRUCT_FLOAT_FIELD_ONLY_TWO), + sir->m_structFields & STRUCT_SECOND_FIELD_SIZE_IS8 }, + }; + int fieldCount = (sir->m_structFields & 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; + const INT64 *aRegBegin = &pData->argumentRegisters.a[sir->m_idxGenReg], *aReg = aRegBegin; + const INT64 *aRegEnd = &pData->argumentRegisters.a[0] + NUM_ARGUMENT_REGISTERS; + const BYTE *stackBegin = (BYTE*)pData->profiledSp + sir->m_byteStackIndex, *stack = stackBegin; + + for (int i = 0; i < fieldCount; ++i) + { + bool inFloatReg = fields[i].isFloat && fReg < fRegEnd; + bool inGenReg = aReg < aRegEnd; + + if (fields[i].is8) + { + UINT64 alignedTo8 = ALIGN_UP(m_bufferPos, 8); + _ASSERTE(alignedTo8 + 8 <= sizeof(pData->buffer)); + m_bufferPos = alignedTo8; + const INT64* src = + inFloatReg ? (const INT64*)fReg++ : + inGenReg ? aReg++ : (const INT64*)Func::postIncrement(stack, 8); + *((INT64*)&pData->buffer[m_bufferPos]) = *src; + m_bufferPos += 8; + } + else + { + _ASSERTE(m_bufferPos + 4 <= sizeof(pData->buffer)); + const INT32* src = + inFloatReg ? (const INT32*)fReg++ : + inGenReg ? (const INT32*)aReg++ : (const INT32*)Func::postIncrement(stack, 4); + *((INT32*)&pData->buffer[m_bufferPos]) = *src; + m_bufferPos += 4; + } + } + // Sanity checks, make sure we've run through (and not overrun) all locations from ArgLocDesc + _ASSERTE(sir->m_cFloatReg < 0 || fReg - fRegBegin == sir->m_cFloatReg); + _ASSERTE(sir->m_cGenReg < 0 || aReg - aRegBegin == sir->m_cGenReg); + _ASSERTE(sir->m_byteStackSize < 0 || stack - stackBegin == sir->m_byteStackSize); + + return &pData->buffer[bufferPosBegin]; +} + LPVOID ProfileArgIterator::GetNextArgAddr() { - // TODO-RISCV64-CQ: copied codes from loongarch however not yet tested. - _ASSERTE(!"RISCV64:NYI"); WRAPPER_NO_CONTRACT; _ASSERTE(m_handle != nullptr); @@ -149,6 +180,18 @@ LPVOID ProfileArgIterator::GetNextArgAddr() return nullptr; } + const ArgLocDesc* sir = m_argIterator.GetArgLocDescForStructInRegs(); + if (sir) + { + // 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) + { + return CopyStructFromRegisters(sir); + } + } + if (TransitionBlock::IsFloatArgumentRegisterOffset(argOffset)) { return (LPBYTE)&pData->floatArgumentRegisters + (argOffset - TransitionBlock::GetOffsetOfFloatArgumentRegisters()); @@ -177,8 +220,6 @@ LPVOID ProfileArgIterator::GetNextArgAddr() LPVOID ProfileArgIterator::GetHiddenArgValue(void) { - // TODO-RISCV64-CQ: copied codes from loongarch however not yet tested. - _ASSERTE(!"RISCV64:NYI"); LIMITED_METHOD_CONTRACT; PROFILE_PLATFORM_SPECIFIC_DATA* pData = reinterpret_cast(m_handle); @@ -188,8 +229,6 @@ LPVOID ProfileArgIterator::GetHiddenArgValue(void) LPVOID ProfileArgIterator::GetThis(void) { - // TODO-RISCV64-CQ: copied codes from loongarch however not yet tested. - _ASSERTE(!"RISCV64:NYI"); CONTRACTL { NOTHROW; @@ -223,8 +262,6 @@ LPVOID ProfileArgIterator::GetThis(void) LPVOID ProfileArgIterator::GetReturnBufferAddr(void) { - // TODO-RISCV64-CQ: copied codes from loongarch however not yet tested. - _ASSERTE(!"RISCV64:NYI"); CONTRACTL { NOTHROW; @@ -242,66 +279,29 @@ LPVOID ProfileArgIterator::GetReturnBufferAddr(void) if (m_argIterator.HasRetBuffArg()) { - if ((pData->flags & PROFILE_ENTER) != 0) - { - return (LPVOID)pData->x8; - } - else - { - // On ARM64 there is no requirement for the method to preserve the value stored in x8. - // In order to workaround this JIT will explicitly return the return buffer address in x0. - _ASSERTE((pData->flags & PROFILE_LEAVE) != 0); - return (LPVOID)pData->argumentRegisters.a[0]; - } + // On RISC-V the method is not required to preserve the return buffer address passed in a0. + // However, JIT does that anyway if leave hook needs to be generated. + _ASSERTE((pData->flags & PROFILE_LEAVE) != 0); + return (LPVOID)pData->argumentRegisters.a[0]; } UINT fpReturnSize = m_argIterator.GetFPReturnSize(); - if (fpReturnSize != 0) + if (fpReturnSize) { - TypeHandle thReturnValueType; - m_argIterator.GetSig()->GetReturnTypeNormalized(&thReturnValueType); - if (!thReturnValueType.IsNull() && thReturnValueType.IsHFA()) + if ((fpReturnSize & STRUCT_HAS_8BYTES_FIELDS_MASK) == STRUCT_HAS_8BYTES_FIELDS_MASK || + (fpReturnSize & STRUCT_FLOAT_FIELD_ONLY_ONE)) { - UINT hfaFieldSize = fpReturnSize / 4; - UINT totalSize = m_argIterator.GetSig()->GetReturnTypeSize(); - _ASSERTE(totalSize % hfaFieldSize == 0); - _ASSERTE(totalSize <= 16); - - BYTE *dest = pData->buffer; - for (UINT floatRegIdx = 0; floatRegIdx < totalSize / hfaFieldSize; ++floatRegIdx) - { - if (hfaFieldSize == 4) - { - *(UINT32*)dest = *(UINT32*)&pData->floatArgumentRegisters.f[floatRegIdx]; - dest += 4; - } - else if (hfaFieldSize == 8) - { - *(UINT64*)dest = *(UINT64*)&pData->floatArgumentRegisters.f[floatRegIdx]; - dest += 8; - } - else - { - _ASSERTE(!"unimplemented on RISCV64 yet!"); -#if 0 - _ASSERTE(hfaFieldSize == 16); - *(NEON128*)dest = pData->floatArgumentRegisters.f[floatRegIdx]; - dest += 16; -#endif - } - - if (floatRegIdx > 8) - { - // There's only space for 8 arguments in buffer - _ASSERTE(FALSE); - break; - } - } - - return pData->buffer; + return &pData->floatArgumentRegisters.f[0]; } - - return &pData->floatArgumentRegisters.f[0]; + ArgLocDesc sir; + sir.m_idxFloatReg = 0; + sir.m_cFloatReg = -1; + sir.m_idxGenReg = 0; + sir.m_cGenReg = -1; + sir.m_byteStackIndex = 0; + sir.m_byteStackSize = -1; + sir.m_structFields = fpReturnSize; + return CopyStructFromRegisters(&sir); } if (!m_argIterator.GetSig()->IsReturnTypeVoid()) @@ -312,8 +312,4 @@ LPVOID ProfileArgIterator::GetReturnBufferAddr(void) return nullptr; } -#undef PROFILE_ENTER -#undef PROFILE_LEAVE -#undef PROFILE_TAILCALL - #endif // PROFILING_SUPPORTED diff --git a/src/tests/profiler/native/eltprofiler/slowpatheltprofiler.cpp b/src/tests/profiler/native/eltprofiler/slowpatheltprofiler.cpp index b62ab2ac669a6..7d1f56e40a098 100644 --- a/src/tests/profiler/native/eltprofiler/slowpatheltprofiler.cpp +++ b/src/tests/profiler/native/eltprofiler/slowpatheltprofiler.cpp @@ -120,57 +120,36 @@ HRESULT SlowPathELTProfiler::Shutdown() { Profiler::Shutdown(); - if (_testType == TestType::EnterHooks) + if (_testType != TestType::EnterHooks && _testType != TestType::LeaveHooks) { - bool _sawFuncsEnter = true; - - for (auto p: _sawFuncEnter) - { - _sawFuncsEnter = _sawFuncsEnter && p.second; - } + return S_OK; + } + + bool allPass = true; + bool isEnter = (_testType == TestType::EnterHooks); + auto& sawFunc = isEnter ? _sawFuncEnter : _sawFuncLeave; - if ((_failures == 0) && _sawFuncsEnter) - { - wcout << L"PROFILER TEST PASSES" << endl; - } - else - { - wcout << L"TEST FAILED _failures=" << _failures.load() << endl; + for (auto p: sawFunc) + { + allPass = allPass && p.second; + } - if (!_sawFuncsEnter) - { - for (auto p: _sawFuncEnter) - { - if (!p.second) - wcout << L"_sawFuncEnter[" << p.first << L"]=" << p.second << endl; - } - } - } + int failures =_failures.load(); + if (failures == 0 && allPass) + { + wcout << L"PROFILER TEST PASSES" << endl; } - else if (_testType == TestType::LeaveHooks) + else { - bool _sawFuncsLeave = true; - - for (auto p: _sawFuncLeave) - { - _sawFuncsLeave = _sawFuncsLeave && p.second; - } + wcout << L"TEST FAILED _failures=" << failures << endl; - if ((_failures == 0) && _sawFuncsLeave) + if (!allPass) { - wcout << L"PROFILER TEST PASSES" << endl; - } - else - { - wcout << L"TEST FAILED _failures=" << _failures.load() << endl; - - if (!_sawFuncsLeave) + const wchar_t* label = isEnter ? L"Enter" : L"Leave"; + for (auto p: sawFunc) { - for (auto p: _sawFuncLeave) - { - if (!p.second) - wcout << L"_sawFuncLeave[" << p.first << L"]=" << p.second << endl; - } + if (!p.second) + wcout << L"_sawFunc" << label << L"[" << p.first << L"]=" << p.second << endl; } } }