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
6XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7XX XX
8XX Lower XX
9XX XX
10XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
11XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
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
22class Lowering : public Phase
23{
24public:
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
43private:
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
310public:
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
329private:
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_
373