| 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_ |
| 373 | |