From 429b350877d121f738dfdfbefbf2110eb4cebebf Mon Sep 17 00:00:00 2001 From: jashook Date: Mon, 10 Apr 2017 16:14:04 -0700 Subject: [PATCH] Do not reuse amd64 abi logic --- src/vm/argdestination.h | 41 +++++++++++++++++++++++++++++++++ src/vm/callingconvention.h | 29 ++++++++++++++++------- src/vm/object.cpp | 7 ++++++ src/vm/reflectioninvocation.cpp | 10 ++++++++ 4 files changed, 79 insertions(+), 8 deletions(-) diff --git a/src/vm/argdestination.h b/src/vm/argdestination.h index 8a3fb4fdf2d2..f8d7653a2365 100644 --- a/src/vm/argdestination.h +++ b/src/vm/argdestination.h @@ -30,6 +30,9 @@ class ArgDestination LIMITED_METHOD_CONTRACT; #if defined(UNIX_AMD64_ABI) && defined(FEATURE_UNIX_AMD64_STRUCT_PASSING) _ASSERTE((argLocDescForStructInRegs != NULL) || (offset != TransitionBlock::StructInRegsOffset)); +#elif defined(_TARGET_ARM64_) + // This assert is not interesting on arm64. argLocDescForStructInRegs could be + // initialized if the args are being enregistered. #else _ASSERTE(argLocDescForStructInRegs == NULL); #endif @@ -42,6 +45,44 @@ class ArgDestination return dac_cast(dac_cast(m_base) + m_offset); } +#if defined(_TARGET_ARM64_) + + // Returns true if the ArgDestination represents an HFA struct + bool IsHFA() + { + return m_argLocDescForStructInRegs != NULL; + } + + // Copy struct argument into registers described by the current ArgDestination. + // Arguments: + // src = source data of the structure + // fieldBytes - size of the structure + void CopyHFAStructToRegister(void *src, int fieldBytes) + { + // We are either copying either a float or double HFA and need to + // enregister each field. + + int floatRegCount = m_argLocDescForStructInRegs->m_cFloatReg; + bool typeFloat = m_argLocDescForStructInRegs->m_isSinglePrecision; + void* dest = this->GetDestinationAddress(); + + if (typeFloat) + { + for (int i = 0; i < floatRegCount; ++i) + { + // Copy 4 bytes on 8 bytes alignment + *((UINT64*)dest + i) = *((UINT32*)src + i); + } + } + else + { + // We can just do a memcpy. + memcpyNoGCRefs(dest, src, fieldBytes); + } + } + +#endif // defined(_TARGET_ARM64_) + #if defined(UNIX_AMD64_ABI) && defined(FEATURE_UNIX_AMD64_STRUCT_PASSING) // Returns true if the ArgDestination represents a struct passed in registers. diff --git a/src/vm/callingconvention.h b/src/vm/callingconvention.h index cde2ba465a1e..9c56de3eb1d3 100644 --- a/src/vm/callingconvention.h +++ b/src/vm/callingconvention.h @@ -34,21 +34,26 @@ BOOL IsRetBuffPassedAsFirstArg(); // and possibly on to the stack as well. struct ArgLocDesc { - int m_idxFloatReg; // First floating point register used (or -1) - int m_cFloatReg; // Count of floating point registers used (or 0) + int m_idxFloatReg; // First floating point register used (or -1) + int m_cFloatReg; // Count of floating point registers used (or 0) - int m_idxGenReg; // First general register used (or -1) - int m_cGenReg; // Count of general registers used (or 0) + int m_idxGenReg; // First general register used (or -1) + int m_cGenReg; // Count of general registers used (or 0) - int m_idxStack; // First stack slot used (or -1) - int m_cStack; // Count of stack slots used (or 0) + int m_idxStack; // First stack slot used (or -1) + int m_cStack; // Count of stack slots used (or 0) #if defined(UNIX_AMD64_ABI) && defined(FEATURE_UNIX_AMD64_STRUCT_PASSING) - EEClass* m_eeClass; // For structs passed in register, it points to the EEClass of the struct + EEClass* m_eeClass; // For structs passed in register, it points to the EEClass of the struct #endif // UNIX_AMD64_ABI && FEATURE_UNIX_AMD64_STRUCT_PASSING +#if defined(_TARGET_ARM64_) + bool m_isSinglePrecision; // For determining if HFA is single or double + // precision +#endif // defined(_TARGET_ARM64_) + #if defined(_TARGET_ARM_) BOOL m_fRequires64BitAlignment; // True if the argument should always be aligned (in registers or on the stack #endif @@ -70,6 +75,9 @@ struct ArgLocDesc #if defined(_TARGET_ARM_) m_fRequires64BitAlignment = FALSE; #endif +#if defined(_TARGET_ARM64_) + m_isSinglePrecision = FALSE; +#endif // defined(_TARGET_ARM64_) #if defined(UNIX_AMD64_ABI) && defined(FEATURE_UNIX_AMD64_STRUCT_PASSING) m_eeClass = NULL; #endif @@ -556,7 +564,10 @@ class ArgIteratorTemplate : public ARGITERATOR_BASE if (!m_argTypeHandle.IsNull() && m_argTypeHandle.IsHFA()) { CorElementType type = m_argTypeHandle.GetHFAType(); - pLoc->m_cFloatReg = (type == ELEMENT_TYPE_R4)? GetArgSize()/sizeof(float): GetArgSize()/sizeof(double); + bool isFloatType = (type == ELEMENT_TYPE_R4); + + pLoc->m_cFloatReg = isFloatType ? GetArgSize()/sizeof(float): GetArgSize()/sizeof(double); + pLoc->m_isSinglePrecision = isFloatType; } else { @@ -1103,7 +1114,9 @@ int ArgIteratorTemplate::GetNextOffset() // Handle HFAs: packed structures of 1-4 floats or doubles that are passed in FP argument // registers if possible. if (thValueType.IsHFA()) + { fFloatingPoint = true; + } #endif break; diff --git a/src/vm/object.cpp b/src/vm/object.cpp index 1725ef7db43b..9d1ff969eabe 100644 --- a/src/vm/object.cpp +++ b/src/vm/object.cpp @@ -1592,6 +1592,13 @@ void STDCALL CopyValueClassArgUnchecked(ArgDestination *argDest, void* src, Meth return; } +#elif defined(_TARGET_ARM64_) + + if (argDest->IsHFA()) + { + argDest->CopyHFAStructToRegister(src, pMT->GetAlignedNumInstanceFieldBytes()); + } + #endif // UNIX_AMD64_ABI && FEATURE_UNIX_AMD64_STRUCT_PASSING // destOffset is only valid for Nullable passed in registers _ASSERTE(destOffset == 0); diff --git a/src/vm/reflectioninvocation.cpp b/src/vm/reflectioninvocation.cpp index 626e872255c3..a2b8c4aefc3b 100644 --- a/src/vm/reflectioninvocation.cpp +++ b/src/vm/reflectioninvocation.cpp @@ -1383,8 +1383,18 @@ FCIMPL4(Object*, RuntimeMethodHandle::InvokeMethod, } #endif +#ifdef defined(_TARGET_ARM64_) + ArgLocDesc argLocDescForStructInRegs; + argit.GetArgLoc(ofs, &argLocDescForStructInRegs); + + ArgDestination argDest(pTransitionBlock, ofs, &argLocDescForStructInRegs); + +#else // !_TARGET_ARM64_ + ArgDestination argDest(pTransitionBlock, ofs, argit.GetArgLocDescForStructInRegs()); +#endif // defined(_TARGET_ARM64_) + if(needsStackCopy) { MethodTable * pMT = th.GetMethodTable();