e29bb9c4d6457c906b65ab3a1394774697f79fdc
[platform/upstream/coreclr.git] / src / jit / lower.h
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 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7 XX                                                                           XX
8 XX                               Lower                                       XX
9 XX                                                                           XX
10 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
11 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
12 */
13
14 #ifndef _LOWER_H_
15 #define _LOWER_H_
16
17 #include "compiler.h"
18 #include "phase.h"
19 #include "lsra.h"
20 #include "sideeffects.h"
21
22 class Lowering : public Phase
23 {
24 public:
25     inline Lowering(Compiler* compiler, LinearScanInterface* lsra)
26         : Phase(compiler, "Lowering", PHASE_LOWERING), vtableCallTemp(BAD_VAR_NUM)
27     {
28         m_lsra = (LinearScan*)lsra;
29         assert(m_lsra);
30     }
31     virtual void DoPhase() override;
32
33     // This variant of LowerRange is called from outside of the main Lowering pass,
34     // so it creates its own instance of Lowering to do so.
35     void LowerRange(BasicBlock* block, LIR::ReadOnlyRange& range)
36     {
37         Lowering lowerer(comp, m_lsra);
38         lowerer.m_block = block;
39
40         lowerer.LowerRange(range);
41     }
42
43 private:
44     // LowerRange handles new code that is introduced by or after Lowering.
45     void LowerRange(LIR::ReadOnlyRange& range)
46     {
47         for (GenTree* newNode : range)
48         {
49             LowerNode(newNode);
50         }
51     }
52     void LowerRange(GenTree* firstNode, GenTree* lastNode)
53     {
54         LIR::ReadOnlyRange range(firstNode, lastNode);
55         LowerRange(range);
56     }
57
58     // ContainCheckRange handles new code that is introduced by or after Lowering,
59     // and that is known to be already in Lowered form.
60     void ContainCheckRange(LIR::ReadOnlyRange& range)
61     {
62         for (GenTree* newNode : range)
63         {
64             ContainCheckNode(newNode);
65         }
66     }
67     void ContainCheckRange(GenTree* firstNode, GenTree* lastNode)
68     {
69         LIR::ReadOnlyRange range(firstNode, lastNode);
70         ContainCheckRange(range);
71     }
72
73     void InsertTreeBeforeAndContainCheck(GenTree* insertionPoint, GenTree* tree)
74     {
75         LIR::Range range = LIR::SeqTree(comp, tree);
76         ContainCheckRange(range);
77         BlockRange().InsertBefore(insertionPoint, std::move(range));
78     }
79
80     void ContainCheckNode(GenTree* node);
81
82     void ContainCheckDivOrMod(GenTreeOp* node);
83     void ContainCheckReturnTrap(GenTreeOp* node);
84     void ContainCheckArrOffset(GenTreeArrOffs* node);
85     void ContainCheckLclHeap(GenTreeOp* node);
86     void ContainCheckRet(GenTreeOp* node);
87     void ContainCheckJTrue(GenTreeOp* node);
88
89     void ContainCheckCallOperands(GenTreeCall* call);
90     void ContainCheckIndir(GenTreeIndir* indirNode);
91     void ContainCheckStoreIndir(GenTreeIndir* indirNode);
92     void ContainCheckMul(GenTreeOp* node);
93     void ContainCheckShiftRotate(GenTreeOp* node);
94     void ContainCheckStoreLoc(GenTreeLclVarCommon* storeLoc);
95     void ContainCheckCast(GenTreeCast* node);
96     void ContainCheckCompare(GenTreeOp* node);
97     void ContainCheckBinary(GenTreeOp* node);
98     void ContainCheckBoundsChk(GenTreeBoundsChk* node);
99 #ifdef _TARGET_XARCH_
100     void ContainCheckFloatBinary(GenTreeOp* node);
101     void ContainCheckIntrinsic(GenTreeOp* node);
102 #endif // _TARGET_XARCH_
103 #ifdef FEATURE_SIMD
104     void ContainCheckSIMD(GenTreeSIMD* simdNode);
105 #endif // FEATURE_SIMD
106 #ifdef FEATURE_HW_INTRINSICS
107     void ContainCheckHWIntrinsic(GenTreeHWIntrinsic* node);
108 #endif // FEATURE_HW_INTRINSICS
109
110 #ifdef DEBUG
111     static void CheckCallArg(GenTree* arg);
112     static void CheckCall(GenTreeCall* call);
113     static void CheckNode(Compiler* compiler, GenTree* node);
114     static bool CheckBlock(Compiler* compiler, BasicBlock* block);
115 #endif // DEBUG
116
117     void LowerBlock(BasicBlock* block);
118     GenTree* LowerNode(GenTree* node);
119
120     void CheckVSQuirkStackPaddingNeeded(GenTreeCall* call);
121
122     // ------------------------------
123     // Call Lowering
124     // ------------------------------
125     void LowerCall(GenTree* call);
126 #ifndef _TARGET_64BIT_
127     GenTree* DecomposeLongCompare(GenTree* cmp);
128 #endif
129     GenTree* OptimizeConstCompare(GenTree* cmp);
130     GenTree* LowerCompare(GenTree* cmp);
131     GenTree* LowerJTrue(GenTreeOp* jtrue);
132     void LowerJmpMethod(GenTree* jmp);
133     void LowerRet(GenTree* ret);
134     GenTree* LowerDelegateInvoke(GenTreeCall* call);
135     GenTree* LowerIndirectNonvirtCall(GenTreeCall* call);
136     GenTree* LowerDirectCall(GenTreeCall* call);
137     GenTree* LowerNonvirtPinvokeCall(GenTreeCall* call);
138     GenTree* LowerTailCallViaHelper(GenTreeCall* callNode, GenTree* callTarget);
139     void LowerFastTailCall(GenTreeCall* callNode);
140     void InsertProfTailCallHook(GenTreeCall* callNode, GenTree* insertionPoint);
141     GenTree* LowerVirtualVtableCall(GenTreeCall* call);
142     GenTree* LowerVirtualStubCall(GenTreeCall* call);
143     void LowerArgsForCall(GenTreeCall* call);
144     void ReplaceArgWithPutArgOrBitcast(GenTree** ppChild, GenTree* newNode);
145     GenTree* NewPutArg(GenTreeCall* call, GenTree* arg, fgArgTabEntry* info, var_types type);
146     void LowerArg(GenTreeCall* call, GenTree** ppTree);
147 #ifdef _TARGET_ARMARCH_
148     GenTree* LowerFloatArg(GenTree** pArg, fgArgTabEntry* info);
149     GenTree* LowerFloatArgReg(GenTree* arg, regNumber regNum);
150 #endif
151
152     void InsertPInvokeCallProlog(GenTreeCall* call);
153     void InsertPInvokeCallEpilog(GenTreeCall* call);
154     void InsertPInvokeMethodProlog();
155     void InsertPInvokeMethodEpilog(BasicBlock* returnBB DEBUGARG(GenTree* lastExpr));
156     GenTree* SetGCState(int cns);
157     GenTree* CreateReturnTrapSeq();
158     enum FrameLinkAction
159     {
160         PushFrame,
161         PopFrame
162     };
163     GenTree* CreateFrameLinkUpdate(FrameLinkAction);
164     GenTree* AddrGen(ssize_t addr);
165     GenTree* AddrGen(void* addr);
166
167     GenTree* Ind(GenTree* tree)
168     {
169         return comp->gtNewOperNode(GT_IND, TYP_I_IMPL, tree);
170     }
171
172     GenTree* PhysReg(regNumber reg, var_types type = TYP_I_IMPL)
173     {
174         return comp->gtNewPhysRegNode(reg, type);
175     }
176
177     GenTree* ThisReg(GenTreeCall* call)
178     {
179         return PhysReg(comp->codeGen->genGetThisArgReg(call), TYP_REF);
180     }
181
182     GenTree* Offset(GenTree* base, unsigned offset)
183     {
184         var_types resultType = (base->TypeGet() == TYP_REF) ? TYP_BYREF : base->TypeGet();
185         return new (comp, GT_LEA) GenTreeAddrMode(resultType, base, nullptr, 0, offset);
186     }
187
188     GenTree* OffsetByIndex(GenTree* base, GenTree* index)
189     {
190         var_types resultType = (base->TypeGet() == TYP_REF) ? TYP_BYREF : base->TypeGet();
191         return new (comp, GT_LEA) GenTreeAddrMode(resultType, base, index, 0, 0);
192     }
193
194     GenTree* OffsetByIndexWithScale(GenTree* base, GenTree* index, unsigned scale)
195     {
196         var_types resultType = (base->TypeGet() == TYP_REF) ? TYP_BYREF : base->TypeGet();
197         return new (comp, GT_LEA) GenTreeAddrMode(resultType, base, index, scale, 0);
198     }
199
200     // Replace the definition of the given use with a lclVar, allocating a new temp
201     // if 'tempNum' is BAD_VAR_NUM. Returns the LclVar node.
202     GenTreeLclVar* ReplaceWithLclVar(LIR::Use& use, unsigned tempNum = BAD_VAR_NUM)
203     {
204         GenTree* oldUseNode = use.Def();
205         if ((oldUseNode->gtOper != GT_LCL_VAR) || (tempNum != BAD_VAR_NUM))
206         {
207             use.ReplaceWithLclVar(comp, m_block->getBBWeight(comp), tempNum);
208             GenTree* newUseNode = use.Def();
209             ContainCheckRange(oldUseNode->gtNext, newUseNode);
210             return newUseNode->AsLclVar();
211         }
212         return oldUseNode->AsLclVar();
213     }
214
215     // return true if this call target is within range of a pc-rel call on the machine
216     bool IsCallTargetInRange(void* addr);
217
218 #if defined(_TARGET_XARCH_)
219     GenTree* PreferredRegOptionalOperand(GenTree* tree);
220
221     // ------------------------------------------------------------------
222     // SetRegOptionalBinOp - Indicates which of the operands of a bin-op
223     // register requirement is optional. Xarch instruction set allows
224     // either of op1 or op2 of binary operation (e.g. add, mul etc) to be
225     // a memory operand.  This routine provides info to register allocator
226     // which of its operands optionally require a register.  Lsra might not
227     // allocate a register to RefTypeUse positions of such operands if it
228     // is beneficial. In such a case codegen will treat them as memory
229     // operands.
230     //
231     // Arguments:
232     //     tree  -             Gentree of a binary operation.
233     //     isSafeToMarkOp1     True if it's safe to mark op1 as register optional
234     //     isSafeToMarkOp2     True if it's safe to mark op2 as register optional
235     //
236     // Returns
237     //     The caller is expected to get isSafeToMarkOp1 and isSafeToMarkOp2
238     //     by calling IsSafeToContainMem.
239     //
240     // Note: On xarch at most only one of the operands will be marked as
241     // reg optional, even when both operands could be considered register
242     // optional.
243     void SetRegOptionalForBinOp(GenTree* tree, bool isSafeToMarkOp1, bool isSafeToMarkOp2)
244     {
245         assert(GenTree::OperIsBinary(tree->OperGet()));
246
247         GenTree* const op1 = tree->gtGetOp1();
248         GenTree* const op2 = tree->gtGetOp2();
249
250         const unsigned operatorSize = genTypeSize(tree->TypeGet());
251
252         const bool op1Legal =
253             isSafeToMarkOp1 && tree->OperIsCommutative() && (operatorSize == genTypeSize(op1->TypeGet()));
254         const bool op2Legal = isSafeToMarkOp2 && (operatorSize == genTypeSize(op2->TypeGet()));
255
256         GenTree* regOptionalOperand = nullptr;
257         if (op1Legal)
258         {
259             regOptionalOperand = op2Legal ? PreferredRegOptionalOperand(tree) : op1;
260         }
261         else if (op2Legal)
262         {
263             regOptionalOperand = op2;
264         }
265         if (regOptionalOperand != nullptr)
266         {
267             regOptionalOperand->SetRegOptional();
268         }
269     }
270 #endif // defined(_TARGET_XARCH_)
271
272     // Per tree node member functions
273     void LowerStoreIndir(GenTreeIndir* node);
274     GenTree* LowerAdd(GenTree* node);
275     bool LowerUnsignedDivOrMod(GenTreeOp* divMod);
276     GenTree* LowerConstIntDivOrMod(GenTree* node);
277     GenTree* LowerSignedDivOrMod(GenTree* node);
278     void LowerBlockStore(GenTreeBlk* blkNode);
279     void LowerPutArgStk(GenTreePutArgStk* tree);
280
281     GenTree* TryCreateAddrMode(LIR::Use&& use, bool isIndir);
282     void AddrModeCleanupHelper(GenTreeAddrMode* addrMode, GenTree* node);
283
284     GenTree* LowerSwitch(GenTree* node);
285     bool TryLowerSwitchToBitTest(
286         BasicBlock* jumpTable[], unsigned jumpCount, unsigned targetCount, BasicBlock* bbSwitch, GenTree* switchValue);
287
288     void LowerCast(GenTree* node);
289
290 #if !CPU_LOAD_STORE_ARCH
291     bool IsRMWIndirCandidate(GenTree* operand, GenTree* storeInd);
292     bool IsBinOpInRMWStoreInd(GenTree* tree);
293     bool IsRMWMemOpRootedAtStoreInd(GenTree* storeIndTree, GenTree** indirCandidate, GenTree** indirOpSource);
294     bool LowerRMWMemOp(GenTreeIndir* storeInd);
295 #endif
296
297     void WidenSIMD12IfNecessary(GenTreeLclVarCommon* node);
298     void LowerStoreLoc(GenTreeLclVarCommon* tree);
299     GenTree* LowerArrElem(GenTree* node);
300     void LowerRotate(GenTree* tree);
301     void LowerShift(GenTreeOp* shift);
302 #ifdef FEATURE_SIMD
303     void LowerSIMD(GenTreeSIMD* simdNode);
304 #endif // FEATURE_SIMD
305 #ifdef FEATURE_HW_INTRINSICS
306     void LowerHWIntrinsic(GenTreeHWIntrinsic* node);
307 #endif // FEATURE_HW_INTRINSICS
308
309     // Utility functions
310 public:
311     static bool IndirsAreEquivalent(GenTree* pTreeA, GenTree* pTreeB);
312
313     // return true if 'childNode' is an immediate that can be contained
314     //  by the 'parentNode' (i.e. folded into an instruction)
315     //  for example small enough and non-relocatable
316     bool IsContainableImmed(GenTree* parentNode, GenTree* childNode);
317
318     // Return true if 'node' is a containable memory op.
319     bool IsContainableMemoryOp(GenTree* node)
320     {
321         return m_lsra->isContainableMemoryOp(node);
322     }
323
324 #ifdef FEATURE_HW_INTRINSICS
325     // Return true if 'node' is a containable HWIntrinsic op.
326     bool IsContainableHWIntrinsicOp(GenTreeHWIntrinsic* containingNode, GenTree* node, bool* supportsRegOptional);
327 #endif // FEATURE_HW_INTRINSICS
328
329 private:
330     static bool NodesAreEquivalentLeaves(GenTree* candidate, GenTree* storeInd);
331
332     bool AreSourcesPossiblyModifiedLocals(GenTree* addr, GenTree* base, GenTree* index);
333
334     // Makes 'childNode' contained in the 'parentNode'
335     void MakeSrcContained(GenTree* parentNode, GenTree* childNode);
336
337     // Checks and makes 'childNode' contained in the 'parentNode'
338     bool CheckImmedAndMakeContained(GenTree* parentNode, GenTree* childNode);
339
340     // Checks for memory conflicts in the instructions between childNode and parentNode, and returns true if childNode
341     // can be contained.
342     bool IsSafeToContainMem(GenTree* parentNode, GenTree* childNode);
343
344     inline LIR::Range& BlockRange() const
345     {
346         return LIR::AsRange(m_block);
347     }
348
349     // Any tracked lclVar accessed by a LCL_FLD or STORE_LCL_FLD should be marked doNotEnregister.
350     // This method checks, and asserts in the DEBUG case if it is not so marked,
351     // but in the non-DEBUG case (asserts disabled) set the flag so that we don't generate bad code.
352     // This ensures that the local's value is valid on-stack as expected for a *LCL_FLD.
353     void verifyLclFldDoNotEnregister(unsigned lclNum)
354     {
355         LclVarDsc* varDsc = &(comp->lvaTable[lclNum]);
356         // Do a couple of simple checks before setting lvDoNotEnregister.
357         // This may not cover all cases in 'isRegCandidate()' but we don't want to
358         // do an expensive check here. For non-candidates it is not harmful to set lvDoNotEnregister.
359         if (varDsc->lvTracked && !varDsc->lvDoNotEnregister)
360         {
361             assert(!m_lsra->isRegCandidate(varDsc));
362             comp->lvaSetVarDoNotEnregister(lclNum DEBUG_ARG(Compiler::DNER_LocalField));
363         }
364     }
365
366     LinearScan*   m_lsra;
367     unsigned      vtableCallTemp;       // local variable we use as a temp for vtable calls
368     SideEffectSet m_scratchSideEffects; // SideEffectSet used for IsSafeToContainMem and isRMWIndirCandidate
369     BasicBlock*   m_block;
370 };
371
372 #endif // _LOWER_H_