return resultMask;
}
+//-------------------------------------------------------------------------
+// TreatAsHasRetBufArg:
+//
+// Arguments:
+// compiler, the compiler instance so that we can call eeGetHelperNum
+//
+// Return Value:
+// Returns true if we treat the call as if it has a retBuf argument
+// This method may actually have a retBuf argument
+// or it could be a JIT helper that we are still transforming during
+// the importer phase.
+//
+// Notes:
+// On ARM64 marking the method with the GTF_CALL_M_RETBUFFARG flag
+// will make HasRetBufArg() return true, but will also force the
+// use of register x8 to pass the RetBuf argument.
+//
+// These two Jit Helpers that we handle here by returning true
+// aren't actually defined to return a struct, so they don't expect
+// their RetBuf to be passed in x8, instead they expect it in x0.
+//
+bool GenTreeCall::TreatAsHasRetBufArg(Compiler* compiler)
+{
+ if (HasRetBufArg())
+ {
+ return true;
+ }
+ else
+ {
+ // If we see a Jit helper call that returns a TYP_STRUCT we will
+ // transform it as if it has a Return Buffer Argument
+ //
+ if (IsHelperCall() && (gtCall.gtReturnType == TYP_STRUCT))
+ {
+ // There are two possible helper calls that use this path:
+ // CORINFO_HELP_GETFIELDSTRUCT and CORINFO_HELP_UNBOX_NULLABLE
+ //
+ CorInfoHelpFunc helpFunc = compiler->eeGetHelperNum(gtCall.gtCallMethHnd);
+
+ if (helpFunc == CORINFO_HELP_GETFIELDSTRUCT)
+ {
+ return true;
+ }
+ else if (helpFunc == CORINFO_HELP_UNBOX_NULLABLE)
+ {
+ return true;
+ }
+ else
+ {
+ assert(!"Unexpected JIT helper in TreatAsHasRetBufArg");
+ }
+ }
+ }
+ return false;
+}
+
/*****************************************************************************
*
* Returns non-zero if the two trees are identical.
{
if (pFieldInfo->helper == CORINFO_HELP_GETFIELDSTRUCT)
{
- // The helper ALWAYS takes a 'return buffer'. (really just the
- // the first parameter is really an out parameter)
- tree->gtCall.gtCallMoreFlags |= GTF_CALL_M_RETBUFFARG;
-
if (!varTypeIsStruct(lclTyp))
{
// get the result as primitive type
tree = gtNewOperNode(GT_IND, lclTyp, tree);
}
}
- else
- if (varTypeIsIntegral(lclTyp) && genTypeSize(lclTyp) < genTypeSize(TYP_INT))
+ else if (varTypeIsIntegral(lclTyp) && genTypeSize(lclTyp) < genTypeSize(TYP_INT))
{
// The helper does not extend the small return types.
tree = gtNewCastNode(genActualType(lclTyp), tree, lclTyp);
}
#endif // !LEGACY_BACKEND
- // Returns true if the call has retBuf argument
- bool HasRetBufArg() const { return (gtCallMoreFlags & GTF_CALL_M_RETBUFFARG) != 0; }
+ // Returns true if this call uses a retBuf argument and its calling convention
+ bool HasRetBufArg() const
+ {
+ return (gtCallMoreFlags & GTF_CALL_M_RETBUFFARG) != 0;
+ }
+
+ //-------------------------------------------------------------------------
+ // TreatAsHasRetBufArg:
+ //
+ // Arguments:
+ // compiler, the compiler instance so that we can call eeGetHelperNum
+ //
+ // Return Value:
+ // Returns true if we treat the call as if it has a retBuf argument
+ // This method may actually have a retBuf argument
+ // or it could be a JIT helper that we are still transforming during
+ // the importer phase.
+ //
+ // Notes:
+ // On ARM64 marking the method with the GTF_CALL_M_RETBUFFARG flag
+ // will make HasRetBufArg() return true, but will also force the
+ // use of register x8 to pass the RetBuf argument.
+ //
+ bool TreatAsHasRetBufArg(Compiler* compiler);
//-----------------------------------------------------------------------------------------
// HasMultiRegRetVal: whether the call node returns its value in multiple return registers.
//
// Arguments:
// None
-
+ //
// Return Value:
// True if the call is returning a multi-reg return value. False otherwise.
//
if (src->gtOper == GT_CALL)
{
- if (src->AsCall()->HasRetBufArg())
+ if (src->AsCall()->TreatAsHasRetBufArg(this))
{
// Case of call returning a struct via hidden retbuf arg
}
else if (op->gtOper == GT_CALL)
{
- if (op->AsCall()->HasRetBufArg())
+ if (op->AsCall()->TreatAsHasRetBufArg(this))
{
// This must be one of those 'special' helpers that don't
// really have a return buffer, but instead use it as a way
// Don't optimize, just call the helper and be done with it
args = gtNewArgList(op2, op1);
op1 = gtNewHelperCallNode(helper, (var_types)((helper == CORINFO_HELP_UNBOX)?TYP_BYREF:TYP_STRUCT), callFlags, args);
-
- if (helper == CORINFO_HELP_UNBOX_NULLABLE)
- {
- // NOTE! This really isn't a return buffer. On the native side this
- // is the first argument, but the trees are prettier this way
- // so fake it as a return buffer.
- op1->gtCall.gtCallMoreFlags |= GTF_CALL_M_RETBUFFARG;
- }
}
assert(helper == CORINFO_HELP_UNBOX && op1->gtType == TYP_BYREF || // Unbox helper returns a byref.