GenTree* gtNewTempAssign(unsigned tmp,
GenTree* val,
+ unsigned curLevel = CHECK_SPILL_NONE,
Statement** pAfterStmt = nullptr,
const DebugInfo& di = DebugInfo(),
BasicBlock* block = nullptr);
void impAppendStmt(Statement* stmt);
void impInsertStmtBefore(Statement* stmt, Statement* stmtBefore);
Statement* impAppendTree(GenTree* tree, unsigned chkLevel, const DebugInfo& di, bool checkConsumedDebugInfo = true);
- void impInsertTreeBefore(GenTree* tree, const DebugInfo& di, Statement* stmtBefore);
- void impAssignTempGen(unsigned tmp,
+ void impAssignTempGen(unsigned lclNum,
GenTree* val,
unsigned curLevel = CHECK_SPILL_NONE,
Statement** pAfterStmt = nullptr,
const DebugInfo& di = DebugInfo(),
BasicBlock* block = nullptr);
- void impAssignTempGen(unsigned tmpNum,
- GenTree* val,
- CORINFO_CLASS_HANDLE structHnd,
- unsigned curLevel,
- Statement** pAfterStmt = nullptr,
- const DebugInfo& di = DebugInfo(),
- BasicBlock* block = nullptr);
-
Statement* impExtractLastStmt();
GenTree* impCloneExpr(GenTree* tree,
GenTree** clone,
- CORINFO_CLASS_HANDLE structHnd,
unsigned curLevel,
Statement** pAfterStmt DEBUGARG(const char* reason));
GenTree* impAssignStruct(GenTree* dest,
Statement** pAfterStmt = nullptr,
const DebugInfo& di = DebugInfo(),
BasicBlock* block = nullptr);
- GenTree* impAssignStructPtr(GenTree* dest,
- GenTree* src,
- CORINFO_CLASS_HANDLE structHnd,
- unsigned curLevel,
- Statement** pAfterStmt = nullptr,
- const DebugInfo& di = DebugInfo(),
- BasicBlock* block = nullptr);
+ GenTree* impAssignStructPtr(GenTree* dest, GenTree* src, unsigned curLevel);
- GenTree* impGetStructAddr(GenTree* structVal, CORINFO_CLASS_HANDLE structHnd, unsigned curLevel, bool willDeref);
+ GenTree* impGetStructAddr(GenTree* structVal, unsigned curLevel, bool willDeref);
var_types impNormStructType(CORINFO_CLASS_HANDLE structHnd, CorInfoType* simdBaseJitType = nullptr);
- GenTree* impNormStructVal(GenTree* structVal, CORINFO_CLASS_HANDLE structHnd, unsigned curLevel);
+ GenTree* impNormStructVal(GenTree* structVal, unsigned curLevel);
GenTree* impTokenToHandle(CORINFO_RESOLVED_TOKEN* pResolvedToken,
bool* pRuntimeLookup = nullptr,
};
#ifdef FEATURE_SIMD
- GenTree* getSIMDStructFromField(GenTree* tree,
- CorInfoType* simdBaseJitTypeOut,
- unsigned* indexOut,
- unsigned* simdSizeOut,
- bool ignoreUsedInSIMDIntrinsic = false);
+ GenTree* getSIMDStructFromField(GenTree* tree,
+ unsigned* indexOut,
+ unsigned* simdSizeOut,
+ bool ignoreUsedInSIMDIntrinsic = false);
bool fgMorphCombineSIMDFieldAssignments(BasicBlock* block, Statement* stmt);
void impMarkContiguousSIMDFieldAssignments(Statement* stmt);
// The lifetime of this var might expand multiple BBs. So it is a long lifetime compiler temp.
lvaInlineeReturnSpillTemp = lvaGrabTemp(false DEBUGARG("Inline return value spill temp"));
lvaTable[lvaInlineeReturnSpillTemp].lvType = info.compRetType;
+ if (varTypeIsStruct(info.compRetType))
+ {
+ lvaSetStruct(lvaInlineeReturnSpillTemp, info.compMethodInfo->args.retTypeClass, false);
+ }
// The return spill temp is single def only if the method has a single return block.
if (fgReturnCount == 1)
}
else
{
- // We're going to assign the argument value to the
- // temp we use for it in the inline body.
- const unsigned tmpNum = argInfo.argTmpNum;
- const var_types argType = lclVarInfo[argNum].lclTypeInfo;
+ // We're going to assign the argument value to the temp we use for it in the inline body.
+ GenTree* store = gtNewTempAssign(argInfo.argTmpNum, argNode);
- // Create the temp assignment for this argument
- CORINFO_CLASS_HANDLE structHnd = NO_CLASS_HANDLE;
-
- if (varTypeIsStruct(argType))
- {
- structHnd = lclVarInfo[argNum].lclVerTypeInfo.GetClassHandleForValueClass();
- assert(structHnd != NO_CLASS_HANDLE);
- }
-
- // Unsafe value cls check is not needed for argTmpNum here since in-linee compiler instance
- // would have iterated over these and marked them accordingly.
- impAssignTempGen(tmpNum, argNode, structHnd, CHECK_SPILL_NONE, &afterStmt, callDI, block);
-
- // We used to refine the temp type here based on
- // the actual arg, but we now do this up front, when
- // creating the temp, over in impInlineFetchArg.
- CLANG_FORMAT_COMMENT_ANCHOR;
+ newStmt = gtNewStmt(store, callDI);
+ fgInsertStmtAfter(block, afterStmt, newStmt);
+ afterStmt = newStmt;
-#ifdef DEBUG
- if (verbose)
- {
- gtDispStmt(afterStmt);
- }
-#endif // DEBUG
+ DISPSTMT(afterStmt);
}
}
else if (argInfo.argIsByRefToStructLocal)
continue;
}
- var_types lclTyp = lvaTable[tmpNum].lvType;
+ var_types lclTyp = tmpDsc->TypeGet();
noway_assert(lclTyp == lclVarInfo[lclNum + inlineInfo->argCnt].lclTypeInfo);
- if (lclTyp != TYP_STRUCT)
- {
- // Unsafe value cls check is not needed here since in-linee compiler instance would have
- // iterated over locals and marked accordingly.
- impAssignTempGen(tmpNum, gtNewZeroConNode(genActualType(lclTyp)), NO_CLASS_HANDLE, CHECK_SPILL_NONE,
- &afterStmt, callDI, block);
- }
- else
- {
- tree = gtNewBlkOpNode(gtNewLclvNode(tmpNum, lclTyp), gtNewIconNode(0));
+ tree = gtNewTempAssign(tmpNum, (lclTyp == TYP_STRUCT) ? gtNewIconNode(0) : gtNewZeroConNode(lclTyp));
- newStmt = gtNewStmt(tree, callDI);
- fgInsertStmtAfter(block, afterStmt, newStmt);
- afterStmt = newStmt;
- }
+ newStmt = gtNewStmt(tree, callDI);
+ fgInsertStmtAfter(block, afterStmt, newStmt);
+ afterStmt = newStmt;
-#ifdef DEBUG
- if (verbose)
- {
- gtDispStmt(afterStmt);
- }
-#endif // DEBUG
+ DISPSTMT(afterStmt);
}
}
}
// Arguments:
// tmp - local number for a compiler temp
// val - value to assign to the temp
+// curLevel - stack level to spill at (importer-only)
// pAfterStmt - statement to insert any additional statements after
-// ilOffset - il offset for new statements
+// di - debug info for new statements
// block - block to insert any additional statements in
//
// Return Value:
// May set compFloatingPointUsed.
//
GenTree* Compiler::gtNewTempAssign(
- unsigned tmp, GenTree* val, Statement** pAfterStmt, const DebugInfo& di, BasicBlock* block)
+ unsigned tmp, GenTree* val, unsigned curLevel, Statement** pAfterStmt, const DebugInfo& di, BasicBlock* block)
{
// Self-assignment is a nop.
if (val->OperGet() == GT_LCL_VAR && val->AsLclVarCommon()->GetLclNum() == tmp)
}
else if (varTypeIsStruct(varDsc) && !val->IsInitVal())
{
- store = impAssignStruct(gtNewLclvNode(tmp, dstTyp), val, CHECK_SPILL_NONE, pAfterStmt, di, block);
+ store = impAssignStruct(gtNewLclvNode(tmp, dstTyp), val, curLevel, pAfterStmt, di, block);
}
else
{
// helper needs pointer to struct, not struct itself
if (pFieldInfo->helper == CORINFO_HELP_SETFIELDSTRUCT)
{
- assg = impGetStructAddr(assg, structType, CHECK_SPILL_ALL, true);
+ assg = impGetStructAddr(assg, CHECK_SPILL_ALL, true);
}
else if (lclTyp == TYP_DOUBLE && assg->TypeGet() == TYP_FLOAT)
{
{
if (!varTypeIsStruct(lclTyp))
{
- // get the result as primitive type
- result = impGetStructAddr(result, structType, CHECK_SPILL_ALL, true);
+ result = impGetStructAddr(result, CHECK_SPILL_ALL, true);
result = gtNewIndir(lclTyp, result);
}
}
{
if (varTypeIsStruct(lclTyp))
{
- result = impAssignStructPtr(result, assg, structType, CHECK_SPILL_ALL);
+ result = impAssignStructPtr(result, assg, CHECK_SPILL_ALL);
}
else
{
GenTree* immOpDup = nullptr;
- immOp = impCloneExpr(immOp, &immOpDup, NO_CLASS_HANDLE, CHECK_SPILL_ALL,
+ immOp = impCloneExpr(immOp, &immOpDup, CHECK_SPILL_ALL,
nullptr DEBUGARG("Clone an immediate operand for immediate value bounds check"));
if (immLowerBound != 0)
if (varTypeIsByte(simdBaseType) && (simdSize == 16))
{
- op1 = impCloneExpr(op1, &op2, NO_CLASS_HANDLE, CHECK_SPILL_ALL,
+ op1 = impCloneExpr(op1, &op2, CHECK_SPILL_ALL,
nullptr DEBUGARG("Clone op1 for vector extractmostsignificantbits"));
op1 = gtNewSimdGetLowerNode(TYP_SIMD8, op1, simdBaseJitType, simdSize);
{
if ((simdSize == 8) && ((simdBaseType == TYP_INT) || (simdBaseType == TYP_UINT)))
{
- op1 = impCloneExpr(op1, &op2, NO_CLASS_HANDLE, CHECK_SPILL_ALL,
+ op1 = impCloneExpr(op1, &op2, CHECK_SPILL_ALL,
nullptr DEBUGARG("Clone op1 for vector extractmostsignificantbits"));
op1 = gtNewSimdHWIntrinsicNode(TYP_SIMD8, op1, op2, NI_AdvSimd_AddPairwise, simdBaseJitType,
simdSize);
else
{
GenTree* clonedOp1 = nullptr;
- op1 = impCloneExpr(op1, &clonedOp1, NO_CLASS_HANDLE, CHECK_SPILL_ALL,
+ op1 = impCloneExpr(op1, &clonedOp1, CHECK_SPILL_ALL,
nullptr DEBUGARG("Clone op1 for Sse.CompareScalarGreaterThan"));
retNode = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op2, op1, intrinsic, simdBaseJitType, simdSize);
else
{
GenTree* clonedOp1 = nullptr;
- op1 = impCloneExpr(op1, &clonedOp1, NO_CLASS_HANDLE, CHECK_SPILL_ALL,
+ op1 = impCloneExpr(op1, &clonedOp1, CHECK_SPILL_ALL,
nullptr DEBUGARG("Clone op1 for Sse2.CompareScalarGreaterThan"));
retNode = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op2, op1, intrinsic, simdBaseJitType, simdSize);
/*****************************************************************************
*
- * Insert the given expression tree before "stmtBefore"
- */
-
-void Compiler::impInsertTreeBefore(GenTree* tree, const DebugInfo& di, Statement* stmtBefore)
-{
- /* Allocate an 'expression statement' node */
-
- Statement* stmt = gtNewStmt(tree, di);
-
- /* Append the statement to the current block's stmt list */
-
- impInsertStmtBefore(stmt, stmtBefore);
-}
-
-/*****************************************************************************
- *
* Append an assignment of the given value to a temp to the current tree list.
* curLevel is the stack level for which the spill to the temp is being done.
*/
-void Compiler::impAssignTempGen(unsigned tmp,
+void Compiler::impAssignTempGen(unsigned lclNum,
GenTree* val,
unsigned curLevel,
Statement** pAfterStmt, /* = NULL */
BasicBlock* block /* = NULL */
)
{
- GenTree* asg = gtNewTempAssign(tmp, val);
-
- if (!asg->IsNothingNode())
- {
- if (pAfterStmt)
- {
- Statement* asgStmt = gtNewStmt(asg, di);
- fgInsertStmtAfter(block, *pAfterStmt, asgStmt);
- *pAfterStmt = asgStmt;
- }
- else
- {
- impAppendTree(asg, curLevel, impCurStmtDI);
- }
- }
-}
-
-/*****************************************************************************
- * same as above, but handle the valueclass case too
- */
-
-void Compiler::impAssignTempGen(unsigned tmpNum,
- GenTree* val,
- CORINFO_CLASS_HANDLE structType,
- unsigned curLevel,
- Statement** pAfterStmt, /* = NULL */
- const DebugInfo& di, /* = DebugInfo() */
- BasicBlock* block /* = NULL */
- )
-{
- GenTree* asg;
-
- assert(val->TypeGet() != TYP_STRUCT || structType != NO_CLASS_HANDLE);
- if (varTypeIsStruct(val) && (structType != NO_CLASS_HANDLE))
- {
- assert(tmpNum < lvaCount);
- assert(structType != NO_CLASS_HANDLE);
-
- // if the method is non-verifiable the assert is not true
- // so at least ignore it in the case when verification is turned on
- // since any block that tries to use the temp would have failed verification.
- var_types varType = lvaTable[tmpNum].lvType;
- assert(varType == TYP_UNDEF || varTypeIsStruct(varType));
- lvaSetStruct(tmpNum, structType, false);
-
- varType = lvaTable[tmpNum].lvType;
- // Now, set the type of the struct value. Note that lvaSetStruct may modify the type
- // of the lclVar to a specialized type (e.g. TYP_SIMD), based on the handle (structType)
- // that has been passed in for the value being assigned to the temp, in which case we
- // need to set 'val' to that same type.
- // Note also that if we always normalized the types of any node that might be a struct
- // type, this would not be necessary - but that requires additional JIT/EE interface
- // calls that may not actually be required - e.g. if we only access a field of a struct.
-
- GenTree* dst = gtNewLclvNode(tmpNum, varType);
- asg = impAssignStruct(dst, val, curLevel, pAfterStmt, di, block);
- }
- else
- {
- asg = gtNewTempAssign(tmpNum, val);
- }
+ GenTree* asg = gtNewTempAssign(lclNum, val, curLevel, pAfterStmt, di, block);
if (!asg->IsNothingNode())
{
WellKnownArg wellKnownArgType =
srcCall->ShouldHaveRetBufArg() ? WellKnownArg::RetBuffer : WellKnownArg::None;
- GenTree* destAddr = impGetStructAddr(dest, srcCall->gtRetClsHnd, CHECK_SPILL_ALL, /* willDeref */ true);
+ GenTree* destAddr = impGetStructAddr(dest, CHECK_SPILL_ALL, /* willDeref */ true);
NewCallArg newArg = NewCallArg::Primitive(destAddr).WellKnown(wellKnownArgType);
#if !defined(TARGET_ARM)
if (call->ShouldHaveRetBufArg())
{
// insert the return value buffer into the argument list as first byref parameter after 'this'
- GenTree* destAddr = impGetStructAddr(dest, call->gtRetClsHnd, CHECK_SPILL_ALL, /* willDeref */ true);
+ GenTree* destAddr = impGetStructAddr(dest, CHECK_SPILL_ALL, /* willDeref */ true);
call->gtArgs.InsertAfterThisOrFirst(this,
NewCallArg::Primitive(destAddr).WellKnown(WellKnownArg::RetBuffer));
{
// Since we are assigning the result of a GT_MKREFANY, "destAddr" must point to a refany.
// TODO-CQ: we can do this without address-exposing the local on the LHS.
- GenTree* destAddr = impGetStructAddr(dest, impGetRefAnyClass(), CHECK_SPILL_ALL, /* willDeref */ true);
+ GenTree* destAddr = impGetStructAddr(dest, CHECK_SPILL_ALL, /* willDeref */ true);
GenTree* destAddrClone;
- destAddr = impCloneExpr(destAddr, &destAddrClone, NO_CLASS_HANDLE, curLevel,
- pAfterStmt DEBUGARG("MKREFANY assignment"));
+ destAddr = impCloneExpr(destAddr, &destAddrClone, curLevel, pAfterStmt DEBUGARG("MKREFANY assignment"));
assert(OFFSETOF__CORINFO_TypedReference__dataPtr == 0);
assert(destAddr->gtType == TYP_I_IMPL || destAddr->gtType == TYP_BYREF);
// Arguments:
// destAddr - address of the destination of the assignment
// src - source of the assignment
-// structHnd - handle representing the struct type
// curLevel - stack level for which a spill may be being done
-// pAfterStmt - statement to insert any additional statements after
-// di - debug info for new statements
-// block - block to insert any additional statements in
//
// Return Value:
// The tree that should be appended to the statement list that represents the assignment.
// Notes:
// Temp assignments may be appended to impStmtList if spilling is necessary.
//
-GenTree* Compiler::impAssignStructPtr(GenTree* destAddr,
- GenTree* src,
- CORINFO_CLASS_HANDLE structHnd,
- unsigned curLevel,
- Statement** pAfterStmt, /* = NULL */
- const DebugInfo& di, /* = DebugInfo() */
- BasicBlock* block /* = NULL */
- )
+GenTree* Compiler::impAssignStructPtr(GenTree* destAddr, GenTree* src, unsigned curLevel)
{
var_types type = src->TypeGet();
ClassLayout* layout = (type == TYP_STRUCT) ? src->GetLayout(this) : nullptr;
GenTree* dst = gtNewLoadValueNode(type, layout, destAddr);
- GenTree* store = impAssignStruct(dst, src, curLevel, pAfterStmt, di, block);
+ GenTree* store = impAssignStruct(dst, src, curLevel);
return store;
}
//
// Arguments:
// structVal - The value in question
-// structHnd - The struct handle for "structVal"
// curLevel - Stack level for spilling
// willDeref - Whether the caller will dereference the address
//
// will return its address. Otherwise, address of a temporary assigned
// the value of "structVal" will be returned.
//
-GenTree* Compiler::impGetStructAddr(GenTree* structVal,
- CORINFO_CLASS_HANDLE structHnd,
- unsigned curLevel,
- bool willDeref)
+GenTree* Compiler::impGetStructAddr(GenTree* structVal, unsigned curLevel, bool willDeref)
{
assert(varTypeIsStruct(structVal));
switch (structVal->OperGet())
case GT_COMMA:
impAppendTree(structVal->AsOp()->gtGetOp1(), curLevel, impCurStmtDI);
- return impGetStructAddr(structVal->AsOp()->gtGetOp2(), structHnd, curLevel, willDeref);
+ return impGetStructAddr(structVal->AsOp()->gtGetOp2(), curLevel, willDeref);
default:
break;
}
unsigned lclNum = lvaGrabTemp(true DEBUGARG("location for address-of(RValue)"));
- impAssignTempGen(lclNum, structVal, structHnd, curLevel);
+ impAssignTempGen(lclNum, structVal, curLevel);
// The 'return value' is now address of the temp itself.
return gtNewLclVarAddrNode(lclNum, TYP_BYREF);
//
// Arguments:
// structVal - The node to normalize
-// structHnd - The struct type
// curLevel - The current stack level
//
// Return Value:
// The normalized "structVal".
//
-GenTree* Compiler::impNormStructVal(GenTree* structVal, CORINFO_CLASS_HANDLE structHnd, unsigned curLevel)
+GenTree* Compiler::impNormStructVal(GenTree* structVal, unsigned curLevel)
{
assert(varTypeIsStruct(structVal));
var_types structType = structVal->TypeGet();
{
if ((i == 1 && pRuntimeLookup->indirectFirstOffset) || (i == 2 && pRuntimeLookup->indirectSecondOffset))
{
- indOffTree = impCloneExpr(slotPtrTree, &slotPtrTree, NO_CLASS_HANDLE, CHECK_SPILL_ALL,
+ indOffTree = impCloneExpr(slotPtrTree, &slotPtrTree, CHECK_SPILL_ALL,
nullptr DEBUGARG("impRuntimeLookup indirectOffset"));
}
}
/* Assign the spilled entry to the temp */
- impAssignTempGen(tnum, tree, verCurrentState.esStack[level].seTypeInfo.GetClassHandle(), level);
+ impAssignTempGen(tnum, tree, level);
if (isNewTemp)
{
* If the tree has side-effects, it will be spilled to a temp.
*/
-GenTree* Compiler::impCloneExpr(GenTree* tree,
- GenTree** pClone,
- CORINFO_CLASS_HANDLE structHnd,
- unsigned curLevel,
+GenTree* Compiler::impCloneExpr(GenTree* tree,
+ GenTree** pClone,
+ unsigned curLevel,
Statement** pAfterStmt DEBUGARG(const char* reason))
{
if (!(tree->gtFlags & GTF_GLOB_EFFECT))
// specialized type (e.g. a SIMD type). So we will get the type from
// the lclVar AFTER calling impAssignTempGen().
- impAssignTempGen(temp, tree, structHnd, curLevel, pAfterStmt, impCurStmtDI);
+ impAssignTempGen(temp, tree, curLevel, pAfterStmt, impCurStmtDI);
var_types type = genActualType(lvaTable[temp].TypeGet());
*pClone = gtNewLclvNode(temp, type);
GenTree* objToBox = impPopStack().val;
// Spill struct to get its address (to access hasValue field)
- objToBox = impGetStructAddr(objToBox, nullableCls, CHECK_SPILL_ALL, true);
- static_assert_no_msg(OFFSETOF__CORINFO_NullableOfT__hasValue == 0);
+ objToBox = impGetStructAddr(objToBox, CHECK_SPILL_ALL, true);
+ static_assert_no_msg(OFFSETOF__CORINFO_NullableOfT__hasValue == 0);
impPushOnStack(gtNewIndir(TYP_BOOL, objToBox), typeInfo(TI_INT));
JITDUMP("\n Importing BOX; ISINST; BR_TRUE/FALSE as nullableVT.hasValue\n");
if (varTypeIsStruct(exprToBox))
{
assert(info.compCompHnd->getClassSize(pResolvedToken->hClass) == info.compCompHnd->getClassSize(operCls));
- op1 = impAssignStructPtr(op1, exprToBox, operCls, CHECK_SPILL_ALL);
+ op1 = impAssignStructPtr(op1, exprToBox, CHECK_SPILL_ALL);
}
else
{
return;
}
- op1 = gtNewHelperCallNode(boxHelper, TYP_REF, op2, impGetStructAddr(exprToBox, operCls, CHECK_SPILL_ALL, true));
+ op1 = gtNewHelperCallNode(boxHelper, TYP_REF, op2, impGetStructAddr(exprToBox, CHECK_SPILL_ALL, true));
}
/* Push the result back on the stack, */
unsigned tmpNum = lvaGrabTemp(true DEBUGARG("pseudo return buffer"));
// No need to spill anything as we're about to return.
- impAssignTempGen(tmpNum, op, info.compMethodInfo->args.retTypeClass, CHECK_SPILL_NONE);
+ impAssignTempGen(tmpNum, op, CHECK_SPILL_NONE);
op = gtNewLclvNode(tmpNum, info.compRetType);
JITDUMP("\nimpFixupStructReturnType: created a pseudo-return buffer for a special helper\n");
// This can replace op1 with a GT_COMMA that evaluates op1 into a local
//
- op1 = impCloneExpr(op1, &temp, NO_CLASS_HANDLE, CHECK_SPILL_ALL, nullptr DEBUGARG("CASTCLASS eval op1"));
+ op1 = impCloneExpr(op1, &temp, CHECK_SPILL_ALL, nullptr DEBUGARG("CASTCLASS eval op1"));
//
// op1 is now known to be a non-complex tree
// thus we can use gtClone(op1) from now on
}
else
{
- op1 = impGetStructAddr(op1, clsHnd, CHECK_SPILL_ALL, false);
+ op1 = impGetStructAddr(op1, CHECK_SPILL_ALL, false);
}
JITDUMP("\n ... optimized to ...\n");
else
{
const unsigned tmpNum = lvaGrabTemp(true DEBUGARG("dup spill"));
- impAssignTempGen(tmpNum, op1, tiRetVal.GetClassHandle(), CHECK_SPILL_ALL);
+ impAssignTempGen(tmpNum, op1, CHECK_SPILL_ALL);
var_types type = genActualType(lvaTable[tmpNum].TypeGet());
assert(lvaTable[tmpNum].lvSingleDef == 0);
}
else
{
- op1 = impCloneExpr(op1, &op2, tiRetVal.GetClassHandle(), CHECK_SPILL_ALL,
- nullptr DEBUGARG("DUP instruction"));
+ op1 = impCloneExpr(op1, &op2, CHECK_SPILL_ALL, nullptr DEBUGARG("DUP instruction"));
}
assert(!(op1->gtFlags & GTF_GLOB_EFFECT) && !(op2->gtFlags & GTF_GLOB_EFFECT));
{
BADCODE("top of stack must be a value type");
}
- obj = impGetStructAddr(obj, objType, CHECK_SPILL_ALL, true);
+ obj = impGetStructAddr(obj, CHECK_SPILL_ALL, true);
}
op1 = gtNewFieldAddrNode(varTypeIsGC(obj) ? TYP_BYREF : TYP_I_IMPL, resolvedToken.hField, obj,
op1 = impPopStack().val;
// make certain it is normalized;
- op1 = impNormStructVal(op1, impGetRefAnyClass(), CHECK_SPILL_ALL);
+ op1 = impNormStructVal(op1, CHECK_SPILL_ALL);
// Call helper GETREFANY(classHandle, op1);
GenTreeCall* helperCall = gtNewHelperCallNode(CORINFO_HELP_GETREFANY, TYP_BYREF);
else
{
// Get the address of the refany
- op1 = impGetStructAddr(op1, impGetRefAnyClass(), CHECK_SPILL_ALL, /* willDeref */ true);
+ op1 = impGetStructAddr(op1, CHECK_SPILL_ALL, /* willDeref */ true);
// Fetch the type from the correct slot
op1 = gtNewOperNode(GT_ADD, TYP_BYREF, op1,
if (opcode == CEE_UNBOX)
{
GenTree* cloneOperand;
- op1 = impCloneExpr(op1, &cloneOperand, NO_CLASS_HANDLE, CHECK_SPILL_ALL,
+ op1 = impCloneExpr(op1, &cloneOperand, CHECK_SPILL_ALL,
nullptr DEBUGARG("optimized unbox clone"));
GenTree* boxPayloadOffset = gtNewIconNode(TARGET_POINTER_SIZE, TYP_I_IMPL);
// push(clone + TARGET_POINTER_SIZE)
//
GenTree* cloneOperand;
- op1 = impCloneExpr(op1, &cloneOperand, NO_CLASS_HANDLE, CHECK_SPILL_ALL,
- nullptr DEBUGARG("inline UNBOX clone1"));
+ op1 = impCloneExpr(op1, &cloneOperand, CHECK_SPILL_ALL, nullptr DEBUGARG("inline UNBOX clone1"));
op1 = gtNewMethodTableLookup(op1);
GenTree* condBox = gtNewOperNode(GT_EQ, TYP_INT, op1, op2);
- op1 = impCloneExpr(cloneOperand, &cloneOperand, NO_CLASS_HANDLE, CHECK_SPILL_ALL,
+ op1 = impCloneExpr(cloneOperand, &cloneOperand, CHECK_SPILL_ALL,
nullptr DEBUGARG("inline UNBOX clone2"));
op2 = impTokenToHandle(&resolvedToken);
if (op2 == nullptr)
CORINFO_CLASS_HANDLE hClass DEBUGARG(CorInfoCallConvExtension callConv))
{
unsigned tmpNum = lvaGrabTemp(true DEBUGARG("Return value temp for multireg return"));
- impAssignTempGen(tmpNum, op, hClass, CHECK_SPILL_ALL);
+ lvaSetStruct(tmpNum, hClass, false);
+
+ impAssignTempGen(tmpNum, op, CHECK_SPILL_ALL);
LclVarDsc* varDsc = lvaGetDesc(tmpNum);
}
}
- impAssignTempGen(lvaInlineeReturnSpillTemp, op2, se.seTypeInfo.GetClassHandle(), CHECK_SPILL_ALL);
+ impAssignTempGen(lvaInlineeReturnSpillTemp, op2, CHECK_SPILL_ALL);
var_types lclRetType = lvaGetDesc(lvaInlineeReturnSpillTemp)->lvType;
GenTree* tmpOp2 = gtNewLclvNode(lvaInlineeReturnSpillTemp, lclRetType);
assert(info.compRetNativeType != TYP_VOID);
assert(fgMoreThanOneReturnBlock() || impInlineInfo->HasGcRefLocals());
- impAssignTempGen(lvaInlineeReturnSpillTemp, op2, se.seTypeInfo.GetClassHandle(), CHECK_SPILL_ALL);
+ impAssignTempGen(lvaInlineeReturnSpillTemp, op2, CHECK_SPILL_ALL);
}
if (compMethodReturnsMultiRegRetType())
{
inlRetExpr->gtSubstExpr =
impAssignStructPtr(dest, gtNewLclvNode(lvaInlineeReturnSpillTemp, info.compRetType),
- retClsHnd, CHECK_SPILL_ALL);
+ CHECK_SPILL_ALL);
}
}
else
{
- inlRetExpr->gtSubstExpr = impAssignStructPtr(dest, op2, retClsHnd, CHECK_SPILL_ALL);
+ inlRetExpr->gtSubstExpr = impAssignStructPtr(dest, op2, CHECK_SPILL_ALL);
}
}
}
GenTree* retBuffAddr =
gtNewLclvNode(info.compRetBuffArg, TYP_BYREF DEBUGARG(impCurStmtDI.GetLocation().GetOffset()));
- op2 = impAssignStructPtr(retBuffAddr, op2, retClsHnd, CHECK_SPILL_ALL);
+ op2 = impAssignStructPtr(retBuffAddr, op2, CHECK_SPILL_ALL);
impAppendTree(op2, CHECK_SPILL_NONE, impCurStmtDI);
// There are cases where the address of the implicit RetBuf should be returned explicitly.
// Clone the (possibly transformed) "this" pointer
GenTree* thisPtrCopy;
- thisPtr = impCloneExpr(thisPtr, &thisPtrCopy, NO_CLASS_HANDLE, CHECK_SPILL_ALL,
- nullptr DEBUGARG("LDVIRTFTN this pointer"));
+ thisPtr =
+ impCloneExpr(thisPtr, &thisPtrCopy, CHECK_SPILL_ALL, nullptr DEBUGARG("LDVIRTFTN this pointer"));
GenTree* fptr = impImportLdvirtftn(thisPtr, pResolvedToken, callInfo);
assert(fptr != nullptr);
unsigned calliSlot = lvaGrabTemp(true DEBUGARG("calli"));
LclVarDsc* varDsc = lvaGetDesc(calliSlot);
- impAssignTempGen(calliSlot, call, tiRetVal.GetClassHandle(), CHECK_SPILL_NONE);
+ impAssignTempGen(calliSlot, call, CHECK_SPILL_NONE);
// impAssignTempGen can change src arg list and return type for call that returns struct.
var_types type = genActualType(lvaTable[calliSlot].TypeGet());
call = gtNewLclvNode(calliSlot, type);
if (call->IsUnmanaged())
{
// Native ABIs do not allow retbufs to alias anything.
- // This is allowed by the managed ABI and impAssignStructPtr will
+ // This is allowed by the managed ABI and impAssignStruct will
// never introduce copies due to this.
unsigned tmpNum = lvaGrabTemp(true DEBUGARG("Retbuf for unmanaged call"));
- impAssignTempGen(tmpNum, call, retClsHnd, CHECK_SPILL_ALL);
+ impAssignTempGen(tmpNum, call, CHECK_SPILL_ALL);
return gtNewLclvNode(tmpNum, lvaGetDesc(tmpNum)->TypeGet());
}
if (fgAddrCouldBeNull(array))
{
GenTree* arrayClone;
- array = impCloneExpr(array, &arrayClone, NO_CLASS_HANDLE, (unsigned)CHECK_SPILL_ALL,
+ array = impCloneExpr(array, &arrayClone, CHECK_SPILL_ALL,
nullptr DEBUGARG("MemoryMarshal.GetArrayDataReference array"));
- impAppendTree(gtNewNullCheck(array, compCurBB), (unsigned)CHECK_SPILL_ALL, impCurStmtDI);
+ impAppendTree(gtNewNullCheck(array, compCurBB), CHECK_SPILL_ALL, impCurStmtDI);
array = arrayClone;
}
noway_assert(genTypeSize(rawHandle->TypeGet()) == genTypeSize(TYP_I_IMPL));
unsigned rawHandleSlot = lvaGrabTemp(true DEBUGARG("rawHandle"));
- impAssignTempGen(rawHandleSlot, rawHandle, clsHnd, CHECK_SPILL_NONE);
+ impAssignTempGen(rawHandleSlot, rawHandle, CHECK_SPILL_NONE);
GenTree* lclVarAddr = gtNewLclVarAddrNode(rawHandleSlot);
var_types resultType = JITtype2varType(sig->retType);
#endif // defined(DEBUG)
// We need to use both index and ptr-to-span twice, so clone or spill.
- index = impCloneExpr(index, &indexClone, NO_CLASS_HANDLE, CHECK_SPILL_ALL,
- nullptr DEBUGARG("Span.get_Item index"));
+ index = impCloneExpr(index, &indexClone, CHECK_SPILL_ALL, nullptr DEBUGARG("Span.get_Item index"));
if (impIsAddressInLocal(ptrToSpan))
{
}
else
{
- ptrToSpan = impCloneExpr(ptrToSpan, &ptrToSpanClone, NO_CLASS_HANDLE, CHECK_SPILL_ALL,
+ ptrToSpan = impCloneExpr(ptrToSpan, &ptrToSpanClone, CHECK_SPILL_ALL,
nullptr DEBUGARG("Span.get_Item ptrToSpan"));
}
GenTree* gtArrClone = nullptr;
if (((gtArr->gtFlags & GTF_GLOB_EFFECT) != 0) || (ni == NI_System_Array_GetUpperBound))
{
- gtArr = impCloneExpr(gtArr, >ArrClone, NO_CLASS_HANDLE, CHECK_SPILL_ALL,
+ gtArr = impCloneExpr(gtArr, >ArrClone, CHECK_SPILL_ALL,
nullptr DEBUGARG("MD intrinsics array"));
}
// * 64-bit lzcnt: (value == 0) ? 64 : (63 ^ BSR(value))
GenTree* op1Dup;
- op1 = impCloneExpr(op1, &op1Dup, NO_CLASS_HANDLE, (unsigned)CHECK_SPILL_ALL,
- nullptr DEBUGARG("Cloning op1 for LeadingZeroCount"));
+ op1 = impCloneExpr(op1, &op1Dup, CHECK_SPILL_ALL, nullptr DEBUGARG("Cloning op1 for LeadingZeroCount"));
hwintrinsic = varTypeIsLong(baseType) ? NI_X86Base_X64_BitScanReverse : NI_X86Base_BitScanReverse;
op1Dup = gtNewScalarHWIntrinsicNode(baseType, op1Dup, hwintrinsic);
// * 64-bit tzcnt: (value == 0) ? 64 : BSF(value)
GenTree* op1Dup;
- op1 = impCloneExpr(op1, &op1Dup, NO_CLASS_HANDLE, (unsigned)CHECK_SPILL_ALL,
- nullptr DEBUGARG("Cloning op1 for TrailingZeroCount"));
+ op1 =
+ impCloneExpr(op1, &op1Dup, CHECK_SPILL_ALL, nullptr DEBUGARG("Cloning op1 for TrailingZeroCount"));
hwintrinsic = varTypeIsLong(baseType) ? NI_X86Base_X64_BitScanForward : NI_X86Base_BitScanForward;
op1Dup = gtNewScalarHWIntrinsicNode(baseType, op1Dup, hwintrinsic);
JITDUMP("Calling impNormStructVal on:\n");
DISPTREE(argNode);
- argNode = impNormStructVal(argNode, classHnd, CHECK_SPILL_ALL);
+ argNode = impNormStructVal(argNode, CHECK_SPILL_ALL);
// For SIMD types the normalization can normalize TYP_STRUCT to
// e.g. TYP_SIMD16 which we keep (along with the class handle) in
// the CallArgs.
assert(retExpr->OperGet() == GT_RET_EXPR);
const unsigned tmp = comp->lvaGrabTemp(true DEBUGARG("spilling ret_expr"));
JITDUMP("Storing return expression [%06u] to a local var V%02u.\n", comp->dspTreeID(retExpr), tmp);
- comp->impAssignTempGen(tmp, retExpr, (unsigned)Compiler::CHECK_SPILL_NONE);
+ comp->impAssignTempGen(tmp, retExpr, Compiler::CHECK_SPILL_NONE);
*pRetExpr = comp->gtNewLclvNode(tmp, retExpr->TypeGet());
assert(comp->lvaTable[tmp].lvSingleDef == 0);
if (unrolled != nullptr)
{
// We succeeded, fill the placeholders:
- impAssignTempGen(spanObjRef, impGetStructAddr(spanObj, spanCls, CHECK_SPILL_NONE, true));
+ impAssignTempGen(spanObjRef, impGetStructAddr(spanObj, CHECK_SPILL_NONE, true));
impAssignTempGen(spanDataTmp, spanData);
if (unrolled->OperIs(GT_QMARK))
{
GenTree* tree = stmt->GetRootNode();
assert(tree->OperGet() == GT_ASG);
- GenTree* originalLHS = tree->AsOp()->gtOp1;
- GenTree* prevLHS = tree->AsOp()->gtOp1;
- GenTree* prevRHS = tree->AsOp()->gtOp2;
- unsigned index = 0;
- CorInfoType simdBaseJitType = CORINFO_TYPE_UNDEF;
- unsigned simdSize = 0;
- GenTree* simdLclAddr = getSIMDStructFromField(prevRHS, &simdBaseJitType, &index, &simdSize, true);
-
- if ((simdLclAddr == nullptr) || (index != 0) || (simdBaseJitType != CORINFO_TYPE_FLOAT))
+ GenTree* originalLHS = tree->AsOp()->gtOp1;
+ GenTree* prevLHS = tree->AsOp()->gtOp1;
+ GenTree* prevRHS = tree->AsOp()->gtOp2;
+ unsigned index = 0;
+ var_types simdBaseType = prevRHS->TypeGet();
+ unsigned simdSize = 0;
+ GenTree* simdLclAddr = getSIMDStructFromField(prevRHS, &index, &simdSize, true);
+
+ if ((simdLclAddr == nullptr) || (index != 0) || (simdBaseType != TYP_FLOAT))
{
// if the RHS is not from a SIMD vector field X, then there is no need to check further.
return false;
}
- var_types simdBaseType = JitType2PreciseVarType(simdBaseJitType);
var_types simdType = getSIMDTypeForSize(simdSize);
int assignmentsCount = simdSize / genTypeSize(simdBaseType) - 1;
int remainingAssignments = assignmentsCount;
// Arguments:
// tree - GentreePtr. This node will be checked to see this is a field which belongs to a simd
// struct used for simd intrinsic or not.
-// simdBaseJitTypeOut - CorInfoType pointer, if the tree node is the tree we want, we set *simdBaseJitTypeOut
-// to simd lclvar's base JIT type.
// indexOut - unsigned pointer, if the tree is used for simd intrinsic, we will set *indexOut
// equals to the index number of this field.
// simdSizeOut - unsigned pointer, if the tree is used for simd intrinsic, set the *simdSizeOut
// A GenTree* which points the simd lclvar tree belongs to. If the tree is not the simd
// instrinic related field, return nullptr.
//
-GenTree* Compiler::getSIMDStructFromField(GenTree* tree,
- CorInfoType* simdBaseJitTypeOut,
- unsigned* indexOut,
- unsigned* simdSizeOut,
- bool ignoreUsedInSIMDIntrinsic /*false*/)
+GenTree* Compiler::getSIMDStructFromField(GenTree* tree,
+ unsigned* indexOut,
+ unsigned* simdSizeOut,
+ bool ignoreUsedInSIMDIntrinsic /*false*/)
{
if (tree->OperIs(GT_IND))
{
LclVarDsc* varDsc = lvaGetDesc(objRef->AsLclVarCommon());
if (varTypeIsSIMD(varDsc) && (varDsc->lvIsUsedInSIMDIntrinsic() || ignoreUsedInSIMDIntrinsic))
{
- CorInfoType simdBaseJitType = varDsc->GetSimdBaseJitType();
- var_types simdBaseType = JITtype2varType(simdBaseJitType);
- unsigned fieldOffset = addr->AsFieldAddr()->gtFldOffset;
- unsigned baseTypeSize = genTypeSize(simdBaseType);
+ var_types elementType = tree->TypeGet();
+ unsigned fieldOffset = addr->AsFieldAddr()->gtFldOffset;
+ unsigned elementSize = genTypeSize(elementType);
- // Below condition is convervative. We don't actually need the two types to
- // match (only the tree type is relevant), but we don't have a convenient way
- // to turn the tree type into "CorInfoType".
- if ((tree->TypeGet() == simdBaseType) && ((fieldOffset % baseTypeSize) == 0))
+ if (varTypeIsArithmetic(elementType) && ((fieldOffset % elementSize) == 0))
{
- *simdSizeOut = varDsc->lvExactSize();
- *simdBaseJitTypeOut = simdBaseJitType;
- *indexOut = fieldOffset / baseTypeSize;
+ *simdSizeOut = varDsc->lvExactSize();
+ *indexOut = fieldOffset / elementSize;
return objRef;
}
Statement* pAfterStatement = lastStmt;
const DebugInfo& di = lastStmt->GetDebugInfo();
- GenTree* tree = gtNewTempAssign(genReturnLocal, ret->gtGetOp1(), &pAfterStatement, di, block);
+ GenTree* tree =
+ gtNewTempAssign(genReturnLocal, ret->gtGetOp1(), CHECK_SPILL_NONE, &pAfterStatement, di, block);
if (tree->OperIsCopyBlkOp())
{
tree = fgMorphCopyBlock(tree);
// Handle calls that may return the struct via a return buffer.
if (tree->OperIs(GT_CALL, GT_RET_EXPR))
{
- tree = impNormStructVal(tree, se.seTypeInfo.GetClassHandle(), CHECK_SPILL_ALL);
+ tree = impNormStructVal(tree, CHECK_SPILL_ALL);
}
return tree;
GenTree* expr = stmt->GetRootNode();
if (expr->OperGet() == GT_ASG && expr->TypeGet() == TYP_FLOAT)
{
- GenTree* curDst = expr->AsOp()->gtOp1;
- GenTree* curSrc = expr->AsOp()->gtOp2;
- unsigned index = 0;
- CorInfoType simdBaseJitType = CORINFO_TYPE_UNDEF;
- unsigned simdSize = 0;
- GenTree* srcSimdLclAddr = getSIMDStructFromField(curSrc, &simdBaseJitType, &index, &simdSize, true);
-
- if (srcSimdLclAddr == nullptr || simdBaseJitType != CORINFO_TYPE_FLOAT)
+ GenTree* curDst = expr->AsOp()->gtOp1;
+ GenTree* curSrc = expr->AsOp()->gtOp2;
+ unsigned index = 0;
+ var_types simdBaseType = curSrc->TypeGet();
+ unsigned simdSize = 0;
+ GenTree* srcSimdLclAddr = getSIMDStructFromField(curSrc, &index, &simdSize, true);
+
+ if (srcSimdLclAddr == nullptr || simdBaseType != TYP_FLOAT)
{
fgPreviousCandidateSIMDFieldAsgStmt = nullptr;
}
else if (fgPreviousCandidateSIMDFieldAsgStmt != nullptr)
{
assert(index > 0);
- var_types simdBaseType = JitType2PreciseVarType(simdBaseJitType);
- GenTree* prevAsgExpr = fgPreviousCandidateSIMDFieldAsgStmt->GetRootNode();
- GenTree* prevDst = prevAsgExpr->AsOp()->gtOp1;
- GenTree* prevSrc = prevAsgExpr->AsOp()->gtOp2;
+ GenTree* prevAsgExpr = fgPreviousCandidateSIMDFieldAsgStmt->GetRootNode();
+ GenTree* prevDst = prevAsgExpr->AsOp()->gtOp1;
+ GenTree* prevSrc = prevAsgExpr->AsOp()->gtOp2;
if (!areArgumentsContiguous(prevDst, curDst) || !areArgumentsContiguous(prevSrc, curSrc))
{
fgPreviousCandidateSIMDFieldAsgStmt = nullptr;
case NI_Quaternion_Inverse:
{
GenTree* clonedOp1;
- op1 = impCloneExpr(op1, &clonedOp1, NO_CLASS_HANDLE, CHECK_SPILL_ALL,
+ op1 = impCloneExpr(op1, &clonedOp1, CHECK_SPILL_ALL,
nullptr DEBUGARG("Clone op1 for quaternion inverse (1)"));
GenTree* clonedOp2;
- clonedOp1 = impCloneExpr(clonedOp1, &clonedOp2, NO_CLASS_HANDLE, CHECK_SPILL_ALL,
+ clonedOp1 = impCloneExpr(clonedOp1, &clonedOp2, CHECK_SPILL_ALL,
nullptr DEBUGARG("Clone op1 for quaternion inverse (2)"));
GenTreeVecCon* vecCon = gtNewVconNode(retType);
case NI_Vector4_Length:
{
GenTree* clonedOp1;
- op1 = impCloneExpr(op1, &clonedOp1, NO_CLASS_HANDLE, CHECK_SPILL_ALL,
- nullptr DEBUGARG("Clone op1 for vector length"));
+ op1 =
+ impCloneExpr(op1, &clonedOp1, CHECK_SPILL_ALL, nullptr DEBUGARG("Clone op1 for vector length"));
op1 = gtNewSimdDotProdNode(retType, op1, clonedOp1, simdBaseJitType, simdSize);
case NI_Vector4_LengthSquared:
{
GenTree* clonedOp1;
- op1 = impCloneExpr(op1, &clonedOp1, NO_CLASS_HANDLE, CHECK_SPILL_ALL,
+ op1 = impCloneExpr(op1, &clonedOp1, CHECK_SPILL_ALL,
nullptr DEBUGARG("Clone op1 for vector length squared"));
return gtNewSimdDotProdNode(retType, op1, clonedOp1, simdBaseJitType, simdSize);
case NI_Vector4_Normalize:
{
GenTree* clonedOp1;
- op1 = impCloneExpr(op1, &clonedOp1, NO_CLASS_HANDLE, CHECK_SPILL_ALL,
+ op1 = impCloneExpr(op1, &clonedOp1, CHECK_SPILL_ALL,
nullptr DEBUGARG("Clone op1 for vector normalize (1)"));
GenTree* clonedOp2;
- clonedOp1 = impCloneExpr(clonedOp1, &clonedOp2, NO_CLASS_HANDLE, CHECK_SPILL_ALL,
+ clonedOp1 = impCloneExpr(clonedOp1, &clonedOp2, CHECK_SPILL_ALL,
nullptr DEBUGARG("Clone op1 for vector normalize (2)"));
op1 = gtNewSimdDotProdNode(retType, op1, clonedOp1, simdBaseJitType, simdSize);
op1 = gtNewSimdBinOpNode(GT_SUB, simdType, op1, op2, simdBaseJitType, simdSize);
GenTree* clonedOp1;
- op1 = impCloneExpr(op1, &clonedOp1, NO_CLASS_HANDLE, CHECK_SPILL_ALL,
+ op1 = impCloneExpr(op1, &clonedOp1, CHECK_SPILL_ALL,
nullptr DEBUGARG("Clone diff for vector distance"));
op1 = gtNewSimdDotProdNode(retType, op1, clonedOp1, simdBaseJitType, simdSize);
op1 = gtNewSimdBinOpNode(GT_SUB, simdType, op1, op2, simdBaseJitType, simdSize);
GenTree* clonedOp1;
- op1 = impCloneExpr(op1, &clonedOp1, NO_CLASS_HANDLE, CHECK_SPILL_ALL,
+ op1 = impCloneExpr(op1, &clonedOp1, CHECK_SPILL_ALL,
nullptr DEBUGARG("Clone diff for vector distance squared"));
return gtNewSimdDotProdNode(retType, op1, clonedOp1, simdBaseJitType, simdSize);
// clonedOp3 = op3
GenTree* clonedOp3;
- op3 = impCloneExpr(op3, &clonedOp3, NO_CLASS_HANDLE, CHECK_SPILL_ALL,
- nullptr DEBUGARG("Clone op3 for vector lerp"));
+ op3 = impCloneExpr(op3, &clonedOp3, CHECK_SPILL_ALL, nullptr DEBUGARG("Clone op3 for vector lerp"));
#if defined(TARGET_XARCH)
// op3 = 1.0f - op3