summaryrefslogtreecommitdiff
path: root/src/jit/gentree.h
diff options
context:
space:
mode:
authorJiyoung Yun <jy910.yun@samsung.com>2017-04-13 14:17:19 +0900
committerJiyoung Yun <jy910.yun@samsung.com>2017-04-13 14:17:19 +0900
commita56e30c8d33048216567753d9d3fefc2152af8ac (patch)
tree7e5d979695fc4a431740982eb1cfecc2898b23a5 /src/jit/gentree.h
parent4b11dc566a5bbfa1378d6266525c281b028abcc8 (diff)
downloadcoreclr-a56e30c8d33048216567753d9d3fefc2152af8ac.tar.gz
coreclr-a56e30c8d33048216567753d9d3fefc2152af8ac.tar.bz2
coreclr-a56e30c8d33048216567753d9d3fefc2152af8ac.zip
Imported Upstream version 2.0.0.11353upstream/2.0.0.11353
Diffstat (limited to 'src/jit/gentree.h')
-rw-r--r--src/jit/gentree.h288
1 files changed, 167 insertions, 121 deletions
diff --git a/src/jit/gentree.h b/src/jit/gentree.h
index 0ea8321e77..1d52248657 100644
--- a/src/jit/gentree.h
+++ b/src/jit/gentree.h
@@ -120,6 +120,8 @@ enum genTreeKinds
GTK_NOVALUE = 0x0400, // node does not produce a value
GTK_NOTLIR = 0x0800, // node is not allowed in LIR
+ GTK_NOCONTAIN = 0x1000, // this node is a value, but may not be contained
+
/* Define composite value(s) */
GTK_SMPOP = (GTK_UNOP | GTK_BINOP | GTK_RELOP | GTK_LOGOP)
@@ -147,6 +149,61 @@ struct BasicBlock;
struct InlineCandidateInfo;
+typedef unsigned short AssertionIndex;
+
+static const AssertionIndex NO_ASSERTION_INDEX = 0;
+
+class AssertionInfo
+{
+ // true if the assertion holds on the bbNext edge instead of the bbJumpDest edge (for GT_JTRUE nodes)
+ unsigned short m_isNextEdgeAssertion : 1;
+ // 1-based index of the assertion
+ unsigned short m_assertionIndex : 15;
+
+ AssertionInfo(bool isNextEdgeAssertion, AssertionIndex assertionIndex)
+ : m_isNextEdgeAssertion(isNextEdgeAssertion), m_assertionIndex(assertionIndex)
+ {
+ assert(m_assertionIndex == assertionIndex);
+ }
+
+public:
+ AssertionInfo() : AssertionInfo(false, 0)
+ {
+ }
+
+ AssertionInfo(AssertionIndex assertionIndex) : AssertionInfo(false, assertionIndex)
+ {
+ }
+
+ static AssertionInfo ForNextEdge(AssertionIndex assertionIndex)
+ {
+ // Ignore the edge information if there's no assertion
+ bool isNextEdge = (assertionIndex != NO_ASSERTION_INDEX);
+ return AssertionInfo(isNextEdge, assertionIndex);
+ }
+
+ void Clear()
+ {
+ m_isNextEdgeAssertion = 0;
+ m_assertionIndex = NO_ASSERTION_INDEX;
+ }
+
+ bool HasAssertion() const
+ {
+ return m_assertionIndex != NO_ASSERTION_INDEX;
+ }
+
+ AssertionIndex GetAssertionIndex() const
+ {
+ return m_assertionIndex;
+ }
+
+ bool IsNextEdgeAssertion() const
+ {
+ return m_isNextEdgeAssertion;
+ }
+};
+
/*****************************************************************************/
// GT_FIELD nodes will be lowered into more "code-gen-able" representations, like
@@ -394,28 +451,27 @@ struct GenTree
unsigned char gtLIRFlags; // Used for nodes that are in LIR. See LIR::Flags in lir.h for the various flags.
#if ASSERTION_PROP
- unsigned short gtAssertionNum; // 0 or Assertion table index
- // valid only for non-GT_STMT nodes
+ AssertionInfo gtAssertionInfo; // valid only for non-GT_STMT nodes
- bool HasAssertion() const
+ bool GeneratesAssertion() const
{
- return gtAssertionNum != 0;
+ return gtAssertionInfo.HasAssertion();
}
+
void ClearAssertion()
{
- gtAssertionNum = 0;
+ gtAssertionInfo.Clear();
}
- unsigned short GetAssertion() const
+ AssertionInfo GetAssertionInfo() const
{
- return gtAssertionNum;
+ return gtAssertionInfo;
}
- void SetAssertion(unsigned short value)
+
+ void SetAssertionInfo(AssertionInfo info)
{
- assert((unsigned short)value == value);
- gtAssertionNum = (unsigned short)value;
+ gtAssertionInfo = info;
}
-
#endif
#if FEATURE_STACK_FP_X87
@@ -555,6 +611,8 @@ public:
__declspec(property(get = GetRegNum, put = SetRegNum)) regNumber gtRegNum;
+ bool canBeContained() const;
+
// for codegen purposes, is this node a subnode of its parent
bool isContained() const;
@@ -1852,6 +1910,10 @@ public:
{
return (gtFlags & GTF_REVERSE_OPS) ? true : false;
}
+ bool IsUnsigned() const
+ {
+ return ((gtFlags & GTF_UNSIGNED) != 0);
+ }
inline bool IsCnsIntOrI() const;
@@ -2051,19 +2113,22 @@ public:
};
//------------------------------------------------------------------------
-// GenTreeUseEdgeIterator: an iterator that will produce each use edge of a
-// GenTree node in the order in which they are
-// used. Note that the use edges of a node may not
-// correspond exactly to the nodes on the other
-// ends of its use edges: in particular, GT_LIST
-// nodes are expanded into their component parts
-// (with the optional exception of multi-reg
-// arguments). This differs from the behavior of
-// GenTree::GetChildPointer(), which does not expand
-// lists.
+// GenTreeUseEdgeIterator: an iterator that will produce each use edge of a GenTree node in the order in which
+// they are used.
//
-// Note: valid values of this type may be obtained by calling
-// `GenTree::UseEdgesBegin` and `GenTree::UseEdgesEnd`.
+// The use edges of a node may not correspond exactly to the nodes on the other ends of its use edges: in
+// particular, GT_LIST nodes are expanded into their component parts. This differs from the behavior of
+// GenTree::GetChildPointer(), which does not expand lists.
+//
+// Operand iteration is common enough in the back end of the compiler that the implementation of this type has
+// traded some simplicity for speed:
+// - As much work as is reasonable is done in the constructor rather than during operand iteration
+// - Node-specific functionality is handled by a small class of "advance" functions called by operator++
+// rather than making operator++ itself handle all nodes
+// - Some specialization has been performed for specific node types/shapes (e.g. the advance function for
+// binary nodes is specialized based on whether or not the node has the GTF_REVERSE_OPS flag set)
+//
+// Valid values of this type may be obtained by calling `GenTree::UseEdgesBegin` and `GenTree::UseEdgesEnd`.
//
class GenTreeUseEdgeIterator final
{
@@ -2071,6 +2136,20 @@ class GenTreeUseEdgeIterator final
friend GenTreeUseEdgeIterator GenTree::UseEdgesBegin();
friend GenTreeUseEdgeIterator GenTree::UseEdgesEnd();
+ enum
+ {
+ CALL_INSTANCE = 0,
+ CALL_ARGS = 1,
+ CALL_LATE_ARGS = 2,
+ CALL_CONTROL_EXPR = 3,
+ CALL_COOKIE = 4,
+ CALL_ADDRESS = 5,
+ CALL_TERMINAL = 6,
+ };
+
+ typedef void (GenTreeUseEdgeIterator::*AdvanceFn)();
+
+ AdvanceFn m_advance;
GenTree* m_node;
GenTree** m_edge;
GenTree* m_argList;
@@ -2078,24 +2157,40 @@ class GenTreeUseEdgeIterator final
GenTreeUseEdgeIterator(GenTree* node);
- GenTree** GetNextUseEdge() const;
- void MoveToNextCallUseEdge();
- void MoveToNextPhiUseEdge();
-#ifdef FEATURE_SIMD
- void MoveToNextSIMDUseEdge();
-#endif
- void MoveToNextFieldUseEdge();
+ // Advance functions for special nodes
+ void AdvanceCmpXchg();
+ void AdvanceBoundsChk();
+ void AdvanceArrElem();
+ void AdvanceArrOffset();
+ void AdvanceDynBlk();
+ void AdvanceStoreDynBlk();
+
+ template <bool ReverseOperands>
+ void AdvanceBinOp();
+ void SetEntryStateForBinOp();
+
+ // An advance function for list-like nodes (Phi, SIMDIntrinsicInitN, FieldList)
+ void AdvanceList();
+ void SetEntryStateForList(GenTree* list);
+
+ // The advance function for call nodes
+ template <int state>
+ void AdvanceCall();
+
+ void Terminate();
public:
GenTreeUseEdgeIterator();
inline GenTree** operator*()
{
+ assert(m_state != -1);
return m_edge;
}
inline GenTree** operator->()
{
+ assert(m_state != -1);
return m_edge;
}
@@ -3390,7 +3485,7 @@ struct GenTreeCall final : public GenTree
//
bool HasMultiRegRetVal() const
{
-#if defined(_TARGET_X86_) && !defined(LEGACY_BACKEND)
+#if (defined(_TARGET_X86_) || defined(_TARGET_ARM_)) && !defined(LEGACY_BACKEND)
// LEGACY_BACKEND does not use multi reg returns for calls with long return types
return varTypeIsLong(gtType);
#elif FEATURE_MULTIREG_RET
@@ -3620,8 +3715,7 @@ struct GenTreeFptrVal : public GenTree
CORINFO_METHOD_HANDLE gtFptrMethod;
#ifdef FEATURE_READYTORUN_COMPILER
- CORINFO_CONST_LOOKUP gtEntryPoint;
- CORINFO_RESOLVED_TOKEN* gtLdftnResolvedToken;
+ CORINFO_CONST_LOOKUP gtEntryPoint;
#endif
GenTreeFptrVal(var_types type, CORINFO_METHOD_HANDLE meth) : GenTree(GT_FTN_ADDR, type), gtFptrMethod(meth)
@@ -4071,6 +4165,7 @@ struct GenTreeAddrMode : public GenTreeOp
GenTreeAddrMode(var_types type, GenTreePtr base, GenTreePtr index, unsigned scale, unsigned offset)
: GenTreeOp(GT_LEA, type, base, index)
{
+ assert(base != nullptr || index != nullptr);
gtScale = scale;
gtOffset = offset;
}
@@ -4571,7 +4666,7 @@ struct GenTreePhiArg : public GenTreeLclVarCommon
#endif
};
-/* gtPutArgStk -- Argument passed on stack */
+/* gtPutArgStk -- Argument passed on stack (GT_PUTARG_STK) */
struct GenTreePutArgStk : public GenTreeUnOp
{
@@ -4580,105 +4675,58 @@ struct GenTreePutArgStk : public GenTreeUnOp
unsigned gtPadAlign; // Number of padding slots for stack alignment
#endif
-#if FEATURE_FASTTAILCALL
- bool putInIncomingArgArea; // Whether this arg needs to be placed in incoming arg area.
- // By default this is false and will be placed in out-going arg area.
- // Fast tail calls set this to true.
- // In future if we need to add more such bool fields consider bit fields.
-
- GenTreePutArgStk(genTreeOps oper,
- var_types type,
- unsigned slotNum PUT_STRUCT_ARG_STK_ONLY_ARG(unsigned numSlots)
- PUT_STRUCT_ARG_STK_ONLY_ARG(bool isStruct),
- bool _putInIncomingArgArea = false DEBUGARG(GenTreePtr callNode = nullptr)
- DEBUGARG(bool largeNode = false))
- : GenTreeUnOp(oper, type DEBUGARG(largeNode))
+ // Don't let clang-format mess with the GenTreePutArgStk constructor.
+ // clang-format off
+
+ GenTreePutArgStk(genTreeOps oper,
+ var_types type,
+ GenTreePtr op1,
+ unsigned slotNum
+ PUT_STRUCT_ARG_STK_ONLY_ARG(unsigned numSlots),
+ bool putInIncomingArgArea = false,
+ GenTreeCall* callNode = nullptr)
+ : GenTreeUnOp(oper, type, op1 DEBUGARG(/*largeNode*/ false))
, gtSlotNum(slotNum)
#if defined(UNIX_X86_ABI)
, gtPadAlign(0)
#endif
- , putInIncomingArgArea(_putInIncomingArgArea)
+#if FEATURE_FASTTAILCALL
+ , gtPutInIncomingArgArea(putInIncomingArgArea)
+#endif // FEATURE_FASTTAILCALL
#ifdef FEATURE_PUT_STRUCT_ARG_STK
, gtPutArgStkKind(Kind::Invalid)
, gtNumSlots(numSlots)
, gtNumberReferenceSlots(0)
, gtGcPtrs(nullptr)
#endif // FEATURE_PUT_STRUCT_ARG_STK
- {
-#ifdef DEBUG
- gtCall = callNode;
+#if defined(DEBUG) || defined(UNIX_X86_ABI)
+ , gtCall(callNode)
#endif
+ {
}
- GenTreePutArgStk(genTreeOps oper,
- var_types type,
- GenTreePtr op1,
- unsigned slotNum PUT_STRUCT_ARG_STK_ONLY_ARG(unsigned numSlots),
- bool _putInIncomingArgArea = false DEBUGARG(GenTreePtr callNode = nullptr)
- DEBUGARG(bool largeNode = false))
- : GenTreeUnOp(oper, type, op1 DEBUGARG(largeNode))
- , gtSlotNum(slotNum)
-#if defined(UNIX_X86_ABI)
- , gtPadAlign(0)
-#endif
- , putInIncomingArgArea(_putInIncomingArgArea)
-#ifdef FEATURE_PUT_STRUCT_ARG_STK
- , gtPutArgStkKind(Kind::Invalid)
- , gtNumSlots(numSlots)
- , gtNumberReferenceSlots(0)
- , gtGcPtrs(nullptr)
-#endif // FEATURE_PUT_STRUCT_ARG_STK
+// clang-format on
+
+#if FEATURE_FASTTAILCALL
+
+ bool gtPutInIncomingArgArea; // Whether this arg needs to be placed in incoming arg area.
+ // By default this is false and will be placed in out-going arg area.
+ // Fast tail calls set this to true.
+ // In future if we need to add more such bool fields consider bit fields.
+
+ bool putInIncomingArgArea() const
{
-#ifdef DEBUG
- gtCall = callNode;
-#endif
+ return gtPutInIncomingArgArea;
}
#else // !FEATURE_FASTTAILCALL
- GenTreePutArgStk(genTreeOps oper,
- var_types type,
- unsigned slotNum PUT_STRUCT_ARG_STK_ONLY_ARG(unsigned numSlots)
- DEBUGARG(GenTreePtr callNode = NULL) DEBUGARG(bool largeNode = false))
- : GenTreeUnOp(oper, type DEBUGARG(largeNode))
- , gtSlotNum(slotNum)
-#if defined(UNIX_X86_ABI)
- , gtPadAlign(0)
-#endif
-#ifdef FEATURE_PUT_STRUCT_ARG_STK
- , gtPutArgStkKind(Kind::Invalid)
- , gtNumSlots(numSlots)
- , gtNumberReferenceSlots(0)
- , gtGcPtrs(nullptr)
-#endif // FEATURE_PUT_STRUCT_ARG_STK
+ bool putInIncomingArgArea() const
{
-#ifdef DEBUG
- gtCall = callNode;
-#endif
+ return false;
}
- GenTreePutArgStk(genTreeOps oper,
- var_types type,
- GenTreePtr op1,
- unsigned slotNum PUT_STRUCT_ARG_STK_ONLY_ARG(unsigned numSlots)
- DEBUGARG(GenTreePtr callNode = NULL) DEBUGARG(bool largeNode = false))
- : GenTreeUnOp(oper, type, op1 DEBUGARG(largeNode))
- , gtSlotNum(slotNum)
-#if defined(UNIX_X86_ABI)
- , gtPadAlign(0)
-#endif
-#ifdef FEATURE_PUT_STRUCT_ARG_STK
- , gtPutArgStkKind(Kind::Invalid)
- , gtNumSlots(numSlots)
- , gtNumberReferenceSlots(0)
- , gtGcPtrs(nullptr)
-#endif // FEATURE_PUT_STRUCT_ARG_STK
- {
-#ifdef DEBUG
- gtCall = callNode;
-#endif
- }
-#endif // FEATURE_FASTTAILCALL
+#endif // !FEATURE_FASTTAILCALL
unsigned getArgOffset()
{
@@ -4698,13 +4746,12 @@ struct GenTreePutArgStk : public GenTreeUnOp
#endif
#ifdef FEATURE_PUT_STRUCT_ARG_STK
+
unsigned getArgSize()
{
return gtNumSlots * TARGET_POINTER_SIZE;
}
-#endif // FEATURE_PUT_STRUCT_ARG_STK
-#ifdef FEATURE_PUT_STRUCT_ARG_STK
//------------------------------------------------------------------------
// setGcPointers: Sets the number of references and the layout of the struct object returned by the VM.
//
@@ -4726,13 +4773,7 @@ struct GenTreePutArgStk : public GenTreeUnOp
gtNumberReferenceSlots = numPointers;
gtGcPtrs = pointers;
}
-#endif // FEATURE_PUT_STRUCT_ARG_STK
-#ifdef DEBUG
- GenTreePtr gtCall; // the call node to which this argument belongs
-#endif
-
-#ifdef FEATURE_PUT_STRUCT_ARG_STK
// Instruction selection: during codegen time, what code sequence we will be using
// to encode this operation.
// TODO-Throughput: The following information should be obtained from the child
@@ -4751,7 +4792,12 @@ struct GenTreePutArgStk : public GenTreeUnOp
unsigned gtNumSlots; // Number of slots for the argument to be passed on stack
unsigned gtNumberReferenceSlots; // Number of reference slots.
BYTE* gtGcPtrs; // gcPointers
-#endif // FEATURE_PUT_STRUCT_ARG_STK
+
+#endif // FEATURE_PUT_STRUCT_ARG_STK
+
+#if defined(DEBUG) || defined(UNIX_X86_ABI)
+ GenTreeCall* gtCall; // the call node to which this argument belongs
+#endif
#if DEBUGGABLE_GENTREE
GenTreePutArgStk() : GenTreeUnOp()