1 | // Licensed to the .NET Foundation under one or more agreements. |
2 | // The .NET Foundation licenses this file to you under the MIT license. |
3 | // See the LICENSE file in the project root for more information. |
4 | |
5 | // clang-format off |
6 | /*****************************************************************************/ |
7 | #ifndef GTNODE |
8 | #error Define GTNODE before including this file. |
9 | #endif |
10 | /*****************************************************************************/ |
11 | // |
12 | // Node enum |
13 | // , GenTree struct flavor |
14 | // ,commutative |
15 | // ,operKind |
16 | |
17 | GTNODE(NONE , char ,0,GTK_SPECIAL) |
18 | |
19 | //----------------------------------------------------------------------------- |
20 | // Leaf nodes (i.e. these nodes have no sub-operands): |
21 | //----------------------------------------------------------------------------- |
22 | |
23 | GTNODE(LCL_VAR , GenTreeLclVar ,0,GTK_LEAF|GTK_LOCAL) // local variable |
24 | GTNODE(LCL_FLD , GenTreeLclFld ,0,GTK_LEAF|GTK_LOCAL) // field in a non-primitive variable |
25 | GTNODE(LCL_VAR_ADDR , GenTreeLclVar ,0,GTK_LEAF) // address of local variable |
26 | GTNODE(LCL_FLD_ADDR , GenTreeLclFld ,0,GTK_LEAF) // address of field in a non-primitive variable |
27 | GTNODE(STORE_LCL_VAR , GenTreeLclVar ,0,GTK_UNOP|GTK_LOCAL|GTK_NOVALUE) // store to local variable |
28 | GTNODE(STORE_LCL_FLD , GenTreeLclFld ,0,GTK_UNOP|GTK_LOCAL|GTK_NOVALUE) // store to field in a non-primitive variable |
29 | GTNODE(CATCH_ARG , GenTree ,0,GTK_LEAF) // Exception object in a catch block |
30 | GTNODE(LABEL , GenTreeLabel ,0,GTK_LEAF) // Jump-target |
31 | GTNODE(FTN_ADDR , GenTreeFptrVal ,0,GTK_LEAF) // Address of a function |
32 | GTNODE(RET_EXPR , GenTreeRetExpr ,0,GTK_LEAF) // Place holder for the return expression from an inline candidate |
33 | |
34 | //----------------------------------------------------------------------------- |
35 | // Constant nodes: |
36 | //----------------------------------------------------------------------------- |
37 | |
38 | GTNODE(CNS_INT , GenTreeIntCon ,0,GTK_LEAF|GTK_CONST) |
39 | GTNODE(CNS_LNG , GenTreeLngCon ,0,GTK_LEAF|GTK_CONST) |
40 | GTNODE(CNS_DBL , GenTreeDblCon ,0,GTK_LEAF|GTK_CONST) |
41 | GTNODE(CNS_STR , GenTreeStrCon ,0,GTK_LEAF|GTK_CONST) |
42 | |
43 | //----------------------------------------------------------------------------- |
44 | // Unary operators (1 operand): |
45 | //----------------------------------------------------------------------------- |
46 | |
47 | GTNODE(NOT , GenTreeOp ,0,GTK_UNOP) |
48 | GTNODE(NOP , GenTree ,0,GTK_UNOP|GTK_NOCONTAIN) |
49 | GTNODE(NEG , GenTreeOp ,0,GTK_UNOP) |
50 | GTNODE(COPY , GenTreeCopyOrReload,0,GTK_UNOP) // Copies a variable from its current location to a register that satisfies |
51 | // code generation constraints. The child is the actual lclVar node. |
52 | GTNODE(RELOAD , GenTreeCopyOrReload,0,GTK_UNOP) |
53 | GTNODE(ARR_LENGTH , GenTreeArrLen ,0,GTK_UNOP|GTK_EXOP) // array-length |
54 | GTNODE(INTRINSIC , GenTreeIntrinsic ,0,GTK_BINOP|GTK_EXOP) // intrinsics |
55 | |
56 | GTNODE(LOCKADD , GenTreeOp ,0,GTK_BINOP|GTK_NOVALUE) |
57 | GTNODE(XADD , GenTreeOp ,0,GTK_BINOP) |
58 | GTNODE(XCHG , GenTreeOp ,0,GTK_BINOP) |
59 | GTNODE(CMPXCHG , GenTreeCmpXchg ,0,GTK_SPECIAL) |
60 | GTNODE(MEMORYBARRIER , GenTree ,0,GTK_LEAF|GTK_NOVALUE) |
61 | |
62 | GTNODE(CAST , GenTreeCast ,0,GTK_UNOP|GTK_EXOP) // conversion to another type |
63 | #if defined(_TARGET_ARM_) |
64 | GTNODE(BITCAST , GenTreeMultiRegOp ,0,GTK_UNOP) // reinterpretation of bits as another type |
65 | #else |
66 | GTNODE(BITCAST , GenTreeOp ,0,GTK_UNOP) // reinterpretation of bits as another type |
67 | #endif |
68 | GTNODE(CKFINITE , GenTreeOp ,0,GTK_UNOP|GTK_NOCONTAIN) // Check for NaN |
69 | GTNODE(LCLHEAP , GenTreeOp ,0,GTK_UNOP|GTK_NOCONTAIN) // alloca() |
70 | GTNODE(JMP , GenTreeVal ,0,GTK_LEAF|GTK_NOVALUE) // Jump to another function |
71 | |
72 | GTNODE(ADDR , GenTreeOp ,0,GTK_UNOP) // address of |
73 | GTNODE(IND , GenTreeOp ,0,GTK_UNOP) // load indirection |
74 | GTNODE(STOREIND , GenTreeStoreInd ,0,GTK_BINOP|GTK_NOVALUE) // store indirection |
75 | |
76 | // TODO-Cleanup: GT_ARR_BOUNDS_CHECK should be made a GTK_BINOP now that it has only two child nodes |
77 | GTNODE(ARR_BOUNDS_CHECK , GenTreeBoundsChk ,0,GTK_SPECIAL|GTK_NOVALUE)// array bounds check |
78 | GTNODE(OBJ , GenTreeObj ,0,GTK_UNOP|GTK_EXOP) // Object that MAY have gc pointers, and thus includes the relevant gc layout info. |
79 | GTNODE(STORE_OBJ , GenTreeBlk ,0,GTK_BINOP|GTK_EXOP|GTK_NOVALUE) // Object that MAY have gc pointers, and thus includes the relevant gc layout info. |
80 | GTNODE(BLK , GenTreeBlk ,0,GTK_UNOP) // Block/object with no gc pointers, and with a known size (e.g. a struct with no gc fields) |
81 | GTNODE(STORE_BLK , GenTreeBlk ,0,GTK_BINOP|GTK_NOVALUE) // Block/object with no gc pointers, and with a known size (e.g. a struct with no gc fields) |
82 | GTNODE(DYN_BLK , GenTreeBlk ,0,GTK_SPECIAL) // Dynamically sized block object |
83 | GTNODE(STORE_DYN_BLK , GenTreeBlk ,0,GTK_SPECIAL|GTK_NOVALUE)// Dynamically sized block object |
84 | GTNODE(BOX , GenTreeBox ,0,GTK_UNOP|GTK_EXOP|GTK_NOTLIR) |
85 | |
86 | #ifdef FEATURE_SIMD |
87 | GTNODE(SIMD_CHK , GenTreeBoundsChk ,0,GTK_SPECIAL|GTK_NOVALUE)// Compare whether an index is less than the given SIMD vector length, and call CORINFO_HELP_RNGCHKFAIL if not. |
88 | // TODO-CQ: In future may want to add a field that specifies different exceptions but we'll |
89 | // need VM assistance for that. |
90 | // TODO-CQ: It would actually be very nice to make this an unconditional throw, and expose the control flow that |
91 | // does the compare, so that it can be more easily optimized. But that involves generating qmarks at import time... |
92 | #endif // FEATURE_SIMD |
93 | |
94 | #ifdef FEATURE_HW_INTRINSICS |
95 | GTNODE(HW_INTRINSIC_CHK , GenTreeBoundsChk ,0,GTK_SPECIAL|GTK_NOVALUE)// Compare whether an imm8 argument is in the valid range, and throw ArgumentOutOfRangeException if not. |
96 | #endif |
97 | |
98 | GTNODE(ALLOCOBJ , GenTreeAllocObj ,0,GTK_UNOP|GTK_EXOP) // object allocator |
99 | |
100 | GTNODE(INIT_VAL , GenTreeOp ,0,GTK_UNOP) // Initialization value for an initBlk |
101 | |
102 | GTNODE(RUNTIMELOOKUP , GenTreeRuntimeLookup, 0,GTK_UNOP|GTK_EXOP) // Runtime handle lookup |
103 | |
104 | GTNODE(BSWAP , GenTreeOp ,0,GTK_UNOP) // Byte swap (32-bit or 64-bit) |
105 | GTNODE(BSWAP16 , GenTreeOp ,0,GTK_UNOP) // Byte swap (16-bit) |
106 | |
107 | //----------------------------------------------------------------------------- |
108 | // Binary operators (2 operands): |
109 | //----------------------------------------------------------------------------- |
110 | |
111 | GTNODE(ADD , GenTreeOp ,1,GTK_BINOP) |
112 | GTNODE(SUB , GenTreeOp ,0,GTK_BINOP) |
113 | GTNODE(MUL , GenTreeOp ,1,GTK_BINOP) |
114 | GTNODE(DIV , GenTreeOp ,0,GTK_BINOP) |
115 | GTNODE(MOD , GenTreeOp ,0,GTK_BINOP) |
116 | |
117 | GTNODE(UDIV , GenTreeOp ,0,GTK_BINOP) |
118 | GTNODE(UMOD , GenTreeOp ,0,GTK_BINOP) |
119 | |
120 | GTNODE(OR , GenTreeOp ,1,GTK_BINOP|GTK_LOGOP) |
121 | GTNODE(XOR , GenTreeOp ,1,GTK_BINOP|GTK_LOGOP) |
122 | GTNODE(AND , GenTreeOp ,1,GTK_BINOP|GTK_LOGOP) |
123 | |
124 | GTNODE(LSH , GenTreeOp ,0,GTK_BINOP) |
125 | GTNODE(RSH , GenTreeOp ,0,GTK_BINOP) |
126 | GTNODE(RSZ , GenTreeOp ,0,GTK_BINOP) |
127 | GTNODE(ROL , GenTreeOp ,0,GTK_BINOP) |
128 | GTNODE(ROR , GenTreeOp ,0,GTK_BINOP) |
129 | GTNODE(MULHI , GenTreeOp ,1,GTK_BINOP) // returns high bits (top N bits of the 2N bit result of an NxN multiply) |
130 | // GT_MULHI is used in division by a constant (fgMorphDivByConst). We turn |
131 | // the div into a MULHI + some adjustments. In codegen, we only use the |
132 | // results of the high register, and we drop the low results. |
133 | |
134 | GTNODE(ASG , GenTreeOp ,0,GTK_BINOP|GTK_NOTLIR) |
135 | GTNODE(EQ , GenTreeOp ,0,GTK_BINOP|GTK_RELOP) |
136 | GTNODE(NE , GenTreeOp ,0,GTK_BINOP|GTK_RELOP) |
137 | GTNODE(LT , GenTreeOp ,0,GTK_BINOP|GTK_RELOP) |
138 | GTNODE(LE , GenTreeOp ,0,GTK_BINOP|GTK_RELOP) |
139 | GTNODE(GE , GenTreeOp ,0,GTK_BINOP|GTK_RELOP) |
140 | GTNODE(GT , GenTreeOp ,0,GTK_BINOP|GTK_RELOP) |
141 | |
142 | // These are similar to GT_EQ/GT_NE but they generate "test" instead of "cmp" instructions. |
143 | // Currently these are generated during lowering for code like ((x & y) eq|ne 0) only on |
144 | // XArch but ARM could too use these for the same purpose as there is a "tst" instruction. |
145 | // Note that the general case of comparing a register against 0 is handled directly by |
146 | // codegen which emits a "test reg, reg" instruction, that would be more difficult to do |
147 | // during lowering because the source operand is used twice so it has to be a lclvar. |
148 | // Because of this there is no need to also add GT_TEST_LT/LE/GE/GT opers. |
149 | GTNODE(TEST_EQ , GenTreeOp ,0,GTK_BINOP|GTK_RELOP) |
150 | GTNODE(TEST_NE , GenTreeOp ,0,GTK_BINOP|GTK_RELOP) |
151 | |
152 | GTNODE(COMMA , GenTreeOp ,0,GTK_BINOP|GTK_NOTLIR) |
153 | |
154 | GTNODE(QMARK , GenTreeQmark ,0,GTK_BINOP|GTK_EXOP|GTK_NOTLIR) |
155 | GTNODE(COLON , GenTreeColon ,0,GTK_BINOP|GTK_NOTLIR) |
156 | |
157 | GTNODE(INDEX , GenTreeIndex ,0,GTK_BINOP|GTK_EXOP|GTK_NOTLIR) // SZ-array-element |
158 | GTNODE(INDEX_ADDR , GenTreeIndex ,0,GTK_BINOP|GTK_EXOP) // addr of SZ-array-element; used when |
159 | // aiming to minimize compile times. |
160 | |
161 | GTNODE(MKREFANY , GenTreeOp ,0,GTK_BINOP) |
162 | |
163 | GTNODE(LEA , GenTreeAddrMode ,0,GTK_BINOP|GTK_EXOP) |
164 | |
165 | #if !defined(_TARGET_64BIT_) |
166 | // A GT_LONG node simply represents the long value produced by the concatenation |
167 | // of its two (lower and upper half) operands. Some GT_LONG nodes are transient, |
168 | // during the decomposing of longs; others are handled by codegen as operands of |
169 | // nodes such as calls, returns and stores of long lclVars. |
170 | GTNODE(LONG , GenTreeOp ,0,GTK_BINOP) |
171 | |
172 | // The following are nodes representing x86/arm32 specific long operators, including |
173 | // high operators of a 64-bit operations that requires a carry/borrow, which are |
174 | // named GT_XXX_HI for consistency, low operators of 64-bit operations that need |
175 | // to not be modified in phases post-decompose, and operators that return 64-bit |
176 | // results in one instruction. |
177 | GTNODE(ADD_LO , GenTreeOp ,1,GTK_BINOP) |
178 | GTNODE(ADD_HI , GenTreeOp ,1,GTK_BINOP) |
179 | GTNODE(SUB_LO , GenTreeOp ,0,GTK_BINOP) |
180 | GTNODE(SUB_HI , GenTreeOp ,0,GTK_BINOP) |
181 | |
182 | // A mul that returns the 2N bit result of an NxN multiply. This op is used for |
183 | // multiplies that take two ints and return a long result. All other multiplies |
184 | // with long results are morphed into helper calls. It is similar to GT_MULHI, |
185 | // the difference being that GT_MULHI drops the lo part of the result, whereas |
186 | // GT_MUL_LONG keeps both parts of the result. |
187 | #if !defined(_TARGET_64BIT_) |
188 | GTNODE(MUL_LONG , GenTreeMultiRegOp ,1,GTK_BINOP) |
189 | #endif |
190 | |
191 | // The following are nodes that specify shifts that take a GT_LONG op1. The GT_LONG |
192 | // contains the hi and lo parts of three operand shift form where one op will be |
193 | // shifted into the other op as part of the operation (LSH_HI will shift |
194 | // the high bits of the lo operand into the high operand as it shifts left. RSH_LO |
195 | // will shift the lo bits of the high operand into the lo operand). LSH_HI |
196 | // represents the high operation of a 64-bit left shift by a constant int, and |
197 | // RSH_LO represents the lo operation of a 64-bit right shift by a constant int. |
198 | GTNODE(LSH_HI , GenTreeOp ,0,GTK_BINOP) |
199 | GTNODE(RSH_LO , GenTreeOp ,0,GTK_BINOP) |
200 | #endif // !defined(_TARGET_64BIT_) |
201 | |
202 | #ifdef FEATURE_SIMD |
203 | GTNODE(SIMD , GenTreeSIMD ,0,GTK_BINOP|GTK_EXOP) // SIMD functions/operators/intrinsics |
204 | #endif // FEATURE_SIMD |
205 | |
206 | #ifdef FEATURE_HW_INTRINSICS |
207 | GTNODE(HWIntrinsic , GenTreeHWIntrinsic ,0,GTK_BINOP|GTK_EXOP) // hardware intrinsics |
208 | #endif // FEATURE_HW_INTRINSICS |
209 | |
210 | //----------------------------------------------------------------------------- |
211 | // LIR specific compare and conditional branch/set nodes: |
212 | //----------------------------------------------------------------------------- |
213 | |
214 | GTNODE(CMP , GenTreeOp ,0,GTK_BINOP|GTK_NOVALUE) // Sets the condition flags according to the compare result. |
215 | // N.B. Not a relop, it does not produce a value and it cannot be reversed. |
216 | GTNODE(JCMP , GenTreeOp ,0,GTK_BINOP|GTK_NOVALUE) // Makes a comparison and jump if the condition specified. Does not set flags |
217 | GTNODE(JCC , GenTreeCC ,0,GTK_LEAF|GTK_NOVALUE) // Checks the condition flags and branch if the condition specified |
218 | // by GenTreeCC::gtCondition is true. |
219 | GTNODE(SETCC , GenTreeCC ,0,GTK_LEAF) // Checks the condition flags and produces 1 if the condition specified |
220 | // by GenTreeCC::gtCondition is true and 0 otherwise. |
221 | #ifdef _TARGET_XARCH_ |
222 | GTNODE(BT , GenTreeOp ,0,GTK_BINOP|GTK_NOVALUE) // The XARCH BT instruction. Like CMP, this sets the condition flags (CF |
223 | // to be precise) and does not produce a value. |
224 | #endif |
225 | //----------------------------------------------------------------------------- |
226 | // Other nodes that look like unary/binary operators: |
227 | //----------------------------------------------------------------------------- |
228 | |
229 | GTNODE(JTRUE , GenTreeOp ,0,GTK_UNOP|GTK_NOVALUE) |
230 | |
231 | GTNODE(LIST , GenTreeArgList ,0,GTK_BINOP|GTK_NOVALUE) |
232 | GTNODE(FIELD_LIST , GenTreeFieldList ,0,GTK_BINOP) // List of fields of a struct, when passed as an argument |
233 | |
234 | //----------------------------------------------------------------------------- |
235 | // Other nodes that have special structure: |
236 | //----------------------------------------------------------------------------- |
237 | |
238 | GTNODE(FIELD , GenTreeField ,0,GTK_SPECIAL) // Member-field |
239 | GTNODE(ARR_ELEM , GenTreeArrElem ,0,GTK_SPECIAL) // Multi-dimensional array-element address |
240 | GTNODE(ARR_INDEX , GenTreeArrIndex ,0,GTK_BINOP|GTK_EXOP) // Effective, bounds-checked index for one dimension of a multi-dimensional array element |
241 | GTNODE(ARR_OFFSET , GenTreeArrOffs ,0,GTK_SPECIAL) // Flattened offset of multi-dimensional array element |
242 | GTNODE(CALL , GenTreeCall ,0,GTK_SPECIAL|GTK_NOCONTAIN) |
243 | |
244 | //----------------------------------------------------------------------------- |
245 | // Statement operator nodes: |
246 | //----------------------------------------------------------------------------- |
247 | |
248 | GTNODE(BEG_STMTS , GenTree ,0,GTK_SPECIAL|GTK_NOVALUE)// used only temporarily in importer by impBegin/EndTreeList() |
249 | GTNODE(STMT , GenTreeStmt ,0,GTK_SPECIAL|GTK_NOVALUE)// top-level list nodes in bbTreeList |
250 | |
251 | GTNODE(RETURN , GenTreeOp ,0,GTK_UNOP|GTK_NOVALUE) // return from current function |
252 | GTNODE(SWITCH , GenTreeOp ,0,GTK_UNOP|GTK_NOVALUE) // switch |
253 | |
254 | GTNODE(NO_OP , GenTree ,0,GTK_LEAF|GTK_NOVALUE) // nop! |
255 | |
256 | GTNODE(START_NONGC , GenTree ,0,GTK_LEAF|GTK_NOVALUE) // starts a new instruction group that will be non-gc interruptible |
257 | |
258 | GTNODE(PROF_HOOK , GenTree ,0,GTK_LEAF|GTK_NOVALUE) // profiler Enter/Leave/TailCall hook |
259 | |
260 | GTNODE(RETFILT , GenTreeOp ,0,GTK_UNOP|GTK_NOVALUE) // end filter with TYP_I_IMPL return value |
261 | #if !FEATURE_EH_FUNCLETS |
262 | GTNODE(END_LFIN , GenTreeVal ,0,GTK_LEAF|GTK_NOVALUE) // end locally-invoked finally |
263 | #endif // !FEATURE_EH_FUNCLETS |
264 | |
265 | //----------------------------------------------------------------------------- |
266 | // Nodes used for optimizations. |
267 | //----------------------------------------------------------------------------- |
268 | |
269 | GTNODE(PHI , GenTreeOp ,0,GTK_UNOP) // phi node for ssa. |
270 | GTNODE(PHI_ARG , GenTreePhiArg ,0,GTK_LEAF|GTK_LOCAL) // phi(phiarg, phiarg, phiarg) |
271 | |
272 | //----------------------------------------------------------------------------- |
273 | // Nodes used by Lower to generate a closer CPU representation of other nodes |
274 | //----------------------------------------------------------------------------- |
275 | |
276 | GTNODE(JMPTABLE , GenTreeJumpTable ,0, GTK_LEAF|GTK_NOCONTAIN) // Generates the jump table for switches |
277 | GTNODE(SWITCH_TABLE , GenTreeOp ,0, GTK_BINOP|GTK_NOVALUE) // Jump Table based switch construct |
278 | |
279 | //----------------------------------------------------------------------------- |
280 | // Nodes used only within the code generator: |
281 | //----------------------------------------------------------------------------- |
282 | |
283 | GTNODE(CLS_VAR , GenTreeClsVar ,0,GTK_LEAF) // static data member |
284 | GTNODE(CLS_VAR_ADDR , GenTreeClsVar ,0,GTK_LEAF) // static data member address |
285 | GTNODE(ARGPLACE , GenTreeArgPlace ,0,GTK_LEAF|GTK_NOVALUE|GTK_NOTLIR) // placeholder for a register arg |
286 | GTNODE(NULLCHECK , GenTreeOp ,0,GTK_UNOP|GTK_NOVALUE) // null checks the source |
287 | GTNODE(PHYSREG , GenTreePhysReg ,0,GTK_LEAF) // read from a physical register |
288 | GTNODE(EMITNOP , GenTree ,0,GTK_LEAF|GTK_NOVALUE) // emitter-placed nop |
289 | GTNODE(PINVOKE_PROLOG , GenTree ,0,GTK_LEAF|GTK_NOVALUE) // pinvoke prolog seq |
290 | GTNODE(PINVOKE_EPILOG , GenTree ,0,GTK_LEAF|GTK_NOVALUE) // pinvoke epilog seq |
291 | #if defined(_TARGET_ARM_) |
292 | GTNODE(PUTARG_REG , GenTreeMultiRegOp ,0,GTK_UNOP) // operator that places outgoing arg in register |
293 | #else |
294 | GTNODE(PUTARG_REG , GenTreeOp ,0,GTK_UNOP) // operator that places outgoing arg in register |
295 | #endif |
296 | GTNODE(PUTARG_STK , GenTreePutArgStk ,0,GTK_UNOP|GTK_NOVALUE) // operator that places outgoing arg in stack |
297 | #if FEATURE_ARG_SPLIT |
298 | GTNODE(PUTARG_SPLIT , GenTreePutArgSplit ,0,GTK_UNOP) // operator that places outgoing arg in registers with stack (split struct in ARM32) |
299 | #endif // FEATURE_ARG_SPLIT |
300 | GTNODE(RETURNTRAP , GenTreeOp ,0,GTK_UNOP|GTK_NOVALUE) // a conditional call to wait on gc |
301 | GTNODE(SWAP , GenTreeOp ,0,GTK_BINOP|GTK_NOVALUE) // op1 and op2 swap (registers) |
302 | GTNODE(IL_OFFSET , GenTreeStmt ,0,GTK_LEAF|GTK_NOVALUE) // marks an IL offset for debugging purposes |
303 | |
304 | /*****************************************************************************/ |
305 | #undef GTNODE |
306 | /*****************************************************************************/ |
307 | // clang-format on |
308 | |