}
info;
+ // Returns true if the method being compiled returns a non-void and non-struct value.
+ // Note that lvaInitTypeRef() normalizes compRetNativeType for struct returns in a
+ // single register as per target arch ABI (e.g on Amd64 Windows structs of size 1, 2,
+ // 4 or 8 gets normalized to TYP_BYTE/TYP_SHORT/TYP_INT/TYP_LONG; On Arm Hfa structs).
+ // Methods returning such structs are considered to return non-struct return value and
+ // this method returns true in that case.
+ bool compMethodReturnsNativeScalarType()
+ {
+ return (info.compRetType != TYP_VOID) && !varTypeIsStruct(info.compRetNativeType);
+ }
+
+ // Returns true if the method being compiled returns RetBuf addr as its return value
+ bool compMethodReturnsRetBufAddr()
+ {
+ // Profiler Leave calllback expects the address of retbuf as return value for
+ // methods with hidden RetBuf argument. impReturnInstruction() when profiler
+ // callbacks are needed creates GT_RETURN(TYP_BYREF, op1 = Addr of RetBuf) for
+ // methods with hidden RetBufArg.
+ //
+ // TODO-AMD64-Unix - As per this ABI, addr of RetBuf needs to be returned by
+ // methods with hidden RetBufArg. Right now we are special casing GT_RETURN
+ // of TYP_VOID in codegenxarch.cpp to generate "mov rax, addr of RetBuf".
+ // Instead we should consider explicitly materializing GT_RETURN of TYP_BYREF
+ // return addr of RetBuf in IR.
+ return compIsProfilerHookNeeded() && (info.compRetBuffArg != BAD_VAR_NUM);
+ }
+
+ // Returns true if the method returns a value in more than one return register
+ // TODO-ARM-Bug: Deal with multi-register genReturnLocaled structs?
+ // TODO-ARM64: Does this apply for ARM64 too?
+ bool compMethodReturnsMultiRegRetType()
+ {
+#if FEATURE_MULTIREG_RET
+#ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
+ // Methods returning a struct in two registers is considered having a return value of TYP_STRUCT.
+ // Such method's compRetNativeType is TYP_STRUCT without a hidden RetBufArg
+ return varTypeIsStruct(info.compRetNativeType) && (info.compRetBuffArg == BAD_VAR_NUM);
+#endif
+#endif
+ return false;
+ }
+
+ // Returns true if the method being compiled returns a value
+ bool compMethodHasRetVal()
+ {
+ return compMethodReturnsNativeScalarType() ||
+ compMethodReturnsRetBufAddr() ||
+ compMethodReturnsMultiRegRetType();
+ }
+
#if defined(DEBUG)
void compDispLocalVars();
//
// We don't have a oneReturn block for this method
//
- genReturnBB = NULL;
+ genReturnBB = nullptr;
}
// If there is a return value, then create a temp for it. Real returns will store the value in there and
- // it'll be reloaded by the single return.
- // TODO-ARM-Bug: Deal with multi-register genReturnLocaled structs?
- // TODO-ARM64: Does this apply for ARM64 too?
-#if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
- // Create a local temp to store the return if the return type is not void and the
- // native return type is not a struct or the native return type is a struct that is returned
- // in registers (no RetBuffArg argument.)
- // If we fold all returns into a single return statement, create a temp for struct type variables as well.
- if (genReturnBB && ((info.compRetType != TYP_VOID && !varTypeIsStruct(info.compRetNativeType)) ||
- (varTypeIsStruct(info.compRetNativeType) && info.compRetBuffArg == BAD_VAR_NUM)))
-#else // !defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
- if (genReturnBB && (info.compRetType != TYP_VOID) && !varTypeIsStruct(info.compRetNativeType))
-#endif // !defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
+ // it'll be reloaded by the single return.
+ if (genReturnBB && compMethodHasRetVal())
{
genReturnLocal = lvaGrabTemp(true DEBUGARG("Single return block return value"));
-#if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
- var_types retLocalType = TYP_STRUCT;
- if (info.compRetNativeType == TYP_STRUCT)
+
+ if (compMethodReturnsNativeScalarType())
{
- // If the native ret type is a struct, make sure the right
- // normalized type is assigned to the local variable.
- SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR structDesc;
- assert(info.compMethodInfo->args.retTypeClass != nullptr);
- eeGetSystemVAmd64PassStructInRegisterDescriptor(info.compMethodInfo->args.retTypeClass, &structDesc);
- if (structDesc.passedInRegisters && structDesc.eightByteCount <= 1)
- {
- retLocalType = lvaTable[genReturnLocal].lvType = getEightByteType(structDesc, 0);
- }
- else
- {
- lvaTable[genReturnLocal].lvType = TYP_STRUCT;
- }
+ lvaTable[genReturnLocal].lvType = genActualType(info.compRetNativeType);
}
- else
-#endif // defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
+ else if (compMethodReturnsRetBufAddr())
{
- lvaTable[genReturnLocal].lvType = genActualType(info.compRetNativeType);
+ lvaTable[genReturnLocal].lvType = TYP_BYREF;
}
-
- if (varTypeIsFloating(lvaTable[genReturnLocal].lvType))
+ else if (compMethodReturnsMultiRegRetType())
{
- this->compFloatingPointUsed = true;
+ lvaTable[genReturnLocal].lvType = TYP_STRUCT;
+ lvaSetStruct(genReturnLocal, info.compMethodInfo->args.retTypeClass, true);
+#if FEATURE_MULTIREG_ARGS_OR_RET
+ lvaTable[genReturnLocal].lvIsMultiRegArgOrRet = true;
+#endif
}
-
-#if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
- // Handle a struct return type for System V Amd64 systems.
- if (varTypeIsStruct(info.compRetNativeType))
+ else
{
- // Handle the normalized return type.
- if (varTypeIsStruct(retLocalType))
- {
- lvaSetStruct(genReturnLocal, info.compMethodInfo->args.retTypeClass, true);
- }
- else
- {
- lvaTable[genReturnLocal].lvVerTypeInfo = typeInfo(TI_STRUCT, info.compMethodInfo->args.retTypeClass);
- }
+ assert(!"unreached");
+ }
- lvaTable[genReturnLocal].lvIsMultiRegArgOrRet = true;
+ if (varTypeIsFloating(lvaTable[genReturnLocal].lvType))
+ {
+ this->compFloatingPointUsed = true;
}
-#endif // defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
if (!varTypeIsFloating(info.compRetType))
lvaTable[genReturnLocal].setPrefReg(REG_INTRET, this);
//
// spill any value that is currently in the oneReturnStmtNode
- if (oneReturnStmtNode != NULL)
+ if (oneReturnStmtNode != nullptr)
{
fgInsertStmtAtEnd(genReturnBB, oneReturnStmtNode);
- oneReturnStmtNode = NULL;
+ oneReturnStmtNode = nullptr;
}
//make sure to reload the return value as part of the return (it is saved by the "real return").
if (genReturnLocal != BAD_VAR_NUM)
{
-#if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
- noway_assert(info.compRetType != TYP_VOID);
-#else // !defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
- noway_assert(info.compRetType != TYP_VOID && info.compRetNativeType != TYP_STRUCT);
-#endif // !defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
+ noway_assert(compMethodHasRetVal());
+
GenTreePtr retTemp = gtNewLclvNode(genReturnLocal, lvaTable[genReturnLocal].TypeGet());
//make sure copy prop ignores this node (make sure it always does a reload from the temp).