summaryrefslogtreecommitdiff
path: root/src/jit/lower.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/jit/lower.cpp')
-rw-r--r--src/jit/lower.cpp1341
1 files changed, 674 insertions, 667 deletions
diff --git a/src/jit/lower.cpp b/src/jit/lower.cpp
index b5129ca9f0..c4ae0c842e 100644
--- a/src/jit/lower.cpp
+++ b/src/jit/lower.cpp
@@ -33,7 +33,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
// MakeSrcContained: Make "tree" a contained node
//
// Arguments:
-// 'parentNode' is a non-leaf node that can contain its 'childNode'
+// 'parentNode' is a non-leaf node that can contain its 'childNode'
// 'childNode' is an op that will now be contained by its parent.
//
// Notes:
@@ -52,13 +52,13 @@ void Lowering::MakeSrcContained(GenTreePtr parentNode, GenTreePtr childNode)
//------------------------------------------------------------------------
// CheckImmedAndMakeContained: Check and make 'childNode' contained
// Arguments:
-// 'parentNode' is any non-leaf node
+// 'parentNode' is any non-leaf node
// 'childNode' is an child op of 'parentNode'
// Return value:
// returns true if we are able to make childNode contained immediate
//
// Notes:
-// Checks if the 'childNode' is a containable immediate
+// Checks if the 'childNode' is a containable immediate
// and then makes it contained
//
bool Lowering::CheckImmedAndMakeContained(GenTree* parentNode, GenTree* childNode)
@@ -94,15 +94,14 @@ bool Lowering::IsSafeToContainMem(GenTree* parentNode, GenTree* childNode)
assert(childNode->isMemoryOp());
// Check conflicts against nodes between 'childNode' and 'parentNode'
- GenTree* node;
+ GenTree* node;
unsigned int childFlags = (childNode->gtFlags & GTF_ALL_EFFECT);
- for (node = childNode->gtNext;
- (node != parentNode) && (node != nullptr);
- node = node->gtNext)
+ for (node = childNode->gtNext; (node != parentNode) && (node != nullptr); node = node->gtNext)
{
if ((childFlags != 0) && node->IsCall())
{
- bool isPureHelper = (node->gtCall.gtCallType == CT_HELPER) && comp->s_helperCallProperties.IsPure(comp->eeGetHelperNum(node->gtCall.gtCallMethHnd));
+ bool isPureHelper = (node->gtCall.gtCallType == CT_HELPER) &&
+ comp->s_helperCallProperties.IsPure(comp->eeGetHelperNum(node->gtCall.gtCallMethHnd));
if (!isPureHelper && ((node->gtFlags & childFlags & GTF_ALL_EFFECT) != 0))
{
return false;
@@ -123,7 +122,7 @@ bool Lowering::IsSafeToContainMem(GenTree* parentNode, GenTree* childNode)
//------------------------------------------------------------------------
-//static
+// static
Compiler::fgWalkResult Lowering::LowerNodeHelper(GenTreePtr* pTree, Compiler::fgWalkData* data)
{
Lowering* lower = (Lowering*)data->pCallbackData;
@@ -131,16 +130,13 @@ Compiler::fgWalkResult Lowering::LowerNodeHelper(GenTreePtr* pTree, Compiler::fg
return Compiler::WALK_CONTINUE;
}
-
/** Creates an assignment of an existing tree to a new temporary local variable
* and the specified reference count for the new variable.
*/
-GenTreePtr Lowering::CreateLocalTempAsg(GenTreePtr rhs,
- unsigned refCount,
- GenTreePtr* ppLclVar) //out legacy arg
+GenTreePtr Lowering::CreateLocalTempAsg(GenTreePtr rhs, unsigned refCount, GenTreePtr* ppLclVar) // out legacy arg
{
- unsigned lclNum = comp->lvaGrabTemp(true DEBUGARG("Lowering is creating a new local variable"));
- comp->lvaSortAgain = true;
+ unsigned lclNum = comp->lvaGrabTemp(true DEBUGARG("Lowering is creating a new local variable"));
+ comp->lvaSortAgain = true;
comp->lvaTable[lclNum].lvType = rhs->TypeGet();
// Make sure we don't lose precision when downgrading to short
@@ -148,8 +144,9 @@ GenTreePtr Lowering::CreateLocalTempAsg(GenTreePtr rhs,
comp->lvaTable[lclNum].lvRefCnt = (short)(refCount);
JITDUMP("Lowering has requested a new temporary local variable: V%02u with refCount %u \n", lclNum, refCount);
- GenTreeLclVar* store = new(comp, GT_STORE_LCL_VAR) GenTreeLclVar(GT_STORE_LCL_VAR, rhs->TypeGet(), lclNum, BAD_IL_OFFSET);
- store->gtOp1 = rhs;
+ GenTreeLclVar* store =
+ new (comp, GT_STORE_LCL_VAR) GenTreeLclVar(GT_STORE_LCL_VAR, rhs->TypeGet(), lclNum, BAD_IL_OFFSET);
+ store->gtOp1 = rhs;
store->gtFlags = (rhs->gtFlags & GTF_COMMON_MASK);
store->gtFlags |= GTF_VAR_DEF;
return store;
@@ -173,37 +170,38 @@ GenTreePtr Lowering::CreateLocalTempAsg(GenTreePtr rhs,
// The newly created statement is usually an embedded statement but it can also be a top-level
// statement if the tree to be replaced extends to the begining of the current statement. If
// a top-level statement is created any embedded statements contained in the tree move to the
-// the new top-level statement, before the current statement. Such embedded statements need to
+// the new top-level statement, before the current statement. Such embedded statements need to
// be lowered here because the normal lowering code path won't reach them anymore.
//
-// TODO-Cleanup:
-// Some uses of fgInsertEmbeddedFormTemp in lowering could be replaced with this to avoid
+// TODO-Cleanup:
+// Some uses of fgInsertEmbeddedFormTemp in lowering could be replaced with this to avoid
// duplication, see LowerArrElem for example.
GenTreeStmt* Lowering::CreateTemporary(GenTree** ppTree)
{
GenTreeStmt* newStmt = comp->fgInsertEmbeddedFormTemp(ppTree);
- // The tree is assumed to be already lowered so the newly created statement
+ // The tree is assumed to be already lowered so the newly created statement
// should not be lowered again.
newStmt->gtFlags |= GTF_STMT_SKIP_LOWER;
assert(newStmt->gtStmtExpr->OperIsLocalStore());
- // If the newly created statement is top-level then we need to manually lower its embedded
+ // If the newly created statement is top-level then we need to manually lower its embedded
// statements, the tree is lowered but some of its embedded statements are yet to be lowered.
if (newStmt->gtStmtIsTopLevel())
{
GenTree* curStmt = comp->compCurStmt;
- for (GenTree* nextEmbeddedStmt = newStmt->gtStmtNextIfEmbedded();
- nextEmbeddedStmt != nullptr;
- nextEmbeddedStmt = nextEmbeddedStmt->gtStmt.gtStmtNextIfEmbedded())
+ for (GenTree* nextEmbeddedStmt = newStmt->gtStmtNextIfEmbedded(); nextEmbeddedStmt != nullptr;
+ nextEmbeddedStmt = nextEmbeddedStmt->gtStmt.gtStmtNextIfEmbedded())
{
// A previous call to CreateTemporary could have created embedded statements
// from the tree and those are already lowered.
if ((nextEmbeddedStmt->gtFlags & GTF_STMT_SKIP_LOWER) != 0)
+ {
continue;
+ }
#ifdef DEBUG
if (comp->verbose)
@@ -216,7 +214,7 @@ GenTreeStmt* Lowering::CreateTemporary(GenTree** ppTree)
nextEmbeddedStmt->gtFlags |= GTF_STMT_SKIP_LOWER;
// Lowering can remove the statement and set compCurStmt to another suitable statement.
- // Currently only switch lowering does this and since embedded statements can't contain
+ // Currently only switch lowering does this and since embedded statements can't contain
// a GT_SWITCH this case should never be hit here.
assert(comp->compCurStmt == nextEmbeddedStmt);
}
@@ -227,7 +225,7 @@ GenTreeStmt* Lowering::CreateTemporary(GenTree** ppTree)
return newStmt;
}
-// This is the main entry point for Lowering.
+// This is the main entry point for Lowering.
// In addition to that, LowerNode is also responsible for initializing the
// treeNodeMap data structure consumed by LSRA. This map is a 1:1 mapping between
@@ -251,46 +249,46 @@ void Lowering::LowerNode(GenTreePtr* ppTree, Compiler::fgWalkData* data)
assert(*ppTree);
switch ((*ppTree)->gtOper)
{
- case GT_IND:
- case GT_STOREIND:
- LowerInd(ppTree);
- break;
+ case GT_IND:
+ case GT_STOREIND:
+ LowerInd(ppTree);
+ break;
- case GT_ADD:
- LowerAdd(ppTree, data);
- break;
-
- case GT_UDIV:
- case GT_UMOD:
- LowerUnsignedDivOrMod(*ppTree);
- break;
+ case GT_ADD:
+ LowerAdd(ppTree, data);
+ break;
- case GT_DIV:
- case GT_MOD:
- LowerSignedDivOrMod(ppTree, data);
- break;
+ case GT_UDIV:
+ case GT_UMOD:
+ LowerUnsignedDivOrMod(*ppTree);
+ break;
- case GT_SWITCH:
- LowerSwitch(ppTree);
- break;
+ case GT_DIV:
+ case GT_MOD:
+ LowerSignedDivOrMod(ppTree, data);
+ break;
- case GT_CALL:
- LowerCall(*ppTree);
- break;
+ case GT_SWITCH:
+ LowerSwitch(ppTree);
+ break;
- case GT_JMP:
- LowerJmpMethod(*ppTree);
- break;
+ case GT_CALL:
+ LowerCall(*ppTree);
+ break;
- case GT_RETURN:
- LowerRet(*ppTree);
- break;
+ case GT_JMP:
+ LowerJmpMethod(*ppTree);
+ break;
- case GT_CAST:
- LowerCast(ppTree);
- break;
+ case GT_RETURN:
+ LowerRet(*ppTree);
+ break;
- case GT_ARR_ELEM:
+ case GT_CAST:
+ LowerCast(ppTree);
+ break;
+
+ case GT_ARR_ELEM:
{
GenTree* oldTree = *ppTree;
LowerArrElem(ppTree, data);
@@ -298,57 +296,57 @@ void Lowering::LowerNode(GenTreePtr* ppTree, Compiler::fgWalkData* data)
}
break;
- case GT_ROL:
- case GT_ROR:
- LowerRotate(*ppTree);
- break;
+ case GT_ROL:
+ case GT_ROR:
+ LowerRotate(*ppTree);
+ break;
#ifdef FEATURE_SIMD
- case GT_SIMD:
- if ((*ppTree)->TypeGet() == TYP_SIMD12)
- {
- // GT_SIMD node requiring to produce TYP_SIMD12 in fact
- // produces a TYP_SIMD16 result
- (*ppTree)->gtType = TYP_SIMD16;
- }
- break;
+ case GT_SIMD:
+ if ((*ppTree)->TypeGet() == TYP_SIMD12)
+ {
+ // GT_SIMD node requiring to produce TYP_SIMD12 in fact
+ // produces a TYP_SIMD16 result
+ (*ppTree)->gtType = TYP_SIMD16;
+ }
+ break;
- case GT_LCL_VAR:
- case GT_STORE_LCL_VAR:
- if ((*ppTree)->TypeGet() == TYP_SIMD12)
- {
+ case GT_LCL_VAR:
+ case GT_STORE_LCL_VAR:
+ if ((*ppTree)->TypeGet() == TYP_SIMD12)
+ {
#ifdef _TARGET_64BIT_
- // Assumption 1:
- // RyuJit backend depends on the assumption that on 64-Bit targets Vector3 size is rounded off
- // to TARGET_POINTER_SIZE and hence Vector3 locals on stack can be treated as TYP_SIMD16 for
- // reading and writing purposes.
- //
- // Assumption 2:
- // RyuJit backend is making another implicit assumption that Vector3 type args when passed in
- // registers or on stack, the upper most 4-bytes will be zero.
- //
- // For P/Invoke return and Reverse P/Invoke argument passing, native compiler doesn't guarantee
- // that upper 4-bytes of a Vector3 type struct is zero initialized and hence assumption 2 is
- // invalid.
- //
- // RyuJIT x64 Windows: arguments are treated as passed by ref and hence read/written just 12
- // bytes. In case of Vector3 returns, Caller allocates a zero initialized Vector3 local and
- // passes it retBuf arg and Callee method writes only 12 bytes to retBuf. For this reason,
- // there is no need to clear upper 4-bytes of Vector3 type args.
- //
- // RyuJIT x64 Unix: arguments are treated as passed by value and read/writen as if TYP_SIMD16.
- // Vector3 return values are returned two return registers and Caller assembles them into a
- // single xmm reg. Hence RyuJIT explicitly generates code to clears upper 4-bytes of Vector3
- // type args in prolog and Vector3 type return value of a call
- (*ppTree)->gtType = TYP_SIMD16;
+ // Assumption 1:
+ // RyuJit backend depends on the assumption that on 64-Bit targets Vector3 size is rounded off
+ // to TARGET_POINTER_SIZE and hence Vector3 locals on stack can be treated as TYP_SIMD16 for
+ // reading and writing purposes.
+ //
+ // Assumption 2:
+ // RyuJit backend is making another implicit assumption that Vector3 type args when passed in
+ // registers or on stack, the upper most 4-bytes will be zero.
+ //
+ // For P/Invoke return and Reverse P/Invoke argument passing, native compiler doesn't guarantee
+ // that upper 4-bytes of a Vector3 type struct is zero initialized and hence assumption 2 is
+ // invalid.
+ //
+ // RyuJIT x64 Windows: arguments are treated as passed by ref and hence read/written just 12
+ // bytes. In case of Vector3 returns, Caller allocates a zero initialized Vector3 local and
+ // passes it retBuf arg and Callee method writes only 12 bytes to retBuf. For this reason,
+ // there is no need to clear upper 4-bytes of Vector3 type args.
+ //
+ // RyuJIT x64 Unix: arguments are treated as passed by value and read/writen as if TYP_SIMD16.
+ // Vector3 return values are returned two return registers and Caller assembles them into a
+ // single xmm reg. Hence RyuJIT explicitly generates code to clears upper 4-bytes of Vector3
+ // type args in prolog and Vector3 type return value of a call
+ (*ppTree)->gtType = TYP_SIMD16;
#else
- NYI("Lowering of TYP_SIMD12 locals");
+ NYI("Lowering of TYP_SIMD12 locals");
#endif // _TARGET_64BIT_
- }
-#endif //FEATURE_SIMD
+ }
+#endif // FEATURE_SIMD
- default:
- return;
+ default:
+ return;
}
}
@@ -435,8 +433,8 @@ void Lowering::LowerSwitch(GenTreePtr* pTree)
// jumpCnt is the number of elements in the jump table array.
// jumpTab is the actual pointer to the jump table array.
// targetCnt is the number of unique targets in the jump table array.
- jumpCnt = originalSwitchBB->bbJumpSwt->bbsCount;
- jumpTab = originalSwitchBB->bbJumpSwt->bbsDstTab;
+ jumpCnt = originalSwitchBB->bbJumpSwt->bbsCount;
+ jumpTab = originalSwitchBB->bbJumpSwt->bbsDstTab;
targetCnt = originalSwitchBB->NumSucc(comp);
JITDUMP("Lowering switch BB%02u, %d cases\n", originalSwitchBB->bbNum, jumpCnt);
@@ -461,15 +459,15 @@ void Lowering::LowerSwitch(GenTreePtr* pTree)
// Remove extra predecessor links if there was more than one case.
for (unsigned i = 1; i < jumpCnt; ++i)
{
- (void) comp->fgRemoveRefPred(jumpTab[i], originalSwitchBB);
+ (void)comp->fgRemoveRefPred(jumpTab[i], originalSwitchBB);
}
- // We have to get rid of the GT_SWITCH node but a child might have side effects so just assign
+ // We have to get rid of the GT_SWITCH node but a child might have side effects so just assign
// the result of the child subtree to a temp.
GenTree* store = CreateLocalTempAsg(tree->gtOp.gtOp1, 1);
tree->InsertAfterSelf(store, comp->compCurStmt->AsStmt());
Compiler::fgSnipNode(comp->compCurStmt->AsStmt(), tree);
*pTree = store;
-
+
return;
}
@@ -481,13 +479,13 @@ void Lowering::LowerSwitch(GenTreePtr* pTree)
GenTreeStmt* asgStmt = comp->fgInsertEmbeddedFormTemp(&(tree->gtOp.gtOp1));
// GT_SWITCH(indexExpression) is now two statements:
- // 1. a statement containing 'asg' (for temp = indexExpression)
+ // 1. a statement containing 'asg' (for temp = indexExpression)
// 2. and a statement with GT_SWITCH(temp)
- // The return value of fgInsertEmbeddedFormTemp is stmt 1
+ // The return value of fgInsertEmbeddedFormTemp is stmt 1
// The 'asg' can either be a GT_ASG or a GT_STORE_LCL_VAR
// 'tree' is still a GT_SWITCH but tree->gtOp.gtOp1 is modified to be 'temp'
-
+
// The asgStmt needs to pickup the IL offsets from the current statement
//
asgStmt->gtStmtILoffsx = comp->compCurStmt->gtStmt.gtStmtILoffsx;
@@ -498,11 +496,11 @@ void Lowering::LowerSwitch(GenTreePtr* pTree)
assert(tree->gtOper == GT_SWITCH);
GenTreePtr temp = tree->gtOp.gtOp1;
assert(temp->gtOper == GT_LCL_VAR);
- unsigned tempLclNum = temp->gtLclVarCommon.gtLclNum;
- LclVarDsc * tempVarDsc = comp->lvaTable + tempLclNum;
- var_types tempLclType = tempVarDsc->TypeGet();
+ unsigned tempLclNum = temp->gtLclVarCommon.gtLclNum;
+ LclVarDsc* tempVarDsc = comp->lvaTable + tempLclNum;
+ var_types tempLclType = tempVarDsc->TypeGet();
- BasicBlock* defaultBB = jumpTab[jumpCnt - 1];
+ BasicBlock* defaultBB = jumpTab[jumpCnt - 1];
BasicBlock* followingBB = originalSwitchBB->bbNext;
/* Is the number of cases right for a test and jump switch? */
@@ -513,7 +511,9 @@ void Lowering::LowerSwitch(GenTreePtr* pTree)
// This means really just a single cmp/jcc (aka a simple if/else)
if (fFirstCaseFollows || fDefaultFollows)
+ {
minSwitchTabJumpCnt++;
+ }
#if defined(_TARGET_ARM_)
// On ARM for small switch tables we will
@@ -526,23 +526,21 @@ void Lowering::LowerSwitch(GenTreePtr* pTree)
// the default case. As stated above, this conditional is being shared between
// both GT_SWITCH lowering code paths.
// This condition is of the form: if (temp > jumpTableLength - 2){ goto jumpTable[jumpTableLength - 1]; }
- GenTreePtr gtDefaultCaseCond = comp->gtNewOperNode(GT_GT, TYP_INT,
- comp->gtNewLclvNode(tempLclNum, tempLclType),
+ GenTreePtr gtDefaultCaseCond = comp->gtNewOperNode(GT_GT, TYP_INT, comp->gtNewLclvNode(tempLclNum, tempLclType),
comp->gtNewIconNode(jumpCnt - 2, TYP_INT));
//
- // Make sure we perform an unsigned comparison, just in case the switch index in 'temp'
+ // Make sure we perform an unsigned comparison, just in case the switch index in 'temp'
// is now less than zero 0 (that would also hit the default case).
gtDefaultCaseCond->gtFlags |= GTF_UNSIGNED;
/* Increment the lvRefCnt and lvRefCntWtd for temp */
tempVarDsc->incRefCnts(originalSwitchBB->getBBWeight(comp), comp);
- GenTreePtr gtDefaultCaseJump = comp->gtNewOperNode(GT_JTRUE,
- TYP_VOID,
- gtDefaultCaseCond);
- gtDefaultCaseJump->gtFlags = tree->gtFlags;
+ GenTreePtr gtDefaultCaseJump = comp->gtNewOperNode(GT_JTRUE, TYP_VOID, gtDefaultCaseCond);
+ gtDefaultCaseJump->gtFlags = tree->gtFlags;
- GenTreePtr condStmt = comp->fgNewStmtFromTree(gtDefaultCaseJump, originalSwitchBB, comp->compCurStmt->gtStmt.gtStmtILoffsx);
+ GenTreePtr condStmt =
+ comp->fgNewStmtFromTree(gtDefaultCaseJump, originalSwitchBB, comp->compCurStmt->gtStmt.gtStmtILoffsx);
#ifdef DEBUG
condStmt->gtStmt.gtStmtLastILoffs = comp->compCurStmt->gtStmt.gtStmtLastILoffs;
@@ -598,7 +596,7 @@ void Lowering::LowerSwitch(GenTreePtr* pTree)
for (unsigned i = 1; i < jumpCnt - 1; ++i)
{
assert(jumpTab[i] == uniqueSucc);
- (void) comp->fgRemoveRefPred(uniqueSucc, afterDefCondBlock);
+ (void)comp->fgRemoveRefPred(uniqueSucc, afterDefCondBlock);
}
if (afterDefCondBlock->bbNext == uniqueSucc)
{
@@ -629,8 +627,8 @@ void Lowering::LowerSwitch(GenTreePtr* pTree)
// We'll use 'afterDefCondBlock' for the first conditional. After that, we'll add new
// blocks. If we end up not needing it at all (say, if all the non-default cases just fall through),
// we'll delete it.
- bool fUsedAfterDefCondBlock = false;
- BasicBlock* currentBlock = afterDefCondBlock;
+ bool fUsedAfterDefCondBlock = false;
+ BasicBlock* currentBlock = afterDefCondBlock;
// Walk to entries 0 to jumpCnt - 1. If a case target follows, ignore it and let it fall through.
// If no case target follows, the last one doesn't need to be a compare/branch: it can be an
@@ -694,14 +692,14 @@ void Lowering::LowerSwitch(GenTreePtr* pTree)
// |____GT_EQ
// |____ (switchIndex) (The temp variable)
// |____ (ICon) (The actual case constant)
- GenTreePtr gtCaseCond = comp->gtNewOperNode(GT_EQ, TYP_INT,
- comp->gtNewLclvNode(tempLclNum, tempLclType),
- comp->gtNewIconNode(i, TYP_INT));
+ GenTreePtr gtCaseCond =
+ comp->gtNewOperNode(GT_EQ, TYP_INT, comp->gtNewLclvNode(tempLclNum, tempLclType),
+ comp->gtNewIconNode(i, TYP_INT));
/* Increment the lvRefCnt and lvRefCntWtd for temp */
tempVarDsc->incRefCnts(originalSwitchBB->getBBWeight(comp), comp);
GenTreePtr gtCaseBranch = comp->gtNewOperNode(GT_JTRUE, TYP_VOID, gtCaseCond);
- GenTreePtr gtCaseStmt = comp->fgNewStmtFromTree(gtCaseBranch, currentBlock);
+ GenTreePtr gtCaseStmt = comp->fgNewStmtFromTree(gtCaseBranch, currentBlock);
comp->fgInsertStmtAtEnd(currentBlock, gtCaseStmt);
}
}
@@ -742,10 +740,9 @@ void Lowering::LowerSwitch(GenTreePtr* pTree)
JITDUMP("Lowering switch BB%02u: using jump table expansion\n", originalSwitchBB->bbNum);
- GenTreePtr gtTableSwitch = comp->gtNewOperNode(GT_SWITCH_TABLE,
- TYP_VOID,
- comp->gtNewLclvNode(tempLclNum, tempLclType),
- comp->gtNewJmpTableNode());
+ GenTreePtr gtTableSwitch =
+ comp->gtNewOperNode(GT_SWITCH_TABLE, TYP_VOID, comp->gtNewLclvNode(tempLclNum, tempLclType),
+ comp->gtNewJmpTableNode());
/* Increment the lvRefCnt and lvRefCntWtd for temp */
tempVarDsc->incRefCnts(originalSwitchBB->getBBWeight(comp), comp);
@@ -787,7 +784,7 @@ void Lowering::SpliceInUnary(GenTreePtr parent, GenTreePtr* ppChild, GenTreePtr
GenTreePtr oldChild = *ppChild;
// Replace tree in the parent node
- *ppChild = newNode;
+ *ppChild = newNode;
newNode->gtOp.gtOp1 = oldChild;
oldChild->InsertAfterSelf(newNode);
@@ -814,8 +811,8 @@ void Lowering::SpliceInUnary(GenTreePtr parent, GenTreePtr* ppChild, GenTreePtr
// this method allocates a single GT_PUTARG_REG for 1 eightbyte structs and a GT_LIST of two GT_PUTARG_REGs
// for two eightbyte structs.
//
-// For STK passed structs the method generates GT_PUTARG_STK tree. For System V systems with native struct passing
-// (i.e. FEATURE_UNIX_AMD64_STRUCT_PASSING defined) this method also sets the GP pointers count and the pointers
+// For STK passed structs the method generates GT_PUTARG_STK tree. For System V systems with native struct passing
+// (i.e. FEATURE_UNIX_AMD64_STRUCT_PASSING defined) this method also sets the GP pointers count and the pointers
// layout object, so the codegen of the GT_PUTARG_STK could use this for optimizing copying to the stack by value.
// (using block copy primitives for non GC pointers and a single TARGET_POINTER_SIZE copy with recording GC info.)
//
@@ -825,8 +822,8 @@ GenTreePtr Lowering::NewPutArg(GenTreeCall* call, GenTreePtr arg, fgArgTabEntryP
assert(arg != nullptr);
assert(info != nullptr);
- GenTreePtr putArg = nullptr;
- bool updateArgTable = true;
+ GenTreePtr putArg = nullptr;
+ bool updateArgTable = true;
#if !defined(_TARGET_64BIT_)
if (varTypeIsLong(type))
@@ -834,11 +831,11 @@ GenTreePtr Lowering::NewPutArg(GenTreeCall* call, GenTreePtr arg, fgArgTabEntryP
// For TYP_LONG, we leave the GT_LONG as the arg, and put the putArg below it.
// Therefore, we don't update the arg table entry.
updateArgTable = false;
- type = TYP_INT;
+ type = TYP_INT;
}
#endif // !defined(_TARGET_64BIT_)
- bool isOnStack = true;
+ bool isOnStack = true;
#ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
if (varTypeIsStruct(type))
{
@@ -848,8 +845,8 @@ GenTreePtr Lowering::NewPutArg(GenTreeCall* call, GenTreePtr arg, fgArgTabEntryP
{
isOnStack = info->regNum == REG_STK;
}
-#else // !FEATURE_UNIX_AMD64_STRUCT_PASSING
- isOnStack = info->regNum == REG_STK;
+#else // !FEATURE_UNIX_AMD64_STRUCT_PASSING
+ isOnStack = info->regNum == REG_STK;
#endif // !FEATURE_UNIX_AMD64_STRUCT_PASSING
if (!isOnStack)
@@ -860,7 +857,7 @@ GenTreePtr Lowering::NewPutArg(GenTreeCall* call, GenTreePtr arg, fgArgTabEntryP
{
type = TYP_LONG;
}
-#endif //FEATURE_SIMD
+#endif // FEATURE_SIMD
#if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
if (info->isStruct)
@@ -953,7 +950,8 @@ GenTreePtr Lowering::NewPutArg(GenTreeCall* call, GenTreePtr arg, fgArgTabEntryP
// Create a new GT_PUTARG_REG node with op1 the original GT_LCL_FLD.
GenTreePtr newOper = comp->gtNewOperNode(
GT_PUTARG_REG,
- comp->GetTypeFromClassificationAndSizes(info->structDesc.eightByteClassifications[ctr], info->structDesc.eightByteSizes[ctr]),
+ comp->GetTypeFromClassificationAndSizes(info->structDesc.eightByteClassifications[ctr],
+ info->structDesc.eightByteSizes[ctr]),
argListPtr->gtOp.gtOp1);
// CopyCosts
@@ -969,13 +967,13 @@ GenTreePtr Lowering::NewPutArg(GenTreeCall* call, GenTreePtr arg, fgArgTabEntryP
}
else
{
- assert(false && "Illegal count of eightbytes for the CLR type system"); // No more than 2 eightbytes for the CLR.
-
+ assert(false &&
+ "Illegal count of eightbytes for the CLR type system"); // No more than 2 eightbytes for the CLR.
}
}
else
#else // not defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
-#if FEATURE_MULTIREG_ARGS
+#if FEATURE_MULTIREG_ARGS
if ((info->numRegs > 1) && (arg->OperGet() == GT_LIST))
{
assert(arg->OperGet() == GT_LIST);
@@ -986,7 +984,7 @@ GenTreePtr Lowering::NewPutArg(GenTreeCall* call, GenTreePtr arg, fgArgTabEntryP
GenTreePtr curOp = argListPtr->gtOp.gtOp1;
var_types curTyp = curOp->TypeGet();
- // Create a new GT_PUTARG_REG node with op1
+ // Create a new GT_PUTARG_REG node with op1
GenTreePtr newOper = comp->gtNewOperNode(GT_PUTARG_REG, curTyp, curOp);
// CopyCosts
@@ -1001,7 +999,7 @@ GenTreePtr Lowering::NewPutArg(GenTreeCall* call, GenTreePtr arg, fgArgTabEntryP
return arg;
}
else
-#endif // FEATURE_MULTIREG_ARGS
+#endif // FEATURE_MULTIREG_ARGS
#endif // not defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
{
putArg = comp->gtNewOperNode(GT_PUTARG_REG, type, arg);
@@ -1010,42 +1008,37 @@ GenTreePtr Lowering::NewPutArg(GenTreeCall* call, GenTreePtr arg, fgArgTabEntryP
else
{
// Mark this one as tail call arg if it is a fast tail call.
- // This provides the info to put this argument in in-coming arg area slot
+ // This provides the info to put this argument in in-coming arg area slot
// instead of in out-going arg area slot.
- FEATURE_UNIX_AMD64_STRUCT_PASSING_ONLY(assert(info->isStruct == varTypeIsStruct(type))); // Make sure state is correct
+ FEATURE_UNIX_AMD64_STRUCT_PASSING_ONLY(assert(info->isStruct == varTypeIsStruct(type))); // Make sure state is
+ // correct
#if FEATURE_FASTTAILCALL
- putArg = new (comp, GT_PUTARG_STK) GenTreePutArgStk(GT_PUTARG_STK,
- type,
- arg,
- info->slotNum
- FEATURE_UNIX_AMD64_STRUCT_PASSING_ONLY_ARG(info->numSlots)
- FEATURE_UNIX_AMD64_STRUCT_PASSING_ONLY_ARG(info->isStruct),
- call->IsFastTailCall()
- DEBUGARG(call));
+ putArg = new (comp, GT_PUTARG_STK)
+ GenTreePutArgStk(GT_PUTARG_STK, type, arg,
+ info->slotNum FEATURE_UNIX_AMD64_STRUCT_PASSING_ONLY_ARG(info->numSlots)
+ FEATURE_UNIX_AMD64_STRUCT_PASSING_ONLY_ARG(info->isStruct),
+ call->IsFastTailCall() DEBUGARG(call));
#else
- putArg = new (comp, GT_PUTARG_STK) GenTreePutArgStk(GT_PUTARG_STK,
- type,
- arg,
- info->slotNum
- FEATURE_UNIX_AMD64_STRUCT_PASSING_ONLY_ARG(info->numSlots)
- FEATURE_UNIX_AMD64_STRUCT_PASSING_ONLY_ARG(info->isStruct)
- DEBUGARG(call));
+ putArg = new (comp, GT_PUTARG_STK)
+ GenTreePutArgStk(GT_PUTARG_STK, type, arg,
+ info->slotNum FEATURE_UNIX_AMD64_STRUCT_PASSING_ONLY_ARG(info->numSlots)
+ FEATURE_UNIX_AMD64_STRUCT_PASSING_ONLY_ARG(info->isStruct) DEBUGARG(call));
#endif
#ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
// If the ArgTabEntry indicates that this arg is a struct
// get and store the number of slots that are references.
// This is later used in the codegen for PUT_ARG_STK implementation
- // for struct to decide whether and how many single eight-byte copies
+ // for struct to decide whether and how many single eight-byte copies
// to be done (only for reference slots), so gcinfo is emitted.
- // For non-reference slots faster/smaller size instructions are used -
+ // For non-reference slots faster/smaller size instructions are used -
// pair copying using XMM registers or rep mov instructions.
if (info->isStruct)
{
- unsigned numRefs = 0;
- BYTE* gcLayout = new (comp, CMK_Codegen) BYTE[info->numSlots];
+ unsigned numRefs = 0;
+ BYTE* gcLayout = new (comp, CMK_Codegen) BYTE[info->numSlots];
// We use GT_OBJ for non-SIMD struct arguments. However, for
// SIMD arguments the GT_OBJ has already been transformed.
if (arg->gtOper != GT_OBJ)
@@ -1111,20 +1104,16 @@ void Lowering::LowerArg(GenTreeCall* call, GenTreePtr* ppArg)
// assignments/stores at this level are not really placing an arg
// they are setting up temporary locals that will later be placed into
// outgoing regs or stack
- if (
- !arg->OperIsAssignment() &&
- !arg->OperIsStore() &&
- !arg->IsArgPlaceHolderNode() &&
- !arg->IsNothingNode() &&
+ if (!arg->OperIsAssignment() && !arg->OperIsStore() && !arg->IsArgPlaceHolderNode() && !arg->IsNothingNode() &&
#ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
- !arg->OperIsPutArgStk() &&
-#endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
+ !arg->OperIsPutArgStk() &&
+#endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
!arg->OperIsCopyBlkOp()) // these are de facto placeholders (apparently)
{
fgArgTabEntryPtr info = comp->gtArgEntryByNode(call, arg);
assert(info->node == arg);
- bool isReg = (info->regNum != REG_STK);
- var_types type = arg->TypeGet();
+ bool isReg = (info->regNum != REG_STK);
+ var_types type = arg->TypeGet();
if (varTypeIsSmall(type))
{
@@ -1152,11 +1141,9 @@ void Lowering::LowerArg(GenTreeCall* call, GenTreePtr* ppArg)
GenTreePtr argLo = arg->gtGetOp1();
GenTreePtr argHi = arg->gtGetOp2();
- NYI_IF((argHi->OperGet() == GT_ADD_HI) ||
- (argHi->OperGet() == GT_SUB_HI) ||
- (argHi->OperGet() == GT_NEG),
+ NYI_IF((argHi->OperGet() == GT_ADD_HI) || (argHi->OperGet() == GT_SUB_HI) || (argHi->OperGet() == GT_NEG),
"Hi and Lo cannot be reordered");
-
+
GenTreePtr putArgLo = NewPutArg(call, argLo, info, type);
GenTreePtr putArgHi = NewPutArg(call, argHi, info, type);
@@ -1167,7 +1154,7 @@ void Lowering::LowerArg(GenTreeCall* call, GenTreePtr* ppArg)
GenTreePtr argLoFirst = comp->fgGetFirstNode(argLo);
GenTreePtr argHiFirst = comp->fgGetFirstNode(argHi);
- GenTreePtr argLoPrev = argLoFirst->gtPrev;
+ GenTreePtr argLoPrev = argLoFirst->gtPrev;
noway_assert(argHiFirst->gtPrev == argLo);
noway_assert(arg->gtPrev == argHi);
@@ -1181,14 +1168,14 @@ void Lowering::LowerArg(GenTreeCall* call, GenTreePtr* ppArg)
assert(comp->compCurStmt->gtStmt.gtStmtList == argLoFirst);
comp->compCurStmt->gtStmt.gtStmtList = argHiFirst;
}
- argHi->gtNext = putArgHi;
- putArgHi->gtPrev = argHi;
- putArgHi->gtNext = argLoFirst;
+ argHi->gtNext = putArgHi;
+ putArgHi->gtPrev = argHi;
+ putArgHi->gtNext = argLoFirst;
argLoFirst->gtPrev = putArgHi;
- argLo->gtNext = putArgLo;
- putArgLo->gtPrev = argLo;
- putArgLo->gtNext = arg;
- arg->gtPrev = putArgLo;
+ argLo->gtNext = putArgLo;
+ putArgLo->gtPrev = argLo;
+ putArgLo->gtNext = arg;
+ arg->gtPrev = putArgLo;
assert((arg->gtFlags & GTF_REVERSE_OPS) == 0);
arg->gtFlags |= GTF_REVERSE_OPS;
@@ -1202,15 +1189,15 @@ void Lowering::LowerArg(GenTreeCall* call, GenTreePtr* ppArg)
// Insert a copy to move float value to integer register.
if (call->IsVarargs() && varTypeIsFloating(type))
{
- var_types intType = (type == TYP_DOUBLE) ? TYP_LONG : TYP_INT;
- GenTreePtr intArg = comp->gtNewOperNode(GT_COPY, intType, arg);
+ var_types intType = (type == TYP_DOUBLE) ? TYP_LONG : TYP_INT;
+ GenTreePtr intArg = comp->gtNewOperNode(GT_COPY, intType, arg);
intArg->CopyCosts(arg);
info->node = intArg;
SpliceInUnary(call, ppArg, intArg);
// Update arg/type with new ones.
- arg = intArg;
+ arg = intArg;
type = intType;
}
#endif
@@ -1257,7 +1244,7 @@ void Lowering::LowerArgsForCall(GenTreeCall* call)
// (optionally specifying the register to place it in)
GenTree* Lowering::AddrGen(ssize_t addr, regNumber reg)
{
- //this should end up in codegen as : instGen_Set_Reg_To_Imm(EA_HANDLE_CNS_RELOC, reg, addr)
+ // this should end up in codegen as : instGen_Set_Reg_To_Imm(EA_HANDLE_CNS_RELOC, reg, addr)
GenTree* result = comp->gtNewIconHandleNode(addr, GTF_ICON_FTN_ADDR);
result->gtRegNum = reg;
@@ -1274,7 +1261,7 @@ GenTree* Lowering::AddrGen(void* addr, regNumber reg)
// do some common operations on trees before they are inserted as top level statements
GenTreeStmt* Lowering::LowerMorphAndSeqTree(GenTree* tree)
{
- tree = comp->fgMorphTree(tree);
+ tree = comp->fgMorphTree(tree);
GenTreeStmt* stmt = comp->fgNewStmtFromTree(tree);
return stmt;
}
@@ -1288,14 +1275,14 @@ GenTreeStmt* Lowering::LowerMorphAndSeqTree(GenTree* tree)
//
void Lowering::LowerCall(GenTree* node)
{
- GenTreeCall* call = node->AsCall();
+ GenTreeCall* call = node->AsCall();
GenTreeStmt* callStmt = comp->compCurStmt->AsStmt();
assert(comp->fgTreeIsInStmt(call, callStmt));
JITDUMP("lowering call (before):\n");
DISPTREE(call);
JITDUMP("\n");
-
+
LowerArgsForCall(call);
// RyuJIT arm is not set up for lowered call control
@@ -1318,33 +1305,33 @@ void Lowering::LowerCall(GenTree* node)
// Virtual and interface calls
switch (call->gtFlags & GTF_CALL_VIRT_KIND_MASK)
{
- case GTF_CALL_VIRT_STUB:
- result = LowerVirtualStubCall(call);
- break;
+ case GTF_CALL_VIRT_STUB:
+ result = LowerVirtualStubCall(call);
+ break;
- case GTF_CALL_VIRT_VTABLE:
- // stub dispatching is off or this is not a virtual call (could be a tailcall)
- result = LowerVirtualVtableCall(call);
- break;
+ case GTF_CALL_VIRT_VTABLE:
+ // stub dispatching is off or this is not a virtual call (could be a tailcall)
+ result = LowerVirtualVtableCall(call);
+ break;
- case GTF_CALL_NONVIRT:
- if (call->IsUnmanaged())
- {
- result = LowerNonvirtPinvokeCall(call);
- }
- else if (call->gtCallType == CT_INDIRECT)
- {
- result = LowerIndirectNonvirtCall(call);
- }
- else
- {
- result = LowerDirectCall(call);
- }
- break;
+ case GTF_CALL_NONVIRT:
+ if (call->IsUnmanaged())
+ {
+ result = LowerNonvirtPinvokeCall(call);
+ }
+ else if (call->gtCallType == CT_INDIRECT)
+ {
+ result = LowerIndirectNonvirtCall(call);
+ }
+ else
+ {
+ result = LowerDirectCall(call);
+ }
+ break;
- default:
- noway_assert(!"strange call type");
- break;
+ default:
+ noway_assert(!"strange call type");
+ break;
}
}
@@ -1361,7 +1348,7 @@ void Lowering::LowerCall(GenTree* node)
JITDUMP("results of lowering call:\n");
DISPTREE(result);
}
-
+
if (call->IsTailCallViaHelper())
{
// Either controlExpr or gtCallAddr must contain real call target.
@@ -1379,20 +1366,20 @@ void Lowering::LowerCall(GenTree* node)
comp->gtSetEvalOrder(result);
comp->fgSetTreeSeq(result, nullptr);
JITDUMP("results of lowering tail call via helper:\n");
- DISPTREE(result);
+ DISPTREE(result);
}
}
else if (call->IsFastTailCall())
{
LowerFastTailCall(call);
}
-
+
if (result)
- {
+ {
GenTree* insertionPoint = call;
if (!call->IsTailCallViaHelper())
- {
- // The controlExpr should go before the gtCallCookie and the gtCallAddr, if they exist
+ {
+ // The controlExpr should go before the gtCallCookie and the gtCallAddr, if they exist
if (call->gtCallType == CT_INDIRECT)
{
if (call->gtCallCookie != nullptr)
@@ -1425,18 +1412,18 @@ void Lowering::LowerCall(GenTree* node)
JITDUMP("\n");
}
-// Though the below described issue gets fixed in intellitrace dll of VS2015 (a.k.a Dev14),
+// Though the below described issue gets fixed in intellitrace dll of VS2015 (a.k.a Dev14),
// we still need this quirk for desktop so that older version of VS (e.g. VS2010/2012)
// continues to work.
// This quirk is excluded from other targets that have no back compat burden.
//
-// Quirk for VS debug-launch scenario to work:
+// Quirk for VS debug-launch scenario to work:
// See if this is a PInvoke call with exactly one param that is the address of a struct local.
// In such a case indicate to frame-layout logic to add 16-bytes of padding
// between save-reg area and locals. This is to protect against the buffer
-// overrun bug in microsoft.intellitrace.11.0.0.dll!ProfilerInterop.InitInterop().
+// overrun bug in microsoft.intellitrace.11.0.0.dll!ProfilerInterop.InitInterop().
//
-// A work-around to this bug is to disable IntelliTrace debugging
+// A work-around to this bug is to disable IntelliTrace debugging
// (VS->Tools->Options->IntelliTrace->Enable IntelliTrace - uncheck this option).
// The reason why this works on Jit64 is that at the point of AV the call stack is
//
@@ -1460,14 +1447,14 @@ void Lowering::LowerCall(GenTree* node)
//
// Due to buffer overrun, rbx doesn't get impacted. Whereas RyuJIT jitted code of
// the same method is pushing regs in the following order
-//
+//
// rbp
// rdi
// rsi
// rbx
// struct local
//
-// Therefore as a fix, we add padding between save-reg area and locals to
+// Therefore as a fix, we add padding between save-reg area and locals to
// make this scenario work against JB.
//
// Note: If this quirk gets broken due to other JIT optimizations, we should consider
@@ -1480,7 +1467,7 @@ void Lowering::CheckVSQuirkStackPaddingNeeded(GenTreeCall* call)
// Confine this to IL stub calls which aren't marked as unmanaged.
if (call->IsPInvoke() && !call->IsUnmanaged())
{
- bool paddingNeeded = false;
+ bool paddingNeeded = false;
GenTreePtr firstPutArgReg = nullptr;
for (GenTreeArgList* args = call->gtCallLateArgs; args; args = args->Rest())
{
@@ -1488,7 +1475,7 @@ void Lowering::CheckVSQuirkStackPaddingNeeded(GenTreeCall* call)
if (tmp->OperGet() == GT_PUTARG_REG)
{
if (firstPutArgReg == nullptr)
- {
+ {
firstPutArgReg = tmp;
GenTreePtr op1 = firstPutArgReg->gtOp.gtOp1;
@@ -1504,7 +1491,7 @@ void Lowering::CheckVSQuirkStackPaddingNeeded(GenTreeCall* call)
// First arg is addr of a struct local.
paddingNeeded = true;
}
- else
+ else
{
// Not a struct local.
assert(paddingNeeded == false);
@@ -1540,7 +1527,7 @@ void Lowering::CheckVSQuirkStackPaddingNeeded(GenTreeCall* call)
// We need to insert this after all nested calls, but before all the arguments to this call have been set up.
// To do this, we look for the first GT_PUTARG_STK or GT_PUTARG_REG, and insert the hook immediately before
// that. If there are no args, then it should be inserted before the call node.
-//
+//
// For example:
// * stmtExpr void (top level) (IL 0x000...0x010)
// arg0 SETUP | /--* argPlace ref REG NA $c5
@@ -1557,7 +1544,7 @@ void Lowering::CheckVSQuirkStackPaddingNeeded(GenTreeCall* call)
// arg0 in rcx | +--* putarg_reg ref REG NA
// control expr | +--* const(h) long 0x7ffe8e910e98 ftn REG NA
// \--* call void System.Runtime.Remoting.Identity.RemoveAppNameOrAppGuidIfNecessary $VN.Void
-//
+//
// In this case, the GT_PUTARG_REG src is a nested call. We need to put the embedded statement after that call
// (as shown). We assume that of all the GT_PUTARG_*, only the first one can have a nested call.
//
@@ -1566,7 +1553,7 @@ void Lowering::CheckVSQuirkStackPaddingNeeded(GenTreeCall* call)
// insertionPoint - if caller has an insertion point; If null
// profiler hook is inserted before args are setup
// but after all arg side effects are computed.
-void Lowering::InsertProfTailCallHook(GenTreeCall* call, GenTree *insertionPoint)
+void Lowering::InsertProfTailCallHook(GenTreeCall* call, GenTree* insertionPoint)
{
assert(call->IsTailCall());
assert(comp->compIsProfilerHookNeeded());
@@ -1608,24 +1595,24 @@ void Lowering::InsertProfTailCallHook(GenTreeCall* call, GenTree *insertionPoin
}
assert(insertionPoint != nullptr);
- GenTreeStmt* callStmt = comp->compCurStmt->AsStmt();
- GenTreePtr profHookNode = new (comp, GT_PROF_HOOK) GenTree(GT_PROF_HOOK, TYP_VOID);
+ GenTreeStmt* callStmt = comp->compCurStmt->AsStmt();
+ GenTreePtr profHookNode = new (comp, GT_PROF_HOOK) GenTree(GT_PROF_HOOK, TYP_VOID);
comp->fgInsertTreeBeforeAsEmbedded(profHookNode, insertionPoint, callStmt, comp->compCurBB);
}
// Lower fast tail call implemented as epilog+jmp.
// Also inserts PInvoke method epilog if required.
-void Lowering::LowerFastTailCall(GenTreeCall *call)
+void Lowering::LowerFastTailCall(GenTreeCall* call)
{
#if FEATURE_FASTTAILCALL
// Tail call restrictions i.e. conditions under which tail prefix is ignored.
// Most of these checks are already done by importer or fgMorphTailCall().
// This serves as a double sanity check.
- assert((comp->info.compFlags & CORINFO_FLG_SYNCH) == 0); // tail calls from synchronized methods
- assert(!comp->opts.compNeedSecurityCheck); // tail call from methods that need security check
- assert(!call->IsUnmanaged()); // tail calls to unamanaged methods
- assert(!comp->compLocallocUsed); // tail call from methods that also do localloc
- assert(!comp->getNeedsGSSecurityCookie()); // jit64 compat: tail calls from methods that need GS check
+ assert((comp->info.compFlags & CORINFO_FLG_SYNCH) == 0); // tail calls from synchronized methods
+ assert(!comp->opts.compNeedSecurityCheck); // tail call from methods that need security check
+ assert(!call->IsUnmanaged()); // tail calls to unamanaged methods
+ assert(!comp->compLocallocUsed); // tail call from methods that also do localloc
+ assert(!comp->getNeedsGSSecurityCookie()); // jit64 compat: tail calls from methods that need GS check
// We expect to see a call that meets the following conditions
assert(call->IsFastTailCall());
@@ -1634,14 +1621,14 @@ void Lowering::LowerFastTailCall(GenTreeCall *call)
// other in mutual recursion. Therefore, this block is reachable through
// a GC-safe point or the whole method is marked as fully interruptible.
//
- // TODO-Cleanup:
+ // TODO-Cleanup:
// optReachWithoutCall() depends on the fact that loop headers blocks
// will have a block number > fgLastBB. These loop headers gets added
// after dominator computation and get skipped by OptReachWithoutCall().
- // The below condition cannot be asserted in lower because fgSimpleLowering()
+ // The below condition cannot be asserted in lower because fgSimpleLowering()
// can add a new basic block for range check failure which becomes
// fgLastBB with block number > loop header block number.
- // assert((comp->compCurBB->bbFlags & BBF_GC_SAFE_POINT) ||
+ // assert((comp->compCurBB->bbFlags & BBF_GC_SAFE_POINT) ||
// !comp->optReachWithoutCall(comp->fgFirstBB, comp->compCurBB) || comp->genInterruptible);
// If PInvokes are in-lined, we have to remember to execute PInvoke method epilog anywhere that
@@ -1653,37 +1640,43 @@ void Lowering::LowerFastTailCall(GenTreeCall *call)
// Args for tail call are setup in incoming arg area. The gc-ness of args of
// caller and callee (which being tail called) may not match. Therefore, everything
- // from arg setup until the epilog need to be non-interuptible by GC. This is
+ // from arg setup until the epilog need to be non-interuptible by GC. This is
// achieved by inserting GT_START_NONGC before the very first GT_PUTARG_STK node
// of call is setup. Note that once a stack arg is setup, it cannot have nested
// calls subsequently in execution order to setup other args, because the nested
- // call could over-write the stack arg that is setup earlier.
- GenTreePtr firstPutArgStk = nullptr;
- GenTreeArgList* args;
+ // call could over-write the stack arg that is setup earlier.
+ GenTreePtr firstPutArgStk = nullptr;
+ GenTreeArgList* args;
ArrayStack<GenTree*> putargs(comp);
for (args = call->gtCallArgs; args; args = args->Rest())
{
GenTreePtr tmp = args->Current();
if (tmp->OperGet() == GT_PUTARG_STK)
+ {
putargs.Push(tmp);
+ }
}
for (args = call->gtCallLateArgs; args; args = args->Rest())
{
GenTreePtr tmp = args->Current();
if (tmp->OperGet() == GT_PUTARG_STK)
+ {
putargs.Push(tmp);
+ }
}
if (putargs.Height() > 0)
+ {
firstPutArgStk = putargs.Bottom();
+ }
// If we have a putarg_stk node, also count the number of non-standard args the
// call node has. Note that while determining whether a tail call can be fast
// tail called, we don't count non-standard args (passed in R10 or R11) since they
// don't contribute to outgoing arg space. These non-standard args are not
- // accounted in caller's arg count but accounted in callee's arg count after
+ // accounted in caller's arg count but accounted in callee's arg count after
// fgMorphArgs(). Therefore, exclude callee's non-standard args while mapping
// callee's stack arg num to corresponding caller's stack arg num.
unsigned calleeNonStandardArgCount = call->GetNonStandardAddedArgCount(comp);
@@ -1691,9 +1684,9 @@ void Lowering::LowerFastTailCall(GenTreeCall *call)
// Say Caller(a, b, c, d, e) fast tail calls Callee(e, d, c, b, a)
// i.e. passes its arguments in reverse to Callee. During call site
// setup, after computing argument side effects, stack args are setup
- // first and reg args next. In the above example, both Callers and
+ // first and reg args next. In the above example, both Callers and
// Callee stack args (e and a respectively) share the same stack slot
- // and are alive at the same time. The act of setting up Callee's
+ // and are alive at the same time. The act of setting up Callee's
// stack arg will over-write the stack arg of Caller and if there are
// further uses of Caller stack arg we have to make sure that we move
// it to a temp before over-writing its slot and use temp in place of
@@ -1713,15 +1706,15 @@ void Lowering::LowerFastTailCall(GenTreeCall *call)
{
GenTreePtr putArgStkNode = putargs.Bottom(i);
- assert(putArgStkNode->OperGet() == GT_PUTARG_STK);
-
+ assert(putArgStkNode->OperGet() == GT_PUTARG_STK);
+
// Get the caller arg num corresponding to this callee arg.
// Note that these two args share the same stack slot. Therefore,
// if there are further uses of corresponding caller arg, we need
// to move it to a temp and use the temp in this call tree.
//
// Note that Caller is guaranteed to have a param corresponding to
- // this Callee's arg since fast tail call mechanism counts the
+ // this Callee's arg since fast tail call mechanism counts the
// stack slots required for both Caller and Callee for passing params
// and allow fast tail call only if stack slots required by Caller >=
// Callee.
@@ -1730,27 +1723,28 @@ void Lowering::LowerFastTailCall(GenTreeCall *call)
unsigned callerArgNum = argTabEntry->argNum - calleeNonStandardArgCount;
noway_assert(callerArgNum < comp->info.compArgsCount);
- unsigned callerArgLclNum = callerArgNum;
- LclVarDsc* callerArgDsc = comp->lvaTable + callerArgLclNum;
+ unsigned callerArgLclNum = callerArgNum;
+ LclVarDsc* callerArgDsc = comp->lvaTable + callerArgLclNum;
if (callerArgDsc->lvPromoted)
{
- callerArgLclNum = callerArgDsc->lvFieldLclStart; // update the callerArgNum to the promoted struct field's lclNum
+ callerArgLclNum =
+ callerArgDsc->lvFieldLclStart; // update the callerArgNum to the promoted struct field's lclNum
callerArgDsc = comp->lvaTable + callerArgLclNum;
}
noway_assert(callerArgDsc->lvIsParam);
// Start searching in execution order list till we encounter call node
- unsigned tmpLclNum = BAD_VAR_NUM;
- var_types tmpType = TYP_UNDEF;
+ unsigned tmpLclNum = BAD_VAR_NUM;
+ var_types tmpType = TYP_UNDEF;
for (GenTreePtr treeNode = putArgStkNode->gtNext; treeNode != call; treeNode = treeNode->gtNext)
- {
+ {
if (treeNode->OperIsLocal() || treeNode->OperIsLocalAddr())
- {
+ {
// This should neither be a GT_REG_VAR nor GT_PHI_ARG.
assert((treeNode->OperGet() != GT_REG_VAR) && (treeNode->OperGet() != GT_PHI_ARG));
- GenTreeLclVarCommon *lcl = treeNode->AsLclVarCommon();
- LclVarDsc* lclVar = &comp->lvaTable[lcl->gtLclNum];
+ GenTreeLclVarCommon* lcl = treeNode->AsLclVarCommon();
+ LclVarDsc* lclVar = &comp->lvaTable[lcl->gtLclNum];
// Fast tail calling criteria permits passing of structs of size 1, 2, 4 and 8 as args.
// It is possible that the callerArgLclNum corresponds to such a struct whose stack slot
@@ -1762,17 +1756,17 @@ void Lowering::LowerFastTailCall(GenTreeCall *call)
// Create tmp and use it in place of callerArgDsc
if (tmpLclNum == BAD_VAR_NUM)
{
- tmpLclNum = comp->lvaGrabTemp(true DEBUGARG("Fast tail call lowering is creating a new local variable"));
- comp->lvaSortAgain = true;
- tmpType = genActualType(callerArgDsc->lvaArgType());
- comp->lvaTable[tmpLclNum].lvType = tmpType;
+ tmpLclNum = comp->lvaGrabTemp(
+ true DEBUGARG("Fast tail call lowering is creating a new local variable"));
+ comp->lvaSortAgain = true;
+ tmpType = genActualType(callerArgDsc->lvaArgType());
+ comp->lvaTable[tmpLclNum].lvType = tmpType;
comp->lvaTable[tmpLclNum].lvRefCnt = 1;
}
lcl->SetLclNum(tmpLclNum);
lcl->SetOper(GT_LCL_VAR);
-
- }
+ }
}
}
@@ -1782,23 +1776,24 @@ void Lowering::LowerFastTailCall(GenTreeCall *call)
if (tmpLclNum != BAD_VAR_NUM)
{
assert(tmpType != TYP_UNDEF);
- GenTreeLclVar* local = new(comp, GT_LCL_VAR) GenTreeLclVar(GT_LCL_VAR, tmpType, callerArgLclNum, BAD_IL_OFFSET);
+ GenTreeLclVar* local =
+ new (comp, GT_LCL_VAR) GenTreeLclVar(GT_LCL_VAR, tmpType, callerArgLclNum, BAD_IL_OFFSET);
GenTree* assignExpr = comp->gtNewTempAssign(tmpLclNum, local);
comp->fgInsertTreeBeforeAsEmbedded(assignExpr, firstPutArgStk, callStmt, comp->compCurBB);
}
}
// Insert GT_START_NONGC node before the first GT_PUTARG_STK node.
- // Note that if there are no args to be setup on stack, no need to
- // insert GT_START_NONGC node.
+ // Note that if there are no args to be setup on stack, no need to
+ // insert GT_START_NONGC node.
GenTreePtr startNonGCNode = nullptr;
if (firstPutArgStk != nullptr)
- {
- startNonGCNode = new (comp, GT_START_NONGC) GenTree(GT_START_NONGC, TYP_VOID);
+ {
+ startNonGCNode = new (comp, GT_START_NONGC) GenTree(GT_START_NONGC, TYP_VOID);
comp->fgInsertTreeBeforeAsEmbedded(startNonGCNode, firstPutArgStk, callStmt, comp->compCurBB);
// Gc-interruptability in the following case:
- // foo(a, b, c, d, e) { bar(a, b, c, d, e); }
+ // foo(a, b, c, d, e) { bar(a, b, c, d, e); }
// bar(a, b, c, d, e) { foo(a, b, d, d, e); }
//
// Since the instruction group starting from the instruction that sets up first
@@ -1824,7 +1819,7 @@ void Lowering::LowerFastTailCall(GenTreeCall *call)
InsertProfTailCallHook(call, startNonGCNode);
}
-#else // !FEATURE_FASTTAILCALL
+#else // !FEATURE_FASTTAILCALL
// Platform choose not to implement fast tail call mechanism.
// In such a case we should never be reaching this method as
@@ -1834,7 +1829,6 @@ void Lowering::LowerFastTailCall(GenTreeCall *call)
#endif
}
-
//------------------------------------------------------------------------
// LowerTailCallViaHelper: lower a call via the tailcall helper. Morph
// has already inserted tailcall helper special arguments. This function
@@ -1848,7 +1842,8 @@ void Lowering::LowerFastTailCall(GenTreeCall *call)
// For x86, lower
// tail.call(<function args>, int numberOfOldStackArgs, int dummyNumberOfNewStackArgs, int flags, void* dummyArg)
// as
-// JIT_TailCall(<function args>, int numberOfOldStackArgsWords, int numberOfNewStackArgsWords, int flags, void* callTarget)
+// JIT_TailCall(<function args>, int numberOfOldStackArgsWords, int numberOfNewStackArgsWords, int flags, void*
+// callTarget)
// Note that the special arguments are on the stack, whereas the function arguments follow the normal convention.
//
// Also inserts PInvoke method epilog if required.
@@ -1860,22 +1855,22 @@ void Lowering::LowerFastTailCall(GenTreeCall *call)
// Return Value:
// Returns control expression tree for making a call to helper Jit_TailCall.
//
-GenTree* Lowering::LowerTailCallViaHelper(GenTreeCall* call, GenTree *callTarget)
-{
+GenTree* Lowering::LowerTailCallViaHelper(GenTreeCall* call, GenTree* callTarget)
+{
// Tail call restrictions i.e. conditions under which tail prefix is ignored.
// Most of these checks are already done by importer or fgMorphTailCall().
// This serves as a double sanity check.
- assert((comp->info.compFlags & CORINFO_FLG_SYNCH) == 0); // tail calls from synchronized methods
- assert(!comp->opts.compNeedSecurityCheck); // tail call from methods that need security check
- assert(!call->IsUnmanaged()); // tail calls to unamanaged methods
- assert(!comp->compLocallocUsed); // tail call from methods that also do localloc
- assert(!comp->getNeedsGSSecurityCookie()); // jit64 compat: tail calls from methods that need GS check
-
+ assert((comp->info.compFlags & CORINFO_FLG_SYNCH) == 0); // tail calls from synchronized methods
+ assert(!comp->opts.compNeedSecurityCheck); // tail call from methods that need security check
+ assert(!call->IsUnmanaged()); // tail calls to unamanaged methods
+ assert(!comp->compLocallocUsed); // tail call from methods that also do localloc
+ assert(!comp->getNeedsGSSecurityCookie()); // jit64 compat: tail calls from methods that need GS check
+
// We expect to see a call that meets the following conditions
assert(call->IsTailCallViaHelper());
assert(callTarget != nullptr);
-
- // The TailCall helper call never returns to the caller and is not GC interruptible.
+
+ // The TailCall helper call never returns to the caller and is not GC interruptible.
// Therefore the block containing the tail call should be a GC safe point to avoid
// GC starvation.
assert(comp->compCurBB->bbFlags & BBF_GC_SAFE_POINT);
@@ -1888,7 +1883,7 @@ GenTree* Lowering::LowerTailCallViaHelper(GenTreeCall* call, GenTree *callTarget
}
// Remove gtCallAddr from execution order if one present.
- GenTreeStmt* callStmt = comp->compCurStmt->AsStmt();
+ GenTreeStmt* callStmt = comp->compCurStmt->AsStmt();
if (call->gtCallType == CT_INDIRECT)
{
assert(call->gtCallAddr != nullptr);
@@ -1899,13 +1894,13 @@ GenTree* Lowering::LowerTailCallViaHelper(GenTreeCall* call, GenTree *callTarget
#if defined(_TARGET_AMD64_)
- // For AMD64, first argument is CopyRoutine and second argument is a place holder node.
+// For AMD64, first argument is CopyRoutine and second argument is a place holder node.
#ifdef DEBUG
argEntry = comp->gtArgEntryByArgNum(call, 0);
assert(argEntry != nullptr);
assert(argEntry->node->gtOper == GT_PUTARG_REG);
- GenTree *firstArg = argEntry->node->gtOp.gtOp1;
+ GenTree* firstArg = argEntry->node->gtOp.gtOp1;
assert(firstArg->gtOper == GT_CNS_INT);
#endif
@@ -1913,9 +1908,9 @@ GenTree* Lowering::LowerTailCallViaHelper(GenTreeCall* call, GenTree *callTarget
argEntry = comp->gtArgEntryByArgNum(call, 1);
assert(argEntry != nullptr);
assert(argEntry->node->gtOper == GT_PUTARG_REG);
- GenTree *secondArg = argEntry->node->gtOp.gtOp1;
+ GenTree* secondArg = argEntry->node->gtOp.gtOp1;
- comp->fgInsertTreeInListAfter(callTarget, secondArg, callStmt);
+ comp->fgInsertTreeInListAfter(callTarget, secondArg, callStmt);
comp->fgDeleteTreeFromList(callStmt, secondArg);
argEntry->node->gtOp.gtOp1 = callTarget;
@@ -1937,7 +1932,7 @@ GenTree* Lowering::LowerTailCallViaHelper(GenTreeCall* call, GenTree *callTarget
assert(argEntry->node->gtOper == GT_PUTARG_STK);
GenTree* arg0 = argEntry->node->gtOp.gtOp1;
- comp->fgInsertTreeInListAfter(callTarget, arg0, callStmt);
+ comp->fgInsertTreeInListAfter(callTarget, arg0, callStmt);
comp->fgDeleteTreeFromList(callStmt, arg0);
argEntry->node->gtOp.gtOp1 = callTarget;
@@ -1948,9 +1943,8 @@ GenTree* Lowering::LowerTailCallViaHelper(GenTreeCall* call, GenTree *callTarget
GenTree* arg1 = argEntry->node->gtOp.gtOp1;
assert(arg1->gtOper == GT_CNS_INT);
- ssize_t tailCallHelperFlags =
- 1 | // always restore EDI,ESI,EBX
- (call->IsVirtualStub() ? 0x2 : 0x0); // Stub dispatch flag
+ ssize_t tailCallHelperFlags = 1 | // always restore EDI,ESI,EBX
+ (call->IsVirtualStub() ? 0x2 : 0x0); // Stub dispatch flag
arg1->gtIntCon.gtIconVal = tailCallHelperFlags;
// arg 2 == numberOfNewStackArgsWords
@@ -1976,13 +1970,13 @@ GenTree* Lowering::LowerTailCallViaHelper(GenTreeCall* call, GenTree *callTarget
#endif // _TARGET_*
// Transform this call node into a call to Jit tail call helper.
- call->gtCallType = CT_HELPER;
+ call->gtCallType = CT_HELPER;
call->gtCallMethHnd = comp->eeFindHelper(CORINFO_HELP_TAILCALL);
call->gtFlags &= ~GTF_CALL_VIRT_KIND_MASK;
// Lower this as if it were a pure helper call.
call->gtCallMoreFlags &= ~(GTF_CALL_M_TAILCALL | GTF_CALL_M_TAILCALL_VIA_HELPER);
- GenTree *result = LowerDirectCall(call);
+ GenTree* result = LowerDirectCall(call);
// Now add back tail call flags for identifying this node as tail call dispatched via helper.
call->gtCallMoreFlags |= GTF_CALL_M_TAILCALL | GTF_CALL_M_TAILCALL_VIA_HELPER;
@@ -2033,7 +2027,7 @@ void Lowering::LowerRet(GenTree* ret)
GenTree* Lowering::LowerDirectCall(GenTreeCall* call)
{
noway_assert(call->gtCallType == CT_USER_FUNC || call->gtCallType == CT_HELPER);
-
+
// Don't support tail calling helper methods.
// But we might encounter tail calls dispatched via JIT helper appear as a tail call to helper.
noway_assert(!call->IsTailCall() || call->IsTailCallViaHelper() || call->gtCallType == CT_USER_FUNC);
@@ -2042,19 +2036,19 @@ GenTree* Lowering::LowerDirectCall(GenTreeCall* call)
// call is known at JIT time. If not it is either an indirect call
// or the address must be accessed via an single/double indirection.
- void* addr;
- InfoAccessType accessType;
+ void* addr;
+ InfoAccessType accessType;
CorInfoHelpFunc helperNum = comp->eeGetHelperNum(call->gtCallMethHnd);
#ifdef FEATURE_READYTORUN_COMPILER
if (call->gtEntryPoint.addr != nullptr)
{
accessType = call->gtEntryPoint.accessType;
- addr = call->gtEntryPoint.addr;
+ addr = call->gtEntryPoint.addr;
}
else
#endif
- if (call->gtCallType == CT_HELPER)
+ if (call->gtCallType == CT_HELPER)
{
noway_assert(helperNum != CORINFO_HELP_UNDEF);
@@ -2071,106 +2065,110 @@ GenTree* Lowering::LowerDirectCall(GenTreeCall* call)
else
{
accessType = IAT_PVALUE;
- addr = pAddr;
+ addr = pAddr;
}
}
else
{
noway_assert(helperNum == CORINFO_HELP_UNDEF);
- CORINFO_ACCESS_FLAGS aflags = CORINFO_ACCESS_ANY;
+ CORINFO_ACCESS_FLAGS aflags = CORINFO_ACCESS_ANY;
if (call->IsSameThis())
+ {
aflags = (CORINFO_ACCESS_FLAGS)(aflags | CORINFO_ACCESS_THIS);
+ }
if (!call->NeedsNullCheck())
+ {
aflags = (CORINFO_ACCESS_FLAGS)(aflags | CORINFO_ACCESS_NONNULL);
+ }
CORINFO_CONST_LOOKUP addrInfo;
comp->info.compCompHnd->getFunctionEntryPoint(call->gtCallMethHnd, &addrInfo, aflags);
accessType = addrInfo.accessType;
- addr = addrInfo.addr;
+ addr = addrInfo.addr;
}
GenTree* result = nullptr;
switch (accessType)
{
- case IAT_VALUE:
- // Non-virtual direct call to known address
- if (!IsCallTargetInRange(addr) || call->IsTailCall())
- {
- result = AddrGen(addr);
- }
- else
- {
- // a direct call within range of hardware relative call instruction
- // stash the address for codegen
- call->gtDirectCallAddress = addr;
- }
- break;
-
- case IAT_PVALUE:
- {
- // Non-virtual direct calls to addresses accessed by
- // a single indirection.
- GenTree* cellAddr = AddrGen(addr);
- GenTree* indir = Ind(cellAddr);
+ case IAT_VALUE:
+ // Non-virtual direct call to known address
+ if (!IsCallTargetInRange(addr) || call->IsTailCall())
+ {
+ result = AddrGen(addr);
+ }
+ else
+ {
+ // a direct call within range of hardware relative call instruction
+ // stash the address for codegen
+ call->gtDirectCallAddress = addr;
+ }
+ break;
+
+ case IAT_PVALUE:
+ {
+ // Non-virtual direct calls to addresses accessed by
+ // a single indirection.
+ GenTree* cellAddr = AddrGen(addr);
+ GenTree* indir = Ind(cellAddr);
#ifdef FEATURE_READYTORUN_COMPILER
#ifdef _TARGET_ARM64_
- // For arm64, we dispatch code same as VSD using X11 for indirection cell address,
- // which ZapIndirectHelperThunk expects.
- if (call->IsR2RRelativeIndir())
- {
- cellAddr->gtRegNum = REG_R2R_INDIRECT_PARAM;
- indir->gtRegNum = REG_JUMP_THUNK_PARAM;
- }
+ // For arm64, we dispatch code same as VSD using X11 for indirection cell address,
+ // which ZapIndirectHelperThunk expects.
+ if (call->IsR2RRelativeIndir())
+ {
+ cellAddr->gtRegNum = REG_R2R_INDIRECT_PARAM;
+ indir->gtRegNum = REG_JUMP_THUNK_PARAM;
+ }
#endif
#endif
- result = indir;
- break;
- }
-
- case IAT_PPVALUE:
- // Non-virtual direct calls to addresses accessed by
- // a double indirection.
- //
- // Double-indirection. Load the address into a register
- // and call indirectly through the register
- noway_assert(helperNum == CORINFO_HELP_UNDEF);
- result = AddrGen(addr);
- result = Ind(Ind(result));
- break;
-
- default:
- noway_assert(!"Bad accessType");
- break;
+ result = indir;
+ break;
+ }
+
+ case IAT_PPVALUE:
+ // Non-virtual direct calls to addresses accessed by
+ // a double indirection.
+ //
+ // Double-indirection. Load the address into a register
+ // and call indirectly through the register
+ noway_assert(helperNum == CORINFO_HELP_UNDEF);
+ result = AddrGen(addr);
+ result = Ind(Ind(result));
+ break;
+
+ default:
+ noway_assert(!"Bad accessType");
+ break;
}
return result;
}
-
GenTree* Lowering::LowerDelegateInvoke(GenTreeCall* call)
{
noway_assert(call->gtCallType == CT_USER_FUNC);
- assert((comp->info.compCompHnd->getMethodAttribs(call->gtCallMethHnd) & (CORINFO_FLG_DELEGATE_INVOKE|CORINFO_FLG_FINAL)) == (CORINFO_FLG_DELEGATE_INVOKE|CORINFO_FLG_FINAL));
+ assert((comp->info.compCompHnd->getMethodAttribs(call->gtCallMethHnd) &
+ (CORINFO_FLG_DELEGATE_INVOKE | CORINFO_FLG_FINAL)) == (CORINFO_FLG_DELEGATE_INVOKE | CORINFO_FLG_FINAL));
GenTree* thisArgNode;
if (call->IsTailCallViaHelper())
{
#ifdef _TARGET_X86_ // x86 tailcall via helper follows normal calling convention, but with extra stack args.
const unsigned argNum = 0;
-#else // !_TARGET_X86_
+#else // !_TARGET_X86_
// In case of helper dispatched tail calls, "thisptr" will be the third arg.
// The first two args are: real call target and addr of args copy routine.
- const unsigned argNum = 2;
+ const unsigned argNum = 2;
#endif // !_TARGET_X86_
fgArgTabEntryPtr thisArgTabEntry = comp->gtArgEntryByArgNum(call, argNum);
- thisArgNode = thisArgTabEntry->node;
+ thisArgNode = thisArgTabEntry->node;
}
else
{
@@ -2198,9 +2196,9 @@ GenTree* Lowering::LowerDelegateInvoke(GenTreeCall* call)
else
#endif // _TARGET_X86_
{
- unsigned delegateInvokeTmp = comp->lvaGrabTemp(true DEBUGARG("delegate invoke call"));
- GenTreeStmt* newStmt = comp->fgInsertEmbeddedFormTemp(&thisArgNode->gtOp.gtOp1, delegateInvokeTmp);
- originalThisExpr = thisArgNode->gtOp.gtOp1; // it's changed; reload it.
+ unsigned delegateInvokeTmp = comp->lvaGrabTemp(true DEBUGARG("delegate invoke call"));
+ GenTreeStmt* newStmt = comp->fgInsertEmbeddedFormTemp(&thisArgNode->gtOp.gtOp1, delegateInvokeTmp);
+ originalThisExpr = thisArgNode->gtOp.gtOp1; // it's changed; reload it.
newStmt->gtFlags |= GTF_STMT_SKIP_LOWER; // we're in postorder so we have already processed this subtree
GenTree* stLclVar = newStmt->gtStmtExpr;
assert(stLclVar->OperIsLocalStore());
@@ -2210,11 +2208,8 @@ GenTree* Lowering::LowerDelegateInvoke(GenTreeCall* call)
// replace original expression feeding into thisPtr with
// [originalThis + offsetOfDelegateInstance]
- GenTree* newThisAddr = new(comp, GT_LEA) GenTreeAddrMode(TYP_REF,
- originalThisExpr,
- nullptr,
- 0,
- comp->eeGetEEInfo()->offsetOfDelegateInstance);
+ GenTree* newThisAddr = new (comp, GT_LEA)
+ GenTreeAddrMode(TYP_REF, originalThisExpr, nullptr, 0, comp->eeGetEEInfo()->offsetOfDelegateInstance);
originalThisExpr->InsertAfterSelf(newThisAddr);
GenTree* newThis = comp->gtNewOperNode(GT_IND, TYP_REF, newThisAddr);
@@ -2228,7 +2223,7 @@ GenTree* Lowering::LowerDelegateInvoke(GenTreeCall* call)
GenTree* base = new (comp, GT_LCL_VAR) GenTreeLclVar(originalThisExpr->TypeGet(), lclNum, BAD_IL_OFFSET);
unsigned targetOffs = comp->eeGetEEInfo()->offsetOfDelegateFirstTarget;
- GenTree* result = new(comp, GT_LEA) GenTreeAddrMode(TYP_REF, base, nullptr, 0, targetOffs);
+ GenTree* result = new (comp, GT_LEA) GenTreeAddrMode(TYP_REF, base, nullptr, 0, targetOffs);
GenTree* callTarget = Ind(result);
// don't need to sequence and insert this tree, caller will do it
@@ -2253,7 +2248,6 @@ GenTree* Lowering::LowerIndirectNonvirtCall(GenTreeCall* call)
return nullptr;
}
-
//------------------------------------------------------------------------
// CreateReturnTrapSeq: Create a tree to perform a "return trap", used in PInvoke
// epilogs to invoke a GC under a condition. The return trap checks some global
@@ -2292,7 +2286,6 @@ GenTree* Lowering::CreateReturnTrapSeq()
return comp->gtNewOperNode(GT_RETURNTRAP, TYP_INT, testTree);
}
-
//------------------------------------------------------------------------
// SetGCState: Create a tree that stores the given constant (0 or 1) into the
// thread's GC state field.
@@ -2313,17 +2306,16 @@ GenTree* Lowering::SetGCState(int state)
const CORINFO_EE_INFO* pInfo = comp->eeGetEEInfo();
- GenTree* base = new(comp, GT_LCL_VAR) GenTreeLclVar(TYP_I_IMPL, comp->info.compLvFrameListRoot, -1);
+ GenTree* base = new (comp, GT_LCL_VAR) GenTreeLclVar(TYP_I_IMPL, comp->info.compLvFrameListRoot, -1);
- GenTree* storeGcState = new(comp, GT_STOREIND)
+ GenTree* storeGcState = new (comp, GT_STOREIND)
GenTreeStoreInd(TYP_BYTE,
- new(comp, GT_LEA) GenTreeAddrMode(TYP_I_IMPL, base, nullptr, 1, pInfo->offsetOfGCState),
- new(comp, GT_CNS_INT) GenTreeIntCon(TYP_BYTE, state));
+ new (comp, GT_LEA) GenTreeAddrMode(TYP_I_IMPL, base, nullptr, 1, pInfo->offsetOfGCState),
+ new (comp, GT_CNS_INT) GenTreeIntCon(TYP_BYTE, state));
return storeGcState;
}
-
//------------------------------------------------------------------------
// CreateFrameLinkUpdate: Create a tree that either links or unlinks the
// locally-allocated InlinedCallFrame from the Frame list.
@@ -2338,22 +2330,21 @@ GenTree* Lowering::SetGCState(int state)
//
GenTree* Lowering::CreateFrameLinkUpdate(FrameLinkAction action)
{
- const CORINFO_EE_INFO* pInfo = comp->eeGetEEInfo();
+ const CORINFO_EE_INFO* pInfo = comp->eeGetEEInfo();
const CORINFO_EE_INFO::InlinedCallFrameInfo& callFrameInfo = pInfo->inlinedCallFrameInfo;
- GenTree* TCB = new(comp, GT_LCL_VAR)
- GenTreeLclVar(GT_LCL_VAR, TYP_I_IMPL, comp->info.compLvFrameListRoot, (IL_OFFSET)-1); // cast to resolve ambiguity.
+ GenTree* TCB = new (comp, GT_LCL_VAR) GenTreeLclVar(GT_LCL_VAR, TYP_I_IMPL, comp->info.compLvFrameListRoot,
+ (IL_OFFSET)-1); // cast to resolve ambiguity.
// Thread->m_pFrame
- GenTree* addr = new(comp, GT_LEA)
- GenTreeAddrMode(TYP_I_IMPL, TCB, nullptr, 1, pInfo->offsetOfThreadFrame);
+ GenTree* addr = new (comp, GT_LEA) GenTreeAddrMode(TYP_I_IMPL, TCB, nullptr, 1, pInfo->offsetOfThreadFrame);
GenTree* data = nullptr;
if (action == PushFrame)
{
// Thread->m_pFrame = &inlinedCallFrame;
- data = new(comp, GT_LCL_FLD_ADDR)
+ data = new (comp, GT_LCL_FLD_ADDR)
GenTreeLclFld(GT_LCL_FLD_ADDR, TYP_BYREF, comp->lvaInlinedPInvokeFrameVar, callFrameInfo.offsetOfFrameVptr);
}
else
@@ -2361,14 +2352,13 @@ GenTree* Lowering::CreateFrameLinkUpdate(FrameLinkAction action)
assert(action == PopFrame);
// Thread->m_pFrame = inlinedCallFrame.m_pNext;
- data = new(comp, GT_LCL_FLD)
- GenTreeLclFld(GT_LCL_FLD, TYP_BYREF, comp->lvaInlinedPInvokeFrameVar, pInfo->inlinedCallFrameInfo.offsetOfFrameLink);
+ data = new (comp, GT_LCL_FLD) GenTreeLclFld(GT_LCL_FLD, TYP_BYREF, comp->lvaInlinedPInvokeFrameVar,
+ pInfo->inlinedCallFrameInfo.offsetOfFrameLink);
}
- GenTree* storeInd = new(comp, GT_STOREIND) GenTreeStoreInd(TYP_I_IMPL, addr, data);
+ GenTree* storeInd = new (comp, GT_STOREIND) GenTreeStoreInd(TYP_I_IMPL, addr, data);
return storeInd;
}
-
//------------------------------------------------------------------------
// InsertPInvokeMethodProlog: Create the code that runs at the start of
// every method that has PInvoke calls.
@@ -2380,7 +2370,7 @@ GenTree* Lowering::CreateFrameLinkUpdate(FrameLinkAction action)
//
// The (current) layout is as follows:
//
-// 64-bit 32-bit CORINFO_EE_INFO
+// 64-bit 32-bit CORINFO_EE_INFO
// offset offset field name offset when set
// -----------------------------------------------------------------------------------------
// +00h +00h GS cookie offsetOfGSCookie
@@ -2419,12 +2409,12 @@ void Lowering::InsertPInvokeMethodProlog()
JITDUMP("======= Inserting PInvoke method prolog\n");
- const CORINFO_EE_INFO* pInfo = comp->eeGetEEInfo();
+ const CORINFO_EE_INFO* pInfo = comp->eeGetEEInfo();
const CORINFO_EE_INFO::InlinedCallFrameInfo& callFrameInfo = pInfo->inlinedCallFrameInfo;
// First arg: &compiler->lvaInlinedPInvokeFrameVar + callFrameInfo.offsetOfFrameVptr
- GenTree* frameAddr = new(comp, GT_LCL_FLD_ADDR)
+ GenTree* frameAddr = new (comp, GT_LCL_FLD_ADDR)
GenTreeLclFld(GT_LCL_FLD_ADDR, TYP_BYREF, comp->lvaInlinedPInvokeFrameVar, callFrameInfo.offsetOfFrameVptr);
// Call runtime helper to fill in our InlinedCallFrame and push it on the Frame list:
@@ -2434,8 +2424,8 @@ void Lowering::InsertPInvokeMethodProlog()
#ifdef _TARGET_X86_
GenTreeArgList* argList = comp->gtNewArgList(frameAddr);
-#else // !_TARGET_X86_
- GenTreeArgList* argList = comp->gtNewArgList(frameAddr, PhysReg(REG_SECRET_STUB_PARAM));
+#else // !_TARGET_X86_
+ GenTreeArgList* argList = comp->gtNewArgList(frameAddr, PhysReg(REG_SECRET_STUB_PARAM));
#endif // !_TARGET_X86_
GenTree* call = comp->gtNewHelperCallNode(CORINFO_HELP_INIT_PINVOKE_FRAME, TYP_I_IMPL, 0, argList);
@@ -2445,8 +2435,9 @@ void Lowering::InsertPInvokeMethodProlog()
noway_assert(!varDsc->lvIsParam);
noway_assert(varDsc->lvType == TYP_I_IMPL);
- GenTree* store = new(comp, GT_STORE_LCL_VAR)
- GenTreeLclVar(GT_STORE_LCL_VAR, TYP_I_IMPL, comp->info.compLvFrameListRoot, (IL_OFFSET)-1); // cast to resolve ambiguity.
+ GenTree* store =
+ new (comp, GT_STORE_LCL_VAR) GenTreeLclVar(GT_STORE_LCL_VAR, TYP_I_IMPL, comp->info.compLvFrameListRoot,
+ (IL_OFFSET)-1); // cast to resolve ambiguity.
store->gtOp.gtOp1 = call;
store->gtFlags |= GTF_VAR_DEF;
@@ -2455,14 +2446,14 @@ void Lowering::InsertPInvokeMethodProlog()
GenTree* lastStmt = stmt;
DISPTREE(lastStmt);
-#ifndef _TARGET_X86_ // For x86, this step is done at the call site (due to stack pointer not being static in the function).
+#ifndef _TARGET_X86_ // For x86, this step is done at the call site (due to stack pointer not being static in the
+ // function).
// --------------------------------------------------------
// InlinedCallFrame.m_pCallSiteSP = @RSP;
- GenTreeLclFld* storeSP = new(comp, GT_STORE_LCL_FLD)
- GenTreeLclFld(GT_STORE_LCL_FLD, TYP_I_IMPL, comp->lvaInlinedPInvokeFrameVar,
- callFrameInfo.offsetOfCallSiteSP);
+ GenTreeLclFld* storeSP = new (comp, GT_STORE_LCL_FLD)
+ GenTreeLclFld(GT_STORE_LCL_FLD, TYP_I_IMPL, comp->lvaInlinedPInvokeFrameVar, callFrameInfo.offsetOfCallSiteSP);
storeSP->gtOp1 = PhysReg(REG_SPBASE);
GenTreeStmt* storeSPStmt = LowerMorphAndSeqTree(storeSP);
@@ -2475,9 +2466,9 @@ void Lowering::InsertPInvokeMethodProlog()
// --------------------------------------------------------
// InlinedCallFrame.m_pCalleeSavedEBP = @RBP;
- GenTreeLclFld* storeFP = new(comp, GT_STORE_LCL_FLD)
- GenTreeLclFld(GT_STORE_LCL_FLD, TYP_I_IMPL, comp->lvaInlinedPInvokeFrameVar,
- callFrameInfo.offsetOfCalleeSavedFP);
+ GenTreeLclFld* storeFP =
+ new (comp, GT_STORE_LCL_FLD) GenTreeLclFld(GT_STORE_LCL_FLD, TYP_I_IMPL, comp->lvaInlinedPInvokeFrameVar,
+ callFrameInfo.offsetOfCalleeSavedFP);
storeFP->gtOp1 = PhysReg(REG_FPBASE);
GenTreeStmt* storeFPStmt = LowerMorphAndSeqTree(storeFP);
@@ -2499,7 +2490,6 @@ void Lowering::InsertPInvokeMethodProlog()
}
}
-
//------------------------------------------------------------------------
// InsertPInvokeMethodEpilog: Code that needs to be run when exiting any method
// that has PInvoke inlines. This needs to be inserted any place you can exit the
@@ -2512,8 +2502,7 @@ void Lowering::InsertPInvokeMethodProlog()
// Return Value:
// Code tree to perform the action.
//
-void Lowering::InsertPInvokeMethodEpilog(BasicBlock *returnBB
- DEBUGARG(GenTreePtr lastExpr) )
+void Lowering::InsertPInvokeMethodEpilog(BasicBlock* returnBB DEBUGARG(GenTreePtr lastExpr))
{
assert(returnBB != nullptr);
assert(comp->info.compCallUnmanaged);
@@ -2526,13 +2515,14 @@ void Lowering::InsertPInvokeMethodEpilog(BasicBlock *returnBB
JITDUMP("======= Inserting PInvoke method epilog\n");
// Method doing PInvoke calls has exactly one return block unless it has "jmp" or tail calls.
- assert(((returnBB == comp->genReturnBB) && (returnBB->bbJumpKind == BBJ_RETURN)) || returnBB->endsWithTailCallOrJmp(comp));
+ assert(((returnBB == comp->genReturnBB) && (returnBB->bbJumpKind == BBJ_RETURN)) ||
+ returnBB->endsWithTailCallOrJmp(comp));
- GenTreeStmt* lastTopLevelStmt = comp->fgGetLastTopLevelStmt(returnBB)->AsStmt();
- GenTreePtr lastTopLevelStmtExpr = lastTopLevelStmt->gtStmtExpr;
+ GenTreeStmt* lastTopLevelStmt = comp->fgGetLastTopLevelStmt(returnBB)->AsStmt();
+ GenTreePtr lastTopLevelStmtExpr = lastTopLevelStmt->gtStmtExpr;
// Gentree of the last top level stmnt should match.
- assert(lastTopLevelStmtExpr == lastExpr);
+ assert(lastTopLevelStmtExpr == lastExpr);
// Note: PInvoke Method Epilog (PME) needs to be inserted just before GT_RETURN, GT_JMP or GT_CALL node in execution
// order so that it is guaranteed that there will be no further PInvokes after that point in the method.
@@ -2556,7 +2546,7 @@ void Lowering::InsertPInvokeMethodEpilog(BasicBlock *returnBB
// will be live-in to a BBJ_RETURN block without any uses. Long term we need to fix liveness for x64 case to
// properly extend the life of compLvFrameListRoot var.
//
- // Thread.offsetOfGcState = 0/1
+ // Thread.offsetOfGcState = 0/1
// That is [tcb + offsetOfGcState] = 1
GenTree* storeGCState = SetGCState(1);
comp->fgInsertTreeBeforeAsEmbedded(storeGCState, lastTopLevelStmtExpr, lastTopLevelStmt, returnBB);
@@ -2570,7 +2560,6 @@ void Lowering::InsertPInvokeMethodEpilog(BasicBlock *returnBB
}
}
-
//------------------------------------------------------------------------
// InsertPInvokeCallProlog: Emit the call-site prolog for direct calls to unmanaged code.
// It does all the necessary call-site setup of the InlinedCallFrame.
@@ -2601,11 +2590,12 @@ void Lowering::InsertPInvokeCallProlog(GenTreeCall* call)
if (comp->opts.ShouldUsePInvokeHelpers())
{
// First argument is the address of the frame variable.
- GenTree* frameAddr = new(comp, GT_LCL_VAR_ADDR)
+ GenTree* frameAddr = new (comp, GT_LCL_VAR_ADDR)
GenTreeLclVar(GT_LCL_VAR_ADDR, TYP_BYREF, comp->lvaInlinedPInvokeFrameVar, BAD_IL_OFFSET);
// Insert call to CORINFO_HELP_JIT_PINVOKE_BEGIN
- GenTree* helperCall = comp->gtNewHelperCallNode(CORINFO_HELP_JIT_PINVOKE_BEGIN, TYP_VOID, 0, comp->gtNewArgList(frameAddr));
+ GenTree* helperCall =
+ comp->gtNewHelperCallNode(CORINFO_HELP_JIT_PINVOKE_BEGIN, TYP_VOID, 0, comp->gtNewArgList(frameAddr));
comp->fgMorphTree(helperCall);
comp->fgInsertTreeBeforeAsEmbedded(helperCall, insertBefore, comp->compCurStmt->AsStmt(), currBlock);
@@ -2639,10 +2629,9 @@ void Lowering::InsertPInvokeCallProlog(GenTreeCall* call)
{
assert(callType == CT_USER_FUNC);
- void* pEmbedMethodHandle = nullptr;
- CORINFO_METHOD_HANDLE embedMethodHandle = comp->info.compCompHnd->embedMethodHandle(
- call->gtCallMethHnd,
- &pEmbedMethodHandle);
+ void* pEmbedMethodHandle = nullptr;
+ CORINFO_METHOD_HANDLE embedMethodHandle =
+ comp->info.compCompHnd->embedMethodHandle(call->gtCallMethHnd, &pEmbedMethodHandle);
noway_assert((!embedMethodHandle) != (!pEmbedMethodHandle));
@@ -2661,11 +2650,9 @@ void Lowering::InsertPInvokeCallProlog(GenTreeCall* call)
if (src != nullptr)
{
// Store into InlinedCallFrame.m_Datum, the offset of which is given by offsetOfCallTarget.
- GenTreeLclFld* store = new(comp, GT_STORE_LCL_FLD)
- GenTreeLclFld(GT_STORE_LCL_FLD,
- TYP_I_IMPL,
- comp->lvaInlinedPInvokeFrameVar,
- callFrameInfo.offsetOfCallTarget);
+ GenTreeLclFld* store =
+ new (comp, GT_STORE_LCL_FLD) GenTreeLclFld(GT_STORE_LCL_FLD, TYP_I_IMPL, comp->lvaInlinedPInvokeFrameVar,
+ callFrameInfo.offsetOfCallTarget);
store->gtOp1 = src;
comp->fgInsertTreeBeforeAsEmbedded(store, insertBefore, comp->compCurStmt->AsStmt(), currBlock);
DISPTREE(comp->compCurStmt);
@@ -2676,11 +2663,8 @@ void Lowering::InsertPInvokeCallProlog(GenTreeCall* call)
// ----------------------------------------------------------------------------------
// InlinedCallFrame.m_pCallSiteSP = SP
- GenTreeLclFld* storeCallSiteSP = new(comp, GT_STORE_LCL_FLD)
- GenTreeLclFld(GT_STORE_LCL_FLD,
- TYP_I_IMPL,
- comp->lvaInlinedPInvokeFrameVar,
- callFrameInfo.offsetOfCallSiteSP);
+ GenTreeLclFld* storeCallSiteSP = new (comp, GT_STORE_LCL_FLD)
+ GenTreeLclFld(GT_STORE_LCL_FLD, TYP_I_IMPL, comp->lvaInlinedPInvokeFrameVar, callFrameInfo.offsetOfCallSiteSP);
storeCallSiteSP->gtOp1 = PhysReg(REG_SPBASE);
@@ -2692,17 +2676,15 @@ void Lowering::InsertPInvokeCallProlog(GenTreeCall* call)
// ----------------------------------------------------------------------------------
// InlinedCallFrame.m_pCallerReturnAddress = &label (the address of the instruction immediately following the call)
- GenTreeLclFld* storeLab = new(comp, GT_STORE_LCL_FLD)
- GenTreeLclFld(GT_STORE_LCL_FLD,
- TYP_I_IMPL,
- comp->lvaInlinedPInvokeFrameVar,
- callFrameInfo.offsetOfReturnAddress);
+ GenTreeLclFld* storeLab =
+ new (comp, GT_STORE_LCL_FLD) GenTreeLclFld(GT_STORE_LCL_FLD, TYP_I_IMPL, comp->lvaInlinedPInvokeFrameVar,
+ callFrameInfo.offsetOfReturnAddress);
// We don't have a real label, and inserting one is hard (even if we made a special node),
// so for now we will just 'know' what this means in codegen.
- GenTreeLabel* labelRef = new(comp, GT_LABEL) GenTreeLabel(nullptr);
- labelRef->gtType = TYP_I_IMPL;
- storeLab->gtOp1 = labelRef;
+ GenTreeLabel* labelRef = new (comp, GT_LABEL) GenTreeLabel(nullptr);
+ labelRef->gtType = TYP_I_IMPL;
+ storeLab->gtOp1 = labelRef;
comp->fgInsertTreeBeforeAsEmbedded(storeLab, insertBefore, comp->compCurStmt->AsStmt(), currBlock);
DISPTREE(comp->compCurStmt);
@@ -2710,7 +2692,7 @@ void Lowering::InsertPInvokeCallProlog(GenTreeCall* call)
if (!(comp->opts.eeFlags & CORJIT_FLG_IL_STUB))
{
// Set the TCB's frame to be the one we just created.
- // Note the init routine for the InlinedCallFrame (CORINFO_HELP_INIT_PINVOKE_FRAME)
+ // Note the init routine for the InlinedCallFrame (CORINFO_HELP_INIT_PINVOKE_FRAME)
// has prepended it to the linked list to maintain the stack of Frames.
//
// Stubs do this once per stub, not once per call.
@@ -2729,7 +2711,6 @@ void Lowering::InsertPInvokeCallProlog(GenTreeCall* call)
DISPTREE(comp->compCurStmt);
}
-
//------------------------------------------------------------------------
// InsertPInvokeCallEpilog: Insert the code that goes after every inlined pinvoke call.
//
@@ -2749,12 +2730,13 @@ void Lowering::InsertPInvokeCallEpilog(GenTreeCall* call)
noway_assert(comp->lvaInlinedPInvokeFrameVar != BAD_VAR_NUM);
// First argument is the address of the frame variable.
- GenTree* frameAddr = new(comp, GT_LCL_VAR)
- GenTreeLclVar(GT_LCL_VAR, TYP_BYREF, comp->lvaInlinedPInvokeFrameVar, BAD_IL_OFFSET);
+ GenTree* frameAddr =
+ new (comp, GT_LCL_VAR) GenTreeLclVar(GT_LCL_VAR, TYP_BYREF, comp->lvaInlinedPInvokeFrameVar, BAD_IL_OFFSET);
frameAddr->gtOper = GT_LCL_VAR_ADDR;
// Insert call to CORINFO_HELP_JIT_PINVOKE_END
- GenTree* helperCall = comp->gtNewHelperCallNode(CORINFO_HELP_JIT_PINVOKE_END, TYP_VOID, 0, comp->gtNewArgList(frameAddr));
+ GenTree* helperCall =
+ comp->gtNewHelperCallNode(CORINFO_HELP_JIT_PINVOKE_END, TYP_VOID, 0, comp->gtNewArgList(frameAddr));
comp->fgMorphTree(helperCall);
comp->fgInsertTreeAfterAsEmbedded(helperCall, call, comp->compCurStmt->AsStmt(), currBlock);
@@ -2768,8 +2750,8 @@ void Lowering::InsertPInvokeCallEpilog(GenTreeCall* call)
// gcstate = 1
GenTree* latest = call;
- GenTree* tree = SetGCState(1);
- newStmt = comp->fgInsertTreeAfterAsEmbedded(tree, latest, topStmt, currBlock);
+ GenTree* tree = SetGCState(1);
+ newStmt = comp->fgInsertTreeAfterAsEmbedded(tree, latest, topStmt, currBlock);
DISPTREE(newStmt);
latest = tree;
if (newStmt->gtStmtIsTopLevel())
@@ -2777,7 +2759,7 @@ void Lowering::InsertPInvokeCallEpilog(GenTreeCall* call)
topStmt = newStmt;
}
- tree = CreateReturnTrapSeq();
+ tree = CreateReturnTrapSeq();
newStmt = comp->fgInsertTreeAfterAsEmbedded(tree, latest, topStmt, currBlock);
DISPTREE(newStmt);
latest = tree;
@@ -2801,7 +2783,6 @@ void Lowering::InsertPInvokeCallEpilog(GenTreeCall* call)
}
}
-
//------------------------------------------------------------------------
// LowerNonvirtPinvokeCall: Lower a non-virtual / indirect PInvoke call
//
@@ -2828,7 +2809,8 @@ GenTree* Lowering::LowerNonvirtPinvokeCall(GenTreeCall* call)
// // Set up frame information
// inlinedCallFrame.callTarget = methodHandle; // stored in m_Datum
// inlinedCallFrame.m_pCallSiteSP = SP; // x86 only
- // inlinedCallFrame.m_pCallerReturnAddress = &label; (the address of the instruction immediately following the call)
+ // inlinedCallFrame.m_pCallerReturnAddress = &label; (the address of the instruction immediately following the
+ // call)
// Thread.m_pFrame = &inlinedCallFrame; (non-IL-stub only)
//
// // Switch the thread's GC mode to preemptive mode
@@ -2863,7 +2845,7 @@ GenTree* Lowering::LowerNonvirtPinvokeCall(GenTreeCall* call)
// platform. They may be changed in the future such that they preserve all register values.
GenTree* result = nullptr;
- void* addr = nullptr;
+ void* addr = nullptr;
// assert we have seen one of these
noway_assert(comp->info.compCallUnmanaged != 0);
@@ -2880,19 +2862,19 @@ GenTree* Lowering::LowerNonvirtPinvokeCall(GenTreeCall* call)
if (call->gtCallType != CT_INDIRECT)
{
noway_assert(call->gtCallType == CT_USER_FUNC);
- CORINFO_METHOD_HANDLE methHnd = call->gtCallMethHnd;
+ CORINFO_METHOD_HANDLE methHnd = call->gtCallMethHnd;
CORINFO_CONST_LOOKUP lookup;
#if COR_JIT_EE_VERSION > 460
comp->info.compCompHnd->getAddressOfPInvokeTarget(methHnd, &lookup);
#else
- void* pIndirection;
+ void* pIndirection;
lookup.accessType = IAT_PVALUE;
- lookup.addr = comp->info.compCompHnd->getAddressOfPInvokeFixup(methHnd, &pIndirection);
+ lookup.addr = comp->info.compCompHnd->getAddressOfPInvokeFixup(methHnd, &pIndirection);
if (lookup.addr == nullptr)
{
lookup.accessType = IAT_PPVALUE;
- lookup.addr = pIndirection;
+ lookup.addr = pIndirection;
}
#endif
@@ -2906,8 +2888,8 @@ GenTree* Lowering::LowerNonvirtPinvokeCall(GenTreeCall* call)
}
else
{
- // a direct call within range of hardware relative call instruction
- // stash the address for codegen
+ // a direct call within range of hardware relative call instruction
+ // stash the address for codegen
call->gtDirectCallAddress = addr;
#ifdef FEATURE_READYTORUN_COMPILER
call->gtEntryPoint.addr = nullptr;
@@ -2930,15 +2912,15 @@ GenTree* Lowering::LowerNonvirtPinvokeCall(GenTreeCall* call)
return result;
}
-// Expand the code necessary to calculate the control target.
+// Expand the code necessary to calculate the control target.
// Returns: the expression needed to calculate the control target
// May insert embedded statements
GenTree* Lowering::LowerVirtualVtableCall(GenTreeCall* call)
{
- noway_assert(call->gtCallType == CT_USER_FUNC);
+ noway_assert(call->gtCallType == CT_USER_FUNC);
// If this is a tail call via helper, thisPtr will be the third argument.
- int thisPtrArgNum;
+ int thisPtrArgNum;
regNumber thisPtrArgReg;
#ifndef _TARGET_X86_ // x86 tailcall via helper follows normal calling convention, but with extra stack args.
@@ -2958,7 +2940,7 @@ GenTree* Lowering::LowerVirtualVtableCall(GenTreeCall* call)
fgArgTabEntry* argEntry = comp->gtArgEntryByArgNum(call, thisPtrArgNum);
assert(argEntry->regNum == thisPtrArgReg);
assert(argEntry->node->gtOper == GT_PUTARG_REG);
- GenTree *thisPtr = argEntry->node->gtOp.gtOp1;
+ GenTree* thisPtr = argEntry->node->gtOp.gtOp1;
// If what we are passing as the thisptr is not already a local, make a new local to place it in
// because we will be creating expressions based on it.
@@ -2988,11 +2970,12 @@ GenTree* Lowering::LowerVirtualVtableCall(GenTreeCall* call)
GenTree* local;
if (thisPtr->isLclField())
{
- local = new(comp, GT_LCL_FLD) GenTreeLclFld(GT_LCL_FLD, thisPtr->TypeGet(), lclNum, thisPtr->AsLclFld()->gtLclOffs);
+ local = new (comp, GT_LCL_FLD)
+ GenTreeLclFld(GT_LCL_FLD, thisPtr->TypeGet(), lclNum, thisPtr->AsLclFld()->gtLclOffs);
}
else
{
- local = new(comp, GT_LCL_VAR) GenTreeLclVar(GT_LCL_VAR, thisPtr->TypeGet(), lclNum, BAD_IL_OFFSET);
+ local = new (comp, GT_LCL_VAR) GenTreeLclVar(GT_LCL_VAR, thisPtr->TypeGet(), lclNum, BAD_IL_OFFSET);
}
// pointer to virtual table = [REG_CALL_THIS + offs]
@@ -3000,8 +2983,9 @@ GenTree* Lowering::LowerVirtualVtableCall(GenTreeCall* call)
// Get hold of the vtable offset (note: this might be expensive)
unsigned vtabOffsOfIndirection;
- unsigned vtabOffsAfterIndirection;
- comp->info.compCompHnd->getMethodVTableOffset(call->gtCallMethHnd, &vtabOffsOfIndirection, &vtabOffsAfterIndirection);
+ unsigned vtabOffsAfterIndirection;
+ comp->info.compCompHnd->getMethodVTableOffset(call->gtCallMethHnd, &vtabOffsOfIndirection,
+ &vtabOffsAfterIndirection);
// Get the appropriate vtable chunk
// result = [REG_CALL_IND_SCRATCH + vtabOffsOfIndirection]
@@ -3056,11 +3040,11 @@ GenTree* Lowering::LowerVirtualStubCall(GenTreeCall* call)
// TODO-Cleanup: Disable emitting random NOPs
// This is code to set up an indirect call to a stub address computed
- // via dictionary lookup.
+ // via dictionary lookup.
if (call->gtCallType == CT_INDIRECT)
{
NYI_X86("Virtual Stub dispatched call lowering via dictionary lookup");
-
+
// The importer decided we needed a stub call via a computed
// stub dispatch address, i.e. an address which came from a dictionary lookup.
// - The dictionary lookup produces an indirected address, suitable for call
@@ -3088,7 +3072,7 @@ GenTree* Lowering::LowerVirtualStubCall(GenTreeCall* call)
noway_assert(call->IsVirtualStubRelativeIndir());
// Direct stub calls, though the stubAddr itself may still need to be
- // accesed via an indirection.
+ // accesed via an indirection.
GenTree* addr = AddrGen(stubAddr);
#ifdef _TARGET_X86_
@@ -3105,12 +3089,12 @@ GenTree* Lowering::LowerVirtualStubCall(GenTreeCall* call)
{
GenTree* indir = Ind(addr);
- // On x86 we generate this:
- // call dword ptr [rel32] ; FF 15 ---rel32----
- // So we don't use a register.
+// On x86 we generate this:
+// call dword ptr [rel32] ; FF 15 ---rel32----
+// So we don't use a register.
#ifndef _TARGET_X86_
// on x64 we must materialize the target using specific registers.
- addr->gtRegNum = REG_VIRTUAL_STUB_PARAM;
+ addr->gtRegNum = REG_VIRTUAL_STUB_PARAM;
indir->gtRegNum = REG_JUMP_THUNK_PARAM;
#endif
result = indir;
@@ -3121,7 +3105,6 @@ GenTree* Lowering::LowerVirtualStubCall(GenTreeCall* call)
return result;
}
-
//------------------------------------------------------------------------
// LowerIndCleanupHelper: Remove the nodes that are no longer used after an
// addressing mode is constructed
@@ -3138,7 +3121,10 @@ GenTree* Lowering::LowerVirtualStubCall(GenTreeCall* call)
void Lowering::LowerIndCleanupHelper(GenTreeAddrMode* addrMode, GenTreePtr tree)
{
- if (tree == addrMode->Base() || tree == addrMode->Index()) return;
+ if (tree == addrMode->Base() || tree == addrMode->Index())
+ {
+ return;
+ }
unsigned childCount = tree->NumChildren();
for (unsigned i = 0; i < childCount; i++)
{
@@ -3154,7 +3140,7 @@ void Lowering::LowerIndCleanupHelper(GenTreeAddrMode* addrMode, GenTreePtr tree)
// returns: true if the sources given may be modified before they are used
bool Lowering::AreSourcesPossiblyModified(GenTree* use, GenTree* src1, GenTree* src2)
{
- GenTree* cursor = use;
+ GenTree* cursor = use;
GenTree* firstTree = comp->compCurStmt->AsStmt()->gtStmtList;
while (cursor && cursor != firstTree)
@@ -3162,11 +3148,17 @@ bool Lowering::AreSourcesPossiblyModified(GenTree* use, GenTree* src1, GenTree*
cursor = cursor->gtPrev;
if (cursor == src1)
+ {
src1 = nullptr;
+ }
if (cursor == src2)
+ {
src2 = nullptr;
+ }
if (src2 == nullptr && src1 == nullptr)
+ {
return false;
+ }
if (src1 && comp->fgNodesMayInterfere(src1, cursor))
{
@@ -3177,7 +3169,6 @@ bool Lowering::AreSourcesPossiblyModified(GenTree* use, GenTree* src1, GenTree*
{
return true;
}
-
}
assert(!"ran off beginning of stmt\n");
return true;
@@ -3195,12 +3186,12 @@ bool Lowering::AreSourcesPossiblyModified(GenTree* use, GenTree* src1, GenTree*
//
void Lowering::LowerAddrMode(GenTreePtr* pTree, GenTree* before, Compiler::fgWalkData* data, bool isIndir)
{
- GenTree* addr = *pTree;
- GenTreePtr base = nullptr;
- GenTreePtr index = nullptr;
- unsigned scale = 0;
- unsigned offset = 0;
- bool rev = false;
+ GenTree* addr = *pTree;
+ GenTreePtr base = nullptr;
+ GenTreePtr index = nullptr;
+ unsigned scale = 0;
+ unsigned offset = 0;
+ bool rev = false;
// If it's not an indir, we need the fgWalkData to get info about the parent.
assert(isIndir || data);
@@ -3210,7 +3201,9 @@ void Lowering::LowerAddrMode(GenTreePtr* pTree, GenTree* before, Compiler::fgWal
comp->codeGen->genCreateAddrMode(addr, -1, true, 0, &rev, &base, &index, &scale, &offset, true /*nogen*/);
if (scale == 0)
+ {
scale = 1;
+ }
if (!isIndir)
{
@@ -3230,7 +3223,7 @@ void Lowering::LowerAddrMode(GenTreePtr* pTree, GenTree* before, Compiler::fgWal
// make sure there are not any side effects between def of leaves and use
if (doAddrMode && !AreSourcesPossiblyModified(addr, base, index))
{
- GenTreePtr arrLength = NULL;
+ GenTreePtr arrLength = nullptr;
JITDUMP("Addressing mode:\n");
JITDUMP(" Base\n");
@@ -3246,15 +3239,16 @@ void Lowering::LowerAddrMode(GenTreePtr* pTree, GenTree* before, Compiler::fgWal
}
var_types addrModeType = addr->TypeGet();
- if (addrModeType == TYP_REF)
+ if (addrModeType == TYP_REF)
+ {
addrModeType = TYP_BYREF;
+ }
+
+ GenTreeAddrMode* addrMode = new (comp, GT_LEA) GenTreeAddrMode(addrModeType, base, index, scale, offset);
- GenTreeAddrMode* addrMode =
- new(comp, GT_LEA) GenTreeAddrMode(addrModeType, base, index, scale, offset);
-
addrMode->CopyCosts(addr);
addrMode->gtRsvdRegs = addr->gtRsvdRegs;
- addrMode->gtFlags |= (addr->gtFlags & (GTF_ALL_EFFECT | GTF_IND_FLAGS));
+ addrMode->gtFlags |= (addr->gtFlags & (GTF_ALL_EFFECT | GTF_IND_FLAGS));
JITDUMP("New addressing mode node:\n");
DISPNODE(addrMode);
@@ -3288,7 +3282,7 @@ void Lowering::LowerAddrMode(GenTreePtr* pTree, GenTree* before, Compiler::fgWal
LowerIndCleanupHelper(addrMode, addr);
GenTree* old = *pTree;
- *pTree = addrMode;
+ *pTree = addrMode;
if (!isIndir)
{
@@ -3311,7 +3305,7 @@ void Lowering::LowerAddrMode(GenTreePtr* pTree, GenTree* before, Compiler::fgWal
void Lowering::LowerAdd(GenTreePtr* pTree, Compiler::fgWalkData* data)
{
- GenTreePtr newNode = NULL;
+ GenTreePtr newNode = nullptr;
GenTreePtr addr = *pTree;
@@ -3319,20 +3313,28 @@ void Lowering::LowerAdd(GenTreePtr* pTree, Compiler::fgWalkData* data)
// For ARM architectures we don't have the LEA instruction
// therefore we won't get much benefit from doing this.
return;
-#else // _TARGET_ARMARCH_
+#else // _TARGET_ARMARCH_
if (data->parentStack->Height() < 2)
+ {
return;
-
+ }
+
// if this is a child of an indir, let the parent handle it
if (data->parentStack->Index(1)->OperIsIndir())
+ {
return;
+ }
// if there is a chain of adds, only look at the topmost one
if (data->parentStack->Index(1)->gtOper == GT_ADD)
+ {
return;
+ }
if (!varTypeIsIntegralOrI(addr))
+ {
return;
+ }
LowerAddrMode(pTree, addr, data, false);
#endif // !_TARGET_ARMARCH_
@@ -3361,7 +3363,7 @@ void Lowering::LowerUnsignedDivOrMod(GenTree* tree)
if (tree->OperGet() == GT_UDIV)
{
- newOper = GT_RSZ;
+ newOper = GT_RSZ;
divisorValue = genLog2(divisorValue);
}
else
@@ -3377,7 +3379,7 @@ void Lowering::LowerUnsignedDivOrMod(GenTree* tree)
}
//------------------------------------------------------------------------
-// LowerSignedDivOrMod: transform integer GT_DIV/GT_MOD nodes with a power of 2
+// LowerSignedDivOrMod: transform integer GT_DIV/GT_MOD nodes with a power of 2
// const divisor into equivalent but faster sequences.
//
// Arguments:
@@ -3399,8 +3401,8 @@ void Lowering::LowerSignedDivOrMod(GenTreePtr* ppTree, Compiler::fgWalkData* dat
if (dividend->IsCnsIntOrI())
{
- // We shouldn't see a divmod with constant operands here but if we do then it's likely
- // because optimizations are disabled or it's a case that's supposed to throw an exception.
+ // We shouldn't see a divmod with constant operands here but if we do then it's likely
+ // because optimizations are disabled or it's a case that's supposed to throw an exception.
// Don't optimize this.
return;
}
@@ -3410,7 +3412,7 @@ void Lowering::LowerSignedDivOrMod(GenTreePtr* ppTree, Compiler::fgWalkData* dat
if (divisorValue == -1)
{
// x / -1 can't be optimized because INT_MIN / -1 is required to throw an exception.
-
+
// x % -1 is always 0 and the IL spec says that the rem instruction "can" throw an exception if x is
// the minimum representable integer. However, the C# spec says that an exception "is" thrown in this
// case so optimizing this case would break C# code.
@@ -3418,22 +3420,22 @@ void Lowering::LowerSignedDivOrMod(GenTreePtr* ppTree, Compiler::fgWalkData* dat
// A runtime check could be used to handle this case but it's probably too rare to matter.
return;
}
-
+
bool isDiv = divMod->OperGet() == GT_DIV;
if (isDiv)
{
- if ((type == TYP_INT && divisorValue == INT_MIN) ||
- (type == TYP_LONG && divisorValue == INT64_MIN))
+ if ((type == TYP_INT && divisorValue == INT_MIN) || (type == TYP_LONG && divisorValue == INT64_MIN))
{
- // If the divisor is the minimum representable integer value then we can use a compare,
+ // If the divisor is the minimum representable integer value then we can use a compare,
// the result is 1 iff the dividend equals divisor.
divMod->SetOper(GT_EQ);
return;
}
}
- size_t absDivisorValue = (divisorValue == SSIZE_T_MIN) ? static_cast<size_t>(divisorValue) : static_cast<size_t>(abs(divisorValue));
+ size_t absDivisorValue =
+ (divisorValue == SSIZE_T_MIN) ? static_cast<size_t>(divisorValue) : static_cast<size_t>(abs(divisorValue));
if (isPow2(absDivisorValue))
{
@@ -3442,14 +3444,12 @@ void Lowering::LowerSignedDivOrMod(GenTreePtr* ppTree, Compiler::fgWalkData* dat
CreateTemporary(&(divMod->gtOp.gtOp1));
dividend = divMod->gtGetOp1();
- GenTreeStmt* curStmt = comp->compCurStmt->AsStmt();
- unsigned curBBWeight = currBlock->getBBWeight(comp);
- unsigned dividendLclNum = dividend->gtLclVar.gtLclNum;
+ GenTreeStmt* curStmt = comp->compCurStmt->AsStmt();
+ unsigned curBBWeight = currBlock->getBBWeight(comp);
+ unsigned dividendLclNum = dividend->gtLclVar.gtLclNum;
- GenTree* adjustment = comp->gtNewOperNode(
- GT_RSH, type,
- dividend,
- comp->gtNewIconNode(type == TYP_INT ? 31 : 63));
+ GenTree* adjustment =
+ comp->gtNewOperNode(GT_RSH, type, dividend, comp->gtNewIconNode(type == TYP_INT ? 31 : 63));
if (absDivisorValue == 2)
{
@@ -3459,16 +3459,12 @@ void Lowering::LowerSignedDivOrMod(GenTreePtr* ppTree, Compiler::fgWalkData* dat
}
else
{
- adjustment = comp->gtNewOperNode(
- GT_AND, type,
- adjustment,
- comp->gtNewIconNode(absDivisorValue - 1, type));
+ adjustment =
+ comp->gtNewOperNode(GT_AND, type, adjustment, comp->gtNewIconNode(absDivisorValue - 1, type));
}
- GenTree* adjustedDividend = comp->gtNewOperNode(
- GT_ADD, type,
- adjustment,
- comp->gtNewLclvNode(dividendLclNum, type));
+ GenTree* adjustedDividend =
+ comp->gtNewOperNode(GT_ADD, type, adjustment, comp->gtNewLclvNode(dividendLclNum, type));
comp->lvaTable[dividendLclNum].incRefCnts(curBBWeight, comp);
@@ -3479,17 +3475,12 @@ void Lowering::LowerSignedDivOrMod(GenTreePtr* ppTree, Compiler::fgWalkData* dat
// perform the division by right shifting the adjusted dividend
divisor->gtIntCon.SetIconValue(genLog2(absDivisorValue));
- newDivMod = comp->gtNewOperNode(
- GT_RSH, type,
- adjustedDividend,
- divisor);
+ newDivMod = comp->gtNewOperNode(GT_RSH, type, adjustedDividend, divisor);
if (divisorValue < 0)
{
// negate the result if the divisor is negative
- newDivMod = comp->gtNewOperNode(
- GT_NEG, type,
- newDivMod);
+ newDivMod = comp->gtNewOperNode(GT_NEG, type, newDivMod);
}
}
else
@@ -3499,18 +3490,13 @@ void Lowering::LowerSignedDivOrMod(GenTreePtr* ppTree, Compiler::fgWalkData* dat
// which simply discards the low log2(divisor) bits, that's just dividend & ~(divisor - 1)
divisor->gtIntCon.SetIconValue(~(absDivisorValue - 1));
- newDivMod = comp->gtNewOperNode(
- GT_SUB, type,
- comp->gtNewLclvNode(dividendLclNum, type),
- comp->gtNewOperNode(
- GT_AND, type,
- adjustedDividend,
- divisor));
+ newDivMod = comp->gtNewOperNode(GT_SUB, type, comp->gtNewLclvNode(dividendLclNum, type),
+ comp->gtNewOperNode(GT_AND, type, adjustedDividend, divisor));
comp->lvaTable[dividendLclNum].incRefCnts(curBBWeight, comp);
}
- // Remove the divisor and dividend nodes from the linear order,
+ // Remove the divisor and dividend nodes from the linear order,
// since we have reused them and will resequence the tree
comp->fgSnipNode(curStmt, divisor);
comp->fgSnipNode(curStmt, dividend);
@@ -3540,8 +3526,8 @@ void Lowering::LowerSignedDivOrMod(GenTreePtr* ppTree, Compiler::fgWalkData* dat
void Lowering::LowerInd(GenTreePtr* pTree)
{
- GenTreePtr newNode = NULL;
- GenTreePtr cTree = *pTree;
+ GenTreePtr newNode = nullptr;
+ GenTreePtr cTree = *pTree;
JITDUMP("\n");
DISPNODE(cTree);
@@ -3550,12 +3536,14 @@ void Lowering::LowerInd(GenTreePtr* pTree)
GenTreePtr before = cTree;
if (cTree->OperGet() == GT_STOREIND && !cTree->IsReverseOp())
+ {
before = comp->fgGetFirstNode(cTree->gtGetOp2());
+ }
LowerAddrMode(&cTree->gtOp.gtOp1, before, nullptr, true);
// Mark all GT_STOREIND nodes to indicate that it is not known
- // whether it represents a RMW memory op.
+ // whether it represents a RMW memory op.
if (cTree->OperGet() == GT_STOREIND)
{
cTree->AsStoreInd()->SetRMWStatusDefault();
@@ -3605,15 +3593,14 @@ void Lowering::LowerInd(GenTreePtr* pTree)
// reference to NewTemp), because that provides more accurate lifetimes.
// There may be 1, 2 or 3 dimensions, with 1, 2 or 3 arrMDIdx nodes, respectively.
-void
-Lowering::LowerArrElem(GenTree **ppTree, Compiler::fgWalkData* data)
+void Lowering::LowerArrElem(GenTree** ppTree, Compiler::fgWalkData* data)
{
- GenTreePtr tree = *ppTree;
+ GenTreePtr tree = *ppTree;
// This will assert if we don't have an ArrElem node
GenTreeArrElem* arrElem = tree->AsArrElem();
- Compiler* comp = data->compiler;
+ Compiler* comp = data->compiler;
GenTreePtr curStmt = comp->compCurStmt;
- unsigned char rank = arrElem->gtArrElem.gtArrRank;
+ unsigned char rank = arrElem->gtArrElem.gtArrRank;
JITDUMP("Lowering ArrElem\n");
JITDUMP("============\n");
@@ -3628,16 +3615,15 @@ Lowering::LowerArrElem(GenTree **ppTree, Compiler::fgWalkData* data)
// Split off the array object and store to a temporary variable.
GenTreeStmt* newStmt = comp->fgInsertEmbeddedFormTemp(&(arrElem->gtArrObj));
newStmt->gtFlags |= GTF_STMT_SKIP_LOWER;
- GenTreePtr stLclVar = newStmt->gtStmtExpr;
+ GenTreePtr stLclVar = newStmt->gtStmtExpr;
assert(stLclVar->OperIsLocalStore());
// If we have made a new top-level statement, and it has inherited any
// embedded statements from curStmt, they have not yet been lowered.
if (newStmt->gtStmtIsTopLevel())
{
- for (GenTreePtr nextEmbeddedStmt = newStmt->gtStmtNextIfEmbedded();
- nextEmbeddedStmt != nullptr;
- nextEmbeddedStmt = nextEmbeddedStmt->gtStmt.gtStmtNextIfEmbedded())
+ for (GenTreePtr nextEmbeddedStmt = newStmt->gtStmtNextIfEmbedded(); nextEmbeddedStmt != nullptr;
+ nextEmbeddedStmt = nextEmbeddedStmt->gtStmt.gtStmtNextIfEmbedded())
{
comp->compCurStmt = nextEmbeddedStmt;
comp->fgWalkTreePost(&nextEmbeddedStmt->gtStmt.gtStmtExpr, &Lowering::LowerNodeHelper, this, true);
@@ -3660,8 +3646,8 @@ Lowering::LowerArrElem(GenTree **ppTree, Compiler::fgWalkData* data)
if ((currIndexNode->gtFlags & GTF_SIDE_EFFECT) != 0)
{
// Split off this index computation and store to a temporary variable.
- GenTreeStmt* newStmt = comp->fgInsertEmbeddedFormTemp(&(arrElem->gtArrElem.gtArrInds[dim]));
- GenTreePtr stLclVar = newStmt->gtStmtExpr;
+ GenTreeStmt* newStmt = comp->fgInsertEmbeddedFormTemp(&(arrElem->gtArrElem.gtArrInds[dim]));
+ GenTreePtr stLclVar = newStmt->gtStmtExpr;
assert(stLclVar->OperIsLocalStore());
// We can't have made a new top-level statement, because we know we've got an ArrObj
// prior to the index nodes.
@@ -3673,12 +3659,12 @@ Lowering::LowerArrElem(GenTree **ppTree, Compiler::fgWalkData* data)
}
// The first ArrOffs node will have 0 for the offset of the previous dimension.
- GenTree* prevArrOffs = new(comp, GT_CNS_INT) GenTreeIntCon(TYP_I_IMPL, 0);
+ GenTree* prevArrOffs = new (comp, GT_CNS_INT) GenTreeIntCon(TYP_I_IMPL, 0);
comp->fgInsertLinearNodeBefore(prevArrOffs, arrObjNode);
for (unsigned char dim = 0; dim < rank; dim++)
{
- GenTree* currIndexTree = arrElem->gtArrElem.gtArrInds[dim];
+ GenTree* currIndexTree = arrElem->gtArrElem.gtArrInds[dim];
GenTree* insertBeforeNode = nextNode;
// Use the original arrObjNode on the 0th ArrIndex node, and clone it for subsequent ones.
@@ -3698,9 +3684,9 @@ Lowering::LowerArrElem(GenTree **ppTree, Compiler::fgWalkData* data)
if (currIndexTree->gtNext != insertBeforeNode)
{
GenTree* firstIndexNode = comp->fgGetFirstNode(currIndexTree);
- GenTree* oldPrevNode = firstIndexNode->gtPrev;
- GenTree* oldNextNode = currIndexTree->gtNext;
- GenTree* newPrevNode = insertBeforeNode->gtPrev;
+ GenTree* oldPrevNode = firstIndexNode->gtPrev;
+ GenTree* oldNextNode = currIndexTree->gtNext;
+ GenTree* newPrevNode = insertBeforeNode->gtPrev;
// All these are inner nodes, so they cannot be null.
assert(oldPrevNode != nullptr && oldNextNode != nullptr && newPrevNode != nullptr);
@@ -3708,46 +3694,49 @@ Lowering::LowerArrElem(GenTree **ppTree, Compiler::fgWalkData* data)
oldNextNode->gtPrev = oldPrevNode;
firstIndexNode->gtPrev = newPrevNode;
- newPrevNode->gtNext = firstIndexNode;
+ newPrevNode->gtNext = firstIndexNode;
- currIndexTree->gtNext = insertBeforeNode;
+ currIndexTree->gtNext = insertBeforeNode;
insertBeforeNode->gtPrev = currIndexTree;
}
// Next comes the GT_ARR_INDEX node.
- GenTreeArrIndex* arrMDIdx = new(comp, GT_ARR_INDEX)
+ GenTreeArrIndex* arrMDIdx = new (comp, GT_ARR_INDEX)
GenTreeArrIndex(TYP_INT, idxArrObjNode, currIndexTree, dim, rank, arrElem->gtArrElem.gtArrElemType);
- arrMDIdx->gtFlags |= ((idxArrObjNode->gtFlags|currIndexTree->gtFlags) & GTF_ALL_EFFECT);
+ arrMDIdx->gtFlags |= ((idxArrObjNode->gtFlags | currIndexTree->gtFlags) & GTF_ALL_EFFECT);
comp->fgInsertLinearNodeBefore(arrMDIdx, insertBeforeNode);
GenTree* offsArrObjNode = comp->gtClone(arrObjNode);
comp->fgInsertLinearNodeBefore(offsArrObjNode, insertBeforeNode);
- GenTreeArrOffs* arrOffs = new(comp, GT_ARR_OFFSET)
- GenTreeArrOffs(TYP_I_IMPL, prevArrOffs, arrMDIdx, offsArrObjNode, dim, rank, arrElem->gtArrElem.gtArrElemType);
+ GenTreeArrOffs* arrOffs =
+ new (comp, GT_ARR_OFFSET) GenTreeArrOffs(TYP_I_IMPL, prevArrOffs, arrMDIdx, offsArrObjNode, dim, rank,
+ arrElem->gtArrElem.gtArrElemType);
comp->fgInsertLinearNodeBefore(arrOffs, insertBeforeNode);
- arrOffs->gtFlags |= ((prevArrOffs->gtFlags|arrMDIdx->gtFlags|offsArrObjNode->gtFlags) & GTF_ALL_EFFECT);
+ arrOffs->gtFlags |= ((prevArrOffs->gtFlags | arrMDIdx->gtFlags | offsArrObjNode->gtFlags) & GTF_ALL_EFFECT);
prevArrOffs = arrOffs;
}
- // Generate the LEA and make it reverse evaluation, because we want to evaluate the index expression before the base.
+ // Generate the LEA and make it reverse evaluation, because we want to evaluate the index expression before the
+ // base.
GenTreePtr leaBase = comp->gtClone(arrObjNode);
- unsigned scale = arrElem->gtArrElem.gtArrElemSize;
- unsigned offset = comp->eeGetMDArrayDataOffset(arrElem->gtArrElem.gtArrElemType, arrElem->gtArrElem.gtArrRank);
+ unsigned scale = arrElem->gtArrElem.gtArrElemSize;
+ unsigned offset = comp->eeGetMDArrayDataOffset(arrElem->gtArrElem.gtArrElemType, arrElem->gtArrElem.gtArrRank);
GenTreePtr leaIndexNode = prevArrOffs;
if (!jitIsScaleIndexMul(scale))
{
- // We do the address arithmetic in TYP_I_IMPL, though note that the lower bounds and lengths in memory are TYP_INT
- GenTreePtr scaleNode = new(comp, GT_CNS_INT) GenTreeIntCon(TYP_I_IMPL, scale);
- GenTreePtr mulNode = new(comp, GT_MUL) GenTreeOp(GT_MUL, TYP_I_IMPL, leaIndexNode, scaleNode);
+ // We do the address arithmetic in TYP_I_IMPL, though note that the lower bounds and lengths in memory are
+ // TYP_INT
+ GenTreePtr scaleNode = new (comp, GT_CNS_INT) GenTreeIntCon(TYP_I_IMPL, scale);
+ GenTreePtr mulNode = new (comp, GT_MUL) GenTreeOp(GT_MUL, TYP_I_IMPL, leaIndexNode, scaleNode);
comp->fgInsertLinearNodeBefore(scaleNode, nextNode);
comp->fgInsertLinearNodeBefore(mulNode, nextNode);
leaIndexNode = mulNode;
- scale = 1;
+ scale = 1;
}
comp->fgInsertLinearNodeBefore(leaBase, nextNode);
- GenTreePtr leaNode = new(comp, GT_LEA) GenTreeAddrMode(arrElem->TypeGet(), leaBase, leaIndexNode, scale, offset);
+ GenTreePtr leaNode = new (comp, GT_LEA) GenTreeAddrMode(arrElem->TypeGet(), leaBase, leaIndexNode, scale, offset);
leaNode->gtFlags |= GTF_REVERSE_OPS;
comp->fgInsertLinearNodeBefore(leaNode, nextNode);
@@ -3762,7 +3751,7 @@ Lowering::LowerArrElem(GenTree **ppTree, Compiler::fgWalkData* data)
// We can have a top-level GT_ARR_ELEM. For example, a function call
// with a parameter of GT_ARR_ELEM can end up being simplified by the
// inliner to single GT_ARR_ELEM node if the function has an empty body.
- arrElem->gtPrev->gtNext = nullptr;
+ arrElem->gtPrev->gtNext = nullptr;
curStmt->gtStmt.gtStmtExpr = *ppTree;
}
@@ -3807,23 +3796,23 @@ void Lowering::DoPhase()
#endif
#if !defined(_TARGET_64BIT_)
- DecomposeLongs decomp(comp); // Initialize the long decomposition class.
+ DecomposeLongs decomp(comp); // Initialize the long decomposition class.
decomp.PrepareForDecomposition();
#endif // !defined(_TARGET_64BIT_)
for (BasicBlock* block = comp->fgFirstBB; block; block = block->bbNext)
{
- GenTreePtr stmt;
+ GenTreePtr stmt;
/* Make the block publicly available */
- currBlock = block;
+ currBlock = block;
comp->compCurBB = block;
#if !defined(_TARGET_64BIT_)
decomp.DecomposeBlock(block);
#endif //!_TARGET_64BIT_
- // Walk the statement trees in this basic block
+ // Walk the statement trees in this basic block
for (stmt = block->bbTreeList; stmt; stmt = stmt->gtNext)
{
if (stmt->gtFlags & GTF_STMT_SKIP_LOWER)
@@ -3873,10 +3862,10 @@ void Lowering::DoPhase()
comp->fgLocalVarLiveness();
// local var liveness can delete code, which may create empty blocks
- if (!comp->opts.MinOpts() && !comp->opts.compDbgCode)
+ if (!comp->opts.MinOpts() && !comp->opts.compDbgCode)
{
comp->optLoopsMarked = false;
- bool modified = comp->fgUpdateFlowGraph();
+ bool modified = comp->fgUpdateFlowGraph();
if (modified || comp->lvaSortAgain)
{
JITDUMP("had to run another liveness pass:\n");
@@ -3911,9 +3900,7 @@ void Lowering::DoPhase()
// It's also desirable to avoid initializing this code using a non-execution order traversal.
//
LsraLocation currentLoc = 1;
- for( BasicBlock* block = m_lsra->startBlockSequence();
- block != nullptr;
- block = m_lsra->moveToNextBlock())
+ for (BasicBlock* block = m_lsra->startBlockSequence(); block != nullptr; block = m_lsra->moveToNextBlock())
{
GenTreePtr stmt;
@@ -3925,7 +3912,9 @@ void Lowering::DoPhase()
for (stmt = block->FirstNonPhiDef(); stmt; stmt = stmt->gtNext)
{
if (stmt->gtStmt.gtStmtIsEmbedded())
+ {
continue;
+ }
/* We increment the number position of each tree node by 2 to
* simplify the logic when there's the case of a tree that implicitly
@@ -3950,7 +3939,9 @@ void Lowering::DoPhase()
for (stmt = block->FirstNonPhiDef(); stmt; stmt = stmt->gtNext)
{
if (stmt->gtStmt.gtStmtIsEmbedded())
+ {
continue;
+ }
comp->compCurStmt = stmt;
@@ -3970,7 +3961,7 @@ void Lowering::DoPhase()
else if (comp->optIsTrackedLocal(tree))
{
tree->gtLsraInfo.isLocalDefUse = true;
- tree->gtLsraInfo.dstCount = 0;
+ tree->gtLsraInfo.dstCount = 0;
}
#if 0
// TODO-CQ: Enable this code after fixing the isContained() logic to not abort for these
@@ -4009,53 +4000,56 @@ void Lowering::DoPhase()
bool Lowering::IndirsAreEquivalent(GenTreePtr candidate, GenTreePtr storeInd)
{
assert(candidate->OperGet() == GT_IND);
- assert(storeInd->OperGet() == GT_STOREIND);
-
+ assert(storeInd->OperGet() == GT_STOREIND);
+
// We should check the size of the indirections. If they are
// different, say because of a cast, then we can't call them equivalent. Doing so could cause us
// to drop a cast.
- // Signed-ness difference is okay and expected since a store indirection must always
+ // Signed-ness difference is okay and expected since a store indirection must always
// be signed based on the CIL spec, but a load could be unsigned.
if (genTypeSize(candidate->gtType) != genTypeSize(storeInd->gtType))
+ {
return false;
-
+ }
+
GenTreePtr pTreeA = candidate->gtGetOp1();
GenTreePtr pTreeB = storeInd->gtGetOp1();
-
+
// This method will be called by codegen (as well as during lowering).
// After register allocation, the sources may have been spilled and reloaded
// to a different register, indicated by an inserted GT_RELOAD node.
pTreeA = pTreeA->gtSkipReloadOrCopy();
pTreeB = pTreeB->gtSkipReloadOrCopy();
- genTreeOps oper;
- unsigned kind;
+ genTreeOps oper;
+ unsigned kind;
if (pTreeA->OperGet() != pTreeB->OperGet())
+ {
return false;
+ }
oper = pTreeA->OperGet();
switch (oper)
{
- case GT_LCL_VAR:
- case GT_LCL_VAR_ADDR:
- case GT_CLS_VAR_ADDR:
- case GT_CNS_INT:
- return NodesAreEquivalentLeaves(pTreeA, pTreeB);
+ case GT_LCL_VAR:
+ case GT_LCL_VAR_ADDR:
+ case GT_CLS_VAR_ADDR:
+ case GT_CNS_INT:
+ return NodesAreEquivalentLeaves(pTreeA, pTreeB);
- case GT_LEA:
+ case GT_LEA:
{
GenTreeAddrMode* gtAddr1 = pTreeA->AsAddrMode();
GenTreeAddrMode* gtAddr2 = pTreeB->AsAddrMode();
return NodesAreEquivalentLeaves(gtAddr1->Base(), gtAddr2->Base()) &&
- NodesAreEquivalentLeaves(gtAddr1->Index(), gtAddr2->Index()) &&
- gtAddr1->gtScale == gtAddr2->gtScale &&
- gtAddr1->gtOffset == gtAddr2->gtOffset;
+ NodesAreEquivalentLeaves(gtAddr1->Index(), gtAddr2->Index()) &&
+ gtAddr1->gtScale == gtAddr2->gtScale && gtAddr1->gtOffset == gtAddr2->gtOffset;
}
- default:
- // We don't handle anything that is not either a constant,
- // a local var or LEA.
- return false;
+ default:
+ // We don't handle anything that is not either a constant,
+ // a local var or LEA.
+ return false;
}
}
@@ -4065,36 +4059,46 @@ bool Lowering::IndirsAreEquivalent(GenTreePtr candidate, GenTreePtr storeInd)
bool Lowering::NodesAreEquivalentLeaves(GenTreePtr tree1, GenTreePtr tree2)
{
if (tree1 == nullptr && tree2 == nullptr)
+ {
return true;
+ }
// both null, they are equivalent, otherwise if either is null not equivalent
if (tree1 == nullptr || tree2 == nullptr)
+ {
return false;
+ }
tree1 = tree1->gtSkipReloadOrCopy();
tree2 = tree2->gtSkipReloadOrCopy();
if (tree1->TypeGet() != tree2->TypeGet())
+ {
return false;
+ }
if (tree1->OperGet() != tree2->OperGet())
+ {
return false;
+ }
if (!tree1->OperIsLeaf() || !tree2->OperIsLeaf())
+ {
return false;
+ }
switch (tree1->OperGet())
{
- case GT_CNS_INT:
- return tree1->gtIntCon.gtIconVal == tree2->gtIntCon.gtIconVal &&
- tree1->IsIconHandle() == tree2->IsIconHandle();
- case GT_LCL_VAR:
- case GT_LCL_VAR_ADDR:
- return tree1->gtLclVarCommon.gtLclNum == tree2->gtLclVarCommon.gtLclNum;
- case GT_CLS_VAR_ADDR:
- return tree1->gtClsVar.gtClsVarHnd == tree2->gtClsVar.gtClsVarHnd;
- default:
- return false;
+ case GT_CNS_INT:
+ return tree1->gtIntCon.gtIconVal == tree2->gtIntCon.gtIconVal &&
+ tree1->IsIconHandle() == tree2->IsIconHandle();
+ case GT_LCL_VAR:
+ case GT_LCL_VAR_ADDR:
+ return tree1->gtLclVarCommon.gtLclNum == tree2->gtLclVarCommon.gtLclNum;
+ case GT_CLS_VAR_ADDR:
+ return tree1->gtClsVar.gtClsVarHnd == tree2->gtClsVar.gtClsVarHnd;
+ default:
+ return false;
}
}
@@ -4119,7 +4123,7 @@ void Lowering::ReplaceNode(GenTree** ppTreeLocation, GenTree* replacementNode, G
JITDUMP("The node that replaces it is:\n");
DISPTREE(replacementNode);
- assert(comp->fgStmtContainsNode((GenTreeStmt*) stmt, treeLocation));
+ assert(comp->fgStmtContainsNode((GenTreeStmt*)stmt, treeLocation));
GenTreePtr first = comp->fgGetFirstNode(treeLocation);
comp->fgRemoveContainedEmbeddedStatements(treeLocation, stmt->AsStmt(), block);
@@ -4157,7 +4161,7 @@ void Lowering::ReplaceNode(GenTree** ppTreeLocation, GenTree* replacementNode, G
}
replacementNode->gtNext = gtNext;
- treeLocation = replacementNode;
+ treeLocation = replacementNode;
#ifdef DEBUG
comp->fgDebugCheckLinks();
#endif
@@ -4175,7 +4179,6 @@ void Lowering::UnlinkNode(GenTree** ppParentLink, GenTree* stmt, BasicBlock* blo
ReplaceNode(ppParentLink, comp->gtNewNothingNode(), stmt, block);
}
-
#ifdef _TARGET_64BIT_
/**
* Get common information required to handle a cast instruction
@@ -4194,87 +4197,88 @@ void Lowering::getCastDescription(GenTreePtr treeNode, CastInfo* castInfo)
var_types dstType = treeNode->CastToType();
var_types srcType = castOp->TypeGet();
- castInfo->unsignedDest = varTypeIsUnsigned(dstType);
+ castInfo->unsignedDest = varTypeIsUnsigned(dstType);
castInfo->unsignedSource = varTypeIsUnsigned(srcType);
// If necessary, force the srcType to unsigned when the GT_UNSIGNED flag is set.
if (!castInfo->unsignedSource && (treeNode->gtFlags & GTF_UNSIGNED) != 0)
{
- srcType = genUnsignedType(srcType);
+ srcType = genUnsignedType(srcType);
castInfo->unsignedSource = true;
}
- if (treeNode->gtOverflow() && (genTypeSize(srcType) >= genTypeSize(dstType) || (srcType == TYP_INT && dstType == TYP_ULONG)))
+ if (treeNode->gtOverflow() &&
+ (genTypeSize(srcType) >= genTypeSize(dstType) || (srcType == TYP_INT && dstType == TYP_ULONG)))
{
castInfo->requiresOverflowCheck = true;
}
if (castInfo->requiresOverflowCheck)
{
- ssize_t typeMin = 0;
- ssize_t typeMax = 0;
- ssize_t typeMask = 0;
- bool signCheckOnly = false;
+ ssize_t typeMin = 0;
+ ssize_t typeMax = 0;
+ ssize_t typeMask = 0;
+ bool signCheckOnly = false;
// Do we need to compare the value, or just check masks
switch (dstType)
{
- default:
- assert(!"unreachable: getCastDescription");
- break;
+ default:
+ assert(!"unreachable: getCastDescription");
+ break;
- case TYP_BYTE:
- typeMask = ssize_t((int)0xFFFFFF80);
- typeMin = SCHAR_MIN;
- typeMax = SCHAR_MAX;
- break;
+ case TYP_BYTE:
+ typeMask = ssize_t((int)0xFFFFFF80);
+ typeMin = SCHAR_MIN;
+ typeMax = SCHAR_MAX;
+ break;
- case TYP_UBYTE:
- typeMask = ssize_t((int)0xFFFFFF00L);
- break;
+ case TYP_UBYTE:
+ typeMask = ssize_t((int)0xFFFFFF00L);
+ break;
- case TYP_SHORT:
- typeMask = ssize_t((int)0xFFFF8000);
- typeMin = SHRT_MIN;
- typeMax = SHRT_MAX;
- break;
+ case TYP_SHORT:
+ typeMask = ssize_t((int)0xFFFF8000);
+ typeMin = SHRT_MIN;
+ typeMax = SHRT_MAX;
+ break;
- case TYP_CHAR:
- typeMask = ssize_t((int)0xFFFF0000L);
- break;
+ case TYP_CHAR:
+ typeMask = ssize_t((int)0xFFFF0000L);
+ break;
- case TYP_INT:
- if (srcType == TYP_UINT)
- {
- signCheckOnly = true;
- }
- else
- {
- typeMask = 0xFFFFFFFF80000000LL;
- typeMin = INT_MIN;
- typeMax = INT_MAX;
- }
- break;
+ case TYP_INT:
+ if (srcType == TYP_UINT)
+ {
+ signCheckOnly = true;
+ }
+ else
+ {
+ typeMask = 0xFFFFFFFF80000000LL;
+ typeMin = INT_MIN;
+ typeMax = INT_MAX;
+ }
+ break;
- case TYP_UINT:
- if (srcType == TYP_INT)
- {
- signCheckOnly = true;
- }
- else
- {
- typeMask = 0xFFFFFFFF00000000LL;
- }
- break;
+ case TYP_UINT:
+ if (srcType == TYP_INT)
+ {
+ signCheckOnly = true;
+ }
+ else
+ {
+ typeMask = 0xFFFFFFFF00000000LL;
+ }
+ break;
- case TYP_LONG:
- signCheckOnly = true;
- break;
+ case TYP_LONG:
+ signCheckOnly = true;
+ break;
- case TYP_ULONG:
- signCheckOnly = true;
- break;
+ case TYP_ULONG:
+ signCheckOnly = true;
+ break;
}
if (signCheckOnly)
@@ -4282,8 +4286,8 @@ void Lowering::getCastDescription(GenTreePtr treeNode, CastInfo* castInfo)
castInfo->signCheckOnly = true;
}
- castInfo->typeMax = typeMax;
- castInfo->typeMin = typeMin;
+ castInfo->typeMax = typeMax;
+ castInfo->typeMin = typeMin;
castInfo->typeMask = typeMask;
}
}
@@ -4300,14 +4304,17 @@ void Lowering::DumpNodeInfoMap()
for (BasicBlock* block = comp->fgFirstBB; block; block = block->bbNext)
{
- GenTreePtr stmt;
- GenTreePtr tree;
+ GenTreePtr stmt;
+ GenTreePtr tree;
for (stmt = block->FirstNonPhiDef(); stmt; stmt = stmt->gtNext)
{
GenTreePtr node;
foreach_treenode_execution_order(node, stmt)
{
- if (stmt->gtStmt.gtStmtIsEmbedded()) continue;
+ if (stmt->gtStmt.gtStmtIsEmbedded())
+ {
+ continue;
+ }
comp->gtDispTree(node, nullptr, nullptr, true);
printf(" +");
node->gtLsraInfo.dump(m_lsra);