diff options
Diffstat (limited to 'src/jit/lower.cpp')
-rw-r--r-- | src/jit/lower.cpp | 205 |
1 files changed, 122 insertions, 83 deletions
diff --git a/src/jit/lower.cpp b/src/jit/lower.cpp index 0316a34a21..035f0947c2 100644 --- a/src/jit/lower.cpp +++ b/src/jit/lower.cpp @@ -42,9 +42,12 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX void Lowering::MakeSrcContained(GenTreePtr parentNode, GenTreePtr childNode) { assert(!parentNode->OperIsLeaf()); + assert(childNode->canBeContained()); + int srcCount = childNode->gtLsraInfo.srcCount; assert(srcCount >= 0); m_lsra->clearOperandCounts(childNode); + assert(parentNode->gtLsraInfo.srcCount > 0); parentNode->gtLsraInfo.srcCount += srcCount - 1; } @@ -465,7 +468,7 @@ GenTree* Lowering::LowerSwitch(GenTree* node) // both GT_SWITCH lowering code paths. // This condition is of the form: if (temp > jumpTableLength - 2){ goto jumpTable[jumpTableLength - 1]; } GenTreePtr gtDefaultCaseCond = comp->gtNewOperNode(GT_GT, TYP_INT, comp->gtNewLclvNode(tempLclNum, tempLclType), - comp->gtNewIconNode(jumpCnt - 2, TYP_INT)); + comp->gtNewIconNode(jumpCnt - 2, tempLclType)); // Make sure we perform an unsigned comparison, just in case the switch index in 'temp' // is now less than zero 0 (that would also hit the default case). @@ -678,9 +681,16 @@ GenTree* Lowering::LowerSwitch(GenTree* node) JITDUMP("Lowering switch BB%02u: using jump table expansion\n", originalSwitchBB->bbNum); + GenTree* switchValue = comp->gtNewLclvNode(tempLclNum, tempLclType); +#ifdef _TARGET_64BIT_ + if (tempLclType != TYP_I_IMPL) + { + // Note that the switch value is unsigned so the cast should be unsigned as well. + switchValue = comp->gtNewCastNode(TYP_I_IMPL, switchValue, TYP_U_IMPL); + } +#endif GenTreePtr gtTableSwitch = - comp->gtNewOperNode(GT_SWITCH_TABLE, TYP_VOID, comp->gtNewLclvNode(tempLclNum, tempLclType), - comp->gtNewJmpTableNode()); + comp->gtNewOperNode(GT_SWITCH_TABLE, TYP_VOID, switchValue, comp->gtNewJmpTableNode()); /* Increment the lvRefCnt and lvRefCntWtd for temp */ tempVarDsc->incRefCnts(blockWeight, comp); @@ -930,23 +940,11 @@ GenTreePtr Lowering::NewPutArg(GenTreeCall* call, GenTreePtr arg, fgArgTabEntryP // This provides the info to put this argument in in-coming arg area slot // instead of in out-going arg area slot. - PUT_STRUCT_ARG_STK_ONLY(assert(info->isStruct == varTypeIsStruct(type))); // Make sure state is - // correct + PUT_STRUCT_ARG_STK_ONLY(assert(info->isStruct == varTypeIsStruct(type))); // Make sure state is correct -#if FEATURE_FASTTAILCALL putArg = new (comp, GT_PUTARG_STK) GenTreePutArgStk(GT_PUTARG_STK, type, arg, info->slotNum PUT_STRUCT_ARG_STK_ONLY_ARG(info->numSlots), - call->IsFastTailCall() DEBUGARG(call)); -#else - putArg = new (comp, GT_PUTARG_STK) - GenTreePutArgStk(GT_PUTARG_STK, type, arg, - info->slotNum PUT_STRUCT_ARG_STK_ONLY_ARG(info->numSlots) DEBUGARG(call)); -#endif - -#if defined(UNIX_X86_ABI) - assert((info->padStkAlign > 0 && info->numSlots > 0) || (info->padStkAlign == 0)); - putArg->AsPutArgStk()->setArgPadding(info->padStkAlign); -#endif + call->IsFastTailCall(), call); #ifdef FEATURE_PUT_STRUCT_ARG_STK // If the ArgTabEntry indicates that this arg is a struct @@ -971,6 +969,43 @@ GenTreePtr Lowering::NewPutArg(GenTreeCall* call, GenTreePtr arg, fgArgTabEntryP assert(!varTypeIsSIMD(arg)); numRefs = comp->info.compCompHnd->getClassGClayout(arg->gtObj.gtClass, gcLayout); putArg->AsPutArgStk()->setGcPointers(numRefs, gcLayout); + +#ifdef _TARGET_X86_ + // On x86 VM lies about the type of a struct containing a pointer sized + // integer field by returning the type of its field as the type of struct. + // Such struct can be passed in a register depending its position in + // parameter list. VM does this unwrapping only one level and therefore + // a type like Struct Foo { Struct Bar { int f}} awlays needs to be + // passed on stack. Also, VM doesn't lie about type of such a struct + // when it is a field of another struct. That is VM doesn't lie about + // the type of Foo.Bar + // + // We now support the promotion of fields that are of type struct. + // However we only support a limited case where the struct field has a + // single field and that single field must be a scalar type. Say Foo.Bar + // field is getting passed as a parameter to a call, Since it is a TYP_STRUCT, + // as per x86 ABI it should always be passed on stack. Therefore GenTree + // node under a PUTARG_STK could be GT_OBJ(GT_LCL_VAR_ADDR(v1)), where + // local v1 could be a promoted field standing for Foo.Bar. Note that + // the type of v1 will be the type of field of Foo.Bar.f when Foo is + // promoted. That is v1 will be a scalar type. In this case we need to + // pass v1 on stack instead of in a register. + // + // TODO-PERF: replace GT_OBJ(GT_LCL_VAR_ADDR(v1)) with v1 if v1 is + // a scalar type and the width of GT_OBJ matches the type size of v1. + // Note that this cannot be done till call node arguments are morphed + // because we should not lose the fact that the type of argument is + // a struct so that the arg gets correctly marked to be passed on stack. + GenTree* objOp1 = arg->gtGetOp1(); + if (objOp1->OperGet() == GT_LCL_VAR_ADDR) + { + unsigned lclNum = objOp1->AsLclVarCommon()->GetLclNum(); + if (comp->lvaTable[lclNum].lvType != TYP_STRUCT) + { + comp->lvaSetVarDoNotEnregister(lclNum DEBUGARG(Compiler::DNER_VMNeedsStackAddr)); + } + } +#endif // _TARGET_X86_ } } #endif // FEATURE_PUT_STRUCT_ARG_STK @@ -1062,6 +1097,15 @@ void Lowering::LowerArg(GenTreeCall* call, GenTreePtr* ppArg) LclVarDsc* varDsc = &comp->lvaTable[varNum]; type = varDsc->lvType; } + else if (arg->OperGet() == GT_SIMD) + { + assert((arg->AsSIMD()->gtSIMDSize == 16) || (arg->AsSIMD()->gtSIMDSize == 12)); + + if (arg->AsSIMD()->gtSIMDSize == 12) + { + type = TYP_SIMD12; + } + } } #endif // defined(FEATURE_SIMD) && defined(_TARGET_X86_) @@ -1075,25 +1119,41 @@ void Lowering::LowerArg(GenTreeCall* call, GenTreePtr* ppArg) { if (isReg) { - NYI("Lowering of long register argument"); - } + noway_assert(arg->OperGet() == GT_LONG); + assert(info->numRegs == 2); + + GenTreePtr argLo = arg->gtGetOp1(); + GenTreePtr argHi = arg->gtGetOp2(); + + GenTreeFieldList* fieldList = new (comp, GT_FIELD_LIST) GenTreeFieldList(argLo, 0, TYP_INT, nullptr); + (void)new (comp, GT_FIELD_LIST) GenTreeFieldList(argHi, 4, TYP_INT, fieldList); - // For longs, we will replace the GT_LONG with a GT_FIELD_LIST, and put that under a PUTARG_STK. - // Although the hi argument needs to be pushed first, that will be handled by the general case, - // in which the fields will be reversed. - noway_assert(arg->OperGet() == GT_LONG); - assert(info->numSlots == 2); - GenTreePtr argLo = arg->gtGetOp1(); - GenTreePtr argHi = arg->gtGetOp2(); - GenTreeFieldList* fieldList = new (comp, GT_FIELD_LIST) GenTreeFieldList(argLo, 0, TYP_INT, nullptr); - // Only the first fieldList node (GTF_FIELD_LIST_HEAD) is in the instruction sequence. - (void)new (comp, GT_FIELD_LIST) GenTreeFieldList(argHi, 4, TYP_INT, fieldList); - putArg = NewPutArg(call, fieldList, info, TYP_VOID); - - // We can't call ReplaceArgWithPutArgOrCopy here because it presumes that we are keeping the original arg. - BlockRange().InsertBefore(arg, fieldList, putArg); - BlockRange().Remove(arg); - *ppArg = putArg; + putArg = NewPutArg(call, fieldList, info, TYP_VOID); + + BlockRange().InsertBefore(arg, putArg); + BlockRange().Remove(arg); + *ppArg = fieldList; + info->node = fieldList; + } + else + { + // For longs, we will replace the GT_LONG with a GT_FIELD_LIST, and put that under a PUTARG_STK. + // Although the hi argument needs to be pushed first, that will be handled by the general case, + // in which the fields will be reversed. + noway_assert(arg->OperGet() == GT_LONG); + assert(info->numSlots == 2); + GenTreePtr argLo = arg->gtGetOp1(); + GenTreePtr argHi = arg->gtGetOp2(); + GenTreeFieldList* fieldList = new (comp, GT_FIELD_LIST) GenTreeFieldList(argLo, 0, TYP_INT, nullptr); + // Only the first fieldList node (GTF_FIELD_LIST_HEAD) is in the instruction sequence. + (void)new (comp, GT_FIELD_LIST) GenTreeFieldList(argHi, 4, TYP_INT, fieldList); + putArg = NewPutArg(call, fieldList, info, TYP_VOID); + + // We can't call ReplaceArgWithPutArgOrCopy here because it presumes that we are keeping the original arg. + BlockRange().InsertBefore(arg, fieldList, putArg); + BlockRange().Remove(arg); + *ppArg = putArg; + } } else #endif // !defined(_TARGET_64BIT_) @@ -1187,9 +1247,6 @@ void Lowering::LowerCall(GenTree* node) LowerArgsForCall(call); -// RyuJIT arm is not set up for lowered call control -#ifndef _TARGET_ARM_ - // note that everything generated from this point on runs AFTER the outgoing args are placed GenTree* result = nullptr; @@ -1294,7 +1351,6 @@ void Lowering::LowerCall(GenTree* node) call->gtControlExpr = result; } -#endif //!_TARGET_ARM_ if (comp->opts.IsJit64Compat()) { @@ -2196,7 +2252,6 @@ void Lowering::LowerCompare(GenTree* cmp) // automatically inserts a cast from int32 to long on 64 bit architectures. However, the JIT // accidentally generates int/long comparisons internally: // - loop cloning compares int (and even small int) index limits against long constants - // - switch lowering compares a 64 bit switch value against a int32 constant // // TODO-Cleanup: The above mentioned issues should be fixed and then the code below may be // replaced with an assert or at least simplified. The special casing of constants in code @@ -2487,7 +2542,7 @@ GenTree* Lowering::LowerDirectCall(GenTreeCall* call) GenTree* indir = Ind(cellAddr); #ifdef FEATURE_READYTORUN_COMPILER -#ifdef _TARGET_ARM64_ +#if defined(_TARGET_ARMARCH_) // For arm64, we dispatch code same as VSD using X11 for indirection cell address, // which ZapIndirectHelperThunk expects. if (call->IsR2RRelativeIndir()) @@ -2780,6 +2835,9 @@ void Lowering::InsertPInvokeMethodProlog() JITDUMP("======= Inserting PInvoke method prolog\n"); + // The first BB must be a scratch BB in order for us to be able to safely insert the P/Invoke prolog. + assert(comp->fgFirstBBisScratch()); + LIR::Range& firstBlockRange = LIR::AsRange(comp->fgFirstBB); const CORINFO_EE_INFO* pInfo = comp->eeGetEEInfo(); @@ -2795,11 +2853,11 @@ void Lowering::InsertPInvokeMethodProlog() // for x86, don't pass the secretArg. CLANG_FORMAT_COMMENT_ANCHOR; -#ifdef _TARGET_X86_ +#if defined(_TARGET_X86_) || defined(_TARGET_ARM_) GenTreeArgList* argList = comp->gtNewArgList(frameAddr); -#else // !_TARGET_X86_ +#else GenTreeArgList* argList = comp->gtNewArgList(frameAddr, PhysReg(REG_SECRET_STUB_PARAM)); -#endif // !_TARGET_X86_ +#endif GenTree* call = comp->gtNewHelperCallNode(CORINFO_HELP_INIT_PINVOKE_FRAME, TYP_I_IMPL, 0, argList); @@ -2814,14 +2872,13 @@ void Lowering::InsertPInvokeMethodProlog() store->gtOp.gtOp1 = call; store->gtFlags |= GTF_VAR_DEF; - GenTree* insertionPoint = firstBlockRange.FirstNonPhiOrCatchArgNode(); - comp->fgMorphTree(store); - firstBlockRange.InsertBefore(insertionPoint, LIR::SeqTree(comp, store)); + firstBlockRange.InsertAtEnd(LIR::SeqTree(comp, store)); DISPTREERANGE(firstBlockRange, store); -#ifndef _TARGET_X86_ // For x86, this step is done at the call site (due to stack pointer not being static in the - // function). +#if !defined(_TARGET_X86_) && !defined(_TARGET_ARM_) + // For x86, this step is done at the call site (due to stack pointer not being static in the function). + // For arm32, CallSiteSP is set up by the call to CORINFO_HELP_INIT_PINVOKE_FRAME. // -------------------------------------------------------- // InlinedCallFrame.m_pCallSiteSP = @RSP; @@ -2830,10 +2887,13 @@ void Lowering::InsertPInvokeMethodProlog() GenTreeLclFld(GT_STORE_LCL_FLD, TYP_I_IMPL, comp->lvaInlinedPInvokeFrameVar, callFrameInfo.offsetOfCallSiteSP); storeSP->gtOp1 = PhysReg(REG_SPBASE); - firstBlockRange.InsertBefore(insertionPoint, LIR::SeqTree(comp, storeSP)); + firstBlockRange.InsertAtEnd(LIR::SeqTree(comp, storeSP)); DISPTREERANGE(firstBlockRange, storeSP); -#endif // !_TARGET_X86_ +#endif // !defined(_TARGET_X86_) && !defined(_TARGET_ARM_) + +#if !defined(_TARGET_ARM_) + // For arm32, CalleeSavedFP is set up by the call to CORINFO_HELP_INIT_PINVOKE_FRAME. // -------------------------------------------------------- // InlinedCallFrame.m_pCalleeSavedEBP = @RBP; @@ -2843,8 +2903,9 @@ void Lowering::InsertPInvokeMethodProlog() callFrameInfo.offsetOfCalleeSavedFP); storeFP->gtOp1 = PhysReg(REG_FPBASE); - firstBlockRange.InsertBefore(insertionPoint, LIR::SeqTree(comp, storeFP)); + firstBlockRange.InsertAtEnd(LIR::SeqTree(comp, storeFP)); DISPTREERANGE(firstBlockRange, storeFP); +#endif // !defined(_TARGET_ARM_) // -------------------------------------------------------- // On 32-bit targets, CORINFO_HELP_INIT_PINVOKE_FRAME initializes the PInvoke frame and then pushes it onto @@ -2857,7 +2918,7 @@ void Lowering::InsertPInvokeMethodProlog() // Push a frame - if we are NOT in an IL stub, this is done right before the call // The init routine sets InlinedCallFrame's m_pNext, so we just set the thead's top-of-stack GenTree* frameUpd = CreateFrameLinkUpdate(PushFrame); - firstBlockRange.InsertBefore(insertionPoint, LIR::SeqTree(comp, frameUpd)); + firstBlockRange.InsertAtEnd(LIR::SeqTree(comp, frameUpd)); DISPTREERANGE(firstBlockRange, frameUpd); } #endif // _TARGET_64BIT_ @@ -2964,7 +3025,6 @@ void Lowering::InsertPInvokeCallProlog(GenTreeCall* call) noway_assert(comp->lvaInlinedPInvokeFrameVar != BAD_VAR_NUM); -#if COR_JIT_EE_VERSION > 460 if (comp->opts.ShouldUsePInvokeHelpers()) { // First argument is the address of the frame variable. @@ -2980,7 +3040,6 @@ void Lowering::InsertPInvokeCallProlog(GenTreeCall* call) LowerNode(helperCall); // helper call is inserted before current node and should be lowered here. return; } -#endif // Emit the following sequence: // @@ -3113,7 +3172,6 @@ void Lowering::InsertPInvokeCallEpilog(GenTreeCall* call) { JITDUMP("======= Inserting PInvoke call epilog\n"); -#if COR_JIT_EE_VERSION > 460 if (comp->opts.ShouldUsePInvokeHelpers()) { noway_assert(comp->lvaInlinedPInvokeFrameVar != BAD_VAR_NUM); @@ -3131,7 +3189,6 @@ void Lowering::InsertPInvokeCallEpilog(GenTreeCall* call) BlockRange().InsertAfter(call, LIR::SeqTree(comp, helperCall)); return; } -#endif // gcstate = 1 GenTree* insertionPoint = call->gtNext; @@ -3252,18 +3309,7 @@ GenTree* Lowering::LowerNonvirtPinvokeCall(GenTreeCall* call) CORINFO_METHOD_HANDLE methHnd = call->gtCallMethHnd; CORINFO_CONST_LOOKUP lookup; -#if COR_JIT_EE_VERSION > 460 comp->info.compCompHnd->getAddressOfPInvokeTarget(methHnd, &lookup); -#else - void* pIndirection; - lookup.accessType = IAT_PVALUE; - lookup.addr = comp->info.compCompHnd->getAddressOfPInvokeFixup(methHnd, &pIndirection); - if (lookup.addr == nullptr) - { - lookup.accessType = IAT_PPVALUE; - lookup.addr = pIndirection; - } -#endif void* addr = lookup.addr; switch (lookup.accessType) @@ -4381,6 +4427,14 @@ void Lowering::DoPhase() #endif #endif + // If we have any PInvoke calls, insert the one-time prolog code. We'll inserted the epilog code in the + // appropriate spots later. NOTE: there is a minor optimization opportunity here, as we still create p/invoke + // data structures and setup/teardown even if we've eliminated all p/invoke calls due to dead code elimination. + if (comp->info.compCallUnmanaged) + { + InsertPInvokeMethodProlog(); + } + #if !defined(_TARGET_64BIT_) DecomposeLongs decomp(comp); // Initialize the long decomposition class. decomp.PrepareForDecomposition(); @@ -4398,14 +4452,6 @@ void Lowering::DoPhase() LowerBlock(block); } - // If we have any PInvoke calls, insert the one-time prolog code. We've already inserted the epilog code in the - // appropriate spots. NOTE: there is a minor optimization opportunity here, as we still create p/invoke data - // structures and setup/teardown even if we've eliminated all p/invoke calls due to dead code elimination. - if (comp->info.compCallUnmanaged) - { - InsertPInvokeMethodProlog(); - } - #ifdef DEBUG JITDUMP("Lower has completed modifying nodes, proceeding to initialize LSRA TreeNodeInfo structs...\n"); if (VERBOSE) @@ -4558,13 +4604,6 @@ void Lowering::CheckCallArg(GenTree* arg) switch (arg->OperGet()) { -#if !defined(_TARGET_64BIT_) - case GT_LONG: - assert(arg->gtGetOp1()->OperIsPutArg()); - assert(arg->gtGetOp2()->OperIsPutArg()); - break; -#endif - case GT_FIELD_LIST: { GenTreeFieldList* list = arg->AsFieldList(); |