summaryrefslogtreecommitdiff
path: root/src/jit/codegenxarch.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/jit/codegenxarch.cpp')
-rw-r--r--src/jit/codegenxarch.cpp345
1 files changed, 250 insertions, 95 deletions
diff --git a/src/jit/codegenxarch.cpp b/src/jit/codegenxarch.cpp
index e893da6035..23c2a186a4 100644
--- a/src/jit/codegenxarch.cpp
+++ b/src/jit/codegenxarch.cpp
@@ -241,7 +241,9 @@ BasicBlock* CodeGen::genCallFinally(BasicBlock* block)
if ((compiler->lvaPSPSym == BAD_VAR_NUM) ||
(!compiler->compLocallocUsed && (compiler->funCurrentFunc()->funKind == FUNC_ROOT)))
{
+#ifndef UNIX_X86_ABI
inst_RV_RV(INS_mov, REG_ARG_0, REG_SPBASE, TYP_I_IMPL);
+#endif // !UNIX_X86_ABI
}
else
{
@@ -1264,8 +1266,7 @@ void CodeGen::genCodeForTreeNode(GenTreePtr treeNode)
if (compiler->verbose)
{
unsigned seqNum = treeNode->gtSeqNum; // Useful for setting a conditional break in Visual Studio
- printf("Generating: ");
- compiler->gtDispTree(treeNode, nullptr, nullptr, true);
+ compiler->gtDispLIRNode(treeNode, "Generating: ");
}
#endif // DEBUG
@@ -1313,7 +1314,7 @@ void CodeGen::genCodeForTreeNode(GenTreePtr treeNode)
case GT_CNS_INT:
#ifdef _TARGET_X86_
- NYI_IF(treeNode->IsIconHandle(GTF_ICON_TLS_HDL), "TLS constants");
+ assert(!treeNode->IsIconHandle(GTF_ICON_TLS_HDL));
#endif // _TARGET_X86_
__fallthrough;
@@ -1624,6 +1625,7 @@ void CodeGen::genCodeForTreeNode(GenTreePtr treeNode)
break;
case GT_IND:
+ {
#ifdef FEATURE_SIMD
// Handling of Vector3 type values loaded through indirection.
if (treeNode->TypeGet() == TYP_SIMD12)
@@ -1633,10 +1635,21 @@ void CodeGen::genCodeForTreeNode(GenTreePtr treeNode)
}
#endif // FEATURE_SIMD
- genConsumeAddress(treeNode->AsIndir()->Addr());
- emit->emitInsMov(ins_Load(treeNode->TypeGet()), emitTypeSize(treeNode), treeNode);
+ GenTree* addr = treeNode->AsIndir()->Addr();
+ if (addr->IsCnsIntOrI() && addr->IsIconHandle(GTF_ICON_TLS_HDL))
+ {
+ noway_assert(EA_ATTR(genTypeSize(treeNode->gtType)) == EA_PTRSIZE);
+ emit->emitIns_R_C(ins_Load(TYP_I_IMPL), EA_PTRSIZE, treeNode->gtRegNum, FLD_GLOBAL_FS,
+ (int)addr->gtIntCon.gtIconVal);
+ }
+ else
+ {
+ genConsumeAddress(addr);
+ emit->emitInsMov(ins_Load(treeNode->TypeGet()), emitTypeSize(treeNode), treeNode);
+ }
genProduceReg(treeNode);
- break;
+ }
+ break;
case GT_MULHI:
#ifdef _TARGET_X86_
@@ -2008,7 +2021,7 @@ void CodeGen::genCodeForTreeNode(GenTreePtr treeNode)
break;
case GT_CALL:
- genCallInstruction(treeNode);
+ genCallInstruction(treeNode->AsCall());
break;
case GT_JMP:
@@ -3223,7 +3236,7 @@ void CodeGen::genCodeForCpBlkRepMovs(GenTreeBlk* cpBlkNode)
// On x86, longTmpReg must be an xmm reg; on x64 it must be an integer register.
// This is checked by genStoreRegToStackArg.
//
-int CodeGen::genMove8IfNeeded(unsigned size, regNumber longTmpReg, GenTree* srcAddr, unsigned offset)
+unsigned CodeGen::genMove8IfNeeded(unsigned size, regNumber longTmpReg, GenTree* srcAddr, unsigned offset)
{
#ifdef _TARGET_X86_
instruction longMovIns = INS_movq;
@@ -3257,7 +3270,7 @@ int CodeGen::genMove8IfNeeded(unsigned size, regNumber longTmpReg, GenTree* srcA
// intTmpReg must be an integer register.
// This is checked by genStoreRegToStackArg.
//
-int CodeGen::genMove4IfNeeded(unsigned size, regNumber intTmpReg, GenTree* srcAddr, unsigned offset)
+unsigned CodeGen::genMove4IfNeeded(unsigned size, regNumber intTmpReg, GenTree* srcAddr, unsigned offset)
{
if ((size & 4) != 0)
{
@@ -3286,7 +3299,7 @@ int CodeGen::genMove4IfNeeded(unsigned size, regNumber intTmpReg, GenTree* srcAd
// intTmpReg must be an integer register.
// This is checked by genStoreRegToStackArg.
//
-int CodeGen::genMove2IfNeeded(unsigned size, regNumber intTmpReg, GenTree* srcAddr, unsigned offset)
+unsigned CodeGen::genMove2IfNeeded(unsigned size, regNumber intTmpReg, GenTree* srcAddr, unsigned offset)
{
if ((size & 2) != 0)
{
@@ -3315,7 +3328,7 @@ int CodeGen::genMove2IfNeeded(unsigned size, regNumber intTmpReg, GenTree* srcAd
// intTmpReg must be an integer register.
// This is checked by genStoreRegToStackArg.
//
-int CodeGen::genMove1IfNeeded(unsigned size, regNumber intTmpReg, GenTree* srcAddr, unsigned offset)
+unsigned CodeGen::genMove1IfNeeded(unsigned size, regNumber intTmpReg, GenTree* srcAddr, unsigned offset)
{
if ((size & 1) != 0)
@@ -3352,7 +3365,7 @@ void CodeGen::genStructPutArgUnroll(GenTreePutArgStk* putArgNode)
GenTreePtr dstAddr = putArgNode;
GenTreePtr src = putArgNode->gtOp.gtOp1;
- size_t size = putArgNode->getArgSize();
+ unsigned size = putArgNode->getArgSize();
assert(size <= CPBLK_UNROLL_LIMIT);
emitter* emit = getEmitter();
@@ -3813,6 +3826,7 @@ void CodeGen::genLockedInstructions(GenTreeOp* treeNode)
regNumber targetReg = treeNode->gtRegNum;
regNumber dataReg = data->gtRegNum;
regNumber addrReg = addr->gtRegNum;
+ var_types type = genActualType(data->TypeGet());
instruction ins;
// The register allocator should have extended the lifetime of the address
@@ -3827,7 +3841,7 @@ void CodeGen::genLockedInstructions(GenTreeOp* treeNode)
genConsumeOperands(treeNode);
if (targetReg != REG_NA && dataReg != REG_NA && dataReg != targetReg)
{
- inst_RV_RV(ins_Copy(data->TypeGet()), targetReg, dataReg);
+ inst_RV_RV(ins_Copy(type), targetReg, dataReg);
data->gtRegNum = targetReg;
// TODO-XArch-Cleanup: Consider whether it is worth it, for debugging purposes, to restore the
@@ -3853,8 +3867,8 @@ void CodeGen::genLockedInstructions(GenTreeOp* treeNode)
// all of these nodes implicitly do an indirection on op1
// so create a temporary node to feed into the pattern matching
- GenTreeIndir i = indirForm(data->TypeGet(), addr);
- getEmitter()->emitInsBinary(ins, emitTypeSize(data), &i, data);
+ GenTreeIndir i = indirForm(type, addr);
+ getEmitter()->emitInsBinary(ins, emitTypeSize(type), &i, data);
if (treeNode->gtRegNum != REG_NA)
{
@@ -4749,10 +4763,9 @@ bool CodeGen::genEmitOptimizedGCWriteBarrier(GCInfo::WriteBarrierForm writeBarri
}
// Produce code for a GT_CALL node
-void CodeGen::genCallInstruction(GenTreePtr node)
+void CodeGen::genCallInstruction(GenTreeCall* call)
{
- GenTreeCall* call = node->AsCall();
- assert(call->gtOper == GT_CALL);
+ genAlignStackBeforeCall(call);
gtCallTypes callType = (gtCallTypes)call->gtCallType;
@@ -4913,7 +4926,7 @@ void CodeGen::genCallInstruction(GenTreePtr node)
if (callType == CT_INDIRECT)
{
assert(target == nullptr);
- target = call->gtCall.gtCallAddr;
+ target = call->gtCallAddr;
methHnd = nullptr;
}
else
@@ -4993,16 +5006,30 @@ void CodeGen::genCallInstruction(GenTreePtr node)
}
#if defined(_TARGET_X86_)
+ bool fCallerPop = (call->gtFlags & GTF_CALL_POP_ARGS) != 0;
+
+#ifdef UNIX_X86_ABI
+ {
+ CorInfoCallConv callConv = CORINFO_CALLCONV_DEFAULT;
+
+ if ((callType != CT_HELPER) && call->callSig)
+ {
+ callConv = call->callSig->callConv;
+ }
+
+ fCallerPop |= IsCallerPop(callConv);
+ }
+#endif // UNIX_X86_ABI
+
// If the callee pops the arguments, we pass a positive value as the argSize, and the emitter will
// adjust its stack level accordingly.
// If the caller needs to explicitly pop its arguments, we must pass a negative value, and then do the
// pop when we're done.
ssize_t argSizeForEmitter = stackArgBytes;
- if ((call->gtFlags & GTF_CALL_POP_ARGS) != 0)
+ if (fCallerPop)
{
argSizeForEmitter = -stackArgBytes;
}
-
#endif // defined(_TARGET_X86_)
#ifdef FEATURE_AVX_SUPPORT
@@ -5044,11 +5071,20 @@ void CodeGen::genCallInstruction(GenTreePtr node)
genCopyRegIfNeeded(addr, REG_VIRTUAL_STUB_TARGET);
getEmitter()->emitIns_Nop(3);
- getEmitter()->emitIns_Call(emitter::EmitCallType(emitter::EC_INDIR_ARD), methHnd,
- INDEBUG_LDISASM_COMMA(sigInfo) nullptr, argSizeForEmitter,
- retSize MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(secondRetSize),
- gcInfo.gcVarPtrSetCur, gcInfo.gcRegGCrefSetCur, gcInfo.gcRegByrefSetCur,
+
+ // clang-format off
+ getEmitter()->emitIns_Call(emitter::EmitCallType(emitter::EC_INDIR_ARD),
+ methHnd,
+ INDEBUG_LDISASM_COMMA(sigInfo)
+ nullptr,
+ argSizeForEmitter,
+ retSize
+ MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(secondRetSize),
+ gcInfo.gcVarPtrSetCur,
+ gcInfo.gcRegGCrefSetCur,
+ gcInfo.gcRegByrefSetCur,
ilOffset, REG_VIRTUAL_STUB_TARGET, REG_NA, 1, 0);
+ // clang-format on
}
else
#endif
@@ -5060,18 +5096,29 @@ void CodeGen::genCallInstruction(GenTreePtr node)
// contained only if it can be encoded as PC-relative offset.
assert(target->AsIndir()->Base()->AsIntConCommon()->FitsInAddrBase(compiler));
- genEmitCall(emitter::EC_FUNC_TOKEN_INDIR, methHnd,
- INDEBUG_LDISASM_COMMA(sigInfo)(void*) target->AsIndir()
- ->Base()
- ->AsIntConCommon()
- ->IconValue() X86_ARG(argSizeForEmitter),
- retSize MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(secondRetSize), ilOffset);
+ // clang-format off
+ genEmitCall(emitter::EC_FUNC_TOKEN_INDIR,
+ methHnd,
+ INDEBUG_LDISASM_COMMA(sigInfo)
+ (void*) target->AsIndir()->Base()->AsIntConCommon()->IconValue()
+ X86_ARG(argSizeForEmitter),
+ retSize
+ MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(secondRetSize),
+ ilOffset);
+ // clang-format on
}
else
{
- genEmitCall(emitter::EC_INDIR_ARD, methHnd,
- INDEBUG_LDISASM_COMMA(sigInfo) target->AsIndir() X86_ARG(argSizeForEmitter),
- retSize MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(secondRetSize), ilOffset);
+ // clang-format off
+ genEmitCall(emitter::EC_INDIR_ARD,
+ methHnd,
+ INDEBUG_LDISASM_COMMA(sigInfo)
+ target->AsIndir()
+ X86_ARG(argSizeForEmitter),
+ retSize
+ MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(secondRetSize),
+ ilOffset);
+ // clang-format on
}
}
else
@@ -5079,19 +5126,34 @@ void CodeGen::genCallInstruction(GenTreePtr node)
// We have already generated code for gtControlExpr evaluating it into a register.
// We just need to emit "call reg" in this case.
assert(genIsValidIntReg(target->gtRegNum));
- genEmitCall(emitter::EC_INDIR_R, methHnd,
- INDEBUG_LDISASM_COMMA(sigInfo) nullptr // addr
+
+ // clang-format off
+ genEmitCall(emitter::EC_INDIR_R,
+ methHnd,
+ INDEBUG_LDISASM_COMMA(sigInfo)
+ nullptr // addr
X86_ARG(argSizeForEmitter),
- retSize MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(secondRetSize), ilOffset, genConsumeReg(target));
+ retSize
+ MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(secondRetSize),
+ ilOffset,
+ genConsumeReg(target));
+ // clang-format on
}
}
#ifdef FEATURE_READYTORUN_COMPILER
else if (call->gtEntryPoint.addr != nullptr)
{
+ // clang-format off
genEmitCall((call->gtEntryPoint.accessType == IAT_VALUE) ? emitter::EC_FUNC_TOKEN
: emitter::EC_FUNC_TOKEN_INDIR,
- methHnd, INDEBUG_LDISASM_COMMA(sigInfo)(void*) call->gtEntryPoint.addr X86_ARG(argSizeForEmitter),
- retSize MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(secondRetSize), ilOffset);
+ methHnd,
+ INDEBUG_LDISASM_COMMA(sigInfo)
+ (void*) call->gtEntryPoint.addr
+ X86_ARG(argSizeForEmitter),
+ retSize
+ MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(secondRetSize),
+ ilOffset);
+ // clang-format on
}
#endif
else
@@ -5127,18 +5189,18 @@ void CodeGen::genCallInstruction(GenTreePtr node)
}
// Non-virtual direct calls to known addresses
- genEmitCall(emitter::EC_FUNC_TOKEN, methHnd, INDEBUG_LDISASM_COMMA(sigInfo) addr X86_ARG(argSizeForEmitter),
- retSize MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(secondRetSize), ilOffset);
- }
-#if defined(UNIX_X86_ABI)
- // Put back the stack pointer if there was any padding for stack alignment
- unsigned padStackAlign = call->fgArgInfo->GetPadStackAlign();
- if (padStackAlign != 0)
- {
- inst_RV_IV(INS_add, REG_SPBASE, padStackAlign * TARGET_POINTER_SIZE, EA_PTRSIZE);
+ // clang-format off
+ genEmitCall(emitter::EC_FUNC_TOKEN,
+ methHnd,
+ INDEBUG_LDISASM_COMMA(sigInfo)
+ addr
+ X86_ARG(argSizeForEmitter),
+ retSize
+ MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(secondRetSize),
+ ilOffset);
+ // clang-format on
}
-#endif // UNIX_X86_ABI
// if it was a pinvoke we may have needed to get the address of a label
if (genPendingCallLabel)
@@ -5148,11 +5210,6 @@ void CodeGen::genCallInstruction(GenTreePtr node)
genPendingCallLabel = nullptr;
}
-#if defined(_TARGET_X86_)
- // The call will pop its arguments.
- genStackLevel -= stackArgBytes;
-#endif // defined(_TARGET_X86_)
-
// Update GC info:
// All Callee arg registers are trashed and no longer contain any GC pointers.
// TODO-XArch-Bug?: As a matter of fact shouldn't we be killing all of callee trashed regs here?
@@ -5253,7 +5310,7 @@ void CodeGen::genCallInstruction(GenTreePtr node)
gcInfo.gcMarkRegSetNpt(RBM_INTRET);
}
-#if defined(_TARGET_X86_)
+#if !FEATURE_EH_FUNCLETS
//-------------------------------------------------------------------------
// Create a label for tracking of region protected by the monitor in synchronized methods.
// This needs to be here, rather than above where fPossibleSyncHelperCall is set,
@@ -5281,13 +5338,21 @@ void CodeGen::genCallInstruction(GenTreePtr node)
break;
}
}
+#endif // !FEATURE_EH_FUNCLETS
+
+ unsigned stackAdjustBias = 0;
+#if defined(_TARGET_X86_)
// Is the caller supposed to pop the arguments?
- if (((call->gtFlags & GTF_CALL_POP_ARGS) != 0) && (stackArgBytes != 0))
+ if (fCallerPop && (stackArgBytes != 0))
{
- genAdjustSP(stackArgBytes);
+ stackAdjustBias = stackArgBytes;
}
+
+ SubtractStackLevel(stackArgBytes);
#endif // _TARGET_X86_
+
+ genRemoveAlignmentAfterCall(call, stackAdjustBias);
}
// Produce code for a GT_JMP node.
@@ -7137,7 +7202,7 @@ int CodeGenInterface::genSPtoFPdelta()
{
int delta;
-#ifdef PLATFORM_UNIX
+#ifdef UNIX_AMD64_ABI
// We require frame chaining on Unix to support native tool unwinding (such as
// unwinding by the native debugger). We have a CLR-only extension to the
@@ -7145,7 +7210,7 @@ int CodeGenInterface::genSPtoFPdelta()
// If Unix ever supports EnC, the RSP == RBP assumption will have to be reevaluated.
delta = genTotalFrameSize();
-#else // !PLATFORM_UNIX
+#else // !UNIX_AMD64_ABI
// As per Amd64 ABI, RBP offset from initial RSP can be between 0 and 240 if
// RBP needs to be reported in unwind codes. This case would arise for methods
@@ -7171,7 +7236,7 @@ int CodeGenInterface::genSPtoFPdelta()
delta = genTotalFrameSize();
}
-#endif // !PLATFORM_UNIX
+#endif // !UNIX_AMD64_ABI
return delta;
}
@@ -7372,11 +7437,16 @@ void CodeGen::genIntrinsic(GenTreePtr treeNode)
switch (treeNode->gtIntrinsic.gtIntrinsicId)
{
case CORINFO_INTRINSIC_Sqrt:
- noway_assert(treeNode->TypeGet() == TYP_DOUBLE);
+ {
+ // Both operand and its result must be of the same floating point type.
+ GenTreePtr srcNode = treeNode->gtOp.gtOp1;
+ assert(varTypeIsFloating(srcNode));
+ assert(srcNode->TypeGet() == treeNode->TypeGet());
+
genConsumeOperands(treeNode->AsOp());
- getEmitter()->emitInsBinary(ins_FloatSqrt(treeNode->TypeGet()), emitTypeSize(treeNode), treeNode,
- treeNode->gtOp.gtOp1);
+ getEmitter()->emitInsBinary(ins_FloatSqrt(treeNode->TypeGet()), emitTypeSize(treeNode), treeNode, srcNode);
break;
+ }
case CORINFO_INTRINSIC_Abs:
genSSE2BitwiseOp(treeNode);
@@ -7415,16 +7485,10 @@ unsigned CodeGen::getBaseVarForPutArgStk(GenTreePtr treeNode)
unsigned baseVarNum;
-#if FEATURE_FASTTAILCALL
- bool putInIncomingArgArea = treeNode->AsPutArgStk()->putInIncomingArgArea;
-#else
- const bool putInIncomingArgArea = false;
-#endif
-
// Whether to setup stk arg in incoming or out-going arg area?
// Fast tail calls implemented as epilog+jmp = stk arg is setup in incoming arg area.
// All other calls - stk arg is setup in out-going arg area.
- if (putInIncomingArgArea)
+ if (treeNode->AsPutArgStk()->putInIncomingArgArea())
{
// See the note in the function header re: finding the first stack passed argument.
baseVarNum = getFirstArgWithStackSlot();
@@ -7461,7 +7525,96 @@ unsigned CodeGen::getBaseVarForPutArgStk(GenTreePtr treeNode)
return baseVarNum;
}
+//---------------------------------------------------------------------
+// genAlignStackBeforeCall: Align the stack if necessary before a call.
+//
+// Arguments:
+// putArgStk - the putArgStk node.
+//
+void CodeGen::genAlignStackBeforeCall(GenTreePutArgStk* putArgStk)
+{
+#if defined(UNIX_X86_ABI)
+
+ genAlignStackBeforeCall(putArgStk->gtCall);
+
+#endif // UNIX_X86_ABI
+}
+
+//---------------------------------------------------------------------
+// genAlignStackBeforeCall: Align the stack if necessary before a call.
+//
+// Arguments:
+// call - the call node.
+//
+void CodeGen::genAlignStackBeforeCall(GenTreeCall* call)
+{
+#if defined(UNIX_X86_ABI)
+
+ // Have we aligned the stack yet?
+ if (!call->fgArgInfo->IsStkAlignmentDone())
+ {
+ // We haven't done any stack alignment yet for this call. We might need to create
+ // an alignment adjustment, even if this function itself doesn't have any stack args.
+ // This can happen if this function call is part of a nested call sequence, and the outer
+ // call has already pushed some arguments.
+
+ unsigned stkLevel = genStackLevel + call->fgArgInfo->GetStkSizeBytes();
+ call->fgArgInfo->ComputeStackAlignment(stkLevel);
+
+ unsigned padStkAlign = call->fgArgInfo->GetStkAlign();
+ if (padStkAlign != 0)
+ {
+ // Now generate the alignment
+ inst_RV_IV(INS_sub, REG_SPBASE, padStkAlign, EA_PTRSIZE);
+ AddStackLevel(padStkAlign);
+ AddNestedAlignment(padStkAlign);
+ }
+
+ call->fgArgInfo->SetStkAlignmentDone();
+ }
+
+#endif // UNIX_X86_ABI
+}
+
+//---------------------------------------------------------------------
+// genRemoveAlignmentAfterCall: After a call, remove the alignment
+// added before the call, if any.
+//
+// Arguments:
+// call - the call node.
+// bias - additional stack adjustment
+//
+// Note:
+// When bias > 0, caller should adjust stack level appropriately as
+// bias is not considered when adjusting stack level.
+//
+void CodeGen::genRemoveAlignmentAfterCall(GenTreeCall* call, unsigned bias)
+{
+#if defined(_TARGET_X86_)
+#if defined(UNIX_X86_ABI)
+ // Put back the stack pointer if there was any padding for stack alignment
+ unsigned padStkAlign = call->fgArgInfo->GetStkAlign();
+ unsigned padStkAdjust = padStkAlign + bias;
+
+ if (padStkAdjust != 0)
+ {
+ inst_RV_IV(INS_add, REG_SPBASE, padStkAdjust, EA_PTRSIZE);
+ SubtractStackLevel(padStkAlign);
+ SubtractNestedAlignment(padStkAlign);
+ }
+#else // UNIX_X86_ABI
+ if (bias != 0)
+ {
+ genAdjustSP(bias);
+ }
+#endif // !UNIX_X86_ABI_
+#else // _TARGET_X86_
+ assert(bias == 0);
+#endif // !_TARGET_X86
+}
+
#ifdef _TARGET_X86_
+
//---------------------------------------------------------------------
// genAdjustStackForPutArgStk:
// adjust the stack pointer for a putArgStk node if necessary.
@@ -7484,7 +7637,7 @@ bool CodeGen::genAdjustStackForPutArgStk(GenTreePutArgStk* putArgStk)
{
const unsigned argSize = genTypeSize(putArgStk);
inst_RV_IV(INS_sub, REG_SPBASE, argSize, EA_PTRSIZE);
- genStackLevel += argSize;
+ AddStackLevel(argSize);
m_pushStkArg = false;
return true;
}
@@ -7528,7 +7681,7 @@ bool CodeGen::genAdjustStackForPutArgStk(GenTreePutArgStk* putArgStk)
{
m_pushStkArg = false;
inst_RV_IV(INS_sub, REG_SPBASE, argSize, EA_PTRSIZE);
- genStackLevel += argSize;
+ AddStackLevel(argSize);
return true;
}
}
@@ -7616,7 +7769,7 @@ void CodeGen::genPutArgStkFieldList(GenTreePutArgStk* putArgStk)
{
inst_IV(INS_push, 0);
currentOffset -= pushSize;
- genStackLevel += pushSize;
+ AddStackLevel(pushSize);
adjustment -= pushSize;
}
m_pushStkArg = true;
@@ -7638,7 +7791,7 @@ void CodeGen::genPutArgStkFieldList(GenTreePutArgStk* putArgStk)
// Adjust the stack pointer to the next slot boundary.
inst_RV_IV(INS_sub, REG_SPBASE, adjustment, EA_PTRSIZE);
currentOffset -= adjustment;
- genStackLevel += adjustment;
+ AddStackLevel(adjustment);
}
// Does it need to be in a byte register?
@@ -7691,7 +7844,7 @@ void CodeGen::genPutArgStkFieldList(GenTreePutArgStk* putArgStk)
}
}
currentOffset -= TARGET_POINTER_SIZE;
- genStackLevel += TARGET_POINTER_SIZE;
+ AddStackLevel(TARGET_POINTER_SIZE);
}
else
{
@@ -7713,14 +7866,14 @@ void CodeGen::genPutArgStkFieldList(GenTreePutArgStk* putArgStk)
}
else
{
-#if defined(_TARGET_X86_) && defined(FEATURE_SIMD)
+#if defined(FEATURE_SIMD)
if (fieldType == TYP_SIMD12)
{
assert(genIsValidFloatReg(simdTmpReg));
genStoreSIMD12ToStack(argReg, simdTmpReg);
}
else
-#endif // defined(_TARGET_X86_) && defined(FEATURE_SIMD)
+#endif // defined(FEATURE_SIMD)
{
genStoreRegToStackArg(fieldType, argReg, fieldOffset - currentOffset);
}
@@ -7737,7 +7890,7 @@ void CodeGen::genPutArgStkFieldList(GenTreePutArgStk* putArgStk)
{
// We don't expect padding at the beginning of a struct, but it could happen with explicit layout.
inst_RV_IV(INS_sub, REG_SPBASE, currentOffset, EA_PTRSIZE);
- genStackLevel += currentOffset;
+ AddStackLevel(currentOffset);
}
}
#endif // _TARGET_X86_
@@ -7758,15 +7911,7 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* putArgStk)
#ifdef _TARGET_X86_
-#if defined(UNIX_X86_ABI)
- // For each call, first stack argument has the padding for alignment
- // if this value is not zero, use it to adjust the ESP
- unsigned argPadding = putArgStk->getArgPadding();
- if (argPadding != 0)
- {
- inst_RV_IV(INS_sub, REG_SPBASE, argPadding * TARGET_POINTER_SIZE, EA_PTRSIZE);
- }
-#endif
+ genAlignStackBeforeCall(putArgStk);
if (varTypeIsStruct(targetType))
{
@@ -7797,7 +7942,7 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* putArgStk)
{
inst_IV(INS_push, data->gtIntCon.gtIconVal);
}
- genStackLevel += argSize;
+ AddStackLevel(argSize);
}
else if (data->OperGet() == GT_FIELD_LIST)
{
@@ -7896,7 +8041,7 @@ void CodeGen::genPushReg(var_types type, regNumber srcReg)
inst_RV_IV(INS_sub, REG_SPBASE, size, EA_PTRSIZE);
getEmitter()->emitIns_AR_R(ins, attr, srcReg, REG_SPBASE, 0);
}
- genStackLevel += size;
+ AddStackLevel(size);
}
#endif // _TARGET_X86_
@@ -8094,7 +8239,7 @@ void CodeGen::genPutStructArgStk(GenTreePutArgStk* putArgStk)
{
getEmitter()->emitIns_S(INS_push, slotAttr, srcLclNum, srcLclOffset + offset);
}
- genStackLevel += TARGET_POINTER_SIZE;
+ AddStackLevel(TARGET_POINTER_SIZE);
}
#else // !defined(_TARGET_X86_)
@@ -8354,12 +8499,14 @@ void CodeGen::genCreateAndStoreGCInfoX64(unsigned codeSize, unsigned prologSize
// Follow the code pattern of the x86 gc info encoder (genCreateAndStoreGCInfoJIT32).
gcInfo.gcInfoBlockHdrSave(gcInfoEncoder, codeSize, prologSize);
+ // We keep the call count for the second call to gcMakeRegPtrTable() below.
+ unsigned callCnt = 0;
// First we figure out the encoder ID's for the stack slots and registers.
- gcInfo.gcMakeRegPtrTable(gcInfoEncoder, codeSize, prologSize, GCInfo::MAKE_REG_PTR_MODE_ASSIGN_SLOTS);
+ gcInfo.gcMakeRegPtrTable(gcInfoEncoder, codeSize, prologSize, GCInfo::MAKE_REG_PTR_MODE_ASSIGN_SLOTS, &callCnt);
// Now we've requested all the slots we'll need; "finalize" these (make more compact data structures for them).
gcInfoEncoder->FinalizeSlotIds();
// Now we can actually use those slot ID's to declare live ranges.
- gcInfo.gcMakeRegPtrTable(gcInfoEncoder, codeSize, prologSize, GCInfo::MAKE_REG_PTR_MODE_DO_WORK);
+ gcInfo.gcMakeRegPtrTable(gcInfoEncoder, codeSize, prologSize, GCInfo::MAKE_REG_PTR_MODE_DO_WORK, &callCnt);
if (compiler->opts.compDbgEnC)
{
@@ -8466,14 +8613,22 @@ void CodeGen::genEmitHelperCall(unsigned helper, int argSize, emitAttr retSize,
}
}
- getEmitter()->emitIns_Call(callType, compiler->eeFindHelper(helper), INDEBUG_LDISASM_COMMA(nullptr) addr, argSize,
- retSize FEATURE_UNIX_AMD64_STRUCT_PASSING_ONLY_ARG(EA_UNKNOWN), gcInfo.gcVarPtrSetCur,
- gcInfo.gcRegGCrefSetCur, gcInfo.gcRegByrefSetCur,
+ // clang-format off
+ getEmitter()->emitIns_Call(callType,
+ compiler->eeFindHelper(helper),
+ INDEBUG_LDISASM_COMMA(nullptr) addr,
+ argSize,
+ retSize
+ MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(EA_UNKNOWN),
+ gcInfo.gcVarPtrSetCur,
+ gcInfo.gcRegGCrefSetCur,
+ gcInfo.gcRegByrefSetCur,
BAD_IL_OFFSET, // IL offset
callTarget, // ireg
REG_NA, 0, 0, // xreg, xmul, disp
false, // isJump
emitter::emitNoGChelper(helper));
+ // clang-format on
regTracker.rsTrashRegSet(killMask);
regTracker.rsTrashRegsForGCInterruptability();