@@ -844,10 +844,7 @@ GenTree* Compiler::impStoreStruct(GenTree* store,
844
844
GenTreeFlags indirFlags = GTF_EMPTY;
845
845
GenTree* destAddr = impGetNodeAddr(store, CHECK_SPILL_ALL, &indirFlags);
846
846
847
- // Make sure we don't pass something other than a local address to the return buffer arg.
848
- // It is allowed to pass current's method return buffer as it is a local too.
849
- if ((fgAddrCouldBeHeap(destAddr) && !eeIsByrefLike(srcCall->gtRetClsHnd)) ||
850
- (compIsAsync() && !destAddr->OperIs(GT_LCL_ADDR)))
847
+ if (!impIsLegalRetBuf(destAddr, srcCall))
851
848
{
852
849
unsigned tmp = lvaGrabTemp(false DEBUGARG("stack copy for value returned via return buffer"));
853
850
lvaSetStruct(tmp, srcCall->gtRetClsHnd, false);
@@ -971,10 +968,7 @@ GenTree* Compiler::impStoreStruct(GenTree* store,
971
968
GenTreeFlags indirFlags = GTF_EMPTY;
972
969
GenTree* destAddr = impGetNodeAddr(store, CHECK_SPILL_ALL, &indirFlags);
973
970
974
- // Make sure we don't pass something other than a local address to the return buffer arg.
975
- // It is allowed to pass current's method return buffer as it is a local too.
976
- if ((fgAddrCouldBeHeap(destAddr) && !eeIsByrefLike(call->gtRetClsHnd)) ||
977
- (compIsAsync() && !destAddr->OperIs(GT_LCL_ADDR)))
971
+ if (!impIsLegalRetBuf(destAddr, call))
978
972
{
979
973
unsigned tmp = lvaGrabTemp(false DEBUGARG("stack copy for value returned via return buffer"));
980
974
lvaSetStruct(tmp, call->gtRetClsHnd, false);
@@ -1068,6 +1062,46 @@ GenTree* Compiler::impStoreStruct(GenTree* store,
1068
1062
return store;
1069
1063
}
1070
1064
1065
+ //------------------------------------------------------------------------
1066
+ // impIsLegalRetbuf:
1067
+ // Check if a return buffer is of a legal shape.
1068
+ //
1069
+ // Arguments:
1070
+ // retBuf - The return buffer
1071
+ // call - The call that is passed the return buffer
1072
+ //
1073
+ // Return Value:
1074
+ // True if it is legal according to ABI and IR invariants.
1075
+ //
1076
+ // Notes:
1077
+ // ABI requires all return buffers to point to stack. Also, we have an IR
1078
+ // invariant for async calls that return buffers must be the address of a
1079
+ // local.
1080
+ //
1081
+ bool Compiler::impIsLegalRetBuf(GenTree* retBuf, GenTreeCall* call)
1082
+ {
1083
+ if (call->IsAsync())
1084
+ {
1085
+ // Async calls require LCL_ADDR shape for the retbuf to know where to
1086
+ // save the value on resumption.
1087
+ if (!retBuf->OperIs(GT_LCL_ADDR))
1088
+ {
1089
+ return false;
1090
+ }
1091
+
1092
+ // LCL_ADDR on an implicit byref will turn into LCL_VAR in morph.
1093
+ if (lvaIsImplicitByRefLocal(retBuf->AsLclVarCommon()->GetLclNum()))
1094
+ {
1095
+ return false;
1096
+ }
1097
+
1098
+ return true;
1099
+ }
1100
+
1101
+ // The ABI requires the retbuffer to point to stack.
1102
+ return !fgAddrCouldBeHeap(retBuf) || eeIsByrefLike(call->gtRetClsHnd);
1103
+ }
1104
+
1071
1105
//------------------------------------------------------------------------
1072
1106
// impStoreStructPtr: Store (copy) the structure from 'src' to 'destAddr'.
1073
1107
//
0 commit comments