summaryrefslogtreecommitdiff
path: root/src/jit/morph.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/jit/morph.cpp')
-rw-r--r--src/jit/morph.cpp77
1 files changed, 53 insertions, 24 deletions
diff --git a/src/jit/morph.cpp b/src/jit/morph.cpp
index f63496b686..6928c3c393 100644
--- a/src/jit/morph.cpp
+++ b/src/jit/morph.cpp
@@ -6099,7 +6099,7 @@ GenTreePtr Compiler::fgMorphStackArgForVarArgs(unsigned lclNum, var_types varTyp
* Transform the given GT_LCL_VAR tree for code generation.
*/
-GenTreePtr Compiler::fgMorphLocalVar(GenTreePtr tree)
+GenTreePtr Compiler::fgMorphLocalVar(GenTreePtr tree, bool forceRemorph)
{
noway_assert(tree->gtOper == GT_LCL_VAR);
@@ -6129,7 +6129,7 @@ GenTreePtr Compiler::fgMorphLocalVar(GenTreePtr tree)
/* If not during the global morphing phase bail */
- if (!fgGlobalMorph)
+ if (!fgGlobalMorph && !forceRemorph)
{
return tree;
}
@@ -6560,6 +6560,13 @@ GenTreePtr Compiler::fgMorphField(GenTreePtr tree, MorphAddrContext* mac)
GenTreePtr tlsRef = gtNewIconHandleNode(WIN32_TLS_SLOTS, GTF_ICON_TLS_HDL);
+ // Translate GTF_FLD_INITCLASS to GTF_ICON_INITCLASS
+ if ((tree->gtFlags & GTF_FLD_INITCLASS) != 0)
+ {
+ tree->gtFlags &= ~GTF_FLD_INITCLASS;
+ tlsRef->gtFlags |= GTF_ICON_INITCLASS;
+ }
+
tlsRef = gtNewOperNode(GT_IND, TYP_I_IMPL, tlsRef);
if (dllRef != nullptr)
@@ -6614,6 +6621,12 @@ GenTreePtr Compiler::fgMorphField(GenTreePtr tree, MorphAddrContext* mac)
FieldSeqNode* fieldSeq =
fieldMayOverlap ? FieldSeqStore::NotAField() : GetFieldSeqStore()->CreateSingleton(symHnd);
addr->gtIntCon.gtFieldSeq = fieldSeq;
+ // Translate GTF_FLD_INITCLASS to GTF_ICON_INITCLASS
+ if ((tree->gtFlags & GTF_FLD_INITCLASS) != 0)
+ {
+ tree->gtFlags &= ~GTF_FLD_INITCLASS;
+ addr->gtFlags |= GTF_ICON_INITCLASS;
+ }
tree->SetOper(GT_IND);
// The GTF_FLD_NULLCHECK is the same bit as GTF_IND_ARR_LEN.
@@ -6628,9 +6641,10 @@ GenTreePtr Compiler::fgMorphField(GenTreePtr tree, MorphAddrContext* mac)
else
#endif // _TARGET_64BIT_
{
- // Only volatile could be set, and it maps over
- noway_assert((tree->gtFlags & ~(GTF_FLD_VOLATILE | GTF_COMMON_MASK)) == 0);
- noway_assert(GTF_FLD_VOLATILE == GTF_IND_VOLATILE);
+ // Only volatile or classinit could be set, and they map over
+ noway_assert((tree->gtFlags & ~(GTF_FLD_VOLATILE | GTF_FLD_INITCLASS | GTF_COMMON_MASK)) == 0);
+ static_assert_no_msg(GTF_FLD_VOLATILE == GTF_CLS_VAR_VOLATILE);
+ static_assert_no_msg(GTF_FLD_INITCLASS == GTF_CLS_VAR_INITCLASS);
tree->SetOper(GT_CLS_VAR);
tree->gtClsVar.gtClsVarHnd = symHnd;
FieldSeqNode* fieldSeq =
@@ -6644,6 +6658,13 @@ GenTreePtr Compiler::fgMorphField(GenTreePtr tree, MorphAddrContext* mac)
{
GenTreePtr addr = gtNewIconHandleNode((size_t)pFldAddr, GTF_ICON_STATIC_HDL);
+ // Translate GTF_FLD_INITCLASS to GTF_ICON_INITCLASS
+ if ((tree->gtFlags & GTF_FLD_INITCLASS) != 0)
+ {
+ tree->gtFlags &= ~GTF_FLD_INITCLASS;
+ addr->gtFlags |= GTF_ICON_INITCLASS;
+ }
+
// There are two cases here, either the static is RVA based,
// in which case the type of the FIELD node is not a GC type
// and the handle to the RVA is a TYP_I_IMPL. Or the FIELD node is
@@ -8522,7 +8543,8 @@ GenTreePtr Compiler::fgMorphLeaf(GenTreePtr tree)
if (tree->gtOper == GT_LCL_VAR)
{
- return fgMorphLocalVar(tree);
+ const bool forceRemorph = false;
+ return fgMorphLocalVar(tree, forceRemorph);
}
#ifdef _TARGET_X86_
else if (tree->gtOper == GT_LCL_FLD)
@@ -13132,26 +13154,14 @@ GenTreePtr Compiler::fgMorphSmpOp(GenTreePtr tree, MorphAddrContext* mac)
varTypeIsStruct(tempTyp) || (tempTyp == TYP_BLK) || (tempTyp == TYP_LCLBLK);
const unsigned varSize = useExactSize ? varDsc->lvExactSize : genTypeSize(temp);
+ // Make sure we do not enregister this lclVar.
+ lvaSetVarDoNotEnregister(lclNum DEBUGARG(DNER_LocalField));
+
// If the size of the load is greater than the size of the lclVar, we cannot fold this access into
// a lclFld: the access represented by an lclFld node must begin at or after the start of the
// lclVar and must not extend beyond the end of the lclVar.
- if ((ival1 < 0) || ((ival1 + genTypeSize(typ)) > varSize))
- {
- lvaSetVarDoNotEnregister(lclNum DEBUGARG(DNER_LocalField));
- }
- else
+ if ((ival1 >= 0) && ((ival1 + genTypeSize(typ)) <= varSize))
{
- // Make sure we don't separately promote the fields of this struct.
- if (varDsc->lvRegStruct)
- {
- // We can enregister, but can't promote.
- varDsc->lvPromoted = false;
- }
- else
- {
- lvaSetVarDoNotEnregister(lclNum DEBUGARG(DNER_LocalField));
- }
-
// We will turn a GT_LCL_VAR into a GT_LCL_FLD with an gtLclOffs of 'ival'
// or if we already have a GT_LCL_FLD we will adjust the gtLclOffs by adding 'ival'
// Then we change the type of the GT_LCL_FLD to match the orginal GT_IND type.
@@ -13195,6 +13205,25 @@ GenTreePtr Compiler::fgMorphSmpOp(GenTreePtr tree, MorphAddrContext* mac)
DEBUG_DESTROY_NODE(op1); // GT_ADD or GT_ADDR
DEBUG_DESTROY_NODE(tree); // GT_IND
+ // If the result of the fold is a local var, we may need to perform further adjustments e.g. for
+ // normalization.
+ if (temp->OperIs(GT_LCL_VAR))
+ {
+#ifdef DEBUG
+ // We clear this flag on `temp` because `fgMorphLocalVar` may assert that this bit is clear
+ // and the node in question must have this bit set (as it has already been morphed).
+ temp->gtDebugFlags &= ~GTF_DEBUG_NODE_MORPHED;
+#endif // DEBUG
+ const bool forceRemorph = true;
+ temp = fgMorphLocalVar(temp, forceRemorph);
+#ifdef DEBUG
+ // We then set this flag on `temp` because `fgMorhpLocalVar` may not set it itself, and the
+ // caller of `fgMorphSmpOp` may assert that this flag is set on `temp` once this function
+ // returns.
+ temp->gtDebugFlags |= GTF_DEBUG_NODE_MORPHED;
+#endif // DEBUG
+ }
+
return temp;
}
@@ -13644,7 +13673,7 @@ GenTree* Compiler::fgMorphSmpOpOptional(GenTreeOp* tree)
GenTree* op2 = tree->gtOp2;
var_types typ = tree->TypeGet();
- if (GenTree::OperIsCommutative(oper))
+ if (fgGlobalMorph && GenTree::OperIsCommutative(oper))
{
/* Swap the operands so that the more expensive one is 'op1' */
@@ -13682,7 +13711,7 @@ GenTree* Compiler::fgMorphSmpOpOptional(GenTreeOp* tree)
/* Change "((x+icon)+y)" to "((x+y)+icon)"
Don't reorder floating-point operations */
- if ((oper == GT_ADD) && !tree->gtOverflow() && (op1->gtOper == GT_ADD) && !op1->gtOverflow() &&
+ if (fgGlobalMorph && (oper == GT_ADD) && !tree->gtOverflow() && (op1->gtOper == GT_ADD) && !op1->gtOverflow() &&
varTypeIsIntegralOrI(typ))
{
GenTreePtr ad2 = op1->gtOp.gtOp2;