summaryrefslogtreecommitdiff
path: root/src/jit/codegenlegacy.cpp
diff options
context:
space:
mode:
authorMichelle McDaniel <adiaaida@gmail.com>2016-08-09 13:15:05 -0700
committerMichelle McDaniel <adiaaida@gmail.com>2016-08-11 09:53:41 -0700
commit36a2b906c008cd3693a9ab5aef7b4402addd6c74 (patch)
tree27333c6f26304490169825ae1c17484534246dc6 /src/jit/codegenlegacy.cpp
parentab7d6a8df73d3d89210a778338feaa9fedf4146a (diff)
downloadcoreclr-36a2b906c008cd3693a9ab5aef7b4402addd6c74.tar.gz
coreclr-36a2b906c008cd3693a9ab5aef7b4402addd6c74.tar.bz2
coreclr-36a2b906c008cd3693a9ab5aef7b4402addd6c74.zip
Reformat jit sources with clang-tidy and format
This change is the result of running clang-tidy and clang-format on jit sources.
Diffstat (limited to 'src/jit/codegenlegacy.cpp')
-rw-r--r--src/jit/codegenlegacy.cpp14194
1 files changed, 6790 insertions, 7404 deletions
diff --git a/src/jit/codegenlegacy.cpp b/src/jit/codegenlegacy.cpp
index 78edd0cc6a..feb4540907 100644
--- a/src/jit/codegenlegacy.cpp
+++ b/src/jit/codegenlegacy.cpp
@@ -33,7 +33,6 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
#include "gcinfoencoder.h"
#endif
-
/*****************************************************************************
*
* Determine what variables die between beforeSet and afterSet, and
@@ -41,13 +40,12 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
* compiler->compCurLife, gcInfo.gcVarPtrSetCur, regSet.rsMaskVars, gcInfo.gcRegGCrefSetCur, gcInfo.gcRegByrefSetCur
*/
-void CodeGen::genDyingVars(VARSET_VALARG_TP beforeSet,
- VARSET_VALARG_TP afterSet)
+void CodeGen::genDyingVars(VARSET_VALARG_TP beforeSet, VARSET_VALARG_TP afterSet)
{
- unsigned varNum;
- LclVarDsc * varDsc;
- regMaskTP regBit;
- VARSET_TP VARSET_INIT_NOCOPY(deadSet, VarSetOps::Diff(compiler, beforeSet, afterSet));
+ unsigned varNum;
+ LclVarDsc* varDsc;
+ regMaskTP regBit;
+ VARSET_TP VARSET_INIT_NOCOPY(deadSet, VarSetOps::Diff(compiler, beforeSet, afterSet));
if (VarSetOps::IsEmpty(compiler, deadSet))
return;
@@ -75,7 +73,7 @@ void CodeGen::genDyingVars(VARSET_VALARG_TP beforeSet,
if (!varDsc->lvRegister)
{
-#ifdef DEBUG
+#ifdef DEBUG
if (compiler->verbose)
{
printf("\t\t\t\t\t\t\tV%02u,T%02u is a dyingVar\n", varNum, varDsc->lvVarIndex);
@@ -85,7 +83,7 @@ void CodeGen::genDyingVars(VARSET_VALARG_TP beforeSet,
}
#if !FEATURE_FP_REGALLOC
- // We don't do FP-enreg of vars whose liveness changes in GTF_COLON_COND
+ // We don't do FP-enreg of vars whose liveness changes in GTF_COLON_COND
if (!varDsc->IsFloatRegType())
#endif
{
@@ -98,17 +96,18 @@ void CodeGen::genDyingVars(VARSET_VALARG_TP beforeSet,
else
{
regBit = genRegMask(varDsc->lvRegNum);
- if (isRegPairType(varDsc->lvType) && varDsc->lvOtherReg != REG_STK)
+ if (isRegPairType(varDsc->lvType) && varDsc->lvOtherReg != REG_STK)
regBit |= genRegMask(varDsc->lvOtherReg);
}
-#ifdef DEBUG
+#ifdef DEBUG
if (compiler->verbose)
{
- printf("\t\t\t\t\t\t\tV%02u,T%02u in reg %s is a dyingVar\n", varNum, varDsc->lvVarIndex, compiler->compRegVarName(varDsc->lvRegNum));
+ printf("\t\t\t\t\t\t\tV%02u,T%02u in reg %s is a dyingVar\n", varNum, varDsc->lvVarIndex,
+ compiler->compRegVarName(varDsc->lvRegNum));
}
#endif
- noway_assert((regSet.rsMaskVars & regBit) != 0);
+ noway_assert((regSet.rsMaskVars & regBit) != 0);
regSet.RemoveMaskVars(regBit);
@@ -125,17 +124,16 @@ void CodeGen::genDyingVars(VARSET_VALARG_TP beforeSet,
* Change the given enregistered local variable node to a register variable node
*/
-void CodeGenInterface::genBashLclVar(GenTreePtr tree, unsigned varNum,
- LclVarDsc* varDsc)
+void CodeGenInterface::genBashLclVar(GenTreePtr tree, unsigned varNum, LclVarDsc* varDsc)
{
noway_assert(tree->gtOper == GT_LCL_VAR);
noway_assert(varDsc->lvRegister);
- if (isRegPairType(varDsc->lvType))
+ if (isRegPairType(varDsc->lvType))
{
/* Check for the case of a variable that was narrowed to an int */
- if (isRegPairType(tree->gtType))
+ if (isRegPairType(tree->gtType))
{
genMarkTreeInRegPair(tree, gen2regs2pair(varDsc->lvRegNum, varDsc->lvOtherReg));
return;
@@ -153,20 +151,19 @@ void CodeGenInterface::genBashLclVar(GenTreePtr tree, unsigned
unsigned livenessFlags = (tree->gtFlags & GTF_LIVENESS_MASK);
- ValueNumPair vnp = tree->gtVNPair; // Save the ValueNumPair
+ ValueNumPair vnp = tree->gtVNPair; // Save the ValueNumPair
tree->SetOper(GT_REG_VAR);
- tree->gtVNPair = vnp; // Preserve the ValueNumPair, as SetOper will clear it.
+ tree->gtVNPair = vnp; // Preserve the ValueNumPair, as SetOper will clear it.
- tree->gtFlags |= livenessFlags;
- tree->gtFlags |= GTF_REG_VAL;
- tree->gtRegNum = varDsc->lvRegNum;
- tree->gtRegVar.gtRegNum = varDsc->lvRegNum;
+ tree->gtFlags |= livenessFlags;
+ tree->gtFlags |= GTF_REG_VAL;
+ tree->gtRegNum = varDsc->lvRegNum;
+ tree->gtRegVar.gtRegNum = varDsc->lvRegNum;
tree->gtRegVar.SetLclNum(varNum);
-
}
// inline
-void CodeGen::saveLiveness(genLivenessSet * ls)
+void CodeGen::saveLiveness(genLivenessSet* ls)
{
VarSetOps::Assign(compiler, ls->liveSet, compiler->compCurLife);
VarSetOps::Assign(compiler, ls->varPtrSet, gcInfo.gcVarPtrSetCur);
@@ -176,7 +173,7 @@ void CodeGen::saveLiveness(genLivenessSet * ls)
}
// inline
-void CodeGen::restoreLiveness(genLivenessSet * ls)
+void CodeGen::restoreLiveness(genLivenessSet* ls)
{
VarSetOps::Assign(compiler, compiler->compCurLife, ls->liveSet);
VarSetOps::Assign(compiler, gcInfo.gcVarPtrSetCur, ls->varPtrSet);
@@ -186,20 +183,20 @@ void CodeGen::restoreLiveness(genLivenessSet * ls)
}
// inline
-void CodeGen::checkLiveness(genLivenessSet * ls)
+void CodeGen::checkLiveness(genLivenessSet* ls)
{
assert(VarSetOps::Equal(compiler, compiler->compCurLife, ls->liveSet));
assert(VarSetOps::Equal(compiler, gcInfo.gcVarPtrSetCur, ls->varPtrSet));
- assert(regSet.rsMaskVars == ls->maskVars);
+ assert(regSet.rsMaskVars == ls->maskVars);
assert(gcInfo.gcRegGCrefSetCur == ls->gcRefRegs);
assert(gcInfo.gcRegByrefSetCur == ls->byRefRegs);
}
// inline
-bool CodeGenInterface::genMarkLclVar(GenTreePtr tree)
+bool CodeGenInterface::genMarkLclVar(GenTreePtr tree)
{
- unsigned varNum;
- LclVarDsc * varDsc;
+ unsigned varNum;
+ LclVarDsc* varDsc;
assert(tree->gtOper == GT_LCL_VAR);
@@ -209,7 +206,7 @@ bool CodeGenInterface::genMarkLclVar(GenTreePtr tree)
assert(varNum < compiler->lvaCount);
varDsc = compiler->lvaTable + varNum;
- if (varDsc->lvRegister)
+ if (varDsc->lvRegister)
{
genBashLclVar(tree, varNum, varDsc);
return true;
@@ -221,66 +218,65 @@ bool CodeGenInterface::genMarkLclVar(GenTreePtr tree)
}
// inline
-GenTreePtr CodeGen::genGetAddrModeBase(GenTreePtr tree)
+GenTreePtr CodeGen::genGetAddrModeBase(GenTreePtr tree)
{
- bool rev;
- unsigned mul;
- unsigned cns;
- GenTreePtr adr;
- GenTreePtr idx;
-
- if (genCreateAddrMode(tree, // address
- 0, // mode
- false, // fold
- RBM_NONE, // reg mask
- &rev, // reverse ops
- &adr, // base addr
- &idx, // index val
+ bool rev;
+ unsigned mul;
+ unsigned cns;
+ GenTreePtr adr;
+ GenTreePtr idx;
+
+ if (genCreateAddrMode(tree, // address
+ 0, // mode
+ false, // fold
+ RBM_NONE, // reg mask
+ &rev, // reverse ops
+ &adr, // base addr
+ &idx, // index val
#if SCALED_ADDR_MODES
- &mul, // scaling
+ &mul, // scaling
#endif
- &cns, // displacement
- true)) // don't generate code
- return adr;
+ &cns, // displacement
+ true)) // don't generate code
+ return adr;
else
- return NULL;
+ return NULL;
}
// inline
-void CodeGen::genSinglePush()
+void CodeGen::genSinglePush()
{
genStackLevel += sizeof(void*);
}
// inline
-void CodeGen::genSinglePop()
+void CodeGen::genSinglePop()
{
genStackLevel -= sizeof(void*);
}
-
#if FEATURE_STACK_FP_X87
// inline
-void CodeGenInterface::genResetFPstkLevel(unsigned newValue /* = 0 */)
+void CodeGenInterface::genResetFPstkLevel(unsigned newValue /* = 0 */)
{
genFPstkLevel = newValue;
}
// inline
-unsigned CodeGenInterface::genGetFPstkLevel()
+unsigned CodeGenInterface::genGetFPstkLevel()
{
return genFPstkLevel;
}
// inline
-void CodeGenInterface::genIncrementFPstkLevel(unsigned inc /* = 1 */)
+void CodeGenInterface::genIncrementFPstkLevel(unsigned inc /* = 1 */)
{
noway_assert((inc == 0) || genFPstkLevel + inc > genFPstkLevel);
genFPstkLevel += inc;
}
// inline
-void CodeGenInterface::genDecrementFPstkLevel(unsigned dec /* = 1 */)
+void CodeGenInterface::genDecrementFPstkLevel(unsigned dec /* = 1 */)
{
noway_assert((dec == 0) || genFPstkLevel - dec < genFPstkLevel);
genFPstkLevel -= dec;
@@ -293,18 +289,15 @@ void CodeGenInterface::genDecrementFPstkLevel(unsigned dec /* = 1 */)
* Generate code that will set the given register to the integer constant.
*/
-void CodeGen::genSetRegToIcon(regNumber reg,
- ssize_t val,
- var_types type,
- insFlags flags)
+void CodeGen::genSetRegToIcon(regNumber reg, ssize_t val, var_types type, insFlags flags)
{
- noway_assert(type != TYP_REF || val== NULL);
+ noway_assert(type != TYP_REF || val == NULL);
/* Does the reg already hold this constant? */
- if (!regTracker.rsIconIsInReg(val, reg))
+ if (!regTracker.rsIconIsInReg(val, reg))
{
- if (val == 0)
+ if (val == 0)
{
instGen_Set_Reg_To_Zero(emitActualTypeSize(type), reg, flags);
}
@@ -336,11 +329,7 @@ void CodeGen::genSetRegToIcon(regNumber reg,
if (delta == (signed char)delta)
{
/* use an lea instruction to set reg */
- getEmitter()->emitIns_R_AR (INS_lea,
- emitTypeSize(type),
- reg,
- srcReg,
- (int)delta);
+ getEmitter()->emitIns_R_AR(INS_lea, emitTypeSize(type), reg, srcReg, (int)delta);
constantLoaded = true;
}
#elif defined(_TARGET_ARM_)
@@ -348,8 +337,10 @@ void CodeGen::genSetRegToIcon(regNumber reg,
That is, the value we need is 'regS + delta'.
We one to generate one of the following instructions, listed in order of preference:
- adds regD, delta ; 2 bytes. if regD == regS, regD is a low register, and 0<=delta<=255
- subs regD, delta ; 2 bytes. if regD == regS, regD is a low register, and -255<=delta<=0
+ adds regD, delta ; 2 bytes. if regD == regS, regD is a low register, and
+ 0<=delta<=255
+ subs regD, delta ; 2 bytes. if regD == regS, regD is a low register, and
+ -255<=delta<=0
adds regD, regS, delta ; 2 bytes. if regD and regS are low registers and 0<=delta<=7
subs regD, regS, delta ; 2 bytes. if regD and regS are low registers and -7<=delta<=0
mov regD, icon ; 4 bytes. icon is a wacky Thumb 12-bit immediate.
@@ -365,15 +356,17 @@ void CodeGen::genSetRegToIcon(regNumber reg,
0x80000000. In this case, delta will be 1.
*/
- bool useAdd = false;
+ bool useAdd = false;
regMaskTP regMask = genRegMask(reg);
regMaskTP srcRegMask = genRegMask(srcReg);
- if ((flags != INS_FLAGS_NOT_SET) && (reg == srcReg) && (regMask & RBM_LOW_REGS) && (unsigned_abs(delta) <= 255))
+ if ((flags != INS_FLAGS_NOT_SET) && (reg == srcReg) && (regMask & RBM_LOW_REGS) &&
+ (unsigned_abs(delta) <= 255))
{
useAdd = true;
}
- else if ((flags != INS_FLAGS_NOT_SET) && (regMask & RBM_LOW_REGS) && (srcRegMask & RBM_LOW_REGS) && (unsigned_abs(delta) <= 7))
+ else if ((flags != INS_FLAGS_NOT_SET) && (regMask & RBM_LOW_REGS) && (srcRegMask & RBM_LOW_REGS) &&
+ (unsigned_abs(delta) <= 7))
{
useAdd = true;
}
@@ -388,12 +381,7 @@ void CodeGen::genSetRegToIcon(regNumber reg,
if (useAdd)
{
- getEmitter()->emitIns_R_R_I (INS_add,
- EA_4BYTE,
- reg,
- srcReg,
- delta,
- flags);
+ getEmitter()->emitIns_R_R_I(INS_add, EA_4BYTE, reg, srcReg, delta, flags);
constantLoaded = true;
}
#else
@@ -411,10 +399,9 @@ void CodeGen::genSetRegToIcon(regNumber reg,
inst_RV_IV(INS_OR, reg, val, emitActualTypeSize(type));
}
else
- /* For SMALL_CODE it is smaller to push a small immediate and
- then pop it into the dest register */
- if ((compiler->compCodeOpt() == Compiler::SMALL_CODE) &&
- val == (signed char)val)
+ /* For SMALL_CODE it is smaller to push a small immediate and
+ then pop it into the dest register */
+ if ((compiler->compCodeOpt() == Compiler::SMALL_CODE) && val == (signed char)val)
{
/* "mov" has no s(sign)-bit and so always takes 6 bytes,
whereas push+pop takes 2+1 bytes */
@@ -426,7 +413,7 @@ void CodeGen::genSetRegToIcon(regNumber reg,
genSinglePop();
}
else
-#endif // _TARGET_X86_
+#endif // _TARGET_X86_
{
instGen_Set_Reg_To_Imm(emitActualTypeSize(type), reg, val, flags);
}
@@ -449,9 +436,7 @@ void CodeGen::genSetRegToIcon(regNumber reg,
*
*/
-regNumber CodeGen::genGetRegSetToIcon(ssize_t val,
- regMaskTP regBest /* = 0 */,
- var_types type /* = TYP_INT */)
+regNumber CodeGen::genGetRegSetToIcon(ssize_t val, regMaskTP regBest /* = 0 */, var_types type /* = TYP_INT */)
{
regNumber regCns;
#if REDUNDANT_LOAD
@@ -459,7 +444,7 @@ regNumber CodeGen::genGetRegSetToIcon(ssize_t val,
// Is there already a register with zero that we can use?
regCns = regTracker.rsIconIsInReg(val);
- if (regCns == REG_NA)
+ if (regCns == REG_NA)
#endif
{
// If not, grab a register to hold the constant, preferring
@@ -474,8 +459,6 @@ regNumber CodeGen::genGetRegSetToIcon(ssize_t val,
return regCns;
}
-
-
/*****************************************************************************/
/*****************************************************************************
*
@@ -483,50 +466,46 @@ regNumber CodeGen::genGetRegSetToIcon(ssize_t val,
* 'tree' is the resulting tree
*/
-void CodeGen::genIncRegBy(regNumber reg,
- ssize_t ival,
- GenTreePtr tree,
- var_types dstType,
- bool ovfl)
+void CodeGen::genIncRegBy(regNumber reg, ssize_t ival, GenTreePtr tree, var_types dstType, bool ovfl)
{
- bool setFlags = (tree!=NULL) && tree->gtSetFlags();
+ bool setFlags = (tree != NULL) && tree->gtSetFlags();
#ifdef _TARGET_XARCH_
/* First check to see if we can generate inc or dec instruction(s) */
/* But avoid inc/dec on P4 in general for fast code or inside loops for blended code */
if (!ovfl && !compiler->optAvoidIncDec(compiler->compCurBB->getBBWeight(compiler)))
{
- emitAttr size = emitTypeSize(dstType);
+ emitAttr size = emitTypeSize(dstType);
switch (ival)
{
- case 2:
- inst_RV(INS_inc, reg, dstType, size);
- __fallthrough;
- case 1:
- inst_RV(INS_inc, reg, dstType, size);
+ case 2:
+ inst_RV(INS_inc, reg, dstType, size);
+ __fallthrough;
+ case 1:
+ inst_RV(INS_inc, reg, dstType, size);
- goto UPDATE_LIVENESS;
+ goto UPDATE_LIVENESS;
- case -2:
- inst_RV(INS_dec, reg, dstType, size);
- __fallthrough;
- case -1:
- inst_RV(INS_dec, reg, dstType, size);
+ case -2:
+ inst_RV(INS_dec, reg, dstType, size);
+ __fallthrough;
+ case -1:
+ inst_RV(INS_dec, reg, dstType, size);
- goto UPDATE_LIVENESS;
+ goto UPDATE_LIVENESS;
}
}
#endif
- insFlags flags = setFlags ? INS_FLAGS_SET : INS_FLAGS_DONT_CARE;
+ insFlags flags = setFlags ? INS_FLAGS_SET : INS_FLAGS_DONT_CARE;
inst_RV_IV(INS_add, reg, ival, emitActualTypeSize(dstType), flags);
#ifdef _TARGET_XARCH_
UPDATE_LIVENESS:
#endif
- if (setFlags)
+ if (setFlags)
genFlagsEqualToReg(tree, reg);
regTracker.rsTrackRegTrash(reg);
@@ -544,7 +523,6 @@ UPDATE_LIVENESS:
}
}
-
/*****************************************************************************
*
* Subtract the given constant from the specified register.
@@ -555,11 +533,10 @@ UPDATE_LIVENESS:
* 'tree' is the resulting tree.
*/
-void CodeGen::genDecRegBy(regNumber reg,
- ssize_t ival,
- GenTreePtr tree)
+void CodeGen::genDecRegBy(regNumber reg, ssize_t ival, GenTreePtr tree)
{
- noway_assert((tree->gtFlags & GTF_OVERFLOW) && ((tree->gtFlags & GTF_UNSIGNED) || ival == ((tree->gtType == TYP_INT) ? INT32_MIN : SSIZE_T_MIN)));
+ noway_assert((tree->gtFlags & GTF_OVERFLOW) &&
+ ((tree->gtFlags & GTF_UNSIGNED) || ival == ((tree->gtType == TYP_INT) ? INT32_MIN : SSIZE_T_MIN)));
noway_assert(tree->gtType == TYP_INT || tree->gtType == TYP_I_IMPL);
regTracker.rsTrackRegTrash(reg);
@@ -567,7 +544,7 @@ void CodeGen::genDecRegBy(regNumber reg,
noway_assert(!varTypeIsGC(tree->TypeGet()));
gcInfo.gcMarkRegSetNpt(genRegMask(reg));
- insFlags flags = tree->gtSetFlags() ? INS_FLAGS_SET : INS_FLAGS_DONT_CARE;
+ insFlags flags = tree->gtSetFlags() ? INS_FLAGS_SET : INS_FLAGS_DONT_CARE;
inst_RV_IV(INS_sub, reg, ival, emitActualTypeSize(tree->TypeGet()), flags);
if (tree->gtSetFlags())
@@ -585,11 +562,7 @@ void CodeGen::genDecRegBy(regNumber reg,
* 'tree' is the resulting tree
*/
-void CodeGen::genMulRegBy(regNumber reg,
- ssize_t ival,
- GenTreePtr tree,
- var_types dstType,
- bool ovfl)
+void CodeGen::genMulRegBy(regNumber reg, ssize_t ival, GenTreePtr tree, var_types dstType, bool ovfl)
{
noway_assert(genActualType(dstType) == TYP_INT || genActualType(dstType) == TYP_I_IMPL);
@@ -600,10 +573,10 @@ void CodeGen::genMulRegBy(regNumber reg,
genMarkTreeInReg(tree, reg);
}
- bool use_shift = false;
- unsigned shift_by = 0;
+ bool use_shift = false;
+ unsigned shift_by = 0;
- if ((dstType >= TYP_INT) && !ovfl && (ival > 0) && ((ival & (ival-1)) == 0))
+ if ((dstType >= TYP_INT) && !ovfl && (ival > 0) && ((ival & (ival - 1)) == 0))
{
use_shift = true;
BitScanForwardPtr((ULONG*)&shift_by, (ULONG)ival);
@@ -613,15 +586,15 @@ void CodeGen::genMulRegBy(regNumber reg,
{
if (shift_by != 0)
{
- insFlags flags = tree->gtSetFlags() ? INS_FLAGS_SET : INS_FLAGS_DONT_CARE;
+ insFlags flags = tree->gtSetFlags() ? INS_FLAGS_SET : INS_FLAGS_DONT_CARE;
inst_RV_SH(INS_SHIFT_LEFT_LOGICAL, emitTypeSize(dstType), reg, shift_by, flags);
- if (tree->gtSetFlags())
+ if (tree->gtSetFlags())
genFlagsEqualToReg(tree, reg);
}
}
else
{
- instruction ins;
+ instruction ins;
#ifdef _TARGET_XARCH_
ins = getEmitter()->inst3opImulForReg(reg);
#else
@@ -636,7 +609,7 @@ void CodeGen::genMulRegBy(regNumber reg,
/*****************************************************************************/
/*****************************************************************************
*
- * Compute the value 'tree' into a register that's in 'needReg'
+ * Compute the value 'tree' into a register that's in 'needReg'
* (or any free register if 'needReg' is RBM_NONE).
*
* Note that 'needReg' is just a recommendation unless mustReg==RegSet::EXACT_REG.
@@ -645,37 +618,26 @@ void CodeGen::genMulRegBy(regNumber reg,
* If you require that the register returned is trashable, pass true for 'freeOnly'.
*/
-void CodeGen::genComputeReg(GenTreePtr tree,
- regMaskTP needReg,
- RegSet::ExactReg mustReg,
- RegSet::KeepReg keepReg,
- bool freeOnly)
+void CodeGen::genComputeReg(
+ GenTreePtr tree, regMaskTP needReg, RegSet::ExactReg mustReg, RegSet::KeepReg keepReg, bool freeOnly)
{
noway_assert(tree->gtType != TYP_VOID);
-
- regNumber reg;
- regNumber rg2;
+
+ regNumber reg;
+ regNumber rg2;
#if FEATURE_STACK_FP_X87
- noway_assert(genActualType(tree->gtType) == TYP_INT ||
- genActualType(tree->gtType) == TYP_I_IMPL ||
- genActualType(tree->gtType) == TYP_REF ||
- tree->gtType == TYP_BYREF);
+ noway_assert(genActualType(tree->gtType) == TYP_INT || genActualType(tree->gtType) == TYP_I_IMPL ||
+ genActualType(tree->gtType) == TYP_REF || tree->gtType == TYP_BYREF);
#elif defined(_TARGET_ARM_)
- noway_assert(genActualType(tree->gtType) == TYP_INT ||
- genActualType(tree->gtType) == TYP_I_IMPL ||
- genActualType(tree->gtType) == TYP_REF ||
- tree->gtType == TYP_BYREF ||
- genActualType(tree->gtType) == TYP_FLOAT ||
- genActualType(tree->gtType) == TYP_DOUBLE ||
+ noway_assert(genActualType(tree->gtType) == TYP_INT || genActualType(tree->gtType) == TYP_I_IMPL ||
+ genActualType(tree->gtType) == TYP_REF || tree->gtType == TYP_BYREF ||
+ genActualType(tree->gtType) == TYP_FLOAT || genActualType(tree->gtType) == TYP_DOUBLE ||
genActualType(tree->gtType) == TYP_STRUCT);
#else
- noway_assert(genActualType(tree->gtType) == TYP_INT ||
- genActualType(tree->gtType) == TYP_I_IMPL ||
- genActualType(tree->gtType) == TYP_REF ||
- tree->gtType == TYP_BYREF ||
- genActualType(tree->gtType) == TYP_FLOAT ||
- genActualType(tree->gtType) == TYP_DOUBLE);
+ noway_assert(genActualType(tree->gtType) == TYP_INT || genActualType(tree->gtType) == TYP_I_IMPL ||
+ genActualType(tree->gtType) == TYP_REF || tree->gtType == TYP_BYREF ||
+ genActualType(tree->gtType) == TYP_FLOAT || genActualType(tree->gtType) == TYP_DOUBLE);
#endif
/* Generate the value, hopefully into the right register */
@@ -696,7 +658,7 @@ void CodeGen::genComputeReg(GenTreePtr tree,
/* Did the value end up in an acceptable register? */
- if ((mustReg == RegSet::EXACT_REG) && needReg && !(genRegMask(reg) & needReg))
+ if ((mustReg == RegSet::EXACT_REG) && needReg && !(genRegMask(reg) & needReg))
{
/* Not good enough to satisfy the caller's orders */
@@ -714,12 +676,12 @@ void CodeGen::genComputeReg(GenTreePtr tree,
{
/* Do we have to end up with a free register? */
- if (!freeOnly)
+ if (!freeOnly)
goto REG_OK;
/* Did we luck out and the value got computed into an unused reg? */
- if (genRegMask(reg) & regSet.rsRegMaskFree())
+ if (genRegMask(reg) & regSet.rsRegMaskFree())
goto REG_OK;
/* Register already in use, so spill previous value */
@@ -738,11 +700,11 @@ void CodeGen::genComputeReg(GenTreePtr tree,
{
/* OK, let's find a trashable home for the value */
- regMaskTP rv1RegUsed;
+ regMaskTP rv1RegUsed;
- regSet.rsLockReg (genRegMask(reg), &rv1RegUsed);
+ regSet.rsLockReg(genRegMask(reg), &rv1RegUsed);
rg2 = regSet.rsPickReg(needReg);
- regSet.rsUnlockReg(genRegMask(reg), rv1RegUsed);
+ regSet.rsUnlockReg(genRegMask(reg), rv1RegUsed);
}
}
@@ -769,7 +731,7 @@ REG_OK:
/* Does the caller want us to mark the register as used? */
- if (keepReg == RegSet::KEEP_REG)
+ if (keepReg == RegSet::KEEP_REG)
{
/* In case we're computing a value into a register variable */
@@ -788,9 +750,7 @@ REG_OK:
*/
// inline
-void CodeGen::genCompIntoFreeReg(GenTreePtr tree,
- regMaskTP needReg,
- RegSet::KeepReg keepReg)
+void CodeGen::genCompIntoFreeReg(GenTreePtr tree, regMaskTP needReg, RegSet::KeepReg keepReg)
{
genComputeReg(tree, needReg, RegSet::ANY_REG, keepReg, true);
}
@@ -801,9 +761,9 @@ void CodeGen::genCompIntoFreeReg(GenTreePtr tree,
* register (but also make sure the value is presently in a register).
*/
-void CodeGen::genReleaseReg(GenTreePtr tree)
+void CodeGen::genReleaseReg(GenTreePtr tree)
{
- if (tree->gtFlags & GTF_SPILLED)
+ if (tree->gtFlags & GTF_SPILLED)
{
/* The register has been spilled -- reload it */
@@ -822,11 +782,9 @@ void CodeGen::genReleaseReg(GenTreePtr tree)
* where tree will be recovered to, so we disallow keepReg==RegSet::FREE_REG for GC type trees.
*/
-void CodeGen::genRecoverReg(GenTreePtr tree,
- regMaskTP needReg,
- RegSet::KeepReg keepReg)
+void CodeGen::genRecoverReg(GenTreePtr tree, regMaskTP needReg, RegSet::KeepReg keepReg)
{
- if (tree->gtFlags & GTF_SPILLED)
+ if (tree->gtFlags & GTF_SPILLED)
{
/* The register has been spilled -- reload it */
@@ -838,16 +796,16 @@ void CodeGen::genRecoverReg(GenTreePtr tree,
/* We need the tree in another register. So move it there */
noway_assert(tree->gtFlags & GTF_REG_VAL);
- regNumber oldReg = tree->gtRegNum;
+ regNumber oldReg = tree->gtRegNum;
/* Pick an acceptable register */
- regNumber reg = regSet.rsGrabReg(needReg);
+ regNumber reg = regSet.rsGrabReg(needReg);
/* Copy the value */
inst_RV_RV(INS_mov, reg, oldReg, tree->TypeGet());
- tree->gtRegNum = reg;
+ tree->gtRegNum = reg;
gcInfo.gcMarkRegPtrVal(tree);
regSet.rsMarkRegUsed(tree);
@@ -858,7 +816,7 @@ void CodeGen::genRecoverReg(GenTreePtr tree,
/* Free the register if the caller desired so */
- if (keepReg == RegSet::FREE_REG)
+ if (keepReg == RegSet::FREE_REG)
{
regSet.rsMarkRegFree(genRegMask(tree->gtRegNum));
// Can't use RegSet::FREE_REG on a GC type
@@ -870,19 +828,15 @@ void CodeGen::genRecoverReg(GenTreePtr tree,
}
}
-
/*****************************************************************************
*
* Move one half of a register pair to its new regPair(half).
*/
// inline
-void CodeGen::genMoveRegPairHalf(GenTreePtr tree,
- regNumber dst,
- regNumber src,
- int off)
+void CodeGen::genMoveRegPairHalf(GenTreePtr tree, regNumber dst, regNumber src, int off)
{
- if (src == REG_STK)
+ if (src == REG_STK)
{
// handle long to unsigned long overflow casts
while (tree->gtOper == GT_CAST)
@@ -913,16 +867,14 @@ void CodeGen::genMoveRegPairHalf(GenTreePtr tree,
* assume that the current register pair is marked as used and free it.
*/
-void CodeGen::genMoveRegPair(GenTreePtr tree,
- regMaskTP needReg,
- regPairNo newPair)
+void CodeGen::genMoveRegPair(GenTreePtr tree, regMaskTP needReg, regPairNo newPair)
{
- regPairNo oldPair;
+ regPairNo oldPair;
- regNumber oldLo;
- regNumber oldHi;
- regNumber newLo;
- regNumber newHi;
+ regNumber oldLo;
+ regNumber oldHi;
+ regNumber newLo;
+ regNumber newHi;
/* Either a target set or a specific pair may be requested */
@@ -930,42 +882,41 @@ void CodeGen::genMoveRegPair(GenTreePtr tree,
/* Get hold of the current pair */
- oldPair = tree->gtRegPair; noway_assert(oldPair != newPair);
+ oldPair = tree->gtRegPair;
+ noway_assert(oldPair != newPair);
/* Are we supposed to move to a specific pair? */
- if (newPair != REG_PAIR_NONE)
+ if (newPair != REG_PAIR_NONE)
{
- regMaskTP oldMask = genRegPairMask(oldPair);
- regMaskTP loMask = genRegMask(genRegPairLo(newPair));
- regMaskTP hiMask = genRegMask(genRegPairHi(newPair));
- regMaskTP overlap = oldMask & (loMask|hiMask);
+ regMaskTP oldMask = genRegPairMask(oldPair);
+ regMaskTP loMask = genRegMask(genRegPairLo(newPair));
+ regMaskTP hiMask = genRegMask(genRegPairHi(newPair));
+ regMaskTP overlap = oldMask & (loMask | hiMask);
/* First lock any registers that are in both pairs */
- noway_assert((regSet.rsMaskUsed & overlap) == overlap);
- noway_assert((regSet.rsMaskLock & overlap) == 0);
- regSet.rsMaskLock |= overlap;
+ noway_assert((regSet.rsMaskUsed & overlap) == overlap);
+ noway_assert((regSet.rsMaskLock & overlap) == 0);
+ regSet.rsMaskLock |= overlap;
/* Make sure any additional registers we need are free */
- if ((loMask & regSet.rsMaskUsed) != 0 &&
- (loMask & oldMask ) == 0)
+ if ((loMask & regSet.rsMaskUsed) != 0 && (loMask & oldMask) == 0)
{
regSet.rsGrabReg(loMask);
}
- if ((hiMask & regSet.rsMaskUsed) != 0 &&
- (hiMask & oldMask ) == 0)
+ if ((hiMask & regSet.rsMaskUsed) != 0 && (hiMask & oldMask) == 0)
{
regSet.rsGrabReg(hiMask);
}
/* Unlock those registers we have temporarily locked */
- noway_assert((regSet.rsMaskUsed & overlap) == overlap);
- noway_assert((regSet.rsMaskLock & overlap) == overlap);
- regSet.rsMaskLock -= overlap;
+ noway_assert((regSet.rsMaskUsed & overlap) == overlap);
+ noway_assert((regSet.rsMaskLock & overlap) == overlap);
+ regSet.rsMaskLock -= overlap;
/* We can now free the old pair */
@@ -979,18 +930,13 @@ void CodeGen::genMoveRegPair(GenTreePtr tree,
}
// If grabbed pair is the same as old one we're done
- if (newPair==oldPair)
+ if (newPair == oldPair)
{
- noway_assert(
- (oldLo = genRegPairLo(oldPair),
- oldHi = genRegPairHi(oldPair),
- newLo = genRegPairLo(newPair),
- newHi = genRegPairHi(newPair),
- newLo != REG_STK && newHi != REG_STK));
+ noway_assert((oldLo = genRegPairLo(oldPair), oldHi = genRegPairHi(oldPair), newLo = genRegPairLo(newPair),
+ newHi = genRegPairHi(newPair), newLo != REG_STK && newHi != REG_STK));
return;
}
-
/* Move the values from the old pair into the new one */
oldLo = genRegPairLo(oldPair);
@@ -1002,7 +948,7 @@ void CodeGen::genMoveRegPair(GenTreePtr tree,
/* Careful - the register pairs might overlap */
- if (newLo == oldLo)
+ if (newLo == oldLo)
{
/* The low registers are identical, just move the upper half */
@@ -1013,7 +959,7 @@ void CodeGen::genMoveRegPair(GenTreePtr tree,
{
/* The low registers are different, are the upper ones the same? */
- if (newHi == oldHi)
+ if (newHi == oldHi)
{
/* Just move the lower half, then */
genMoveRegPairHalf(tree, newLo, oldLo, 0);
@@ -1022,11 +968,11 @@ void CodeGen::genMoveRegPair(GenTreePtr tree,
{
/* Both sets are different - is there an overlap? */
- if (newLo == oldHi)
+ if (newLo == oldHi)
{
/* Are high and low simply swapped ? */
- if (newHi == oldLo)
+ if (newHi == oldLo)
{
#ifdef _TARGET_ARM_
/* Let's use XOR swap to reduce register pressure. */
@@ -1058,7 +1004,7 @@ void CodeGen::genMoveRegPair(GenTreePtr tree,
/* Record the fact that we're switching to another pair */
- tree->gtRegPair = newPair;
+ tree->gtRegPair = newPair;
}
/*****************************************************************************
@@ -1070,18 +1016,15 @@ void CodeGen::genMoveRegPair(GenTreePtr tree,
* value ends up in as being used.
*/
-void CodeGen::genComputeRegPair(GenTreePtr tree,
- regPairNo needRegPair,
- regMaskTP avoidReg,
- RegSet::KeepReg keepReg,
- bool freeOnly)
+void CodeGen::genComputeRegPair(
+ GenTreePtr tree, regPairNo needRegPair, regMaskTP avoidReg, RegSet::KeepReg keepReg, bool freeOnly)
{
- regMaskTP regMask;
- regPairNo regPair;
- regMaskTP tmpMask;
- regMaskTP tmpUsedMask;
- regNumber rLo;
- regNumber rHi;
+ regMaskTP regMask;
+ regPairNo regPair;
+ regMaskTP tmpMask;
+ regMaskTP tmpUsedMask;
+ regNumber rLo;
+ regNumber rHi;
noway_assert(isRegPairType(tree->gtType));
@@ -1115,8 +1058,8 @@ void CodeGen::genComputeRegPair(GenTreePtr tree,
regPair = tree->gtRegPair;
tmpMask = genRegPairMask(regPair);
- rLo = genRegPairLo(regPair);
- rHi = genRegPairHi(regPair);
+ rLo = genRegPairLo(regPair);
+ rHi = genRegPairHi(regPair);
/* At least one half is in a real register */
@@ -1124,9 +1067,9 @@ void CodeGen::genComputeRegPair(GenTreePtr tree,
/* Did the value end up in an acceptable register pair? */
- if (needRegPair != REG_PAIR_NONE)
+ if (needRegPair != REG_PAIR_NONE)
{
- if (needRegPair != regPair)
+ if (needRegPair != regPair)
{
/* This is a workaround. If we specify a regPair for genMoveRegPair */
/* it expects the source pair being marked as used */
@@ -1134,11 +1077,11 @@ void CodeGen::genComputeRegPair(GenTreePtr tree,
genMoveRegPair(tree, 0, needRegPair);
}
}
- else if (freeOnly)
+ else if (freeOnly)
{
/* Do we have to end up with a free register pair?
Something might have gotten freed up above */
- bool mustMoveReg=false;
+ bool mustMoveReg = false;
regMask = regSet.rsRegMaskFree() & ~avoidReg;
@@ -1161,7 +1104,7 @@ void CodeGen::genComputeRegPair(GenTreePtr tree,
/* Did the value end up in a free register pair? */
- if (mustMoveReg)
+ if (mustMoveReg)
{
/* We'll have to move the value to a free (trashable) pair */
genMoveRegPair(tree, regMask, REG_PAIR_NONE);
@@ -1173,8 +1116,8 @@ void CodeGen::genComputeRegPair(GenTreePtr tree,
noway_assert(!freeOnly);
/* it is possible to have tmpMask also in the regSet.rsMaskUsed */
- tmpUsedMask = tmpMask & regSet.rsMaskUsed;
- tmpMask &= ~regSet.rsMaskUsed;
+ tmpUsedMask = tmpMask & regSet.rsMaskUsed;
+ tmpMask &= ~regSet.rsMaskUsed;
/* Make sure that the value is in "real" registers*/
if (rLo == REG_STK)
@@ -1219,7 +1162,7 @@ void CodeGen::genComputeRegPair(GenTreePtr tree,
/* Does the caller want us to mark the register as used? */
- if (keepReg == RegSet::KEEP_REG)
+ if (keepReg == RegSet::KEEP_REG)
{
/* In case we're computing a value into a register variable */
@@ -1238,9 +1181,7 @@ void CodeGen::genComputeRegPair(GenTreePtr tree,
*/
// inline
-void CodeGen::genCompIntoFreeRegPair(GenTreePtr tree,
- regMaskTP avoidReg,
- RegSet::KeepReg keepReg)
+void CodeGen::genCompIntoFreeRegPair(GenTreePtr tree, regMaskTP avoidReg, RegSet::KeepReg keepReg)
{
genComputeRegPair(tree, REG_PAIR_NONE, avoidReg, keepReg, true);
}
@@ -1252,9 +1193,9 @@ void CodeGen::genCompIntoFreeRegPair(GenTreePtr tree,
* pair).
*/
-void CodeGen::genReleaseRegPair(GenTreePtr tree)
+void CodeGen::genReleaseRegPair(GenTreePtr tree)
{
- if (tree->gtFlags & GTF_SPILLED)
+ if (tree->gtFlags & GTF_SPILLED)
{
/* The register has been spilled -- reload it */
@@ -1272,11 +1213,9 @@ void CodeGen::genReleaseRegPair(GenTreePtr tree)
* if 'keepReg' is 0, free the register pair.
*/
-void CodeGen::genRecoverRegPair(GenTreePtr tree,
- regPairNo regPair,
- RegSet::KeepReg keepReg)
+void CodeGen::genRecoverRegPair(GenTreePtr tree, regPairNo regPair, RegSet::KeepReg keepReg)
{
- if (tree->gtFlags & GTF_SPILLED)
+ if (tree->gtFlags & GTF_SPILLED)
{
regMaskTP regMask;
@@ -1292,7 +1231,7 @@ void CodeGen::genRecoverRegPair(GenTreePtr tree,
/* Does the caller insist on the value being in a specific place? */
- if (regPair != REG_PAIR_NONE && regPair != tree->gtRegPair)
+ if (regPair != REG_PAIR_NONE && regPair != tree->gtRegPair)
{
/* No good -- we'll have to move the value to a new place */
@@ -1300,7 +1239,7 @@ void CodeGen::genRecoverRegPair(GenTreePtr tree,
/* Mark the pair as used if appropriate */
- if (keepReg == RegSet::KEEP_REG)
+ if (keepReg == RegSet::KEEP_REG)
regSet.rsMarkRegPairUsed(tree);
return;
@@ -1308,7 +1247,7 @@ void CodeGen::genRecoverRegPair(GenTreePtr tree,
/* Free the register pair if the caller desired so */
- if (keepReg == RegSet::FREE_REG)
+ if (keepReg == RegSet::FREE_REG)
regSet.rsMarkRegFree(genRegPairMask(tree->gtRegPair));
}
@@ -1319,7 +1258,7 @@ void CodeGen::genRecoverRegPair(GenTreePtr tree,
*/
// inline
-void CodeGen::genEvalIntoFreeRegPair(GenTreePtr tree, regPairNo regPair, regMaskTP avoidReg)
+void CodeGen::genEvalIntoFreeRegPair(GenTreePtr tree, regPairNo regPair, regMaskTP avoidReg)
{
genComputeRegPair(tree, regPair, avoidReg, RegSet::KEEP_REG);
genRecoverRegPair(tree, regPair, RegSet::FREE_REG);
@@ -1334,17 +1273,17 @@ void CodeGen::genEvalIntoFreeRegPair(GenTreePtr tree, regPairNo regPair,
*/
// inline
-void CodeGen::genMakeRegPairAvailable(regPairNo regPair)
+void CodeGen::genMakeRegPairAvailable(regPairNo regPair)
{
/* Make sure the target of the store is available */
- regNumber regLo = genRegPairLo(regPair);
- regNumber regHi = genRegPairHi(regPair);
+ regNumber regLo = genRegPairLo(regPair);
+ regNumber regHi = genRegPairHi(regPair);
- if ((regHi != REG_STK) && (regSet.rsMaskUsed & genRegMask(regHi)))
+ if ((regHi != REG_STK) && (regSet.rsMaskUsed & genRegMask(regHi)))
regSet.rsSpillReg(regHi);
- if ((regLo != REG_STK) && (regSet.rsMaskUsed & genRegMask(regLo)))
+ if ((regLo != REG_STK) && (regSet.rsMaskUsed & genRegMask(regLo)))
regSet.rsSpillReg(regLo);
}
@@ -1353,12 +1292,12 @@ void CodeGen::genMakeRegPairAvailable(regPairNo regPair)
*
* Return true if the given tree 'addr' can be computed via an addressing mode,
* such as "[ebx+esi*4+20]". If the expression isn't an address mode already
- * try to make it so (but we don't try 'too hard' to accomplish this).
+ * try to make it so (but we don't try 'too hard' to accomplish this).
*
* If we end up needing a register (or two registers) to hold some part(s) of the
* address, we return the use register mask via '*useMaskPtr'.
*
- * If keepReg==RegSet::KEEP_REG, the registers (viz. *useMaskPtr) will be marked as
+ * If keepReg==RegSet::KEEP_REG, the registers (viz. *useMaskPtr) will be marked as
* in use. The caller would then be responsible for calling
* regSet.rsMarkRegFree(*useMaskPtr).
*
@@ -1366,66 +1305,60 @@ void CodeGen::genMakeRegPairAvailable(regPairNo regPair)
* calling genDoneAddressable(addr, *useMaskPtr, RegSet::FREE_REG);
*/
-bool CodeGen::genMakeIndAddrMode(GenTreePtr addr,
- GenTreePtr oper,
- bool forLea,
- regMaskTP regMask,
- RegSet::KeepReg keepReg,
- regMaskTP * useMaskPtr,
- bool deferOK)
+bool CodeGen::genMakeIndAddrMode(GenTreePtr addr,
+ GenTreePtr oper,
+ bool forLea,
+ regMaskTP regMask,
+ RegSet::KeepReg keepReg,
+ regMaskTP* useMaskPtr,
+ bool deferOK)
{
if (addr->gtOper == GT_ARR_ELEM)
{
- regMaskTP regs = genMakeAddrArrElem(addr, oper, RBM_ALLINT, keepReg);
- *useMaskPtr = regs;
+ regMaskTP regs = genMakeAddrArrElem(addr, oper, RBM_ALLINT, keepReg);
+ *useMaskPtr = regs;
return true;
}
- bool rev;
- GenTreePtr rv1;
- GenTreePtr rv2;
- bool operIsArrIndex; // is oper an array index
- GenTreePtr scaledIndex; // If scaled addressing mode can't be used
+ bool rev;
+ GenTreePtr rv1;
+ GenTreePtr rv2;
+ bool operIsArrIndex; // is oper an array index
+ GenTreePtr scaledIndex; // If scaled addressing mode can't be used
+
+ regMaskTP anyMask = RBM_ALLINT;
- regMaskTP anyMask = RBM_ALLINT;
+ unsigned cns;
+ unsigned mul;
- unsigned cns;
- unsigned mul;
+ GenTreePtr tmp;
+ int ixv = INT_MAX; // unset value
- GenTreePtr tmp;
- int ixv = INT_MAX; // unset value
-
- GenTreePtr scaledIndexVal;
+ GenTreePtr scaledIndexVal;
- regMaskTP newLiveMask;
- regMaskTP rv1Mask;
- regMaskTP rv2Mask;
+ regMaskTP newLiveMask;
+ regMaskTP rv1Mask;
+ regMaskTP rv2Mask;
/* Deferred address mode forming NYI for x86 */
-
noway_assert(deferOK == false);
- noway_assert(oper == NULL
- || ((oper->OperIsIndir() || oper->OperIsAtomicOp())
- &&
- ((oper->gtOper == GT_CMPXCHG && oper->gtCmpXchg.gtOpLocation == addr)
- || oper->gtOp.gtOp1 == addr)));
+ noway_assert(oper == NULL ||
+ ((oper->OperIsIndir() || oper->OperIsAtomicOp()) &&
+ ((oper->gtOper == GT_CMPXCHG && oper->gtCmpXchg.gtOpLocation == addr) || oper->gtOp.gtOp1 == addr)));
operIsArrIndex = (oper != nullptr && oper->OperGet() == GT_IND && (oper->gtFlags & GTF_IND_ARR_INDEX) != 0);
if (addr->gtOper == GT_LEA)
{
- rev = (addr->gtFlags & GTF_REVERSE_OPS) != 0;
- GenTreeAddrMode * lea = addr->AsAddrMode();
- rv1 = lea->Base();
- rv2 = lea->Index();
- mul = lea->gtScale;
- cns = lea->gtOffset;
+ rev = (addr->gtFlags & GTF_REVERSE_OPS) != 0;
+ GenTreeAddrMode* lea = addr->AsAddrMode();
+ rv1 = lea->Base();
+ rv2 = lea->Index();
+ mul = lea->gtScale;
+ cns = lea->gtOffset;
- if (rv1 != NULL &&
- rv2 == NULL &&
- cns == 0 &&
- (rv1->gtFlags & GTF_REG_VAL) != 0)
+ if (rv1 != NULL && rv2 == NULL && cns == 0 && (rv1->gtFlags & GTF_REG_VAL) != 0)
{
scaledIndex = NULL;
goto YES;
@@ -1433,58 +1366,56 @@ bool CodeGen::genMakeIndAddrMode(GenTreePtr addr,
}
else
{
- // NOTE: FOR NOW THIS ISN'T APPROPRIATELY INDENTED - THIS IS TO MAKE IT
- // EASIER TO MERGE
+ // NOTE: FOR NOW THIS ISN'T APPROPRIATELY INDENTED - THIS IS TO MAKE IT
+ // EASIER TO MERGE
- /* Is the complete address already sitting in a register? */
+ /* Is the complete address already sitting in a register? */
- if ((addr->gtFlags & GTF_REG_VAL) ||
- (addr->gtOper == GT_LCL_VAR && genMarkLclVar(addr)))
- {
- genUpdateLife(addr);
+ if ((addr->gtFlags & GTF_REG_VAL) || (addr->gtOper == GT_LCL_VAR && genMarkLclVar(addr)))
+ {
+ genUpdateLife(addr);
- rv1 = addr;
- rv2 = scaledIndex = 0;
- cns = 0;
+ rv1 = addr;
+ rv2 = scaledIndex = 0;
+ cns = 0;
- goto YES;
- }
+ goto YES;
+ }
- /* Is it an absolute address */
+ /* Is it an absolute address */
- if (addr->IsCnsIntOrI())
- {
- rv1 = rv2 = scaledIndex = 0;
- // along this code path cns is never used, so place a BOGUS value in it as proof
- // cns = addr->gtIntCon.gtIconVal;
- cns = UINT_MAX;
+ if (addr->IsCnsIntOrI())
+ {
+ rv1 = rv2 = scaledIndex = 0;
+ // along this code path cns is never used, so place a BOGUS value in it as proof
+ // cns = addr->gtIntCon.gtIconVal;
+ cns = UINT_MAX;
- goto YES;
- }
+ goto YES;
+ }
- /* Is there a chance of forming an address mode? */
+ /* Is there a chance of forming an address mode? */
- if (!genCreateAddrMode(addr, forLea ? 1 : 0, false, regMask, &rev, &rv1, &rv2, &mul, &cns))
- {
- /* This better not be an array index */
- noway_assert(!operIsArrIndex);
+ if (!genCreateAddrMode(addr, forLea ? 1 : 0, false, regMask, &rev, &rv1, &rv2, &mul, &cns))
+ {
+ /* This better not be an array index */
+ noway_assert(!operIsArrIndex);
- return false;
- }
- // THIS IS THE END OF THE INAPPROPRIATELY INDENTED SECTION
+ return false;
+ }
+ // THIS IS THE END OF THE INAPPROPRIATELY INDENTED SECTION
}
- /* For scaled array access, RV2 may not be pointing to the index of the
- array if the CPU does not support the needed scaling factor. We will
- make it point to the actual index, and scaledIndex will point to
- the scaled value */
+ /* For scaled array access, RV2 may not be pointing to the index of the
+ array if the CPU does not support the needed scaling factor. We will
+ make it point to the actual index, and scaledIndex will point to
+ the scaled value */
- scaledIndex = NULL;
+ scaledIndex = NULL;
scaledIndexVal = NULL;
- if (operIsArrIndex && rv2 != NULL
- && (rv2->gtOper == GT_MUL || rv2->gtOper == GT_LSH)
- && rv2->gtOp.gtOp2->IsIntCnsFitsInI32())
+ if (operIsArrIndex && rv2 != NULL && (rv2->gtOper == GT_MUL || rv2->gtOper == GT_LSH) &&
+ rv2->gtOp.gtOp2->IsIntCnsFitsInI32())
{
scaledIndex = rv2;
compiler->optGetArrayRefScaleAndIndex(scaledIndex, &scaledIndexVal DEBUGARG(true));
@@ -1494,10 +1425,10 @@ bool CodeGen::genMakeIndAddrMode(GenTreePtr addr,
/* Has the address already been computed? */
- if (addr->gtFlags & GTF_REG_VAL)
+ if (addr->gtFlags & GTF_REG_VAL)
{
- if (forLea)
- return true;
+ if (forLea)
+ return true;
rv1 = addr;
rv2 = NULL;
@@ -1529,7 +1460,7 @@ bool CodeGen::genMakeIndAddrMode(GenTreePtr addr,
// Trivial case : Is either rv1 or rv2 a NULL ?
- if (!rv2)
+ if (!rv2)
{
/* A single operand, make sure it's in a register */
@@ -1559,13 +1490,12 @@ bool CodeGen::genMakeIndAddrMode(GenTreePtr addr,
noway_assert(rv1 && rv2);
-
/* If we have to check a constant array index, compare it against
the array dimension (see below) but then fold the index with a
scaling factor (if any) and additional offset (if any).
*/
- if (rv2->gtOper == GT_CNS_INT || (scaledIndex != NULL && scaledIndexVal->gtOper == GT_CNS_INT))
+ if (rv2->gtOper == GT_CNS_INT || (scaledIndex != NULL && scaledIndexVal->gtOper == GT_CNS_INT))
{
if (scaledIndex != NULL)
{
@@ -1578,7 +1508,7 @@ bool CodeGen::genMakeIndAddrMode(GenTreePtr addr,
/* Get hold of the index value and see if it's a constant */
- if (rv2->IsIntCnsFitsInI32())
+ if (rv2->IsIntCnsFitsInI32())
{
ixv = (int)rv2->gtIntCon.gtIconVal;
// Maybe I should just set "fold" true in the call to genMakeAddressable above.
@@ -1599,7 +1529,7 @@ bool CodeGen::genMakeIndAddrMode(GenTreePtr addr,
/* Add the scaled index into the added value */
- if (mul)
+ if (mul)
cns += ixv * mul;
else
cns += ixv;
@@ -1612,11 +1542,11 @@ bool CodeGen::genMakeIndAddrMode(GenTreePtr addr,
}
}
- if (rv1->gtFlags & GTF_REG_VAL)
+ if (rv1->gtFlags & GTF_REG_VAL)
{
/* op1 already in register - how about op2? */
- if (rv2->gtFlags & GTF_REG_VAL)
+ if (rv2->gtFlags & GTF_REG_VAL)
{
/* Great - both operands are in registers already. Just update
the liveness and we are done. */
@@ -1671,7 +1601,7 @@ bool CodeGen::genMakeIndAddrMode(GenTreePtr addr,
{
// Free up rv2 in the right fashion (it might be re-marked if keepReg)
regSet.rsMarkRegUsed(rv1, oper);
- regSet.rsLockUsedReg (genRegMask(rv1->gtRegNum));
+ regSet.rsLockUsedReg(genRegMask(rv1->gtRegNum));
genReleaseReg(rv2);
regSet.rsUnlockUsedReg(genRegMask(rv1->gtRegNum));
genReleaseReg(rv1);
@@ -1687,19 +1617,19 @@ bool CodeGen::genMakeIndAddrMode(GenTreePtr addr,
goto DONE_REGS;
}
- if (forLea && !cns)
- return false;
+ if (forLea && !cns)
+ return false;
/* Make sure we preserve the correct operand order */
- if (rev)
+ if (rev)
{
/* Generate the second operand first */
// Determine what registers go live between rv2 and rv1
newLiveMask = genNewLiveRegMask(rv2, rv1);
- rv2Mask = regMask & ~newLiveMask;
+ rv2Mask = regMask & ~newLiveMask;
rv2Mask &= ~rv1->gtRsvdRegs;
if (rv2Mask == RBM_NONE)
@@ -1709,7 +1639,7 @@ bool CodeGen::genMakeIndAddrMode(GenTreePtr addr,
// so ignore the regMask hint, but try to avoid using
// the registers in newLiveMask and the rv1->gtRsvdRegs
//
- rv2Mask = RBM_ALLINT & ~newLiveMask;
+ rv2Mask = RBM_ALLINT & ~newLiveMask;
rv2Mask = regSet.rsMustExclude(rv2Mask, rv1->gtRsvdRegs);
}
@@ -1726,7 +1656,7 @@ bool CodeGen::genMakeIndAddrMode(GenTreePtr addr,
/* Free up both operands in the right order (they might be
re-marked as used below)
*/
- regSet.rsLockUsedReg (genRegMask(rv1->gtRegNum));
+ regSet.rsLockUsedReg(genRegMask(rv1->gtRegNum));
genReleaseReg(rv2);
regSet.rsUnlockUsedReg(genRegMask(rv1->gtRegNum));
genReleaseReg(rv1);
@@ -1738,9 +1668,9 @@ bool CodeGen::genMakeIndAddrMode(GenTreePtr addr,
// Determine what registers go live between rv1 and rv2
newLiveMask = genNewLiveRegMask(rv1, rv2);
- rv1Mask = regMask & ~newLiveMask;
+ rv1Mask = regMask & ~newLiveMask;
rv1Mask &= ~rv2->gtRsvdRegs;
-
+
if (rv1Mask == RBM_NONE)
{
// The regMask hint cannot be honored
@@ -1784,35 +1714,37 @@ bool CodeGen::genMakeIndAddrMode(GenTreePtr addr,
/* Even though we have not explicitly marked rv2 as used,
rv2->gtRegNum may be used if rv2 is a multi-use or
an enregistered variable. */
- regMaskTP rv2Used;
- regSet.rsLockReg (genRegMask(rv2->gtRegNum), &rv2Used);
+ regMaskTP rv2Used;
+ regSet.rsLockReg(genRegMask(rv2->gtRegNum), &rv2Used);
/* Check for special case both rv1 and rv2 are the same register */
if (rv2Used != genRegMask(rv1->gtRegNum))
{
genReleaseReg(rv1);
- regSet.rsUnlockReg(genRegMask(rv2->gtRegNum), rv2Used);
+ regSet.rsUnlockReg(genRegMask(rv2->gtRegNum), rv2Used);
}
else
{
- regSet.rsUnlockReg(genRegMask(rv2->gtRegNum), rv2Used);
+ regSet.rsUnlockReg(genRegMask(rv2->gtRegNum), rv2Used);
genReleaseReg(rv1);
}
}
}
- /*-------------------------------------------------------------------------
- *
- * At this point, both rv1 and rv2 (if present) are in registers
- *
- */
+/*-------------------------------------------------------------------------
+ *
+ * At this point, both rv1 and rv2 (if present) are in registers
+ *
+ */
DONE_REGS:
/* We must verify that 'rv1' and 'rv2' are both sitting in registers */
- if (rv1 && !(rv1->gtFlags & GTF_REG_VAL)) return false;
- if (rv2 && !(rv2->gtFlags & GTF_REG_VAL)) return false;
+ if (rv1 && !(rv1->gtFlags & GTF_REG_VAL))
+ return false;
+ if (rv2 && !(rv2->gtFlags & GTF_REG_VAL))
+ return false;
YES:
@@ -1821,8 +1753,7 @@ YES:
// needs to know that it has to call rsFreeReg(reg1) twice. We can't do
// that currently as we return a single mask in useMaskPtr.
- if ((keepReg == RegSet::KEEP_REG) && oper && rv1 && rv2 &&
- (rv1->gtFlags & rv2->gtFlags & GTF_REG_VAL))
+ if ((keepReg == RegSet::KEEP_REG) && oper && rv1 && rv2 && (rv1->gtFlags & rv2->gtFlags & GTF_REG_VAL))
{
if (rv1->gtRegNum == rv2->gtRegNum)
{
@@ -1833,7 +1764,7 @@ YES:
/* Check either register operand to see if it needs to be saved */
- if (rv1)
+ if (rv1)
{
noway_assert(rv1->gtFlags & GTF_REG_VAL);
@@ -1849,7 +1780,7 @@ YES:
}
}
- if (rv2)
+ if (rv2)
{
noway_assert(rv2->gtFlags & GTF_REG_VAL);
@@ -1857,19 +1788,19 @@ YES:
regSet.rsMarkRegUsed(rv2, oper);
}
- if (deferOK)
+ if (deferOK)
{
noway_assert(!scaledIndex);
- return true;
+ return true;
}
/* Compute the set of registers the address depends on */
- regMaskTP useMask = RBM_NONE;
+ regMaskTP useMask = RBM_NONE;
if (rv1)
{
- if (rv1->gtFlags & GTF_SPILLED)
+ if (rv1->gtFlags & GTF_SPILLED)
regSet.rsUnspillReg(rv1, 0, RegSet::KEEP_REG);
noway_assert(rv1->gtFlags & GTF_REG_VAL);
@@ -1878,13 +1809,13 @@ YES:
if (rv2)
{
- if (rv2->gtFlags & GTF_SPILLED)
+ if (rv2->gtFlags & GTF_SPILLED)
{
if (rv1)
{
- regMaskTP lregMask = genRegMask(rv1->gtRegNum);
- regMaskTP used;
-
+ regMaskTP lregMask = genRegMask(rv1->gtRegNum);
+ regMaskTP used;
+
regSet.rsLockReg(lregMask, &used);
regSet.rsUnspillReg(rv2, 0, RegSet::KEEP_REG);
regSet.rsUnlockReg(lregMask, used);
@@ -1908,14 +1839,14 @@ YES:
* 'oper' is an array bounds check (a GT_ARR_BOUNDS_CHECK node).
*/
-void CodeGen::genRangeCheck(GenTreePtr oper)
+void CodeGen::genRangeCheck(GenTreePtr oper)
{
noway_assert(oper->OperGet() == GT_ARR_BOUNDS_CHECK);
GenTreeBoundsChk* bndsChk = oper->AsBoundsChk();
- GenTreePtr arrLen = bndsChk->gtArrLen;
- GenTreePtr arrRef = NULL;
- int lenOffset = 0;
+ GenTreePtr arrLen = bndsChk->gtArrLen;
+ GenTreePtr arrRef = NULL;
+ int lenOffset = 0;
// If "arrLen" is a ARR_LENGTH operation, get the array whose length that takes in a register.
// Otherwise, if the length is not a constant, get it (the length, not the arr reference) in
@@ -1924,7 +1855,7 @@ void CodeGen::genRangeCheck(GenTreePtr oper)
if (arrLen->OperGet() == GT_ARR_LENGTH)
{
GenTreeArrLen* arrLenExact = arrLen->AsArrLen();
- lenOffset = arrLenExact->ArrLenOffset();
+ lenOffset = arrLenExact->ArrLenOffset();
#if !CPU_LOAD_STORE_ARCH && !defined(_TARGET_64BIT_)
// We always load the length into a register on ARM and x64.
@@ -1950,7 +1881,7 @@ void CodeGen::genRangeCheck(GenTreePtr oper)
}
#endif
- // If we didn't find one of the special forms above, generate code to evaluate the array length to a register.
+ // If we didn't find one of the special forms above, generate code to evaluate the array length to a register.
if (arrRef == NULL)
{
// (Unless it's a constant.)
@@ -1966,7 +1897,7 @@ void CodeGen::genRangeCheck(GenTreePtr oper)
/* Is the array index a constant value? */
GenTreePtr index = bndsChk->gtIndex;
- if (!index->IsCnsIntOrI())
+ if (!index->IsCnsIntOrI())
{
// No, it's not a constant.
genCodeForTree(index, RBM_ALLINT);
@@ -1983,12 +1914,14 @@ void CodeGen::genRangeCheck(GenTreePtr oper)
noway_assert(index->gtFlags & GTF_REG_VAL);
noway_assert(regSet.rsMaskUsed & genRegMask(index->gtRegNum));
- noway_assert(index->TypeGet() == TYP_I_IMPL || (varTypeIsIntegral(index->TypeGet()) && !varTypeIsLong(index->TypeGet())));
+ noway_assert(index->TypeGet() == TYP_I_IMPL ||
+ (varTypeIsIntegral(index->TypeGet()) && !varTypeIsLong(index->TypeGet())));
var_types indxType = index->TypeGet();
- if (indxType != TYP_I_IMPL) indxType = TYP_INT;
+ if (indxType != TYP_I_IMPL)
+ indxType = TYP_INT;
if (arrRef != NULL)
- { // _TARGET_X86_ or X64 when we have a TYP_INT (32-bit) index expression in the index register
+ { // _TARGET_X86_ or X64 when we have a TYP_INT (32-bit) index expression in the index register
/* Generate "cmp index, [arrRef+LenOffs]" */
inst_RV_AT(INS_cmp, emitTypeSize(indxType), indxType, index->gtRegNum, arrRef, lenOffset);
@@ -2015,7 +1948,7 @@ void CodeGen::genRangeCheck(GenTreePtr oper)
bool indIsInt = true;
#ifdef _TARGET_64BIT_
- int ixv = 0;
+ int ixv = 0;
ssize_t ixvFull = index->AsIntConCommon()->IconValue();
if (ixvFull > INT32_MAX)
{
@@ -2027,10 +1960,10 @@ void CodeGen::genRangeCheck(GenTreePtr oper)
}
#else
ssize_t ixvFull = index->AsIntConCommon()->IconValue();
- int ixv = (int)ixvFull;
+ int ixv = (int)ixvFull;
#endif
if (arrRef != NULL && indIsInt)
- { // _TARGET_X86_ or X64 when we have a TYP_INT (32-bit) index expression in the index register
+ { // _TARGET_X86_ or X64 when we have a TYP_INT (32-bit) index expression in the index register
/* Generate "cmp [arrRef+LenOffs], ixv" */
inst_AT_IV(INS_cmp, EA_4BYTE, arrRef, ixv, lenOffset);
// Generate "jbe <fail_label>"
@@ -2052,7 +1985,7 @@ void CodeGen::genRangeCheck(GenTreePtr oper)
}
else
{
- /* Generate "cmp arrLen, ixv" */
+ /* Generate "cmp arrLen, ixv" */
inst_RV_IV(INS_cmp, arrLen->gtRegNum, ixv, EA_4BYTE);
// Generate "jbe <fail_label>"
emitJumpKind jmpLEU = genJumpKindForOper(GT_LE, CK_UNSIGNED);
@@ -2070,7 +2003,7 @@ void CodeGen::genRangeCheck(GenTreePtr oper)
regSet.rsMarkRegFree(arrLen->gtRegNum, arrLen);
}
- if (!index->IsCnsIntOrI())
+ if (!index->IsCnsIntOrI())
{
regSet.rsMarkRegFree(index->gtRegNum, index);
}
@@ -2085,11 +2018,8 @@ void CodeGen::genRangeCheck(GenTreePtr oper)
*/
// inline
-regMaskTP CodeGen::genMakeRvalueAddressable(GenTreePtr tree,
- regMaskTP needReg,
- RegSet::KeepReg keepReg,
- bool forLoadStore,
- bool smallOK)
+regMaskTP CodeGen::genMakeRvalueAddressable(
+ GenTreePtr tree, regMaskTP needReg, RegSet::KeepReg keepReg, bool forLoadStore, bool smallOK)
{
regNumber reg;
@@ -2114,10 +2044,9 @@ regMaskTP CodeGen::genMakeRvalueAddressable(GenTreePtr tree,
/*****************************************************************************/
-
-bool CodeGen::genIsLocalLastUse (GenTreePtr tree)
+bool CodeGen::genIsLocalLastUse(GenTreePtr tree)
{
- const LclVarDsc * varDsc = &compiler->lvaTable[tree->gtLclVarCommon.gtLclNum];
+ const LclVarDsc* varDsc = &compiler->lvaTable[tree->gtLclVarCommon.gtLclNum];
noway_assert(tree->OperGet() == GT_LCL_VAR);
noway_assert(varDsc->lvTracked);
@@ -2125,7 +2054,6 @@ bool CodeGen::genIsLocalLastUse (GenTreePtr tree)
return ((tree->gtFlags & GTF_VAR_DEATH) != 0);
}
-
/*****************************************************************************
*
* This is genMakeAddressable(GT_ARR_ELEM).
@@ -2139,10 +2067,7 @@ bool CodeGen::genIsLocalLastUse (GenTreePtr tree)
* where to look for the offset to use.
*/
-regMaskTP CodeGen::genMakeAddrArrElem(GenTreePtr arrElem,
- GenTreePtr tree,
- regMaskTP needReg,
- RegSet::KeepReg keepReg)
+regMaskTP CodeGen::genMakeAddrArrElem(GenTreePtr arrElem, GenTreePtr tree, regMaskTP needReg, RegSet::KeepReg keepReg)
{
noway_assert(arrElem->gtOper == GT_ARR_ELEM);
noway_assert(!tree || tree->gtOper == GT_IND || tree == arrElem);
@@ -2160,15 +2085,15 @@ regMaskTP CodeGen::genMakeAddrArrElem(GenTreePtr arrElem,
applies to all type of tree nodes except for GT_ARR_ELEM.
*/
- GenTreePtr arrObj = arrElem->gtArrElem.gtArrObj;
- unsigned rank = arrElem->gtArrElem.gtArrRank;
- var_types elemType = arrElem->gtArrElem.gtArrElemType;
- regMaskTP addrReg = RBM_NONE;
- regMaskTP regNeed = RBM_ALLINT;
+ GenTreePtr arrObj = arrElem->gtArrElem.gtArrObj;
+ unsigned rank = arrElem->gtArrElem.gtArrRank;
+ var_types elemType = arrElem->gtArrElem.gtArrElemType;
+ regMaskTP addrReg = RBM_NONE;
+ regMaskTP regNeed = RBM_ALLINT;
#if FEATURE_WRITE_BARRIER && !NOGC_WRITE_BARRIERS
// In CodeGen::WriteBarrier we set up ARG_1 followed by ARG_0
- // since the arrObj participates in the lea/add instruction
+ // since the arrObj participates in the lea/add instruction
// that computes ARG_0 we should avoid putting it in ARG_1
//
if (varTypeIsGC(elemType))
@@ -2188,9 +2113,7 @@ regMaskTP CodeGen::genMakeAddrArrElem(GenTreePtr arrElem,
// it can be collected from here on. This is not an issue for locals that are
// in a register, as they get marked as used an will be tracked.
// The bug that caused this is #100776. (untracked vars?)
- if (arrObj->OperGet() == GT_LCL_VAR &&
- compiler->optIsTrackedLocal(arrObj) &&
- genIsLocalLastUse(arrObj) &&
+ if (arrObj->OperGet() == GT_LCL_VAR && compiler->optIsTrackedLocal(arrObj) && genIsLocalLastUse(arrObj) &&
!genMarkLclVar(arrObj))
{
genCodeForTree(arrObj, regNeed);
@@ -2199,13 +2122,11 @@ regMaskTP CodeGen::genMakeAddrArrElem(GenTreePtr arrElem,
}
else
{
- addrReg = genMakeAddressable2(arrObj,
- regNeed,
- RegSet::KEEP_REG,
- true, // forLoadStore
- false, // smallOK
- false, // deferOK
- true); // evalSideEffs
+ addrReg = genMakeAddressable2(arrObj, regNeed, RegSet::KEEP_REG,
+ true, // forLoadStore
+ false, // smallOK
+ false, // deferOK
+ true); // evalSideEffs
}
unsigned dim;
@@ -2217,19 +2138,19 @@ regMaskTP CodeGen::genMakeAddrArrElem(GenTreePtr arrElem,
addrReg = genKeepAddressable(arrObj, addrReg);
genComputeAddressable(arrObj, addrReg, RegSet::KEEP_REG, regNeed, RegSet::KEEP_REG);
- regNumber arrReg = arrObj->gtRegNum;
- regMaskTP arrRegMask = genRegMask(arrReg);
- regMaskTP indRegMask = RBM_ALLINT & ~arrRegMask;
+ regNumber arrReg = arrObj->gtRegNum;
+ regMaskTP arrRegMask = genRegMask(arrReg);
+ regMaskTP indRegMask = RBM_ALLINT & ~arrRegMask;
regSet.rsLockUsedReg(arrRegMask);
/* Now process all the indices, do the range check, and compute
the offset of the element */
- regNumber accReg = DUMMY_INIT(REG_CORRUPT); // accumulates the offset calculation
+ regNumber accReg = DUMMY_INIT(REG_CORRUPT); // accumulates the offset calculation
for (dim = 0; dim < rank; dim++)
{
- GenTreePtr index = arrElem->gtArrElem.gtArrInds[dim];
+ GenTreePtr index = arrElem->gtArrElem.gtArrInds[dim];
/* Get the index into a free register (other than the register holding the array) */
@@ -2238,42 +2159,24 @@ regMaskTP CodeGen::genMakeAddrArrElem(GenTreePtr arrElem,
#if CPU_LOAD_STORE_ARCH
/* Subtract the lower bound, and do the range check */
- regNumber valueReg = regSet.rsGrabReg(RBM_ALLINT & ~genRegMask(arrReg) & ~genRegMask(index->gtRegNum));
- getEmitter()->emitIns_R_AR(
- INS_ldr, EA_4BYTE,
- valueReg,
- arrReg,
- compiler->eeGetArrayDataOffset(elemType) + sizeof(int) * (dim + rank));
+ regNumber valueReg = regSet.rsGrabReg(RBM_ALLINT & ~genRegMask(arrReg) & ~genRegMask(index->gtRegNum));
+ getEmitter()->emitIns_R_AR(INS_ldr, EA_4BYTE, valueReg, arrReg,
+ compiler->eeGetArrayDataOffset(elemType) + sizeof(int) * (dim + rank));
regTracker.rsTrackRegTrash(valueReg);
- getEmitter()->emitIns_R_R(
- INS_sub, EA_4BYTE,
- index->gtRegNum,
- valueReg);
+ getEmitter()->emitIns_R_R(INS_sub, EA_4BYTE, index->gtRegNum, valueReg);
regTracker.rsTrackRegTrash(index->gtRegNum);
- getEmitter()->emitIns_R_AR(
- INS_ldr, EA_4BYTE,
- valueReg,
- arrReg,
- compiler->eeGetArrayDataOffset(elemType) + sizeof(int) * dim);
- getEmitter()->emitIns_R_R(
- INS_cmp, EA_4BYTE,
- index->gtRegNum,
- valueReg);
+ getEmitter()->emitIns_R_AR(INS_ldr, EA_4BYTE, valueReg, arrReg,
+ compiler->eeGetArrayDataOffset(elemType) + sizeof(int) * dim);
+ getEmitter()->emitIns_R_R(INS_cmp, EA_4BYTE, index->gtRegNum, valueReg);
#else
/* Subtract the lower bound, and do the range check */
- getEmitter()->emitIns_R_AR(
- INS_sub, EA_4BYTE,
- index->gtRegNum,
- arrReg,
- compiler->eeGetArrayDataOffset(elemType) + sizeof(int) * (dim + rank));
+ getEmitter()->emitIns_R_AR(INS_sub, EA_4BYTE, index->gtRegNum, arrReg,
+ compiler->eeGetArrayDataOffset(elemType) + sizeof(int) * (dim + rank));
regTracker.rsTrackRegTrash(index->gtRegNum);
- getEmitter()->emitIns_R_AR(
- INS_cmp, EA_4BYTE,
- index->gtRegNum,
- arrReg,
- compiler->eeGetArrayDataOffset(elemType) + sizeof(int) * dim);
+ getEmitter()->emitIns_R_AR(INS_cmp, EA_4BYTE, index->gtRegNum, arrReg,
+ compiler->eeGetArrayDataOffset(elemType) + sizeof(int) * dim);
#endif
emitJumpKind jmpGEU = genJumpKindForOper(GT_GE, CK_UNSIGNED);
genJumpToThrowHlpBlk(jmpGEU, SCK_RNGCHK_FAIL);
@@ -2293,22 +2196,13 @@ regMaskTP CodeGen::genMakeAddrArrElem(GenTreePtr arrElem,
noway_assert(accReg != DUMMY_INIT(REG_CORRUPT));
#if CPU_LOAD_STORE_ARCH
- getEmitter()->emitIns_R_AR(
- INS_ldr, EA_4BYTE,
- valueReg,
- arrReg,
- compiler->eeGetArrayDataOffset(elemType) + sizeof(int) * dim);
+ getEmitter()->emitIns_R_AR(INS_ldr, EA_4BYTE, valueReg, arrReg,
+ compiler->eeGetArrayDataOffset(elemType) + sizeof(int) * dim);
regTracker.rsTrackRegTrash(valueReg);
- getEmitter()->emitIns_R_R(
- INS_MUL, EA_4BYTE,
- accReg,
- valueReg);
+ getEmitter()->emitIns_R_R(INS_MUL, EA_4BYTE, accReg, valueReg);
#else
- getEmitter()->emitIns_R_AR(
- INS_MUL, EA_4BYTE,
- accReg,
- arrReg,
- compiler->eeGetArrayDataOffset(elemType) + sizeof(int) * dim);
+ getEmitter()->emitIns_R_AR(INS_MUL, EA_4BYTE, accReg, arrReg,
+ compiler->eeGetArrayDataOffset(elemType) + sizeof(int) * dim);
#endif
inst_RV_RV(INS_add, accReg, index->gtRegNum);
@@ -2336,7 +2230,7 @@ regMaskTP CodeGen::genMakeAddrArrElem(GenTreePtr arrElem,
/* We mark the addressability registers on arrObj and gtArrInds[0].
instGetAddrMode() knows to work with this. */
- regSet.rsMarkRegUsed(arrObj, tree);
+ regSet.rsMarkRegUsed(arrObj, tree);
regSet.rsMarkRegUsed(arrElem->gtArrElem.gtArrInds[0], tree);
}
@@ -2379,18 +2273,15 @@ regMaskTP CodeGen::genMakeAddrArrElem(GenTreePtr arrElem,
* to free the addressability registers.
*/
-regMaskTP CodeGen::genMakeAddressable(GenTreePtr tree,
- regMaskTP needReg,
- RegSet::KeepReg keepReg,
- bool smallOK,
- bool deferOK)
+regMaskTP CodeGen::genMakeAddressable(
+ GenTreePtr tree, regMaskTP needReg, RegSet::KeepReg keepReg, bool smallOK, bool deferOK)
{
- GenTreePtr addr = NULL;
- regMaskTP regMask;
+ GenTreePtr addr = NULL;
+ regMaskTP regMask;
/* Is the value simply sitting in a register? */
- if (tree->gtFlags & GTF_REG_VAL)
+ if (tree->gtFlags & GTF_REG_VAL)
{
genUpdateLife(tree);
@@ -2402,7 +2293,6 @@ regMaskTP CodeGen::genMakeAddressable(GenTreePtr tree,
// TODO: since stack temps are always addressable. This would require
// TODO: recording the fact that a particular tree is in a stack temp.
-
/* byte/char/short operand -- is this acceptable to the caller? */
if (varTypeIsSmall(tree->TypeGet()) && !smallOK)
@@ -2413,85 +2303,79 @@ regMaskTP CodeGen::genMakeAddressable(GenTreePtr tree,
switch (tree->gtOper)
{
- case GT_LCL_FLD:
-
- // We only use GT_LCL_FLD for lvDoNotEnregister vars, so we don't have
- // to worry about it being enregistered.
- noway_assert(compiler->lvaTable[tree->gtLclFld.gtLclNum].lvRegister == 0);
-
- genUpdateLife(tree);
- return 0;
-
+ case GT_LCL_FLD:
- case GT_LCL_VAR:
+ // We only use GT_LCL_FLD for lvDoNotEnregister vars, so we don't have
+ // to worry about it being enregistered.
+ noway_assert(compiler->lvaTable[tree->gtLclFld.gtLclNum].lvRegister == 0);
- if (!genMarkLclVar(tree))
- {
genUpdateLife(tree);
return 0;
- }
- __fallthrough; // it turns out the variable lives in a register
+ case GT_LCL_VAR:
- case GT_REG_VAR:
+ if (!genMarkLclVar(tree))
+ {
+ genUpdateLife(tree);
+ return 0;
+ }
- genUpdateLife(tree);
+ __fallthrough; // it turns out the variable lives in a register
- goto GOT_VAL;
+ case GT_REG_VAR:
+
+ genUpdateLife(tree);
- case GT_CLS_VAR:
+ goto GOT_VAL;
- return 0;
+ case GT_CLS_VAR:
- case GT_CNS_INT:
+ return 0;
+
+ case GT_CNS_INT:
#ifdef _TARGET_64BIT_
- // Non-relocs will be sign extended, so we don't have to enregister
- // constants that are equivalent to a sign-extended int.
- // Relocs can be left alone if they are RIP-relative.
- if ((genTypeSize(tree->TypeGet()) > 4) && (!tree->IsIntCnsFitsInI32() ||
- (tree->IsIconHandle() &&
- (IMAGE_REL_BASED_REL32 != compiler->eeGetRelocTypeHint((void*)tree->gtIntCon.gtIconVal)))))
- {
- break;
- }
+ // Non-relocs will be sign extended, so we don't have to enregister
+ // constants that are equivalent to a sign-extended int.
+ // Relocs can be left alone if they are RIP-relative.
+ if ((genTypeSize(tree->TypeGet()) > 4) &&
+ (!tree->IsIntCnsFitsInI32() ||
+ (tree->IsIconHandle() &&
+ (IMAGE_REL_BASED_REL32 != compiler->eeGetRelocTypeHint((void*)tree->gtIntCon.gtIconVal)))))
+ {
+ break;
+ }
#endif // _TARGET_64BIT_
- __fallthrough;
-
- case GT_CNS_LNG:
- case GT_CNS_DBL:
- // For MinOpts, we don't do constant folding, so we have
- // constants showing up in places we don't like.
- // force them into a register now to prevent that.
- if (compiler->opts.OptEnabled(CLFLG_CONSTANTFOLD))
- return 0;
- break;
+ __fallthrough;
+ case GT_CNS_LNG:
+ case GT_CNS_DBL:
+ // For MinOpts, we don't do constant folding, so we have
+ // constants showing up in places we don't like.
+ // force them into a register now to prevent that.
+ if (compiler->opts.OptEnabled(CLFLG_CONSTANTFOLD))
+ return 0;
+ break;
- case GT_IND:
- case GT_NULLCHECK:
+ case GT_IND:
+ case GT_NULLCHECK:
- /* Try to make the address directly addressable */
+ /* Try to make the address directly addressable */
- if (genMakeIndAddrMode(tree->gtOp.gtOp1,
- tree,
- false, /* not for LEA */
- needReg,
- keepReg,
- &regMask,
- deferOK))
- {
- genUpdateLife(tree);
- return regMask;
- }
+ if (genMakeIndAddrMode(tree->gtOp.gtOp1, tree, false, /* not for LEA */
+ needReg, keepReg, &regMask, deferOK))
+ {
+ genUpdateLife(tree);
+ return regMask;
+ }
- /* No good, we'll have to load the address into a register */
+ /* No good, we'll have to load the address into a register */
- addr = tree;
- tree = tree->gtOp.gtOp1;
- break;
+ addr = tree;
+ tree = tree->gtOp.gtOp1;
+ break;
- default:
- break;
+ default:
+ break;
}
EVAL_TREE:
@@ -2504,7 +2388,7 @@ GOT_VAL:
noway_assert(tree->gtFlags & GTF_REG_VAL);
- if (isRegPairType(tree->gtType))
+ if (isRegPairType(tree->gtType))
{
/* Are we supposed to hang on to the register? */
@@ -2523,7 +2407,7 @@ GOT_VAL:
regMask = genRegMask(tree->gtRegNum);
}
- return regMask;
+ return regMask;
}
/*****************************************************************************
@@ -2534,19 +2418,19 @@ GOT_VAL:
* freeOnly - target register needs to be a scratch register
*/
-void CodeGen::genComputeAddressable(GenTreePtr tree,
- regMaskTP addrReg,
- RegSet::KeepReg keptReg,
- regMaskTP needReg,
- RegSet::KeepReg keepReg,
- bool freeOnly)
+void CodeGen::genComputeAddressable(GenTreePtr tree,
+ regMaskTP addrReg,
+ RegSet::KeepReg keptReg,
+ regMaskTP needReg,
+ RegSet::KeepReg keepReg,
+ bool freeOnly)
{
noway_assert(genStillAddressable(tree));
noway_assert(varTypeIsIntegralOrI(tree->TypeGet()));
genDoneAddressable(tree, addrReg, keptReg);
- regNumber reg;
+ regNumber reg;
if (tree->gtFlags & GTF_REG_VAL)
{
@@ -2588,13 +2472,13 @@ void CodeGen::genComputeAddressable(GenTreePtr tree,
* Should be similar to genMakeAddressable() but gives more control.
*/
-regMaskTP CodeGen::genMakeAddressable2(GenTreePtr tree,
- regMaskTP needReg,
- RegSet::KeepReg keepReg,
- bool forLoadStore,
- bool smallOK,
- bool deferOK,
- bool evalSideEffs)
+regMaskTP CodeGen::genMakeAddressable2(GenTreePtr tree,
+ regMaskTP needReg,
+ RegSet::KeepReg keepReg,
+ bool forLoadStore,
+ bool smallOK,
+ bool deferOK,
+ bool evalSideEffs)
{
bool evalToReg = false;
@@ -2613,7 +2497,7 @@ regMaskTP CodeGen::genMakeAddressable2(GenTreePtr tree,
noway_assert(tree->gtFlags & GTF_REG_VAL);
- if (isRegPairType(tree->gtType))
+ if (isRegPairType(tree->gtType))
{
/* Are we supposed to hang on to the register? */
@@ -2645,14 +2529,14 @@ regMaskTP CodeGen::genMakeAddressable2(GenTreePtr tree,
*/
// inline
-bool CodeGen::genStillAddressable(GenTreePtr tree)
+bool CodeGen::genStillAddressable(GenTreePtr tree)
{
/* Has the value (or one or more of its sub-operands) been spilled? */
- if (tree->gtFlags & (GTF_SPILLED|GTF_SPILLED_OPER))
- return false;
+ if (tree->gtFlags & (GTF_SPILLED | GTF_SPILLED_OPER))
+ return false;
- return true;
+ return true;
}
/*****************************************************************************
@@ -2661,19 +2545,17 @@ bool CodeGen::genStillAddressable(GenTreePtr tree)
* argument indicates whether we're in the 'lock' or 'reload' phase.
*/
-regMaskTP CodeGen::genRestoreAddrMode(GenTreePtr addr,
- GenTreePtr tree,
- bool lockPhase)
+regMaskTP CodeGen::genRestoreAddrMode(GenTreePtr addr, GenTreePtr tree, bool lockPhase)
{
- regMaskTP regMask = RBM_NONE;
+ regMaskTP regMask = RBM_NONE;
/* Have we found a spilled value? */
- if (tree->gtFlags & GTF_SPILLED)
+ if (tree->gtFlags & GTF_SPILLED)
{
/* Do nothing if we're locking, otherwise reload and lock */
- if (!lockPhase)
+ if (!lockPhase)
{
/* Unspill the register */
@@ -2693,33 +2575,33 @@ regMaskTP CodeGen::genRestoreAddrMode(GenTreePtr addr,
regSet.rsMaskLock |= regMask;
}
- return regMask;
+ return regMask;
}
/* Is this sub-tree sitting in a register? */
- if (tree->gtFlags & GTF_REG_VAL)
+ if (tree->gtFlags & GTF_REG_VAL)
{
regMask = genRegMask(tree->gtRegNum);
/* Lock the register if we're in the locking phase */
- if (lockPhase)
+ if (lockPhase)
regSet.rsMaskLock |= regMask;
}
else
{
/* Process any sub-operands of this node */
- unsigned kind = tree->OperKind();
+ unsigned kind = tree->OperKind();
- if (kind & GTK_SMPOP)
+ if (kind & GTK_SMPOP)
{
/* Unary/binary operator */
- if (tree->gtOp.gtOp1)
+ if (tree->gtOp.gtOp1)
regMask |= genRestoreAddrMode(addr, tree->gtOp.gtOp1, lockPhase);
- if (tree->gtGetOp2())
+ if (tree->gtGetOp2())
regMask |= genRestoreAddrMode(addr, tree->gtOp.gtOp2, lockPhase);
}
else if (tree->gtOper == GT_ARR_ELEM)
@@ -2727,7 +2609,7 @@ regMaskTP CodeGen::genRestoreAddrMode(GenTreePtr addr,
/* gtArrObj is the array-object and gtArrInds[0] is marked with the register
which holds the offset-calculation */
- regMask |= genRestoreAddrMode(addr, tree->gtArrElem.gtArrObj, lockPhase);
+ regMask |= genRestoreAddrMode(addr, tree->gtArrElem.gtArrObj, lockPhase);
regMask |= genRestoreAddrMode(addr, tree->gtArrElem.gtArrInds[0], lockPhase);
}
else if (tree->gtOper == GT_CMPXCHG)
@@ -2738,11 +2620,11 @@ regMaskTP CodeGen::genRestoreAddrMode(GenTreePtr addr,
{
/* Must be a leaf/constant node */
- noway_assert(kind & (GTK_LEAF|GTK_CONST));
+ noway_assert(kind & (GTK_LEAF | GTK_CONST));
}
}
- return regMask;
+ return regMask;
}
/*****************************************************************************
@@ -2753,19 +2635,17 @@ regMaskTP CodeGen::genRestoreAddrMode(GenTreePtr addr,
* registers).
*/
-regMaskTP CodeGen::genRestAddressable(GenTreePtr tree,
- regMaskTP addrReg,
- regMaskTP lockMask)
+regMaskTP CodeGen::genRestAddressable(GenTreePtr tree, regMaskTP addrReg, regMaskTP lockMask)
{
noway_assert((regSet.rsMaskLock & lockMask) == lockMask);
/* Is this a 'simple' register spill? */
- if (tree->gtFlags & GTF_SPILLED)
+ if (tree->gtFlags & GTF_SPILLED)
{
/* The mask must match the original register/regpair */
- if (isRegPairType(tree->gtType))
+ if (isRegPairType(tree->gtType))
{
noway_assert(addrReg == genRegPairMask(tree->gtRegPair));
@@ -2782,15 +2662,15 @@ regMaskTP CodeGen::genRestAddressable(GenTreePtr tree,
addrReg = genRegMask(tree->gtRegNum);
}
- noway_assert((regSet.rsMaskLock & lockMask) == lockMask);
- regSet.rsMaskLock -= lockMask;
+ noway_assert((regSet.rsMaskLock & lockMask) == lockMask);
+ regSet.rsMaskLock -= lockMask;
- return addrReg;
+ return addrReg;
}
/* We have a complex address mode with some of its sub-operands spilled */
- noway_assert((tree->gtFlags & GTF_REG_VAL ) == 0);
+ noway_assert((tree->gtFlags & GTF_REG_VAL) == 0);
noway_assert((tree->gtFlags & GTF_SPILLED_OPER) != 0);
/*
@@ -2806,17 +2686,17 @@ regMaskTP CodeGen::genRestAddressable(GenTreePtr tree,
3. Unlock all the registers.
*/
- addrReg = genRestoreAddrMode(tree, tree, true);
- addrReg |= genRestoreAddrMode(tree, tree, false);
+ addrReg = genRestoreAddrMode(tree, tree, true);
+ addrReg |= genRestoreAddrMode(tree, tree, false);
/* Unlock all registers that the address mode uses */
lockMask |= addrReg;
- noway_assert((regSet.rsMaskLock & lockMask) == lockMask);
- regSet.rsMaskLock -= lockMask;
+ noway_assert((regSet.rsMaskLock & lockMask) == lockMask);
+ regSet.rsMaskLock -= lockMask;
- return addrReg;
+ return addrReg;
}
/*****************************************************************************
@@ -2829,15 +2709,13 @@ regMaskTP CodeGen::genRestAddressable(GenTreePtr tree,
* the address (these will be marked as used on exit).
*/
-regMaskTP CodeGen::genKeepAddressable(GenTreePtr tree,
- regMaskTP addrReg,
- regMaskTP avoidMask)
+regMaskTP CodeGen::genKeepAddressable(GenTreePtr tree, regMaskTP addrReg, regMaskTP avoidMask)
{
/* Is the operand still addressable? */
- tree = tree->gtEffectiveVal(/*commaOnly*/true); // Strip off commas for this purpose.
+ tree = tree->gtEffectiveVal(/*commaOnly*/ true); // Strip off commas for this purpose.
- if (!genStillAddressable(tree))
+ if (!genStillAddressable(tree))
{
if (avoidMask)
{
@@ -2851,10 +2729,10 @@ regMaskTP CodeGen::genKeepAddressable(GenTreePtr tree,
addrReg = genRestAddressable(tree, addrReg, avoidMask);
- noway_assert((regSet.rsMaskLock & avoidMask) == 0);
+ noway_assert((regSet.rsMaskLock & avoidMask) == 0);
}
- return addrReg;
+ return addrReg;
}
/*****************************************************************************
@@ -2866,9 +2744,7 @@ regMaskTP CodeGen::genKeepAddressable(GenTreePtr tree,
* by genMakeAddressable().
*/
-void CodeGen::genDoneAddressable(GenTreePtr tree,
- regMaskTP addrReg,
- RegSet::KeepReg keptReg)
+void CodeGen::genDoneAddressable(GenTreePtr tree, regMaskTP addrReg, RegSet::KeepReg keptReg)
{
if (keptReg == RegSet::FREE_REG)
{
@@ -2876,7 +2752,7 @@ void CodeGen::genDoneAddressable(GenTreePtr tree,
// ie. There may be a pending use in a higher-up tree.
addrReg &= ~regSet.rsMaskUsed;
-
+
/* addrReg was not marked as used. So just reset its GC info */
if (addrReg)
{
@@ -2901,48 +2777,41 @@ void CodeGen::genDoneAddressable(GenTreePtr tree,
* to evaluate into the FP stack, we do this and return zero.
*/
-GenTreePtr CodeGen::genMakeAddrOrFPstk(GenTreePtr tree,
- regMaskTP * regMaskPtr,
- bool roundResult)
+GenTreePtr CodeGen::genMakeAddrOrFPstk(GenTreePtr tree, regMaskTP* regMaskPtr, bool roundResult)
{
*regMaskPtr = 0;
switch (tree->gtOper)
{
- case GT_LCL_VAR:
- case GT_LCL_FLD:
- case GT_CLS_VAR:
- return tree;
+ case GT_LCL_VAR:
+ case GT_LCL_FLD:
+ case GT_CLS_VAR:
+ return tree;
- case GT_CNS_DBL:
- if (tree->gtType == TYP_FLOAT)
- {
- float f = forceCastToFloat(tree->gtDblCon.gtDconVal);
- return genMakeConst(&f, TYP_FLOAT, tree, false);
- }
- return genMakeConst(&tree->gtDblCon.gtDconVal, tree->gtType, tree, true);
+ case GT_CNS_DBL:
+ if (tree->gtType == TYP_FLOAT)
+ {
+ float f = forceCastToFloat(tree->gtDblCon.gtDconVal);
+ return genMakeConst(&f, TYP_FLOAT, tree, false);
+ }
+ return genMakeConst(&tree->gtDblCon.gtDconVal, tree->gtType, tree, true);
- case GT_IND:
- case GT_NULLCHECK:
+ case GT_IND:
+ case GT_NULLCHECK:
- /* Try to make the address directly addressable */
+ /* Try to make the address directly addressable */
- if (genMakeIndAddrMode(tree->gtOp.gtOp1,
- tree,
- false, /* not for LEA */
- 0,
- RegSet::FREE_REG,
- regMaskPtr,
- false))
- {
- genUpdateLife(tree);
- return tree;
- }
+ if (genMakeIndAddrMode(tree->gtOp.gtOp1, tree, false, /* not for LEA */
+ 0, RegSet::FREE_REG, regMaskPtr, false))
+ {
+ genUpdateLife(tree);
+ return tree;
+ }
- break;
+ break;
- default:
- break;
+ default:
+ break;
}
#if FEATURE_STACK_FP_X87
/* We have no choice but to compute the value 'tree' onto the FP stack */
@@ -2952,14 +2821,13 @@ GenTreePtr CodeGen::genMakeAddrOrFPstk(GenTreePtr tree,
return 0;
}
-
/*****************************************************************************/
/*****************************************************************************
*
* Display a string literal value (debug only).
*/
-#ifdef DEBUG
+#ifdef DEBUG
#endif
/*****************************************************************************
@@ -2970,17 +2838,17 @@ GenTreePtr CodeGen::genMakeAddrOrFPstk(GenTreePtr tree,
*
* TODO-ARM-Bug?: pushReg is not implemented (is it needed for ARM?)
*/
-void CodeGen::genEmitGSCookieCheck(bool pushReg)
+void CodeGen::genEmitGSCookieCheck(bool pushReg)
{
// Make sure that EAX didn't die in the return expression
if (!pushReg && (compiler->info.compRetType == TYP_REF))
gcInfo.gcRegGCrefSetCur |= RBM_INTRET;
// Add cookie check code for unsafe buffers
- BasicBlock *gsCheckBlk;
- regMaskTP byrefPushedRegs = RBM_NONE;
- regMaskTP norefPushedRegs = RBM_NONE;
- regMaskTP pushedRegs = RBM_NONE;
+ BasicBlock* gsCheckBlk;
+ regMaskTP byrefPushedRegs = RBM_NONE;
+ regMaskTP norefPushedRegs = RBM_NONE;
+ regMaskTP pushedRegs = RBM_NONE;
noway_assert(compiler->gsGlobalSecurityCookieAddr || compiler->gsGlobalSecurityCookieVal);
@@ -2992,30 +2860,24 @@ void CodeGen::genEmitGSCookieCheck(bool pushReg)
#if CPU_LOAD_STORE_ARCH
regNumber reg = regSet.rsGrabReg(RBM_ALLINT);
- getEmitter()->emitIns_R_S(ins_Load(TYP_INT), EA_4BYTE,
- reg,
- compiler->lvaGSSecurityCookie, 0);
+ getEmitter()->emitIns_R_S(ins_Load(TYP_INT), EA_4BYTE, reg, compiler->lvaGSSecurityCookie, 0);
regTracker.rsTrackRegTrash(reg);
- if (arm_Valid_Imm_For_Alu(compiler->gsGlobalSecurityCookieVal) ||
+ if (arm_Valid_Imm_For_Alu(compiler->gsGlobalSecurityCookieVal) ||
arm_Valid_Imm_For_Alu(~compiler->gsGlobalSecurityCookieVal))
{
- getEmitter()->emitIns_R_I(INS_cmp, EA_4BYTE,
- reg,
- compiler->gsGlobalSecurityCookieVal);
+ getEmitter()->emitIns_R_I(INS_cmp, EA_4BYTE, reg, compiler->gsGlobalSecurityCookieVal);
}
else
{
// Load CookieVal into a register
regNumber immReg = regSet.rsGrabReg(RBM_ALLINT & ~genRegMask(reg));
instGen_Set_Reg_To_Imm(EA_4BYTE, immReg, compiler->gsGlobalSecurityCookieVal);
- getEmitter()->emitIns_R_R(INS_cmp, EA_4BYTE,
- reg, immReg);
+ getEmitter()->emitIns_R_R(INS_cmp, EA_4BYTE, reg, immReg);
}
#else
- getEmitter()->emitIns_S_I(INS_cmp, EA_PTRSIZE,
- compiler->lvaGSSecurityCookie, 0,
- (int)compiler->gsGlobalSecurityCookieVal);
+ getEmitter()->emitIns_S_I(INS_cmp, EA_PTRSIZE, compiler->lvaGSSecurityCookie, 0,
+ (int)compiler->gsGlobalSecurityCookieVal);
#endif
}
else
@@ -3023,37 +2885,38 @@ void CodeGen::genEmitGSCookieCheck(bool pushReg)
regNumber regGSCheck;
regMaskTP regMaskGSCheck;
#if CPU_LOAD_STORE_ARCH
- regGSCheck = regSet.rsGrabReg(RBM_ALLINT);
+ regGSCheck = regSet.rsGrabReg(RBM_ALLINT);
regMaskGSCheck = genRegMask(regGSCheck);
#else
// Don't pick the 'this' register
if (compiler->lvaKeepAliveAndReportThis() && compiler->lvaTable[compiler->info.compThisArg].lvRegister &&
(compiler->lvaTable[compiler->info.compThisArg].lvRegNum == REG_ECX))
{
- regGSCheck = REG_EDX;
+ regGSCheck = REG_EDX;
regMaskGSCheck = RBM_EDX;
}
else
{
- regGSCheck = REG_ECX;
+ regGSCheck = REG_ECX;
regMaskGSCheck = RBM_ECX;
}
// NGen case
- if (pushReg && (regMaskGSCheck & (regSet.rsMaskUsed|regSet.rsMaskVars|regSet.rsMaskLock)))
+ if (pushReg && (regMaskGSCheck & (regSet.rsMaskUsed | regSet.rsMaskVars | regSet.rsMaskLock)))
{
pushedRegs = genPushRegs(regMaskGSCheck, &byrefPushedRegs, &norefPushedRegs);
}
else
{
- noway_assert((regMaskGSCheck & (regSet.rsMaskUsed|regSet.rsMaskVars|regSet.rsMaskLock)) == 0);
+ noway_assert((regMaskGSCheck & (regSet.rsMaskUsed | regSet.rsMaskVars | regSet.rsMaskLock)) == 0);
}
#endif
#if defined(_TARGET_ARM_)
instGen_Set_Reg_To_Imm(EA_HANDLE_CNS_RELOC, regGSCheck, (ssize_t)compiler->gsGlobalSecurityCookieAddr);
- getEmitter()->emitIns_R_R_I(INS_ldr, EA_PTRSIZE, regGSCheck, regGSCheck,0);
+ getEmitter()->emitIns_R_R_I(INS_ldr, EA_PTRSIZE, regGSCheck, regGSCheck, 0);
#else
- getEmitter()->emitIns_R_C(ins_Load(TYP_I_IMPL), EA_PTR_DSP_RELOC, regGSCheck, FLD_GLOBAL_DS, (ssize_t)compiler->gsGlobalSecurityCookieAddr);
+ getEmitter()->emitIns_R_C(ins_Load(TYP_I_IMPL), EA_PTR_DSP_RELOC, regGSCheck, FLD_GLOBAL_DS,
+ (ssize_t)compiler->gsGlobalSecurityCookieAddr);
#endif // !_TARGET_ARM_
regTracker.rsTrashRegSet(regMaskGSCheck);
#ifdef _TARGET_ARM_
@@ -3066,7 +2929,7 @@ void CodeGen::genEmitGSCookieCheck(bool pushReg)
#endif
}
- gsCheckBlk = genCreateTempLabel();
+ gsCheckBlk = genCreateTempLabel();
emitJumpKind jmpEqual = genJumpKindForOper(GT_EQ, CK_SIGNED);
inst_JMP(jmpEqual, gsCheckBlk);
genEmitHelperCall(CORINFO_HELP_FAIL_FAST, 0, EA_UNKNOWN);
@@ -3075,21 +2938,20 @@ void CodeGen::genEmitGSCookieCheck(bool pushReg)
genPopRegs(pushedRegs, byrefPushedRegs, norefPushedRegs);
}
-
/*****************************************************************************
*
* Generate any side effects within the given expression tree.
*/
-void CodeGen::genEvalSideEffects(GenTreePtr tree)
+void CodeGen::genEvalSideEffects(GenTreePtr tree)
{
- genTreeOps oper;
- unsigned kind;
+ genTreeOps oper;
+ unsigned kind;
AGAIN:
/* Does this sub-tree contain any side-effects? */
- if (tree->gtFlags & GTF_SIDE_EFFECT)
+ if (tree->gtFlags & GTF_SIDE_EFFECT)
{
#if FEATURE_STACK_FP_X87
/* Remember the current FP stack level */
@@ -3099,7 +2961,7 @@ AGAIN:
{
regMaskTP addrReg = genMakeAddressable(tree, RBM_ALLINT, RegSet::KEEP_REG, true, false);
- if (tree->gtFlags & GTF_REG_VAL)
+ if (tree->gtFlags & GTF_REG_VAL)
{
gcInfo.gcMarkRegPtrVal(tree);
genDoneAddressable(tree, addrReg, RegSet::KEEP_REG);
@@ -3107,8 +2969,7 @@ AGAIN:
// GTF_IND_RNGCHK trees have already de-referenced the pointer, and so
// do not need an additional null-check
/* Do this only if the GTF_EXCEPT or GTF_IND_VOLATILE flag is set on the indir */
- else if ((tree->gtFlags & GTF_IND_ARR_INDEX) == 0 &&
- ((tree->gtFlags & GTF_EXCEPT) | GTF_IND_VOLATILE))
+ else if ((tree->gtFlags & GTF_IND_ARR_INDEX) == 0 && ((tree->gtFlags & GTF_EXCEPT) | GTF_IND_VOLATILE))
{
/* Compare against any register to do null-check */
CLANG_FORMAT_COMMENT_ANCHOR;
@@ -3119,7 +2980,8 @@ AGAIN:
#elif CPU_LOAD_STORE_ARCH
if (varTypeIsFloating(tree->TypeGet()))
{
- genComputeAddressableFloat(tree, addrReg, RBM_NONE, RegSet::KEEP_REG, RBM_ALLFLOAT, RegSet::FREE_REG);
+ genComputeAddressableFloat(tree, addrReg, RBM_NONE, RegSet::KEEP_REG, RBM_ALLFLOAT,
+ RegSet::FREE_REG);
}
else
{
@@ -3128,7 +2990,7 @@ AGAIN:
#ifdef _TARGET_ARM_
if (tree->gtFlags & GTF_IND_VOLATILE)
{
- // Emit a memory barrier instruction after the load
+ // Emit a memory barrier instruction after the load
instGen_MemoryBarrier();
}
#endif
@@ -3145,7 +3007,7 @@ AGAIN:
{
/* Generate the expression and throw it away */
genCodeForTree(tree, RBM_ALL(tree->TypeGet()));
- if (tree->gtFlags & GTF_REG_VAL)
+ if (tree->gtFlags & GTF_REG_VAL)
{
gcInfo.gcMarkRegPtrVal(tree);
}
@@ -3154,7 +3016,7 @@ AGAIN:
/* If the tree computed a value on the FP stack, pop the stack */
if (genNumberTemps() > iTemps)
{
- noway_assert(genNumberTemps() == iTemps+1);
+ noway_assert(genNumberTemps() == iTemps + 1);
genDiscardStackFP(tree);
}
#endif
@@ -3170,18 +3032,17 @@ AGAIN:
/* Is this a constant or leaf node? */
- if (kind & (GTK_CONST|GTK_LEAF))
+ if (kind & (GTK_CONST | GTK_LEAF))
{
#if FEATURE_STACK_FP_X87
- if (tree->IsRegVar() && isFloatRegType(tree->gtType) &&
- tree->IsRegVarDeath())
+ if (tree->IsRegVar() && isFloatRegType(tree->gtType) && tree->IsRegVarDeath())
{
genRegVarDeathStackFP(tree);
FlatFPX87_Unload(&compCurFPState, tree->gtRegNum);
}
#endif
genUpdateLife(tree);
- gcInfo.gcMarkRegPtrVal (tree);
+ gcInfo.gcMarkRegPtrVal(tree);
return;
}
@@ -3189,7 +3050,7 @@ AGAIN:
noway_assert(kind & GTK_SMPOP);
- if (tree->gtGetOp2())
+ if (tree->gtGetOp2())
{
genEvalSideEffects(tree->gtOp.gtOp1);
@@ -3199,7 +3060,7 @@ AGAIN:
else
{
tree = tree->gtOp.gtOp1;
- if (tree)
+ if (tree)
goto AGAIN;
}
}
@@ -3216,148 +3077,132 @@ AGAIN:
* RBM_NONE if a write-barrier is not needed.
*/
-regMaskTP CodeGen::WriteBarrier(GenTreePtr tgt,
- GenTreePtr assignVal,
- regMaskTP tgtAddrReg)
+regMaskTP CodeGen::WriteBarrier(GenTreePtr tgt, GenTreePtr assignVal, regMaskTP tgtAddrReg)
{
noway_assert(assignVal->gtFlags & GTF_REG_VAL);
GCInfo::WriteBarrierForm wbf = gcInfo.gcIsWriteBarrierCandidate(tgt, assignVal);
- if (wbf == GCInfo::WBF_NoBarrier)
+ if (wbf == GCInfo::WBF_NoBarrier)
return RBM_NONE;
- regMaskTP resultRegMask = RBM_NONE;
+ regMaskTP resultRegMask = RBM_NONE;
#if FEATURE_WRITE_BARRIER
- regNumber reg = assignVal->gtRegNum;
+ regNumber reg = assignVal->gtRegNum;
#if defined(_TARGET_X86_) && NOGC_WRITE_BARRIERS
#ifdef DEBUG
if (wbf != GCInfo::WBF_NoBarrier_CheckNotHeapInDebug) // This one is always a call to a C++ method.
{
#endif
- const static int regToHelper[2][8] =
- {
- // If the target is known to be in managed memory
- {
- CORINFO_HELP_ASSIGN_REF_EAX,
- CORINFO_HELP_ASSIGN_REF_ECX,
- -1,
- CORINFO_HELP_ASSIGN_REF_EBX,
- -1,
- CORINFO_HELP_ASSIGN_REF_EBP,
- CORINFO_HELP_ASSIGN_REF_ESI,
- CORINFO_HELP_ASSIGN_REF_EDI,
- },
-
- // Don't know if the target is in managed memory
- {
- CORINFO_HELP_CHECKED_ASSIGN_REF_EAX,
- CORINFO_HELP_CHECKED_ASSIGN_REF_ECX,
- -1,
- CORINFO_HELP_CHECKED_ASSIGN_REF_EBX,
- -1,
- CORINFO_HELP_CHECKED_ASSIGN_REF_EBP,
- CORINFO_HELP_CHECKED_ASSIGN_REF_ESI,
- CORINFO_HELP_CHECKED_ASSIGN_REF_EDI,
- },
- };
-
- noway_assert(regToHelper[0][REG_EAX] == CORINFO_HELP_ASSIGN_REF_EAX);
- noway_assert(regToHelper[0][REG_ECX] == CORINFO_HELP_ASSIGN_REF_ECX);
- noway_assert(regToHelper[0][REG_EBX] == CORINFO_HELP_ASSIGN_REF_EBX);
- noway_assert(regToHelper[0][REG_ESP] == -1 );
- noway_assert(regToHelper[0][REG_EBP] == CORINFO_HELP_ASSIGN_REF_EBP);
- noway_assert(regToHelper[0][REG_ESI] == CORINFO_HELP_ASSIGN_REF_ESI);
- noway_assert(regToHelper[0][REG_EDI] == CORINFO_HELP_ASSIGN_REF_EDI);
-
- noway_assert(regToHelper[1][REG_EAX] == CORINFO_HELP_CHECKED_ASSIGN_REF_EAX);
- noway_assert(regToHelper[1][REG_ECX] == CORINFO_HELP_CHECKED_ASSIGN_REF_ECX);
- noway_assert(regToHelper[1][REG_EBX] == CORINFO_HELP_CHECKED_ASSIGN_REF_EBX);
- noway_assert(regToHelper[1][REG_ESP] == -1 );
- noway_assert(regToHelper[1][REG_EBP] == CORINFO_HELP_CHECKED_ASSIGN_REF_EBP);
- noway_assert(regToHelper[1][REG_ESI] == CORINFO_HELP_CHECKED_ASSIGN_REF_ESI);
- noway_assert(regToHelper[1][REG_EDI] == CORINFO_HELP_CHECKED_ASSIGN_REF_EDI);
-
- noway_assert((reg != REG_ESP) && (reg != REG_WRITE_BARRIER));
+ const static int regToHelper[2][8] = {
+ // If the target is known to be in managed memory
+ {
+ CORINFO_HELP_ASSIGN_REF_EAX, CORINFO_HELP_ASSIGN_REF_ECX, -1, CORINFO_HELP_ASSIGN_REF_EBX, -1,
+ CORINFO_HELP_ASSIGN_REF_EBP, CORINFO_HELP_ASSIGN_REF_ESI, CORINFO_HELP_ASSIGN_REF_EDI,
+ },
- /*
- Generate the following code:
+ // Don't know if the target is in managed memory
+ {
+ CORINFO_HELP_CHECKED_ASSIGN_REF_EAX, CORINFO_HELP_CHECKED_ASSIGN_REF_ECX, -1,
+ CORINFO_HELP_CHECKED_ASSIGN_REF_EBX, -1, CORINFO_HELP_CHECKED_ASSIGN_REF_EBP,
+ CORINFO_HELP_CHECKED_ASSIGN_REF_ESI, CORINFO_HELP_CHECKED_ASSIGN_REF_EDI,
+ },
+ };
- lea edx, tgt
- call write_barrier_helper_reg
+ noway_assert(regToHelper[0][REG_EAX] == CORINFO_HELP_ASSIGN_REF_EAX);
+ noway_assert(regToHelper[0][REG_ECX] == CORINFO_HELP_ASSIGN_REF_ECX);
+ noway_assert(regToHelper[0][REG_EBX] == CORINFO_HELP_ASSIGN_REF_EBX);
+ noway_assert(regToHelper[0][REG_ESP] == -1);
+ noway_assert(regToHelper[0][REG_EBP] == CORINFO_HELP_ASSIGN_REF_EBP);
+ noway_assert(regToHelper[0][REG_ESI] == CORINFO_HELP_ASSIGN_REF_ESI);
+ noway_assert(regToHelper[0][REG_EDI] == CORINFO_HELP_ASSIGN_REF_EDI);
- First grab the RBM_WRITE_BARRIER register for the target address.
- */
+ noway_assert(regToHelper[1][REG_EAX] == CORINFO_HELP_CHECKED_ASSIGN_REF_EAX);
+ noway_assert(regToHelper[1][REG_ECX] == CORINFO_HELP_CHECKED_ASSIGN_REF_ECX);
+ noway_assert(regToHelper[1][REG_EBX] == CORINFO_HELP_CHECKED_ASSIGN_REF_EBX);
+ noway_assert(regToHelper[1][REG_ESP] == -1);
+ noway_assert(regToHelper[1][REG_EBP] == CORINFO_HELP_CHECKED_ASSIGN_REF_EBP);
+ noway_assert(regToHelper[1][REG_ESI] == CORINFO_HELP_CHECKED_ASSIGN_REF_ESI);
+ noway_assert(regToHelper[1][REG_EDI] == CORINFO_HELP_CHECKED_ASSIGN_REF_EDI);
- regNumber rg1;
- bool trashOp1;
+ noway_assert((reg != REG_ESP) && (reg != REG_WRITE_BARRIER));
- if ((tgtAddrReg & RBM_WRITE_BARRIER) == 0)
- {
- rg1 = regSet.rsGrabReg(RBM_WRITE_BARRIER);
+ /*
+ Generate the following code:
- regSet.rsMaskUsed |= RBM_WRITE_BARRIER;
- regSet.rsMaskLock |= RBM_WRITE_BARRIER;
+ lea edx, tgt
+ call write_barrier_helper_reg
- trashOp1 = false;
- }
- else
- {
- rg1 = REG_WRITE_BARRIER;
+ First grab the RBM_WRITE_BARRIER register for the target address.
+ */
- trashOp1 = true;
- }
+ regNumber rg1;
+ bool trashOp1;
- noway_assert(rg1 == REG_WRITE_BARRIER);
+ if ((tgtAddrReg & RBM_WRITE_BARRIER) == 0)
+ {
+ rg1 = regSet.rsGrabReg(RBM_WRITE_BARRIER);
- /* Generate "lea EDX, [addr-mode]" */
+ regSet.rsMaskUsed |= RBM_WRITE_BARRIER;
+ regSet.rsMaskLock |= RBM_WRITE_BARRIER;
- noway_assert(tgt->gtType == TYP_REF);
- tgt->gtType = TYP_BYREF;
- inst_RV_TT(INS_lea, rg1, tgt, 0, EA_BYREF);
+ trashOp1 = false;
+ }
+ else
+ {
+ rg1 = REG_WRITE_BARRIER;
- /* Free up anything that was tied up by the LHS */
- genDoneAddressable(tgt, tgtAddrReg, RegSet::KEEP_REG);
+ trashOp1 = true;
+ }
- // In case "tgt" was a comma:
- tgt = tgt->gtEffectiveVal();
+ noway_assert(rg1 == REG_WRITE_BARRIER);
- regTracker.rsTrackRegTrash(rg1);
- gcInfo.gcMarkRegSetNpt(genRegMask(rg1));
- gcInfo.gcMarkRegPtrVal(rg1, TYP_BYREF);
+ /* Generate "lea EDX, [addr-mode]" */
+ noway_assert(tgt->gtType == TYP_REF);
+ tgt->gtType = TYP_BYREF;
+ inst_RV_TT(INS_lea, rg1, tgt, 0, EA_BYREF);
- /* Call the proper vm helper */
+ /* Free up anything that was tied up by the LHS */
+ genDoneAddressable(tgt, tgtAddrReg, RegSet::KEEP_REG);
- // enforced by gcIsWriteBarrierCandidate
- noway_assert(tgt->gtOper == GT_IND ||
- tgt->gtOper == GT_CLS_VAR);
+ // In case "tgt" was a comma:
+ tgt = tgt->gtEffectiveVal();
- unsigned tgtAnywhere = 0;
- if ((tgt->gtOper == GT_IND) &&
- ((tgt->gtFlags & GTF_IND_TGTANYWHERE) || (tgt->gtOp.gtOp1->TypeGet() == TYP_I_IMPL)))
- {
- tgtAnywhere = 1;
- }
+ regTracker.rsTrackRegTrash(rg1);
+ gcInfo.gcMarkRegSetNpt(genRegMask(rg1));
+ gcInfo.gcMarkRegPtrVal(rg1, TYP_BYREF);
- int helper = regToHelper[tgtAnywhere][reg];
- resultRegMask = genRegMask(reg);
+ /* Call the proper vm helper */
- gcInfo.gcMarkRegSetNpt(RBM_WRITE_BARRIER); // byref EDX is killed in the call
+ // enforced by gcIsWriteBarrierCandidate
+ noway_assert(tgt->gtOper == GT_IND || tgt->gtOper == GT_CLS_VAR);
- genEmitHelperCall(helper,
- 0, // argSize
- EA_PTRSIZE); // retSize
+ unsigned tgtAnywhere = 0;
+ if ((tgt->gtOper == GT_IND) &&
+ ((tgt->gtFlags & GTF_IND_TGTANYWHERE) || (tgt->gtOp.gtOp1->TypeGet() == TYP_I_IMPL)))
+ {
+ tgtAnywhere = 1;
+ }
- if (!trashOp1)
- {
- regSet.rsMaskUsed &= ~RBM_WRITE_BARRIER;
- regSet.rsMaskLock &= ~RBM_WRITE_BARRIER;
- }
+ int helper = regToHelper[tgtAnywhere][reg];
+ resultRegMask = genRegMask(reg);
- return resultRegMask;
+ gcInfo.gcMarkRegSetNpt(RBM_WRITE_BARRIER); // byref EDX is killed in the call
+
+ genEmitHelperCall(helper,
+ 0, // argSize
+ EA_PTRSIZE); // retSize
+
+ if (!trashOp1)
+ {
+ regSet.rsMaskUsed &= ~RBM_WRITE_BARRIER;
+ regSet.rsMaskLock &= ~RBM_WRITE_BARRIER;
+ }
+
+ return resultRegMask;
#ifdef DEBUG
}
@@ -3367,120 +3212,120 @@ regMaskTP CodeGen::WriteBarrier(GenTreePtr tgt,
#if defined(DEBUG) || !(defined(_TARGET_X86_) && NOGC_WRITE_BARRIERS)
{
- /*
- Generate the following code (or its equivalent on the given target):
+ /*
+ Generate the following code (or its equivalent on the given target):
- mov arg1, srcReg
- lea arg0, tgt
- call write_barrier_helper
+ mov arg1, srcReg
+ lea arg0, tgt
+ call write_barrier_helper
- First, setup REG_ARG_1 with the GC ref that we are storing via the Write Barrier
- */
+ First, setup REG_ARG_1 with the GC ref that we are storing via the Write Barrier
+ */
- if (reg != REG_ARG_1)
- {
- // We may need to spill whatever is in the ARG_1 register
- //
- if ((regSet.rsMaskUsed & RBM_ARG_1) != 0)
+ if (reg != REG_ARG_1)
{
- regSet.rsSpillReg(REG_ARG_1);
- }
+ // We may need to spill whatever is in the ARG_1 register
+ //
+ if ((regSet.rsMaskUsed & RBM_ARG_1) != 0)
+ {
+ regSet.rsSpillReg(REG_ARG_1);
+ }
- inst_RV_RV(INS_mov, REG_ARG_1, reg, TYP_REF);
- }
- resultRegMask = RBM_ARG_1;
+ inst_RV_RV(INS_mov, REG_ARG_1, reg, TYP_REF);
+ }
+ resultRegMask = RBM_ARG_1;
- regTracker.rsTrackRegTrash(REG_ARG_1);
- gcInfo.gcMarkRegSetNpt(REG_ARG_1);
- gcInfo.gcMarkRegSetGCref(RBM_ARG_1); // gcref in ARG_1
+ regTracker.rsTrackRegTrash(REG_ARG_1);
+ gcInfo.gcMarkRegSetNpt(REG_ARG_1);
+ gcInfo.gcMarkRegSetGCref(RBM_ARG_1); // gcref in ARG_1
- bool free_arg1 = false;
- if ((regSet.rsMaskUsed & RBM_ARG_1) == 0)
- {
- regSet.rsMaskUsed |= RBM_ARG_1;
- free_arg1 = true;
- }
+ bool free_arg1 = false;
+ if ((regSet.rsMaskUsed & RBM_ARG_1) == 0)
+ {
+ regSet.rsMaskUsed |= RBM_ARG_1;
+ free_arg1 = true;
+ }
- // Then we setup REG_ARG_0 with the target address to store into via the Write Barrier
+ // Then we setup REG_ARG_0 with the target address to store into via the Write Barrier
- /* Generate "lea R0, [addr-mode]" */
+ /* Generate "lea R0, [addr-mode]" */
- noway_assert(tgt->gtType == TYP_REF);
- tgt->gtType = TYP_BYREF;
+ noway_assert(tgt->gtType == TYP_REF);
+ tgt->gtType = TYP_BYREF;
- tgtAddrReg = genKeepAddressable(tgt, tgtAddrReg);
+ tgtAddrReg = genKeepAddressable(tgt, tgtAddrReg);
- // We may need to spill whatever is in the ARG_0 register
- //
- if (((tgtAddrReg & RBM_ARG_0) == 0) && // tgtAddrReg does not contain REG_ARG_0
- ((regSet.rsMaskUsed & RBM_ARG_0) != 0) && // and regSet.rsMaskUsed contains REG_ARG_0
- (reg != REG_ARG_0)) // unless REG_ARG_0 contains the REF value being written, which we're finished with.
- {
- regSet.rsSpillReg(REG_ARG_0);
- }
+ // We may need to spill whatever is in the ARG_0 register
+ //
+ if (((tgtAddrReg & RBM_ARG_0) == 0) && // tgtAddrReg does not contain REG_ARG_0
+ ((regSet.rsMaskUsed & RBM_ARG_0) != 0) && // and regSet.rsMaskUsed contains REG_ARG_0
+ (reg != REG_ARG_0)) // unless REG_ARG_0 contains the REF value being written, which we're finished with.
+ {
+ regSet.rsSpillReg(REG_ARG_0);
+ }
- inst_RV_TT(INS_lea, REG_ARG_0, tgt, 0, EA_BYREF);
+ inst_RV_TT(INS_lea, REG_ARG_0, tgt, 0, EA_BYREF);
- /* Free up anything that was tied up by the LHS */
- genDoneAddressable(tgt, tgtAddrReg, RegSet::KEEP_REG);
+ /* Free up anything that was tied up by the LHS */
+ genDoneAddressable(tgt, tgtAddrReg, RegSet::KEEP_REG);
- regTracker.rsTrackRegTrash(REG_ARG_0);
- gcInfo.gcMarkRegSetNpt(REG_ARG_0);
- gcInfo.gcMarkRegSetByref(RBM_ARG_0); // byref in ARG_0
+ regTracker.rsTrackRegTrash(REG_ARG_0);
+ gcInfo.gcMarkRegSetNpt(REG_ARG_0);
+ gcInfo.gcMarkRegSetByref(RBM_ARG_0); // byref in ARG_0
#ifdef _TARGET_ARM_
#if NOGC_WRITE_BARRIERS
- // Finally, we may be required to spill whatever is in the further argument registers
- // trashed by the call. The write barrier trashes some further registers --
- // either the standard volatile var set, or, if we're using assembly barriers, a more specialized set.
+ // Finally, we may be required to spill whatever is in the further argument registers
+ // trashed by the call. The write barrier trashes some further registers --
+ // either the standard volatile var set, or, if we're using assembly barriers, a more specialized set.
- regMaskTP volatileRegsTrashed = RBM_CALLEE_TRASH_NOGC;
+ regMaskTP volatileRegsTrashed = RBM_CALLEE_TRASH_NOGC;
#else
- regMaskTP volatileRegsTrashed = RBM_CALLEE_TRASH;
+ regMaskTP volatileRegsTrashed = RBM_CALLEE_TRASH;
#endif
- // Spill any other registers trashed by the write barrier call and currently in use.
- regMaskTP mustSpill = (volatileRegsTrashed & regSet.rsMaskUsed & ~(RBM_ARG_0|RBM_ARG_1));
- if (mustSpill) regSet.rsSpillRegs(mustSpill);
+ // Spill any other registers trashed by the write barrier call and currently in use.
+ regMaskTP mustSpill = (volatileRegsTrashed & regSet.rsMaskUsed & ~(RBM_ARG_0 | RBM_ARG_1));
+ if (mustSpill)
+ regSet.rsSpillRegs(mustSpill);
#endif // _TARGET_ARM_
- bool free_arg0 = false;
- if ((regSet.rsMaskUsed & RBM_ARG_0) == 0)
- {
- regSet.rsMaskUsed |= RBM_ARG_0;
- free_arg0 = true;
- }
+ bool free_arg0 = false;
+ if ((regSet.rsMaskUsed & RBM_ARG_0) == 0)
+ {
+ regSet.rsMaskUsed |= RBM_ARG_0;
+ free_arg0 = true;
+ }
- // genEmitHelperCall might need to grab a register
- // so don't let it spill one of the arguments
- //
- regMaskTP reallyUsedRegs = RBM_NONE;
- regSet.rsLockReg(RBM_ARG_0|RBM_ARG_1, &reallyUsedRegs);
+ // genEmitHelperCall might need to grab a register
+ // so don't let it spill one of the arguments
+ //
+ regMaskTP reallyUsedRegs = RBM_NONE;
+ regSet.rsLockReg(RBM_ARG_0 | RBM_ARG_1, &reallyUsedRegs);
- genGCWriteBarrier(tgt, wbf);
+ genGCWriteBarrier(tgt, wbf);
- regSet.rsUnlockReg(RBM_ARG_0|RBM_ARG_1, reallyUsedRegs);
- gcInfo.gcMarkRegSetNpt(RBM_ARG_0 | RBM_ARG_1); // byref ARG_0 and reg ARG_1 are killed by the call
+ regSet.rsUnlockReg(RBM_ARG_0 | RBM_ARG_1, reallyUsedRegs);
+ gcInfo.gcMarkRegSetNpt(RBM_ARG_0 | RBM_ARG_1); // byref ARG_0 and reg ARG_1 are killed by the call
- if (free_arg0)
- {
- regSet.rsMaskUsed &= ~RBM_ARG_0;
- }
- if (free_arg1)
- {
- regSet.rsMaskUsed &= ~RBM_ARG_1;
- }
+ if (free_arg0)
+ {
+ regSet.rsMaskUsed &= ~RBM_ARG_0;
+ }
+ if (free_arg1)
+ {
+ regSet.rsMaskUsed &= ~RBM_ARG_1;
+ }
- return resultRegMask;
+ return resultRegMask;
}
#endif // defined(DEBUG) || !(defined(_TARGET_X86_) && NOGC_WRITE_BARRIERS)
-#else // !FEATURE_WRITE_BARRIER
+#else // !FEATURE_WRITE_BARRIER
NYI("FEATURE_WRITE_BARRIER unimplemented");
- return resultRegMask;
+ return resultRegMask;
#endif // !FEATURE_WRITE_BARRIER
-
}
#ifdef _TARGET_X86_
@@ -3490,56 +3335,53 @@ regMaskTP CodeGen::WriteBarrier(GenTreePtr tgt,
* of two long values have been compared.
*/
-void CodeGen::genJccLongHi(genTreeOps cmp,
- BasicBlock * jumpTrue,
- BasicBlock * jumpFalse,
- bool isUnsigned )
+void CodeGen::genJccLongHi(genTreeOps cmp, BasicBlock* jumpTrue, BasicBlock* jumpFalse, bool isUnsigned)
{
if (cmp != GT_NE)
{
- jumpFalse->bbFlags |= BBF_JMP_TARGET|BBF_HAS_LABEL;
+ jumpFalse->bbFlags |= BBF_JMP_TARGET | BBF_HAS_LABEL;
}
switch (cmp)
{
- case GT_EQ:
- inst_JMP(EJ_jne, jumpFalse);
- break;
+ case GT_EQ:
+ inst_JMP(EJ_jne, jumpFalse);
+ break;
- case GT_NE:
- inst_JMP(EJ_jne, jumpTrue);
- break;
+ case GT_NE:
+ inst_JMP(EJ_jne, jumpTrue);
+ break;
- case GT_LT:
- case GT_LE:
- if (isUnsigned)
- {
- inst_JMP(EJ_ja , jumpFalse);
- inst_JMP(EJ_jb , jumpTrue);
- }
- else
- {
- inst_JMP(EJ_jg , jumpFalse);
- inst_JMP(EJ_jl , jumpTrue);
- }
- break;
+ case GT_LT:
+ case GT_LE:
+ if (isUnsigned)
+ {
+ inst_JMP(EJ_ja, jumpFalse);
+ inst_JMP(EJ_jb, jumpTrue);
+ }
+ else
+ {
+ inst_JMP(EJ_jg, jumpFalse);
+ inst_JMP(EJ_jl, jumpTrue);
+ }
+ break;
- case GT_GE:
- case GT_GT:
- if (isUnsigned)
- {
- inst_JMP(EJ_jb , jumpFalse);
- inst_JMP(EJ_ja , jumpTrue);
- }
- else
- {
- inst_JMP(EJ_jl , jumpFalse);
- inst_JMP(EJ_jg , jumpTrue);
- }
- break;
+ case GT_GE:
+ case GT_GT:
+ if (isUnsigned)
+ {
+ inst_JMP(EJ_jb, jumpFalse);
+ inst_JMP(EJ_ja, jumpTrue);
+ }
+ else
+ {
+ inst_JMP(EJ_jl, jumpFalse);
+ inst_JMP(EJ_jg, jumpTrue);
+ }
+ break;
- default:
- noway_assert(!"expected a comparison operator");
+ default:
+ noway_assert(!"expected a comparison operator");
}
}
@@ -3549,38 +3391,36 @@ void CodeGen::genJccLongHi(genTreeOps cmp,
* of two long values have been compared.
*/
-void CodeGen::genJccLongLo(genTreeOps cmp,
- BasicBlock* jumpTrue,
- BasicBlock* jumpFalse)
+void CodeGen::genJccLongLo(genTreeOps cmp, BasicBlock* jumpTrue, BasicBlock* jumpFalse)
{
switch (cmp)
{
- case GT_EQ:
- inst_JMP(EJ_je , jumpTrue);
- break;
+ case GT_EQ:
+ inst_JMP(EJ_je, jumpTrue);
+ break;
- case GT_NE:
- inst_JMP(EJ_jne, jumpTrue);
- break;
+ case GT_NE:
+ inst_JMP(EJ_jne, jumpTrue);
+ break;
- case GT_LT:
- inst_JMP(EJ_jb , jumpTrue);
- break;
+ case GT_LT:
+ inst_JMP(EJ_jb, jumpTrue);
+ break;
- case GT_LE:
- inst_JMP(EJ_jbe, jumpTrue);
- break;
+ case GT_LE:
+ inst_JMP(EJ_jbe, jumpTrue);
+ break;
- case GT_GE:
- inst_JMP(EJ_jae, jumpTrue);
- break;
+ case GT_GE:
+ inst_JMP(EJ_jae, jumpTrue);
+ break;
- case GT_GT:
- inst_JMP(EJ_ja , jumpTrue);
- break;
+ case GT_GT:
+ inst_JMP(EJ_ja, jumpTrue);
+ break;
- default:
- noway_assert(!"expected comparison");
+ default:
+ noway_assert(!"expected comparison");
}
}
#elif defined(_TARGET_ARM_)
@@ -3590,10 +3430,7 @@ void CodeGen::genJccLongLo(genTreeOps cmp,
* of two long values have been compared.
*/
-void CodeGen::genJccLongHi(genTreeOps cmp,
- BasicBlock * jumpTrue,
- BasicBlock * jumpFalse,
- bool isUnsigned)
+void CodeGen::genJccLongHi(genTreeOps cmp, BasicBlock* jumpTrue, BasicBlock* jumpFalse, bool isUnsigned)
{
if (cmp != GT_NE)
{
@@ -3602,44 +3439,44 @@ void CodeGen::genJccLongHi(genTreeOps cmp,
switch (cmp)
{
- case GT_EQ:
- inst_JMP(EJ_ne, jumpFalse);
- break;
+ case GT_EQ:
+ inst_JMP(EJ_ne, jumpFalse);
+ break;
- case GT_NE:
- inst_JMP(EJ_ne, jumpTrue);
- break;
+ case GT_NE:
+ inst_JMP(EJ_ne, jumpTrue);
+ break;
- case GT_LT:
- case GT_LE:
- if (isUnsigned)
- {
- inst_JMP(EJ_hi, jumpFalse);
- inst_JMP(EJ_lo, jumpTrue);
- }
- else
- {
- inst_JMP(EJ_gt, jumpFalse);
- inst_JMP(EJ_lt, jumpTrue);
- }
- break;
+ case GT_LT:
+ case GT_LE:
+ if (isUnsigned)
+ {
+ inst_JMP(EJ_hi, jumpFalse);
+ inst_JMP(EJ_lo, jumpTrue);
+ }
+ else
+ {
+ inst_JMP(EJ_gt, jumpFalse);
+ inst_JMP(EJ_lt, jumpTrue);
+ }
+ break;
- case GT_GE:
- case GT_GT:
- if (isUnsigned)
- {
- inst_JMP(EJ_lo, jumpFalse);
- inst_JMP(EJ_hi, jumpTrue);
- }
- else
- {
- inst_JMP(EJ_lt, jumpFalse);
- inst_JMP(EJ_gt, jumpTrue);
- }
- break;
+ case GT_GE:
+ case GT_GT:
+ if (isUnsigned)
+ {
+ inst_JMP(EJ_lo, jumpFalse);
+ inst_JMP(EJ_hi, jumpTrue);
+ }
+ else
+ {
+ inst_JMP(EJ_lt, jumpFalse);
+ inst_JMP(EJ_gt, jumpTrue);
+ }
+ break;
- default:
- noway_assert(!"expected a comparison operator");
+ default:
+ noway_assert(!"expected a comparison operator");
}
}
@@ -3649,38 +3486,36 @@ void CodeGen::genJccLongHi(genTreeOps cmp,
* of two long values have been compared.
*/
-void CodeGen::genJccLongLo(genTreeOps cmp,
- BasicBlock* jumpTrue,
- BasicBlock* jumpFalse)
+void CodeGen::genJccLongLo(genTreeOps cmp, BasicBlock* jumpTrue, BasicBlock* jumpFalse)
{
switch (cmp)
{
- case GT_EQ:
- inst_JMP(EJ_eq, jumpTrue);
- break;
+ case GT_EQ:
+ inst_JMP(EJ_eq, jumpTrue);
+ break;
- case GT_NE:
- inst_JMP(EJ_ne, jumpTrue);
- break;
+ case GT_NE:
+ inst_JMP(EJ_ne, jumpTrue);
+ break;
- case GT_LT:
- inst_JMP(EJ_lo, jumpTrue);
- break;
+ case GT_LT:
+ inst_JMP(EJ_lo, jumpTrue);
+ break;
- case GT_LE:
- inst_JMP(EJ_ls, jumpTrue);
- break;
+ case GT_LE:
+ inst_JMP(EJ_ls, jumpTrue);
+ break;
- case GT_GE:
- inst_JMP(EJ_hs, jumpTrue);
- break;
+ case GT_GE:
+ inst_JMP(EJ_hs, jumpTrue);
+ break;
- case GT_GT:
- inst_JMP(EJ_hi, jumpTrue);
- break;
+ case GT_GT:
+ inst_JMP(EJ_hi, jumpTrue);
+ break;
- default:
- noway_assert(!"expected comparison");
+ default:
+ noway_assert(!"expected comparison");
}
}
#endif
@@ -3689,50 +3524,47 @@ void CodeGen::genJccLongLo(genTreeOps cmp,
* Called by genCondJump() for TYP_LONG.
*/
-void CodeGen::genCondJumpLng(GenTreePtr cond,
- BasicBlock* jumpTrue,
- BasicBlock* jumpFalse,
- bool bFPTransition)
+void CodeGen::genCondJumpLng(GenTreePtr cond, BasicBlock* jumpTrue, BasicBlock* jumpFalse, bool bFPTransition)
{
noway_assert(jumpTrue && jumpFalse);
noway_assert((cond->gtFlags & GTF_REVERSE_OPS) == false); // Done in genCondJump()
noway_assert(cond->gtOp.gtOp1->gtType == TYP_LONG);
- GenTreePtr op1 = cond->gtOp.gtOp1;
- GenTreePtr op2 = cond->gtOp.gtOp2;
- genTreeOps cmp = cond->OperGet();
+ GenTreePtr op1 = cond->gtOp.gtOp1;
+ GenTreePtr op2 = cond->gtOp.gtOp2;
+ genTreeOps cmp = cond->OperGet();
- regMaskTP addrReg;
+ regMaskTP addrReg;
/* Are we comparing against a constant? */
- if (op2->gtOper == GT_CNS_LNG)
+ if (op2->gtOper == GT_CNS_LNG)
{
- __int64 lval = op2->gtLngCon.gtLconVal;
- regNumber rTmp;
+ __int64 lval = op2->gtLngCon.gtLconVal;
+ regNumber rTmp;
// We're "done" evaluating op2; let's strip any commas off op1 before we
// evaluate it.
op1 = genCodeForCommaTree(op1);
/* We can generate better code for some special cases */
- instruction ins = INS_invalid;
- bool useIncToSetFlags = false;
- bool specialCaseCmp = false;
+ instruction ins = INS_invalid;
+ bool useIncToSetFlags = false;
+ bool specialCaseCmp = false;
if (cmp == GT_EQ)
{
if (lval == 0)
{
/* op1 == 0 */
- ins = INS_OR;
+ ins = INS_OR;
useIncToSetFlags = false;
specialCaseCmp = true;
}
else if (lval == -1)
{
/* op1 == -1 */
- ins = INS_AND;
+ ins = INS_AND;
useIncToSetFlags = true;
specialCaseCmp = true;
}
@@ -3742,14 +3574,14 @@ void CodeGen::genCondJumpLng(GenTreePtr cond,
if (lval == 0)
{
/* op1 != 0 */
- ins = INS_OR;
+ ins = INS_OR;
useIncToSetFlags = false;
specialCaseCmp = true;
}
else if (lval == -1)
{
/* op1 != -1 */
- ins = INS_AND;
+ ins = INS_AND;
useIncToSetFlags = true;
specialCaseCmp = true;
}
@@ -3761,7 +3593,7 @@ void CodeGen::genCondJumpLng(GenTreePtr cond,
addrReg = genMakeRvalueAddressable(op1, 0, RegSet::KEEP_REG, false, true);
- regMaskTP tmpMask = regSet.rsRegMaskCanGrab();
+ regMaskTP tmpMask = regSet.rsRegMaskCanGrab();
insFlags flags = useIncToSetFlags ? INS_FLAGS_DONT_CARE : INS_FLAGS_SET;
if (op1->gtFlags & GTF_REG_VAL)
@@ -3797,9 +3629,8 @@ void CodeGen::genCondJumpLng(GenTreePtr cond,
/* Set the flags using INS_AND | INS_OR */
inst_RV_TT(ins, rTmp, op1, 4, EA_4BYTE, flags);
}
-
}
- else // op1 is not GTF_REG_VAL
+ else // op1 is not GTF_REG_VAL
{
rTmp = regSet.rsGrabReg(tmpMask);
@@ -3841,19 +3672,18 @@ void CodeGen::genCondJumpLng(GenTreePtr cond,
/* Compare the high part first */
- int ival = (int)(lval >> 32);
+ int ival = (int)(lval >> 32);
/* Comparing a register against 0 is easier */
- if (!ival && (op1->gtFlags & GTF_REG_VAL)
- && (rTmp = genRegPairHi(op1->gtRegPair)) != REG_STK )
+ if (!ival && (op1->gtFlags & GTF_REG_VAL) && (rTmp = genRegPairHi(op1->gtRegPair)) != REG_STK)
{
/* Generate 'test rTmp, rTmp' */
instGen_Compare_Reg_To_Zero(emitTypeSize(op1->TypeGet()), rTmp); // set flags
}
else
{
- if (!(op1->gtFlags & GTF_REG_VAL) && (op1->gtOper == GT_CNS_LNG))
+ if (!(op1->gtFlags & GTF_REG_VAL) && (op1->gtOper == GT_CNS_LNG))
{
/* Special case: comparison of two constants */
// Needed as gtFoldExpr() doesn't fold longs
@@ -3881,14 +3711,14 @@ void CodeGen::genCondJumpLng(GenTreePtr cond,
if (bFPTransition)
{
jumpTrue = genTransitionBlockStackFP(&compCurFPState, compiler->compCurBB, jumpTrue);
- }
+ }
#endif
/* Generate the appropriate jumps */
- if (cond->gtFlags & GTF_UNSIGNED)
- genJccLongHi(cmp, jumpTrue, jumpFalse, true);
+ if (cond->gtFlags & GTF_UNSIGNED)
+ genJccLongHi(cmp, jumpTrue, jumpFalse, true);
else
- genJccLongHi(cmp, jumpTrue, jumpFalse);
+ genJccLongHi(cmp, jumpTrue, jumpFalse);
/* Compare the low part second */
@@ -3896,21 +3726,20 @@ void CodeGen::genCondJumpLng(GenTreePtr cond,
/* Comparing a register against 0 is easier */
- if (!ival && (op1->gtFlags & GTF_REG_VAL)
- && (rTmp = genRegPairLo(op1->gtRegPair)) != REG_STK)
+ if (!ival && (op1->gtFlags & GTF_REG_VAL) && (rTmp = genRegPairLo(op1->gtRegPair)) != REG_STK)
{
/* Generate 'test rTmp, rTmp' */
instGen_Compare_Reg_To_Zero(emitTypeSize(op1->TypeGet()), rTmp); // set flags
}
else
{
- if (!(op1->gtFlags & GTF_REG_VAL) && (op1->gtOper == GT_CNS_LNG))
+ if (!(op1->gtFlags & GTF_REG_VAL) && (op1->gtOper == GT_CNS_LNG))
{
/* Special case: comparison of two constants */
// Needed as gtFoldExpr() doesn't fold longs
noway_assert(addrReg == 0);
- int op1_loword = (int) op1->gtLngCon.gtLconVal;
+ int op1_loword = (int)op1->gtLngCon.gtLconVal;
/* get the constant operand into a register */
rTmp = genGetRegSetToIcon(op1_loword);
@@ -3981,7 +3810,7 @@ void CodeGen::genCondJumpLng(GenTreePtr cond,
inst_RV_TT(INS_cmp, genRegPairHi(regPair), op2, 4);
- if (cond->gtFlags & GTF_UNSIGNED)
+ if (cond->gtFlags & GTF_UNSIGNED)
genJccLongHi(cmp, jumpTrue, jumpFalse, true);
else
genJccLongHi(cmp, jumpTrue, jumpFalse);
@@ -4006,7 +3835,6 @@ void CodeGen::genCondJumpLng(GenTreePtr cond,
}
}
-
/*****************************************************************************
* gen_fcomp_FN, gen_fcomp_FS_TT, gen_fcompp_FS
* Called by genCondJumpFlt() to generate the fcomp instruction appropriate
@@ -4029,7 +3857,7 @@ void CodeGen::genCondJumpLng(GenTreePtr cond,
* already placed its result in the EFLAGS register.
*/
-bool CodeGen::genUse_fcomip()
+bool CodeGen::genUse_fcomip()
{
return compiler->opts.compUseFCOMI;
}
@@ -4045,72 +3873,70 @@ bool CodeGen::genUse_fcomip()
* Returns the flags the following jump/set instruction should use.
*/
-emitJumpKind CodeGen::genCondSetFlags(GenTreePtr cond)
+emitJumpKind CodeGen::genCondSetFlags(GenTreePtr cond)
{
noway_assert(cond->OperIsCompare());
noway_assert(varTypeIsI(genActualType(cond->gtOp.gtOp1->gtType)));
- GenTreePtr op1 = cond->gtOp.gtOp1;
- GenTreePtr op2 = cond->gtOp.gtOp2;
- genTreeOps cmp = cond->OperGet();
+ GenTreePtr op1 = cond->gtOp.gtOp1;
+ GenTreePtr op2 = cond->gtOp.gtOp2;
+ genTreeOps cmp = cond->OperGet();
- if (cond->gtFlags & GTF_REVERSE_OPS)
+ if (cond->gtFlags & GTF_REVERSE_OPS)
{
/* Don't forget to modify the condition as well */
cond->gtOp.gtOp1 = op2;
cond->gtOp.gtOp2 = op1;
- cond->SetOper (GenTree::SwapRelop(cmp));
- cond->gtFlags &= ~GTF_REVERSE_OPS;
+ cond->SetOper(GenTree::SwapRelop(cmp));
+ cond->gtFlags &= ~GTF_REVERSE_OPS;
/* Get hold of the new values */
- cmp = cond->OperGet();
- op1 = cond->gtOp.gtOp1;
- op2 = cond->gtOp.gtOp2;
+ cmp = cond->OperGet();
+ op1 = cond->gtOp.gtOp1;
+ op2 = cond->gtOp.gtOp2;
}
// Note that op1's type may get bashed. So save it early
- var_types op1Type = op1->TypeGet();
- bool unsignedCmp = (cond->gtFlags & GTF_UNSIGNED) != 0;
- emitAttr size = EA_UNKNOWN;
+ var_types op1Type = op1->TypeGet();
+ bool unsignedCmp = (cond->gtFlags & GTF_UNSIGNED) != 0;
+ emitAttr size = EA_UNKNOWN;
+
+ regMaskTP regNeed;
+ regMaskTP addrReg1 = RBM_NONE;
+ regMaskTP addrReg2 = RBM_NONE;
+ emitJumpKind jumpKind = EJ_COUNT; // Initialize with an invalid value
- regMaskTP regNeed;
- regMaskTP addrReg1 = RBM_NONE;
- regMaskTP addrReg2 = RBM_NONE;
- emitJumpKind jumpKind = EJ_COUNT; // Initialize with an invalid value
+ bool byteCmp;
+ bool shortCmp;
- bool byteCmp;
- bool shortCmp;
-
regMaskTP newLiveMask;
regNumber op1Reg;
/* Are we comparing against a constant? */
- if (op2->IsCnsIntOrI())
+ if (op2->IsCnsIntOrI())
{
- ssize_t ival = op2->gtIntConCommon.IconValue();
+ ssize_t ival = op2->gtIntConCommon.IconValue();
/* unsigned less than comparisons with 1 ('< 1' )
should be transformed into '== 0' to potentially
suppress a tst instruction.
*/
- if ((ival == 1) && (cmp == GT_LT) && unsignedCmp)
+ if ((ival == 1) && (cmp == GT_LT) && unsignedCmp)
{
op2->gtIntCon.gtIconVal = ival = 0;
- cond->gtOper = cmp = GT_EQ;
+ cond->gtOper = cmp = GT_EQ;
}
/* Comparisons against 0 can be easier */
- if (ival == 0)
+ if (ival == 0)
{
// if we can safely change the comparison to unsigned we do so
- if (!unsignedCmp &&
- varTypeIsSmall(op1->TypeGet()) &&
- varTypeIsUnsigned(op1->TypeGet()))
+ if (!unsignedCmp && varTypeIsSmall(op1->TypeGet()) && varTypeIsUnsigned(op1->TypeGet()))
{
unsignedCmp = true;
}
@@ -4128,18 +3954,18 @@ emitJumpKind CodeGen::genCondSetFlags(GenTreePtr cond)
/* Is this a simple zero/non-zero test? */
- if (cmp == GT_EQ || cmp == GT_NE)
+ if (cmp == GT_EQ || cmp == GT_NE)
{
/* Is the operand an "AND" operation? */
- if (op1->gtOper == GT_AND)
+ if (op1->gtOper == GT_AND)
{
- GenTreePtr an1 = op1->gtOp.gtOp1;
- GenTreePtr an2 = op1->gtOp.gtOp2;
+ GenTreePtr an1 = op1->gtOp.gtOp1;
+ GenTreePtr an2 = op1->gtOp.gtOp2;
/* Check for the case "expr & icon" */
- if (an2->IsIntCnsFitsInI32())
+ if (an2->IsIntCnsFitsInI32())
{
int iVal = (int)an2->gtIntCon.gtIconVal;
@@ -4147,18 +3973,18 @@ emitJumpKind CodeGen::genCondSetFlags(GenTreePtr cond)
switch (an1->gtType)
{
- case TYP_BOOL:
- case TYP_BYTE:
- if (iVal & 0xffffff00)
- goto NO_TEST_FOR_AND;
- break;
- case TYP_CHAR:
- case TYP_SHORT:
- if (iVal & 0xffff0000)
- goto NO_TEST_FOR_AND;
- break;
- default:
- break;
+ case TYP_BOOL:
+ case TYP_BYTE:
+ if (iVal & 0xffffff00)
+ goto NO_TEST_FOR_AND;
+ break;
+ case TYP_CHAR:
+ case TYP_SHORT:
+ if (iVal & 0xffff0000)
+ goto NO_TEST_FOR_AND;
+ break;
+ default:
+ break;
}
if (an1->IsCnsIntOrI())
@@ -4177,7 +4003,7 @@ emitJumpKind CodeGen::genCondSetFlags(GenTreePtr cond)
genComputeAddressable(an1, addrReg1, RegSet::KEEP_REG, RBM_NONE, RegSet::KEEP_REG);
if (arm_Valid_Imm_For_Alu(iVal))
{
- inst_RV_IV(INS_TEST,an1->gtRegNum, iVal, emitActualTypeSize(an1->gtType));
+ inst_RV_IV(INS_TEST, an1->gtRegNum, iVal, emitActualTypeSize(an1->gtType));
}
else
{
@@ -4195,7 +4021,8 @@ emitJumpKind CodeGen::genCondSetFlags(GenTreePtr cond)
// Check to see if we can use a smaller immediate.
if ((an1->gtFlags & GTF_REG_VAL) && ((iVal & 0x0000FFFF) == iVal))
{
- var_types testType = (var_types)(((iVal & 0x000000FF) == iVal) ? TYP_UBYTE : TYP_USHORT);
+ var_types testType =
+ (var_types)(((iVal & 0x000000FF) == iVal) ? TYP_UBYTE : TYP_USHORT);
#if CPU_HAS_BYTE_REGS
// if we don't have byte-able register, switch to the 2-byte form
if ((testType == TYP_UBYTE) && !(genRegMask(an1->gtRegNum) & RBM_BYTE_REGS))
@@ -4213,12 +4040,9 @@ emitJumpKind CodeGen::genCondSetFlags(GenTreePtr cond)
}
}
-
goto DONE;
- NO_TEST_FOR_AND:
- ;
-
+ NO_TEST_FOR_AND:;
}
// TODO: Check for other cases that can generate 'test',
@@ -4234,7 +4058,7 @@ emitJumpKind CodeGen::genCondSetFlags(GenTreePtr cond)
{
/*
Unsigned comparison to 0. Using this table:
-
+
----------------------------------------------------
| Comparison | Flags Checked | Instruction Used |
----------------------------------------------------
@@ -4250,34 +4074,58 @@ emitJumpKind CodeGen::genCondSetFlags(GenTreePtr cond)
----------------------------------------------------
| > 0 | ZF = 0 | jne |
----------------------------------------------------
- */
+ */
switch (cmp)
{
#ifdef _TARGET_ARM_
- case GT_EQ: jumpKind = EJ_eq; break;
- case GT_NE: jumpKind = EJ_ne; break;
- case GT_LT: jumpKind = EJ_NONE; break;
- case GT_LE: jumpKind = EJ_eq; break;
- case GT_GE: jumpKind = EJ_NONE; break;
- case GT_GT: jumpKind = EJ_ne; break;
+ case GT_EQ:
+ jumpKind = EJ_eq;
+ break;
+ case GT_NE:
+ jumpKind = EJ_ne;
+ break;
+ case GT_LT:
+ jumpKind = EJ_NONE;
+ break;
+ case GT_LE:
+ jumpKind = EJ_eq;
+ break;
+ case GT_GE:
+ jumpKind = EJ_NONE;
+ break;
+ case GT_GT:
+ jumpKind = EJ_ne;
+ break;
#elif defined(_TARGET_X86_)
- case GT_EQ: jumpKind = EJ_je; break;
- case GT_NE: jumpKind = EJ_jne; break;
- case GT_LT: jumpKind = EJ_NONE; break;
- case GT_LE: jumpKind = EJ_je; break;
- case GT_GE: jumpKind = EJ_NONE; break;
- case GT_GT: jumpKind = EJ_jne; break;
+ case GT_EQ:
+ jumpKind = EJ_je;
+ break;
+ case GT_NE:
+ jumpKind = EJ_jne;
+ break;
+ case GT_LT:
+ jumpKind = EJ_NONE;
+ break;
+ case GT_LE:
+ jumpKind = EJ_je;
+ break;
+ case GT_GE:
+ jumpKind = EJ_NONE;
+ break;
+ case GT_GT:
+ jumpKind = EJ_jne;
+ break;
#endif // TARGET
- default:
- noway_assert(!"Unexpected comparison OpCode");
- break;
+ default:
+ noway_assert(!"Unexpected comparison OpCode");
+ break;
}
}
else
{
/*
Signed comparison to 0. Using this table:
-
+
-----------------------------------------------------
| Comparison | Flags Checked | Instruction Used |
-----------------------------------------------------
@@ -4298,31 +4146,55 @@ emitJumpKind CodeGen::genCondSetFlags(GenTreePtr cond)
switch (cmp)
{
#ifdef _TARGET_ARM_
- case GT_EQ: jumpKind = EJ_eq; break;
- case GT_NE: jumpKind = EJ_ne; break;
- case GT_LT: jumpKind = EJ_mi; break;
- case GT_LE: jumpKind = EJ_NONE; break;
- case GT_GE: jumpKind = EJ_pl; break;
- case GT_GT: jumpKind = EJ_NONE; break;
+ case GT_EQ:
+ jumpKind = EJ_eq;
+ break;
+ case GT_NE:
+ jumpKind = EJ_ne;
+ break;
+ case GT_LT:
+ jumpKind = EJ_mi;
+ break;
+ case GT_LE:
+ jumpKind = EJ_NONE;
+ break;
+ case GT_GE:
+ jumpKind = EJ_pl;
+ break;
+ case GT_GT:
+ jumpKind = EJ_NONE;
+ break;
#elif defined(_TARGET_X86_)
- case GT_EQ: jumpKind = EJ_je; break;
- case GT_NE: jumpKind = EJ_jne; break;
- case GT_LT: jumpKind = EJ_js; break;
- case GT_LE: jumpKind = EJ_NONE; break;
- case GT_GE: jumpKind = EJ_jns; break;
- case GT_GT: jumpKind = EJ_NONE; break;
+ case GT_EQ:
+ jumpKind = EJ_je;
+ break;
+ case GT_NE:
+ jumpKind = EJ_jne;
+ break;
+ case GT_LT:
+ jumpKind = EJ_js;
+ break;
+ case GT_LE:
+ jumpKind = EJ_NONE;
+ break;
+ case GT_GE:
+ jumpKind = EJ_jns;
+ break;
+ case GT_GT:
+ jumpKind = EJ_NONE;
+ break;
#endif // TARGET
- default:
- noway_assert(!"Unexpected comparison OpCode");
- break;
+ default:
+ noway_assert(!"Unexpected comparison OpCode");
+ break;
}
assert(jumpKind == genJumpKindForOper(cmp, CK_LOGICAL));
}
- assert(jumpKind != EJ_COUNT); // Ensure that it was assigned a valid value above
+ assert(jumpKind != EJ_COUNT); // Ensure that it was assigned a valid value above
/* Is the value a simple local variable? */
- if (op1->gtOper == GT_LCL_VAR)
+ if (op1->gtOper == GT_LCL_VAR)
{
/* Is the flags register set to the value? */
@@ -4352,7 +4224,7 @@ emitJumpKind CodeGen::genCondSetFlags(GenTreePtr cond)
}
}
- if (flags)
+ if (flags)
{
if (jumpKind != EJ_NONE)
{
@@ -4362,9 +4234,9 @@ emitJumpKind CodeGen::genCondSetFlags(GenTreePtr cond)
/* Is the value in a register? */
- if (op1->gtFlags & GTF_REG_VAL)
+ if (op1->gtFlags & GTF_REG_VAL)
{
- regNumber reg = op1->gtRegNum;
+ regNumber reg = op1->gtRegNum;
/* With a 'test' we can do any signed test or any test for equality */
@@ -4396,7 +4268,6 @@ emitJumpKind CodeGen::genCondSetFlags(GenTreePtr cond)
{
bool smallOk = true;
-
/* make sure that constant is not out of op1's range
if it is, we need to perform an int with int comparison
and therefore, we set smallOk to false, so op1 gets loaded
@@ -4407,45 +4278,63 @@ emitJumpKind CodeGen::genCondSetFlags(GenTreePtr cond)
* comparison, we can use smallOk. But we don't know which
* flags will be needed. This probably doesn't happen often.
*/
- var_types gtType=op1->TypeGet();
+ var_types gtType = op1->TypeGet();
switch (gtType)
{
- case TYP_BYTE: if (ival != (signed char )ival) smallOk = false; break;
- case TYP_BOOL:
- case TYP_UBYTE: if (ival != (unsigned char )ival) smallOk = false; break;
+ case TYP_BYTE:
+ if (ival != (signed char)ival)
+ smallOk = false;
+ break;
+ case TYP_BOOL:
+ case TYP_UBYTE:
+ if (ival != (unsigned char)ival)
+ smallOk = false;
+ break;
- case TYP_SHORT: if (ival != (signed short)ival) smallOk = false; break;
- case TYP_CHAR: if (ival != (unsigned short)ival) smallOk = false; break;
+ case TYP_SHORT:
+ if (ival != (signed short)ival)
+ smallOk = false;
+ break;
+ case TYP_CHAR:
+ if (ival != (unsigned short)ival)
+ smallOk = false;
+ break;
#ifdef _TARGET_64BIT_
- case TYP_INT: if (!FitsIn<INT32>(ival)) smallOk = false; break;
- case TYP_UINT: if (!FitsIn<UINT32>(ival)) smallOk = false; break;
+ case TYP_INT:
+ if (!FitsIn<INT32>(ival))
+ smallOk = false;
+ break;
+ case TYP_UINT:
+ if (!FitsIn<UINT32>(ival))
+ smallOk = false;
+ break;
#endif // _TARGET_64BIT_
- default: break;
+ default:
+ break;
}
- if (smallOk && // constant is in op1's range
- !unsignedCmp && // signed comparison
- varTypeIsSmall(gtType) && // smalltype var
- varTypeIsUnsigned(gtType)) // unsigned type
+ if (smallOk && // constant is in op1's range
+ !unsignedCmp && // signed comparison
+ varTypeIsSmall(gtType) && // smalltype var
+ varTypeIsUnsigned(gtType)) // unsigned type
{
unsignedCmp = true;
}
/* Make the comparand addressable */
addrReg1 = genMakeRvalueAddressable(op1, RBM_NONE, RegSet::KEEP_REG, false, smallOk);
-
}
-// #if defined(DEBUGGING_SUPPORT)
+ // #if defined(DEBUGGING_SUPPORT)
/* Special case: comparison of two constants */
// Needed if Importer doesn't call gtFoldExpr()
- if (!(op1->gtFlags & GTF_REG_VAL) && (op1->IsCnsIntOrI()))
+ if (!(op1->gtFlags & GTF_REG_VAL) && (op1->IsCnsIntOrI()))
{
// noway_assert(compiler->opts.MinOpts() || compiler->opts.compDbgCode);
@@ -4458,7 +4347,7 @@ emitJumpKind CodeGen::genCondSetFlags(GenTreePtr cond)
addrReg1 = genRegMask(op1->gtRegNum);
}
-// #endif
+ // #endif
/* Compare the operand against the constant */
@@ -4489,7 +4378,7 @@ emitJumpKind CodeGen::genCondSetFlags(GenTreePtr cond)
noway_assert(op1->gtOper != GT_CNS_INT);
- if (op2->gtOper == GT_LCL_VAR)
+ if (op2->gtOper == GT_LCL_VAR)
genMarkLclVar(op2);
assert(((addrReg1 | addrReg2) & regSet.rsMaskUsed) == (addrReg1 | addrReg2));
@@ -4497,7 +4386,7 @@ emitJumpKind CodeGen::genCondSetFlags(GenTreePtr cond)
/* Are we comparing against a register? */
- if (op2->gtFlags & GTF_REG_VAL)
+ if (op2->gtFlags & GTF_REG_VAL)
{
/* Make the comparands addressable and mark as used */
@@ -4506,7 +4395,7 @@ emitJumpKind CodeGen::genCondSetFlags(GenTreePtr cond)
/* Is the size of the comparison byte/char/short ? */
- if (varTypeIsSmall(op1->TypeGet()))
+ if (varTypeIsSmall(op1->TypeGet()))
{
/* Is op2 sitting in an appropriate register? */
@@ -4544,7 +4433,7 @@ emitJumpKind CodeGen::genCondSetFlags(GenTreePtr cond)
goto DONE;
-NO_SMALL_CMP:
+ NO_SMALL_CMP:
// op1 has been made addressable and is marked as in use
// op2 is un-generated
@@ -4555,7 +4444,7 @@ NO_SMALL_CMP:
regNumber reg1 = regSet.rsPickReg();
noway_assert(varTypeIsSmall(op1->TypeGet()));
- instruction ins = ins_Move_Extend(op1->TypeGet(), (op1->gtFlags & GTF_REG_VAL)!=0);
+ instruction ins = ins_Move_Extend(op1->TypeGet(), (op1->gtFlags & GTF_REG_VAL) != 0);
// regSet.rsPickReg can cause one of the trees within this address mode to get spilled
// so we need to make sure it is still valid. Note that at this point, reg1 is
@@ -4582,8 +4471,8 @@ NO_SMALL_CMP:
}
// We come here if op2 is not enregistered or not in a "good" register.
-
- assert(addrReg1 == 0);
+
+ assert(addrReg1 == 0);
// Determine what registers go live between op1 and op2
newLiveMask = genNewLiveRegMask(op1, op2);
@@ -4600,12 +4489,12 @@ NO_SMALL_CMP:
#if CPU_HAS_BYTE_REGS
// if necessary setup regNeed to select just the byte-able registers
- if (byteCmp)
+ if (byteCmp)
regNeed = regSet.rsNarrowHint(RBM_BYTE_REGS, regNeed);
#endif // CPU_HAS_BYTE_REGS
// Compute the first comparand into some register, regNeed here is simply a hint because RegSet::ANY_REG is used.
- //
+ //
genComputeReg(op1, regNeed, RegSet::ANY_REG, RegSet::FREE_REG);
noway_assert(op1->gtFlags & GTF_REG_VAL);
@@ -4617,7 +4506,7 @@ NO_SMALL_CMP:
#if CPU_HAS_BYTE_REGS
// if necessary setup regNeed to select just the byte-able registers
- if (byteCmp)
+ if (byteCmp)
regNeed &= RBM_BYTE_REGS;
#endif // CPU_HAS_BYTE_REGS
@@ -4627,13 +4516,12 @@ NO_SMALL_CMP:
// avoid selecting op2 reserved regs, as using them will force a spill temp to be used.
regNeed = regSet.rsMustExclude(regNeed, op2->gtRsvdRegs);
- // Did we end up in an acceptable register?
+ // Did we end up in an acceptable register?
// and do we have an acceptable free register available to grab?
//
- if ( ((genRegMask(op1Reg) & regNeed) == 0) &&
- ((regSet.rsRegMaskFree() & regNeed) != 0) )
+ if (((genRegMask(op1Reg) & regNeed) == 0) && ((regSet.rsRegMaskFree() & regNeed) != 0))
{
- // Grab an acceptable register
+ // Grab an acceptable register
regNumber newReg = regSet.rsGrabReg(regNeed);
noway_assert(op1Reg != newReg);
@@ -4662,7 +4550,7 @@ NO_SMALL_CMP:
/* Mark the register as 'used' */
regSet.rsMarkRegUsed(op1);
-
+
addrReg1 = genRegMask(op1Reg);
assert(((addrReg1 | addrReg2) & regSet.rsMaskUsed) == (addrReg1 | addrReg2));
@@ -4682,7 +4570,7 @@ DONE_OP1:
#if CPU_HAS_BYTE_REGS
// if necessary setup regNeed to select just the byte-able registers
- if (byteCmp)
+ if (byteCmp)
regNeed &= RBM_BYTE_REGS;
#endif // CPU_HAS_BYTE_REGS
@@ -4738,7 +4626,7 @@ DONE_OP1:
inst_RV_TT(INS_cmp, op1->gtRegNum, op2, 0, size);
DONE:
-
+
jumpKind = genJumpKindForOper(cmp, unsignedCmp ? CK_UNSIGNED : CK_SIGNED);
DONE_FLAGS: // We have determined what jumpKind to use
@@ -4752,7 +4640,7 @@ DONE_FLAGS: // We have determined what jumpKind to use
genDoneAddressable(op1, addrReg1, RegSet::KEEP_REG);
genDoneAddressable(op2, addrReg2, RegSet::KEEP_REG);
- noway_assert(jumpKind != EJ_COUNT); // Ensure that it was assigned a valid value
+ noway_assert(jumpKind != EJ_COUNT); // Ensure that it was assigned a valid value
return jumpKind;
}
@@ -4765,20 +4653,16 @@ DONE_FLAGS: // We have determined what jumpKind to use
* the given relational operator yields 'true'.
*/
-void CodeGen::genCondJump(GenTreePtr cond,
- BasicBlock *destTrue,
- BasicBlock *destFalse,
- bool bStackFPFixup
- )
+void CodeGen::genCondJump(GenTreePtr cond, BasicBlock* destTrue, BasicBlock* destFalse, bool bStackFPFixup)
{
- BasicBlock * jumpTrue;
- BasicBlock * jumpFalse;
+ BasicBlock* jumpTrue;
+ BasicBlock* jumpFalse;
- GenTreePtr op1 = cond->gtOp.gtOp1;
- GenTreePtr op2 = cond->gtOp.gtOp2;
- genTreeOps cmp = cond->OperGet();
+ GenTreePtr op1 = cond->gtOp.gtOp1;
+ GenTreePtr op2 = cond->gtOp.gtOp2;
+ genTreeOps cmp = cond->OperGet();
- if (destTrue)
+ if (destTrue)
{
jumpTrue = destTrue;
jumpFalse = destFalse;
@@ -4794,80 +4678,78 @@ void CodeGen::genCondJump(GenTreePtr cond,
noway_assert(cond->OperIsCompare());
/* Make sure the more expensive operand is 'op1' */
- noway_assert( (cond->gtFlags & GTF_REVERSE_OPS) == 0 );
+ noway_assert((cond->gtFlags & GTF_REVERSE_OPS) == 0);
- if (cond->gtFlags & GTF_REVERSE_OPS) // TODO: note that this is now dead code, since the above is a noway_assert()
+ if (cond->gtFlags & GTF_REVERSE_OPS) // TODO: note that this is now dead code, since the above is a noway_assert()
{
/* Don't forget to modify the condition as well */
cond->gtOp.gtOp1 = op2;
cond->gtOp.gtOp2 = op1;
- cond->SetOper (GenTree::SwapRelop(cmp));
- cond->gtFlags &= ~GTF_REVERSE_OPS;
+ cond->SetOper(GenTree::SwapRelop(cmp));
+ cond->gtFlags &= ~GTF_REVERSE_OPS;
/* Get hold of the new values */
- cmp = cond->OperGet();
- op1 = cond->gtOp.gtOp1;
- op2 = cond->gtOp.gtOp2;
+ cmp = cond->OperGet();
+ op1 = cond->gtOp.gtOp1;
+ op2 = cond->gtOp.gtOp2;
}
/* What is the type of the operand? */
switch (genActualType(op1->gtType))
{
- case TYP_INT:
- case TYP_REF:
- case TYP_BYREF:
- emitJumpKind jumpKind;
+ case TYP_INT:
+ case TYP_REF:
+ case TYP_BYREF:
+ emitJumpKind jumpKind;
- // Check if we can use the currently set flags. Else set them
+ // Check if we can use the currently set flags. Else set them
- jumpKind = genCondSetFlags(cond);
+ jumpKind = genCondSetFlags(cond);
#if FEATURE_STACK_FP_X87
- if (bStackFPFixup)
- {
- genCondJmpInsStackFP(jumpKind,
- jumpTrue,
- jumpFalse);
- }
- else
+ if (bStackFPFixup)
+ {
+ genCondJmpInsStackFP(jumpKind, jumpTrue, jumpFalse);
+ }
+ else
#endif
- {
- /* Generate the conditional jump */
- inst_JMP(jumpKind, jumpTrue);
- }
+ {
+ /* Generate the conditional jump */
+ inst_JMP(jumpKind, jumpTrue);
+ }
- return;
+ return;
- case TYP_LONG:
+ case TYP_LONG:
#if FEATURE_STACK_FP_X87
- if (bStackFPFixup)
- {
- genCondJumpLngStackFP(cond, jumpTrue, jumpFalse);
- }
- else
+ if (bStackFPFixup)
+ {
+ genCondJumpLngStackFP(cond, jumpTrue, jumpFalse);
+ }
+ else
#endif
- {
- genCondJumpLng(cond, jumpTrue, jumpFalse);
- }
- return;
+ {
+ genCondJumpLng(cond, jumpTrue, jumpFalse);
+ }
+ return;
- case TYP_FLOAT:
- case TYP_DOUBLE:
+ case TYP_FLOAT:
+ case TYP_DOUBLE:
#if FEATURE_STACK_FP_X87
- genCondJumpFltStackFP(cond, jumpTrue, jumpFalse, bStackFPFixup);
+ genCondJumpFltStackFP(cond, jumpTrue, jumpFalse, bStackFPFixup);
#else
- genCondJumpFloat(cond, jumpTrue, jumpFalse);
+ genCondJumpFloat(cond, jumpTrue, jumpFalse);
#endif
- return;
+ return;
- default:
+ default:
#ifdef DEBUG
- compiler->gtDispTree(cond);
+ compiler->gtDispTree(cond);
#endif
- unreached(); // unexpected/unsupported 'jtrue' operands type
+ unreached(); // unexpected/unsupported 'jtrue' operands type
}
}
@@ -4877,7 +4759,7 @@ void CodeGen::genCondJump(GenTreePtr cond,
#ifdef DEBUG
-void CodeGen::genStressRegs(GenTreePtr tree)
+void CodeGen::genStressRegs(GenTreePtr tree)
{
if (regSet.rsStressRegs() < 2)
return;
@@ -4893,13 +4775,14 @@ void CodeGen::genStressRegs(GenTreePtr tree)
for (regNum = REG_FIRST, regBit = 1; regNum < REG_COUNT; regNum = REG_NEXT(regNum), regBit <<= 1)
{
- if ((spillRegs & regBit) && (regSet.rsUsedTree[regNum] != NULL) && (genTypeSize(regSet.rsUsedTree[regNum]->TypeGet()) > 0))
+ if ((spillRegs & regBit) && (regSet.rsUsedTree[regNum] != NULL) &&
+ (genTypeSize(regSet.rsUsedTree[regNum]->TypeGet()) > 0))
{
regSet.rsSpillReg(regNum);
spillRegs &= regSet.rsMaskUsed;
- if (!spillRegs)
+ if (!spillRegs)
break;
}
}
@@ -4913,8 +4796,8 @@ void CodeGen::genStressRegs(GenTreePtr tree)
/* It is sometimes reasonable to expect that calling genCodeForTree()
on certain trees won't spill anything */
- if ((compiler->compCurStmt == compiler->compCurBB->bbTreeList) &&
- (compiler->compCurBB->bbCatchTyp) && handlerGetsXcptnObj(compiler->compCurBB->bbCatchTyp))
+ if ((compiler->compCurStmt == compiler->compCurBB->bbTreeList) && (compiler->compCurBB->bbCatchTyp) &&
+ handlerGetsXcptnObj(compiler->compCurBB->bbCatchTyp))
{
trashRegs &= ~(RBM_EXCEPTION_OBJECT);
}
@@ -4929,8 +4812,8 @@ void CodeGen::genStressRegs(GenTreePtr tree)
if (tree->gtType == TYP_INT && tree->OperIsSimple())
{
- GenTreePtr op1 = tree->gtOp.gtOp1;
- GenTreePtr op2 = tree->gtOp.gtOp2;
+ GenTreePtr op1 = tree->gtOp.gtOp1;
+ GenTreePtr op2 = tree->gtOp.gtOp2;
if (op1 && (op1->gtFlags & GTF_REG_VAL))
trashRegs &= ~genRegMask(op1->gtRegNum);
if (op2 && (op2->gtFlags & GTF_REG_VAL))
@@ -4941,7 +4824,7 @@ void CodeGen::genStressRegs(GenTreePtr tree)
{
if (compiler->info.compCallUnmanaged)
{
- LclVarDsc * varDsc = &compiler->lvaTable[compiler->info.compLvFrameListRoot];
+ LclVarDsc* varDsc = &compiler->lvaTable[compiler->info.compLvFrameListRoot];
if (varDsc->lvRegister)
trashRegs &= ~genRegMask(varDsc->lvRegNum);
}
@@ -4955,7 +4838,7 @@ void CodeGen::genStressRegs(GenTreePtr tree)
// This is obviously false for ARM, but this function is never called.
for (regNumber reg = REG_INT_FIRST; reg <= REG_INT_LAST; reg = REG_NEXT(reg))
{
- regMaskTP regMask = genRegMask(reg);
+ regMaskTP regMask = genRegMask(reg);
if (regSet.rsRegsModified(regMask & trashRegs))
genSetRegToIcon(reg, 0);
@@ -4964,22 +4847,19 @@ void CodeGen::genStressRegs(GenTreePtr tree)
#endif // DEBUG
-
/*****************************************************************************
*
* Generate code for a GTK_CONST tree
*/
-void CodeGen::genCodeForTreeConst(GenTreePtr tree,
- regMaskTP destReg,
- regMaskTP bestReg)
+void CodeGen::genCodeForTreeConst(GenTreePtr tree, regMaskTP destReg, regMaskTP bestReg)
{
noway_assert(tree->IsCnsIntOrI());
- ssize_t ival = tree->gtIntConCommon.IconValue();
- regMaskTP needReg = destReg;
- regNumber reg;
- bool needReloc = compiler->opts.compReloc && tree->IsIconHandle();
+ ssize_t ival = tree->gtIntConCommon.IconValue();
+ regMaskTP needReg = destReg;
+ regNumber reg;
+ bool needReloc = compiler->opts.compReloc && tree->IsIconHandle();
#if REDUNDANT_LOAD
@@ -5011,14 +4891,14 @@ void CodeGen::genCodeForTreeConst(GenTreePtr tree,
/* Is the constant already in register? If so, use this register */
reg = regTracker.rsIconIsInReg(ival);
- if (reg != REG_NA)
+ if (reg != REG_NA)
goto REG_LOADED;
}
}
#endif // REDUNDANT_LOAD
- reg = regSet.rsPickReg(needReg, bestReg);
+ reg = regSet.rsPickReg(needReg, bestReg);
/* If the constant is a handle, we need a reloc to be applied to it */
@@ -5034,10 +4914,10 @@ void CodeGen::genCodeForTreeConst(GenTreePtr tree,
REG_LOADED:
-#ifdef DEBUG
+#ifdef DEBUG
/* Special case: GT_CNS_INT - Restore the current live set if it was changed */
- if (!genTempLiveChg)
+ if (!genTempLiveChg)
{
VarSetOps::Assign(compiler, compiler->compCurLife, genTempOldLife);
genTempLiveChg = true;
@@ -5048,216 +4928,214 @@ REG_LOADED:
genCodeForTree_DONE(tree, reg);
}
-
/*****************************************************************************
*
* Generate code for a GTK_LEAF tree
*/
-void CodeGen::genCodeForTreeLeaf(GenTreePtr tree,
- regMaskTP destReg,
- regMaskTP bestReg)
+void CodeGen::genCodeForTreeLeaf(GenTreePtr tree, regMaskTP destReg, regMaskTP bestReg)
{
- genTreeOps oper = tree->OperGet();
- regNumber reg = DUMMY_INIT(REG_CORRUPT);
- regMaskTP regs = regSet.rsMaskUsed;
- regMaskTP needReg = destReg;
- size_t size;
+ genTreeOps oper = tree->OperGet();
+ regNumber reg = DUMMY_INIT(REG_CORRUPT);
+ regMaskTP regs = regSet.rsMaskUsed;
+ regMaskTP needReg = destReg;
+ size_t size;
noway_assert(tree->OperKind() & GTK_LEAF);
switch (oper)
{
- case GT_REG_VAR:
- NO_WAY("GT_REG_VAR should have been caught above");
- break;
+ case GT_REG_VAR:
+ NO_WAY("GT_REG_VAR should have been caught above");
+ break;
- case GT_LCL_VAR:
+ case GT_LCL_VAR:
- /* Does the variable live in a register? */
+ /* Does the variable live in a register? */
- if (genMarkLclVar(tree))
- {
- genCodeForTree_REG_VAR1(tree);
- return;
- }
+ if (genMarkLclVar(tree))
+ {
+ genCodeForTree_REG_VAR1(tree);
+ return;
+ }
#if REDUNDANT_LOAD
- /* Is the local variable already in register? */
+ /* Is the local variable already in register? */
- reg = findStkLclInReg(tree->gtLclVarCommon.gtLclNum);
+ reg = findStkLclInReg(tree->gtLclVarCommon.gtLclNum);
- if (reg != REG_NA)
- {
- /* Use the register the variable happens to be in */
- regMaskTP regMask = genRegMask(reg);
+ if (reg != REG_NA)
+ {
+ /* Use the register the variable happens to be in */
+ regMaskTP regMask = genRegMask(reg);
- // If the register that it was in isn't one of the needRegs
- // then try to move it into a needReg register
+ // If the register that it was in isn't one of the needRegs
+ // then try to move it into a needReg register
- if (((regMask & needReg) == 0) && (regSet.rsRegMaskCanGrab() & needReg))
- {
- regNumber rg2 = reg;
- reg = regSet.rsPickReg(needReg, bestReg);
- if (reg != rg2)
+ if (((regMask & needReg) == 0) && (regSet.rsRegMaskCanGrab() & needReg))
{
- regMask = genRegMask(reg);
- inst_RV_RV(INS_mov, reg, rg2, tree->TypeGet());
+ regNumber rg2 = reg;
+ reg = regSet.rsPickReg(needReg, bestReg);
+ if (reg != rg2)
+ {
+ regMask = genRegMask(reg);
+ inst_RV_RV(INS_mov, reg, rg2, tree->TypeGet());
+ }
}
- }
- gcInfo.gcMarkRegPtrVal (reg, tree->TypeGet());
- regTracker.rsTrackRegLclVar(reg, tree->gtLclVarCommon.gtLclNum);
- break;
- }
+ gcInfo.gcMarkRegPtrVal(reg, tree->TypeGet());
+ regTracker.rsTrackRegLclVar(reg, tree->gtLclVarCommon.gtLclNum);
+ break;
+ }
#endif
- goto MEM_LEAF;
+ goto MEM_LEAF;
- case GT_LCL_FLD:
+ case GT_LCL_FLD:
- // We only use GT_LCL_FLD for lvDoNotEnregister vars, so we don't have
- // to worry about it being enregistered.
- noway_assert(compiler->lvaTable[tree->gtLclFld.gtLclNum].lvRegister == 0);
- goto MEM_LEAF;
+ // We only use GT_LCL_FLD for lvDoNotEnregister vars, so we don't have
+ // to worry about it being enregistered.
+ noway_assert(compiler->lvaTable[tree->gtLclFld.gtLclNum].lvRegister == 0);
+ goto MEM_LEAF;
- case GT_CLS_VAR:
+ case GT_CLS_VAR:
- MEM_LEAF:
+ MEM_LEAF:
- /* Pick a register for the value */
+ /* Pick a register for the value */
- reg = regSet.rsPickReg(needReg, bestReg);
+ reg = regSet.rsPickReg(needReg, bestReg);
- /* Load the variable into the register */
+ /* Load the variable into the register */
- size = genTypeSize(tree->gtType);
+ size = genTypeSize(tree->gtType);
- if (size < EA_4BYTE)
- {
- instruction ins = ins_Move_Extend(tree->TypeGet(), (tree->gtFlags & GTF_REG_VAL)!=0);
- inst_RV_TT(ins, reg, tree, 0);
+ if (size < EA_4BYTE)
+ {
+ instruction ins = ins_Move_Extend(tree->TypeGet(), (tree->gtFlags & GTF_REG_VAL) != 0);
+ inst_RV_TT(ins, reg, tree, 0);
- /* We've now "promoted" the tree-node to TYP_INT */
+ /* We've now "promoted" the tree-node to TYP_INT */
- tree->gtType = TYP_INT;
- }
- else
- {
- inst_RV_TT(INS_mov, reg, tree, 0);
- }
+ tree->gtType = TYP_INT;
+ }
+ else
+ {
+ inst_RV_TT(INS_mov, reg, tree, 0);
+ }
- regTracker.rsTrackRegTrash(reg);
+ regTracker.rsTrackRegTrash(reg);
- gcInfo.gcMarkRegPtrVal (reg, tree->TypeGet());
+ gcInfo.gcMarkRegPtrVal(reg, tree->TypeGet());
- switch (oper)
- {
- case GT_CLS_VAR:
- regTracker.rsTrackRegClsVar(reg, tree);
- break;
- case GT_LCL_VAR:
- regTracker.rsTrackRegLclVar(reg, tree->gtLclVarCommon.gtLclNum);
- break;
- case GT_LCL_FLD:
- break;
- default: noway_assert(!"Unexpected oper");
- }
+ switch (oper)
+ {
+ case GT_CLS_VAR:
+ regTracker.rsTrackRegClsVar(reg, tree);
+ break;
+ case GT_LCL_VAR:
+ regTracker.rsTrackRegLclVar(reg, tree->gtLclVarCommon.gtLclNum);
+ break;
+ case GT_LCL_FLD:
+ break;
+ default:
+ noway_assert(!"Unexpected oper");
+ }
#ifdef _TARGET_ARM_
- if (tree->gtFlags & GTF_IND_VOLATILE)
- {
- // Emit a memory barrier instruction after the load
- instGen_MemoryBarrier();
- }
+ if (tree->gtFlags & GTF_IND_VOLATILE)
+ {
+ // Emit a memory barrier instruction after the load
+ instGen_MemoryBarrier();
+ }
#endif
- break;
+ break;
- case GT_NO_OP:
- // The VM does certain things with actual NOP instructions
- // so generate something small that has no effect, but isn't
- // a typical NOP
- if (tree->gtFlags & GTF_NO_OP_NO)
- {
+ case GT_NO_OP:
+ // The VM does certain things with actual NOP instructions
+ // so generate something small that has no effect, but isn't
+ // a typical NOP
+ if (tree->gtFlags & GTF_NO_OP_NO)
+ {
#ifdef _TARGET_XARCH_
- // The VM expects 0x66 0x90 for a 2-byte NOP, not 0x90 0x90
- instGen(INS_nop);
- instGen(INS_nop);
-#elif defined (_TARGET_ARM_)
- // The VM isn't checking yet, when it does, hopefully it will
- // get fooled by the wider variant.
- instGen(INS_nopw);
+ // The VM expects 0x66 0x90 for a 2-byte NOP, not 0x90 0x90
+ instGen(INS_nop);
+ instGen(INS_nop);
+#elif defined(_TARGET_ARM_)
+ // The VM isn't checking yet, when it does, hopefully it will
+ // get fooled by the wider variant.
+ instGen(INS_nopw);
#else
- NYI("Non-nop NO_OP");
-#endif
- }
- else
- {
- instGen(INS_nop);
- }
- reg = REG_STK;
- break;
+ NYI("Non-nop NO_OP");
+#endif
+ }
+ else
+ {
+ instGen(INS_nop);
+ }
+ reg = REG_STK;
+ break;
#if !FEATURE_EH_FUNCLETS
- case GT_END_LFIN:
-
- /* Have to clear the shadowSP of the nesting level which
- encloses the finally */
-
- unsigned finallyNesting;
- finallyNesting = (unsigned)tree->gtVal.gtVal1;
- noway_assert(tree->gtVal.gtVal1 < compiler->compHndBBtabCount); //assert we didn't truncate with the cast above.
- noway_assert(finallyNesting < compiler->compHndBBtabCount);
-
- // The last slot is reserved for ICodeManager::FixContext(ppEndRegion)
- unsigned filterEndOffsetSlotOffs;
- PREFIX_ASSUME(compiler->lvaLclSize(compiler->lvaShadowSPslotsVar) > sizeof(void*)); //below doesn't underflow.
- filterEndOffsetSlotOffs = (unsigned)(compiler->lvaLclSize(compiler->lvaShadowSPslotsVar) - (sizeof(void*)));
-
- unsigned curNestingSlotOffs;
- curNestingSlotOffs = filterEndOffsetSlotOffs - ((finallyNesting + 1) * sizeof(void*));
- instGen_Store_Imm_Into_Lcl(TYP_I_IMPL, EA_PTRSIZE, 0,
- compiler->lvaShadowSPslotsVar, curNestingSlotOffs);
- reg = REG_STK;
- break;
+ case GT_END_LFIN:
+
+ /* Have to clear the shadowSP of the nesting level which
+ encloses the finally */
+
+ unsigned finallyNesting;
+ finallyNesting = (unsigned)tree->gtVal.gtVal1;
+ noway_assert(tree->gtVal.gtVal1 <
+ compiler->compHndBBtabCount); // assert we didn't truncate with the cast above.
+ noway_assert(finallyNesting < compiler->compHndBBtabCount);
+
+ // The last slot is reserved for ICodeManager::FixContext(ppEndRegion)
+ unsigned filterEndOffsetSlotOffs;
+ PREFIX_ASSUME(compiler->lvaLclSize(compiler->lvaShadowSPslotsVar) >
+ sizeof(void*)); // below doesn't underflow.
+ filterEndOffsetSlotOffs = (unsigned)(compiler->lvaLclSize(compiler->lvaShadowSPslotsVar) - (sizeof(void*)));
+
+ unsigned curNestingSlotOffs;
+ curNestingSlotOffs = filterEndOffsetSlotOffs - ((finallyNesting + 1) * sizeof(void*));
+ instGen_Store_Imm_Into_Lcl(TYP_I_IMPL, EA_PTRSIZE, 0, compiler->lvaShadowSPslotsVar, curNestingSlotOffs);
+ reg = REG_STK;
+ break;
#endif // !FEATURE_EH_FUNCLETS
- case GT_CATCH_ARG:
+ case GT_CATCH_ARG:
- noway_assert(compiler->compCurBB->bbCatchTyp && handlerGetsXcptnObj(compiler->compCurBB->bbCatchTyp));
+ noway_assert(compiler->compCurBB->bbCatchTyp && handlerGetsXcptnObj(compiler->compCurBB->bbCatchTyp));
- /* Catch arguments get passed in a register. genCodeForBBlist()
- would have marked it as holding a GC object, but not used. */
+ /* Catch arguments get passed in a register. genCodeForBBlist()
+ would have marked it as holding a GC object, but not used. */
- noway_assert(gcInfo.gcRegGCrefSetCur & RBM_EXCEPTION_OBJECT);
- reg = REG_EXCEPTION_OBJECT;
- break;
+ noway_assert(gcInfo.gcRegGCrefSetCur & RBM_EXCEPTION_OBJECT);
+ reg = REG_EXCEPTION_OBJECT;
+ break;
- case GT_JMP:
- genCodeForTreeLeaf_GT_JMP(tree);
- return;
+ case GT_JMP:
+ genCodeForTreeLeaf_GT_JMP(tree);
+ return;
- case GT_MEMORYBARRIER:
- // Emit the memory barrier instruction
- instGen_MemoryBarrier();
- reg = REG_STK;
- break;
+ case GT_MEMORYBARRIER:
+ // Emit the memory barrier instruction
+ instGen_MemoryBarrier();
+ reg = REG_STK;
+ break;
- default:
+ default:
#ifdef DEBUG
- compiler->gtDispTree(tree);
+ compiler->gtDispTree(tree);
#endif
- noway_assert(!"unexpected leaf");
+ noway_assert(!"unexpected leaf");
}
noway_assert(reg != DUMMY_INIT(REG_CORRUPT));
genCodeForTree_DONE(tree, reg);
}
-
-GenTreePtr CodeGen::genCodeForCommaTree (GenTreePtr tree)
+GenTreePtr CodeGen::genCodeForCommaTree(GenTreePtr tree)
{
while (tree->OperGet() == GT_COMMA)
{
@@ -5275,7 +5153,7 @@ GenTreePtr CodeGen::genCodeForCommaTree (GenTreePtr tree)
* Generate code for the a leaf node of type GT_JMP
*/
-void CodeGen::genCodeForTreeLeaf_GT_JMP(GenTreePtr tree)
+void CodeGen::genCodeForTreeLeaf_GT_JMP(GenTreePtr tree)
{
noway_assert(compiler->compCurBB->bbFlags & BBF_HAS_JMP);
@@ -5283,7 +5161,7 @@ void CodeGen::genCodeForTreeLeaf_GT_JMP(GenTreePtr tree)
if (compiler->compIsProfilerHookNeeded())
{
/* fire the event at the call site */
- unsigned saveStackLvl2 = genStackLevel;
+ unsigned saveStackLvl2 = genStackLevel;
compiler->info.compProfilerCallback = true;
@@ -5293,11 +5171,14 @@ void CodeGen::genCodeForTreeLeaf_GT_JMP(GenTreePtr tree)
//
regMaskTP byrefPushedRegs;
regMaskTP norefPushedRegs;
- regMaskTP pushedArgRegs = genPushRegs(RBM_ARG_REGS & (regSet.rsMaskUsed|regSet.rsMaskVars|regSet.rsMaskLock), &byrefPushedRegs, &norefPushedRegs);
+ regMaskTP pushedArgRegs =
+ genPushRegs(RBM_ARG_REGS & (regSet.rsMaskUsed | regSet.rsMaskVars | regSet.rsMaskLock), &byrefPushedRegs,
+ &norefPushedRegs);
if (compiler->compProfilerMethHndIndirected)
{
- getEmitter()->emitIns_AR_R(INS_push, EA_PTR_DSP_RELOC, REG_NA, REG_NA, (ssize_t)compiler->compProfilerMethHnd);
+ getEmitter()->emitIns_AR_R(INS_push, EA_PTR_DSP_RELOC, REG_NA, REG_NA,
+ (ssize_t)compiler->compProfilerMethHnd);
}
else
{
@@ -5306,8 +5187,8 @@ void CodeGen::genCodeForTreeLeaf_GT_JMP(GenTreePtr tree)
genSinglePush();
genEmitHelperCall(CORINFO_HELP_PROF_FCN_TAILCALL,
- sizeof(int) * 1, // argSize
- EA_UNKNOWN); // retSize
+ sizeof(int) * 1, // argSize
+ EA_UNKNOWN); // retSize
//
// Adjust the number of stack slots used by this managed method if necessary.
@@ -5320,7 +5201,7 @@ void CodeGen::genCodeForTreeLeaf_GT_JMP(GenTreePtr tree)
genPopRegs(pushedArgRegs, byrefPushedRegs, norefPushedRegs);
#elif _TARGET_ARM_
// For GT_JMP nodes we have added r0 as a used register, when under arm profiler, to evaluate GT_JMP node.
- // To emit tailcall callback we need r0 to pass profiler handle. Any free register could be used as call target.
+ // To emit tailcall callback we need r0 to pass profiler handle. Any free register could be used as call target.
regNumber argReg = regSet.rsGrabReg(RBM_PROFILER_JMP_USED);
noway_assert(argReg == REG_PROFILER_JMP_ARG);
regSet.rsLockReg(RBM_PROFILER_JMP_USED);
@@ -5331,18 +5212,18 @@ void CodeGen::genCodeForTreeLeaf_GT_JMP(GenTreePtr tree)
regTracker.rsTrackRegTrash(argReg);
}
else
- {
+ {
instGen_Set_Reg_To_Imm(EA_4BYTE, argReg, (ssize_t)compiler->compProfilerMethHnd);
}
genEmitHelperCall(CORINFO_HELP_PROF_FCN_TAILCALL,
- 0, // argSize
- EA_UNKNOWN); // retSize
+ 0, // argSize
+ EA_UNKNOWN); // retSize
regSet.rsUnlockReg(RBM_PROFILER_JMP_USED);
-#else
+#else
NYI("Pushing the profilerHandle & caller's sp for the profiler callout and locking 'arguments'");
-#endif //_TARGET_X86_
+#endif //_TARGET_X86_
/* Restore the stack level */
genStackLevel = saveStackLvl2;
@@ -5366,18 +5247,16 @@ void CodeGen::genCodeForTreeLeaf_GT_JMP(GenTreePtr tree)
// arguments, which is safe because RegAlloc prevents that by
// not enregistering any RegArgs when a JMP opcode is used.
- if (compiler->info.compArgsCount == 0)
+ if (compiler->info.compArgsCount == 0)
{
return;
}
- unsigned varNum;
- LclVarDsc * varDsc;
+ unsigned varNum;
+ LclVarDsc* varDsc;
// First move any enregistered stack arguments back to the stack
- for (varNum = 0, varDsc = compiler->lvaTable;
- varNum < compiler->info.compArgsCount;
- varNum++ , varDsc++)
+ for (varNum = 0, varDsc = compiler->lvaTable; varNum < compiler->info.compArgsCount; varNum++, varDsc++)
{
noway_assert(varDsc->lvIsParam);
if (varDsc->lvIsRegArg || !varDsc->lvRegister)
@@ -5392,31 +5271,20 @@ void CodeGen::genCodeForTreeLeaf_GT_JMP(GenTreePtr tree)
{
/* long - at least the low half must be enregistered */
- getEmitter()->emitIns_S_R(ins_Store(TYP_INT),
- EA_4BYTE,
- varDsc->lvRegNum,
- varNum,
- 0);
+ getEmitter()->emitIns_S_R(ins_Store(TYP_INT), EA_4BYTE, varDsc->lvRegNum, varNum, 0);
/* Is the upper half also enregistered? */
if (varDsc->lvOtherReg != REG_STK)
{
- getEmitter()->emitIns_S_R(ins_Store(TYP_INT),
- EA_4BYTE,
- varDsc->lvOtherReg,
- varNum,
- sizeof(int));
+ getEmitter()->emitIns_S_R(ins_Store(TYP_INT), EA_4BYTE, varDsc->lvOtherReg, varNum, sizeof(int));
}
}
else
#endif // _TARGET_64BIT_
{
- getEmitter()->emitIns_S_R(ins_Store(varDsc->TypeGet()),
- emitTypeSize(varDsc->TypeGet()),
- varDsc->lvRegNum,
- varNum,
- 0);
+ getEmitter()->emitIns_S_R(ins_Store(varDsc->TypeGet()), emitTypeSize(varDsc->TypeGet()), varDsc->lvRegNum,
+ varNum, 0);
}
}
@@ -5425,13 +5293,11 @@ void CodeGen::genCodeForTreeLeaf_GT_JMP(GenTreePtr tree)
#endif
// Next move any un-enregistered register arguments back to their register
- for (varNum = 0, varDsc = compiler->lvaTable;
- varNum < compiler->info.compArgsCount;
- varNum++ , varDsc++)
+ for (varNum = 0, varDsc = compiler->lvaTable; varNum < compiler->info.compArgsCount; varNum++, varDsc++)
{
/* Is this variable a register arg? */
- if (!varDsc->lvIsRegArg)
+ if (!varDsc->lvIsRegArg)
continue;
/* Register argument */
@@ -5447,20 +5313,13 @@ void CodeGen::genCodeForTreeLeaf_GT_JMP(GenTreePtr tree)
{
/* long - at least the low half must be enregistered */
- getEmitter()->emitIns_R_S(ins_Load(TYP_INT),
- EA_4BYTE,
- varDsc->lvArgReg,
- varNum,
- 0);
+ getEmitter()->emitIns_R_S(ins_Load(TYP_INT), EA_4BYTE, varDsc->lvArgReg, varNum, 0);
regTracker.rsTrackRegTrash(varDsc->lvArgReg);
/* Also assume the upper half also enregistered */
- getEmitter()->emitIns_R_S(ins_Load(TYP_INT),
- EA_4BYTE,
- genRegArgNext(varDsc->lvArgReg),
- varNum,
- sizeof(int));
+ getEmitter()->emitIns_R_S(ins_Load(TYP_INT), EA_4BYTE, genRegArgNext(varDsc->lvArgReg), varNum,
+ sizeof(int));
regTracker.rsTrackRegTrash(genRegArgNext(varDsc->lvArgReg));
#ifdef _TARGET_ARM_
@@ -5471,7 +5330,7 @@ void CodeGen::genCodeForTreeLeaf_GT_JMP(GenTreePtr tree)
else
#endif // _TARGET_64BIT_
#ifdef _TARGET_ARM_
- if (varDsc->lvIsHfaRegArg())
+ if (varDsc->lvIsHfaRegArg())
{
const var_types elemType = varDsc->GetHfaType();
const instruction loadOp = ins_Load(elemType);
@@ -5481,11 +5340,7 @@ void CodeGen::genCodeForTreeLeaf_GT_JMP(GenTreePtr tree)
for (unsigned ofs = 0; ofs < maxSize; ofs += (unsigned)size)
{
- getEmitter()->emitIns_R_S(loadOp,
- size,
- argReg,
- varNum,
- ofs);
+ getEmitter()->emitIns_R_S(loadOp, size, argReg, varNum, ofs);
assert(genIsValidFloatReg(argReg)); // we don't use register tracking for FP
argReg = regNextOfType(argReg, elemType);
}
@@ -5500,11 +5355,7 @@ void CodeGen::genCodeForTreeLeaf_GT_JMP(GenTreePtr tree)
for (unsigned ofs = 0; ofs < maxSize; ofs += (unsigned)size)
{
- getEmitter()->emitIns_R_S(loadOp,
- size,
- argReg,
- varNum,
- ofs);
+ getEmitter()->emitIns_R_S(loadOp, size, argReg, varNum, ofs);
regTracker.rsTrackRegTrash(argReg);
fixedArgsMask |= genRegMask(argReg);
@@ -5515,9 +5366,9 @@ void CodeGen::genCodeForTreeLeaf_GT_JMP(GenTreePtr tree)
else
#endif //_TARGET_ARM_
{
- var_types loadType = varDsc->TypeGet();
- regNumber argReg = varDsc->lvArgReg; // incoming arg register
- bool twoParts = false;
+ var_types loadType = varDsc->TypeGet();
+ regNumber argReg = varDsc->lvArgReg; // incoming arg register
+ bool twoParts = false;
if (compiler->info.compIsVarArgs && isFloatRegType(loadType))
{
@@ -5529,11 +5380,7 @@ void CodeGen::genCodeForTreeLeaf_GT_JMP(GenTreePtr tree)
assert(isValidIntArgReg(argReg));
}
- getEmitter()->emitIns_R_S(ins_Load(loadType),
- emitTypeSize(loadType),
- argReg,
- varNum,
- 0);
+ getEmitter()->emitIns_R_S(ins_Load(loadType), emitTypeSize(loadType), argReg, varNum, 0);
regTracker.rsTrackRegTrash(argReg);
#ifdef _TARGET_ARM_
@@ -5544,11 +5391,7 @@ void CodeGen::genCodeForTreeLeaf_GT_JMP(GenTreePtr tree)
argReg = genRegArgNext(argReg);
assert(isValidIntArgReg(argReg));
- getEmitter()->emitIns_R_S(ins_Load(loadType),
- emitTypeSize(loadType),
- argReg,
- varNum,
- REGSIZE_BYTES);
+ getEmitter()->emitIns_R_S(ins_Load(loadType), emitTypeSize(loadType), argReg, varNum, REGSIZE_BYTES);
regTracker.rsTrackRegTrash(argReg);
#ifdef _TARGET_ARM_
@@ -5587,7 +5430,7 @@ void CodeGen::genCodeForTreeLeaf_GT_JMP(GenTreePtr tree)
// Skip the 'vararg cookie.'
regDeclArgs = REG_NEXT(regDeclArgs);
- // Also add offset for the vararg cookie.
+ // Also add offset for the vararg cookie.
int offset = REGSIZE_BYTES;
// Load all the variable arguments in registers back to their registers.
@@ -5610,12 +5453,11 @@ void CodeGen::genCodeForTreeLeaf_GT_JMP(GenTreePtr tree)
* passed in pCallBackData. If the variable is assigned to, return
* Compiler::WALK_ABORT. Otherwise return Compiler::WALK_CONTINUE.
*/
-Compiler::fgWalkResult CodeGen::fgIsVarAssignedTo(GenTreePtr *pTree, Compiler::fgWalkData *data)
+Compiler::fgWalkResult CodeGen::fgIsVarAssignedTo(GenTreePtr* pTree, Compiler::fgWalkData* data)
{
GenTreePtr tree = *pTree;
- if ((tree->OperIsAssignment()) &&
- (tree->gtOp.gtOp1->OperGet() == GT_LCL_VAR) &&
- (tree->gtOp.gtOp1->gtLclVarCommon.gtLclNum == (unsigned) (size_t)data->pCallbackData))
+ if ((tree->OperIsAssignment()) && (tree->gtOp.gtOp1->OperGet() == GT_LCL_VAR) &&
+ (tree->gtOp.gtOp1->gtLclVarCommon.gtLclNum == (unsigned)(size_t)data->pCallbackData))
{
return Compiler::WALK_ABORT;
}
@@ -5623,11 +5465,10 @@ Compiler::fgWalkResult CodeGen::fgIsVarAssignedTo(GenTreePtr *pTree, Compiler::f
return Compiler::WALK_CONTINUE;
}
-
regNumber CodeGen::genIsEnregisteredIntVariable(GenTreePtr tree)
{
- unsigned varNum;
- LclVarDsc * varDsc;
+ unsigned varNum;
+ LclVarDsc* varDsc;
if (tree->gtOper == GT_LCL_VAR)
{
@@ -5637,7 +5478,7 @@ regNumber CodeGen::genIsEnregisteredIntVariable(GenTreePtr tree)
noway_assert(varNum < compiler->lvaCount);
varDsc = compiler->lvaTable + varNum;
- if (!varDsc->IsFloatRegType() && varDsc->lvRegister)
+ if (!varDsc->IsFloatRegType() && varDsc->lvRegister)
{
return varDsc->lvRegNum;
}
@@ -5647,12 +5488,12 @@ regNumber CodeGen::genIsEnregisteredIntVariable(GenTreePtr tree)
}
// inline
-void CodeGen::unspillLiveness(genLivenessSet * ls)
+void CodeGen::unspillLiveness(genLivenessSet* ls)
{
// Only try to unspill the registers that are missing from the currentLiveRegs
//
- regMaskTP cannotSpillMask = ls->maskVars | ls->gcRefRegs | ls->byRefRegs;
- regMaskTP currentLiveRegs = regSet.rsMaskVars | gcInfo.gcRegGCrefSetCur | gcInfo.gcRegByrefSetCur;
+ regMaskTP cannotSpillMask = ls->maskVars | ls->gcRefRegs | ls->byRefRegs;
+ regMaskTP currentLiveRegs = regSet.rsMaskVars | gcInfo.gcRegGCrefSetCur | gcInfo.gcRegByrefSetCur;
cannotSpillMask &= ~currentLiveRegs;
// Typically this will always be true and we will return
@@ -5667,8 +5508,8 @@ void CodeGen::unspillLiveness(genLivenessSet * ls)
if ((cannotSpillMask & genRegMask(reg)) == 0)
continue;
- RegSet::SpillDsc * spill = regSet.rsSpillDesc[reg];
-
+ RegSet::SpillDsc* spill = regSet.rsSpillDesc[reg];
+
// Was it spilled, if not then skip it.
//
if (!spill)
@@ -5685,23 +5526,21 @@ void CodeGen::unspillLiveness(genLivenessSet * ls)
* Generate code for a qmark colon
*/
-void CodeGen::genCodeForQmark(GenTreePtr tree,
- regMaskTP destReg,
- regMaskTP bestReg)
+void CodeGen::genCodeForQmark(GenTreePtr tree, regMaskTP destReg, regMaskTP bestReg)
{
- GenTreePtr op1 = tree->gtOp.gtOp1;
- GenTreePtr op2 = tree->gtOp.gtOp2;
- regNumber reg;
- regMaskTP regs = regSet.rsMaskUsed;
- regMaskTP needReg = destReg;
+ GenTreePtr op1 = tree->gtOp.gtOp1;
+ GenTreePtr op2 = tree->gtOp.gtOp2;
+ regNumber reg;
+ regMaskTP regs = regSet.rsMaskUsed;
+ regMaskTP needReg = destReg;
noway_assert(compiler->compQmarkUsed);
noway_assert(tree->gtOper == GT_QMARK);
noway_assert(op1->OperIsCompare());
noway_assert(op2->gtOper == GT_COLON);
- GenTreePtr thenNode = op2->AsColon()->ThenNode();
- GenTreePtr elseNode = op2->AsColon()->ElseNode();
+ GenTreePtr thenNode = op2->AsColon()->ThenNode();
+ GenTreePtr elseNode = op2->AsColon()->ElseNode();
/* If elseNode is a Nop node you must reverse the
thenNode and elseNode prior to reaching here!
@@ -5736,12 +5575,12 @@ void CodeGen::genCodeForQmark(GenTreePtr tree,
or the 'lab_done' label
*/
- BasicBlock * lab_true;
- BasicBlock * lab_false;
- BasicBlock * lab_done;
+ BasicBlock* lab_true;
+ BasicBlock* lab_false;
+ BasicBlock* lab_done;
- genLivenessSet entryLiveness;
- genLivenessSet exitLiveness;
+ genLivenessSet entryLiveness;
+ genLivenessSet exitLiveness;
lab_true = genCreateTempLabel();
lab_false = genCreateTempLabel();
@@ -5754,7 +5593,7 @@ void CodeGen::genCodeForQmark(GenTreePtr tree,
#ifdef DEBUG
regMaskTP spillMask = regSet.rsMaskUsedFloat | regSet.rsMaskLockedFloat | regSet.rsMaskRegVarFloat;
- // spillMask should be the whole FP stack
+ // spillMask should be the whole FP stack
noway_assert(compCurFPState.m_uStackSize == genCountBits(spillMask));
#endif
@@ -5778,7 +5617,7 @@ void CodeGen::genCodeForQmark(GenTreePtr tree,
before spilling regSet.rsMaskUsed */
regMaskTP rsAdditionalCandidates = regSet.rsMaskUsed & regSet.rsMaskVars;
- regMaskTP rsAdditional = RBM_NONE;
+ regMaskTP rsAdditional = RBM_NONE;
// For each multi-use of an enregistered variable, we need to determine if
// it can get spilled inside the qmark colon. This can only happen if
@@ -5798,7 +5637,8 @@ void CodeGen::genCodeForQmark(GenTreePtr tree,
{
Compiler::printTreeID(tree);
printf(": Qmark-Colon additional spilling candidates are ");
- dspRegMask(rsAdditionalCandidates); printf("\n");
+ dspRegMask(rsAdditionalCandidates);
+ printf("\n");
}
#endif
@@ -5807,17 +5647,17 @@ void CodeGen::genCodeForQmark(GenTreePtr tree,
VARSET_TP VARSET_INIT(compiler, rsLiveNow, compiler->compCurLife);
VARSET_TP VARSET_INIT_NOCOPY(rsLiveAfter, compiler->fgUpdateLiveSet(compiler->compCurLife,
- compiler->compCurLifeTree,
- tree));
+ compiler->compCurLifeTree, tree));
- VARSET_TP VARSET_INIT_NOCOPY(regVarLiveNow, VarSetOps::Intersection(compiler, compiler->raRegVarsMask, rsLiveNow));
+ VARSET_TP VARSET_INIT_NOCOPY(regVarLiveNow,
+ VarSetOps::Intersection(compiler, compiler->raRegVarsMask, rsLiveNow));
VARSET_ITER_INIT(compiler, iter, regVarLiveNow, varIndex);
while (iter.NextElem(compiler, &varIndex))
{
// Find the variable in compiler->lvaTable
- unsigned varNum = compiler->lvaTrackedToVarNum[varIndex];
- LclVarDsc *varDsc = compiler->lvaTable + varNum;
+ unsigned varNum = compiler->lvaTrackedToVarNum[varIndex];
+ LclVarDsc* varDsc = compiler->lvaTable + varNum;
#if !FEATURE_FP_REGALLOC
if (varDsc->IsFloatRegType())
@@ -5837,7 +5677,7 @@ void CodeGen::genCodeForQmark(GenTreePtr tree,
regBit = genRegMask(varDsc->lvRegNum);
// For longs we may need to spill both regs
- if (isRegPairType(varDsc->lvType) && varDsc->lvOtherReg != REG_STK)
+ if (isRegPairType(varDsc->lvType) && varDsc->lvOtherReg != REG_STK)
regBit |= genRegMask(varDsc->lvOtherReg);
}
@@ -5855,7 +5695,8 @@ void CodeGen::genCodeForQmark(GenTreePtr tree,
if (!(op2->gtFlags & GTF_ASG))
continue;
- if (compiler->fgWalkTreePre(&op2, CodeGen::fgIsVarAssignedTo, (void *)(size_t)varNum) == Compiler::WALK_ABORT)
+ if (compiler->fgWalkTreePre(&op2, CodeGen::fgIsVarAssignedTo, (void*)(size_t)varNum) ==
+ Compiler::WALK_ABORT)
{
// Variable was assigned to, so we need to spill it.
@@ -5865,7 +5706,8 @@ void CodeGen::genCodeForQmark(GenTreePtr tree,
{
Compiler::printTreeID(tree);
printf(": Qmark-Colon candidate ");
- dspRegMask(regBit); printf("\n");
+ dspRegMask(regBit);
+ printf("\n");
printf(" is assigned to inside colon and will be spilled\n");
}
#endif
@@ -5881,7 +5723,8 @@ void CodeGen::genCodeForQmark(GenTreePtr tree,
{
Compiler::printTreeID(tree);
printf(": Qmark-Colon candidate ");
- dspRegMask(regBit); printf("\n");
+ dspRegMask(regBit);
+ printf("\n");
printf(" is alive at end of colon and will be spilled\n");
}
#endif
@@ -5893,10 +5736,10 @@ void CodeGen::genCodeForQmark(GenTreePtr tree,
{
Compiler::printTreeID(tree);
printf(": Qmark-Colon approved additional spilling candidates are ");
- dspRegMask(rsAdditional); printf("\n");
+ dspRegMask(rsAdditional);
+ printf("\n");
}
#endif
-
}
noway_assert((rsAdditionalCandidates | rsAdditional) == rsAdditionalCandidates);
@@ -5904,7 +5747,8 @@ void CodeGen::genCodeForQmark(GenTreePtr tree,
// We only need to spill registers that are modified by the qmark tree, as specified in tree->gtUsedRegs.
// If we ever need to use and spill a register while generating code that is not in tree->gtUsedRegs,
// we will have unbalanced spills and generate bad code.
- regMaskTP rsSpill = ((regSet.rsMaskUsed & ~(regSet.rsMaskVars|regSet.rsMaskResvd)) | rsAdditional) & tree->gtUsedRegs;
+ regMaskTP rsSpill =
+ ((regSet.rsMaskUsed & ~(regSet.rsMaskVars | regSet.rsMaskResvd)) | rsAdditional) & tree->gtUsedRegs;
#ifdef DEBUG
// Under register stress, regSet.rsPickReg() ignores the recommended registers and always picks
@@ -5930,7 +5774,7 @@ void CodeGen::genCodeForQmark(GenTreePtr tree,
// regSet.rsSpillRegs() will assert if we try to spill any enregistered variables.
// So, pretend there aren't any, and spill them anyway. This will only occur
// if rsAdditional is non-empty.
- regMaskTP rsTemp = regSet.rsMaskVars;
+ regMaskTP rsTemp = regSet.rsMaskVars;
regSet.ClearMaskVars();
regSet.rsSpillRegs(rsSpill);
@@ -5944,11 +5788,9 @@ void CodeGen::genCodeForQmark(GenTreePtr tree,
}
}
-
// Generate the conditional jump but without doing any StackFP fixups.
genCondJump(op1, lab_true, lab_false, false);
-
/* Save the current liveness, register status, and GC pointers */
/* This is the liveness information upon entry */
/* to both the then and else parts of the qmark */
@@ -5969,14 +5811,14 @@ void CodeGen::genCodeForQmark(GenTreePtr tree,
#if FEATURE_STACK_FP_X87
// Store fpstate
- QmarkStateStackFP tempFPState;
- bool bHasFPUState = !compCurFPState.IsEmpty();
+ QmarkStateStackFP tempFPState;
+ bool bHasFPUState = !compCurFPState.IsEmpty();
genQMarkBeforeElseStackFP(&tempFPState, tree->gtQmark.gtElseLiveSet, op1->gtNext);
#endif
/* Does the operator yield a value? */
- if (tree->gtType == TYP_VOID)
+ if (tree->gtType == TYP_VOID)
{
/* Generate the code for the else part of the qmark */
@@ -5993,18 +5835,18 @@ void CodeGen::genCodeForQmark(GenTreePtr tree,
/* Is there a 'then' part? */
- if (thenNode->IsNothingNode())
+ if (thenNode->IsNothingNode())
{
#if FEATURE_STACK_FP_X87
if (bHasFPUState)
{
// We had FP state on entry just after the condition, so potentially, the else
// node may have to do transition work.
- lab_done = genCreateTempLabel();
+ lab_done = genCreateTempLabel();
/* Generate jmp lab_done */
- inst_JMP (EJ_jmp, lab_done);
+ inst_JMP(EJ_jmp, lab_done);
/* No 'then' - just generate the 'lab_true' label */
@@ -6024,11 +5866,11 @@ void CodeGen::genCodeForQmark(GenTreePtr tree,
}
else
{
- lab_done = genCreateTempLabel();
+ lab_done = genCreateTempLabel();
/* Generate jmp lab_done */
- inst_JMP (EJ_jmp, lab_done);
+ inst_JMP(EJ_jmp, lab_done);
/* Restore the liveness that we had upon entry of the then part of the qmark */
@@ -6101,13 +5943,13 @@ void CodeGen::genCodeForQmark(GenTreePtr tree,
saveLiveness(&exitLiveness);
/* Generate jmp lab_done */
- lab_done = genCreateTempLabel();
+ lab_done = genCreateTempLabel();
#ifdef DEBUG
// We will use this to assert we don't emit instructions if we decide not to
// do the jmp
unsigned emittedInstructions = getEmitter()->emitInsCount;
- bool bSkippedJump = false;
+ bool bSkippedJump = false;
#endif
// We would like to know here if the else node is really going to generate
// code, as if it isn't, we're generating here a jump to the next instruction.
@@ -6118,7 +5960,7 @@ void CodeGen::genCodeForQmark(GenTreePtr tree,
#if FEATURE_STACK_FP_X87
!bHasFPUState && // If there is no FPU state, we won't need an x87 transition
#endif
- genIsEnregisteredIntVariable(thenNode) == reg)
+ genIsEnregisteredIntVariable(thenNode) == reg)
{
#ifdef DEBUG
// For the moment, fix this easy case (enregistered else node), which
@@ -6129,7 +5971,7 @@ void CodeGen::genCodeForQmark(GenTreePtr tree,
}
else
{
- inst_JMP (EJ_jmp, lab_done);
+ inst_JMP(EJ_jmp, lab_done);
}
/* Restore the liveness that we had upon entry of the else part of the qmark */
@@ -6171,8 +6013,7 @@ void CodeGen::genCodeForQmark(GenTreePtr tree,
#endif
#ifdef DEBUG
- noway_assert(bSkippedJump == false ||
- getEmitter()->emitInsCount == emittedInstructions);
+ noway_assert(bSkippedJump == false || getEmitter()->emitInsCount == emittedInstructions);
#endif
/* Define the "result" label */
@@ -6187,11 +6028,9 @@ void CodeGen::genCodeForQmark(GenTreePtr tree,
genUpdateLife(tree);
genMarkTreeInReg(tree, reg);
-
}
}
-
/*****************************************************************************
*
* Generate code for a qmark colon using the CMOV instruction. It's OK
@@ -6199,19 +6038,17 @@ void CodeGen::genCodeForQmark(GenTreePtr tree,
* genCodeForQmark to implement it using branches).
*/
-bool CodeGen::genCodeForQmarkWithCMOV(GenTreePtr tree,
- regMaskTP destReg,
- regMaskTP bestReg)
+bool CodeGen::genCodeForQmarkWithCMOV(GenTreePtr tree, regMaskTP destReg, regMaskTP bestReg)
{
#ifdef _TARGET_XARCH_
- GenTreePtr cond = tree->gtOp.gtOp1;
- GenTreePtr colon = tree->gtOp.gtOp2;
+ GenTreePtr cond = tree->gtOp.gtOp1;
+ GenTreePtr colon = tree->gtOp.gtOp2;
// Warning: this naming of the local vars is backwards!
- GenTreePtr thenNode = colon->gtOp.gtOp1;
- GenTreePtr elseNode = colon->gtOp.gtOp2;
- GenTreePtr alwaysNode, predicateNode;
- regNumber reg;
- regMaskTP needReg = destReg;
+ GenTreePtr thenNode = colon->gtOp.gtOp1;
+ GenTreePtr elseNode = colon->gtOp.gtOp2;
+ GenTreePtr alwaysNode, predicateNode;
+ regNumber reg;
+ regMaskTP needReg = destReg;
noway_assert(tree->gtOper == GT_QMARK);
noway_assert(cond->OperIsCompare());
@@ -6233,24 +6070,21 @@ bool CodeGen::genCodeForQmarkWithCMOV(GenTreePtr tree,
/* thenNode better be a local or a constant */
- if ((thenNode->OperGet() != GT_CNS_INT) &&
- (thenNode->OperGet() != GT_LCL_VAR))
+ if ((thenNode->OperGet() != GT_CNS_INT) && (thenNode->OperGet() != GT_LCL_VAR))
{
return false;
}
/* elseNode better be a local or a constant or nothing */
- if ((elseNode->OperGet() != GT_CNS_INT) &&
- (elseNode->OperGet() != GT_LCL_VAR))
+ if ((elseNode->OperGet() != GT_CNS_INT) && (elseNode->OperGet() != GT_LCL_VAR))
{
return false;
}
/* can't handle two constants here */
- if ((thenNode->OperGet() == GT_CNS_INT) &&
- (elseNode->OperGet() == GT_CNS_INT))
+ if ((thenNode->OperGet() == GT_CNS_INT) && (elseNode->OperGet() == GT_CNS_INT))
{
return false;
}
@@ -6273,7 +6107,7 @@ bool CodeGen::genCodeForQmarkWithCMOV(GenTreePtr tree,
alwaysNode = elseNode;
predicateNode = thenNode;
- reverseCond = true;
+ reverseCond = true;
}
else
{
@@ -6287,7 +6121,7 @@ bool CodeGen::genCodeForQmarkWithCMOV(GenTreePtr tree,
// the value of the variable in the predicate node).
// This assert is just paranoid (we've already asserted it above)
- assert (predicateNode->OperGet() == GT_LCL_VAR);
+ assert(predicateNode->OperGet() == GT_LCL_VAR);
if ((predicateNode->gtFlags & GTF_VAR_DEATH) != 0)
{
return false;
@@ -6321,7 +6155,7 @@ bool CodeGen::genCodeForQmarkWithCMOV(GenTreePtr tree,
// Record the chosen register
- reg = alwaysNode->gtRegNum;
+ reg = alwaysNode->gtRegNum;
}
regNumber regPredicate = REG_NA;
@@ -6343,28 +6177,9 @@ bool CodeGen::genCodeForQmarkWithCMOV(GenTreePtr tree,
}
#endif
- const static
- instruction EJtoCMOV[] =
- {
- INS_nop,
- INS_nop,
- INS_cmovo,
- INS_cmovno,
- INS_cmovb,
- INS_cmovae,
- INS_cmove,
- INS_cmovne,
- INS_cmovbe,
- INS_cmova,
- INS_cmovs,
- INS_cmovns,
- INS_cmovpe,
- INS_cmovpo,
- INS_cmovl,
- INS_cmovge,
- INS_cmovle,
- INS_cmovg
- };
+ const static instruction EJtoCMOV[] = {INS_nop, INS_nop, INS_cmovo, INS_cmovno, INS_cmovb, INS_cmovae,
+ INS_cmove, INS_cmovne, INS_cmovbe, INS_cmova, INS_cmovs, INS_cmovns,
+ INS_cmovpe, INS_cmovpo, INS_cmovl, INS_cmovge, INS_cmovle, INS_cmovg};
noway_assert((unsigned)jumpKind < (sizeof(EJtoCMOV) / sizeof(EJtoCMOV[0])));
instruction cmov_ins = EJtoCMOV[jumpKind];
@@ -6395,31 +6210,30 @@ bool CodeGen::genCodeForQmarkWithCMOV(GenTreePtr tree,
#endif
}
-
#ifdef _TARGET_XARCH_
-void CodeGen::genCodeForMultEAX(GenTreePtr tree)
+void CodeGen::genCodeForMultEAX(GenTreePtr tree)
{
- GenTreePtr op1 = tree->gtOp.gtOp1;
- GenTreePtr op2 = tree->gtGetOp2();
- bool ovfl = tree->gtOverflow();
- regNumber reg = DUMMY_INIT(REG_CORRUPT);
- regMaskTP addrReg;
+ GenTreePtr op1 = tree->gtOp.gtOp1;
+ GenTreePtr op2 = tree->gtGetOp2();
+ bool ovfl = tree->gtOverflow();
+ regNumber reg = DUMMY_INIT(REG_CORRUPT);
+ regMaskTP addrReg;
noway_assert(tree->OperGet() == GT_MUL);
/* We'll evaluate 'op1' first */
-
+
regMaskTP op1Mask = regSet.rsMustExclude(RBM_EAX, op2->gtRsvdRegs);
-
+
/* Generate the op1 into op1Mask and hold on to it. freeOnly=true */
-
+
genComputeReg(op1, op1Mask, RegSet::ANY_REG, RegSet::KEEP_REG, true);
noway_assert(op1->gtFlags & GTF_REG_VAL);
// If op2 is a constant we need to load the constant into a register
if (op2->OperKind() & GTK_CONST)
{
- genCodeForTree(op2, RBM_EDX); // since EDX is going to be spilled anyway
+ genCodeForTree(op2, RBM_EDX); // since EDX is going to be spilled anyway
noway_assert(op2->gtFlags & GTF_REG_VAL);
regSet.rsMarkRegUsed(op2);
addrReg = genRegMask(op2->gtRegNum);
@@ -6440,17 +6254,16 @@ void CodeGen::genCodeForMultEAX(GenTreePtr tree)
// For 8 bit operations, we need to pick byte addressable registers
- if (ovfl && varTypeIsByte(tree->TypeGet()) &&
- !(genRegMask(reg) & RBM_BYTE_REGS))
+ if (ovfl && varTypeIsByte(tree->TypeGet()) && !(genRegMask(reg) & RBM_BYTE_REGS))
{
- regNumber byteReg = regSet.rsGrabReg(RBM_BYTE_REGS);
+ regNumber byteReg = regSet.rsGrabReg(RBM_BYTE_REGS);
inst_RV_RV(INS_mov, byteReg, reg);
-
+
regTracker.rsTrackRegTrash(byteReg);
- regSet.rsMarkRegFree (genRegMask(reg));
-
- reg = byteReg;
+ regSet.rsMarkRegFree(genRegMask(reg));
+
+ reg = byteReg;
op1->gtRegNum = reg;
regSet.rsMarkRegUsed(op1);
}
@@ -6474,7 +6287,7 @@ void CodeGen::genCodeForMultEAX(GenTreePtr tree)
/* Compute the new value */
noway_assert(op1->gtRegNum == REG_EAX);
-
+
// Make sure Edx is free (unless used by op2 itself)
bool op2Released = false;
@@ -6490,25 +6303,25 @@ void CodeGen::genCodeForMultEAX(GenTreePtr tree)
regSet.rsGrabReg(RBM_EDX);
op2Released = true;
-
+
/* keepReg==RegSet::FREE_REG so that the other multi-used trees
don't get marked as unspilled as well. */
regSet.rsUnspillReg(op2, RBM_EDX, RegSet::FREE_REG);
}
- instruction ins;
+ instruction ins;
if (tree->gtFlags & GTF_UNSIGNED)
ins = INS_mulEAX;
else
ins = INS_imulEAX;
-
+
inst_TT(ins, op2, 0, 0, opSize);
-
+
/* Both EAX and EDX are now trashed */
-
- regTracker.rsTrackRegTrash (REG_EAX);
- regTracker.rsTrackRegTrash (REG_EDX);
+
+ regTracker.rsTrackRegTrash(REG_EAX);
+ regTracker.rsTrackRegTrash(REG_EDX);
/* Free up anything that was tied up by the operand */
@@ -6529,18 +6342,16 @@ void CodeGen::genCodeForMultEAX(GenTreePtr tree)
if (ovfl)
genCheckOverflow(tree);
-
+
genCodeForTree_DONE(tree, reg);
}
#endif // _TARGET_XARCH_
#ifdef _TARGET_ARM_
-void CodeGen::genCodeForMult64(GenTreePtr tree,
- regMaskTP destReg,
- regMaskTP bestReg)
+void CodeGen::genCodeForMult64(GenTreePtr tree, regMaskTP destReg, regMaskTP bestReg)
{
- GenTreePtr op1 = tree->gtOp.gtOp1;
- GenTreePtr op2 = tree->gtGetOp2();
+ GenTreePtr op1 = tree->gtOp.gtOp1;
+ GenTreePtr op2 = tree->gtGetOp2();
noway_assert(tree->OperGet() == GT_MUL);
@@ -6571,7 +6382,7 @@ void CodeGen::genCodeForMult64(GenTreePtr tree,
regHi = regSet.rsPickReg(destReg & ~genRegMask(regLo));
regSet.rsUnlockReg(genRegMask(regLo));
- instruction ins;
+ instruction ins;
if (tree->gtFlags & GTF_UNSIGNED)
ins = INS_umull;
else
@@ -6588,7 +6399,7 @@ void CodeGen::genCodeForMult64(GenTreePtr tree,
// Keep regLo [and regHi] locked while generating code for the gtOverflow() case
//
regSet.rsLockReg(genRegMask(regLo));
-
+
if (tree->gtFlags & GTF_MUL_64RSLT)
regSet.rsLockReg(genRegMask(regHi));
@@ -6614,7 +6425,7 @@ void CodeGen::genCodeForMult64(GenTreePtr tree,
regSet.rsUnlockReg(genRegMask(regHi));
}
- genUpdateLife(tree);
+ genUpdateLife(tree);
if (tree->gtFlags & GTF_MUL_64RSLT)
genMarkTreeInRegPair(tree, gen2regs2pair(regLo, regHi));
@@ -6623,16 +6434,13 @@ void CodeGen::genCodeForMult64(GenTreePtr tree,
}
#endif // _TARGET_ARM_
-
/*****************************************************************************
*
* Generate code for a simple binary arithmetic or logical operator.
* Handles GT_AND, GT_OR, GT_XOR, GT_ADD, GT_SUB, GT_MUL.
*/
-void CodeGen::genCodeForTreeSmpBinArithLogOp(GenTreePtr tree,
- regMaskTP destReg,
- regMaskTP bestReg)
+void CodeGen::genCodeForTreeSmpBinArithLogOp(GenTreePtr tree, regMaskTP destReg, regMaskTP bestReg)
{
instruction ins;
genTreeOps oper = tree->OperGet();
@@ -6648,25 +6456,43 @@ void CodeGen::genCodeForTreeSmpBinArithLogOp(GenTreePtr tree,
bool isArith;
switch (oper)
{
- case GT_AND: ins = INS_AND; isArith = false; break;
- case GT_OR : ins = INS_OR ; isArith = false; break;
- case GT_XOR: ins = INS_XOR; isArith = false; break;
- case GT_ADD: ins = INS_add; isArith = true; break;
- case GT_SUB: ins = INS_sub; isArith = true; break;
- case GT_MUL: ins = INS_MUL; isArith = true; break;
- default:
- unreached();
+ case GT_AND:
+ ins = INS_AND;
+ isArith = false;
+ break;
+ case GT_OR:
+ ins = INS_OR;
+ isArith = false;
+ break;
+ case GT_XOR:
+ ins = INS_XOR;
+ isArith = false;
+ break;
+ case GT_ADD:
+ ins = INS_add;
+ isArith = true;
+ break;
+ case GT_SUB:
+ ins = INS_sub;
+ isArith = true;
+ break;
+ case GT_MUL:
+ ins = INS_MUL;
+ isArith = true;
+ break;
+ default:
+ unreached();
}
#ifdef _TARGET_XARCH_
/* Special case: try to use the 3 operand form "imul reg, op1, icon" */
- if ((oper == GT_MUL) &&
- op2->IsIntCnsFitsInI32() && // op2 is a constant that fits in a sign-extended 32-bit immediate
- !op1->IsCnsIntOrI() && // op1 is not a constant
- (tree->gtFlags & GTF_MUL_64RSLT) == 0 && // tree not marked with MUL_64RSLT
- !varTypeIsByte(treeType) && // No encoding for say "imul al,al,imm"
- !tree->gtOverflow() ) // 3 operand imul doesn't set flags
+ if ((oper == GT_MUL) &&
+ op2->IsIntCnsFitsInI32() && // op2 is a constant that fits in a sign-extended 32-bit immediate
+ !op1->IsCnsIntOrI() && // op1 is not a constant
+ (tree->gtFlags & GTF_MUL_64RSLT) == 0 && // tree not marked with MUL_64RSLT
+ !varTypeIsByte(treeType) && // No encoding for say "imul al,al,imm"
+ !tree->gtOverflow()) // 3 operand imul doesn't set flags
{
/* Make the first operand addressable */
@@ -6674,7 +6500,7 @@ void CodeGen::genCodeForTreeSmpBinArithLogOp(GenTreePtr tree,
/* Grab a register for the target */
- reg = regSet.rsPickReg(needReg, bestReg);
+ reg = regSet.rsPickReg(needReg, bestReg);
#if LEA_AVAILABLE
/* Compute the value into the target: reg=op1*op2_icon */
@@ -6690,7 +6516,8 @@ void CodeGen::genCodeForTreeSmpBinArithLogOp(GenTreePtr tree,
inst_RV_TT(INS_mov, reg, op1, 0, emitActualTypeSize(op1->TypeGet()));
regSrc = reg;
}
- getEmitter()->emitIns_R_ARX(INS_lea, emitActualTypeSize(treeType), reg, regSrc, regSrc, (op2->gtIntCon.gtIconVal & -2), 0);
+ getEmitter()->emitIns_R_ARX(INS_lea, emitActualTypeSize(treeType), reg, regSrc, regSrc,
+ (op2->gtIntCon.gtIconVal & -2), 0);
}
else
#endif // LEA_AVAILABLE
@@ -6724,137 +6551,132 @@ void CodeGen::genCodeForTreeSmpBinArithLogOp(GenTreePtr tree,
/* We record the accurate (small) types in trees only we need to
* check for overflow. Otherwise we record genActualType()
*/
-
+
noway_assert(ovfl || (treeType == genActualType(treeType)));
-
+
#if LEA_AVAILABLE
-
+
/* Can we use an 'lea' to compute the result?
Can't use 'lea' for overflow as it doesn't set flags
Can't use 'lea' unless we have at least two free registers */
{
- bool bEnoughRegs = genRegCountForLiveIntEnregVars(tree) + // Live intreg variables
- genCountBits(regSet.rsMaskLock) + // Locked registers
- 2 // We will need two regisers
- <= genCountBits(RBM_ALLINT & ~(doubleAlignOrFramePointerUsed() ? RBM_FPBASE : 0));
-
+ bool bEnoughRegs = genRegCountForLiveIntEnregVars(tree) + // Live intreg variables
+ genCountBits(regSet.rsMaskLock) + // Locked registers
+ 2 // We will need two regisers
+ <= genCountBits(RBM_ALLINT & ~(doubleAlignOrFramePointerUsed() ? RBM_FPBASE : 0));
+
regMaskTP regs = RBM_NONE; // OUT argument
- if (!ovfl &&
- bEnoughRegs &&
- genMakeIndAddrMode(tree, NULL, true, needReg, RegSet::FREE_REG, &regs, false))
+ if (!ovfl && bEnoughRegs && genMakeIndAddrMode(tree, NULL, true, needReg, RegSet::FREE_REG, &regs, false))
{
emitAttr size;
-
+
/* Is the value now computed in some register? */
-
- if (tree->gtFlags & GTF_REG_VAL)
+
+ if (tree->gtFlags & GTF_REG_VAL)
{
genCodeForTree_REG_VAR1(tree);
return;
}
-
+
/* If we can reuse op1/2's register directly, and 'tree' is
a simple expression (ie. not in scaled index form),
might as well just use "add" instead of "lea" */
-
+
// However, if we're in a context where we want to evaluate "tree" into a specific
// register different from the reg we'd use in this optimization, then it doesn't
// make sense to do the "add", since we'd also have to do a "mov."
- if (op1->gtFlags & GTF_REG_VAL)
+ if (op1->gtFlags & GTF_REG_VAL)
{
reg = op1->gtRegNum;
-
- if ((genRegMask(reg) & regSet.rsRegMaskFree()) &&
- (genRegMask(reg) & needReg))
+
+ if ((genRegMask(reg) & regSet.rsRegMaskFree()) && (genRegMask(reg) & needReg))
{
if (op2->gtFlags & GTF_REG_VAL)
{
/* Simply add op2 to the register */
-
+
inst_RV_TT(INS_add, reg, op2, 0, emitTypeSize(treeType), flags);
-
- if (tree->gtSetFlags())
+
+ if (tree->gtSetFlags())
genFlagsEqualToReg(tree, reg);
-
+
goto DONE_LEA_ADD;
}
else if (op2->OperGet() == GT_CNS_INT)
{
/* Simply add op2 to the register */
-
+
genIncRegBy(reg, op2->gtIntCon.gtIconVal, tree, treeType);
-
+
goto DONE_LEA_ADD;
}
}
}
-
- if (op2->gtFlags & GTF_REG_VAL)
+
+ if (op2->gtFlags & GTF_REG_VAL)
{
reg = op2->gtRegNum;
-
- if ((genRegMask(reg) & regSet.rsRegMaskFree()) &&
- (genRegMask(reg) & needReg))
+
+ if ((genRegMask(reg) & regSet.rsRegMaskFree()) && (genRegMask(reg) & needReg))
{
if (op1->gtFlags & GTF_REG_VAL)
{
/* Simply add op1 to the register */
-
+
inst_RV_TT(INS_add, reg, op1, 0, emitTypeSize(treeType), flags);
-
- if (tree->gtSetFlags())
+
+ if (tree->gtSetFlags())
genFlagsEqualToReg(tree, reg);
-
+
goto DONE_LEA_ADD;
}
}
}
-
+
// The expression either requires a scaled-index form, or the
// op1 or op2's register can't be targeted, this can be
// caused when op1 or op2 are enregistered variables.
-
- reg = regSet.rsPickReg(needReg, bestReg);
+
+ reg = regSet.rsPickReg(needReg, bestReg);
size = emitActualTypeSize(treeType);
-
+
/* Generate "lea reg, [addr-mode]" */
-
+
inst_RV_AT(INS_lea, size, treeType, reg, tree, 0, flags);
-
+
#ifndef _TARGET_XARCH_
// Don't call genFlagsEqualToReg on x86/x64
// as it does not set the flags
- if (tree->gtSetFlags())
+ if (tree->gtSetFlags())
genFlagsEqualToReg(tree, reg);
#endif
-
-DONE_LEA_ADD:
+
+ DONE_LEA_ADD:
/* The register has been trashed now */
regTracker.rsTrackRegTrash(reg);
-
+
genDoneAddressable(tree, regs, RegSet::FREE_REG);
-
+
/* The following could be an 'inner' pointer!!! */
-
+
noway_assert(treeType == TYP_BYREF || !varTypeIsGC(treeType));
-
+
if (treeType == TYP_BYREF)
{
genUpdateLife(tree);
-
+
gcInfo.gcMarkRegSetNpt(genRegMask(reg)); // in case "reg" was a TYP_GCREF before
gcInfo.gcMarkRegPtrVal(reg, TYP_BYREF);
}
-
+
genCodeForTree_DONE(tree, reg);
return;
}
}
-
+
#endif // LEA_AVAILABLE
-
- noway_assert((varTypeIsGC(treeType) == false) ||
- (treeType == TYP_BYREF && (ins == INS_add || ins == INS_sub)));
+
+ noway_assert((varTypeIsGC(treeType) == false) || (treeType == TYP_BYREF && (ins == INS_add || ins == INS_sub)));
}
/* The following makes an assumption about gtSetEvalOrder(this) */
@@ -6863,7 +6685,7 @@ DONE_LEA_ADD:
/* Compute a useful register mask */
needReg = regSet.rsMustExclude(needReg, op2->gtRsvdRegs);
- needReg = regSet.rsNarrowHint (needReg, regSet.rsRegMaskFree());
+ needReg = regSet.rsNarrowHint(needReg, regSet.rsRegMaskFree());
// Determine what registers go live between op1 and op2
// Don't bother checking if op1 is already in a register.
@@ -6876,7 +6698,7 @@ DONE_LEA_ADD:
regMaskTP newLiveMask = genNewLiveRegMask(op1, op2);
if (newLiveMask)
{
- needReg = regSet.rsNarrowHint (needReg, ~newLiveMask);
+ needReg = regSet.rsNarrowHint(needReg, ~newLiveMask);
}
}
@@ -6891,30 +6713,30 @@ DONE_LEA_ADD:
/* Special case: small_val & small_mask */
- if ( varTypeIsSmall(op1->TypeGet()) &&
- op2->IsCnsIntOrI() &&
- oper == GT_AND)
+ if (varTypeIsSmall(op1->TypeGet()) && op2->IsCnsIntOrI() && oper == GT_AND)
{
- size_t and_val = op2->gtIntCon.gtIconVal;
- size_t andMask;
- var_types typ = op1->TypeGet();
+ size_t and_val = op2->gtIntCon.gtIconVal;
+ size_t andMask;
+ var_types typ = op1->TypeGet();
switch (typ)
{
- case TYP_BOOL:
- case TYP_BYTE:
- case TYP_UBYTE:
- andMask = 0x000000FF;
- break;
- case TYP_SHORT:
- case TYP_CHAR:
- andMask = 0x0000FFFF;
- break;
- default: noway_assert(!"unexpected type"); return;
+ case TYP_BOOL:
+ case TYP_BYTE:
+ case TYP_UBYTE:
+ andMask = 0x000000FF;
+ break;
+ case TYP_SHORT:
+ case TYP_CHAR:
+ andMask = 0x0000FFFF;
+ break;
+ default:
+ noway_assert(!"unexpected type");
+ return;
}
// Is the 'and_val' completely contained within the bits found in 'andMask'
- if ((and_val & ~andMask) == 0)
+ if ((and_val & ~andMask) == 0)
{
// We must use unsigned instructions when loading op1
if (varTypeIsByte(typ))
@@ -6924,7 +6746,7 @@ DONE_LEA_ADD:
else // varTypeIsShort(typ)
{
assert(varTypeIsShort(typ));
- op1->gtType = TYP_CHAR;
+ op1->gtType = TYP_CHAR;
}
/* Generate the first operand into a scratch register */
@@ -6936,16 +6758,15 @@ DONE_LEA_ADD:
regNumber op1Reg = op1->gtRegNum;
- // Did we end up in an acceptable register?
+ // Did we end up in an acceptable register?
// and do we have an acceptable free register available to grab?
//
- if ( ((genRegMask(op1Reg) & needReg) == 0) &&
- ((regSet.rsRegMaskFree() & needReg) != 0) )
+ if (((genRegMask(op1Reg) & needReg) == 0) && ((regSet.rsRegMaskFree() & needReg) != 0))
{
// See if we can pick a register from bestReg
bestReg &= needReg;
- // Grab an acceptable register
+ // Grab an acceptable register
regNumber newReg;
if ((bestReg & regSet.rsRegMaskFree()) != 0)
newReg = regSet.rsGrabReg(bestReg);
@@ -6978,7 +6799,7 @@ DONE_LEA_ADD:
regSet.rsMarkRegUsed(op1);
reg = op1->gtRegNum;
- if (and_val != andMask) // Does the "and" mask only cover some of the bits?
+ if (and_val != andMask) // Does the "and" mask only cover some of the bits?
{
/* "and" the value */
@@ -6987,7 +6808,8 @@ DONE_LEA_ADD:
#ifdef DEBUG
/* Update the live set of register variables */
- if (compiler->opts.varNames) genUpdateLife(tree);
+ if (compiler->opts.varNames)
+ genUpdateLife(tree);
#endif
/* Now we can update the register pointer information */
@@ -7002,7 +6824,7 @@ DONE_LEA_ADD:
#ifdef _TARGET_XARCH_
- // Do we have to use the special "imul" instruction
+ // Do we have to use the special "imul" instruction
// which has eax as the implicit operand ?
//
bool multEAX = false;
@@ -7034,7 +6856,7 @@ DONE_LEA_ADD:
}
}
- if (multEAX)
+ if (multEAX)
{
noway_assert(oper == GT_MUL);
@@ -7056,13 +6878,13 @@ DONE_LEA_ADD:
}
else if (ovfl)
{
- // We always must use the 32x32 => 64 bit multiply
+ // We always must use the 32x32 => 64 bit multiply
// to detect overflow
mult64 = true;
}
}
- if (mult64)
+ if (mult64)
{
noway_assert(oper == GT_MUL);
@@ -7085,7 +6907,7 @@ DONE_LEA_ADD:
/* Compute a useful register mask */
needReg = regSet.rsMustExclude(needReg, op2->gtRsvdRegs);
- needReg = regSet.rsNarrowHint (needReg, regSet.rsRegMaskFree());
+ needReg = regSet.rsNarrowHint(needReg, regSet.rsRegMaskFree());
#if CPU_HAS_BYTE_REGS
/* 8-bit operations can only be done in the byte-regs */
@@ -7093,16 +6915,15 @@ DONE_LEA_ADD:
needReg = regSet.rsNarrowHint(RBM_BYTE_REGS, needReg);
#endif // CPU_HAS_BYTE_REGS
- // Did we end up in an acceptable register?
+ // Did we end up in an acceptable register?
// and do we have an acceptable free register available to grab?
//
- if ( ((genRegMask(op1Reg) & needReg) == 0) &&
- ((regSet.rsRegMaskFree() & needReg) != 0) )
+ if (((genRegMask(op1Reg) & needReg) == 0) && ((regSet.rsRegMaskFree() & needReg) != 0))
{
// See if we can pick a register from bestReg
bestReg &= needReg;
- // Grab an acceptable register
+ // Grab an acceptable register
regNumber newReg;
if ((bestReg & regSet.rsRegMaskFree()) != 0)
newReg = regSet.rsGrabReg(bestReg);
@@ -7139,7 +6960,7 @@ DONE_LEA_ADD:
bool isSmallConst = false;
#ifdef _TARGET_ARM_
- if ((op2->gtOper == GT_CNS_INT) && arm_Valid_Imm_For_Instr(ins, op2->gtIntCon.gtIconVal, INS_FLAGS_DONT_CARE))
+ if ((op2->gtOper == GT_CNS_INT) && arm_Valid_Imm_For_Instr(ins, op2->gtIntCon.gtIconVal, INS_FLAGS_DONT_CARE))
{
isSmallConst = true;
}
@@ -7150,42 +6971,35 @@ DONE_LEA_ADD:
#if CPU_LOAD_STORE_ARCH
genRecoverReg(op1, RBM_ALLINT, RegSet::KEEP_REG);
-#else // !CPU_LOAD_STORE_ARCH
+#else // !CPU_LOAD_STORE_ARCH
/* Is op1 spilled and op2 in a register? */
- if ((op1->gtFlags & GTF_SPILLED) &&
- (op2->gtFlags & GTF_REG_VAL) &&
- (ins != INS_sub) )
+ if ((op1->gtFlags & GTF_SPILLED) && (op2->gtFlags & GTF_REG_VAL) && (ins != INS_sub))
{
- noway_assert(ins == INS_add ||
- ins == INS_MUL ||
- ins == INS_AND ||
- ins == INS_OR ||
- ins == INS_XOR);
+ noway_assert(ins == INS_add || ins == INS_MUL || ins == INS_AND || ins == INS_OR || ins == INS_XOR);
// genMakeRvalueAddressable(GT_LCL_VAR) shouldn't spill anything
noway_assert(op2->gtOper != GT_LCL_VAR ||
varTypeIsSmall(compiler->lvaTable[op2->gtLclVarCommon.gtLclNum].TypeGet()));
- reg = op2->gtRegNum;
+ reg = op2->gtRegNum;
regMaskTP regMask = genRegMask(reg);
/* Is the register holding op2 available? */
- if (regMask & regSet.rsMaskVars)
+ if (regMask & regSet.rsMaskVars)
{
}
else
{
/* Get the temp we spilled into. */
- TempDsc * temp = regSet.rsUnspillInPlace(op1, op1->gtRegNum);
+ TempDsc* temp = regSet.rsUnspillInPlace(op1, op1->gtRegNum);
/* For 8bit operations, we need to make sure that op2 is
in a byte-addressable registers */
- if (varTypeIsByte(treeType) &&
- !(regMask & RBM_BYTE_REGS))
+ if (varTypeIsByte(treeType) && !(regMask & RBM_BYTE_REGS))
{
regNumber byteReg = regSet.rsGrabReg(RBM_BYTE_REGS);
@@ -7196,12 +7010,12 @@ DONE_LEA_ADD:
RBM_BYTE_REGS, and regSet.rsGrabReg() will only spill its args */
noway_assert(op2->gtFlags & GTF_REG_VAL);
- regSet.rsUnlockReg (regMask);
+ regSet.rsUnlockReg(regMask);
regSet.rsMarkRegFree(regMask);
- reg = byteReg;
- regMask = genRegMask(reg);
- op2->gtRegNum = reg;
+ reg = byteReg;
+ regMask = genRegMask(reg);
+ op2->gtRegNum = reg;
regSet.rsMarkRegUsed(op2);
}
@@ -7223,13 +7037,13 @@ DONE_LEA_ADD:
* we can use the flags
*/
- if (tree->gtSetFlags())
+ if (tree->gtSetFlags())
{
genFlagsEqualToReg(tree, reg);
}
/* The result is where the second operand is sitting. Mark result reg as free */
- regSet.rsMarkRegFree(genRegMask(reg)) ;
+ regSet.rsMarkRegFree(genRegMask(reg));
gcInfo.gcMarkRegPtrVal(reg, treeType);
@@ -7248,17 +7062,16 @@ DONE_LEA_ADD:
// For 8 bit operations, we need to pick byte addressable registers
- if (varTypeIsByte(treeType) &&
- !(genRegMask(reg) & RBM_BYTE_REGS))
+ if (varTypeIsByte(treeType) && !(genRegMask(reg) & RBM_BYTE_REGS))
{
- regNumber byteReg = regSet.rsGrabReg(RBM_BYTE_REGS);
+ regNumber byteReg = regSet.rsGrabReg(RBM_BYTE_REGS);
inst_RV_RV(INS_mov, byteReg, reg);
regTracker.rsTrackRegTrash(byteReg);
- regSet.rsMarkRegFree (genRegMask(reg));
+ regSet.rsMarkRegFree(genRegMask(reg));
- reg = byteReg;
+ reg = byteReg;
op1->gtRegNum = reg;
regSet.rsMarkRegUsed(op1);
}
@@ -7283,26 +7096,24 @@ DONE_LEA_ADD:
/* Compute the new value */
- if (isArith &&
- !op2->InReg() &&
- (op2->OperKind() & GTK_CONST)
+ if (isArith && !op2->InReg() && (op2->OperKind() & GTK_CONST)
#if !CPU_HAS_FP_SUPPORT
- && (treeType == TYP_INT || treeType == TYP_I_IMPL)
+ && (treeType == TYP_INT || treeType == TYP_I_IMPL)
#endif
- )
+ )
{
- ssize_t ival = op2->gtIntCon.gtIconVal;
+ ssize_t ival = op2->gtIntCon.gtIconVal;
- if (oper == GT_ADD)
+ if (oper == GT_ADD)
{
genIncRegBy(reg, ival, tree, treeType, ovfl);
}
else if (oper == GT_SUB)
{
- if (ovfl &&
- ((tree->gtFlags & GTF_UNSIGNED) ||
- (ival == ((treeType == TYP_INT) ? INT32_MIN : SSIZE_T_MIN))) // -0x80000000 == 0x80000000. Therefore we can't use -ival.
- )
+ if (ovfl && ((tree->gtFlags & GTF_UNSIGNED) ||
+ (ival == ((treeType == TYP_INT) ? INT32_MIN : SSIZE_T_MIN))) // -0x80000000 == 0x80000000.
+ // Therefore we can't use -ival.
+ )
{
/* For unsigned overflow, we have to use INS_sub to set
the flags correctly */
@@ -7329,12 +7140,12 @@ DONE_LEA_ADD:
{
noway_assert(genRegMask(reg) & RBM_BYTE_REGS);
- regNumber op2reg = op2->gtRegNum;
- regMaskTP op2regMask = genRegMask(op2reg);
+ regNumber op2reg = op2->gtRegNum;
+ regMaskTP op2regMask = genRegMask(op2reg);
if (!(op2regMask & RBM_BYTE_REGS))
{
- regNumber byteReg = regSet.rsGrabReg(RBM_BYTE_REGS);
+ regNumber byteReg = regSet.rsGrabReg(RBM_BYTE_REGS);
inst_RV_RV(INS_mov, byteReg, op2reg);
regTracker.rsTrackRegTrash(byteReg);
@@ -7363,7 +7174,7 @@ DONE_LEA_ADD:
/* 'add'/'sub' set all CC flags, others only ZF+SF */
- if (tree->gtSetFlags())
+ if (tree->gtSetFlags())
genFlagsEqualToReg(tree, reg);
genReleaseReg(op1);
@@ -7380,39 +7191,51 @@ CHK_OVF:
genCodeForTree_DONE(tree, reg);
}
-
/*****************************************************************************
*
* Generate code for a simple binary arithmetic or logical assignment operator: x <op>= y.
* Handles GT_ASG_AND, GT_ASG_OR, GT_ASG_XOR, GT_ASG_ADD, GT_ASG_SUB.
*/
-void CodeGen::genCodeForTreeSmpBinArithLogAsgOp(GenTreePtr tree,
- regMaskTP destReg,
- regMaskTP bestReg)
+void CodeGen::genCodeForTreeSmpBinArithLogAsgOp(GenTreePtr tree, regMaskTP destReg, regMaskTP bestReg)
{
- instruction ins;
- const genTreeOps oper = tree->OperGet();
- const var_types treeType = tree->TypeGet();
- GenTreePtr op1 = tree->gtOp.gtOp1;
- GenTreePtr op2 = tree->gtGetOp2();
- insFlags flags = tree->gtSetFlags() ? INS_FLAGS_SET : INS_FLAGS_DONT_CARE;
- regNumber reg = DUMMY_INIT(REG_CORRUPT);
- regMaskTP needReg = destReg;
- regMaskTP addrReg;
+ instruction ins;
+ const genTreeOps oper = tree->OperGet();
+ const var_types treeType = tree->TypeGet();
+ GenTreePtr op1 = tree->gtOp.gtOp1;
+ GenTreePtr op2 = tree->gtGetOp2();
+ insFlags flags = tree->gtSetFlags() ? INS_FLAGS_SET : INS_FLAGS_DONT_CARE;
+ regNumber reg = DUMMY_INIT(REG_CORRUPT);
+ regMaskTP needReg = destReg;
+ regMaskTP addrReg;
/* Figure out what instruction to generate */
bool isArith;
switch (oper)
{
- case GT_ASG_AND: ins = INS_AND; isArith = false; break;
- case GT_ASG_OR : ins = INS_OR ; isArith = false; break;
- case GT_ASG_XOR: ins = INS_XOR; isArith = false; break;
- case GT_ASG_ADD: ins = INS_add; isArith = true; break;
- case GT_ASG_SUB: ins = INS_sub; isArith = true; break;
- default:
- unreached();
+ case GT_ASG_AND:
+ ins = INS_AND;
+ isArith = false;
+ break;
+ case GT_ASG_OR:
+ ins = INS_OR;
+ isArith = false;
+ break;
+ case GT_ASG_XOR:
+ ins = INS_XOR;
+ isArith = false;
+ break;
+ case GT_ASG_ADD:
+ ins = INS_add;
+ isArith = true;
+ break;
+ case GT_ASG_SUB:
+ ins = INS_sub;
+ isArith = true;
+ break;
+ default:
+ unreached();
}
bool ovfl = false;
@@ -7426,8 +7249,7 @@ void CodeGen::genCodeForTreeSmpBinArithLogAsgOp(GenTreePtr tree,
// We can't use += with overflow if the value cannot be changed
// in case of an overflow-exception which the "+" might cause
noway_assert(!ovfl ||
- ((op1->gtOper == GT_LCL_VAR || op1->gtOper == GT_LCL_FLD) &&
- !compiler->compCurBB->hasTryIndex()));
+ ((op1->gtOper == GT_LCL_VAR || op1->gtOper == GT_LCL_FLD) && !compiler->compCurBB->hasTryIndex()));
/* Do not allow overflow instructions with refs/byrefs */
@@ -7438,122 +7260,126 @@ void CodeGen::genCodeForTreeSmpBinArithLogAsgOp(GenTreePtr tree,
/* Is the second operand a constant? */
- if (op2->IsIntCnsFitsInI32())
+ if (op2->IsIntCnsFitsInI32())
{
- int ival = (int)op2->gtIntCon.gtIconVal;
+ int ival = (int)op2->gtIntCon.gtIconVal;
/* What is the target of the assignment? */
switch (op1->gtOper)
{
- case GT_REG_VAR:
+ case GT_REG_VAR:
-REG_VAR4:
+ REG_VAR4:
- reg = op1->gtRegVar.gtRegNum;
+ reg = op1->gtRegVar.gtRegNum;
- /* No registers are needed for addressing */
+ /* No registers are needed for addressing */
- addrReg = RBM_NONE;
+ addrReg = RBM_NONE;
#if !CPU_LOAD_STORE_ARCH
-INCDEC_REG:
-#endif
- /* We're adding a constant to a register */
-
- if (oper == GT_ASG_ADD)
- genIncRegBy(reg, ival, tree, treeType, ovfl);
- else if (ovfl &&
- ((tree->gtFlags & GTF_UNSIGNED) || ival == ((treeType == TYP_INT) ? INT32_MIN : SSIZE_T_MIN)) // -0x80000000 == 0x80000000. Therefore we can't use -ival.
- )
- /* For unsigned overflow, we have to use INS_sub to set
- the flags correctly */
- genDecRegBy(reg, ival, tree);
- else
- genIncRegBy(reg, -ival, tree, treeType, ovfl);
+ INCDEC_REG:
+#endif
+ /* We're adding a constant to a register */
+
+ if (oper == GT_ASG_ADD)
+ genIncRegBy(reg, ival, tree, treeType, ovfl);
+ else if (ovfl && ((tree->gtFlags & GTF_UNSIGNED) ||
+ ival == ((treeType == TYP_INT) ? INT32_MIN : SSIZE_T_MIN)) // -0x80000000 ==
+ // 0x80000000.
+ // Therefore we can't
+ // use -ival.
+ )
+ /* For unsigned overflow, we have to use INS_sub to set
+ the flags correctly */
+ genDecRegBy(reg, ival, tree);
+ else
+ genIncRegBy(reg, -ival, tree, treeType, ovfl);
- break;
+ break;
- case GT_LCL_VAR:
+ case GT_LCL_VAR:
- /* Does the variable live in a register? */
+ /* Does the variable live in a register? */
- if (genMarkLclVar(op1))
- goto REG_VAR4;
+ if (genMarkLclVar(op1))
+ goto REG_VAR4;
- __fallthrough;
+ __fallthrough;
- default:
+ default:
- /* Make the target addressable for load/store */
- addrReg = genMakeAddressable2(op1, needReg, RegSet::KEEP_REG, true, true);
+ /* Make the target addressable for load/store */
+ addrReg = genMakeAddressable2(op1, needReg, RegSet::KEEP_REG, true, true);
- #if !CPU_LOAD_STORE_ARCH
- // For CPU_LOAD_STORE_ARCH, we always load from memory then store to memory
+#if !CPU_LOAD_STORE_ARCH
+ // For CPU_LOAD_STORE_ARCH, we always load from memory then store to memory
- /* For small types with overflow check, we need to
- sign/zero extend the result, so we need it in a reg */
+ /* For small types with overflow check, we need to
+ sign/zero extend the result, so we need it in a reg */
- if (ovfl && genTypeSize(treeType) < sizeof(int))
- #endif // !CPU_LOAD_STORE_ARCH
- {
- // Load op1 into a reg
+ if (ovfl && genTypeSize(treeType) < sizeof(int))
+#endif // !CPU_LOAD_STORE_ARCH
+ {
+ // Load op1 into a reg
- reg = regSet.rsGrabReg(RBM_ALLINT & ~addrReg);
+ reg = regSet.rsGrabReg(RBM_ALLINT & ~addrReg);
- inst_RV_TT(INS_mov, reg, op1);
+ inst_RV_TT(INS_mov, reg, op1);
- // Issue the add/sub and the overflow check
+ // Issue the add/sub and the overflow check
- inst_RV_IV(ins, reg, ival, emitActualTypeSize(treeType), flags);
- regTracker.rsTrackRegTrash(reg);
+ inst_RV_IV(ins, reg, ival, emitActualTypeSize(treeType), flags);
+ regTracker.rsTrackRegTrash(reg);
- if (ovfl)
- {
- genCheckOverflow(tree);
- }
+ if (ovfl)
+ {
+ genCheckOverflow(tree);
+ }
- /* Store the (sign/zero extended) result back to
- the stack location of the variable */
+ /* Store the (sign/zero extended) result back to
+ the stack location of the variable */
- inst_TT_RV(ins_Store(op1->TypeGet()), op1, reg);
+ inst_TT_RV(ins_Store(op1->TypeGet()), op1, reg);
- break;
- }
+ break;
+ }
#if !CPU_LOAD_STORE_ARCH
- else
- {
- /* Add/subtract the new value into/from the target */
-
- if (op1->gtFlags & GTF_REG_VAL)
+ else
{
- reg = op1->gtRegNum;
- goto INCDEC_REG;
- }
+ /* Add/subtract the new value into/from the target */
- /* Special case: inc/dec (up to P3, or for small code, or blended code outside loops) */
- if (!ovfl && (ival == 1 || ival == -1) && !compiler->optAvoidIncDec(compiler->compCurBB->getBBWeight(compiler)))
- {
- noway_assert(oper == GT_ASG_SUB || oper == GT_ASG_ADD);
- if (oper == GT_ASG_SUB)
- ival = -ival;
+ if (op1->gtFlags & GTF_REG_VAL)
+ {
+ reg = op1->gtRegNum;
+ goto INCDEC_REG;
+ }
- ins = (ival > 0) ? INS_inc : INS_dec;
- inst_TT(ins, op1);
- }
- else
- {
- inst_TT_IV(ins, op1, ival);
- }
+ /* Special case: inc/dec (up to P3, or for small code, or blended code outside loops) */
+ if (!ovfl && (ival == 1 || ival == -1) &&
+ !compiler->optAvoidIncDec(compiler->compCurBB->getBBWeight(compiler)))
+ {
+ noway_assert(oper == GT_ASG_SUB || oper == GT_ASG_ADD);
+ if (oper == GT_ASG_SUB)
+ ival = -ival;
- if ((op1->gtOper == GT_LCL_VAR) && (!ovfl || treeType == TYP_INT))
- {
- if (tree->gtSetFlags())
- genFlagsEqualToVar(tree, op1->gtLclVarCommon.gtLclNum);
- }
+ ins = (ival > 0) ? INS_inc : INS_dec;
+ inst_TT(ins, op1);
+ }
+ else
+ {
+ inst_TT_IV(ins, op1, ival);
+ }
- break;
- }
-#endif // !CPU_LOAD_STORE_ARCH
+ if ((op1->gtOper == GT_LCL_VAR) && (!ovfl || treeType == TYP_INT))
+ {
+ if (tree->gtSetFlags())
+ genFlagsEqualToVar(tree, op1->gtLclVarCommon.gtLclNum);
+ }
+
+ break;
+ }
+#endif // !CPU_LOAD_STORE_ARCH
} // end switch (op1->gtOper)
genDoneAddressable(op1, addrReg, RegSet::KEEP_REG);
@@ -7561,7 +7387,7 @@ INCDEC_REG:
genCodeForTreeSmpOpAsg_DONE_ASSG(tree, addrReg, reg, ovfl);
return;
} // end if (op2->IsIntCnsFitsInI32())
- } // end if (isArith)
+ } // end if (isArith)
noway_assert(!varTypeIsGC(treeType) || ins == INS_sub || ins == INS_add);
@@ -7569,149 +7395,146 @@ INCDEC_REG:
switch (op1->gtOper)
{
- case GT_LCL_VAR:
+ case GT_LCL_VAR:
- /* Does the target variable live in a register? */
+ /* Does the target variable live in a register? */
- if (!genMarkLclVar(op1))
- break;
+ if (!genMarkLclVar(op1))
+ break;
- __fallthrough;
+ __fallthrough;
- case GT_REG_VAR:
+ case GT_REG_VAR:
- /* Get hold of the target register */
+ /* Get hold of the target register */
- reg = op1->gtRegVar.gtRegNum;
+ reg = op1->gtRegVar.gtRegNum;
- /* Make sure the target of the store is available */
+ /* Make sure the target of the store is available */
- if (regSet.rsMaskUsed & genRegMask(reg))
- {
- regSet.rsSpillReg(reg);
- }
+ if (regSet.rsMaskUsed & genRegMask(reg))
+ {
+ regSet.rsSpillReg(reg);
+ }
- /* Make the RHS addressable */
+ /* Make the RHS addressable */
- addrReg = genMakeRvalueAddressable(op2, 0, RegSet::KEEP_REG, false);
+ addrReg = genMakeRvalueAddressable(op2, 0, RegSet::KEEP_REG, false);
- /* Compute the new value into the target register */
- CLANG_FORMAT_COMMENT_ANCHOR;
+ /* Compute the new value into the target register */
+ CLANG_FORMAT_COMMENT_ANCHOR;
#if CPU_HAS_BYTE_REGS
- // Fix 383833 X86 ILGEN
- regNumber reg2;
- if ((op2->gtFlags & GTF_REG_VAL) != 0)
- {
- reg2 = op2->gtRegNum;
- }
- else
- {
- reg2 = REG_STK;
- }
-
- // We can only generate a byte ADD,SUB,OR,AND operation when reg and reg2 are both BYTE registers
- // when op2 is in memory then reg2==REG_STK and we will need to force op2 into a register
- //
- if (varTypeIsByte(treeType) &&
- (((genRegMask(reg) & RBM_BYTE_REGS) == 0) || ((genRegMask(reg2) & RBM_BYTE_REGS) == 0)))
- {
- // We will force op2 into a register (via sign/zero extending load)
- // for the cases where op2 is in memory and thus could have
- // an unmapped page just beyond its location
- //
- if ((op2->OperIsIndir() || (op2->gtOper == GT_CLS_VAR)) && varTypeIsSmall(op2->TypeGet()))
+ // Fix 383833 X86 ILGEN
+ regNumber reg2;
+ if ((op2->gtFlags & GTF_REG_VAL) != 0)
{
- genCodeForTree(op2, 0);
- assert((op2->gtFlags & GTF_REG_VAL) != 0);
+ reg2 = op2->gtRegNum;
+ }
+ else
+ {
+ reg2 = REG_STK;
}
- inst_RV_TT(ins, reg, op2, 0, EA_4BYTE, flags);
-
- bool canOmit = false;
-
- if (varTypeIsUnsigned(treeType))
+ // We can only generate a byte ADD,SUB,OR,AND operation when reg and reg2 are both BYTE registers
+ // when op2 is in memory then reg2==REG_STK and we will need to force op2 into a register
+ //
+ if (varTypeIsByte(treeType) &&
+ (((genRegMask(reg) & RBM_BYTE_REGS) == 0) || ((genRegMask(reg2) & RBM_BYTE_REGS) == 0)))
{
- // When op2 is a byte sized constant we can omit the zero extend instruction
- if ((op2->gtOper == GT_CNS_INT) &&
- ((op2->gtIntCon.gtIconVal & 0xFF) == op2->gtIntCon.gtIconVal))
+ // We will force op2 into a register (via sign/zero extending load)
+ // for the cases where op2 is in memory and thus could have
+ // an unmapped page just beyond its location
+ //
+ if ((op2->OperIsIndir() || (op2->gtOper == GT_CLS_VAR)) && varTypeIsSmall(op2->TypeGet()))
{
- canOmit = true;
+ genCodeForTree(op2, 0);
+ assert((op2->gtFlags & GTF_REG_VAL) != 0);
}
- }
- else // treeType is signed
- {
- // When op2 is a positive 7-bit or smaller constant
- // we can omit the sign extension sequence.
- if ((op2->gtOper == GT_CNS_INT) &&
- ((op2->gtIntCon.gtIconVal & 0x7F) == op2->gtIntCon.gtIconVal))
+
+ inst_RV_TT(ins, reg, op2, 0, EA_4BYTE, flags);
+
+ bool canOmit = false;
+
+ if (varTypeIsUnsigned(treeType))
{
- canOmit = true;
+ // When op2 is a byte sized constant we can omit the zero extend instruction
+ if ((op2->gtOper == GT_CNS_INT) && ((op2->gtIntCon.gtIconVal & 0xFF) == op2->gtIntCon.gtIconVal))
+ {
+ canOmit = true;
+ }
}
- }
-
- if (!canOmit)
- {
- // If reg is a byte reg then we can use a movzx/movsx instruction
- //
- if ((genRegMask(reg) & RBM_BYTE_REGS) != 0)
+ else // treeType is signed
{
- instruction extendIns = ins_Move_Extend(treeType, true);
- inst_RV_RV(extendIns, reg, reg, treeType, emitTypeSize(treeType));
+ // When op2 is a positive 7-bit or smaller constant
+ // we can omit the sign extension sequence.
+ if ((op2->gtOper == GT_CNS_INT) && ((op2->gtIntCon.gtIconVal & 0x7F) == op2->gtIntCon.gtIconVal))
+ {
+ canOmit = true;
+ }
}
- else // we can't encode a movzx/movsx instruction
+
+ if (!canOmit)
{
- if (varTypeIsUnsigned(treeType))
+ // If reg is a byte reg then we can use a movzx/movsx instruction
+ //
+ if ((genRegMask(reg) & RBM_BYTE_REGS) != 0)
{
- // otherwise, we must zero the upper 24 bits of 'reg'
- inst_RV_IV(INS_AND, reg, 0xFF, EA_4BYTE);
+ instruction extendIns = ins_Move_Extend(treeType, true);
+ inst_RV_RV(extendIns, reg, reg, treeType, emitTypeSize(treeType));
}
- else // treeType is signed
+ else // we can't encode a movzx/movsx instruction
{
- // otherwise, we must sign extend the result in the non-byteable register 'reg'
- // We will shift the register left 24 bits, thus putting the sign-bit into the high bit
- // then we do an arithmetic shift back 24 bits which propagate the sign bit correctly.
- //
- inst_RV_SH(INS_SHIFT_LEFT_LOGICAL, EA_4BYTE, reg, 24);
- inst_RV_SH(INS_SHIFT_RIGHT_ARITHM, EA_4BYTE, reg, 24);
+ if (varTypeIsUnsigned(treeType))
+ {
+ // otherwise, we must zero the upper 24 bits of 'reg'
+ inst_RV_IV(INS_AND, reg, 0xFF, EA_4BYTE);
+ }
+ else // treeType is signed
+ {
+ // otherwise, we must sign extend the result in the non-byteable register 'reg'
+ // We will shift the register left 24 bits, thus putting the sign-bit into the high bit
+ // then we do an arithmetic shift back 24 bits which propagate the sign bit correctly.
+ //
+ inst_RV_SH(INS_SHIFT_LEFT_LOGICAL, EA_4BYTE, reg, 24);
+ inst_RV_SH(INS_SHIFT_RIGHT_ARITHM, EA_4BYTE, reg, 24);
+ }
}
}
}
- }
- else
+ else
#endif // CPU_HAS_BYTE_REGS
- {
- inst_RV_TT(ins, reg, op2, 0, emitTypeSize(treeType), flags);
- }
+ {
+ inst_RV_TT(ins, reg, op2, 0, emitTypeSize(treeType), flags);
+ }
- /* The zero flag is now equal to the register value */
+ /* The zero flag is now equal to the register value */
- if (tree->gtSetFlags())
- genFlagsEqualToReg(tree, reg);
+ if (tree->gtSetFlags())
+ genFlagsEqualToReg(tree, reg);
- /* Remember that we trashed the target */
+ /* Remember that we trashed the target */
- regTracker.rsTrackRegTrash(reg);
+ regTracker.rsTrackRegTrash(reg);
- /* Free up anything that was tied up by the RHS */
+ /* Free up anything that was tied up by the RHS */
- genDoneAddressable(op2, addrReg, RegSet::KEEP_REG);
+ genDoneAddressable(op2, addrReg, RegSet::KEEP_REG);
- genCodeForTreeSmpOpAsg_DONE_ASSG(tree, addrReg, reg, ovfl);
- return;
+ genCodeForTreeSmpOpAsg_DONE_ASSG(tree, addrReg, reg, ovfl);
+ return;
- default:
- break;
+ default:
+ break;
} // end switch (op1->gtOper)
#if !CPU_LOAD_STORE_ARCH
/* Special case: "x ^= -1" is actually "not(x)" */
- if (oper == GT_ASG_XOR)
+ if (oper == GT_ASG_XOR)
{
- if (op2->gtOper == GT_CNS_INT &&
- op2->gtIntCon.gtIconVal == -1)
+ if (op2->gtOper == GT_CNS_INT && op2->gtIntCon.gtIconVal == -1)
{
addrReg = genMakeAddressable(op1, RBM_ALLINT, RegSet::KEEP_REG, true);
inst_TT(INS_NOT, op1);
@@ -7726,14 +7549,13 @@ INCDEC_REG:
/* Setup target mask for op2 (byte-regs for small operands) */
unsigned needMask;
- needMask = (varTypeIsByte(treeType)) ? RBM_BYTE_REGS
- : RBM_ALLINT;
+ needMask = (varTypeIsByte(treeType)) ? RBM_BYTE_REGS : RBM_ALLINT;
/* Is the second operand a constant? */
- if (op2->IsIntCnsFitsInI32())
+ if (op2->IsIntCnsFitsInI32())
{
- int ival = (int)op2->gtIntCon.gtIconVal;
+ int ival = (int)op2->gtIntCon.gtIconVal;
/* Make the target addressable */
addrReg = genMakeAddressable(op1, needReg, RegSet::FREE_REG, true);
@@ -7748,7 +7570,7 @@ INCDEC_REG:
/* Is the value or the address to be computed first? */
- if (tree->gtFlags & GTF_REVERSE_OPS)
+ if (tree->gtFlags & GTF_REVERSE_OPS)
{
/* Compute the new value into a register */
@@ -7815,7 +7637,7 @@ INCDEC_REG:
/* Free up anything that was tied up either side */
regSet.rsUnlockUsedReg(addrReg);
genDoneAddressable(op1, addrReg, RegSet::KEEP_REG);
- genReleaseReg (op2);
+ genReleaseReg(op2);
}
else
{
@@ -7834,8 +7656,8 @@ INCDEC_REG:
regSet.rsLockUsedReg(addrReg);
#if !CPU_LOAD_STORE_ARCH
- // For CPU_LOAD_STORE_ARCH, we always load from memory then store to memory
-
+ // For CPU_LOAD_STORE_ARCH, we always load from memory then store to memory
+
/* For small types with overflow check, we need to
sign/zero extend the result, so we need it in a reg */
@@ -7871,21 +7693,18 @@ INCDEC_REG:
genDoneAddressable(op1, addrReg, RegSet::KEEP_REG);
regSet.rsUnlockUsedReg(genRegMask(op2->gtRegNum));
- genReleaseReg (op2);
+ genReleaseReg(op2);
}
genCodeForTreeSmpOpAsg_DONE_ASSG(tree, addrReg, reg, ovfl);
}
-
/*****************************************************************************
*
* Generate code for GT_UMOD.
*/
-void CodeGen::genCodeForUnsignedMod(GenTreePtr tree,
- regMaskTP destReg,
- regMaskTP bestReg)
+void CodeGen::genCodeForUnsignedMod(GenTreePtr tree, regMaskTP destReg, regMaskTP bestReg)
{
assert(tree->OperGet() == GT_UMOD);
@@ -7898,14 +7717,14 @@ void CodeGen::genCodeForUnsignedMod(GenTreePtr tree,
/* Is this a division by an integer constant? */
noway_assert(op2);
- if (compiler->fgIsUnsignedModOptimizable(op2))
+ if (compiler->fgIsUnsignedModOptimizable(op2))
{
/* Generate the operand into some register */
genCompIntoFreeReg(op1, needReg, RegSet::FREE_REG);
noway_assert(op1->gtFlags & GTF_REG_VAL);
- reg = op1->gtRegNum;
+ reg = op1->gtRegNum;
/* Generate the appropriate sequence */
size_t ival = op2->gtIntCon.gtIconVal - 1;
@@ -7922,15 +7741,12 @@ void CodeGen::genCodeForUnsignedMod(GenTreePtr tree,
genCodeForGeneralDivide(tree, destReg, bestReg);
}
-
/*****************************************************************************
*
* Generate code for GT_MOD.
*/
-void CodeGen::genCodeForSignedMod(GenTreePtr tree,
- regMaskTP destReg,
- regMaskTP bestReg)
+void CodeGen::genCodeForSignedMod(GenTreePtr tree, regMaskTP destReg, regMaskTP bestReg)
{
assert(tree->OperGet() == GT_MOD);
@@ -7943,17 +7759,17 @@ void CodeGen::genCodeForSignedMod(GenTreePtr tree,
/* Is this a division by an integer constant? */
noway_assert(op2);
- if (compiler->fgIsSignedModOptimizable(op2))
+ if (compiler->fgIsSignedModOptimizable(op2))
{
- ssize_t ival = op2->gtIntCon.gtIconVal;
- BasicBlock * skip = genCreateTempLabel();
+ ssize_t ival = op2->gtIntCon.gtIconVal;
+ BasicBlock* skip = genCreateTempLabel();
/* Generate the operand into some register */
genCompIntoFreeReg(op1, needReg, RegSet::FREE_REG);
noway_assert(op1->gtFlags & GTF_REG_VAL);
- reg = op1->gtRegNum;
+ reg = op1->gtRegNum;
/* Generate the appropriate sequence */
@@ -7979,9 +7795,9 @@ void CodeGen::genCodeForSignedMod(GenTreePtr tree,
}
else
{
- inst_RV_IV (INS_OR, reg, (int)ival, emitActualTypeSize(treeType));
+ inst_RV_IV(INS_OR, reg, (int)ival, emitActualTypeSize(treeType));
}
- genIncRegBy(reg, 1, NULL, treeType);
+ genIncRegBy(reg, 1, NULL, treeType);
/* Define the 'skip' label and we're done */
@@ -7994,15 +7810,12 @@ void CodeGen::genCodeForSignedMod(GenTreePtr tree,
genCodeForGeneralDivide(tree, destReg, bestReg);
}
-
/*****************************************************************************
*
* Generate code for GT_UDIV.
*/
-void CodeGen::genCodeForUnsignedDiv(GenTreePtr tree,
- regMaskTP destReg,
- regMaskTP bestReg)
+void CodeGen::genCodeForUnsignedDiv(GenTreePtr tree, regMaskTP destReg, regMaskTP bestReg)
{
assert(tree->OperGet() == GT_UDIV);
@@ -8015,9 +7828,9 @@ void CodeGen::genCodeForUnsignedDiv(GenTreePtr tree,
/* Is this a division by an integer constant? */
noway_assert(op2);
- if (compiler->fgIsUnsignedDivOptimizable(op2))
+ if (compiler->fgIsUnsignedDivOptimizable(op2))
{
- size_t ival = op2->gtIntCon.gtIconVal;
+ size_t ival = op2->gtIntCon.gtIconVal;
/* Division by 1 must be handled elsewhere */
@@ -8028,7 +7841,7 @@ void CodeGen::genCodeForUnsignedDiv(GenTreePtr tree,
genCompIntoFreeReg(op1, needReg, RegSet::FREE_REG);
noway_assert(op1->gtFlags & GTF_REG_VAL);
- reg = op1->gtRegNum;
+ reg = op1->gtRegNum;
/* Generate "shr reg, log2(value)" */
@@ -8045,15 +7858,12 @@ void CodeGen::genCodeForUnsignedDiv(GenTreePtr tree,
genCodeForGeneralDivide(tree, destReg, bestReg);
}
-
/*****************************************************************************
*
* Generate code for GT_DIV.
*/
-void CodeGen::genCodeForSignedDiv(GenTreePtr tree,
- regMaskTP destReg,
- regMaskTP bestReg)
+void CodeGen::genCodeForSignedDiv(GenTreePtr tree, regMaskTP destReg, regMaskTP bestReg)
{
assert(tree->OperGet() == GT_DIV);
@@ -8066,7 +7876,7 @@ void CodeGen::genCodeForSignedDiv(GenTreePtr tree,
/* Is this a division by an integer constant? */
noway_assert(op2);
- if (compiler->fgIsSignedDivOptimizable(op2))
+ if (compiler->fgIsSignedDivOptimizable(op2))
{
ssize_t ival_s = op2->gtIntConCommon.IconValue();
assert(ival_s > 0); // Postcondition of compiler->fgIsSignedDivOptimizable...
@@ -8076,14 +7886,14 @@ void CodeGen::genCodeForSignedDiv(GenTreePtr tree,
noway_assert(ival != 1);
- BasicBlock * onNegDivisee = genCreateTempLabel();
+ BasicBlock* onNegDivisee = genCreateTempLabel();
/* Generate the operand into some register */
genCompIntoFreeReg(op1, needReg, RegSet::FREE_REG);
noway_assert(op1->gtFlags & GTF_REG_VAL);
- reg = op1->gtRegNum;
+ reg = op1->gtRegNum;
if (ival == 2)
{
@@ -8108,7 +7918,7 @@ void CodeGen::genCodeForSignedDiv(GenTreePtr tree,
/* The result is the same as the operand */
- reg = op1->gtRegNum;
+ reg = op1->gtRegNum;
}
else
{
@@ -8127,7 +7937,7 @@ void CodeGen::genCodeForSignedDiv(GenTreePtr tree,
emitJumpKind jmpGEL = genJumpKindForOper(GT_GE, CK_LOGICAL);
inst_JMP(jmpGEL, onNegDivisee);
- inst_RV_IV(INS_add, reg, (int)ival-1, emitActualTypeSize(treeType));
+ inst_RV_IV(INS_add, reg, (int)ival - 1, emitActualTypeSize(treeType));
/* Define the 'onNegDivisee' label and we're done */
@@ -8143,7 +7953,7 @@ void CodeGen::genCodeForSignedDiv(GenTreePtr tree,
/* The result is the same as the operand */
- reg = op1->gtRegNum;
+ reg = op1->gtRegNum;
}
genCodeForTree_DONE(tree, reg);
@@ -8153,20 +7963,15 @@ void CodeGen::genCodeForSignedDiv(GenTreePtr tree,
genCodeForGeneralDivide(tree, destReg, bestReg);
}
-
/*****************************************************************************
*
* Generate code for a general divide. Handles the general case for GT_UMOD, GT_MOD, GT_UDIV, GT_DIV
* (if op2 is not a power of 2 constant).
*/
-void CodeGen::genCodeForGeneralDivide(GenTreePtr tree,
- regMaskTP destReg,
- regMaskTP bestReg)
+void CodeGen::genCodeForGeneralDivide(GenTreePtr tree, regMaskTP destReg, regMaskTP bestReg)
{
- assert(tree->OperGet() == GT_UMOD ||
- tree->OperGet() == GT_MOD ||
- tree->OperGet() == GT_UDIV ||
+ assert(tree->OperGet() == GT_UMOD || tree->OperGet() == GT_MOD || tree->OperGet() == GT_UDIV ||
tree->OperGet() == GT_DIV);
GenTreePtr op1 = tree->gtOp.gtOp1;
@@ -8186,11 +7991,11 @@ void CodeGen::genCodeForGeneralDivide(GenTreePtr tree,
/* Which operand are we supposed to evaluate first? */
- if (tree->gtFlags & GTF_REVERSE_OPS)
+ if (tree->gtFlags & GTF_REVERSE_OPS)
{
/* We'll evaluate 'op2' first */
- gotOp1 = false;
+ gotOp1 = false;
destReg &= ~op1->gtRsvdRegs;
/* Also if op1 is an enregistered LCL_VAR then exclude its register as well */
@@ -8199,7 +8004,7 @@ void CodeGen::genCodeForGeneralDivide(GenTreePtr tree,
unsigned varNum = op1->gtLclVarCommon.gtLclNum;
noway_assert(varNum < compiler->lvaCount);
LclVarDsc* varDsc = compiler->lvaTable + varNum;
- if (varDsc->lvRegister)
+ if (varDsc->lvRegister)
{
destReg &= ~genRegMask(varDsc->lvRegNum);
}
@@ -8215,7 +8020,7 @@ void CodeGen::genCodeForGeneralDivide(GenTreePtr tree,
if (RBM_EAX & op2->gtRsvdRegs)
op1Mask = RBM_ALLINT & ~op2->gtRsvdRegs;
else
- op1Mask = RBM_EAX; // EAX would be ideal
+ op1Mask = RBM_EAX; // EAX would be ideal
/* Generate the dividend into EAX and hold on to it. freeOnly=true */
@@ -8224,14 +8029,14 @@ void CodeGen::genCodeForGeneralDivide(GenTreePtr tree,
/* We want to avoid using EAX or EDX for the second operand */
- destReg = regSet.rsMustExclude(destReg, RBM_EAX|RBM_EDX);
+ destReg = regSet.rsMustExclude(destReg, RBM_EAX | RBM_EDX);
/* Make the second operand addressable */
op2 = genCodeForCommaTree(op2);
/* Special case: if op2 is a local var we are done */
- if (op2->gtOper == GT_LCL_VAR || op2->gtOper == GT_LCL_FLD)
+ if (op2->gtOper == GT_LCL_VAR || op2->gtOper == GT_LCL_FLD)
{
if ((op2->gtFlags & GTF_REG_VAL) == 0)
addrReg = genMakeRvalueAddressable(op2, destReg, RegSet::KEEP_REG, false);
@@ -8248,7 +8053,7 @@ void CodeGen::genCodeForGeneralDivide(GenTreePtr tree,
/* Make sure we have the dividend in EAX */
- if (gotOp1)
+ if (gotOp1)
{
/* We've previously computed op1 into EAX */
@@ -8285,7 +8090,7 @@ void CodeGen::genCodeForGeneralDivide(GenTreePtr tree,
/* Perform the division */
if (oper == GT_UMOD || oper == GT_UDIV)
- inst_TT(INS_UNSIGNED_DIVIDE, op2);
+ inst_TT(INS_UNSIGNED_DIVIDE, op2);
else
inst_TT(INS_SIGNED_DIVIDE, op2);
@@ -8303,17 +8108,16 @@ void CodeGen::genCodeForGeneralDivide(GenTreePtr tree,
/* Both EAX and EDX are now trashed */
- regTracker.rsTrackRegTrash (REG_EAX);
- regTracker.rsTrackRegTrash (REG_EDX);
+ regTracker.rsTrackRegTrash(REG_EAX);
+ regTracker.rsTrackRegTrash(REG_EDX);
/* Figure out which register the result is in */
- reg = (oper == GT_DIV || oper == GT_UDIV) ? REG_EAX
- : REG_EDX;
+ reg = (oper == GT_DIV || oper == GT_UDIV) ? REG_EAX : REG_EDX;
/* Don't forget to mark the first operand as using EAX and EDX */
- op1->gtRegNum = reg;
+ op1->gtRegNum = reg;
genCodeForTree_DONE(tree, reg);
@@ -8321,11 +8125,11 @@ void CodeGen::genCodeForGeneralDivide(GenTreePtr tree,
/* Which operand are we supposed to evaluate first? */
- if (tree->gtFlags & GTF_REVERSE_OPS)
+ if (tree->gtFlags & GTF_REVERSE_OPS)
{
/* We'll evaluate 'op2' first */
- gotOp1 = false;
+ gotOp1 = false;
destReg &= ~op1->gtRsvdRegs;
/* Also if op1 is an enregistered LCL_VAR then exclude its register as well */
@@ -8334,7 +8138,7 @@ void CodeGen::genCodeForGeneralDivide(GenTreePtr tree,
unsigned varNum = op1->gtLclVarCommon.gtLclNum;
noway_assert(varNum < compiler->lvaCount);
LclVarDsc* varDsc = compiler->lvaTable + varNum;
- if (varDsc->lvRegister)
+ if (varDsc->lvRegister)
{
destReg &= ~genRegMask(varDsc->lvRegNum);
}
@@ -8344,7 +8148,7 @@ void CodeGen::genCodeForGeneralDivide(GenTreePtr tree,
{
/* We'll evaluate 'op1' first */
- gotOp1 = true;
+ gotOp1 = true;
regMaskTP op1Mask = RBM_ALLINT & ~op2->gtRsvdRegs;
/* Generate the dividend into a register and hold on to it. */
@@ -8359,7 +8163,7 @@ void CodeGen::genCodeForGeneralDivide(GenTreePtr tree,
noway_assert(op2->gtFlags & GTF_REG_VAL);
addrReg = genRegMask(op2->gtRegNum);
- if (gotOp1)
+ if (gotOp1)
{
// Recover op1 if spilled
genRecoverReg(op1, RBM_NONE, RegSet::KEEP_REG);
@@ -8383,7 +8187,7 @@ void CodeGen::genCodeForGeneralDivide(GenTreePtr tree,
ins = INS_sdiv;
getEmitter()->emitIns_R_R_R(ins, EA_4BYTE, reg, op1->gtRegNum, op2->gtRegNum);
-
+
if (oper == GT_UMOD || oper == GT_MOD)
{
getEmitter()->emitIns_R_R_R(INS_mul, EA_4BYTE, reg, op2->gtRegNum, reg);
@@ -8400,37 +8204,38 @@ void CodeGen::genCodeForGeneralDivide(GenTreePtr tree,
#endif
}
-
/*****************************************************************************
*
* Generate code for an assignment shift (x <op>= ). Handles GT_ASG_LSH, GT_ASG_RSH, GT_ASG_RSZ.
*/
-void CodeGen::genCodeForAsgShift(GenTreePtr tree,
- regMaskTP destReg,
- regMaskTP bestReg)
+void CodeGen::genCodeForAsgShift(GenTreePtr tree, regMaskTP destReg, regMaskTP bestReg)
{
- assert(tree->OperGet() == GT_ASG_LSH ||
- tree->OperGet() == GT_ASG_RSH ||
- tree->OperGet() == GT_ASG_RSZ);
-
- const genTreeOps oper = tree->OperGet();
- GenTreePtr op1 = tree->gtOp.gtOp1;
- GenTreePtr op2 = tree->gtOp.gtOp2;
- const var_types treeType = tree->TypeGet();
- insFlags flags = tree->gtSetFlags() ? INS_FLAGS_SET : INS_FLAGS_DONT_CARE;
- regMaskTP needReg = destReg;
- regNumber reg;
- instruction ins;
- regMaskTP addrReg;
+ assert(tree->OperGet() == GT_ASG_LSH || tree->OperGet() == GT_ASG_RSH || tree->OperGet() == GT_ASG_RSZ);
+
+ const genTreeOps oper = tree->OperGet();
+ GenTreePtr op1 = tree->gtOp.gtOp1;
+ GenTreePtr op2 = tree->gtOp.gtOp2;
+ const var_types treeType = tree->TypeGet();
+ insFlags flags = tree->gtSetFlags() ? INS_FLAGS_SET : INS_FLAGS_DONT_CARE;
+ regMaskTP needReg = destReg;
+ regNumber reg;
+ instruction ins;
+ regMaskTP addrReg;
switch (oper)
{
- case GT_ASG_LSH: ins = INS_SHIFT_LEFT_LOGICAL; break;
- case GT_ASG_RSH: ins = INS_SHIFT_RIGHT_ARITHM; break;
- case GT_ASG_RSZ: ins = INS_SHIFT_RIGHT_LOGICAL; break;
- default:
- unreached();
+ case GT_ASG_LSH:
+ ins = INS_SHIFT_LEFT_LOGICAL;
+ break;
+ case GT_ASG_RSH:
+ ins = INS_SHIFT_RIGHT_ARITHM;
+ break;
+ case GT_ASG_RSZ:
+ ins = INS_SHIFT_RIGHT_LOGICAL;
+ break;
+ default:
+ unreached();
}
noway_assert(!varTypeIsGC(treeType));
@@ -8438,7 +8243,7 @@ void CodeGen::genCodeForAsgShift(GenTreePtr tree,
/* Shifts by a constant amount are easier */
- if (op2->IsCnsIntOrI())
+ if (op2->IsCnsIntOrI())
{
/* Make the target addressable */
@@ -8446,13 +8251,11 @@ void CodeGen::genCodeForAsgShift(GenTreePtr tree,
/* Are we shifting a register left by 1 bit? */
- if ((oper == GT_ASG_LSH) &&
- (op2->gtIntCon.gtIconVal == 1) &&
- (op1->gtFlags & GTF_REG_VAL))
+ if ((oper == GT_ASG_LSH) && (op2->gtIntCon.gtIconVal == 1) && (op1->gtFlags & GTF_REG_VAL))
{
/* The target lives in a register */
- reg = op1->gtRegNum;
+ reg = op1->gtRegNum;
/* "add reg, reg" is cheaper than "shl reg, 1" */
@@ -8493,7 +8296,7 @@ void CodeGen::genCodeForAsgShift(GenTreePtr tree,
/* If the target is a register, it has a new value */
- if (op1->gtFlags & GTF_REG_VAL)
+ if (op1->gtFlags & GTF_REG_VAL)
regTracker.rsTrackRegTrash(op1->gtRegNum);
genDoneAddressable(op1, addrReg, RegSet::KEEP_REG);
@@ -8509,7 +8312,7 @@ void CodeGen::genCodeForAsgShift(GenTreePtr tree,
{
genFlagsEqualToVar(tree, op1->gtLclVarCommon.gtLclNum);
}
- else if (op1->gtOper == GT_REG_VAR)
+ else if (op1->gtOper == GT_REG_VAR)
{
genFlagsEqualToReg(tree, op1->gtRegNum);
}
@@ -8545,7 +8348,7 @@ void CodeGen::genCodeForAsgShift(GenTreePtr tree,
regSet.rsMarkRegUsed(op2);
tempRegs = regSet.rsMustExclude(RBM_ALLINT, genRegMask(op2->gtRegNum));
- addrReg = genMakeAddressable(op1, tempRegs, RegSet::KEEP_REG, true);
+ addrReg = genMakeAddressable(op1, tempRegs, RegSet::KEEP_REG, true);
genRecoverReg(op2, op2Regs, RegSet::KEEP_REG);
}
@@ -8557,7 +8360,7 @@ void CodeGen::genCodeForAsgShift(GenTreePtr tree,
excludeMask |= RBM_SHIFT;
tempRegs = regSet.rsMustExclude(RBM_ALLINT, excludeMask);
- addrReg = genMakeAddressable(op1, tempRegs, RegSet::KEEP_REG, true);
+ addrReg = genMakeAddressable(op1, tempRegs, RegSet::KEEP_REG, true);
/* Load the shift count into the necessary register */
genComputeReg(op2, op2Regs, RegSet::EXACT_REG, RegSet::KEEP_REG);
@@ -8583,7 +8386,7 @@ void CodeGen::genCodeForAsgShift(GenTreePtr tree,
/* If the value is in a register, it's now trash */
- if (op1->gtFlags & GTF_REG_VAL)
+ if (op1->gtFlags & GTF_REG_VAL)
regTracker.rsTrackRegTrash(op1->gtRegNum);
/* Release the op2 [RBM_SHIFT] operand */
@@ -8594,39 +8397,42 @@ void CodeGen::genCodeForAsgShift(GenTreePtr tree,
genCodeForTreeSmpOpAsg_DONE_ASSG(tree, addrReg, /* unused for ovfl=false */ REG_NA, /* ovfl */ false);
}
-
/*****************************************************************************
*
* Generate code for a shift. Handles GT_LSH, GT_RSH, GT_RSZ.
*/
-void CodeGen::genCodeForShift(GenTreePtr tree,
- regMaskTP destReg,
- regMaskTP bestReg)
+void CodeGen::genCodeForShift(GenTreePtr tree, regMaskTP destReg, regMaskTP bestReg)
{
assert(tree->OperIsShift());
- const genTreeOps oper = tree->OperGet();
- GenTreePtr op1 = tree->gtOp.gtOp1;
- GenTreePtr op2 = tree->gtOp.gtOp2;
- const var_types treeType = tree->TypeGet();
- insFlags flags = tree->gtSetFlags() ? INS_FLAGS_SET : INS_FLAGS_DONT_CARE;
- regMaskTP needReg = destReg;
- regNumber reg;
- instruction ins;
+ const genTreeOps oper = tree->OperGet();
+ GenTreePtr op1 = tree->gtOp.gtOp1;
+ GenTreePtr op2 = tree->gtOp.gtOp2;
+ const var_types treeType = tree->TypeGet();
+ insFlags flags = tree->gtSetFlags() ? INS_FLAGS_SET : INS_FLAGS_DONT_CARE;
+ regMaskTP needReg = destReg;
+ regNumber reg;
+ instruction ins;
switch (oper)
{
- case GT_LSH: ins = INS_SHIFT_LEFT_LOGICAL; break;
- case GT_RSH: ins = INS_SHIFT_RIGHT_ARITHM; break;
- case GT_RSZ: ins = INS_SHIFT_RIGHT_LOGICAL; break;
- default:
- unreached();
+ case GT_LSH:
+ ins = INS_SHIFT_LEFT_LOGICAL;
+ break;
+ case GT_RSH:
+ ins = INS_SHIFT_RIGHT_ARITHM;
+ break;
+ case GT_RSZ:
+ ins = INS_SHIFT_RIGHT_LOGICAL;
+ break;
+ default:
+ unreached();
}
/* Is the shift count constant? */
noway_assert(op2);
- if (op2->IsIntCnsFitsInI32())
+ if (op2->IsIntCnsFitsInI32())
{
// TODO: Check to see if we could generate a LEA instead!
@@ -8646,7 +8452,7 @@ void CodeGen::genCodeForShift(GenTreePtr tree,
CLANG_FORMAT_COMMENT_ANCHOR;
#ifndef _TARGET_ARM_
- if (oper == GT_LSH)
+ if (oper == GT_LSH)
{
emitAttr size = emitActualTypeSize(treeType);
if (op2->gtIntConCommon.IconValue() == 1)
@@ -8667,9 +8473,9 @@ void CodeGen::genCodeForShift(GenTreePtr tree,
#endif // _TARGET_ARM_
{
#ifndef _TARGET_ARM_
-DO_SHIFT_BY_CNS:
+ DO_SHIFT_BY_CNS:
#endif // _TARGET_ARM_
- // If we are shifting 'reg' by zero bits and do not need the flags to be set
+ // If we are shifting 'reg' by zero bits and do not need the flags to be set
// then we can just skip emitting the instruction as 'reg' is already correct.
//
if ((op2->gtIntConCommon.IconValue() != 0) || tree->gtSetFlags())
@@ -8722,9 +8528,9 @@ DO_SHIFT_BY_CNS:
noway_assert(op2->gtFlags & GTF_REG_VAL);
#ifdef _TARGET_XARCH_
noway_assert(genRegMask(op2->gtRegNum) == op2RegMask);
-#endif
+#endif
// Check for the case of op1 being spilled during the evaluation of op2
- if (op1->gtFlags & GTF_SPILLED)
+ if (op1->gtFlags & GTF_SPILLED)
{
// The register has been spilled -- reload it to any register except ECX
regSet.rsLockUsedReg(op2RegMask);
@@ -8755,29 +8561,22 @@ DO_SHIFT_BY_CNS:
genCodeForTree_DONE(tree, reg);
}
-
/*****************************************************************************
*
* Generate code for a top-level relational operator (not one that is part of a GT_JTRUE tree).
* Handles GT_EQ, GT_NE, GT_LT, GT_LE, GT_GE, GT_GT.
*/
-void CodeGen::genCodeForRelop(GenTreePtr tree,
- regMaskTP destReg,
- regMaskTP bestReg)
+void CodeGen::genCodeForRelop(GenTreePtr tree, regMaskTP destReg, regMaskTP bestReg)
{
- assert(tree->OperGet() == GT_EQ ||
- tree->OperGet() == GT_NE ||
- tree->OperGet() == GT_LT ||
- tree->OperGet() == GT_LE ||
- tree->OperGet() == GT_GE ||
- tree->OperGet() == GT_GT);
-
- const genTreeOps oper = tree->OperGet();
- GenTreePtr op1 = tree->gtOp.gtOp1;
- const var_types treeType = tree->TypeGet();
- regMaskTP needReg = destReg;
- regNumber reg;
+ assert(tree->OperGet() == GT_EQ || tree->OperGet() == GT_NE || tree->OperGet() == GT_LT ||
+ tree->OperGet() == GT_LE || tree->OperGet() == GT_GE || tree->OperGet() == GT_GT);
+
+ const genTreeOps oper = tree->OperGet();
+ GenTreePtr op1 = tree->gtOp.gtOp1;
+ const var_types treeType = tree->TypeGet();
+ regMaskTP needReg = destReg;
+ regNumber reg;
// Longs and float comparisons are converted to "?:"
noway_assert(!compiler->fgMorphRelopToQmark(op1));
@@ -8809,17 +8608,17 @@ void CodeGen::genCodeForRelop(GenTreePtr tree,
// mov reg, 1
// L_end:
- BasicBlock * L_true;
- BasicBlock * L_end;
+ BasicBlock* L_true;
+ BasicBlock* L_end;
L_true = genCreateTempLabel();
L_end = genCreateTempLabel();
inst_JMP(jumpKind, L_true);
- getEmitter()->emitIns_R_I(INS_mov, EA_4BYTE, reg, 0); // Executes when the cond is false
+ getEmitter()->emitIns_R_I(INS_mov, EA_4BYTE, reg, 0); // Executes when the cond is false
inst_JMP(EJ_jmp, L_end);
genDefineTempLabel(L_true);
- getEmitter()->emitIns_R_I(INS_mov, EA_4BYTE, reg, 1); // Executes when the cond is true
+ getEmitter()->emitIns_R_I(INS_mov, EA_4BYTE, reg, 1); // Executes when the cond is true
genDefineTempLabel(L_end);
regTracker.rsTrackRegTrash(reg);
@@ -8835,7 +8634,7 @@ void CodeGen::genCodeForRelop(GenTreePtr tree,
if (jumpKind == EJ_jb)
{
inst_RV_RV(INS_SUBC, reg, reg);
- inst_RV (INS_NEG, reg, TYP_INT);
+ inst_RV(INS_NEG, reg, TYP_INT);
regTracker.rsTrackRegTrash(reg);
}
else if (jumpKind == EJ_jae)
@@ -8862,7 +8661,7 @@ void CodeGen::genCodeForRelop(GenTreePtr tree,
}
#else
NYI("TARGET");
-#endif // _TARGET_XXX
+#endif // _TARGET_XXX
genCodeForTree_DONE(tree, reg);
}
@@ -8877,15 +8676,14 @@ void CodeGen::genCodeForRelop(GenTreePtr tree,
// Return Value:
// None
-void CodeGen::genCodeForCopyObj(GenTreePtr tree,
- regMaskTP destReg)
+void CodeGen::genCodeForCopyObj(GenTreePtr tree, regMaskTP destReg)
{
- GenTreePtr op1 = tree->gtGetOp1();
- GenTreePtr op2 = tree->gtGetOp2();
- regMaskTP needReg = destReg;
- regMaskTP regs = regSet.rsMaskUsed;
- GenTreePtr opsPtr[3];
- regMaskTP regsPtr[3];
+ GenTreePtr op1 = tree->gtGetOp1();
+ GenTreePtr op2 = tree->gtGetOp2();
+ regMaskTP needReg = destReg;
+ regMaskTP regs = regSet.rsMaskUsed;
+ GenTreePtr opsPtr[3];
+ regMaskTP regsPtr[3];
noway_assert(tree->OperGet() == GT_COPYOBJ);
noway_assert(op1->IsList());
@@ -8902,28 +8700,28 @@ void CodeGen::genCodeForCopyObj(GenTreePtr tree,
#ifdef _TARGET_ARM_
if (cpObjOp->IsVolatile())
{
- // Emit a memory barrier instruction before the CopyBlk
+ // Emit a memory barrier instruction before the CopyBlk
instGen_MemoryBarrier();
}
#endif
- GenTreePtr srcObj = cpObjOp->Source();
- GenTreePtr dstObj = cpObjOp->Dest();
+ GenTreePtr srcObj = cpObjOp->Source();
+ GenTreePtr dstObj = cpObjOp->Dest();
noway_assert(dstObj->gtType == TYP_BYREF || dstObj->gtType == TYP_I_IMPL);
#ifdef DEBUG
- CORINFO_CLASS_HANDLE clsHnd = (CORINFO_CLASS_HANDLE)op2->gtIntCon.gtIconVal;
- size_t debugBlkSize = roundUp(compiler->info.compCompHnd->getClassSize(clsHnd), TARGET_POINTER_SIZE);
+ CORINFO_CLASS_HANDLE clsHnd = (CORINFO_CLASS_HANDLE)op2->gtIntCon.gtIconVal;
+ size_t debugBlkSize = roundUp(compiler->info.compCompHnd->getClassSize(clsHnd), TARGET_POINTER_SIZE);
// Since we round up, we are not handling the case where we have a non-pointer sized struct with GC pointers.
// The EE currently does not allow this. Let's assert it just to be safe.
noway_assert(compiler->info.compCompHnd->getClassSize(clsHnd) == debugBlkSize);
#endif
- size_t blkSize = cpObjOp->gtSlots * TARGET_POINTER_SIZE;
- unsigned slots = cpObjOp->gtSlots;
- BYTE * gcPtrs = cpObjOp->gtGcPtrs;
- unsigned gcPtrCount = cpObjOp->gtGcPtrCount;
+ size_t blkSize = cpObjOp->gtSlots * TARGET_POINTER_SIZE;
+ unsigned slots = cpObjOp->gtSlots;
+ BYTE* gcPtrs = cpObjOp->gtGcPtrs;
+ unsigned gcPtrCount = cpObjOp->gtGcPtrCount;
// Make sure gcPtr settings are consisten.
if (gcPtrCount > 0)
@@ -8931,40 +8729,40 @@ void CodeGen::genCodeForCopyObj(GenTreePtr tree,
assert(cpObjOp->HasGCPtr());
}
- GenTreePtr treeFirst, treeSecond;
- regNumber regFirst, regSecond;
+ GenTreePtr treeFirst, treeSecond;
+ regNumber regFirst, regSecond;
// Check what order the object-ptrs have to be evaluated in ?
if (op1->gtFlags & GTF_REVERSE_OPS)
{
- treeFirst = srcObj;
+ treeFirst = srcObj;
treeSecond = dstObj;
#if CPU_USES_BLOCK_MOVE
- regFirst = REG_ESI;
+ regFirst = REG_ESI;
regSecond = REG_EDI;
#else
- regFirst = REG_ARG_1;
+ regFirst = REG_ARG_1;
regSecond = REG_ARG_0;
#endif
}
else
{
- treeFirst = dstObj;
+ treeFirst = dstObj;
treeSecond = srcObj;
#if CPU_USES_BLOCK_MOVE
- regFirst = REG_EDI;
+ regFirst = REG_EDI;
regSecond = REG_ESI;
#else
- regFirst = REG_ARG_0;
+ regFirst = REG_ARG_0;
regSecond = REG_ARG_1;
#endif
}
- bool dstIsOnStack = (dstObj->gtOper == GT_ADDR && (dstObj->gtFlags & GTF_ADDR_ONSTACK));
- bool srcIsOnStack = (srcObj->gtOper == GT_ADDR && (srcObj->gtFlags & GTF_ADDR_ONSTACK));
- emitAttr srcType = (varTypeIsGC(srcObj) && !srcIsOnStack) ? EA_BYREF : EA_PTRSIZE;
- emitAttr dstType = (varTypeIsGC(dstObj) && !dstIsOnStack) ? EA_BYREF : EA_PTRSIZE;
+ bool dstIsOnStack = (dstObj->gtOper == GT_ADDR && (dstObj->gtFlags & GTF_ADDR_ONSTACK));
+ bool srcIsOnStack = (srcObj->gtOper == GT_ADDR && (srcObj->gtFlags & GTF_ADDR_ONSTACK));
+ emitAttr srcType = (varTypeIsGC(srcObj) && !srcIsOnStack) ? EA_BYREF : EA_PTRSIZE;
+ emitAttr dstType = (varTypeIsGC(dstObj) && !dstIsOnStack) ? EA_BYREF : EA_PTRSIZE;
#if CPU_USES_BLOCK_MOVE
// Materialize the trees in the order desired
@@ -8989,7 +8787,7 @@ void CodeGen::genCodeForCopyObj(GenTreePtr tree,
}
else
{
- // This helper will act like a MOVSD
+ // This helper will act like a MOVSD
// -- inputs EDI and ESI are byrefs
// -- including incrementing of ESI and EDI by 4
// -- helper will trash ECX
@@ -8997,8 +8795,8 @@ void CodeGen::genCodeForCopyObj(GenTreePtr tree,
regMaskTP argRegs = genRegMask(regFirst) | genRegMask(regSecond);
regSet.rsLockUsedReg(argRegs);
genEmitHelperCall(CORINFO_HELP_ASSIGN_BYREF,
- 0, // argSize
- EA_PTRSIZE); // retSize
+ 0, // argSize
+ EA_PTRSIZE); // retSize
regSet.rsUnlockUsedReg(argRegs);
}
@@ -9015,7 +8813,7 @@ void CodeGen::genCodeForCopyObj(GenTreePtr tree,
/* The emitter won't record CORINFO_HELP_ASSIGN_BYREF in the GC tables as
it is a emitNoGChelper. However, we have to let the emitter know that
- the GC liveness has changed. We do this by creating a new label.
+ the GC liveness has changed. We do this by creating a new label.
*/
noway_assert(emitter::emitNoGChelper(CORINFO_HELP_ASSIGN_BYREF));
@@ -9025,15 +8823,15 @@ void CodeGen::genCodeForCopyObj(GenTreePtr tree,
#else // !CPU_USES_BLOCK_MOVE
#ifndef _TARGET_ARM_
- // Currently only the ARM implementation is provided
+// Currently only the ARM implementation is provided
#error "COPYBLK for non-ARM && non-CPU_USES_BLOCK_MOVE"
#endif
// Materialize the trees in the order desired
- bool helperUsed;
- regNumber regDst;
- regNumber regSrc;
- regNumber regTemp;
+ bool helperUsed;
+ regNumber regDst;
+ regNumber regSrc;
+ regNumber regTemp;
if ((gcPtrCount > 0) && !dstIsOnStack)
{
@@ -9044,7 +8842,7 @@ void CodeGen::genCodeForCopyObj(GenTreePtr tree,
/* The helper is a Asm-routine that will trash R2,R3 and LR */
{
/* Spill any callee-saved registers which are being used */
- regMaskTP spillRegs = RBM_CALLEE_TRASH_NOGC & regSet.rsMaskUsed;
+ regMaskTP spillRegs = RBM_CALLEE_TRASH_NOGC & regSet.rsMaskUsed;
if (spillRegs)
{
@@ -9056,7 +8854,7 @@ void CodeGen::genCodeForCopyObj(GenTreePtr tree,
// We will also use it as the temp register for our load/store sequences
//
assert(REG_R2 == REG_TMP_1);
- regTemp = regSet.rsGrabReg(RBM_R2);
+ regTemp = regSet.rsGrabReg(RBM_R2);
helperUsed = true;
}
else
@@ -9067,7 +8865,7 @@ void CodeGen::genCodeForCopyObj(GenTreePtr tree,
// Grab any temp register to use for our load/store sequences
//
- regTemp = regSet.rsGrabReg(RBM_ALLINT);
+ regTemp = regSet.rsGrabReg(RBM_ALLINT);
helperUsed = false;
}
assert(dstObj->gtFlags & GTF_REG_VAL);
@@ -9079,18 +8877,18 @@ void CodeGen::genCodeForCopyObj(GenTreePtr tree,
assert(regDst != regTemp);
assert(regSrc != regTemp);
- instruction loadIns = ins_Load(TYP_I_IMPL); // INS_ldr
- instruction storeIns = ins_Store(TYP_I_IMPL); // INS_str
+ instruction loadIns = ins_Load(TYP_I_IMPL); // INS_ldr
+ instruction storeIns = ins_Store(TYP_I_IMPL); // INS_str
- size_t offset = 0;
+ size_t offset = 0;
while (blkSize >= TARGET_POINTER_SIZE)
{
CorInfoGCType gcType;
CorInfoGCType gcTypeNext = TYPE_GC_NONE;
- var_types type = TYP_I_IMPL;
+ var_types type = TYP_I_IMPL;
-#if FEATURE_WRITE_BARRIER
- gcType = (CorInfoGCType)(*gcPtrs++);
+#if FEATURE_WRITE_BARRIER
+ gcType = (CorInfoGCType)(*gcPtrs++);
if (blkSize > TARGET_POINTER_SIZE)
gcTypeNext = (CorInfoGCType)(*gcPtrs);
@@ -9107,7 +8905,7 @@ void CodeGen::genCodeForCopyObj(GenTreePtr tree,
}
#else
gcType = TYPE_GC_NONE;
-#endif // FEATURE_WRITE_BARRIER
+#endif // FEATURE_WRITE_BARRIER
blkSize -= TARGET_POINTER_SIZE;
@@ -9119,8 +8917,7 @@ void CodeGen::genCodeForCopyObj(GenTreePtr tree,
getEmitter()->emitIns_R_R_I(storeIns, opSize, regTemp, regDst, offset);
offset += TARGET_POINTER_SIZE;
- if ((helperUsed && (gcTypeNext != TYPE_GC_NONE)) ||
- ((offset >= 128) && (blkSize > 0)))
+ if ((helperUsed && (gcTypeNext != TYPE_GC_NONE)) || ((offset >= 128) && (blkSize > 0)))
{
getEmitter()->emitIns_R_I(INS_add, srcType, regSrc, offset);
getEmitter()->emitIns_R_I(INS_add, dstType, regDst, offset);
@@ -9131,7 +8928,7 @@ void CodeGen::genCodeForCopyObj(GenTreePtr tree,
{
assert(offset == 0);
- // The helper will act like this:
+ // The helper will act like this:
// -- inputs R0 and R1 are byrefs
// -- helper will perform copy from *R1 into *R0
// -- helper will perform post increment of R0 and R1 by 4
@@ -9143,8 +8940,8 @@ void CodeGen::genCodeForCopyObj(GenTreePtr tree,
regMaskTP argRegs = genRegMask(regFirst) | genRegMask(regSecond);
regSet.rsLockUsedReg(argRegs);
genEmitHelperCall(CORINFO_HELP_ASSIGN_BYREF,
- 0, // argSize
- EA_PTRSIZE); // retSize
+ 0, // argSize
+ EA_PTRSIZE); // retSize
regSet.rsUnlockUsedReg(argRegs);
regTracker.rsTrackRegMaskTrash(RBM_CALLEE_TRASH_NOGC);
@@ -9159,14 +8956,14 @@ void CodeGen::genCodeForCopyObj(GenTreePtr tree,
/* The emitter won't record CORINFO_HELP_ASSIGN_BYREF in the GC tables as
it is a emitNoGChelper. However, we have to let the emitter know that
- the GC liveness has changed. We do this by creating a new label.
+ the GC liveness has changed. We do this by creating a new label.
*/
noway_assert(emitter::emitNoGChelper(CORINFO_HELP_ASSIGN_BYREF));
genDefineTempLabel(&dummyBB);
-#endif // !CPU_USES_BLOCK_MOVE
+#endif // !CPU_USES_BLOCK_MOVE
assert(blkSize == 0);
@@ -9178,22 +8975,21 @@ void CodeGen::genCodeForCopyObj(GenTreePtr tree,
#ifdef _TARGET_ARM_
if (tree->AsBlkOp()->IsVolatile())
{
- // Emit a memory barrier instruction after the CopyBlk
+ // Emit a memory barrier instruction after the CopyBlk
instGen_MemoryBarrier();
}
#endif
}
-void CodeGen::genCodeForBlkOp(GenTreePtr tree,
- regMaskTP destReg)
+void CodeGen::genCodeForBlkOp(GenTreePtr tree, regMaskTP destReg)
{
- genTreeOps oper = tree->OperGet();
- GenTreePtr op1 = tree->gtOp.gtOp1;
- GenTreePtr op2 = tree->gtGetOp2();
- regMaskTP needReg = destReg;
- regMaskTP regs = regSet.rsMaskUsed;
- GenTreePtr opsPtr[3];
- regMaskTP regsPtr[3];
+ genTreeOps oper = tree->OperGet();
+ GenTreePtr op1 = tree->gtOp.gtOp1;
+ GenTreePtr op2 = tree->gtGetOp2();
+ regMaskTP needReg = destReg;
+ regMaskTP regs = regSet.rsMaskUsed;
+ GenTreePtr opsPtr[3];
+ regMaskTP regsPtr[3];
noway_assert(oper == GT_COPYBLK || oper == GT_INITBLK);
noway_assert(op1->IsList());
@@ -9207,20 +9003,18 @@ void CodeGen::genCodeForBlkOp(GenTreePtr tree,
#endif
{
GenTreePtr destPtr, srcPtrOrVal;
- destPtr = op1->gtOp.gtOp1;
+ destPtr = op1->gtOp.gtOp1;
srcPtrOrVal = op1->gtOp.gtOp2;
noway_assert(destPtr->TypeGet() == TYP_BYREF || varTypeIsIntegral(destPtr->TypeGet()));
noway_assert((oper == GT_COPYBLK &&
- (srcPtrOrVal->TypeGet() == TYP_BYREF || varTypeIsIntegral(srcPtrOrVal->TypeGet())))
- ||
- (oper == GT_INITBLK &&
- varTypeIsIntegral(srcPtrOrVal->TypeGet())));
+ (srcPtrOrVal->TypeGet() == TYP_BYREF || varTypeIsIntegral(srcPtrOrVal->TypeGet()))) ||
+ (oper == GT_INITBLK && varTypeIsIntegral(srcPtrOrVal->TypeGet())));
noway_assert(op1 && op1->IsList());
noway_assert(destPtr && srcPtrOrVal);
-#if CPU_USES_BLOCK_MOVE
- regs = (oper == GT_INITBLK) ? RBM_EAX : RBM_ESI; // What is the needReg for Val/Src
+#if CPU_USES_BLOCK_MOVE
+ regs = (oper == GT_INITBLK) ? RBM_EAX : RBM_ESI; // What is the needReg for Val/Src
/* Some special code for block moves/inits for constant sizes */
@@ -9228,18 +9022,17 @@ void CodeGen::genCodeForBlkOp(GenTreePtr tree,
// Is this a fixed size COPYBLK?
// or a fixed size INITBLK with a constant init value?
//
- if ((op2->IsCnsIntOrI()) &&
- ((oper == GT_COPYBLK) || (srcPtrOrVal->IsCnsIntOrI())))
+ if ((op2->IsCnsIntOrI()) && ((oper == GT_COPYBLK) || (srcPtrOrVal->IsCnsIntOrI())))
{
- size_t length = (size_t)op2->gtIntCon.gtIconVal;
- size_t initVal = 0;
+ size_t length = (size_t)op2->gtIntCon.gtIconVal;
+ size_t initVal = 0;
instruction ins_P, ins_PR, ins_B;
if (oper == GT_INITBLK)
{
- ins_P = INS_stosp;
+ ins_P = INS_stosp;
ins_PR = INS_r_stosp;
- ins_B = INS_stosb;
+ ins_B = INS_stosb;
/* Properly extend the init constant from a U1 to a U4 */
initVal = 0xFF & ((unsigned)op1->gtOp.gtOp2->gtIntCon.gtIconVal);
@@ -9254,7 +9047,7 @@ void CodeGen::genCodeForBlkOp(GenTreePtr tree,
#ifdef _TARGET_64BIT_
if (length > 4)
{
- initVal = initVal | (initVal << 32);
+ initVal = initVal | (initVal << 32);
op1->gtOp.gtOp2->gtType = TYP_LONG;
}
else
@@ -9267,23 +9060,23 @@ void CodeGen::genCodeForBlkOp(GenTreePtr tree,
}
else
{
- ins_P = INS_movsp;
+ ins_P = INS_movsp;
ins_PR = INS_r_movsp;
- ins_B = INS_movsb;
+ ins_B = INS_movsb;
}
// Determine if we will be using SSE2
unsigned movqLenMin = 8;
unsigned movqLenMax = 24;
- bool bWillUseSSE2 = false;
- bool bWillUseOnlySSE2 = false;
- bool bNeedEvaluateCnst = true; // If we only use SSE2, we will just load the constant there.
+ bool bWillUseSSE2 = false;
+ bool bWillUseOnlySSE2 = false;
+ bool bNeedEvaluateCnst = true; // If we only use SSE2, we will just load the constant there.
#ifdef _TARGET_64BIT_
- // Until we get SSE2 instructions that move 16 bytes at a time instead of just 8
- // there is no point in wasting space on the bigger instructions
+// Until we get SSE2 instructions that move 16 bytes at a time instead of just 8
+// there is no point in wasting space on the bigger instructions
#else // !_TARGET_64BIT_
@@ -9303,7 +9096,7 @@ void CodeGen::genCodeForBlkOp(GenTreePtr tree,
// Be less aggressive when we are inside a conditional
movqLenMax = 16;
}
- else if (curBBweight >= (BB_LOOP_WEIGHT*BB_UNITY_WEIGHT) / 2)
+ else if (curBBweight >= (BB_LOOP_WEIGHT * BB_UNITY_WEIGHT) / 2)
{
// Be more aggressive when we are inside a loop
movqLenMax = 48;
@@ -9316,9 +9109,7 @@ void CodeGen::genCodeForBlkOp(GenTreePtr tree,
movqLenMax += 16;
}
- if (compiler->compCodeOpt() != Compiler::SMALL_CODE &&
- length >= movqLenMin &&
- length <= movqLenMax)
+ if (compiler->compCodeOpt() != Compiler::SMALL_CODE && length >= movqLenMin && length <= movqLenMax)
{
bWillUseSSE2 = true;
@@ -9366,8 +9157,8 @@ void CodeGen::genCodeForBlkOp(GenTreePtr tree,
if (bWillUseSSE2)
{
- int blkDisp = 0;
- regNumber xmmReg = REG_XMM0;
+ int blkDisp = 0;
+ regNumber xmmReg = REG_XMM0;
if (oper == GT_INITBLK)
{
@@ -9382,8 +9173,9 @@ void CodeGen::genCodeForBlkOp(GenTreePtr tree,
}
}
- JITLOG_THIS(compiler, (LL_INFO100, "Using XMM instructions for %3d byte %s while compiling %s\n",
- length, (oper == GT_INITBLK) ? "initblk" : "copyblk", compiler->info.compFullName));
+ JITLOG_THIS(compiler,
+ (LL_INFO100, "Using XMM instructions for %3d byte %s while compiling %s\n", length,
+ (oper == GT_INITBLK) ? "initblk" : "copyblk", compiler->info.compFullName));
while (length > 7)
{
@@ -9505,8 +9297,8 @@ void CodeGen::genCodeForBlkOp(GenTreePtr tree,
// else No need to trash EAX as it wasnt destroyed by the "rep stos"
genReleaseReg(op1->gtOp.gtOp1);
- if (bNeedEvaluateCnst) genReleaseReg(op1->gtOp.gtOp2);
-
+ if (bNeedEvaluateCnst)
+ genReleaseReg(op1->gtOp.gtOp2);
}
else
{
@@ -9517,8 +9309,7 @@ void CodeGen::genCodeForBlkOp(GenTreePtr tree,
// What order should the Dest, Val/Src, and Size be calculated
- compiler->fgOrderBlockOps(tree, RBM_EDI, regs, RBM_ECX,
- opsPtr, regsPtr); // OUT arguments
+ compiler->fgOrderBlockOps(tree, RBM_EDI, regs, RBM_ECX, opsPtr, regsPtr); // OUT arguments
noway_assert(((oper == GT_INITBLK) && (regs == RBM_EAX)) || ((oper == GT_COPYBLK) && (regs == RBM_ESI)));
genComputeReg(opsPtr[0], regsPtr[0], RegSet::EXACT_REG, RegSet::KEEP_REG, (regsPtr[0] != RBM_EAX));
@@ -9528,14 +9319,14 @@ void CodeGen::genCodeForBlkOp(GenTreePtr tree,
genRecoverReg(opsPtr[0], regsPtr[0], RegSet::KEEP_REG);
genRecoverReg(opsPtr[1], regsPtr[1], RegSet::KEEP_REG);
- noway_assert((op1->gtOp.gtOp1->gtFlags & GTF_REG_VAL) && // Dest
- (op1->gtOp.gtOp1->gtRegNum == REG_EDI));
+ noway_assert((op1->gtOp.gtOp1->gtFlags & GTF_REG_VAL) && // Dest
+ (op1->gtOp.gtOp1->gtRegNum == REG_EDI));
- noway_assert((op1->gtOp.gtOp2->gtFlags & GTF_REG_VAL) && // Val/Src
- (genRegMask(op1->gtOp.gtOp2->gtRegNum) == regs));
+ noway_assert((op1->gtOp.gtOp2->gtFlags & GTF_REG_VAL) && // Val/Src
+ (genRegMask(op1->gtOp.gtOp2->gtRegNum) == regs));
- noway_assert((op2->gtFlags & GTF_REG_VAL) && // Size
- (op2->gtRegNum == REG_ECX));
+ noway_assert((op2->gtFlags & GTF_REG_VAL) && // Size
+ (op2->gtRegNum == REG_ECX));
if (oper == GT_INITBLK)
instGen(INS_r_stosb);
@@ -9554,7 +9345,7 @@ void CodeGen::genCodeForBlkOp(GenTreePtr tree,
genReleaseReg(opsPtr[2]);
}
-#else // !CPU_USES_BLOCK_MOVE
+#else // !CPU_USES_BLOCK_MOVE
#ifndef _TARGET_ARM_
// Currently only the ARM implementation is provided
@@ -9564,15 +9355,14 @@ void CodeGen::genCodeForBlkOp(GenTreePtr tree,
// Is this a fixed size COPYBLK?
// or a fixed size INITBLK with a constant init value?
//
- if ((op2->OperGet() == GT_CNS_INT) &&
- ((oper == GT_COPYBLK) || (srcPtrOrVal->OperGet() == GT_CNS_INT)))
+ if ((op2->OperGet() == GT_CNS_INT) && ((oper == GT_COPYBLK) || (srcPtrOrVal->OperGet() == GT_CNS_INT)))
{
- GenTreePtr dstOp = op1->gtOp.gtOp1;
- GenTreePtr srcOp = op1->gtOp.gtOp2;
- unsigned length = (unsigned)op2->gtIntCon.gtIconVal;
- unsigned fullStoreCount = length / TARGET_POINTER_SIZE;
- unsigned initVal = 0;
- bool useLoop = false;
+ GenTreePtr dstOp = op1->gtOp.gtOp1;
+ GenTreePtr srcOp = op1->gtOp.gtOp2;
+ unsigned length = (unsigned)op2->gtIntCon.gtIconVal;
+ unsigned fullStoreCount = length / TARGET_POINTER_SIZE;
+ unsigned initVal = 0;
+ bool useLoop = false;
if (oper == GT_INITBLK)
{
@@ -9585,22 +9375,21 @@ void CodeGen::genCodeForBlkOp(GenTreePtr tree,
if (initVal != 0)
{
- initVal = initVal | (initVal << 8) | (initVal << 16) | (initVal << 24);
+ initVal = initVal | (initVal << 8) | (initVal << 16) | (initVal << 24);
op1->gtOp.gtOp2->gtIntCon.gtIconVal = initVal;
}
}
// Will we be using a loop to implement this INITBLK/COPYBLK?
- if (((oper == GT_COPYBLK) && (fullStoreCount >= 8)) ||
- ((oper == GT_INITBLK) && (fullStoreCount >= 16)))
+ if (((oper == GT_COPYBLK) && (fullStoreCount >= 8)) || ((oper == GT_INITBLK) && (fullStoreCount >= 16)))
{
useLoop = true;
}
- regMaskTP usedRegs;
- regNumber regDst;
- regNumber regSrc;
- regNumber regTemp;
+ regMaskTP usedRegs;
+ regNumber regDst;
+ regNumber regSrc;
+ regNumber regTemp;
/* Evaluate dest and src/val */
@@ -9631,11 +9420,11 @@ void CodeGen::genCodeForBlkOp(GenTreePtr tree,
assert(dstOp->gtFlags & GTF_REG_VAL);
assert(srcOp->gtFlags & GTF_REG_VAL);
- regDst = dstOp->gtRegNum;
- regSrc = srcOp->gtRegNum;
- usedRegs = (genRegMask(regSrc) | genRegMask(regDst));
- bool dstIsOnStack = (dstOp->gtOper == GT_ADDR && (dstOp->gtFlags & GTF_ADDR_ONSTACK));
- emitAttr dstType = (varTypeIsGC(dstOp) && !dstIsOnStack) ? EA_BYREF : EA_PTRSIZE;
+ regDst = dstOp->gtRegNum;
+ regSrc = srcOp->gtRegNum;
+ usedRegs = (genRegMask(regSrc) | genRegMask(regDst));
+ bool dstIsOnStack = (dstOp->gtOper == GT_ADDR && (dstOp->gtFlags & GTF_ADDR_ONSTACK));
+ emitAttr dstType = (varTypeIsGC(dstOp) && !dstIsOnStack) ? EA_BYREF : EA_PTRSIZE;
emitAttr srcType;
if (oper == GT_COPYBLK)
@@ -9644,7 +9433,7 @@ void CodeGen::genCodeForBlkOp(GenTreePtr tree,
regTemp = regSet.rsGrabReg(regSet.rsNarrowHint(regSet.rsRegMaskCanGrab() & ~usedRegs, RBM_LOW_REGS));
usedRegs |= genRegMask(regTemp);
bool srcIsOnStack = (srcOp->gtOper == GT_ADDR && (srcOp->gtFlags & GTF_ADDR_ONSTACK));
- srcType = (varTypeIsGC(srcOp) && !srcIsOnStack) ? EA_BYREF : EA_PTRSIZE;
+ srcType = (varTypeIsGC(srcOp) && !srcIsOnStack) ? EA_BYREF : EA_PTRSIZE;
}
else
{
@@ -9652,10 +9441,10 @@ void CodeGen::genCodeForBlkOp(GenTreePtr tree,
srcType = EA_PTRSIZE;
}
- instruction loadIns = ins_Load(TYP_I_IMPL); // INS_ldr
- instruction storeIns = ins_Store(TYP_I_IMPL); // INS_str
+ instruction loadIns = ins_Load(TYP_I_IMPL); // INS_ldr
+ instruction storeIns = ins_Store(TYP_I_IMPL); // INS_str
- int finalOffset;
+ int finalOffset;
// Can we emit a small number of ldr/str instructions to implement this INITBLK/COPYBLK?
if (!useLoop)
@@ -9678,26 +9467,28 @@ void CodeGen::genCodeForBlkOp(GenTreePtr tree,
finalOffset = fullStoreCount * TARGET_POINTER_SIZE;
length -= finalOffset;
}
- else // We will use a loop to implement this INITBLK/COPYBLK
+ else // We will use a loop to implement this INITBLK/COPYBLK
{
- unsigned pairStoreLoopCount = fullStoreCount / 2;
+ unsigned pairStoreLoopCount = fullStoreCount / 2;
// We need a second temp register for CopyBlk
- regNumber regTemp2 = REG_STK;
+ regNumber regTemp2 = REG_STK;
if (oper == GT_COPYBLK)
{
// Prefer a low register, but avoid one of the ones we've already grabbed
- regTemp2 = regSet.rsGrabReg(regSet.rsNarrowHint(regSet.rsRegMaskCanGrab() & ~usedRegs, RBM_LOW_REGS));
+ regTemp2 =
+ regSet.rsGrabReg(regSet.rsNarrowHint(regSet.rsRegMaskCanGrab() & ~usedRegs, RBM_LOW_REGS));
usedRegs |= genRegMask(regTemp2);
}
// Pick and initialize the loop counter register
regNumber regLoopIndex;
- regLoopIndex = regSet.rsGrabReg(regSet.rsNarrowHint(regSet.rsRegMaskCanGrab() & ~usedRegs, RBM_LOW_REGS));
+ regLoopIndex =
+ regSet.rsGrabReg(regSet.rsNarrowHint(regSet.rsRegMaskCanGrab() & ~usedRegs, RBM_LOW_REGS));
genSetRegToIcon(regLoopIndex, pairStoreLoopCount, TYP_INT);
// Create and define the Basic Block for the loop top
- BasicBlock * loopTopBlock = genCreateTempLabel();
+ BasicBlock* loopTopBlock = genCreateTempLabel();
genDefineTempLabel(loopTopBlock);
// The loop body
@@ -9752,8 +9543,8 @@ void CodeGen::genCodeForBlkOp(GenTreePtr tree,
if (length & sizeof(short))
{
- loadIns = ins_Load(TYP_USHORT); // INS_ldrh
- storeIns = ins_Store(TYP_USHORT); // INS_strh
+ loadIns = ins_Load(TYP_USHORT); // INS_ldrh
+ storeIns = ins_Store(TYP_USHORT); // INS_strh
if (oper == GT_COPYBLK)
{
@@ -9772,8 +9563,8 @@ void CodeGen::genCodeForBlkOp(GenTreePtr tree,
if (length & sizeof(char))
{
- loadIns = ins_Load(TYP_UBYTE); // INS_ldrb
- storeIns = ins_Store(TYP_UBYTE); // INS_strb
+ loadIns = ins_Load(TYP_UBYTE); // INS_ldrb
+ storeIns = ins_Store(TYP_UBYTE); // INS_strb
if (oper == GT_COPYBLK)
{
@@ -9802,8 +9593,7 @@ void CodeGen::genCodeForBlkOp(GenTreePtr tree,
// What order should the Dest, Val/Src, and Size be calculated
- compiler->fgOrderBlockOps(tree, RBM_ARG_0, RBM_ARG_1, RBM_ARG_2,
- opsPtr, regsPtr); // OUT arguments
+ compiler->fgOrderBlockOps(tree, RBM_ARG_0, RBM_ARG_1, RBM_ARG_2, opsPtr, regsPtr); // OUT arguments
genComputeReg(opsPtr[0], regsPtr[0], RegSet::EXACT_REG, RegSet::KEEP_REG);
genComputeReg(opsPtr[1], regsPtr[1], RegSet::EXACT_REG, RegSet::KEEP_REG);
@@ -9813,19 +9603,20 @@ void CodeGen::genCodeForBlkOp(GenTreePtr tree,
genRecoverReg(opsPtr[1], regsPtr[1], RegSet::KEEP_REG);
noway_assert((op1->gtOp.gtOp1->gtFlags & GTF_REG_VAL) && // Dest
- (op1->gtOp.gtOp1->gtRegNum == REG_ARG_0));
+ (op1->gtOp.gtOp1->gtRegNum == REG_ARG_0));
noway_assert((op1->gtOp.gtOp2->gtFlags & GTF_REG_VAL) && // Val/Src
- (op1->gtOp.gtOp2->gtRegNum == REG_ARG_1));
+ (op1->gtOp.gtOp2->gtRegNum == REG_ARG_1));
- noway_assert((op2->gtFlags & GTF_REG_VAL) && // Size
- (op2->gtRegNum == REG_ARG_2));
+ noway_assert((op2->gtFlags & GTF_REG_VAL) && // Size
+ (op2->gtRegNum == REG_ARG_2));
regSet.rsLockUsedReg(RBM_ARG_0 | RBM_ARG_1 | RBM_ARG_2);
genEmitHelperCall(oper == GT_COPYBLK ? CORINFO_HELP_MEMCPY
- /* GT_INITBLK */ : CORINFO_HELP_MEMSET,
- 0, EA_UNKNOWN);
+ /* GT_INITBLK */
+ : CORINFO_HELP_MEMSET,
+ 0, EA_UNKNOWN);
regTracker.rsTrackRegMaskTrash(RBM_CALLEE_TRASH);
@@ -9837,35 +9628,33 @@ void CodeGen::genCodeForBlkOp(GenTreePtr tree,
if ((oper == GT_COPYBLK) && tree->AsBlkOp()->IsVolatile())
{
- // Emit a memory barrier instruction after the CopyBlk
+ // Emit a memory barrier instruction after the CopyBlk
instGen_MemoryBarrier();
}
-#endif // !CPU_USES_BLOCK_MOVE
+#endif // !CPU_USES_BLOCK_MOVE
}
}
BasicBlock dummyBB;
#ifdef _PREFAST_
#pragma warning(push)
-#pragma warning(disable:21000) // Suppress PREFast warning about overly large function
+#pragma warning(disable : 21000) // Suppress PREFast warning about overly large function
#endif
-void CodeGen::genCodeForTreeSmpOp(GenTreePtr tree,
- regMaskTP destReg,
- regMaskTP bestReg)
+void CodeGen::genCodeForTreeSmpOp(GenTreePtr tree, regMaskTP destReg, regMaskTP bestReg)
{
- const genTreeOps oper = tree->OperGet();
- const var_types treeType = tree->TypeGet();
- GenTreePtr op1 = tree->gtOp.gtOp1;
- GenTreePtr op2 = tree->gtGetOp2();
- regNumber reg = DUMMY_INIT(REG_CORRUPT);
- regMaskTP regs = regSet.rsMaskUsed;
- regMaskTP needReg = destReg;
- insFlags flags = tree->gtSetFlags() ? INS_FLAGS_SET : INS_FLAGS_DONT_CARE;
- emitAttr size;
- instruction ins;
- regMaskTP addrReg;
- GenTreePtr opsPtr[3];
- regMaskTP regsPtr[3];
+ const genTreeOps oper = tree->OperGet();
+ const var_types treeType = tree->TypeGet();
+ GenTreePtr op1 = tree->gtOp.gtOp1;
+ GenTreePtr op2 = tree->gtGetOp2();
+ regNumber reg = DUMMY_INIT(REG_CORRUPT);
+ regMaskTP regs = regSet.rsMaskUsed;
+ regMaskTP needReg = destReg;
+ insFlags flags = tree->gtSetFlags() ? INS_FLAGS_SET : INS_FLAGS_DONT_CARE;
+ emitAttr size;
+ instruction ins;
+ regMaskTP addrReg;
+ GenTreePtr opsPtr[3];
+ regMaskTP regsPtr[3];
#ifdef DEBUG
addrReg = 0xDEADCAFE;
@@ -9886,7 +9675,7 @@ void CodeGen::genCodeForTreeSmpOp(GenTreePtr tree,
return;
case GT_ASG_AND:
- case GT_ASG_OR :
+ case GT_ASG_OR:
case GT_ASG_XOR:
case GT_ASG_ADD:
case GT_ASG_SUB:
@@ -9899,7 +9688,8 @@ void CodeGen::genCodeForTreeSmpOp(GenTreePtr tree,
// Note that the specialCase here occurs when the treeType specifies a byte sized operation
// and we decided to enregister the op1 LclVar in a non-byteable register (ESI or EDI)
//
- bool specialCase; specialCase = false;
+ bool specialCase;
+ specialCase = false;
if (op1->gtOper == GT_REG_VAR)
{
/* Get hold of the target register */
@@ -9913,9 +9703,9 @@ void CodeGen::genCodeForTreeSmpOp(GenTreePtr tree,
regTracker.rsTrackRegTrash(byteReg);
inst_RV(INS_NEG, byteReg, treeType, emitTypeSize(treeType));
- var_types op1Type = op1->TypeGet();
+ var_types op1Type = op1->TypeGet();
instruction wideningIns = ins_Move_Extend(op1Type, true);
- inst_RV_RV(wideningIns, reg, byteReg, op1Type, emitTypeSize(op1Type));
+ inst_RV_RV(wideningIns, reg, byteReg, op1Type, emitTypeSize(op1Type));
regTracker.rsTrackRegTrash(reg);
specialCase = true;
}
@@ -9934,11 +9724,11 @@ void CodeGen::genCodeForTreeSmpOp(GenTreePtr tree,
{
// Fix 388382 ARM JitStress WP7
var_types op1Type = op1->TypeGet();
- regNumber reg = regSet.rsPickFreeReg();
+ regNumber reg = regSet.rsPickFreeReg();
inst_RV_TT(ins_Load(op1Type), reg, op1, 0, emitTypeSize(op1Type));
regTracker.rsTrackRegTrash(reg);
inst_RV_IV(INS_NEG, reg, 0, emitTypeSize(treeType), flags);
- inst_TT_RV(ins_Store(op1Type), op1, reg, 0, emitTypeSize(op1Type));
+ inst_TT_RV(ins_Store(op1Type), op1, reg, 0, emitTypeSize(op1Type));
}
#endif
if (op1->gtFlags & GTF_REG_VAL)
@@ -9949,7 +9739,7 @@ void CodeGen::genCodeForTreeSmpOp(GenTreePtr tree,
return;
case GT_AND:
- case GT_OR :
+ case GT_OR:
case GT_XOR:
case GT_ADD:
case GT_SUB:
@@ -9987,12 +9777,11 @@ void CodeGen::genCodeForTreeSmpOp(GenTreePtr tree,
genCompIntoFreeReg(op1, needReg, RegSet::FREE_REG);
noway_assert(op1->gtFlags & GTF_REG_VAL);
- reg = op1->gtRegNum;
+ reg = op1->gtRegNum;
/* Negate/reverse the value in the register */
- inst_RV((oper == GT_NEG) ? INS_NEG
- : INS_NOT, reg, treeType);
+ inst_RV((oper == GT_NEG) ? INS_NEG : INS_NOT, reg, treeType);
/* The register is now trashed */
@@ -10002,7 +9791,7 @@ void CodeGen::genCodeForTreeSmpOp(GenTreePtr tree,
return;
case GT_IND:
- case GT_NULLCHECK: // At this point, explicit null checks are just like inds...
+ case GT_NULLCHECK: // At this point, explicit null checks are just like inds...
/* Make sure the operand is addressable */
@@ -10016,7 +9805,7 @@ void CodeGen::genCodeForTreeSmpOp(GenTreePtr tree,
/* Pick a register for the value */
- if (needReg == RBM_ALLINT && bestReg == 0)
+ if (needReg == RBM_ALLINT && bestReg == 0)
{
/* Absent a better suggestion, pick a useless register */
@@ -10028,11 +9817,8 @@ void CodeGen::genCodeForTreeSmpOp(GenTreePtr tree,
if (op1->IsCnsIntOrI() && op1->IsIconHandle(GTF_ICON_TLS_HDL))
{
noway_assert(size == EA_PTRSIZE);
- getEmitter()->emitIns_R_C (ins_Load(TYP_I_IMPL),
- EA_PTRSIZE,
- reg,
- FLD_GLOBAL_FS,
- (int)op1->gtIntCon.gtIconVal);
+ getEmitter()->emitIns_R_C(ins_Load(TYP_I_IMPL), EA_PTRSIZE, reg, FLD_GLOBAL_FS,
+ (int)op1->gtIntCon.gtIconVal);
}
else
{
@@ -10055,7 +9841,8 @@ void CodeGen::genCodeForTreeSmpOp(GenTreePtr tree,
#ifdef DEBUG
/* Update the live set of register variables */
- if (compiler->opts.varNames) genUpdateLife(tree);
+ if (compiler->opts.varNames)
+ genUpdateLife(tree);
#endif
/* Now we can update the register pointer information */
@@ -10071,12 +9858,11 @@ void CodeGen::genCodeForTreeSmpOp(GenTreePtr tree,
genCodeForNumericCast(tree, destReg, bestReg);
return;
-
case GT_JTRUE:
/* Is this a test of a relational operator? */
- if (op1->OperIsCompare())
+ if (op1->OperIsCompare())
{
/* Generate the conditional jump */
@@ -10086,7 +9872,7 @@ void CodeGen::genCodeForTreeSmpOp(GenTreePtr tree,
return;
}
-#ifdef DEBUG
+#ifdef DEBUG
compiler->gtDispTree(tree);
#endif
NO_WAY("ISSUE: can we ever have a jumpCC without a compare node?");
@@ -10098,9 +9884,9 @@ void CodeGen::genCodeForTreeSmpOp(GenTreePtr tree,
case GT_RETFILT:
noway_assert(tree->gtType == TYP_VOID || op1 != 0);
- if (op1 == 0) // endfinally
+ if (op1 == 0) // endfinally
{
- reg = REG_NA;
+ reg = REG_NA;
#ifdef _TARGET_XARCH_
/* Return using a pop-jmp sequence. As the "try" block calls
@@ -10111,18 +9897,18 @@ void CodeGen::genCodeForTreeSmpOp(GenTreePtr tree,
inst_RV(INS_pop_hide, REG_EAX, TYP_I_IMPL);
inst_RV(INS_i_jmp, REG_EAX, TYP_I_IMPL);
#elif defined(_TARGET_ARM_)
- // Nothing needed for ARM
+// Nothing needed for ARM
#else
NYI("TARGET");
#endif
}
- else // endfilter
+ else // endfilter
{
genComputeReg(op1, RBM_INTRET, RegSet::EXACT_REG, RegSet::FREE_REG);
noway_assert(op1->gtFlags & GTF_REG_VAL);
noway_assert(op1->gtRegNum == REG_INTRET);
/* The return value has now been computed */
- reg = op1->gtRegNum;
+ reg = op1->gtRegNum;
/* Return */
instGen_Return(0);
@@ -10147,11 +9933,11 @@ void CodeGen::genCodeForTreeSmpOp(GenTreePtr tree,
/* Is there a return value and/or an exit statement? */
- if (op1)
+ if (op1)
{
- if (op1->gtType == TYP_VOID)
+ if (op1->gtType == TYP_VOID)
{
- //We're returning nothing, just generate the block (shared epilog calls).
+ // We're returning nothing, just generate the block (shared epilog calls).
genCodeForTree(op1, 0);
}
#ifdef _TARGET_ARM_
@@ -10177,17 +9963,17 @@ void CodeGen::genCodeForTreeSmpOp(GenTreePtr tree,
// This can only occur when we are returning a non-HFA struct
// that is composed of a single float field and we performed
// struct promotion and enregistered the float field.
- //
+ //
genComputeReg(op1, 0, RegSet::ANY_REG, RegSet::FREE_REG);
getEmitter()->emitIns_R_R(INS_vmov_f2i, EA_4BYTE, REG_INTRET, op1->gtRegNum);
}
#endif // _TARGET_ARM_
else
{
- //we can now go through this code for compiler->genReturnBB. I've regularized all the code.
+ // we can now go through this code for compiler->genReturnBB. I've regularized all the code.
+
+ // noway_assert(compiler->compCurBB != compiler->genReturnBB);
- //noway_assert(compiler->compCurBB != compiler->genReturnBB);
-
noway_assert(op1->gtType != TYP_VOID);
/* Generate the return value into the return register */
@@ -10202,15 +9988,14 @@ void CodeGen::genCodeForTreeSmpOp(GenTreePtr tree,
/* The return value has now been computed */
- reg = op1->gtRegNum;
+ reg = op1->gtRegNum;
genCodeForTree_DONE(tree, reg);
-
}
#ifdef PROFILING_SUPPORTED
- //The profiling hook does not trash registers, so it's safe to call after we emit the code for
- //the GT_RETURN tree.
+ // The profiling hook does not trash registers, so it's safe to call after we emit the code for
+ // the GT_RETURN tree.
if (compiler->compCurBB == compiler->genReturnBB)
{
@@ -10225,8 +10010,8 @@ void CodeGen::genCodeForTreeSmpOp(GenTreePtr tree,
compiler->lvaTable[compiler->lvaReturnEspCheck].lvOnFrame);
getEmitter()->emitIns_S_R(INS_cmp, EA_PTRSIZE, REG_SPBASE, compiler->lvaReturnEspCheck, 0);
- BasicBlock * esp_check = genCreateTempLabel();
- emitJumpKind jmpEqual = genJumpKindForOper(GT_EQ, CK_SIGNED);
+ BasicBlock* esp_check = genCreateTempLabel();
+ emitJumpKind jmpEqual = genJumpKindForOper(GT_EQ, CK_SIGNED);
inst_JMP(jmpEqual, esp_check);
getEmitter()->emitIns(INS_BREAKPOINT);
genDefineTempLabel(esp_check);
@@ -10238,10 +10023,10 @@ void CodeGen::genCodeForTreeSmpOp(GenTreePtr tree,
if (tree->gtFlags & GTF_REVERSE_OPS)
{
- if (tree->gtType == TYP_VOID)
+ if (tree->gtType == TYP_VOID)
{
genEvalSideEffects(op2);
- genUpdateLife (op2);
+ genUpdateLife(op2);
genEvalSideEffects(op1);
genUpdateLife(tree);
return;
@@ -10278,11 +10063,11 @@ void CodeGen::genCodeForTreeSmpOp(GenTreePtr tree,
/* Generate side effects of the first operand */
genEvalSideEffects(op1);
- genUpdateLife (op1);
+ genUpdateLife(op1);
/* Is the value of the second operand used? */
- if (tree->gtType == TYP_VOID)
+ if (tree->gtType == TYP_VOID)
{
/* The right operand produces no result. The morpher is
responsible for resetting the type of GT_COMMA nodes
@@ -10300,7 +10085,7 @@ void CodeGen::genCodeForTreeSmpOp(GenTreePtr tree,
/* The result of 'op2' is also the final result */
- reg = op2->gtRegNum;
+ reg = op2->gtRegNum;
/* Remember whether we set the flags */
@@ -10316,7 +10101,7 @@ void CodeGen::genCodeForTreeSmpOp(GenTreePtr tree,
/* The result of 'op1' is also the final result */
- reg = op1->gtRegNum;
+ reg = op1->gtRegNum;
/* Remember whether we set the flags */
@@ -10333,7 +10118,7 @@ void CodeGen::genCodeForTreeSmpOp(GenTreePtr tree,
case GT_NOP:
#if OPT_BOOL_OPS
- if (op1 == NULL)
+ if (op1 == NULL)
return;
#endif
@@ -10343,7 +10128,7 @@ void CodeGen::genCodeForTreeSmpOp(GenTreePtr tree,
/* The result is the same as the operand */
- reg = op1->gtRegNum;
+ reg = op1->gtRegNum;
genCodeForTree_DONE(tree, reg);
return;
@@ -10352,7 +10137,7 @@ void CodeGen::genCodeForTreeSmpOp(GenTreePtr tree,
switch (tree->gtIntrinsic.gtIntrinsicId)
{
- case CORINFO_INTRINSIC_Round:
+ case CORINFO_INTRINSIC_Round:
{
noway_assert(tree->gtType == TYP_INT);
@@ -10376,12 +10161,11 @@ void CodeGen::genCodeForTreeSmpOp(GenTreePtr tree,
genCodeForTreeFloat(tree, needReg, bestReg);
return;
#endif
- }
+ }
break;
- default:
- noway_assert(!"unexpected math intrinsic");
-
+ default:
+ noway_assert(!"unexpected math intrinsic");
}
genCodeForTree_DONE(tree, reg);
@@ -10397,7 +10181,7 @@ void CodeGen::genCodeForTreeSmpOp(GenTreePtr tree,
genCodeForCopyObj(tree, destReg);
genCodeForTree_DONE(tree, REG_NA);
return;
-
+
case GT_COPYBLK:
case GT_INITBLK:
@@ -10432,146 +10216,147 @@ void CodeGen::genCodeForTreeSmpOp(GenTreePtr tree,
genComputeReg(op1, RBM_NONE, RegSet::ANY_REG, RegSet::KEEP_REG);
switch (cns)
{
- case 1:
- instGen(INS_lock);
- instEmit_RM(INS_inc, op1, op1, 0); break;
- case -1:
- instGen(INS_lock);
- instEmit_RM(INS_dec, op1, op1, 0); break;
- default:
- assert((int)cns == cns); // By test above for AMD64.
- instGen(INS_lock);
- inst_AT_IV(INS_add, EA_4BYTE, op1, (int)cns, 0); break;
+ case 1:
+ instGen(INS_lock);
+ instEmit_RM(INS_inc, op1, op1, 0);
+ break;
+ case -1:
+ instGen(INS_lock);
+ instEmit_RM(INS_dec, op1, op1, 0);
+ break;
+ default:
+ assert((int)cns == cns); // By test above for AMD64.
+ instGen(INS_lock);
+ inst_AT_IV(INS_add, EA_4BYTE, op1, (int)cns, 0);
+ break;
}
genReleaseReg(op1);
}
else
{
- //non constant addend means it needs to go into a register.
+ // non constant addend means it needs to go into a register.
ins = INS_add;
goto LockBinOpCommon;
}
- genFlagsEqualToNone(); // We didn't compute a result into a register.
- genUpdateLife(tree); // We didn't compute an operand into anything.
+ genFlagsEqualToNone(); // We didn't compute a result into a register.
+ genUpdateLife(tree); // We didn't compute an operand into anything.
return;
case GT_XADD:
- ins = INS_xadd; goto LockBinOpCommon;
+ ins = INS_xadd;
+ goto LockBinOpCommon;
case GT_XCHG:
- ins = INS_xchg; goto LockBinOpCommon;
-LockBinOpCommon:
+ ins = INS_xchg;
+ goto LockBinOpCommon;
+ LockBinOpCommon:
+ {
+ // Compute the second operand into a register. xadd and xchg are r/m32, r32. So even if op2
+ // is a constant, it needs to be in a register. This should be the output register if
+ // possible.
+ //
+ // For reference, gtOp1 is the location. gtOp2 is the addend or the value.
+
+ GenTreePtr location = op1;
+ GenTreePtr value = op2;
+
+ // Again, a friendly reminder. IL calling convention is left to right.
+ if (tree->gtFlags & GTF_REVERSE_OPS)
{
- //Compute the second operand into a register. xadd and xchg are r/m32, r32. So even if op2
- //is a constant, it needs to be in a register. This should be the output register if
- //possible.
- //
- //For reference, gtOp1 is the location. gtOp2 is the addend or the value.
+ // The atomic operations destroy this argument, so force it into a scratch register
+ reg = regSet.rsPickFreeReg();
+ genComputeReg(value, genRegMask(reg), RegSet::EXACT_REG, RegSet::KEEP_REG);
- GenTreePtr location = op1;
- GenTreePtr value = op2;
+ // Must evaluate location into a register
+ genCodeForTree(location, needReg, RBM_NONE);
+ assert(location->gtFlags & GTF_REG_VAL);
+ regSet.rsMarkRegUsed(location);
+ regSet.rsLockUsedReg(genRegMask(location->gtRegNum));
+ genRecoverReg(value, RBM_NONE, RegSet::KEEP_REG);
+ regSet.rsUnlockUsedReg(genRegMask(location->gtRegNum));
- //Again, a friendly reminder. IL calling convention is left to right.
- if (tree->gtFlags & GTF_REVERSE_OPS)
+ if (ins != INS_xchg)
{
- // The atomic operations destroy this argument, so force it into a scratch register
+ // xchg implies the lock prefix, but xadd and add require it.
+ instGen(INS_lock);
+ }
+ instEmit_RM_RV(ins, EA_4BYTE, location, reg, 0);
+ genReleaseReg(value);
+ regTracker.rsTrackRegTrash(reg);
+ genReleaseReg(location);
+ }
+ else
+ {
+ regMaskTP addrReg;
+ if (genMakeIndAddrMode(location, tree, false, /* not for LEA */
+ needReg, RegSet::KEEP_REG, &addrReg))
+ {
+ genUpdateLife(location);
+
reg = regSet.rsPickFreeReg();
genComputeReg(value, genRegMask(reg), RegSet::EXACT_REG, RegSet::KEEP_REG);
-
- // Must evaluate location into a register
- genCodeForTree(location, needReg, RBM_NONE);
- assert(location->gtFlags & GTF_REG_VAL);
- regSet.rsMarkRegUsed(location);
- regSet.rsLockUsedReg(genRegMask(location->gtRegNum));
- genRecoverReg(value, RBM_NONE, RegSet::KEEP_REG);
- regSet.rsUnlockUsedReg(genRegMask(location->gtRegNum));
+ addrReg = genKeepAddressable(location, addrReg, genRegMask(reg));
if (ins != INS_xchg)
{
- //xchg implies the lock prefix, but xadd and add require it.
+ // xchg implies the lock prefix, but xadd and add require it.
instGen(INS_lock);
}
- instEmit_RM_RV(ins, EA_4BYTE, location, reg, 0);
+
+ // instEmit_RM_RV(ins, EA_4BYTE, location, reg, 0);
+ // inst_TT_RV(ins, location, reg);
+ sched_AM(ins, EA_4BYTE, reg, false, location, 0);
+
genReleaseReg(value);
regTracker.rsTrackRegTrash(reg);
- genReleaseReg(location);
+ genDoneAddressable(location, addrReg, RegSet::KEEP_REG);
}
else
{
- regMaskTP addrReg;
- if (genMakeIndAddrMode(location,
- tree,
- false, /* not for LEA */
- needReg,
- RegSet::KEEP_REG,
- &addrReg))
- {
- genUpdateLife(location);
-
- reg = regSet.rsPickFreeReg();
- genComputeReg(value, genRegMask(reg), RegSet::EXACT_REG, RegSet::KEEP_REG);
- addrReg = genKeepAddressable(location, addrReg, genRegMask(reg));
-
- if (ins != INS_xchg)
- {
- //xchg implies the lock prefix, but xadd and add require it.
- instGen(INS_lock);
- }
+ // Must evalute location into a register.
+ genCodeForTree(location, needReg, RBM_NONE);
+ assert(location->gtFlags && GTF_REG_VAL);
+ regSet.rsMarkRegUsed(location);
- // instEmit_RM_RV(ins, EA_4BYTE, location, reg, 0);
- // inst_TT_RV(ins, location, reg);
- sched_AM(ins, EA_4BYTE, reg, false, location, 0);
+ // xadd destroys this argument, so force it into a scratch register
+ reg = regSet.rsPickFreeReg();
+ genComputeReg(value, genRegMask(reg), RegSet::EXACT_REG, RegSet::KEEP_REG);
+ regSet.rsLockUsedReg(genRegMask(value->gtRegNum));
+ genRecoverReg(location, RBM_NONE, RegSet::KEEP_REG);
+ regSet.rsUnlockUsedReg(genRegMask(value->gtRegNum));
- genReleaseReg(value);
- regTracker.rsTrackRegTrash(reg);
- genDoneAddressable(location, addrReg, RegSet::KEEP_REG);
- }
- else
+ if (ins != INS_xchg)
{
- // Must evalute location into a register.
- genCodeForTree(location, needReg, RBM_NONE);
- assert(location->gtFlags && GTF_REG_VAL);
- regSet.rsMarkRegUsed(location);
-
- // xadd destroys this argument, so force it into a scratch register
- reg = regSet.rsPickFreeReg();
- genComputeReg(value, genRegMask(reg), RegSet::EXACT_REG, RegSet::KEEP_REG);
- regSet.rsLockUsedReg(genRegMask(value->gtRegNum));
- genRecoverReg(location, RBM_NONE, RegSet::KEEP_REG);
- regSet.rsUnlockUsedReg(genRegMask(value->gtRegNum));
-
- if (ins != INS_xchg)
- {
- //xchg implies the lock prefix, but xadd and add require it.
- instGen(INS_lock);
- }
+ // xchg implies the lock prefix, but xadd and add require it.
+ instGen(INS_lock);
+ }
- instEmit_RM_RV(ins, EA_4BYTE, location, reg, 0);
+ instEmit_RM_RV(ins, EA_4BYTE, location, reg, 0);
- genReleaseReg(value);
- regTracker.rsTrackRegTrash(reg);
- genReleaseReg(location);
- }
+ genReleaseReg(value);
+ regTracker.rsTrackRegTrash(reg);
+ genReleaseReg(location);
}
+ }
- //The flags are equal to the target of the tree (i.e. the result of the add), not to the
- //result in the register. If tree is actually GT_IND->GT_ADDR->GT_LCL_VAR, we could use
- //that information to set the flags. Doesn't seem like there is a good reason for that.
- //Therefore, trash the flags.
- genFlagsEqualToNone();
+ // The flags are equal to the target of the tree (i.e. the result of the add), not to the
+ // result in the register. If tree is actually GT_IND->GT_ADDR->GT_LCL_VAR, we could use
+ // that information to set the flags. Doesn't seem like there is a good reason for that.
+ // Therefore, trash the flags.
+ genFlagsEqualToNone();
- if (ins == INS_add)
- {
- // If the operator was add, then we were called from the GT_LOCKADD
- // case. In that case we don't use the result, so we don't need to
- // update anything.
- genUpdateLife(tree);
- }
- else
- {
- genCodeForTree_DONE(tree, reg);
- }
+ if (ins == INS_add)
+ {
+ // If the operator was add, then we were called from the GT_LOCKADD
+ // case. In that case we don't use the result, so we don't need to
+ // update anything.
+ genUpdateLife(tree);
+ }
+ else
+ {
+ genCodeForTree_DONE(tree, reg);
}
+ }
return;
#else // !_TARGET_XARCH_
@@ -10586,11 +10371,10 @@ LockBinOpCommon:
case GT_ARR_LENGTH:
{
// Make the corresponding ind(a + c) node, and do codegen for that.
- GenTreePtr addr = compiler->gtNewOperNode(GT_ADD, TYP_BYREF,
- tree->gtArrLen.ArrRef(),
- compiler->gtNewIconNode(tree->AsArrLen()->ArrLenOffset()));
+ GenTreePtr addr = compiler->gtNewOperNode(GT_ADD, TYP_BYREF, tree->gtArrLen.ArrRef(),
+ compiler->gtNewIconNode(tree->AsArrLen()->ArrLenOffset()));
tree->SetOper(GT_IND);
- tree->gtFlags |= GTF_IND_ARR_LEN; // Record that this node represents an array length expression.
+ tree->gtFlags |= GTF_IND_ARR_LEN; // Record that this node represents an array length expression.
assert(tree->TypeGet() == TYP_INT);
tree->gtOp.gtOp1 = addr;
genCodeForTree(tree, destReg, bestReg);
@@ -10614,24 +10398,21 @@ LockBinOpCommon:
#pragma warning(pop) // End suppress PREFast warning about overly large function
#endif
-
-regNumber CodeGen::genIntegerCast(GenTree *tree,
- regMaskTP needReg,
- regMaskTP bestReg)
+regNumber CodeGen::genIntegerCast(GenTree* tree, regMaskTP needReg, regMaskTP bestReg)
{
instruction ins;
emitAttr size;
bool unsv;
bool andv = false;
regNumber reg;
- GenTreePtr op1 = tree->gtOp.gtOp1->gtEffectiveVal();
- var_types dstType = tree->CastToType();
+ GenTreePtr op1 = tree->gtOp.gtOp1->gtEffectiveVal();
+ var_types dstType = tree->CastToType();
var_types srcType = op1->TypeGet();
- if (genTypeSize(srcType) < genTypeSize(dstType))
+ if (genTypeSize(srcType) < genTypeSize(dstType))
{
// Widening cast
-
+
/* we need the source size */
size = EA_ATTR(genTypeSize(srcType));
@@ -10639,7 +10420,7 @@ regNumber CodeGen::genIntegerCast(GenTree *tree,
noway_assert(size < EA_PTRSIZE);
unsv = varTypeIsUnsigned(srcType);
- ins = ins_Move_Extend(srcType, op1->InReg());
+ ins = ins_Move_Extend(srcType, op1->InReg());
/*
Special case: for a cast of byte to char we first
@@ -10671,8 +10452,7 @@ regNumber CodeGen::genIntegerCast(GenTree *tree,
if (op1->InReg())
{
regMaskTP op1RegMask = genRegMask(op1->gtRegNum);
- if ( (((op1RegMask & bestReg) != 0) || (bestReg == 0)) &&
- ((op1RegMask & regSet.rsRegMaskFree()) != 0) )
+ if ((((op1RegMask & bestReg) != 0) || (bestReg == 0)) && ((op1RegMask & regSet.rsRegMaskFree()) != 0))
{
bestReg = op1RegMask;
}
@@ -10680,9 +10460,7 @@ regNumber CodeGen::genIntegerCast(GenTree *tree,
/* Is the value sitting in a non-byte-addressable register? */
- if (op1->InReg() &&
- (size == EA_1BYTE) &&
- !isByteReg(op1->gtRegNum))
+ if (op1->InReg() && (size == EA_1BYTE) && !isByteReg(op1->gtRegNum))
{
if (unsv)
{
@@ -10696,7 +10474,7 @@ regNumber CodeGen::genIntegerCast(GenTree *tree,
{
/* Move the value into a byte register */
- reg = regSet.rsGrabReg(RBM_BYTE_REGS);
+ reg = regSet.rsGrabReg(RBM_BYTE_REGS);
}
if (reg != op1->gtRegNum)
@@ -10719,7 +10497,7 @@ regNumber CodeGen::genIntegerCast(GenTree *tree,
// if we (might) need to set the flags and the value is in the same register
// and we have an unsigned value then use AND instead of MOVZX
- if (tree->gtSetFlags() && unsv && op1->InReg() && (op1->gtRegNum == reg))
+ if (tree->gtSetFlags() && unsv && op1->InReg() && (op1->gtRegNum == reg))
{
#ifdef _TARGET_X86_
noway_assert(ins == INS_movzx);
@@ -10734,10 +10512,10 @@ regNumber CodeGen::genIntegerCast(GenTree *tree,
/* Generate "and reg, MASK */
- insFlags flags = tree->gtSetFlags() ? INS_FLAGS_SET : INS_FLAGS_DONT_CARE;
+ insFlags flags = tree->gtSetFlags() ? INS_FLAGS_SET : INS_FLAGS_DONT_CARE;
inst_RV_IV(INS_AND, reg, (size == EA_1BYTE) ? 0xFF : 0xFFFF, EA_4BYTE, flags);
- if (tree->gtSetFlags())
+ if (tree->gtSetFlags())
genFlagsEqualToReg(tree, reg);
}
else
@@ -10752,15 +10530,15 @@ regNumber CodeGen::genIntegerCast(GenTree *tree,
/* Mask off high bits for cast from byte to char */
- if (andv)
+ if (andv)
{
#ifdef _TARGET_XARCH_
noway_assert(genTypeSize(dstType) == 2 && ins == INS_movsx);
#endif
- insFlags flags = tree->gtSetFlags() ? INS_FLAGS_SET : INS_FLAGS_DONT_CARE;
+ insFlags flags = tree->gtSetFlags() ? INS_FLAGS_SET : INS_FLAGS_DONT_CARE;
inst_RV_IV(INS_AND, reg, 0xFFFF, EA_4BYTE, flags);
- if (tree->gtSetFlags())
+ if (tree->gtSetFlags())
genFlagsEqualToReg(tree, reg);
}
}
@@ -10769,18 +10547,16 @@ regNumber CodeGen::genIntegerCast(GenTree *tree,
return reg;
}
-void CodeGen::genCodeForNumericCast(GenTreePtr tree,
- regMaskTP destReg,
- regMaskTP bestReg)
+void CodeGen::genCodeForNumericCast(GenTreePtr tree, regMaskTP destReg, regMaskTP bestReg)
{
- GenTreePtr op1 = tree->gtOp.gtOp1;
- var_types dstType = tree->CastToType();
- var_types baseType = TYP_INT;
- regNumber reg = DUMMY_INIT(REG_CORRUPT);
- regMaskTP needReg = destReg;
- regMaskTP addrReg;
- emitAttr size;
- BOOL unsv;
+ GenTreePtr op1 = tree->gtOp.gtOp1;
+ var_types dstType = tree->CastToType();
+ var_types baseType = TYP_INT;
+ regNumber reg = DUMMY_INIT(REG_CORRUPT);
+ regMaskTP needReg = destReg;
+ regMaskTP addrReg;
+ emitAttr size;
+ BOOL unsv;
/*
* Constant casts should have been folded earlier
@@ -10788,11 +10564,8 @@ void CodeGen::genCodeForNumericCast(GenTreePtr tree,
* We don't do this optimization for debug code/no optimization
*/
- noway_assert((op1->gtOper != GT_CNS_INT &&
- op1->gtOper != GT_CNS_LNG &&
- op1->gtOper != GT_CNS_DBL) ||
- tree->gtOverflow() ||
- (op1->gtOper == GT_CNS_DBL && !_finite(op1->gtDblCon.gtDconVal)) ||
+ noway_assert((op1->gtOper != GT_CNS_INT && op1->gtOper != GT_CNS_LNG && op1->gtOper != GT_CNS_DBL) ||
+ tree->gtOverflow() || (op1->gtOper == GT_CNS_DBL && !_finite(op1->gtDblCon.gtDconVal)) ||
!compiler->opts.OptEnabled(CLFLG_CONSTANTFOLD));
noway_assert(dstType != TYP_VOID);
@@ -10801,314 +10574,313 @@ void CodeGen::genCodeForNumericCast(GenTreePtr tree,
switch (op1->TypeGet())
{
- case TYP_LONG:
+ case TYP_LONG:
- /* Special case: the long is generated via the mod of long
- with an int. This is really an int and need not be
- converted to a reg pair. NOTE: the flag only indicates
- that this is a case to TYP_INT, it hasn't actually
- verified the second operand of the MOD! */
+ /* Special case: the long is generated via the mod of long
+ with an int. This is really an int and need not be
+ converted to a reg pair. NOTE: the flag only indicates
+ that this is a case to TYP_INT, it hasn't actually
+ verified the second operand of the MOD! */
- if (((op1->gtOper == GT_MOD) || (op1->gtOper == GT_UMOD)) &&
- (op1->gtFlags & GTF_MOD_INT_RESULT))
- {
+ if (((op1->gtOper == GT_MOD) || (op1->gtOper == GT_UMOD)) && (op1->gtFlags & GTF_MOD_INT_RESULT))
+ {
- /* Verify that the op2 of the mod node is
- 1) An integer tree, or
- 2) A long constant that is small enough to fit in an integer
- */
+ /* Verify that the op2 of the mod node is
+ 1) An integer tree, or
+ 2) A long constant that is small enough to fit in an integer
+ */
- GenTreePtr modop2 = op1->gtOp.gtOp2;
- if ((genActualType(modop2->gtType) == TYP_INT) ||
- ((modop2->gtOper == GT_CNS_LNG) &&
- (modop2->gtLngCon.gtLconVal == (int)modop2->gtLngCon.gtLconVal)))
- {
- genCodeForTree(op1, destReg, bestReg);
+ GenTreePtr modop2 = op1->gtOp.gtOp2;
+ if ((genActualType(modop2->gtType) == TYP_INT) ||
+ ((modop2->gtOper == GT_CNS_LNG) && (modop2->gtLngCon.gtLconVal == (int)modop2->gtLngCon.gtLconVal)))
+ {
+ genCodeForTree(op1, destReg, bestReg);
#ifdef _TARGET_64BIT_
- reg = op1->gtRegNum;
-#else // _TARGET_64BIT_
- reg = genRegPairLo(op1->gtRegPair);
+ reg = op1->gtRegNum;
+#else // _TARGET_64BIT_
+ reg = genRegPairLo(op1->gtRegPair);
#endif //_TARGET_64BIT_
- genCodeForTree_DONE(tree, reg);
- return;
+ genCodeForTree_DONE(tree, reg);
+ return;
+ }
}
- }
-
- /* Make the operand addressable. When gtOverflow() is true,
- hold on to the addrReg as we will need it to access the higher dword */
-
- op1 = genCodeForCommaTree(op1); // Strip off any commas (necessary, since we seem to generate code for op1 twice!)
- // See, e.g., the TYP_INT case below...
- addrReg = genMakeAddressable2(op1, 0, tree->gtOverflow() ? RegSet::KEEP_REG : RegSet::FREE_REG, false);
+ /* Make the operand addressable. When gtOverflow() is true,
+ hold on to the addrReg as we will need it to access the higher dword */
- /* Load the lower half of the value into some register */
+ op1 = genCodeForCommaTree(op1); // Strip off any commas (necessary, since we seem to generate code for op1
+ // twice!)
+ // See, e.g., the TYP_INT case below...
- if (op1->gtFlags & GTF_REG_VAL)
- {
- /* Can we simply use the low part of the value? */
- reg = genRegPairLo(op1->gtRegPair);
+ addrReg = genMakeAddressable2(op1, 0, tree->gtOverflow() ? RegSet::KEEP_REG : RegSet::FREE_REG, false);
- if (tree->gtOverflow())
- goto REG_OK;
+ /* Load the lower half of the value into some register */
- regMaskTP loMask;
- loMask = genRegMask(reg);
- if (loMask & regSet.rsRegMaskFree())
- bestReg = loMask;
- }
+ if (op1->gtFlags & GTF_REG_VAL)
+ {
+ /* Can we simply use the low part of the value? */
+ reg = genRegPairLo(op1->gtRegPair);
- // for cast overflow we need to preserve addrReg for testing the hiDword
- // so we lock it to prevent regSet.rsPickReg from picking it.
- if (tree->gtOverflow())
- regSet.rsLockUsedReg(addrReg);
+ if (tree->gtOverflow())
+ goto REG_OK;
- reg = regSet.rsPickReg(needReg, bestReg);
+ regMaskTP loMask;
+ loMask = genRegMask(reg);
+ if (loMask & regSet.rsRegMaskFree())
+ bestReg = loMask;
+ }
- if (tree->gtOverflow())
- regSet.rsUnlockUsedReg(addrReg);
+ // for cast overflow we need to preserve addrReg for testing the hiDword
+ // so we lock it to prevent regSet.rsPickReg from picking it.
+ if (tree->gtOverflow())
+ regSet.rsLockUsedReg(addrReg);
- noway_assert(genStillAddressable(op1));
+ reg = regSet.rsPickReg(needReg, bestReg);
-REG_OK:
- if (((op1->gtFlags & GTF_REG_VAL) == 0) || (reg != genRegPairLo(op1->gtRegPair)))
- {
- /* Generate "mov reg, [addr-mode]" */
- inst_RV_TT(ins_Load(TYP_INT), reg, op1);
- }
+ if (tree->gtOverflow())
+ regSet.rsUnlockUsedReg(addrReg);
- /* conv.ovf.i8i4, or conv.ovf.u8u4 */
+ noway_assert(genStillAddressable(op1));
- if (tree->gtOverflow())
- {
- regNumber hiReg = (op1->gtFlags & GTF_REG_VAL) ? genRegPairHi(op1->gtRegPair)
- : REG_NA;
+ REG_OK:
+ if (((op1->gtFlags & GTF_REG_VAL) == 0) || (reg != genRegPairLo(op1->gtRegPair)))
+ {
+ /* Generate "mov reg, [addr-mode]" */
+ inst_RV_TT(ins_Load(TYP_INT), reg, op1);
+ }
- emitJumpKind jmpNotEqual = genJumpKindForOper(GT_NE, CK_SIGNED);
- emitJumpKind jmpLTS = genJumpKindForOper(GT_LT, CK_SIGNED);
+ /* conv.ovf.i8i4, or conv.ovf.u8u4 */
- switch (dstType)
+ if (tree->gtOverflow())
{
- case TYP_INT: // conv.ovf.i8.i4
- /* Generate the following sequence
-
- test loDWord, loDWord // set flags
- jl neg
- pos: test hiDWord, hiDWord // set flags
- jne ovf
- jmp done
- neg: cmp hiDWord, 0xFFFFFFFF
- jne ovf
- done:
+ regNumber hiReg = (op1->gtFlags & GTF_REG_VAL) ? genRegPairHi(op1->gtRegPair) : REG_NA;
- */
+ emitJumpKind jmpNotEqual = genJumpKindForOper(GT_NE, CK_SIGNED);
+ emitJumpKind jmpLTS = genJumpKindForOper(GT_LT, CK_SIGNED);
- instGen_Compare_Reg_To_Zero(EA_4BYTE, reg);
- if (tree->gtFlags & GTF_UNSIGNED) // conv.ovf.u8.i4 (i4 > 0 and upper bits 0)
+ switch (dstType)
{
- genJumpToThrowHlpBlk(jmpLTS, SCK_OVERFLOW);
- goto UPPER_BITS_ZERO;
- }
+ case TYP_INT: // conv.ovf.i8.i4
+ /* Generate the following sequence
+
+ test loDWord, loDWord // set flags
+ jl neg
+ pos: test hiDWord, hiDWord // set flags
+ jne ovf
+ jmp done
+ neg: cmp hiDWord, 0xFFFFFFFF
+ jne ovf
+ done:
+
+ */
+
+ instGen_Compare_Reg_To_Zero(EA_4BYTE, reg);
+ if (tree->gtFlags & GTF_UNSIGNED) // conv.ovf.u8.i4 (i4 > 0 and upper bits 0)
+ {
+ genJumpToThrowHlpBlk(jmpLTS, SCK_OVERFLOW);
+ goto UPPER_BITS_ZERO;
+ }
#if CPU_LOAD_STORE_ARCH
- // This is tricky.
- // We will generate code like
- // if (...)
- // {
- // ...
- // }
- // else
- // {
- // ...
- // }
- // We load the tree op1 into regs when we generate code for if clause.
- // When we generate else clause, we see the tree is already loaded into reg, and start use it directly.
- // Well, when the code is run, we may execute else clause without going through if clause.
- //
- genCodeForTree(op1, 0);
+ // This is tricky.
+ // We will generate code like
+ // if (...)
+ // {
+ // ...
+ // }
+ // else
+ // {
+ // ...
+ // }
+ // We load the tree op1 into regs when we generate code for if clause.
+ // When we generate else clause, we see the tree is already loaded into reg, and start use it
+ // directly.
+ // Well, when the code is run, we may execute else clause without going through if clause.
+ //
+ genCodeForTree(op1, 0);
#endif
- BasicBlock * neg;
- BasicBlock * done;
+ BasicBlock* neg;
+ BasicBlock* done;
- neg = genCreateTempLabel();
- done = genCreateTempLabel();
+ neg = genCreateTempLabel();
+ done = genCreateTempLabel();
- // Is the loDWord positive or negative
- inst_JMP(jmpLTS, neg);
+ // Is the loDWord positive or negative
+ inst_JMP(jmpLTS, neg);
- // If loDWord is positive, hiDWord should be 0 (sign extended loDWord)
+ // If loDWord is positive, hiDWord should be 0 (sign extended loDWord)
- if (hiReg < REG_STK)
- {
- instGen_Compare_Reg_To_Zero(EA_4BYTE, hiReg);
- }
- else
- {
- inst_TT_IV(INS_cmp, op1, 0x00000000, 4);
- }
+ if (hiReg < REG_STK)
+ {
+ instGen_Compare_Reg_To_Zero(EA_4BYTE, hiReg);
+ }
+ else
+ {
+ inst_TT_IV(INS_cmp, op1, 0x00000000, 4);
+ }
- genJumpToThrowHlpBlk(jmpNotEqual, SCK_OVERFLOW);
- inst_JMP(EJ_jmp, done);
+ genJumpToThrowHlpBlk(jmpNotEqual, SCK_OVERFLOW);
+ inst_JMP(EJ_jmp, done);
- // If loDWord is negative, hiDWord should be -1 (sign extended loDWord)
+ // If loDWord is negative, hiDWord should be -1 (sign extended loDWord)
- genDefineTempLabel(neg);
+ genDefineTempLabel(neg);
- if (hiReg < REG_STK)
- {
- inst_RV_IV(INS_cmp, hiReg, 0xFFFFFFFFL, EA_4BYTE);
- }
- else
- {
- inst_TT_IV(INS_cmp, op1, 0xFFFFFFFFL, 4);
- }
- genJumpToThrowHlpBlk(jmpNotEqual, SCK_OVERFLOW);
+ if (hiReg < REG_STK)
+ {
+ inst_RV_IV(INS_cmp, hiReg, 0xFFFFFFFFL, EA_4BYTE);
+ }
+ else
+ {
+ inst_TT_IV(INS_cmp, op1, 0xFFFFFFFFL, 4);
+ }
+ genJumpToThrowHlpBlk(jmpNotEqual, SCK_OVERFLOW);
- // Done
+ // Done
- genDefineTempLabel(done);
+ genDefineTempLabel(done);
- break;
+ break;
- case TYP_UINT: // conv.ovf.u8u4
-UPPER_BITS_ZERO:
- // Just check that the upper DWord is 0
+ case TYP_UINT: // conv.ovf.u8u4
+ UPPER_BITS_ZERO:
+ // Just check that the upper DWord is 0
- if (hiReg < REG_STK)
- {
- instGen_Compare_Reg_To_Zero(EA_4BYTE, hiReg); // set flags
- }
- else
- {
- inst_TT_IV(INS_cmp, op1, 0, 4);
+ if (hiReg < REG_STK)
+ {
+ instGen_Compare_Reg_To_Zero(EA_4BYTE, hiReg); // set flags
+ }
+ else
+ {
+ inst_TT_IV(INS_cmp, op1, 0, 4);
+ }
+
+ genJumpToThrowHlpBlk(jmpNotEqual, SCK_OVERFLOW);
+ break;
+
+ default:
+ noway_assert(!"Unexpected dstType");
+ break;
}
-
- genJumpToThrowHlpBlk(jmpNotEqual, SCK_OVERFLOW);
- break;
- default:
- noway_assert(!"Unexpected dstType");
- break;
+ genDoneAddressable(op1, addrReg, RegSet::KEEP_REG);
}
- genDoneAddressable(op1, addrReg, RegSet::KEEP_REG);
- }
-
- regTracker.rsTrackRegTrash(reg);
- genDoneAddressable(op1, addrReg, RegSet::FREE_REG);
+ regTracker.rsTrackRegTrash(reg);
+ genDoneAddressable(op1, addrReg, RegSet::FREE_REG);
- genCodeForTree_DONE(tree, reg);
- return;
+ genCodeForTree_DONE(tree, reg);
+ return;
- case TYP_BOOL:
- case TYP_BYTE:
- case TYP_SHORT:
- case TYP_CHAR:
- case TYP_UBYTE:
- break;
+ case TYP_BOOL:
+ case TYP_BYTE:
+ case TYP_SHORT:
+ case TYP_CHAR:
+ case TYP_UBYTE:
+ break;
- case TYP_UINT:
- case TYP_INT:
- break;
+ case TYP_UINT:
+ case TYP_INT:
+ break;
#if FEATURE_STACK_FP_X87
- case TYP_FLOAT:
- NO_WAY("OPCAST from TYP_FLOAT should have been converted into a helper call");
- break;
-
- case TYP_DOUBLE:
- if (compiler->opts.compCanUseSSE2)
- {
- // do the SSE2 based cast inline
- // getting the fp operand
-
- regMaskTP addrRegInt = 0;
- regMaskTP addrRegFlt = 0;
+ case TYP_FLOAT:
+ NO_WAY("OPCAST from TYP_FLOAT should have been converted into a helper call");
+ break;
- // make the operand addressable
- // We don't want to collapse constant doubles into floats, as the SSE2 instruction
- // operates on doubles. Note that these (casts from constant doubles) usually get
- // folded, but we don't do it for some cases (infinitys, etc). So essentially this
- // shouldn't affect performance or size at all. We're fixing this for #336067
- op1 = genMakeAddressableStackFP(op1, &addrRegInt, &addrRegFlt, false);
- if (!addrRegFlt && !op1->IsRegVar())
+ case TYP_DOUBLE:
+ if (compiler->opts.compCanUseSSE2)
{
- // we have the address
+ // do the SSE2 based cast inline
+ // getting the fp operand
- inst_RV_TT(INS_movsdsse2, REG_XMM0, op1, 0, EA_8BYTE);
- genDoneAddressableStackFP(op1, addrRegInt, addrRegFlt, RegSet::KEEP_REG);
- genUpdateLife(op1);
-
- reg = regSet.rsPickReg(needReg);
- getEmitter()->emitIns_R_R(INS_cvttsd2si, EA_8BYTE, reg, REG_XMM0);
+ regMaskTP addrRegInt = 0;
+ regMaskTP addrRegFlt = 0;
- regTracker.rsTrackRegTrash(reg);
- genCodeForTree_DONE(tree, reg);
- }
- else
- {
- // we will need to use a temp to get it into the xmm reg
- var_types typeTemp = op1->TypeGet();
- TempDsc * temp = compiler->tmpGetTemp(typeTemp);
+ // make the operand addressable
+ // We don't want to collapse constant doubles into floats, as the SSE2 instruction
+ // operates on doubles. Note that these (casts from constant doubles) usually get
+ // folded, but we don't do it for some cases (infinitys, etc). So essentially this
+ // shouldn't affect performance or size at all. We're fixing this for #336067
+ op1 = genMakeAddressableStackFP(op1, &addrRegInt, &addrRegFlt, false);
+ if (!addrRegFlt && !op1->IsRegVar())
+ {
+ // we have the address
- size = EA_ATTR(genTypeSize(typeTemp));
+ inst_RV_TT(INS_movsdsse2, REG_XMM0, op1, 0, EA_8BYTE);
+ genDoneAddressableStackFP(op1, addrRegInt, addrRegFlt, RegSet::KEEP_REG);
+ genUpdateLife(op1);
- if (addrRegFlt )
- {
- // On the fp stack; Take reg to top of stack
+ reg = regSet.rsPickReg(needReg);
+ getEmitter()->emitIns_R_R(INS_cvttsd2si, EA_8BYTE, reg, REG_XMM0);
- FlatFPX87_MoveToTOS(&compCurFPState, op1->gtRegNum);
+ regTracker.rsTrackRegTrash(reg);
+ genCodeForTree_DONE(tree, reg);
}
else
{
- // op1->IsRegVar()
- // pick a register
- reg = regSet.PickRegFloat();
- if (!op1->IsRegVarDeath())
+ // we will need to use a temp to get it into the xmm reg
+ var_types typeTemp = op1->TypeGet();
+ TempDsc* temp = compiler->tmpGetTemp(typeTemp);
+
+ size = EA_ATTR(genTypeSize(typeTemp));
+
+ if (addrRegFlt)
{
- // Load it on the fp stack
- genLoadStackFP(op1, reg);
+ // On the fp stack; Take reg to top of stack
+
+ FlatFPX87_MoveToTOS(&compCurFPState, op1->gtRegNum);
}
else
{
- // if it's dying, genLoadStackFP just renames it and then we move reg to TOS
- genLoadStackFP(op1, reg);
- FlatFPX87_MoveToTOS(&compCurFPState, reg);
+ // op1->IsRegVar()
+ // pick a register
+ reg = regSet.PickRegFloat();
+ if (!op1->IsRegVarDeath())
+ {
+ // Load it on the fp stack
+ genLoadStackFP(op1, reg);
+ }
+ else
+ {
+ // if it's dying, genLoadStackFP just renames it and then we move reg to TOS
+ genLoadStackFP(op1, reg);
+ FlatFPX87_MoveToTOS(&compCurFPState, reg);
+ }
}
- }
- // pop it off the fp stack
- compCurFPState.Pop();
+ // pop it off the fp stack
+ compCurFPState.Pop();
- getEmitter()->emitIns_S(INS_fstp, size, temp->tdTempNum(), 0);
- // pick a reg
- reg = regSet.rsPickReg(needReg);
+ getEmitter()->emitIns_S(INS_fstp, size, temp->tdTempNum(), 0);
+ // pick a reg
+ reg = regSet.rsPickReg(needReg);
- inst_RV_ST(INS_movsdsse2, REG_XMM0, temp, 0, TYP_DOUBLE, EA_8BYTE);
- getEmitter()->emitIns_R_R(INS_cvttsd2si, EA_8BYTE, reg, REG_XMM0);
+ inst_RV_ST(INS_movsdsse2, REG_XMM0, temp, 0, TYP_DOUBLE, EA_8BYTE);
+ getEmitter()->emitIns_R_R(INS_cvttsd2si, EA_8BYTE, reg, REG_XMM0);
- // done..release the temp
- compiler->tmpRlsTemp(temp);
+ // done..release the temp
+ compiler->tmpRlsTemp(temp);
- // the reg is now trashed
- regTracker.rsTrackRegTrash(reg);
- genDoneAddressableStackFP(op1, addrRegInt, addrRegFlt, RegSet::KEEP_REG);
- genUpdateLife(op1);
- genCodeForTree_DONE(tree, reg);
+ // the reg is now trashed
+ regTracker.rsTrackRegTrash(reg);
+ genDoneAddressableStackFP(op1, addrRegInt, addrRegFlt, RegSet::KEEP_REG);
+ genUpdateLife(op1);
+ genCodeForTree_DONE(tree, reg);
+ }
}
- }
#else
- case TYP_FLOAT:
- case TYP_DOUBLE:
- genCodeForTreeFloat(tree, needReg, bestReg);
+ case TYP_FLOAT:
+ case TYP_DOUBLE:
+ genCodeForTreeFloat(tree, needReg, bestReg);
#endif // FEATURE_STACK_FP_X87
- return;
+ return;
- default:
- noway_assert(!"unexpected cast type");
+ default:
+ noway_assert(!"unexpected cast type");
}
if (tree->gtOverflow())
@@ -11125,46 +10897,49 @@ UPPER_BITS_ZERO:
switch (dstType)
{
- case TYP_BYTE:
- typeMask = ssize_t((int)0xFFFFFF80);
- typeMin = SCHAR_MIN; typeMax = SCHAR_MAX;
- unsv = (tree->gtFlags & GTF_UNSIGNED);
- break;
- case TYP_SHORT:
- typeMask = ssize_t((int)0xFFFF8000);
- typeMin = SHRT_MIN; typeMax = SHRT_MAX;
- unsv = (tree->gtFlags & GTF_UNSIGNED);
- break;
- case TYP_INT:
- typeMask = ssize_t((int)0x80000000L);
+ case TYP_BYTE:
+ typeMask = ssize_t((int)0xFFFFFF80);
+ typeMin = SCHAR_MIN;
+ typeMax = SCHAR_MAX;
+ unsv = (tree->gtFlags & GTF_UNSIGNED);
+ break;
+ case TYP_SHORT:
+ typeMask = ssize_t((int)0xFFFF8000);
+ typeMin = SHRT_MIN;
+ typeMax = SHRT_MAX;
+ unsv = (tree->gtFlags & GTF_UNSIGNED);
+ break;
+ case TYP_INT:
+ typeMask = ssize_t((int)0x80000000L);
#ifdef _TARGET_64BIT_
- unsv = (tree->gtFlags & GTF_UNSIGNED);
- typeMin = INT_MIN; typeMax = INT_MAX;
+ unsv = (tree->gtFlags & GTF_UNSIGNED);
+ typeMin = INT_MIN;
+ typeMax = INT_MAX;
#else // _TARGET_64BIT_
- noway_assert((tree->gtFlags & GTF_UNSIGNED) != 0);
- unsv = true;
+ noway_assert((tree->gtFlags & GTF_UNSIGNED) != 0);
+ unsv = true;
#endif // _TARGET_64BIT_
- break;
- case TYP_UBYTE:
- unsv = true;
- typeMask = ssize_t((int)0xFFFFFF00L);
- break;
- case TYP_CHAR:
- unsv = true;
- typeMask = ssize_t((int)0xFFFF0000L);
- break;
- case TYP_UINT:
- unsv = true;
+ break;
+ case TYP_UBYTE:
+ unsv = true;
+ typeMask = ssize_t((int)0xFFFFFF00L);
+ break;
+ case TYP_CHAR:
+ unsv = true;
+ typeMask = ssize_t((int)0xFFFF0000L);
+ break;
+ case TYP_UINT:
+ unsv = true;
#ifdef _TARGET_64BIT_
- typeMask = 0xFFFFFFFF00000000LL;
-#else // _TARGET_64BIT_
- typeMask = 0x80000000L;
- noway_assert((tree->gtFlags & GTF_UNSIGNED) == 0);
+ typeMask = 0xFFFFFFFF00000000LL;
+#else // _TARGET_64BIT_
+ typeMask = 0x80000000L;
+ noway_assert((tree->gtFlags & GTF_UNSIGNED) == 0);
#endif // _TARGET_64BIT_
- break;
- default:
- NO_WAY("Unknown type");
- return;
+ break;
+ default:
+ NO_WAY("Unknown type");
+ return;
}
// If we just have to check a mask.
@@ -11217,19 +10992,17 @@ UPPER_BITS_ZERO:
* Generate code for a leaf node of type GT_ADDR
*/
-void CodeGen::genCodeForTreeSmpOp_GT_ADDR(GenTreePtr tree,
- regMaskTP destReg,
- regMaskTP bestReg)
+void CodeGen::genCodeForTreeSmpOp_GT_ADDR(GenTreePtr tree, regMaskTP destReg, regMaskTP bestReg)
{
genTreeOps oper = tree->OperGet();
const var_types treeType = tree->TypeGet();
GenTreePtr op1;
regNumber reg;
- regMaskTP needReg = destReg;
+ regMaskTP needReg = destReg;
regMaskTP addrReg;
#ifdef DEBUG
- reg = (regNumber)0xFEEFFAAF; // to detect uninitialized use
+ reg = (regNumber)0xFEEFFAAF; // to detect uninitialized use
addrReg = 0xDEADCAFE;
#endif
@@ -11245,7 +11018,8 @@ void CodeGen::genCodeForTreeSmpOp_GT_ADDR(GenTreePtr tree,
}
// (tree=op1, needReg=0, keepReg=RegSet::FREE_REG, smallOK=true)
- if (oper == GT_ARR_ELEM) {
+ if (oper == GT_ARR_ELEM)
+ {
// To get the address of the array element,
// we first call genMakeAddrArrElem to make the element addressable.
// (That is, for example, we first emit code to calculate EBX, and EAX.)
@@ -11260,7 +11034,7 @@ void CodeGen::genCodeForTreeSmpOp_GT_ADDR(GenTreePtr tree,
addrReg = genMakeAddressable(op1, 0, RegSet::FREE_REG, true);
}
- noway_assert( treeType == TYP_BYREF || treeType == TYP_I_IMPL );
+ noway_assert(treeType == TYP_BYREF || treeType == TYP_I_IMPL);
// We want to reuse one of the scratch registers that were used
// in forming the address mode as the target register for the lea.
@@ -11268,7 +11042,7 @@ void CodeGen::genCodeForTreeSmpOp_GT_ADDR(GenTreePtr tree,
// form the address (i.e. addrReg), we calculate the scratch register
// to use as the target register for the LEA
- bestReg = regSet.rsUseIfZero (bestReg, addrReg);
+ bestReg = regSet.rsUseIfZero(bestReg, addrReg);
bestReg = regSet.rsNarrowHint(bestReg, addrReg);
/* Even if addrReg is regSet.rsRegMaskCanGrab(), regSet.rsPickReg() won't spill
@@ -11295,13 +11069,12 @@ void CodeGen::genCodeForTreeSmpOp_GT_ADDR(GenTreePtr tree,
// gcInfo.gcMarkRegSetNpt(genRegMask(reg));
noway_assert((gcInfo.gcRegGCrefSetCur & genRegMask(reg)) == 0);
- regTracker.rsTrackRegTrash(reg); // reg does have foldable value in it
+ regTracker.rsTrackRegTrash(reg); // reg does have foldable value in it
gcInfo.gcMarkRegPtrVal(reg, treeType);
genCodeForTree_DONE(tree, reg);
}
-
#ifdef _TARGET_ARM_
/*****************************************************************************
@@ -11312,7 +11085,7 @@ void CodeGen::genCodeForTreeSmpOp_GT_ADDR(GenTreePtr tree,
* isLoadIntoFlt - Perform a load operation if "true" or store if "false."
*
*/
-void CodeGen::genLdStFltRetRegsPromotedVar(LclVarDsc* varDsc, bool isLoadIntoFlt)
+void CodeGen::genLdStFltRetRegsPromotedVar(LclVarDsc* varDsc, bool isLoadIntoFlt)
{
regNumber curReg = REG_FLOATRET;
@@ -11354,12 +11127,12 @@ void CodeGen::genLdStFltRetRegsPromotedVar(LclVarDsc* varDsc, boo
}
}
-void CodeGen::genLoadIntoFltRetRegs(GenTreePtr tree)
+void CodeGen::genLoadIntoFltRetRegs(GenTreePtr tree)
{
assert(tree->TypeGet() == TYP_STRUCT);
assert(tree->gtOper == GT_LCL_VAR);
LclVarDsc* varDsc = compiler->lvaTable + tree->gtLclVarCommon.gtLclNum;
- int slots = varDsc->lvSize() / REGSIZE_BYTES;
+ int slots = varDsc->lvSize() / REGSIZE_BYTES;
if (varDsc->lvPromoted)
{
genLdStFltRetRegsPromotedVar(varDsc, true);
@@ -11369,12 +11142,8 @@ void CodeGen::genLoadIntoFltRetRegs(GenTreePtr tree)
if (slots <= 2)
{
// Use the load float/double instruction.
- inst_RV_TT(
- ins_Load((slots == 1) ? TYP_FLOAT : TYP_DOUBLE),
- REG_FLOATRET,
- tree,
- 0,
- (slots == 1) ? EA_4BYTE : EA_8BYTE);
+ inst_RV_TT(ins_Load((slots == 1) ? TYP_FLOAT : TYP_DOUBLE), REG_FLOATRET, tree, 0,
+ (slots == 1) ? EA_4BYTE : EA_8BYTE);
}
else
{
@@ -11388,7 +11157,7 @@ void CodeGen::genLoadIntoFltRetRegs(GenTreePtr tree)
genMarkTreeInReg(tree, REG_FLOATRET);
}
-void CodeGen::genStoreFromFltRetRegs(GenTreePtr tree)
+void CodeGen::genStoreFromFltRetRegs(GenTreePtr tree)
{
assert(tree->TypeGet() == TYP_STRUCT);
assert(tree->OperGet() == GT_ASG);
@@ -11420,7 +11189,7 @@ void CodeGen::genStoreFromFltRetRegs(GenTreePtr tree)
regMaskTP mask = ((retMask >> REG_FLOATRET) + 1);
assert((mask & (mask - 1)) == 0);
assert(mask <= (1 << MAX_HFA_RET_SLOTS));
- assert((retMask & (((regMaskTP) RBM_FLOATRET) - 1)) == 0);
+ assert((retMask & (((regMaskTP)RBM_FLOATRET) - 1)) == 0);
#endif
int slots = genCountBits(retMask & RBM_ALLFLOAT);
@@ -11435,12 +11204,8 @@ void CodeGen::genStoreFromFltRetRegs(GenTreePtr tree)
{
if (slots <= 2)
{
- inst_TT_RV(
- ins_Store((slots == 1) ? TYP_FLOAT : TYP_DOUBLE),
- op1,
- REG_FLOATRET,
- 0,
- (slots == 1) ? EA_4BYTE : EA_8BYTE);
+ inst_TT_RV(ins_Store((slots == 1) ? TYP_FLOAT : TYP_DOUBLE), op1, REG_FLOATRET, 0,
+ (slots == 1) ? EA_4BYTE : EA_8BYTE);
}
else
{
@@ -11461,24 +11226,24 @@ void CodeGen::genStoreFromFltRetRegs(GenTreePtr tree)
#ifdef _PREFAST_
#pragma warning(push)
-#pragma warning(disable:21000) // Suppress PREFast warning about overly large function
+#pragma warning(disable : 21000) // Suppress PREFast warning about overly large function
#endif
-void CodeGen::genCodeForTreeSmpOpAsg(GenTreePtr tree)
+void CodeGen::genCodeForTreeSmpOpAsg(GenTreePtr tree)
{
noway_assert(tree->gtOper == GT_ASG);
- GenTreePtr op1 = tree->gtOp.gtOp1;
- GenTreePtr op2 = tree->gtOp.gtOp2;
- regMaskTP needReg = RBM_ALLINT;
- regMaskTP bestReg = RBM_CORRUPT;
- regMaskTP addrReg = DUMMY_INIT(RBM_CORRUPT);
- bool ovfl = false; // Do we need an overflow check
- bool volat = false; // Is this a volatile store
- regMaskTP regGC;
- instruction ins;
+ GenTreePtr op1 = tree->gtOp.gtOp1;
+ GenTreePtr op2 = tree->gtOp.gtOp2;
+ regMaskTP needReg = RBM_ALLINT;
+ regMaskTP bestReg = RBM_CORRUPT;
+ regMaskTP addrReg = DUMMY_INIT(RBM_CORRUPT);
+ bool ovfl = false; // Do we need an overflow check
+ bool volat = false; // Is this a volatile store
+ regMaskTP regGC;
+ instruction ins;
#ifdef DEBUGGING_SUPPORT
- unsigned lclVarNum = compiler->lvaCount;
- unsigned lclILoffs = DUMMY_INIT(0);
+ unsigned lclVarNum = compiler->lvaCount;
+ unsigned lclILoffs = DUMMY_INIT(0);
#endif
#ifdef _TARGET_ARM_
@@ -11492,7 +11257,7 @@ void CodeGen::genCodeForTreeSmpOpAsg(GenTreePtr tree)
}
#endif
-#ifdef DEBUG
+#ifdef DEBUG
if (varTypeIsFloating(op1) != varTypeIsFloating(op2))
{
if (varTypeIsFloating(op1))
@@ -11504,211 +11269,211 @@ void CodeGen::genCodeForTreeSmpOpAsg(GenTreePtr tree)
if ((tree->gtFlags & GTF_REVERSE_OPS) == 0)
{
- op1 = genCodeForCommaTree(op1); // Strip away any comma expressions.
+ op1 = genCodeForCommaTree(op1); // Strip away any comma expressions.
}
/* Is the target a register or local variable? */
switch (op1->gtOper)
{
- unsigned varNum;
- LclVarDsc * varDsc;
+ unsigned varNum;
+ LclVarDsc* varDsc;
- case GT_LCL_VAR:
- varNum = op1->gtLclVarCommon.gtLclNum;
- noway_assert(varNum < compiler->lvaCount);
- varDsc = compiler->lvaTable + varNum;
+ case GT_LCL_VAR:
+ varNum = op1->gtLclVarCommon.gtLclNum;
+ noway_assert(varNum < compiler->lvaCount);
+ varDsc = compiler->lvaTable + varNum;
- #ifdef DEBUGGING_SUPPORT
- /* For non-debuggable code, every definition of a lcl-var has
- * to be checked to see if we need to open a new scope for it.
- * Remember the local var info to call siCheckVarScope
- * AFTER code generation of the assignment.
- */
- if (compiler->opts.compScopeInfo && !compiler->opts.compDbgCode && (compiler->info.compVarScopesCount > 0))
- {
- lclVarNum = varNum;
- lclILoffs = op1->gtLclVar.gtLclILoffs;
- }
- #endif
+#ifdef DEBUGGING_SUPPORT
+ /* For non-debuggable code, every definition of a lcl-var has
+ * to be checked to see if we need to open a new scope for it.
+ * Remember the local var info to call siCheckVarScope
+ * AFTER code generation of the assignment.
+ */
+ if (compiler->opts.compScopeInfo && !compiler->opts.compDbgCode && (compiler->info.compVarScopesCount > 0))
+ {
+ lclVarNum = varNum;
+ lclILoffs = op1->gtLclVar.gtLclILoffs;
+ }
+#endif
- /* Check against dead store ? (with min opts we may have dead stores) */
+ /* Check against dead store ? (with min opts we may have dead stores) */
- noway_assert(!varDsc->lvTracked || compiler->opts.MinOpts() || !(op1->gtFlags & GTF_VAR_DEATH));
+ noway_assert(!varDsc->lvTracked || compiler->opts.MinOpts() || !(op1->gtFlags & GTF_VAR_DEATH));
- /* Does this variable live in a register? */
+ /* Does this variable live in a register? */
- if (genMarkLclVar(op1))
- goto REG_VAR2;
+ if (genMarkLclVar(op1))
+ goto REG_VAR2;
- break;
+ break;
-REG_VAR2:
+ REG_VAR2:
- /* Get hold of the target register */
+ /* Get hold of the target register */
- regNumber op1Reg;
+ regNumber op1Reg;
- op1Reg = op1->gtRegVar.gtRegNum;
+ op1Reg = op1->gtRegVar.gtRegNum;
#ifdef DEBUG
- /* Compute the RHS (hopefully) into the variable's register.
- For debuggable code, op1Reg may already be part of regSet.rsMaskVars,
- as variables are kept alive everywhere. So we have to be
- careful if we want to compute the value directly into
- the variable's register. */
+ /* Compute the RHS (hopefully) into the variable's register.
+ For debuggable code, op1Reg may already be part of regSet.rsMaskVars,
+ as variables are kept alive everywhere. So we have to be
+ careful if we want to compute the value directly into
+ the variable's register. */
- bool needToUpdateRegSetCheckLevel;
- needToUpdateRegSetCheckLevel = false;
-#endif
+ bool needToUpdateRegSetCheckLevel;
+ needToUpdateRegSetCheckLevel = false;
+#endif
- // We should only be accessing lvVarIndex if varDsc is tracked.
- assert(varDsc->lvTracked);
+ // We should only be accessing lvVarIndex if varDsc is tracked.
+ assert(varDsc->lvTracked);
- if (VarSetOps::IsMember(compiler, genUpdateLiveSetForward(op2), varDsc->lvVarIndex))
- {
- noway_assert(compiler->opts.compDbgCode);
+ if (VarSetOps::IsMember(compiler, genUpdateLiveSetForward(op2), varDsc->lvVarIndex))
+ {
+ noway_assert(compiler->opts.compDbgCode);
- /* The predictor might expect us to generate op2 directly
- into the var's register. However, since the variable is
- already alive, first kill it and its register. */
+ /* The predictor might expect us to generate op2 directly
+ into the var's register. However, since the variable is
+ already alive, first kill it and its register. */
- if (rpCanAsgOperWithoutReg(op2, true))
+ if (rpCanAsgOperWithoutReg(op2, true))
+ {
+ genUpdateLife(VarSetOps::RemoveElem(compiler, compiler->compCurLife, varDsc->lvVarIndex));
+ needReg = regSet.rsNarrowHint(needReg, genRegMask(op1Reg));
+#ifdef DEBUG
+ needToUpdateRegSetCheckLevel = true;
+#endif
+ }
+ }
+ else
{
- genUpdateLife(VarSetOps::RemoveElem(compiler, compiler->compCurLife, varDsc->lvVarIndex));
needReg = regSet.rsNarrowHint(needReg, genRegMask(op1Reg));
-#ifdef DEBUG
- needToUpdateRegSetCheckLevel = true;
-#endif
}
- }
- else
- {
- needReg = regSet.rsNarrowHint(needReg, genRegMask(op1Reg));
- }
#ifdef DEBUG
- /* Special cases: op2 is a GT_CNS_INT */
+ /* Special cases: op2 is a GT_CNS_INT */
- if (op2->gtOper == GT_CNS_INT && !(op1->gtFlags & GTF_VAR_DEATH))
- {
- /* Save the old life status */
+ if (op2->gtOper == GT_CNS_INT && !(op1->gtFlags & GTF_VAR_DEATH))
+ {
+ /* Save the old life status */
- VarSetOps::Assign(compiler, genTempOldLife, compiler->compCurLife);
- VarSetOps::AddElemD(compiler, compiler->compCurLife, varDsc->lvVarIndex);
+ VarSetOps::Assign(compiler, genTempOldLife, compiler->compCurLife);
+ VarSetOps::AddElemD(compiler, compiler->compCurLife, varDsc->lvVarIndex);
- /* Set a flag to avoid printing the message
- and remember that life was changed. */
+ /* Set a flag to avoid printing the message
+ and remember that life was changed. */
- genTempLiveChg = false;
- }
+ genTempLiveChg = false;
+ }
#endif
-#ifdef DEBUG
- if (needToUpdateRegSetCheckLevel)
- compiler->compRegSetCheckLevel++;
-#endif
- genCodeForTree(op2, needReg, genRegMask(op1Reg));
-#ifdef DEBUG
- if (needToUpdateRegSetCheckLevel)
- compiler->compRegSetCheckLevel--;
- noway_assert(compiler->compRegSetCheckLevel>=0);
-#endif
- noway_assert(op2->gtFlags & GTF_REG_VAL);
+#ifdef DEBUG
+ if (needToUpdateRegSetCheckLevel)
+ compiler->compRegSetCheckLevel++;
+#endif
+ genCodeForTree(op2, needReg, genRegMask(op1Reg));
+#ifdef DEBUG
+ if (needToUpdateRegSetCheckLevel)
+ compiler->compRegSetCheckLevel--;
+ noway_assert(compiler->compRegSetCheckLevel >= 0);
+#endif
+ noway_assert(op2->gtFlags & GTF_REG_VAL);
- /* Make sure the value ends up in the right place ... */
+ /* Make sure the value ends up in the right place ... */
- if (op2->gtRegNum != op1Reg)
- {
- /* Make sure the target of the store is available */
+ if (op2->gtRegNum != op1Reg)
+ {
+ /* Make sure the target of the store is available */
- if (regSet.rsMaskUsed & genRegMask(op1Reg))
- regSet.rsSpillReg(op1Reg);
+ if (regSet.rsMaskUsed & genRegMask(op1Reg))
+ regSet.rsSpillReg(op1Reg);
#ifdef _TARGET_ARM_
- if (op1->TypeGet() == TYP_FLOAT)
- {
- // This can only occur when we are returning a non-HFA struct
- // that is composed of a single float field.
- //
- inst_RV_RV(INS_vmov_i2f, op1Reg, op2->gtRegNum, op1->TypeGet());
- }
- else
+ if (op1->TypeGet() == TYP_FLOAT)
+ {
+ // This can only occur when we are returning a non-HFA struct
+ // that is composed of a single float field.
+ //
+ inst_RV_RV(INS_vmov_i2f, op1Reg, op2->gtRegNum, op1->TypeGet());
+ }
+ else
#endif // _TARGET_ARM_
- {
- inst_RV_RV(INS_mov, op1Reg, op2->gtRegNum, op1->TypeGet());
- }
-
- /* The value has been transferred to 'op1Reg' */
+ {
+ inst_RV_RV(INS_mov, op1Reg, op2->gtRegNum, op1->TypeGet());
+ }
- regTracker.rsTrackRegCopy (op1Reg, op2->gtRegNum);
+ /* The value has been transferred to 'op1Reg' */
- if ((genRegMask(op2->gtRegNum) & regSet.rsMaskUsed) == 0)
- gcInfo.gcMarkRegSetNpt(genRegMask(op2->gtRegNum));
+ regTracker.rsTrackRegCopy(op1Reg, op2->gtRegNum);
- gcInfo.gcMarkRegPtrVal(op1Reg, tree->TypeGet());
- }
- else
- {
- // First we need to remove it from the original reg set mask (or else trigger an
- // assert when we add it to the other reg set mask).
- gcInfo.gcMarkRegSetNpt(genRegMask(op1Reg));
- gcInfo.gcMarkRegPtrVal(op1Reg, tree->TypeGet());
+ if ((genRegMask(op2->gtRegNum) & regSet.rsMaskUsed) == 0)
+ gcInfo.gcMarkRegSetNpt(genRegMask(op2->gtRegNum));
- // The emitter has logic that tracks the GCness of registers and asserts if you
- // try to do bad things to a GC pointer (like lose its GCness).
-
- // An explict cast of a GC pointer to an int (which is legal if the
- // pointer is pinned) is encoded as an assignment of a GC source
- // to a integer variable. Unfortunately if the source was the last
- // use, and the source register gets reused by the destination, no
- // code gets emitted (That is where we are at right now). The emitter
- // thinks the register is a GC pointer (it did not see the cast).
- // This causes asserts, as well as bad GC info since we will continue
- // to report the register as a GC pointer even if we do arithmetic
- // with it. So force the emitter to see the change in the type
- // of variable by placing a label.
- // We only have to do this check at this point because in the
- // CAST morphing, we create a temp and assignment whenever we
- // have a cast that loses its GCness.
-
- if (varTypeGCtype(op2->TypeGet()) != varTypeGCtype(op1->TypeGet()))
+ gcInfo.gcMarkRegPtrVal(op1Reg, tree->TypeGet());
+ }
+ else
{
- void* label = getEmitter()->emitAddLabel(gcInfo.gcVarPtrSetCur, gcInfo.gcRegGCrefSetCur, gcInfo.gcRegByrefSetCur);
+ // First we need to remove it from the original reg set mask (or else trigger an
+ // assert when we add it to the other reg set mask).
+ gcInfo.gcMarkRegSetNpt(genRegMask(op1Reg));
+ gcInfo.gcMarkRegPtrVal(op1Reg, tree->TypeGet());
+
+ // The emitter has logic that tracks the GCness of registers and asserts if you
+ // try to do bad things to a GC pointer (like lose its GCness).
+
+ // An explict cast of a GC pointer to an int (which is legal if the
+ // pointer is pinned) is encoded as an assignment of a GC source
+ // to a integer variable. Unfortunately if the source was the last
+ // use, and the source register gets reused by the destination, no
+ // code gets emitted (That is where we are at right now). The emitter
+ // thinks the register is a GC pointer (it did not see the cast).
+ // This causes asserts, as well as bad GC info since we will continue
+ // to report the register as a GC pointer even if we do arithmetic
+ // with it. So force the emitter to see the change in the type
+ // of variable by placing a label.
+ // We only have to do this check at this point because in the
+ // CAST morphing, we create a temp and assignment whenever we
+ // have a cast that loses its GCness.
+
+ if (varTypeGCtype(op2->TypeGet()) != varTypeGCtype(op1->TypeGet()))
+ {
+ void* label = getEmitter()->emitAddLabel(gcInfo.gcVarPtrSetCur, gcInfo.gcRegGCrefSetCur,
+ gcInfo.gcRegByrefSetCur);
+ }
}
- }
-
- addrReg = 0;
+ addrReg = 0;
- genCodeForTreeSmpOpAsg_DONE_ASSG(tree, addrReg, op1Reg, ovfl);
- goto LExit;
+ genCodeForTreeSmpOpAsg_DONE_ASSG(tree, addrReg, op1Reg, ovfl);
+ goto LExit;
- case GT_LCL_FLD:
+ case GT_LCL_FLD:
- // We only use GT_LCL_FLD for lvDoNotEnregister vars, so we don't have
- // to worry about it being enregistered.
- noway_assert(compiler->lvaTable[op1->gtLclFld.gtLclNum].lvRegister == 0);
- break;
+ // We only use GT_LCL_FLD for lvDoNotEnregister vars, so we don't have
+ // to worry about it being enregistered.
+ noway_assert(compiler->lvaTable[op1->gtLclFld.gtLclNum].lvRegister == 0);
+ break;
- case GT_CLS_VAR:
+ case GT_CLS_VAR:
- __fallthrough;
+ __fallthrough;
- case GT_IND:
- case GT_NULLCHECK:
+ case GT_IND:
+ case GT_NULLCHECK:
- assert((op1->OperGet() == GT_CLS_VAR) || (op1->OperGet() == GT_IND));
+ assert((op1->OperGet() == GT_CLS_VAR) || (op1->OperGet() == GT_IND));
- if (op1->gtFlags & GTF_IND_VOLATILE)
- {
- volat = true;
- }
+ if (op1->gtFlags & GTF_IND_VOLATILE)
+ {
+ volat = true;
+ }
- break;
+ break;
- default:
- break;
+ default:
+ break;
}
/* Is the value being assigned a simple one? */
@@ -11716,461 +11481,466 @@ REG_VAR2:
noway_assert(op2);
switch (op2->gtOper)
{
- case GT_LCL_VAR:
+ case GT_LCL_VAR:
- if (!genMarkLclVar(op2))
- goto SMALL_ASG;
+ if (!genMarkLclVar(op2))
+ goto SMALL_ASG;
- __fallthrough;
+ __fallthrough;
- case GT_REG_VAR:
+ case GT_REG_VAR:
- /* Is the target a byte/short/char value? */
+ /* Is the target a byte/short/char value? */
- if (varTypeIsSmall(op1->TypeGet()))
- goto SMALL_ASG;
+ if (varTypeIsSmall(op1->TypeGet()))
+ goto SMALL_ASG;
- if (tree->gtFlags & GTF_REVERSE_OPS)
- goto SMALL_ASG;
+ if (tree->gtFlags & GTF_REVERSE_OPS)
+ goto SMALL_ASG;
- /* Make the target addressable */
+ /* Make the target addressable */
- op1 = genCodeForCommaTree(op1); // Strip away comma expressions.
+ op1 = genCodeForCommaTree(op1); // Strip away comma expressions.
- addrReg = genMakeAddressable(op1, needReg, RegSet::KEEP_REG, true);
+ addrReg = genMakeAddressable(op1, needReg, RegSet::KEEP_REG, true);
- /* Does the write barrier helper do the assignment? */
+ /* Does the write barrier helper do the assignment? */
- regGC = WriteBarrier(op1, op2, addrReg);
+ regGC = WriteBarrier(op1, op2, addrReg);
- // Was assignment done by the WriteBarrier
- if (regGC == RBM_NONE)
- {
-#ifdef _TARGET_ARM_
- if (volat)
+ // Was assignment done by the WriteBarrier
+ if (regGC == RBM_NONE)
{
- // Emit a memory barrier instruction before the store
- instGen_MemoryBarrier();
- }
+#ifdef _TARGET_ARM_
+ if (volat)
+ {
+ // Emit a memory barrier instruction before the store
+ instGen_MemoryBarrier();
+ }
#endif
- /* Move the value into the target */
+ /* Move the value into the target */
- inst_TT_RV(ins_Store(op1->TypeGet()), op1, op2->gtRegVar.gtRegNum);
+ inst_TT_RV(ins_Store(op1->TypeGet()), op1, op2->gtRegVar.gtRegNum);
- // This is done in WriteBarrier when (regGC != RBM_NONE)
+ // This is done in WriteBarrier when (regGC != RBM_NONE)
- /* Free up anything that was tied up by the LHS */
- genDoneAddressable(op1, addrReg, RegSet::KEEP_REG);
- }
-
- /* Free up the RHS */
- genUpdateLife(op2);
+ /* Free up anything that was tied up by the LHS */
+ genDoneAddressable(op1, addrReg, RegSet::KEEP_REG);
+ }
- /* Remember that we've also touched the op2 register */
+ /* Free up the RHS */
+ genUpdateLife(op2);
- addrReg |= genRegMask(op2->gtRegVar.gtRegNum);
- break;
+ /* Remember that we've also touched the op2 register */
+ addrReg |= genRegMask(op2->gtRegVar.gtRegNum);
+ break;
- case GT_CNS_INT:
+ case GT_CNS_INT:
- ssize_t ival; ival = op2->gtIntCon.gtIconVal;
- emitAttr size; size = emitTypeSize(tree->TypeGet());
+ ssize_t ival;
+ ival = op2->gtIntCon.gtIconVal;
+ emitAttr size;
+ size = emitTypeSize(tree->TypeGet());
- ins = ins_Store(op1->TypeGet());
+ ins = ins_Store(op1->TypeGet());
- // If we are storing a constant into a local variable
- // we extend the size of the store here
- // this normally takes place in CodeGen::inst_TT_IV on x86.
- //
- if ((op1->gtOper == GT_LCL_VAR) && (size < EA_4BYTE))
- {
- unsigned varNum = op1->gtLclVarCommon.gtLclNum;
- LclVarDsc * varDsc = compiler->lvaTable + varNum;
-
- // Fix the immediate by sign extending if needed
- if (!varTypeIsUnsigned(varDsc->TypeGet()))
+ // If we are storing a constant into a local variable
+ // we extend the size of the store here
+ // this normally takes place in CodeGen::inst_TT_IV on x86.
+ //
+ if ((op1->gtOper == GT_LCL_VAR) && (size < EA_4BYTE))
{
- if (size == EA_1BYTE)
+ unsigned varNum = op1->gtLclVarCommon.gtLclNum;
+ LclVarDsc* varDsc = compiler->lvaTable + varNum;
+
+ // Fix the immediate by sign extending if needed
+ if (!varTypeIsUnsigned(varDsc->TypeGet()))
{
- if ((ival & 0x7f) != ival)
- ival = ival | 0xffffff00;
+ if (size == EA_1BYTE)
+ {
+ if ((ival & 0x7f) != ival)
+ ival = ival | 0xffffff00;
+ }
+ else
+ {
+ assert(size == EA_2BYTE);
+ if ((ival & 0x7fff) != ival)
+ ival = ival | 0xffff0000;
+ }
}
- else
+
+ // A local stack slot is at least 4 bytes in size, regardless of
+ // what the local var is typed as, so auto-promote it here
+ // unless it is a field of a promoted struct
+ if (!varDsc->lvIsStructField)
{
- assert(size == EA_2BYTE);
- if ((ival & 0x7fff) != ival)
- ival = ival | 0xffff0000;
+ size = EA_SET_SIZE(size, EA_4BYTE);
+ ins = ins_Store(TYP_INT);
}
}
- // A local stack slot is at least 4 bytes in size, regardless of
- // what the local var is typed as, so auto-promote it here
- // unless it is a field of a promoted struct
- if (!varDsc->lvIsStructField)
- {
- size = EA_SET_SIZE(size, EA_4BYTE);
- ins = ins_Store(TYP_INT);
- }
- }
-
- /* Make the target addressable */
+ /* Make the target addressable */
- addrReg = genMakeAddressable(op1, needReg, RegSet::KEEP_REG, true);
+ addrReg = genMakeAddressable(op1, needReg, RegSet::KEEP_REG, true);
#ifdef _TARGET_ARM_
- if (volat)
- {
- // Emit a memory barrier instruction before the store
- instGen_MemoryBarrier();
- }
+ if (volat)
+ {
+ // Emit a memory barrier instruction before the store
+ instGen_MemoryBarrier();
+ }
#endif
- /* Move the value into the target */
-
- noway_assert(op1->gtOper != GT_REG_VAR);
- if (compiler->opts.compReloc && op2->IsIconHandle())
- {
- /* The constant is actually a handle that may need relocation
- applied to it. genComputeReg will do the right thing (see
- code in genCodeForTreeConst), so we'll just call it to load
- the constant into a register. */
+ /* Move the value into the target */
- genComputeReg(op2, needReg & ~addrReg, RegSet::ANY_REG, RegSet::KEEP_REG);
- addrReg = genKeepAddressable(op1, addrReg, genRegMask(op2->gtRegNum));
- noway_assert(op2->gtFlags & GTF_REG_VAL);
- inst_TT_RV(ins, op1, op2->gtRegNum);
- genReleaseReg(op2);
- }
- else
- {
- regSet.rsLockUsedReg(addrReg);
+ noway_assert(op1->gtOper != GT_REG_VAR);
+ if (compiler->opts.compReloc && op2->IsIconHandle())
+ {
+ /* The constant is actually a handle that may need relocation
+ applied to it. genComputeReg will do the right thing (see
+ code in genCodeForTreeConst), so we'll just call it to load
+ the constant into a register. */
+ genComputeReg(op2, needReg & ~addrReg, RegSet::ANY_REG, RegSet::KEEP_REG);
+ addrReg = genKeepAddressable(op1, addrReg, genRegMask(op2->gtRegNum));
+ noway_assert(op2->gtFlags & GTF_REG_VAL);
+ inst_TT_RV(ins, op1, op2->gtRegNum);
+ genReleaseReg(op2);
+ }
+ else
+ {
+ regSet.rsLockUsedReg(addrReg);
#if REDUNDANT_LOAD
- bool copyIconFromReg = true;
- regNumber iconReg = REG_NA;
+ bool copyIconFromReg = true;
+ regNumber iconReg = REG_NA;
#ifdef _TARGET_ARM_
- // Only if the constant can't be encoded in a small instruction,
- // look for another register to copy the value from. (Assumes
- // target is a small register.)
- if ((op1->gtFlags & GTF_REG_VAL) &&
- !isRegPairType(tree->gtType) &&
- arm_Valid_Imm_For_Small_Mov(op1->gtRegNum, ival, INS_FLAGS_DONT_CARE))
- {
- copyIconFromReg = false;
- }
+ // Only if the constant can't be encoded in a small instruction,
+ // look for another register to copy the value from. (Assumes
+ // target is a small register.)
+ if ((op1->gtFlags & GTF_REG_VAL) && !isRegPairType(tree->gtType) &&
+ arm_Valid_Imm_For_Small_Mov(op1->gtRegNum, ival, INS_FLAGS_DONT_CARE))
+ {
+ copyIconFromReg = false;
+ }
#endif // _TARGET_ARM_
- if (copyIconFromReg)
- {
- iconReg = regTracker.rsIconIsInReg(ival);
- if (iconReg == REG_NA)
- copyIconFromReg = false;
- }
+ if (copyIconFromReg)
+ {
+ iconReg = regTracker.rsIconIsInReg(ival);
+ if (iconReg == REG_NA)
+ copyIconFromReg = false;
+ }
- if (copyIconFromReg &&
- (isByteReg(iconReg) || (genTypeSize(tree->TypeGet()) == EA_PTRSIZE) || (genTypeSize(tree->TypeGet()) == EA_4BYTE)))
- {
- /* Move the value into the target */
+ if (copyIconFromReg && (isByteReg(iconReg) || (genTypeSize(tree->TypeGet()) == EA_PTRSIZE) ||
+ (genTypeSize(tree->TypeGet()) == EA_4BYTE)))
+ {
+ /* Move the value into the target */
- inst_TT_RV(ins, op1, iconReg, 0, size);
- }
- else
+ inst_TT_RV(ins, op1, iconReg, 0, size);
+ }
+ else
#endif // REDUNDANT_LOAD
- {
- inst_TT_IV(ins, op1, ival, 0, size);
- }
-
- regSet.rsUnlockUsedReg(addrReg);
- }
+ {
+ inst_TT_IV(ins, op1, ival, 0, size);
+ }
- /* Free up anything that was tied up by the LHS */
+ regSet.rsUnlockUsedReg(addrReg);
+ }
- genDoneAddressable(op1, addrReg, RegSet::KEEP_REG);
- break;
+ /* Free up anything that was tied up by the LHS */
- default:
+ genDoneAddressable(op1, addrReg, RegSet::KEEP_REG);
+ break;
-SMALL_ASG:
+ default:
- bool isWriteBarrier = false;
- regMaskTP needRegOp1 = RBM_ALLINT;
- RegSet::ExactReg mustReg = RegSet::ANY_REG; // set to RegSet::EXACT_REG for op1 and NOGC helpers
+ SMALL_ASG:
- /* Is the LHS more complex than the RHS? */
+ bool isWriteBarrier = false;
+ regMaskTP needRegOp1 = RBM_ALLINT;
+ RegSet::ExactReg mustReg = RegSet::ANY_REG; // set to RegSet::EXACT_REG for op1 and NOGC helpers
- if (tree->gtFlags & GTF_REVERSE_OPS)
- {
- /* Is the target a byte/short/char value? */
+ /* Is the LHS more complex than the RHS? */
- if (varTypeIsSmall(op1->TypeGet()))
+ if (tree->gtFlags & GTF_REVERSE_OPS)
{
- noway_assert(op1->gtOper != GT_LCL_VAR ||
- (op1->gtFlags & GTF_VAR_CAST) ||
- // TODO: Why does this have to be true?
- compiler->lvaTable[op1->gtLclVarCommon.gtLclNum].lvIsStructField ||
- compiler->lvaTable[op1->gtLclVarCommon.gtLclNum].lvNormalizeOnLoad());
+ /* Is the target a byte/short/char value? */
- if (op2->gtOper == GT_CAST && !op2->gtOverflow())
+ if (varTypeIsSmall(op1->TypeGet()))
{
- /* Special case: cast to small type */
+ noway_assert(op1->gtOper != GT_LCL_VAR || (op1->gtFlags & GTF_VAR_CAST) ||
+ // TODO: Why does this have to be true?
+ compiler->lvaTable[op1->gtLclVarCommon.gtLclNum].lvIsStructField ||
+ compiler->lvaTable[op1->gtLclVarCommon.gtLclNum].lvNormalizeOnLoad());
- if (op2->CastToType() >= op1->gtType)
+ if (op2->gtOper == GT_CAST && !op2->gtOverflow())
{
- /* Make sure the cast operand is not > int */
+ /* Special case: cast to small type */
- if (op2->CastFromType() <= TYP_INT)
+ if (op2->CastToType() >= op1->gtType)
{
- /* Cast via a non-smaller type */
+ /* Make sure the cast operand is not > int */
- op2 = op2->gtCast.CastOp();
+ if (op2->CastFromType() <= TYP_INT)
+ {
+ /* Cast via a non-smaller type */
+
+ op2 = op2->gtCast.CastOp();
+ }
}
}
- }
- if (op2->gtOper == GT_AND &&
- op2->gtOp.gtOp2->gtOper == GT_CNS_INT)
- {
- unsigned mask;
- switch (op1->gtType)
+ if (op2->gtOper == GT_AND && op2->gtOp.gtOp2->gtOper == GT_CNS_INT)
{
- case TYP_BYTE : mask = 0x000000FF; break;
- case TYP_SHORT: mask = 0x0000FFFF; break;
- case TYP_CHAR : mask = 0x0000FFFF; break;
- default: goto SIMPLE_SMALL;
- }
+ unsigned mask;
+ switch (op1->gtType)
+ {
+ case TYP_BYTE:
+ mask = 0x000000FF;
+ break;
+ case TYP_SHORT:
+ mask = 0x0000FFFF;
+ break;
+ case TYP_CHAR:
+ mask = 0x0000FFFF;
+ break;
+ default:
+ goto SIMPLE_SMALL;
+ }
- if (unsigned(op2->gtOp.gtOp2->gtIntCon.gtIconVal) == mask)
- {
- /* Redundant AND */
+ if (unsigned(op2->gtOp.gtOp2->gtIntCon.gtIconVal) == mask)
+ {
+ /* Redundant AND */
- op2 = op2->gtOp.gtOp1;
+ op2 = op2->gtOp.gtOp1;
+ }
}
- }
/* Must get the new value into a byte register */
-SIMPLE_SMALL:
+ SIMPLE_SMALL:
if (varTypeIsByte(op1->TypeGet()))
genComputeReg(op2, RBM_BYTE_REGS, RegSet::EXACT_REG, RegSet::KEEP_REG);
else
goto NOT_SMALL;
- }
- else
- {
-NOT_SMALL:
- /* Generate the RHS into a register */
-
- isWriteBarrier = gcInfo.gcIsWriteBarrierAsgNode(tree);
- if (isWriteBarrier)
+ }
+ else
{
-#if NOGC_WRITE_BARRIERS
- // Exclude the REG_WRITE_BARRIER from op2's needReg mask
- needReg = Target::exclude_WriteBarrierReg(needReg);
- mustReg = RegSet::EXACT_REG;
-#else // !NOGC_WRITE_BARRIERS
- // This code should be generic across architectures.
+ NOT_SMALL:
+ /* Generate the RHS into a register */
- // For the standard JIT Helper calls
- // op1 goes into REG_ARG_0 and
- // op2 goes into REG_ARG_1
- //
- needRegOp1 = RBM_ARG_0;
- needReg = RBM_ARG_1;
+ isWriteBarrier = gcInfo.gcIsWriteBarrierAsgNode(tree);
+ if (isWriteBarrier)
+ {
+#if NOGC_WRITE_BARRIERS
+ // Exclude the REG_WRITE_BARRIER from op2's needReg mask
+ needReg = Target::exclude_WriteBarrierReg(needReg);
+ mustReg = RegSet::EXACT_REG;
+#else // !NOGC_WRITE_BARRIERS
+ // This code should be generic across architectures.
+
+ // For the standard JIT Helper calls
+ // op1 goes into REG_ARG_0 and
+ // op2 goes into REG_ARG_1
+ //
+ needRegOp1 = RBM_ARG_0;
+ needReg = RBM_ARG_1;
#endif // !NOGC_WRITE_BARRIERS
+ }
+ genComputeReg(op2, needReg, mustReg, RegSet::KEEP_REG);
}
- genComputeReg(op2, needReg, mustReg, RegSet::KEEP_REG);
- }
- noway_assert(op2->gtFlags & GTF_REG_VAL);
+ noway_assert(op2->gtFlags & GTF_REG_VAL);
- /* Make the target addressable */
+ /* Make the target addressable */
- op1 = genCodeForCommaTree(op1); // Strip off any comma expressions.
- addrReg = genMakeAddressable(op1, needRegOp1, RegSet::KEEP_REG, true);
-
- /* Make sure the RHS register hasn't been spilled;
- keep the register marked as "used", otherwise
- we might get the pointer lifetimes wrong.
- */
+ op1 = genCodeForCommaTree(op1); // Strip off any comma expressions.
+ addrReg = genMakeAddressable(op1, needRegOp1, RegSet::KEEP_REG, true);
- if (varTypeIsByte(op1->TypeGet()))
- needReg = regSet.rsNarrowHint(RBM_BYTE_REGS, needReg);
+ /* Make sure the RHS register hasn't been spilled;
+ keep the register marked as "used", otherwise
+ we might get the pointer lifetimes wrong.
+ */
- genRecoverReg(op2, needReg, RegSet::KEEP_REG);
- noway_assert(op2->gtFlags & GTF_REG_VAL);
+ if (varTypeIsByte(op1->TypeGet()))
+ needReg = regSet.rsNarrowHint(RBM_BYTE_REGS, needReg);
- /* Lock the RHS temporarily (lock only already used) */
+ genRecoverReg(op2, needReg, RegSet::KEEP_REG);
+ noway_assert(op2->gtFlags & GTF_REG_VAL);
- regSet.rsLockUsedReg(genRegMask(op2->gtRegNum));
+ /* Lock the RHS temporarily (lock only already used) */
- /* Make sure the LHS is still addressable */
+ regSet.rsLockUsedReg(genRegMask(op2->gtRegNum));
- addrReg = genKeepAddressable(op1, addrReg);
+ /* Make sure the LHS is still addressable */
- /* We can unlock (only already used ) the RHS register */
+ addrReg = genKeepAddressable(op1, addrReg);
- regSet.rsUnlockUsedReg(genRegMask(op2->gtRegNum));
+ /* We can unlock (only already used ) the RHS register */
- /* Does the write barrier helper do the assignment? */
+ regSet.rsUnlockUsedReg(genRegMask(op2->gtRegNum));
- regGC = WriteBarrier(op1, op2, addrReg);
+ /* Does the write barrier helper do the assignment? */
- if (regGC != 0)
- {
- // Yes, assignment done by the WriteBarrier
- noway_assert(isWriteBarrier);
- }
- else
- {
-#ifdef _TARGET_ARM_
- if (volat)
+ regGC = WriteBarrier(op1, op2, addrReg);
+
+ if (regGC != 0)
{
- // Emit a memory barrier instruction before the store
- instGen_MemoryBarrier();
+ // Yes, assignment done by the WriteBarrier
+ noway_assert(isWriteBarrier);
}
+ else
+ {
+#ifdef _TARGET_ARM_
+ if (volat)
+ {
+ // Emit a memory barrier instruction before the store
+ instGen_MemoryBarrier();
+ }
#endif
- /* Move the value into the target */
+ /* Move the value into the target */
- inst_TT_RV(ins_Store(op1->TypeGet()), op1, op2->gtRegNum);
- }
+ inst_TT_RV(ins_Store(op1->TypeGet()), op1, op2->gtRegNum);
+ }
#ifdef DEBUG
- /* Update the current liveness info */
- if (compiler->opts.varNames) genUpdateLife(tree);
+ /* Update the current liveness info */
+ if (compiler->opts.varNames)
+ genUpdateLife(tree);
#endif
- // If op2 register is still in use, free it. (Might not be in use, if
- // a full-call write barrier was done, and the register was a caller-saved
- // register.)
- regMaskTP op2RM = genRegMask(op2->gtRegNum);
- if (op2RM & regSet.rsMaskUsed) regSet.rsMarkRegFree(genRegMask(op2->gtRegNum));
+ // If op2 register is still in use, free it. (Might not be in use, if
+ // a full-call write barrier was done, and the register was a caller-saved
+ // register.)
+ regMaskTP op2RM = genRegMask(op2->gtRegNum);
+ if (op2RM & regSet.rsMaskUsed)
+ regSet.rsMarkRegFree(genRegMask(op2->gtRegNum));
- // This is done in WriteBarrier when (regGC != 0)
- if (regGC == 0)
- {
- /* Free up anything that was tied up by the LHS */
- genDoneAddressable(op1, addrReg, RegSet::KEEP_REG);
+ // This is done in WriteBarrier when (regGC != 0)
+ if (regGC == 0)
+ {
+ /* Free up anything that was tied up by the LHS */
+ genDoneAddressable(op1, addrReg, RegSet::KEEP_REG);
+ }
}
- }
- else
- {
- /* Make the target addressable */
+ else
+ {
+ /* Make the target addressable */
- isWriteBarrier = gcInfo.gcIsWriteBarrierAsgNode(tree);
+ isWriteBarrier = gcInfo.gcIsWriteBarrierAsgNode(tree);
- if (isWriteBarrier)
- {
+ if (isWriteBarrier)
+ {
#if NOGC_WRITE_BARRIERS
- /* Try to avoid RBM_TMP_0 */
- needRegOp1 = regSet.rsNarrowHint(needRegOp1, ~RBM_TMP_0);
- mustReg = RegSet::EXACT_REG; // For op2
-#else // !NOGC_WRITE_BARRIERS
- // This code should be generic across architectures.
-
- // For the standard JIT Helper calls
- // op1 goes into REG_ARG_0 and
- // op2 goes into REG_ARG_1
- //
- needRegOp1 = RBM_ARG_0;
- needReg = RBM_ARG_1;
- mustReg = RegSet::EXACT_REG; // For op2
-#endif // !NOGC_WRITE_BARRIERS
- }
+ /* Try to avoid RBM_TMP_0 */
+ needRegOp1 = regSet.rsNarrowHint(needRegOp1, ~RBM_TMP_0);
+ mustReg = RegSet::EXACT_REG; // For op2
+#else // !NOGC_WRITE_BARRIERS
+ // This code should be generic across architectures.
+
+ // For the standard JIT Helper calls
+ // op1 goes into REG_ARG_0 and
+ // op2 goes into REG_ARG_1
+ //
+ needRegOp1 = RBM_ARG_0;
+ needReg = RBM_ARG_1;
+ mustReg = RegSet::EXACT_REG; // For op2
+#endif // !NOGC_WRITE_BARRIERS
+ }
+
+ needRegOp1 = regSet.rsNarrowHint(needRegOp1, ~op2->gtRsvdRegs);
- needRegOp1 = regSet.rsNarrowHint(needRegOp1, ~op2->gtRsvdRegs);
+ op1 = genCodeForCommaTree(op1); // Strip away any comma expression.
- op1 = genCodeForCommaTree(op1); // Strip away any comma expression.
+ addrReg = genMakeAddressable(op1, needRegOp1, RegSet::KEEP_REG, true);
- addrReg = genMakeAddressable(op1,
- needRegOp1,
- RegSet::KEEP_REG, true);
-
#if CPU_HAS_BYTE_REGS
- /* Is the target a byte value? */
- if (varTypeIsByte(op1->TypeGet()))
- {
- /* Must get the new value into a byte register */
- needReg = regSet.rsNarrowHint(RBM_BYTE_REGS, needReg);
- mustReg = RegSet::EXACT_REG;
+ /* Is the target a byte value? */
+ if (varTypeIsByte(op1->TypeGet()))
+ {
+ /* Must get the new value into a byte register */
+ needReg = regSet.rsNarrowHint(RBM_BYTE_REGS, needReg);
+ mustReg = RegSet::EXACT_REG;
- if (op2->gtType >= op1->gtType)
- op2->gtFlags |= GTF_SMALL_OK;
- }
+ if (op2->gtType >= op1->gtType)
+ op2->gtFlags |= GTF_SMALL_OK;
+ }
#endif
#if NOGC_WRITE_BARRIERS
- /* For WriteBarrier we can't use REG_WRITE_BARRIER */
- if (isWriteBarrier)
- needReg = Target::exclude_WriteBarrierReg(needReg);
+ /* For WriteBarrier we can't use REG_WRITE_BARRIER */
+ if (isWriteBarrier)
+ needReg = Target::exclude_WriteBarrierReg(needReg);
- /* Also avoid using the previously computed addrReg(s) */
- bestReg = regSet.rsNarrowHint(needReg, ~addrReg);
+ /* Also avoid using the previously computed addrReg(s) */
+ bestReg = regSet.rsNarrowHint(needReg, ~addrReg);
- /* If we have a reg available to grab then use bestReg */
- if (bestReg & regSet.rsRegMaskCanGrab())
- needReg = bestReg;
+ /* If we have a reg available to grab then use bestReg */
+ if (bestReg & regSet.rsRegMaskCanGrab())
+ needReg = bestReg;
- mustReg = RegSet::EXACT_REG;
+ mustReg = RegSet::EXACT_REG;
#endif
- /* Generate the RHS into a register */
- genComputeReg(op2, needReg, mustReg, RegSet::KEEP_REG);
- noway_assert(op2->gtFlags & GTF_REG_VAL);
-
- /* Make sure the target is still addressable */
- addrReg = genKeepAddressable(op1, addrReg, genRegMask(op2->gtRegNum));
- noway_assert(op2->gtFlags & GTF_REG_VAL);
+ /* Generate the RHS into a register */
+ genComputeReg(op2, needReg, mustReg, RegSet::KEEP_REG);
+ noway_assert(op2->gtFlags & GTF_REG_VAL);
- /* Does the write barrier helper do the assignment? */
+ /* Make sure the target is still addressable */
+ addrReg = genKeepAddressable(op1, addrReg, genRegMask(op2->gtRegNum));
+ noway_assert(op2->gtFlags & GTF_REG_VAL);
- regGC = WriteBarrier(op1, op2, addrReg);
+ /* Does the write barrier helper do the assignment? */
- if (regGC != 0)
- {
- // Yes, assignment done by the WriteBarrier
- noway_assert(isWriteBarrier);
- }
- else
- {
- assert(!isWriteBarrier);
+ regGC = WriteBarrier(op1, op2, addrReg);
-#ifdef _TARGET_ARM_
- if (volat)
+ if (regGC != 0)
{
- // Emit a memory barrier instruction before the store
- instGen_MemoryBarrier();
+ // Yes, assignment done by the WriteBarrier
+ noway_assert(isWriteBarrier);
}
+ else
+ {
+ assert(!isWriteBarrier);
+
+#ifdef _TARGET_ARM_
+ if (volat)
+ {
+ // Emit a memory barrier instruction before the store
+ instGen_MemoryBarrier();
+ }
#endif
- /* Move the value into the target */
+ /* Move the value into the target */
- inst_TT_RV(ins_Store(op1->TypeGet()), op1, op2->gtRegNum);
- }
+ inst_TT_RV(ins_Store(op1->TypeGet()), op1, op2->gtRegNum);
+ }
- /* The new value is no longer needed */
+ /* The new value is no longer needed */
- genReleaseReg(op2);
+ genReleaseReg(op2);
#ifdef DEBUG
- /* Update the current liveness info */
- if (compiler->opts.varNames) genUpdateLife(tree);
+ /* Update the current liveness info */
+ if (compiler->opts.varNames)
+ genUpdateLife(tree);
#endif
- // This is done in WriteBarrier when (regGC != 0)
- if (regGC == 0)
- {
- /* Free up anything that was tied up by the LHS */
- genDoneAddressable(op1, addrReg, RegSet::KEEP_REG);
+ // This is done in WriteBarrier when (regGC != 0)
+ if (regGC == 0)
+ {
+ /* Free up anything that was tied up by the LHS */
+ genDoneAddressable(op1, addrReg, RegSet::KEEP_REG);
+ }
}
- }
- addrReg = RBM_NONE;
- break;
+ addrReg = RBM_NONE;
+ break;
}
noway_assert(addrReg != DUMMY_INIT(RBM_CORRUPT));
@@ -12194,17 +11964,15 @@ LExit:
* Generate code to complete the assignment operation
*/
-void CodeGen::genCodeForTreeSmpOpAsg_DONE_ASSG(GenTreePtr tree,
- regMaskTP addrReg,
- regNumber reg,
- bool ovfl)
+void CodeGen::genCodeForTreeSmpOpAsg_DONE_ASSG(GenTreePtr tree, regMaskTP addrReg, regNumber reg, bool ovfl)
{
const var_types treeType = tree->TypeGet();
GenTreePtr op1 = tree->gtOp.gtOp1;
GenTreePtr op2 = tree->gtOp.gtOp2;
noway_assert(op2);
- if (op1->gtOper == GT_LCL_VAR || op1->gtOper == GT_REG_VAR) genUpdateLife(op1);
+ if (op1->gtOper == GT_LCL_VAR || op1->gtOper == GT_REG_VAR)
+ genUpdateLife(op1);
genUpdateLife(tree);
#if REDUNDANT_LOAD
@@ -12233,15 +12001,13 @@ void CodeGen::genCodeForTreeSmpOpAsg_DONE_ASSG(GenTreePtr tree,
we must have loaded it up from memory, done the increment,
checked for overflow, and then stored it back to memory */
- bool ovfCheckDone = (genTypeSize(op1->TypeGet()) < sizeof(int)) &&
- !(op1->gtFlags & GTF_REG_VAL);
+ bool ovfCheckDone = (genTypeSize(op1->TypeGet()) < sizeof(int)) && !(op1->gtFlags & GTF_REG_VAL);
if (!ovfCheckDone)
{
// For small sizes, reg should be set as we sign/zero extend it.
- noway_assert(genIsValidReg(reg) ||
- genTypeSize(treeType) == sizeof(int));
+ noway_assert(genIsValidReg(reg) || genTypeSize(treeType) == sizeof(int));
/* Currently we don't morph x=x+y into x+=y in try blocks
* if we need overflow check, as x+y may throw an exception.
@@ -12254,42 +12020,39 @@ void CodeGen::genCodeForTreeSmpOpAsg_DONE_ASSG(GenTreePtr tree,
}
}
-
/*****************************************************************************
*
* Generate code for a special op tree
*/
-void CodeGen::genCodeForTreeSpecialOp(GenTreePtr tree,
- regMaskTP destReg,
- regMaskTP bestReg)
+void CodeGen::genCodeForTreeSpecialOp(GenTreePtr tree, regMaskTP destReg, regMaskTP bestReg)
{
- genTreeOps oper = tree->OperGet();
- regNumber reg = DUMMY_INIT(REG_CORRUPT);
- regMaskTP regs = regSet.rsMaskUsed;
+ genTreeOps oper = tree->OperGet();
+ regNumber reg = DUMMY_INIT(REG_CORRUPT);
+ regMaskTP regs = regSet.rsMaskUsed;
noway_assert((tree->OperKind() & (GTK_CONST | GTK_LEAF | GTK_SMPOP)) == 0);
- switch (oper)
+ switch (oper)
{
- case GT_CALL:
- regs = genCodeForCall(tree, true);
+ case GT_CALL:
+ regs = genCodeForCall(tree, true);
- /* If the result is in a register, make sure it ends up in the right place */
+ /* If the result is in a register, make sure it ends up in the right place */
- if (regs != RBM_NONE)
- {
- genMarkTreeInReg(tree, genRegNumFromMask(regs));
- }
+ if (regs != RBM_NONE)
+ {
+ genMarkTreeInReg(tree, genRegNumFromMask(regs));
+ }
- genUpdateLife(tree);
- return;
+ genUpdateLife(tree);
+ return;
- case GT_FIELD:
- NO_WAY("should not see this operator in this phase");
- break;
+ case GT_FIELD:
+ NO_WAY("should not see this operator in this phase");
+ break;
- case GT_ARR_BOUNDS_CHECK:
+ case GT_ARR_BOUNDS_CHECK:
{
#ifdef FEATURE_ENABLE_NO_RANGE_CHECKS
// MUST NEVER CHECK-IN WITH THIS ENABLED.
@@ -12298,33 +12061,29 @@ void CodeGen::genCodeForTreeSpecialOp(GenTreePtr tree,
#endif
genRangeCheck(tree);
}
- return;
+ return;
- case GT_ARR_ELEM:
- genCodeForTreeSmpOp_GT_ADDR(tree, destReg, bestReg);
- return;
+ case GT_ARR_ELEM:
+ genCodeForTreeSmpOp_GT_ADDR(tree, destReg, bestReg);
+ return;
- case GT_CMPXCHG:
+ case GT_CMPXCHG:
{
#if defined(_TARGET_XARCH_)
// cmpxchg does not have an [r/m32], imm32 encoding, so we need a register for the value operand
-
+
// Since this is a "call", evaluate the operands from right to left. Don't worry about spilling
// right now, just get the trees evaluated.
// As a friendly reminder. IL args are evaluated left to right.
-
- GenTreePtr location = tree->gtCmpXchg.gtOpLocation; // arg1
- GenTreePtr value = tree->gtCmpXchg.gtOpValue; // arg2
- GenTreePtr comparand = tree->gtCmpXchg.gtOpComparand; // arg3
- regMaskTP addrReg;
-
- bool isAddr = genMakeIndAddrMode(location,
- tree,
- false, /* not for LEA */
- RBM_ALLINT,
- RegSet::KEEP_REG,
- &addrReg);
+
+ GenTreePtr location = tree->gtCmpXchg.gtOpLocation; // arg1
+ GenTreePtr value = tree->gtCmpXchg.gtOpValue; // arg2
+ GenTreePtr comparand = tree->gtCmpXchg.gtOpComparand; // arg3
+ regMaskTP addrReg;
+
+ bool isAddr = genMakeIndAddrMode(location, tree, false, /* not for LEA */
+ RBM_ALLINT, RegSet::KEEP_REG, &addrReg);
if (!isAddr)
{
@@ -12334,21 +12093,21 @@ void CodeGen::genCodeForTreeSpecialOp(GenTreePtr tree,
regSet.rsMarkRegUsed(location);
}
- // We must have a reg for the Value, but it doesn't really matter which register.
-
+ // We must have a reg for the Value, but it doesn't really matter which register.
+
// Try to avoid EAX and the address regsiter if possible.
genComputeReg(value, regSet.rsNarrowHint(RBM_ALLINT, RBM_EAX | addrReg), RegSet::ANY_REG, RegSet::KEEP_REG);
#ifdef DEBUG
// cmpxchg uses EAX as an implicit operand to hold the comparand
- // We're going to destroy EAX in this operation, so we better not be keeping
+ // We're going to destroy EAX in this operation, so we better not be keeping
// anything important in it.
if (RBM_EAX & regSet.rsMaskVars)
{
// We have a variable enregistered in EAX. Make sure it goes dead in this tree.
for (unsigned varNum = 0; varNum < compiler->lvaCount; ++varNum)
{
- const LclVarDsc & varDesc = compiler->lvaTable[varNum];
+ const LclVarDsc& varDesc = compiler->lvaTable[varNum];
if (!varDesc.lvIsRegCandidate())
continue;
if (!varDesc.lvRegister)
@@ -12369,14 +12128,14 @@ void CodeGen::genCodeForTreeSpecialOp(GenTreePtr tree,
#endif
genComputeReg(comparand, RBM_EAX, RegSet::EXACT_REG, RegSet::KEEP_REG);
- //By this point we've evaluated everything. However the odds are that we've spilled something by
- //now. Let's recover all the registers and force them to stay.
+ // By this point we've evaluated everything. However the odds are that we've spilled something by
+ // now. Let's recover all the registers and force them to stay.
- //Well, we just computed comparand, so it's still in EAX.
+ // Well, we just computed comparand, so it's still in EAX.
noway_assert(comparand->gtRegNum == REG_EAX);
regSet.rsLockUsedReg(RBM_EAX);
- //Stick it anywhere other than EAX.
+ // Stick it anywhere other than EAX.
genRecoverReg(value, ~RBM_EAX, RegSet::KEEP_REG);
reg = value->gtRegNum;
noway_assert(reg != REG_EAX);
@@ -12384,11 +12143,11 @@ void CodeGen::genCodeForTreeSpecialOp(GenTreePtr tree,
if (isAddr)
{
- addrReg = genKeepAddressable(/*location*/tree, addrReg, 0/*avoidMask*/);
+ addrReg = genKeepAddressable(/*location*/ tree, addrReg, 0 /*avoidMask*/);
}
else
{
- genRecoverReg(location, ~(RBM_EAX|genRegMask(reg)), RegSet::KEEP_REG);
+ genRecoverReg(location, ~(RBM_EAX | genRegMask(reg)), RegSet::KEEP_REG);
}
regSet.rsUnlockUsedReg(genRegMask(reg));
@@ -12409,7 +12168,7 @@ void CodeGen::genCodeForTreeSpecialOp(GenTreePtr tree,
genReleaseReg(value);
genReleaseReg(comparand);
- //EAX and the value register are both trashed at this point.
+ // EAX and the value register are both trashed at this point.
regTracker.rsTrackRegTrash(REG_EAX);
regTracker.rsTrackRegTrash(reg);
@@ -12423,25 +12182,24 @@ void CodeGen::genCodeForTreeSpecialOp(GenTreePtr tree,
#endif
}
- default:
-#ifdef DEBUG
- compiler->gtDispTree(tree);
+ default:
+#ifdef DEBUG
+ compiler->gtDispTree(tree);
#endif
- noway_assert(!"unexpected operator");
- NO_WAY("unexpected operator");
+ noway_assert(!"unexpected operator");
+ NO_WAY("unexpected operator");
}
noway_assert(reg != DUMMY_INIT(REG_CORRUPT));
genCodeForTree_DONE(tree, reg);
}
-
/*****************************************************************************
*
* Generate code for the given tree. tree->gtRegNum will be set to the
* register where the tree lives.
*
- * If 'destReg' is non-zero, we'll do our best to compute the value into a
+ * If 'destReg' is non-zero, we'll do our best to compute the value into a
* register that is in that register set.
* Use genComputeReg() if you need the tree in a specific register.
* Use genCompIntoFreeReg() if the register needs to be written to. Otherwise,
@@ -12452,13 +12210,11 @@ void CodeGen::genCodeForTreeSpecialOp(GenTreePtr tree,
*
* The GCness of the register will be properly set in gcInfo.gcRegGCrefSetCur/gcInfo.gcRegByrefSetCur.
*
- * The register will not be marked as used. Use regSet.rsMarkRegUsed() if the
+ * The register will not be marked as used. Use regSet.rsMarkRegUsed() if the
* register will not be consumed right away and could possibly be spilled.
*/
-void CodeGen::genCodeForTree(GenTreePtr tree,
- regMaskTP destReg,
- regMaskTP bestReg)
+void CodeGen::genCodeForTree(GenTreePtr tree, regMaskTP destReg, regMaskTP bestReg)
{
#if 0
if (compiler->verbose)
@@ -12475,25 +12231,25 @@ void CodeGen::genCodeForTree(GenTreePtr tree,
assert(tree->IsNodeProperlySized());
// When assigning to a enregistered local variable we receive
- // a hint that we should target the register that is used to
+ // a hint that we should target the register that is used to
// hold the enregistered local variable.
// When receiving this hint both destReg and bestReg masks are set
// to the register that is used by the enregistered local variable.
- //
+ //
// However it is possible to us to have a different local variable
// targeting the same register to become alive (and later die)
// as we descend the expression tree.
- //
- // To handle such cases we will remove any registers that are alive from the
+ //
+ // To handle such cases we will remove any registers that are alive from the
// both the destReg and bestReg masks.
- //
+ //
regMaskTP liveMask = genLiveMask(tree);
// This removes any registers used to hold enregistered locals
// from the destReg and bestReg masks.
// After this either mask could become 0
- //
- destReg &= ~liveMask;
+ //
+ destReg &= ~liveMask;
bestReg &= ~liveMask;
/* 'destReg' of 0 really means 'any' */
@@ -12507,41 +12263,40 @@ void CodeGen::genCodeForTree(GenTreePtr tree,
switch (tree->TypeGet())
{
- case TYP_LONG:
-#if ! CPU_HAS_FP_SUPPORT
- case TYP_DOUBLE:
+ case TYP_LONG:
+#if !CPU_HAS_FP_SUPPORT
+ case TYP_DOUBLE:
#endif
- genCodeForTreeLng(tree, destReg, /*avoidReg*/RBM_NONE);
- return;
-
+ genCodeForTreeLng(tree, destReg, /*avoidReg*/ RBM_NONE);
+ return;
#if CPU_HAS_FP_SUPPORT
- case TYP_FLOAT:
- case TYP_DOUBLE:
-
- // For comma nodes, we'll get back here for the last node in the comma list.
- if (tree->gtOper != GT_COMMA)
- {
- genCodeForTreeFlt(tree, RBM_ALLFLOAT, RBM_ALLFLOAT & (destReg | bestReg));
- return;
- }
- break;
+ case TYP_FLOAT:
+ case TYP_DOUBLE:
+
+ // For comma nodes, we'll get back here for the last node in the comma list.
+ if (tree->gtOper != GT_COMMA)
+ {
+ genCodeForTreeFlt(tree, RBM_ALLFLOAT, RBM_ALLFLOAT & (destReg | bestReg));
+ return;
+ }
+ break;
#endif
#ifdef DEBUG
- case TYP_UINT:
- case TYP_ULONG:
- noway_assert(!"These types are only used as markers in GT_CAST nodes");
- break;
+ case TYP_UINT:
+ case TYP_ULONG:
+ noway_assert(!"These types are only used as markers in GT_CAST nodes");
+ break;
#endif
- default:
- break;
+ default:
+ break;
}
/* Is the value already in a register? */
- if (tree->gtFlags & GTF_REG_VAL)
+ if (tree->gtFlags & GTF_REG_VAL)
{
genCodeForTree_REG_VAR1(tree);
return;
@@ -12555,7 +12310,7 @@ void CodeGen::genCodeForTree(GenTreePtr tree,
unsigned kind = tree->OperKind();
- if (kind & GTK_CONST)
+ if (kind & GTK_CONST)
{
/* Handle constant nodes */
@@ -12581,7 +12336,6 @@ void CodeGen::genCodeForTree(GenTreePtr tree,
}
}
-
/*****************************************************************************
*
* Generate code for all the basic blocks in the function.
@@ -12589,20 +12343,20 @@ void CodeGen::genCodeForTree(GenTreePtr tree,
#ifdef _PREFAST_
#pragma warning(push)
-#pragma warning(disable:21000) // Suppress PREFast warning about overly large function
+#pragma warning(disable : 21000) // Suppress PREFast warning about overly large function
#endif
-void CodeGen::genCodeForBBlist()
+void CodeGen::genCodeForBBlist()
{
- unsigned varNum;
- LclVarDsc * varDsc;
+ unsigned varNum;
+ LclVarDsc* varDsc;
- unsigned savedStkLvl;
+ unsigned savedStkLvl;
-#ifdef DEBUG
- genInterruptibleUsed = true;
- unsigned stmtNum = 0;
- unsigned totalCostEx = 0;
- unsigned totalCostSz = 0;
+#ifdef DEBUG
+ genInterruptibleUsed = true;
+ unsigned stmtNum = 0;
+ unsigned totalCostEx = 0;
+ unsigned totalCostSz = 0;
// You have to be careful if you create basic blocks from now on
compiler->fgSafeBasicBlockCreation = false;
@@ -12623,7 +12377,8 @@ void CodeGen::genCodeForBBlist()
// Prepare the blocks for exception handling codegen: mark the blocks that needs labels.
genPrepForEHCodegen();
- assert(!compiler->fgFirstBBScratch || compiler->fgFirstBB == compiler->fgFirstBBScratch); // compiler->fgFirstBBScratch has to be first.
+ assert(!compiler->fgFirstBBScratch ||
+ compiler->fgFirstBB == compiler->fgFirstBBScratch); // compiler->fgFirstBBScratch has to be first.
/* Initialize the spill tracking logic */
@@ -12631,14 +12386,13 @@ void CodeGen::genCodeForBBlist()
#ifdef DEBUGGING_SUPPORT
/* Initialize the line# tracking logic */
-
+
if (compiler->opts.compScopeInfo)
{
siInit();
}
#endif
-
#ifdef _TARGET_X86_
if (compiler->compTailCallUsed)
{
@@ -12657,7 +12411,7 @@ void CodeGen::genCodeForBBlist()
if (compiler->info.compCallUnmanaged)
{
- noway_assert(isFramePointerUsed()); // Setup of Pinvoke frame currently requires an EBP style frame
+ noway_assert(isFramePointerUsed()); // Setup of Pinvoke frame currently requires an EBP style frame
regSet.rsSetRegsModified(RBM_INT_CALLEE_SAVED & ~RBM_FPBASE);
}
@@ -12668,18 +12422,16 @@ void CodeGen::genCodeForBBlist()
/* If any arguments live in registers, mark those regs as such */
- for (varNum = 0, varDsc = compiler->lvaTable;
- varNum < compiler->lvaCount;
- varNum++ , varDsc++)
+ for (varNum = 0, varDsc = compiler->lvaTable; varNum < compiler->lvaCount; varNum++, varDsc++)
{
/* Is this variable a parameter assigned to a register? */
- if (!varDsc->lvIsParam || !varDsc->lvRegister)
+ if (!varDsc->lvIsParam || !varDsc->lvRegister)
continue;
/* Is the argument live on entry to the method? */
- if (!VarSetOps::IsMember(compiler, compiler->fgFirstBB->bbLiveIn, varDsc->lvVarIndex))
+ if (!VarSetOps::IsMember(compiler, compiler->fgFirstBB->bbLiveIn, varDsc->lvVarIndex))
continue;
#if CPU_HAS_FP_SUPPORT
@@ -12693,11 +12445,11 @@ void CodeGen::genCodeForBBlist()
/* Mark the register as holding the variable */
- if (isRegPairType(varDsc->lvType))
+ if (isRegPairType(varDsc->lvType))
{
regTracker.rsTrackRegLclVarLng(varDsc->lvRegNum, varNum, true);
- if (varDsc->lvOtherReg != REG_STK)
+ if (varDsc->lvOtherReg != REG_STK)
regTracker.rsTrackRegLclVarLng(varDsc->lvOtherReg, varNum, false);
}
else
@@ -12711,19 +12463,17 @@ void CodeGen::genCodeForBBlist()
// Make sure a set is allocated for compiler->compCurLife (in the long case), so we can set it to empty without
// allocation at the start of each basic block.
VarSetOps::AssignNoCopy(compiler, compiler->compCurLife, VarSetOps::MakeEmpty(compiler));
-
+
/*-------------------------------------------------------------------------
*
* Walk the basic blocks and generate code for each one
*
*/
- BasicBlock * block;
- BasicBlock * lblk; /* previous block */
+ BasicBlock* block;
+ BasicBlock* lblk; /* previous block */
- for (lblk = NULL, block = compiler->fgFirstBB;
- block != NULL;
- lblk = block, block = block->bbNext)
+ for (lblk = NULL, block = compiler->fgFirstBB; block != NULL; lblk = block, block = block->bbNext)
{
#ifdef DEBUG
if (compiler->verbose)
@@ -12734,14 +12484,14 @@ void CodeGen::genCodeForBBlist()
}
#endif // DEBUG
- VARSET_TP VARSET_INIT_NOCOPY(liveSet, VarSetOps::UninitVal());
+ VARSET_TP VARSET_INIT_NOCOPY(liveSet, VarSetOps::UninitVal());
- regMaskTP gcrefRegs = 0;
- regMaskTP byrefRegs = 0;
+ regMaskTP gcrefRegs = 0;
+ regMaskTP byrefRegs = 0;
/* Does any other block jump to this point ? */
- if (block->bbFlags & BBF_JMP_TARGET)
+ if (block->bbFlags & BBF_JMP_TARGET)
{
/* Someone may jump here, so trash all regs */
@@ -12758,11 +12508,11 @@ void CodeGen::genCodeForBBlist()
/* No registers are used or locked on entry to a basic block */
- regSet.rsMaskUsed = RBM_NONE;
- regSet.rsMaskMult = RBM_NONE;
- regSet.rsMaskLock = RBM_NONE;
+ regSet.rsMaskUsed = RBM_NONE;
+ regSet.rsMaskMult = RBM_NONE;
+ regSet.rsMaskLock = RBM_NONE;
- // If we need to reserve registers such that they are not used
+ // If we need to reserve registers such that they are not used
// by CodeGen in this BasicBlock we do so here.
// On the ARM when we have large frame offsets for locals we
// will have RBM_R10 in the regSet.rsMaskResvd set,
@@ -12771,30 +12521,28 @@ void CodeGen::genCodeForBBlist()
//
if (regSet.rsMaskResvd != RBM_NONE)
{
- regSet.rsLockReg(regSet.rsMaskResvd);
+ regSet.rsLockReg(regSet.rsMaskResvd);
regSet.rsSetRegsModified(regSet.rsMaskResvd);
}
/* Figure out which registers hold variables on entry to this block */
-
+
regMaskTP specialUseMask = regSet.rsMaskResvd;
- specialUseMask |= doubleAlignOrFramePointerUsed() ? RBM_SPBASE|RBM_FPBASE
- : RBM_SPBASE;
+ specialUseMask |= doubleAlignOrFramePointerUsed() ? RBM_SPBASE | RBM_FPBASE : RBM_SPBASE;
regSet.ClearMaskVars();
VarSetOps::ClearD(compiler, compiler->compCurLife);
VarSetOps::Assign(compiler, liveSet, block->bbLiveIn);
#if FEATURE_STACK_FP_X87
- VarSetOps::AssignNoCopy(compiler,
- genFPregVars,
+ VarSetOps::AssignNoCopy(compiler, genFPregVars,
VarSetOps::Intersection(compiler, liveSet, compiler->optAllFPregVars));
genFPregCnt = VarSetOps::Count(compiler, genFPregVars);
genFPdeadRegCnt = 0;
#endif
gcInfo.gcResetForBB();
-
- genUpdateLife(liveSet); // This updates regSet.rsMaskVars with bits from any enregistered LclVars
+
+ genUpdateLife(liveSet); // This updates regSet.rsMaskVars with bits from any enregistered LclVars
#if FEATURE_STACK_FP_X87
VarSetOps::IntersectionD(compiler, liveSet, compiler->optAllNonFPvars);
#endif
@@ -12810,20 +12558,20 @@ void CodeGen::genCodeForBBlist()
assert(varDsc->lvTracked);
/* Ignore the variable if it's not not in a reg */
- if (!varDsc->lvRegister)
+ if (!varDsc->lvRegister)
continue;
if (isFloatRegType(varDsc->lvType))
continue;
/* Get hold of the index and the bitmask for the variable */
- regNumber regNum = varDsc->lvRegNum;
- regMaskTP regMask = genRegMask(regNum);
+ regNumber regNum = varDsc->lvRegNum;
+ regMaskTP regMask = genRegMask(regNum);
regSet.AddMaskVars(regMask);
- if (varDsc->lvType == TYP_REF)
+ if (varDsc->lvType == TYP_REF)
gcrefRegs |= regMask;
- else if (varDsc->lvType == TYP_BYREF)
+ else if (varDsc->lvType == TYP_BYREF)
byrefRegs |= regMask;
/* Mark the register holding the variable as such */
@@ -12831,7 +12579,7 @@ void CodeGen::genCodeForBBlist()
if (varTypeIsMultiReg(varDsc))
{
regTracker.rsTrackRegLclVarLng(regNum, varNum, true);
- if (varDsc->lvOtherReg != REG_STK)
+ if (varDsc->lvOtherReg != REG_STK)
{
regTracker.rsTrackRegLclVarLng(varDsc->lvOtherReg, varNum, false);
regMask |= genRegMask(varDsc->lvOtherReg);
@@ -12843,13 +12591,11 @@ void CodeGen::genCodeForBBlist()
}
}
- gcInfo.gcPtrArgCnt = 0;
+ gcInfo.gcPtrArgCnt = 0;
#if FEATURE_STACK_FP_X87
- regSet.rsMaskUsedFloat =
- regSet.rsMaskRegVarFloat =
- regSet.rsMaskLockedFloat = RBM_NONE;
+ regSet.rsMaskUsedFloat = regSet.rsMaskRegVarFloat = regSet.rsMaskLockedFloat = RBM_NONE;
memset(regSet.genUsedRegsFloat, 0, sizeof(regSet.genUsedRegsFloat));
memset(regSet.genRegVarsFloat, 0, sizeof(regSet.genRegVarsFloat));
@@ -12872,7 +12618,7 @@ void CodeGen::genCodeForBBlist()
gcInfo.gcRegByrefSetCur = byrefRegs;
/* Blocks with handlerGetsXcptnObj()==true use GT_CATCH_ARG to
- represent the exception object (TYP_REF).
+ represent the exception object (TYP_REF).
We mark REG_EXCEPTION_OBJECT as holding a GC object on entry
to the block, it will be the first thing evaluated
(thanks to GTF_ORDER_SIDEEFF).
@@ -12880,7 +12626,7 @@ void CodeGen::genCodeForBBlist()
if (handlerGetsXcptnObj(block->bbCatchTyp))
{
- GenTreePtr firstStmt = block->FirstNonPhiDef();
+ GenTreePtr firstStmt = block->FirstNonPhiDef();
if (firstStmt != NULL)
{
GenTreePtr firstTree = firstStmt->gtStmt.gtStmtExpr;
@@ -12903,7 +12649,7 @@ void CodeGen::genCodeForBBlist()
{
assert(block->bbFlags & BBF_JMP_TARGET);
-#ifdef DEBUG
+#ifdef DEBUG
if (compiler->verbose)
{
printf("\nEmitting finally target NOP predecessor for BB%02u\n", block->bbNum);
@@ -12915,10 +12661,8 @@ void CodeGen::genCodeForBBlist()
// block starts an EH region. If we pointed the existing bbEmitCookie here, then the NOP
// would be executed, which we would prefer not to do.
- block->bbUnwindNopEmitCookie = getEmitter()->emitAddLabel(
- gcInfo.gcVarPtrSetCur,
- gcInfo.gcRegGCrefSetCur,
- gcInfo.gcRegByrefSetCur);
+ block->bbUnwindNopEmitCookie =
+ getEmitter()->emitAddLabel(gcInfo.gcVarPtrSetCur, gcInfo.gcRegGCrefSetCur, gcInfo.gcRegByrefSetCur);
instGen(INS_nop);
}
@@ -12934,27 +12678,25 @@ void CodeGen::genCodeForBBlist()
}
#endif
-#ifdef DEBUG
- if (compiler->opts.dspCode)
+#ifdef DEBUG
+ if (compiler->opts.dspCode)
printf("\n L_M%03u_BB%02u:\n", Compiler::s_compMethodsCount, block->bbNum);
#endif
block->bbEmitCookie = NULL;
- if (block->bbFlags & (BBF_JMP_TARGET|BBF_HAS_LABEL))
+ if (block->bbFlags & (BBF_JMP_TARGET | BBF_HAS_LABEL))
{
/* Mark a label and update the current set of live GC refs */
- block->bbEmitCookie = getEmitter()->emitAddLabel(
- gcInfo.gcVarPtrSetCur,
- gcInfo.gcRegGCrefSetCur,
- gcInfo.gcRegByrefSetCur,
+ block->bbEmitCookie =
+ getEmitter()->emitAddLabel(gcInfo.gcVarPtrSetCur, gcInfo.gcRegGCrefSetCur, gcInfo.gcRegByrefSetCur,
#if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
- /*isFinally*/block->bbFlags & BBF_FINALLY_TARGET
+ /*isFinally*/ block->bbFlags & BBF_FINALLY_TARGET
#else
- FALSE
+ FALSE
#endif
- );
+ );
}
if (block == compiler->fgFirstColdBlock)
@@ -12968,7 +12710,7 @@ void CodeGen::genCodeForBBlist()
// We should never have a block that falls through into the Cold section
noway_assert(!lblk->bbFallsThrough());
- // We require the block that starts the Cold section to have a label
+ // We require the block that starts the Cold section to have a label
noway_assert(block->bbEmitCookie);
getEmitter()->emitSetFirstColdIGCookie(block->bbEmitCookie);
}
@@ -12983,19 +12725,19 @@ void CodeGen::genCodeForBBlist()
#if !FEATURE_FIXED_OUT_ARGS
/* Check for inserted throw blocks and adjust genStackLevel */
- if (!isFramePointerUsed() && compiler->fgIsThrowHlpBlk(block))
+ if (!isFramePointerUsed() && compiler->fgIsThrowHlpBlk(block))
{
noway_assert(block->bbFlags & BBF_JMP_TARGET);
genStackLevel = compiler->fgThrowHlpBlkStkLevel(block) * sizeof(int);
- if (genStackLevel)
+ if (genStackLevel)
{
#ifdef _TARGET_X86_
getEmitter()->emitMarkStackLvl(genStackLevel);
inst_RV_IV(INS_add, REG_SPBASE, genStackLevel, EA_PTRSIZE);
genStackLevel = 0;
-#else // _TARGET_X86_
+#else // _TARGET_X86_
NYI("Need emitMarkStackLvl()");
#endif // _TARGET_X86_
}
@@ -13013,9 +12755,9 @@ void CodeGen::genCodeForBBlist()
// BBF_INTERNAL blocks don't correspond to any single IL instruction.
if (compiler->opts.compDbgInfo && (block->bbFlags & BBF_INTERNAL) && block != compiler->fgFirstBB)
- genIPmappingAdd((IL_OFFSETX) ICorDebugInfo::NO_MAPPING, true);
+ genIPmappingAdd((IL_OFFSETX)ICorDebugInfo::NO_MAPPING, true);
- bool firstMapping = true;
+ bool firstMapping = true;
#endif // DEBUGGING_SUPPORT
/*---------------------------------------------------------------------
@@ -13064,15 +12806,16 @@ void CodeGen::genCodeForBBlist()
#endif // DEBUG
/* Get hold of the statement tree */
- GenTreePtr tree = stmt->gtStmt.gtStmtExpr;
+ GenTreePtr tree = stmt->gtStmt.gtStmtExpr;
-#ifdef DEBUG
+#ifdef DEBUG
stmtNum++;
if (compiler->verbose)
{
printf("\nGenerating BB%02u, stmt %u\t\t", block->bbNum, stmtNum);
printf("Holding variables: ");
- dspRegMask(regSet.rsMaskVars); printf("\n\n");
+ dspRegMask(regSet.rsMaskVars);
+ printf("\n\n");
compiler->gtDispTree(compiler->opts.compDbgInfo ? stmt : tree);
printf("\n");
#if FEATURE_STACK_FP_X87
@@ -13080,16 +12823,14 @@ void CodeGen::genCodeForBBlist()
#endif
printf("Execution Order:\n");
- for (GenTreePtr treeNode = stmt->gtStmt.gtStmtList;
- treeNode != NULL;
- treeNode = treeNode->gtNext)
+ for (GenTreePtr treeNode = stmt->gtStmt.gtStmtList; treeNode != NULL; treeNode = treeNode->gtNext)
{
compiler->gtDispTree(treeNode, 0, NULL, true);
}
printf("\n");
}
totalCostEx += (stmt->gtCostEx * block->getBBWeight(compiler));
- totalCostSz += stmt->gtCostSz;
+ totalCostSz += stmt->gtCostSz;
#endif // DEBUG
compiler->compCurStmt = stmt;
@@ -13097,34 +12838,34 @@ void CodeGen::genCodeForBBlist()
compiler->compCurLifeTree = NULL;
switch (tree->gtOper)
{
- case GT_CALL:
- // Managed Retval under managed debugger - we need to make sure that the returned ref-type is
- // reported as alive even though not used within the caller for managed debugger sake. So
- // consider the return value of the method as used if generating debuggable code.
- genCodeForCall(tree, compiler->opts.MinOpts() || compiler->opts.compDbgCode);
- genUpdateLife (tree);
- gcInfo.gcMarkRegSetNpt(RBM_INTRET);
- break;
+ case GT_CALL:
+ // Managed Retval under managed debugger - we need to make sure that the returned ref-type is
+ // reported as alive even though not used within the caller for managed debugger sake. So
+ // consider the return value of the method as used if generating debuggable code.
+ genCodeForCall(tree, compiler->opts.MinOpts() || compiler->opts.compDbgCode);
+ genUpdateLife(tree);
+ gcInfo.gcMarkRegSetNpt(RBM_INTRET);
+ break;
- case GT_IND:
- case GT_NULLCHECK:
+ case GT_IND:
+ case GT_NULLCHECK:
- // Just do the side effects
- genEvalSideEffects(tree);
- break;
+ // Just do the side effects
+ genEvalSideEffects(tree);
+ break;
- default:
- /* Generate code for the tree */
+ default:
+ /* Generate code for the tree */
- genCodeForTree(tree, 0);
- break;
+ genCodeForTree(tree, 0);
+ break;
}
regSet.rsSpillChk();
/* The value of the tree isn't used, unless it's a return stmt */
- if (tree->gtOper != GT_RETURN)
+ if (tree->gtOper != GT_RETURN)
gcInfo.gcMarkRegPtrVal(tree);
#if FEATURE_STACK_FP_X87
@@ -13134,7 +12875,7 @@ void CodeGen::genCodeForBBlist()
#ifdef DEBUG
/* Make sure we didn't bungle pointer register tracking */
- regMaskTP ptrRegs = (gcInfo.gcRegGCrefSetCur|gcInfo.gcRegByrefSetCur);
+ regMaskTP ptrRegs = (gcInfo.gcRegGCrefSetCur | gcInfo.gcRegByrefSetCur);
regMaskTP nonVarPtrRegs = ptrRegs & ~regSet.rsMaskVars;
// If return is a GC-type, clear it. Note that if a common
@@ -13142,9 +12883,8 @@ void CodeGen::genCodeForBBlist()
// even though we might return a ref. We can't use the compRetType
// as the determiner because something we are tracking as a byref
// might be used as a return value of a int function (which is legal)
- if (tree->gtOper == GT_RETURN &&
- (varTypeIsGC(compiler->info.compRetType) ||
- (tree->gtOp.gtOp1 != 0 && varTypeIsGC(tree->gtOp.gtOp1->TypeGet()))))
+ if (tree->gtOper == GT_RETURN && (varTypeIsGC(compiler->info.compRetType) ||
+ (tree->gtOp.gtOp1 != 0 && varTypeIsGC(tree->gtOp.gtOp1->TypeGet()))))
{
nonVarPtrRegs &= ~RBM_INTRET;
}
@@ -13153,14 +12893,13 @@ void CodeGen::genCodeForBBlist()
// harmless "inc" instruction (does not interfere with the exception
// object).
- if ((compiler->opts.eeFlags & CORJIT_FLG_BBINSTR) &&
- (stmt == block->bbTreeList) &&
+ if ((compiler->opts.eeFlags & CORJIT_FLG_BBINSTR) && (stmt == block->bbTreeList) &&
(block->bbCatchTyp && handlerGetsXcptnObj(block->bbCatchTyp)))
{
nonVarPtrRegs &= ~RBM_EXCEPTION_OBJECT;
}
- if (nonVarPtrRegs)
+ if (nonVarPtrRegs)
{
printf("Regset after tree=");
Compiler::printTreeID(tree);
@@ -13187,7 +12926,7 @@ void CodeGen::genCodeForBBlist()
} //-------- END-FOR each statement-tree of the current block ---------
-#ifdef DEBUGGING_SUPPORT
+#ifdef DEBUGGING_SUPPORT
if (compiler->opts.compScopeInfo && (compiler->info.compVarScopesCount > 0))
{
@@ -13208,7 +12947,7 @@ void CodeGen::genCodeForBBlist()
are at the end of the method. It would be nice if we could fix
our code so that this throw block will no longer be necessary. */
- //noway_assert(block->bbCodeOffsEnd != compiler->info.compILCodeSize);
+ // noway_assert(block->bbCodeOffsEnd != compiler->info.compILCodeSize);
siCloseAllOpenScopes();
}
@@ -13218,9 +12957,9 @@ void CodeGen::genCodeForBBlist()
genStackLevel -= savedStkLvl;
- gcInfo.gcMarkRegSetNpt(gcrefRegs|byrefRegs);
+ gcInfo.gcMarkRegSetNpt(gcrefRegs | byrefRegs);
- if (!VarSetOps::Equal(compiler, compiler->compCurLife, block->bbLiveOut))
+ if (!VarSetOps::Equal(compiler, compiler->compCurLife, block->bbLiveOut))
compiler->genChangeLife(block->bbLiveOut DEBUGARG(NULL));
/* Both stacks should always be empty on exit from a basic block */
@@ -13239,113 +12978,114 @@ void CodeGen::genCodeForBBlist()
switch (block->bbJumpKind)
{
- case BBJ_ALWAYS:
- inst_JMP(EJ_jmp, block->bbJumpDest);
- break;
+ case BBJ_ALWAYS:
+ inst_JMP(EJ_jmp, block->bbJumpDest);
+ break;
- case BBJ_RETURN:
- genExitCode(block);
- break;
+ case BBJ_RETURN:
+ genExitCode(block);
+ break;
- case BBJ_THROW:
- // If we have a throw at the end of a function or funclet, we need to emit another instruction
- // afterwards to help the OS unwinder determine the correct context during unwind.
- // We insert an unexecuted breakpoint instruction in several situations
- // following a throw instruction:
- // 1. If the throw is the last instruction of the function or funclet. This helps
- // the OS unwinder determine the correct context during an unwind from the
- // thrown exception.
- // 2. If this is this is the last block of the hot section.
- // 3. If the subsequent block is a special throw block.
- if ((block->bbNext == NULL)
+ case BBJ_THROW:
+ // If we have a throw at the end of a function or funclet, we need to emit another instruction
+ // afterwards to help the OS unwinder determine the correct context during unwind.
+ // We insert an unexecuted breakpoint instruction in several situations
+ // following a throw instruction:
+ // 1. If the throw is the last instruction of the function or funclet. This helps
+ // the OS unwinder determine the correct context during an unwind from the
+ // thrown exception.
+ // 2. If this is this is the last block of the hot section.
+ // 3. If the subsequent block is a special throw block.
+ if ((block->bbNext == NULL)
#if FEATURE_EH_FUNCLETS
- || (block->bbNext->bbFlags & BBF_FUNCLET_BEG)
+ || (block->bbNext->bbFlags & BBF_FUNCLET_BEG)
#endif // FEATURE_EH_FUNCLETS
- || (!isFramePointerUsed() && compiler->fgIsThrowHlpBlk(block->bbNext))
- || block->bbNext == compiler->fgFirstColdBlock
- )
- {
- instGen(INS_BREAKPOINT); // This should never get executed
- }
+ || (!isFramePointerUsed() && compiler->fgIsThrowHlpBlk(block->bbNext)) ||
+ block->bbNext == compiler->fgFirstColdBlock)
+ {
+ instGen(INS_BREAKPOINT); // This should never get executed
+ }
- break;
+ break;
- case BBJ_CALLFINALLY:
+ case BBJ_CALLFINALLY:
#if defined(_TARGET_X86_)
- /* If we are about to invoke a finally locally from a try block,
- we have to set the hidden slot corresponding to the finally's
- nesting level. When invoked in response to an exception, the
- EE usually does it.
+ /* If we are about to invoke a finally locally from a try block,
+ we have to set the hidden slot corresponding to the finally's
+ nesting level. When invoked in response to an exception, the
+ EE usually does it.
- We must have : BBJ_CALLFINALLY followed by a BBJ_ALWAYS.
+ We must have : BBJ_CALLFINALLY followed by a BBJ_ALWAYS.
- This code depends on this order not being messed up.
- We will emit :
- mov [ebp-(n+1)],0
- mov [ebp- n ],0xFC
- push &step
- jmp finallyBlock
+ This code depends on this order not being messed up.
+ We will emit :
+ mov [ebp-(n+1)],0
+ mov [ebp- n ],0xFC
+ push &step
+ jmp finallyBlock
- step: mov [ebp- n ],0
- jmp leaveTarget
- leaveTarget:
- */
+ step: mov [ebp- n ],0
+ jmp leaveTarget
+ leaveTarget:
+ */
- noway_assert(isFramePointerUsed());
+ noway_assert(isFramePointerUsed());
- // Get the nesting level which contains the finally
- compiler->fgGetNestingLevel(block, &finallyNesting);
+ // Get the nesting level which contains the finally
+ compiler->fgGetNestingLevel(block, &finallyNesting);
- // The last slot is reserved for ICodeManager::FixContext(ppEndRegion)
- unsigned filterEndOffsetSlotOffs;
- filterEndOffsetSlotOffs = (unsigned)(compiler->lvaLclSize(compiler->lvaShadowSPslotsVar) - (sizeof(void*)));
-
- unsigned curNestingSlotOffs;
- curNestingSlotOffs = (unsigned)(filterEndOffsetSlotOffs - ((finallyNesting + 1) * sizeof(void*)));
-
- // Zero out the slot for the next nesting level
- instGen_Store_Imm_Into_Lcl(TYP_I_IMPL, EA_PTRSIZE, 0,
- compiler->lvaShadowSPslotsVar, curNestingSlotOffs - sizeof(void*));
+ // The last slot is reserved for ICodeManager::FixContext(ppEndRegion)
+ unsigned filterEndOffsetSlotOffs;
+ filterEndOffsetSlotOffs =
+ (unsigned)(compiler->lvaLclSize(compiler->lvaShadowSPslotsVar) - (sizeof(void*)));
- instGen_Store_Imm_Into_Lcl(TYP_I_IMPL, EA_PTRSIZE, LCL_FINALLY_MARK,
- compiler->lvaShadowSPslotsVar, curNestingSlotOffs);
+ unsigned curNestingSlotOffs;
+ curNestingSlotOffs = (unsigned)(filterEndOffsetSlotOffs - ((finallyNesting + 1) * sizeof(void*)));
- // Now push the address of where the finally funclet should
- // return to directly.
- if ( !(block->bbFlags & BBF_RETLESS_CALL) )
- {
- assert(block->isBBCallAlwaysPair());
- getEmitter()->emitIns_J(INS_push_hide, block->bbNext->bbJumpDest);
- }
- else
- {
- // EE expects a DWORD, so we give him 0
- inst_IV(INS_push_hide, 0);
- }
+ // Zero out the slot for the next nesting level
+ instGen_Store_Imm_Into_Lcl(TYP_I_IMPL, EA_PTRSIZE, 0, compiler->lvaShadowSPslotsVar,
+ curNestingSlotOffs - sizeof(void*));
+
+ instGen_Store_Imm_Into_Lcl(TYP_I_IMPL, EA_PTRSIZE, LCL_FINALLY_MARK, compiler->lvaShadowSPslotsVar,
+ curNestingSlotOffs);
- // Jump to the finally BB
- inst_JMP(EJ_jmp, block->bbJumpDest);
+ // Now push the address of where the finally funclet should
+ // return to directly.
+ if (!(block->bbFlags & BBF_RETLESS_CALL))
+ {
+ assert(block->isBBCallAlwaysPair());
+ getEmitter()->emitIns_J(INS_push_hide, block->bbNext->bbJumpDest);
+ }
+ else
+ {
+ // EE expects a DWORD, so we give him 0
+ inst_IV(INS_push_hide, 0);
+ }
+
+ // Jump to the finally BB
+ inst_JMP(EJ_jmp, block->bbJumpDest);
#elif defined(_TARGET_ARM_)
- // Now set REG_LR to the address of where the finally funclet should
- // return to directly.
+ // Now set REG_LR to the address of where the finally funclet should
+ // return to directly.
- BasicBlock * bbFinallyRet; bbFinallyRet = NULL;
+ BasicBlock* bbFinallyRet;
+ bbFinallyRet = NULL;
- // We don't have retless calls, since we use the BBJ_ALWAYS to point at a NOP pad where
- // we would have otherwise created retless calls.
- assert(block->isBBCallAlwaysPair());
+ // We don't have retless calls, since we use the BBJ_ALWAYS to point at a NOP pad where
+ // we would have otherwise created retless calls.
+ assert(block->isBBCallAlwaysPair());
- assert(block->bbNext != NULL);
- assert(block->bbNext->bbJumpKind == BBJ_ALWAYS);
- assert(block->bbNext->bbJumpDest != NULL);
- assert(block->bbNext->bbJumpDest->bbFlags & BBF_FINALLY_TARGET);
+ assert(block->bbNext != NULL);
+ assert(block->bbNext->bbJumpKind == BBJ_ALWAYS);
+ assert(block->bbNext->bbJumpDest != NULL);
+ assert(block->bbNext->bbJumpDest->bbFlags & BBF_FINALLY_TARGET);
- bbFinallyRet = block->bbNext->bbJumpDest;
- bbFinallyRet->bbFlags |= BBF_JMP_TARGET;
+ bbFinallyRet = block->bbNext->bbJumpDest;
+ bbFinallyRet->bbFlags |= BBF_JMP_TARGET;
#if 0
// We don't know the address of finally funclet yet. But adr requires the offset
@@ -13355,81 +13095,69 @@ void CodeGen::genCodeForBBlist()
EA_4BYTE,
bbFinallyRet,
REG_LR);
-#else // 0
- // Load the address where the finally funclet should return into LR.
- // The funclet prolog/epilog will do "push {lr}" / "pop {pc}" to do
- // the return.
- getEmitter()->emitIns_R_L (INS_movw,
- EA_4BYTE_DSP_RELOC,
- bbFinallyRet,
- REG_LR);
- getEmitter()->emitIns_R_L (INS_movt,
- EA_4BYTE_DSP_RELOC,
- bbFinallyRet,
- REG_LR);
- regTracker.rsTrackRegTrash(REG_LR);
+#else // 0
+ // Load the address where the finally funclet should return into LR.
+ // The funclet prolog/epilog will do "push {lr}" / "pop {pc}" to do
+ // the return.
+ getEmitter()->emitIns_R_L(INS_movw, EA_4BYTE_DSP_RELOC, bbFinallyRet, REG_LR);
+ getEmitter()->emitIns_R_L(INS_movt, EA_4BYTE_DSP_RELOC, bbFinallyRet, REG_LR);
+ regTracker.rsTrackRegTrash(REG_LR);
#endif // 0
- // Jump to the finally BB
- inst_JMP(EJ_jmp, block->bbJumpDest);
+ // Jump to the finally BB
+ inst_JMP(EJ_jmp, block->bbJumpDest);
#else
- NYI("TARGET");
+ NYI("TARGET");
#endif
- // The BBJ_ALWAYS is used because the BBJ_CALLFINALLY can't point to the
- // jump target using bbJumpDest - that is already used to point
- // to the finally block. So just skip past the BBJ_ALWAYS unless the
- // block is RETLESS.
- if ( !(block->bbFlags & BBF_RETLESS_CALL) )
- {
- assert(block->isBBCallAlwaysPair());
+ // The BBJ_ALWAYS is used because the BBJ_CALLFINALLY can't point to the
+ // jump target using bbJumpDest - that is already used to point
+ // to the finally block. So just skip past the BBJ_ALWAYS unless the
+ // block is RETLESS.
+ if (!(block->bbFlags & BBF_RETLESS_CALL))
+ {
+ assert(block->isBBCallAlwaysPair());
- lblk = block;
- block = block->bbNext;
- }
- break;
+ lblk = block;
+ block = block->bbNext;
+ }
+ break;
#ifdef _TARGET_ARM_
- case BBJ_EHCATCHRET:
- // set r0 to the address the VM should return to after the catch
- getEmitter()->emitIns_R_L (INS_movw,
- EA_4BYTE_DSP_RELOC,
- block->bbJumpDest,
- REG_R0);
- getEmitter()->emitIns_R_L (INS_movt,
- EA_4BYTE_DSP_RELOC,
- block->bbJumpDest,
- REG_R0);
- regTracker.rsTrackRegTrash(REG_R0);
+ case BBJ_EHCATCHRET:
+ // set r0 to the address the VM should return to after the catch
+ getEmitter()->emitIns_R_L(INS_movw, EA_4BYTE_DSP_RELOC, block->bbJumpDest, REG_R0);
+ getEmitter()->emitIns_R_L(INS_movt, EA_4BYTE_DSP_RELOC, block->bbJumpDest, REG_R0);
+ regTracker.rsTrackRegTrash(REG_R0);
- __fallthrough;
+ __fallthrough;
- case BBJ_EHFINALLYRET:
- case BBJ_EHFILTERRET:
- genReserveFuncletEpilog(block);
- break;
+ case BBJ_EHFINALLYRET:
+ case BBJ_EHFILTERRET:
+ genReserveFuncletEpilog(block);
+ break;
#else // _TARGET_ARM_
- case BBJ_EHFINALLYRET:
- case BBJ_EHFILTERRET:
- case BBJ_EHCATCHRET:
- break;
+ case BBJ_EHFINALLYRET:
+ case BBJ_EHFILTERRET:
+ case BBJ_EHCATCHRET:
+ break;
#endif // _TARGET_ARM_
- case BBJ_NONE:
- case BBJ_COND:
- case BBJ_SWITCH:
- break;
+ case BBJ_NONE:
+ case BBJ_COND:
+ case BBJ_SWITCH:
+ break;
- default:
- noway_assert(!"Unexpected bbJumpKind");
- break;
+ default:
+ noway_assert(!"Unexpected bbJumpKind");
+ break;
}
-#ifdef DEBUG
+#ifdef DEBUG
compiler->compCurBB = 0;
#endif
@@ -13446,12 +13174,11 @@ void CodeGen::genCodeForBBlist()
compiler->tmpEnd();
-#ifdef DEBUG
+#ifdef DEBUG
if (compiler->verbose)
{
printf("\n# ");
- printf("totalCostEx = %6d, totalCostSz = %5d ",
- totalCostEx, totalCostSz);
+ printf("totalCostEx = %6d, totalCostSz = %5d ", totalCostEx, totalCostSz);
printf("%s\n", compiler->info.compFullName);
}
#endif
@@ -13472,19 +13199,17 @@ void CodeGen::genCodeForBBlist()
#ifdef _PREFAST_
#pragma warning(push)
-#pragma warning(disable:21000) // Suppress PREFast warning about overly large function
+#pragma warning(disable : 21000) // Suppress PREFast warning about overly large function
#endif
-void CodeGen::genCodeForTreeLng(GenTreePtr tree,
- regMaskTP needReg,
- regMaskTP avoidReg)
+void CodeGen::genCodeForTreeLng(GenTreePtr tree, regMaskTP needReg, regMaskTP avoidReg)
{
- genTreeOps oper;
- unsigned kind;
+ genTreeOps oper;
+ unsigned kind;
- regPairNo regPair = DUMMY_INIT(REG_PAIR_CORRUPT);
- regMaskTP addrReg;
- regNumber regLo;
- regNumber regHi;
+ regPairNo regPair = DUMMY_INIT(REG_PAIR_CORRUPT);
+ regMaskTP addrReg;
+ regNumber regLo;
+ regNumber regHi;
noway_assert(tree);
noway_assert(tree->gtOper != GT_STMT);
@@ -13495,10 +13220,10 @@ void CodeGen::genCodeForTreeLng(GenTreePtr tree,
oper = tree->OperGet();
kind = tree->OperKind();
- if (tree->gtFlags & GTF_REG_VAL)
+ if (tree->gtFlags & GTF_REG_VAL)
{
-REG_VAR_LONG:
- regPair = tree->gtRegPair;
+ REG_VAR_LONG:
+ regPair = tree->gtRegPair;
gcInfo.gcMarkRegSetNpt(genRegPairMask(regPair));
@@ -13507,24 +13232,23 @@ REG_VAR_LONG:
/* Is this a constant node? */
- if (kind & GTK_CONST)
+ if (kind & GTK_CONST)
{
- __int64 lval;
+ __int64 lval;
/* Pick a register pair for the value */
- regPair = regSet.rsPickRegPair(needReg);
+ regPair = regSet.rsPickRegPair(needReg);
/* Load the value into the registers */
CLANG_FORMAT_COMMENT_ANCHOR;
#if !CPU_HAS_FP_SUPPORT
- if (oper == GT_CNS_DBL)
+ if (oper == GT_CNS_DBL)
{
noway_assert(sizeof(__int64) == sizeof(double));
- noway_assert(sizeof(tree->gtLngCon.gtLconVal) ==
- sizeof(tree->gtDblCon.gtDconVal));
+ noway_assert(sizeof(tree->gtLngCon.gtLconVal) == sizeof(tree->gtDblCon.gtDconVal));
lval = *(__int64*)(&tree->gtDblCon.gtDconVal);
}
@@ -13536,155 +13260,154 @@ REG_VAR_LONG:
lval = tree->gtLngCon.gtLconVal;
}
- genSetRegToIcon(genRegPairLo(regPair), int(lval ));
+ genSetRegToIcon(genRegPairLo(regPair), int(lval));
genSetRegToIcon(genRegPairHi(regPair), int(lval >> 32));
goto DONE;
}
/* Is this a leaf node? */
- if (kind & GTK_LEAF)
+ if (kind & GTK_LEAF)
{
switch (oper)
{
- case GT_LCL_VAR:
+ case GT_LCL_VAR:
#if REDUNDANT_LOAD
- /* This case has to consider the case in which an int64 LCL_VAR
- * may both be enregistered and also have a cached copy of itself
- * in a different set of registers.
- * We want to return the registers that have the most in common
- * with the needReg mask
- */
+ /* This case has to consider the case in which an int64 LCL_VAR
+ * may both be enregistered and also have a cached copy of itself
+ * in a different set of registers.
+ * We want to return the registers that have the most in common
+ * with the needReg mask
+ */
- /* Does the var have a copy of itself in the cached registers?
- * And are these cached registers both free?
- * If so use these registers if they match any needReg.
- */
+ /* Does the var have a copy of itself in the cached registers?
+ * And are these cached registers both free?
+ * If so use these registers if they match any needReg.
+ */
- regPair = regTracker.rsLclIsInRegPair(tree->gtLclVarCommon.gtLclNum);
+ regPair = regTracker.rsLclIsInRegPair(tree->gtLclVarCommon.gtLclNum);
- if ( ( regPair != REG_PAIR_NONE) &&
- ( (regSet.rsRegMaskFree() & needReg) == needReg ) &&
- ((genRegPairMask(regPair) & needReg) != RBM_NONE ))
- {
- goto DONE;
- }
+ if ((regPair != REG_PAIR_NONE) && ((regSet.rsRegMaskFree() & needReg) == needReg) &&
+ ((genRegPairMask(regPair) & needReg) != RBM_NONE))
+ {
+ goto DONE;
+ }
- /* Does the variable live in a register?
- * If so use these registers.
- */
- if (genMarkLclVar(tree))
- goto REG_VAR_LONG;
+ /* Does the variable live in a register?
+ * If so use these registers.
+ */
+ if (genMarkLclVar(tree))
+ goto REG_VAR_LONG;
- /* If tree is not an enregistered variable then
- * be sure to use any cached register that contain
- * a copy of this local variable
- */
- if (regPair != REG_PAIR_NONE)
- {
- goto DONE;
- }
+ /* If tree is not an enregistered variable then
+ * be sure to use any cached register that contain
+ * a copy of this local variable
+ */
+ if (regPair != REG_PAIR_NONE)
+ {
+ goto DONE;
+ }
#endif
- goto MEM_LEAF;
+ goto MEM_LEAF;
- case GT_LCL_FLD:
+ case GT_LCL_FLD:
- // We only use GT_LCL_FLD for lvDoNotEnregister vars, so we don't have
- // to worry about it being enregistered.
- noway_assert(compiler->lvaTable[tree->gtLclFld.gtLclNum].lvRegister == 0);
- goto MEM_LEAF;
+ // We only use GT_LCL_FLD for lvDoNotEnregister vars, so we don't have
+ // to worry about it being enregistered.
+ noway_assert(compiler->lvaTable[tree->gtLclFld.gtLclNum].lvRegister == 0);
+ goto MEM_LEAF;
- case GT_CLS_VAR:
- MEM_LEAF:
+ case GT_CLS_VAR:
+ MEM_LEAF:
- /* Pick a register pair for the value */
+ /* Pick a register pair for the value */
- regPair = regSet.rsPickRegPair(needReg);
+ regPair = regSet.rsPickRegPair(needReg);
- /* Load the value into the registers */
+ /* Load the value into the registers */
- instruction loadIns;
+ instruction loadIns;
- loadIns = ins_Load(TYP_INT); // INS_ldr
- regLo = genRegPairLo(regPair);
- regHi = genRegPairHi(regPair);
+ loadIns = ins_Load(TYP_INT); // INS_ldr
+ regLo = genRegPairLo(regPair);
+ regHi = genRegPairHi(regPair);
#if CPU_LOAD_STORE_ARCH
- {
- regNumber regAddr = regSet.rsGrabReg(RBM_ALLINT);
- inst_RV_TT(INS_lea, regAddr, tree, 0);
- regTracker.rsTrackRegTrash(regAddr);
-
- if (regLo != regAddr)
{
- // assert(regLo != regAddr); // forced by if statement
- getEmitter()->emitIns_R_R_I(loadIns, EA_4BYTE, regLo, regAddr, 0);
- getEmitter()->emitIns_R_R_I(loadIns, EA_4BYTE, regHi, regAddr, 4);
- }
- else
- {
- // assert(regHi != regAddr); // implied by regpair property and the if statement
- getEmitter()->emitIns_R_R_I(loadIns, EA_4BYTE, regHi, regAddr, 4);
- getEmitter()->emitIns_R_R_I(loadIns, EA_4BYTE, regLo, regAddr, 0);
+ regNumber regAddr = regSet.rsGrabReg(RBM_ALLINT);
+ inst_RV_TT(INS_lea, regAddr, tree, 0);
+ regTracker.rsTrackRegTrash(regAddr);
+
+ if (regLo != regAddr)
+ {
+ // assert(regLo != regAddr); // forced by if statement
+ getEmitter()->emitIns_R_R_I(loadIns, EA_4BYTE, regLo, regAddr, 0);
+ getEmitter()->emitIns_R_R_I(loadIns, EA_4BYTE, regHi, regAddr, 4);
+ }
+ else
+ {
+ // assert(regHi != regAddr); // implied by regpair property and the if statement
+ getEmitter()->emitIns_R_R_I(loadIns, EA_4BYTE, regHi, regAddr, 4);
+ getEmitter()->emitIns_R_R_I(loadIns, EA_4BYTE, regLo, regAddr, 0);
+ }
}
- }
#else
- inst_RV_TT(loadIns, regLo, tree, 0);
- inst_RV_TT(loadIns, regHi, tree, 4);
+ inst_RV_TT(loadIns, regLo, tree, 0);
+ inst_RV_TT(loadIns, regHi, tree, 4);
#endif
#ifdef _TARGET_ARM_
- if ((oper == GT_CLS_VAR) && (tree->gtFlags & GTF_IND_VOLATILE))
- {
- // Emit a memory barrier instruction after the load
- instGen_MemoryBarrier();
- }
+ if ((oper == GT_CLS_VAR) && (tree->gtFlags & GTF_IND_VOLATILE))
+ {
+ // Emit a memory barrier instruction after the load
+ instGen_MemoryBarrier();
+ }
#endif
- regTracker.rsTrackRegTrash(regLo);
- regTracker.rsTrackRegTrash(regHi);
+ regTracker.rsTrackRegTrash(regLo);
+ regTracker.rsTrackRegTrash(regHi);
- goto DONE;
+ goto DONE;
- default:
-#ifdef DEBUG
- compiler->gtDispTree(tree);
+ default:
+#ifdef DEBUG
+ compiler->gtDispTree(tree);
#endif
- noway_assert(!"unexpected leaf");
+ noway_assert(!"unexpected leaf");
}
}
/* Is it a 'simple' unary/binary operator? */
- if (kind & GTK_SMPOP)
+ if (kind & GTK_SMPOP)
{
- instruction insLo;
- instruction insHi;
- bool doLo;
- bool doHi;
- bool setCarry = false;
- int helper;
+ instruction insLo;
+ instruction insHi;
+ bool doLo;
+ bool doHi;
+ bool setCarry = false;
+ int helper;
- GenTreePtr op1 = tree->gtOp.gtOp1;
- GenTreePtr op2 = tree->gtGetOp2();
+ GenTreePtr op1 = tree->gtOp.gtOp1;
+ GenTreePtr op2 = tree->gtGetOp2();
switch (oper)
{
- case GT_ASG:
+ case GT_ASG:
{
#ifdef DEBUGGING_SUPPORT
- unsigned lclVarNum = compiler->lvaCount;
+ unsigned lclVarNum = compiler->lvaCount;
unsigned lclVarILoffs = DUMMY_INIT(0);
#endif
/* Is the target a local ? */
- if (op1->gtOper == GT_LCL_VAR)
+ if (op1->gtOper == GT_LCL_VAR)
{
- unsigned varNum = op1->gtLclVarCommon.gtLclNum;
- LclVarDsc * varDsc;
+ unsigned varNum = op1->gtLclVarCommon.gtLclNum;
+ LclVarDsc* varDsc;
noway_assert(varNum < compiler->lvaCount);
varDsc = compiler->lvaTable + varNum;
@@ -13698,16 +13421,17 @@ REG_VAR_LONG:
* Remember the local var info to call siCheckVarScope
* AFTER codegen of the assignment.
*/
- if (compiler->opts.compScopeInfo && !compiler->opts.compDbgCode && (compiler->info.compVarScopesCount > 0))
+ if (compiler->opts.compScopeInfo && !compiler->opts.compDbgCode &&
+ (compiler->info.compVarScopesCount > 0))
{
- lclVarNum = varNum;
- lclVarILoffs = op1->gtLclVar.gtLclILoffs;
+ lclVarNum = varNum;
+ lclVarILoffs = op1->gtLclVar.gtLclILoffs;
}
#endif
/* Has the variable been assigned to a register (pair) ? */
- if (genMarkLclVar(op1))
+ if (genMarkLclVar(op1))
{
noway_assert(op1->gtFlags & GTF_REG_VAL);
regPair = op1->gtRegPair;
@@ -13717,7 +13441,7 @@ REG_VAR_LONG:
/* Is the value being assigned a constant? */
- if (op2->gtOper == GT_CNS_LNG)
+ if (op2->gtOper == GT_CNS_LNG)
{
/* Move the value into the target */
@@ -13738,7 +13462,7 @@ REG_VAR_LONG:
}
ins = INS_mov;
}
- inst_TT_IV(ins, op1, (int)(op2->gtLngCon.gtLconVal ), 0);
+ inst_TT_IV(ins, op1, (int)(op2->gtLngCon.gtLconVal), 0);
// The REG_STK case has already been handled
if (regHi != REG_STK)
@@ -13752,7 +13476,7 @@ REG_VAR_LONG:
/* Compute the RHS into desired register pair */
- if (regHi != REG_STK)
+ if (regHi != REG_STK)
{
genComputeRegPair(op2, regPair, avoidReg, RegSet::KEEP_REG);
noway_assert(op2->gtFlags & GTF_REG_VAL);
@@ -13775,7 +13499,7 @@ REG_VAR_LONG:
/* move high first, target is on stack */
inst_TT_RV(ins_Store(TYP_INT), op1, curHi, 4);
- if (regLo != curLo)
+ if (regLo != curLo)
{
if ((regSet.rsMaskUsed & genRegMask(regLo)) && (regLo != curHi))
regSet.rsSpillReg(regLo);
@@ -13789,10 +13513,9 @@ REG_VAR_LONG:
}
}
-
/* Is the value being assigned a constant? */
- if (op2->gtOper == GT_CNS_LNG)
+ if (op2->gtOper == GT_CNS_LNG)
{
/* Make the target addressable */
@@ -13800,7 +13523,7 @@ REG_VAR_LONG:
/* Move the value into the target */
- inst_TT_IV(ins_Store(TYP_INT), op1, (int)(op2->gtLngCon.gtLconVal ), 0);
+ inst_TT_IV(ins_Store(TYP_INT), op1, (int)(op2->gtLngCon.gtLconVal), 0);
inst_TT_IV(ins_Store(TYP_INT), op1, (int)(op2->gtLngCon.gtLconVal >> 32), 4);
genDoneAddressable(op1, addrReg, RegSet::KEEP_REG);
@@ -13843,18 +13566,14 @@ REG_VAR_LONG:
/* Eliminate worthless assignment "lcl = lcl" */
- if (op2->gtOper == GT_LCL_VAR &&
- op1->gtOper == GT_LCL_VAR && op2->gtLclVarCommon.gtLclNum ==
- op1->gtLclVarCommon.gtLclNum)
+ if (op2->gtOper == GT_LCL_VAR && op1->gtOper == GT_LCL_VAR &&
+ op2->gtLclVarCommon.gtLclNum == op1->gtLclVarCommon.gtLclNum)
{
genUpdateLife(op2);
goto LAsgExit;
}
-
- if (op2->gtOper == GT_CAST &&
- TYP_ULONG == op2->CastToType() &&
- op2->CastFromType() <= TYP_INT &&
+ if (op2->gtOper == GT_CAST && TYP_ULONG == op2->CastToType() && op2->CastFromType() <= TYP_INT &&
// op1,op2 need to be materialized in the correct order.
(tree->gtFlags & GTF_REVERSE_OPS))
{
@@ -13878,8 +13597,9 @@ REG_VAR_LONG:
// conv.ovf.u8 could overflow if the original number was negative
if (op2->gtOverflow())
{
- noway_assert((op2->gtFlags & GTF_UNSIGNED) == 0); // conv.ovf.u8.un should be bashed to conv.u8.un
- instGen_Compare_Reg_To_Zero(EA_4BYTE, regHi); // set flags
+ noway_assert((op2->gtFlags & GTF_UNSIGNED) ==
+ 0); // conv.ovf.u8.un should be bashed to conv.u8.un
+ instGen_Compare_Reg_To_Zero(EA_4BYTE, regHi); // set flags
emitJumpKind jmpLTS = genJumpKindForOper(GT_LT, CK_SIGNED);
genJumpToThrowHlpBlk(jmpLTS, SCK_OVERFLOW);
}
@@ -13887,12 +13607,12 @@ REG_VAR_LONG:
/* Move the value into the target */
inst_TT_RV(ins_Store(TYP_INT), op1, regHi, 0);
- inst_TT_IV(ins_Store(TYP_INT), op1, 0, 4); // Store 0 in hi-word
+ inst_TT_IV(ins_Store(TYP_INT), op1, 0, 4); // Store 0 in hi-word
/* Free up anything that was tied up by either side */
genDoneAddressable(op1, addrReg, RegSet::KEEP_REG);
- genReleaseReg (smallOpr);
+ genReleaseReg(smallOpr);
#if REDUNDANT_LOAD
if (op1->gtOper == GT_LCL_VAR)
@@ -13902,15 +13622,14 @@ REG_VAR_LONG:
/* mark RHS registers as containing the local var */
regTracker.rsTrackRegLclVarLng(regHi, op1->gtLclVarCommon.gtLclNum, true);
- }
+ }
#endif
goto LAsgExit;
}
-
/* Is the LHS more complex than the RHS? */
- if (tree->gtFlags & GTF_REVERSE_OPS)
+ if (tree->gtFlags & GTF_REVERSE_OPS)
{
/* Generate the RHS into a register pair */
@@ -13918,7 +13637,7 @@ REG_VAR_LONG:
noway_assert(op2->gtFlags & GTF_REG_VAL);
/* Make the target addressable */
- op1 = genCodeForCommaTree(op1);
+ op1 = genCodeForCommaTree(op1);
addrReg = genMakeAddressable(op1, 0, RegSet::KEEP_REG);
/* Make sure the RHS register hasn't been spilled */
@@ -13929,7 +13648,7 @@ REG_VAR_LONG:
{
/* Make the target addressable */
- op1 = genCodeForCommaTree(op1);
+ op1 = genCodeForCommaTree(op1);
addrReg = genMakeAddressable(op1, RBM_ALLINT & ~op2->gtRsvdRegs, RegSet::KEEP_REG, true);
/* Generate the RHS into a register pair */
@@ -13966,7 +13685,7 @@ REG_VAR_LONG:
if ((op2->gtFlags & GTF_REG_VAL) &&
/* constant has precedence over local */
- // rsRegValues[op2->gtRegNum].rvdKind != RV_INT_CNS &&
+ // rsRegValues[op2->gtRegNum].rvdKind != RV_INT_CNS &&
tree->gtOper == GT_ASG)
{
regNumber regNo;
@@ -13974,16 +13693,15 @@ REG_VAR_LONG:
/* mark RHS registers as containing the local var */
regNo = genRegPairLo(op2->gtRegPair);
- if (regNo != REG_STK)
+ if (regNo != REG_STK)
regTracker.rsTrackRegLclVarLng(regNo, op1->gtLclVarCommon.gtLclNum, true);
regNo = genRegPairHi(op2->gtRegPair);
- if (regNo != REG_STK)
+ if (regNo != REG_STK)
{
/* For partially enregistered longs, we might have
stomped on op2's hiReg */
- if (!(op1->gtFlags & GTF_REG_VAL) ||
- regNo != genRegPairLo(op1->gtRegPair))
+ if (!(op1->gtFlags & GTF_REG_VAL) || regNo != genRegPairLo(op1->gtRegPair))
{
regTracker.rsTrackRegLclVarLng(regNo, op1->gtLclVarCommon.gtLclNum, false);
}
@@ -13992,8 +13710,7 @@ REG_VAR_LONG:
}
#endif
-
-LAsgExit:
+ LAsgExit:
genUpdateLife(op1);
genUpdateLife(tree);
@@ -14005,866 +13722,905 @@ LAsgExit:
if (lclVarNum < compiler->lvaCount)
siCheckVarScope(lclVarNum, lclVarILoffs);
#endif
- }
- return;
-
-
- case GT_SUB: insLo = INS_sub; insHi = INS_SUBC; setCarry = true; goto BINOP_OVF;
- case GT_ADD: insLo = INS_add; insHi = INS_ADDC; setCarry = true; goto BINOP_OVF;
-
- bool ovfl;
-
- BINOP_OVF:
- ovfl = tree->gtOverflow();
- goto _BINOP;
-
- case GT_AND: insLo = insHi = INS_AND; goto BINOP;
- case GT_OR : insLo = insHi = INS_OR ; goto BINOP;
- case GT_XOR: insLo = insHi = INS_XOR; goto BINOP;
-
- BINOP: ovfl = false; goto _BINOP;
-
- _BINOP:
-
- /* The following makes an assumption about gtSetEvalOrder(this) */
+ }
+ return;
- noway_assert((tree->gtFlags & GTF_REVERSE_OPS) == 0);
+ case GT_SUB:
+ insLo = INS_sub;
+ insHi = INS_SUBC;
+ setCarry = true;
+ goto BINOP_OVF;
+ case GT_ADD:
+ insLo = INS_add;
+ insHi = INS_ADDC;
+ setCarry = true;
+ goto BINOP_OVF;
+
+ bool ovfl;
+
+ BINOP_OVF:
+ ovfl = tree->gtOverflow();
+ goto _BINOP;
+
+ case GT_AND:
+ insLo = insHi = INS_AND;
+ goto BINOP;
+ case GT_OR:
+ insLo = insHi = INS_OR;
+ goto BINOP;
+ case GT_XOR:
+ insLo = insHi = INS_XOR;
+ goto BINOP;
+
+ BINOP:
+ ovfl = false;
+ goto _BINOP;
+
+ _BINOP:
+
+ /* The following makes an assumption about gtSetEvalOrder(this) */
- /* Special case: check for "(long(intval) << 32) | longval" */
+ noway_assert((tree->gtFlags & GTF_REVERSE_OPS) == 0);
- if (oper == GT_OR && op1->gtOper == GT_LSH)
- {
- GenTreePtr lshLHS = op1->gtOp.gtOp1;
- GenTreePtr lshRHS = op1->gtOp.gtOp2;
+ /* Special case: check for "(long(intval) << 32) | longval" */
- if (lshLHS->gtOper == GT_CAST &&
- lshRHS->gtOper == GT_CNS_INT &&
- lshRHS->gtIntCon.gtIconVal == 32 &&
- genTypeSize(TYP_INT) == genTypeSize(lshLHS->CastFromType()))
+ if (oper == GT_OR && op1->gtOper == GT_LSH)
{
+ GenTreePtr lshLHS = op1->gtOp.gtOp1;
+ GenTreePtr lshRHS = op1->gtOp.gtOp2;
- /* Throw away the cast of the shift operand. */
-
- op1 = lshLHS->gtCast.CastOp();
-
- /* Special case: check op2 for "ulong(intval)" */
- if ((op2->gtOper == GT_CAST) &&
- (op2->CastToType() == TYP_ULONG) &&
- genTypeSize(TYP_INT) == genTypeSize(op2->CastFromType()))
+ if (lshLHS->gtOper == GT_CAST && lshRHS->gtOper == GT_CNS_INT && lshRHS->gtIntCon.gtIconVal == 32 &&
+ genTypeSize(TYP_INT) == genTypeSize(lshLHS->CastFromType()))
{
- /* Throw away the cast of the second operand. */
- op2 = op2->gtCast.CastOp();
- goto SIMPLE_OR_LONG;
- }
- /* Special case: check op2 for "long(intval) & 0xFFFFFFFF" */
- else if (op2->gtOper == GT_AND)
- {
- GenTreePtr andLHS; andLHS = op2->gtOp.gtOp1;
- GenTreePtr andRHS; andRHS = op2->gtOp.gtOp2;
+ /* Throw away the cast of the shift operand. */
- if (andLHS->gtOper == GT_CAST &&
- andRHS->gtOper == GT_CNS_LNG &&
- andRHS->gtLngCon.gtLconVal == 0x00000000FFFFFFFF &&
- genTypeSize(TYP_INT) == genTypeSize(andLHS->CastFromType()))
+ op1 = lshLHS->gtCast.CastOp();
+
+ /* Special case: check op2 for "ulong(intval)" */
+ if ((op2->gtOper == GT_CAST) && (op2->CastToType() == TYP_ULONG) &&
+ genTypeSize(TYP_INT) == genTypeSize(op2->CastFromType()))
{
/* Throw away the cast of the second operand. */
- op2 = andLHS->gtCast.CastOp();
+ op2 = op2->gtCast.CastOp();
+ goto SIMPLE_OR_LONG;
+ }
+ /* Special case: check op2 for "long(intval) & 0xFFFFFFFF" */
+ else if (op2->gtOper == GT_AND)
+ {
+ GenTreePtr andLHS;
+ andLHS = op2->gtOp.gtOp1;
+ GenTreePtr andRHS;
+ andRHS = op2->gtOp.gtOp2;
+
+ if (andLHS->gtOper == GT_CAST && andRHS->gtOper == GT_CNS_LNG &&
+ andRHS->gtLngCon.gtLconVal == 0x00000000FFFFFFFF &&
+ genTypeSize(TYP_INT) == genTypeSize(andLHS->CastFromType()))
+ {
+ /* Throw away the cast of the second operand. */
+
+ op2 = andLHS->gtCast.CastOp();
-SIMPLE_OR_LONG:
- // Load the high DWORD, ie. op1
+ SIMPLE_OR_LONG:
+ // Load the high DWORD, ie. op1
- genCodeForTree(op1, needReg & ~op2->gtRsvdRegs);
+ genCodeForTree(op1, needReg & ~op2->gtRsvdRegs);
- noway_assert(op1->gtFlags & GTF_REG_VAL);
- regHi = op1->gtRegNum;
- regSet.rsMarkRegUsed(op1);
+ noway_assert(op1->gtFlags & GTF_REG_VAL);
+ regHi = op1->gtRegNum;
+ regSet.rsMarkRegUsed(op1);
- // Load the low DWORD, ie. op2
+ // Load the low DWORD, ie. op2
- genCodeForTree(op2, needReg & ~genRegMask(regHi));
+ genCodeForTree(op2, needReg & ~genRegMask(regHi));
- noway_assert(op2->gtFlags & GTF_REG_VAL);
- regLo = op2->gtRegNum;
+ noway_assert(op2->gtFlags & GTF_REG_VAL);
+ regLo = op2->gtRegNum;
- /* Make sure regHi is still around. Also, force
- regLo to be excluded in case regLo==regHi */
+ /* Make sure regHi is still around. Also, force
+ regLo to be excluded in case regLo==regHi */
- genRecoverReg(op1, ~genRegMask(regLo), RegSet::FREE_REG);
- regHi = op1->gtRegNum;
+ genRecoverReg(op1, ~genRegMask(regLo), RegSet::FREE_REG);
+ regHi = op1->gtRegNum;
- regPair = gen2regs2pair(regLo, regHi);
- goto DONE;
+ regPair = gen2regs2pair(regLo, regHi);
+ goto DONE;
+ }
}
- }
- /* Generate the following sequence:
- Prepare op1 (discarding shift)
- Compute op2 into some regpair
- OR regpairhi, op1
- */
+ /* Generate the following sequence:
+ Prepare op1 (discarding shift)
+ Compute op2 into some regpair
+ OR regpairhi, op1
+ */
- /* First, make op1 addressable */
+ /* First, make op1 addressable */
- /* tempReg must avoid both needReg, op2->RsvdRegs and regSet.rsMaskResvd.
+ /* tempReg must avoid both needReg, op2->RsvdRegs and regSet.rsMaskResvd.
- It appears incorrect to exclude needReg as we are not ensuring that the reg pair into
- which the long value is computed is from needReg. But at this point the safest fix is
- to exclude regSet.rsMaskResvd.
+ It appears incorrect to exclude needReg as we are not ensuring that the reg pair into
+ which the long value is computed is from needReg. But at this point the safest fix is
+ to exclude regSet.rsMaskResvd.
- Note that needReg could be the set of free registers (excluding reserved ones). If we don't
- exclude regSet.rsMaskResvd, the expression below will have the effect of trying to choose a reg from
- reserved set which is bound to fail. To prevent that we avoid regSet.rsMaskResvd.
- */
- regMaskTP tempReg = RBM_ALLINT & ~needReg & ~op2->gtRsvdRegs & ~avoidReg & ~regSet.rsMaskResvd;
+ Note that needReg could be the set of free registers (excluding reserved ones). If we don't
+ exclude regSet.rsMaskResvd, the expression below will have the effect of trying to choose a
+ reg from
+ reserved set which is bound to fail. To prevent that we avoid regSet.rsMaskResvd.
+ */
+ regMaskTP tempReg = RBM_ALLINT & ~needReg & ~op2->gtRsvdRegs & ~avoidReg & ~regSet.rsMaskResvd;
- addrReg = genMakeAddressable(op1, tempReg, RegSet::KEEP_REG);
+ addrReg = genMakeAddressable(op1, tempReg, RegSet::KEEP_REG);
- genCompIntoFreeRegPair(op2, avoidReg, RegSet::KEEP_REG);
+ genCompIntoFreeRegPair(op2, avoidReg, RegSet::KEEP_REG);
- noway_assert(op2->gtFlags & GTF_REG_VAL);
- regPair = op2->gtRegPair;
- regHi = genRegPairHi(regPair);
+ noway_assert(op2->gtFlags & GTF_REG_VAL);
+ regPair = op2->gtRegPair;
+ regHi = genRegPairHi(regPair);
- /* The operand might have interfered with the address */
+ /* The operand might have interfered with the address */
- addrReg = genKeepAddressable(op1, addrReg, genRegPairMask(regPair));
+ addrReg = genKeepAddressable(op1, addrReg, genRegPairMask(regPair));
- /* Now compute the result */
+ /* Now compute the result */
- inst_RV_TT(insHi, regHi, op1, 0);
+ inst_RV_TT(insHi, regHi, op1, 0);
- regTracker.rsTrackRegTrash(regHi);
+ regTracker.rsTrackRegTrash(regHi);
- /* Free up anything that was tied up by the LHS */
+ /* Free up anything that was tied up by the LHS */
- genDoneAddressable(op1, addrReg, RegSet::KEEP_REG);
+ genDoneAddressable(op1, addrReg, RegSet::KEEP_REG);
- /* The result is where the second operand is sitting */
+ /* The result is where the second operand is sitting */
- genRecoverRegPair(op2, REG_PAIR_NONE, RegSet::FREE_REG);
+ genRecoverRegPair(op2, REG_PAIR_NONE, RegSet::FREE_REG);
- regPair = op2->gtRegPair;
- goto DONE;
+ regPair = op2->gtRegPair;
+ goto DONE;
+ }
}
- }
-
- /* Special case: check for "longval | (long(intval) << 32)" */
- if (oper == GT_OR && op2->gtOper == GT_LSH)
- {
- GenTreePtr lshLHS = op2->gtOp.gtOp1;
- GenTreePtr lshRHS = op2->gtOp.gtOp2;
-
- if (lshLHS->gtOper == GT_CAST &&
- lshRHS->gtOper == GT_CNS_INT &&
- lshRHS->gtIntCon.gtIconVal == 32 &&
- genTypeSize(TYP_INT) == genTypeSize(lshLHS->CastFromType()))
+ /* Special case: check for "longval | (long(intval) << 32)" */
+ if (oper == GT_OR && op2->gtOper == GT_LSH)
{
- /* We throw away the cast of the shift operand. */
-
- op2 = lshLHS->gtCast.CastOp();
+ GenTreePtr lshLHS = op2->gtOp.gtOp1;
+ GenTreePtr lshRHS = op2->gtOp.gtOp2;
- /* Special case: check op1 for "long(intval) & 0xFFFFFFFF" */
+ if (lshLHS->gtOper == GT_CAST && lshRHS->gtOper == GT_CNS_INT && lshRHS->gtIntCon.gtIconVal == 32 &&
+ genTypeSize(TYP_INT) == genTypeSize(lshLHS->CastFromType()))
- if (op1->gtOper == GT_AND)
{
- GenTreePtr andLHS = op1->gtOp.gtOp1;
- GenTreePtr andRHS = op1->gtOp.gtOp2;
+ /* We throw away the cast of the shift operand. */
- if (andLHS->gtOper == GT_CAST &&
- andRHS->gtOper == GT_CNS_LNG &&
- andRHS->gtLngCon.gtLconVal == 0x00000000FFFFFFFF &&
- genTypeSize(TYP_INT) == genTypeSize(andLHS->CastFromType()))
+ op2 = lshLHS->gtCast.CastOp();
+
+ /* Special case: check op1 for "long(intval) & 0xFFFFFFFF" */
+
+ if (op1->gtOper == GT_AND)
{
- /* Throw away the cast of the first operand. */
+ GenTreePtr andLHS = op1->gtOp.gtOp1;
+ GenTreePtr andRHS = op1->gtOp.gtOp2;
- op1 = andLHS->gtCast.CastOp();
+ if (andLHS->gtOper == GT_CAST && andRHS->gtOper == GT_CNS_LNG &&
+ andRHS->gtLngCon.gtLconVal == 0x00000000FFFFFFFF &&
+ genTypeSize(TYP_INT) == genTypeSize(andLHS->CastFromType()))
+ {
+ /* Throw away the cast of the first operand. */
- // Load the low DWORD, ie. op1
+ op1 = andLHS->gtCast.CastOp();
- genCodeForTree(op1, needReg & ~op2->gtRsvdRegs);
+ // Load the low DWORD, ie. op1
- noway_assert(op1->gtFlags & GTF_REG_VAL);
- regLo = op1->gtRegNum;
- regSet.rsMarkRegUsed(op1);
+ genCodeForTree(op1, needReg & ~op2->gtRsvdRegs);
- // Load the high DWORD, ie. op2
+ noway_assert(op1->gtFlags & GTF_REG_VAL);
+ regLo = op1->gtRegNum;
+ regSet.rsMarkRegUsed(op1);
- genCodeForTree(op2, needReg & ~genRegMask(regLo));
+ // Load the high DWORD, ie. op2
- noway_assert(op2->gtFlags & GTF_REG_VAL);
- regHi = op2->gtRegNum;
+ genCodeForTree(op2, needReg & ~genRegMask(regLo));
- /* Make sure regLo is still around. Also, force
- regHi to be excluded in case regLo==regHi */
+ noway_assert(op2->gtFlags & GTF_REG_VAL);
+ regHi = op2->gtRegNum;
- genRecoverReg(op1, ~genRegMask(regHi), RegSet::FREE_REG);
- regLo = op1->gtRegNum;
+ /* Make sure regLo is still around. Also, force
+ regHi to be excluded in case regLo==regHi */
- regPair = gen2regs2pair(regLo, regHi);
- goto DONE;
+ genRecoverReg(op1, ~genRegMask(regHi), RegSet::FREE_REG);
+ regLo = op1->gtRegNum;
+
+ regPair = gen2regs2pair(regLo, regHi);
+ goto DONE;
+ }
}
- }
- /* Generate the following sequence:
- Compute op1 into some regpair
- Make op2 (ignoring shift) addressable
- OR regPairHi, op2
- */
+ /* Generate the following sequence:
+ Compute op1 into some regpair
+ Make op2 (ignoring shift) addressable
+ OR regPairHi, op2
+ */
- // First, generate the first operand into some register
+ // First, generate the first operand into some register
- genCompIntoFreeRegPair(op1, avoidReg | op2->gtRsvdRegs, RegSet::KEEP_REG);
- noway_assert(op1->gtFlags & GTF_REG_VAL);
+ genCompIntoFreeRegPair(op1, avoidReg | op2->gtRsvdRegs, RegSet::KEEP_REG);
+ noway_assert(op1->gtFlags & GTF_REG_VAL);
- /* Make the second operand addressable */
+ /* Make the second operand addressable */
- addrReg = genMakeAddressable(op2, needReg, RegSet::KEEP_REG);
+ addrReg = genMakeAddressable(op2, needReg, RegSet::KEEP_REG);
- /* Make sure the result is in a free register pair */
+ /* Make sure the result is in a free register pair */
- genRecoverRegPair(op1, REG_PAIR_NONE, RegSet::KEEP_REG);
- regPair = op1->gtRegPair;
- regHi = genRegPairHi(regPair);
+ genRecoverRegPair(op1, REG_PAIR_NONE, RegSet::KEEP_REG);
+ regPair = op1->gtRegPair;
+ regHi = genRegPairHi(regPair);
- /* The operand might have interfered with the address */
+ /* The operand might have interfered with the address */
- addrReg = genKeepAddressable(op2, addrReg, genRegPairMask(regPair));
+ addrReg = genKeepAddressable(op2, addrReg, genRegPairMask(regPair));
- /* Compute the new value */
+ /* Compute the new value */
- inst_RV_TT(insHi, regHi, op2, 0);
+ inst_RV_TT(insHi, regHi, op2, 0);
- /* The value in the high register has been trashed */
+ /* The value in the high register has been trashed */
- regTracker.rsTrackRegTrash(regHi);
+ regTracker.rsTrackRegTrash(regHi);
- goto DONE_OR;
+ goto DONE_OR;
+ }
}
- }
- /* Generate the first operand into registers */
-
- if ( (genCountBits(needReg) == 2) &&
- ((regSet.rsRegMaskFree() & needReg) == needReg ) &&
- ((op2->gtRsvdRegs & needReg) == RBM_NONE) &&
- (!(tree->gtFlags & GTF_ASG)) )
- {
- regPair = regSet.rsPickRegPair(needReg);
- genComputeRegPair(op1, regPair, avoidReg | op2->gtRsvdRegs, RegSet::KEEP_REG);
- }
- else
- {
- genCompIntoFreeRegPair(op1, avoidReg | op2->gtRsvdRegs, RegSet::KEEP_REG);
- }
- noway_assert(op1->gtFlags & GTF_REG_VAL);
- regMaskTP op1Mask;
- regPair = op1->gtRegPair;
- op1Mask = genRegPairMask(regPair);
+ /* Generate the first operand into registers */
- /* Make the second operand addressable */
- regMaskTP needReg2;
- needReg2 = regSet.rsNarrowHint(needReg, ~op1Mask);
- addrReg = genMakeAddressable(op2, needReg2, RegSet::KEEP_REG);
+ if ((genCountBits(needReg) == 2) && ((regSet.rsRegMaskFree() & needReg) == needReg) &&
+ ((op2->gtRsvdRegs & needReg) == RBM_NONE) && (!(tree->gtFlags & GTF_ASG)))
+ {
+ regPair = regSet.rsPickRegPair(needReg);
+ genComputeRegPair(op1, regPair, avoidReg | op2->gtRsvdRegs, RegSet::KEEP_REG);
+ }
+ else
+ {
+ genCompIntoFreeRegPair(op1, avoidReg | op2->gtRsvdRegs, RegSet::KEEP_REG);
+ }
+ noway_assert(op1->gtFlags & GTF_REG_VAL);
+ regMaskTP op1Mask;
+ regPair = op1->gtRegPair;
+ op1Mask = genRegPairMask(regPair);
- // TODO: If 'op1' got spilled and 'op2' happens to be
- // TODO: in a register, and we have add/mul/and/or/xor,
- // TODO: reverse the operands since we can perform the
- // TODO: operation directly with the spill temp, e.g.
- // TODO: 'add regHi, [temp]'.
+ /* Make the second operand addressable */
+ regMaskTP needReg2;
+ needReg2 = regSet.rsNarrowHint(needReg, ~op1Mask);
+ addrReg = genMakeAddressable(op2, needReg2, RegSet::KEEP_REG);
- /* Make sure the result is in a free register pair */
+ // TODO: If 'op1' got spilled and 'op2' happens to be
+ // TODO: in a register, and we have add/mul/and/or/xor,
+ // TODO: reverse the operands since we can perform the
+ // TODO: operation directly with the spill temp, e.g.
+ // TODO: 'add regHi, [temp]'.
- genRecoverRegPair(op1, REG_PAIR_NONE, RegSet::KEEP_REG);
- regPair = op1->gtRegPair;
- op1Mask = genRegPairMask(regPair);
+ /* Make sure the result is in a free register pair */
- regLo = genRegPairLo(regPair);
- regHi = genRegPairHi(regPair);
-
- /* Make sure that we don't spill regLo/regHi below */
- regSet.rsLockUsedReg(op1Mask);
+ genRecoverRegPair(op1, REG_PAIR_NONE, RegSet::KEEP_REG);
+ regPair = op1->gtRegPair;
+ op1Mask = genRegPairMask(regPair);
- /* The operand might have interfered with the address */
+ regLo = genRegPairLo(regPair);
+ regHi = genRegPairHi(regPair);
- addrReg = genKeepAddressable(op2, addrReg);
+ /* Make sure that we don't spill regLo/regHi below */
+ regSet.rsLockUsedReg(op1Mask);
- /* The value in the register pair is about to be trashed */
+ /* The operand might have interfered with the address */
- regTracker.rsTrackRegTrash(regLo);
- regTracker.rsTrackRegTrash(regHi);
+ addrReg = genKeepAddressable(op2, addrReg);
- /* Compute the new value */
+ /* The value in the register pair is about to be trashed */
- doLo = true;
- doHi = true;
+ regTracker.rsTrackRegTrash(regLo);
+ regTracker.rsTrackRegTrash(regHi);
- if (op2->gtOper == GT_CNS_LNG)
- {
- __int64 icon = op2->gtLngCon.gtLconVal;
+ /* Compute the new value */
- /* Check for "(op1 AND -1)" and "(op1 [X]OR 0)" */
+ doLo = true;
+ doHi = true;
- switch (oper)
+ if (op2->gtOper == GT_CNS_LNG)
{
- case GT_AND:
- if ((int)(icon ) == -1)
- doLo = false;
- if ((int)(icon >> 32) == -1)
- doHi = false;
+ __int64 icon = op2->gtLngCon.gtLconVal;
- if (!(icon & I64(0x00000000FFFFFFFF)))
- {
- genSetRegToIcon(regLo, 0);
- doLo = false;
- }
+ /* Check for "(op1 AND -1)" and "(op1 [X]OR 0)" */
- if (!(icon & I64(0xFFFFFFFF00000000)))
+ switch (oper)
{
- /* Just to always set low first*/
+ case GT_AND:
+ if ((int)(icon) == -1)
+ doLo = false;
+ if ((int)(icon >> 32) == -1)
+ doHi = false;
- if (doLo)
- {
- inst_RV_TT(insLo, regLo, op2, 0);
- doLo = false;
- }
- genSetRegToIcon(regHi, 0);
- doHi = false;
- }
+ if (!(icon & I64(0x00000000FFFFFFFF)))
+ {
+ genSetRegToIcon(regLo, 0);
+ doLo = false;
+ }
- break;
+ if (!(icon & I64(0xFFFFFFFF00000000)))
+ {
+ /* Just to always set low first*/
- case GT_OR:
- case GT_XOR:
- if (!(icon & I64(0x00000000FFFFFFFF)))
- doLo = false;
- if (!(icon & I64(0xFFFFFFFF00000000)))
- doHi = false;
- break;
- default:
- break;
+ if (doLo)
+ {
+ inst_RV_TT(insLo, regLo, op2, 0);
+ doLo = false;
+ }
+ genSetRegToIcon(regHi, 0);
+ doHi = false;
+ }
+
+ break;
+
+ case GT_OR:
+ case GT_XOR:
+ if (!(icon & I64(0x00000000FFFFFFFF)))
+ doLo = false;
+ if (!(icon & I64(0xFFFFFFFF00000000)))
+ doHi = false;
+ break;
+ default:
+ break;
+ }
}
- }
- // Fix 383813 X86/ARM ILGEN
- // Fix 383793 ARM ILGEN
- // Fix 383911 ARM ILGEN
- regMaskTP newMask; newMask = addrReg & ~op1Mask;
- regSet.rsLockUsedReg(newMask);
+ // Fix 383813 X86/ARM ILGEN
+ // Fix 383793 ARM ILGEN
+ // Fix 383911 ARM ILGEN
+ regMaskTP newMask;
+ newMask = addrReg & ~op1Mask;
+ regSet.rsLockUsedReg(newMask);
- if (doLo)
- {
- insFlags flagsLo = setCarry ? INS_FLAGS_SET : INS_FLAGS_DONT_CARE;
- inst_RV_TT(insLo, regLo, op2, 0, EA_4BYTE, flagsLo);
- }
- if (doHi)
- {
- insFlags flagsHi = ovfl ? INS_FLAGS_SET : INS_FLAGS_DONT_CARE;
- inst_RV_TT(insHi, regHi, op2, 4, EA_4BYTE, flagsHi);
- }
+ if (doLo)
+ {
+ insFlags flagsLo = setCarry ? INS_FLAGS_SET : INS_FLAGS_DONT_CARE;
+ inst_RV_TT(insLo, regLo, op2, 0, EA_4BYTE, flagsLo);
+ }
+ if (doHi)
+ {
+ insFlags flagsHi = ovfl ? INS_FLAGS_SET : INS_FLAGS_DONT_CARE;
+ inst_RV_TT(insHi, regHi, op2, 4, EA_4BYTE, flagsHi);
+ }
- regSet.rsUnlockUsedReg(newMask);
- regSet.rsUnlockUsedReg(op1Mask);
+ regSet.rsUnlockUsedReg(newMask);
+ regSet.rsUnlockUsedReg(op1Mask);
- DONE_OR:
+ DONE_OR:
- /* Free up anything that was tied up by the LHS */
+ /* Free up anything that was tied up by the LHS */
- genDoneAddressable(op2, addrReg, RegSet::KEEP_REG);
+ genDoneAddressable(op2, addrReg, RegSet::KEEP_REG);
- /* The result is where the first operand is sitting */
+ /* The result is where the first operand is sitting */
- genRecoverRegPair(op1, REG_PAIR_NONE, RegSet::FREE_REG);
+ genRecoverRegPair(op1, REG_PAIR_NONE, RegSet::FREE_REG);
- regPair = op1->gtRegPair;
+ regPair = op1->gtRegPair;
- if (ovfl)
- genCheckOverflow(tree);
+ if (ovfl)
+ genCheckOverflow(tree);
- goto DONE;
+ goto DONE;
- case GT_UMOD:
+ case GT_UMOD:
- regPair = genCodeForLongModInt(tree, needReg);
- goto DONE;
+ regPair = genCodeForLongModInt(tree, needReg);
+ goto DONE;
- case GT_MUL:
+ case GT_MUL:
- /* Special case: both operands promoted from int */
+ /* Special case: both operands promoted from int */
- assert(tree->gtIsValid64RsltMul());
+ assert(tree->gtIsValid64RsltMul());
- /* Change to an integer multiply temporarily */
+ /* Change to an integer multiply temporarily */
- tree->gtType = TYP_INT;
+ tree->gtType = TYP_INT;
- noway_assert(op1->gtOper == GT_CAST && op2->gtOper == GT_CAST);
- tree->gtOp.gtOp1 = op1->gtCast.CastOp();
- tree->gtOp.gtOp2 = op2->gtCast.CastOp();
+ noway_assert(op1->gtOper == GT_CAST && op2->gtOper == GT_CAST);
+ tree->gtOp.gtOp1 = op1->gtCast.CastOp();
+ tree->gtOp.gtOp2 = op2->gtCast.CastOp();
- assert(tree->gtFlags & GTF_MUL_64RSLT);
+ assert(tree->gtFlags & GTF_MUL_64RSLT);
#if defined(_TARGET_X86_)
- // imul on x86 requires EDX:EAX
- genComputeReg(tree, (RBM_EAX|RBM_EDX), RegSet::EXACT_REG, RegSet::FREE_REG);
- noway_assert(tree->gtFlags & GTF_REG_VAL);
- noway_assert(tree->gtRegNum == REG_EAX); // Also REG_EDX is setup with hi 32-bits
+ // imul on x86 requires EDX:EAX
+ genComputeReg(tree, (RBM_EAX | RBM_EDX), RegSet::EXACT_REG, RegSet::FREE_REG);
+ noway_assert(tree->gtFlags & GTF_REG_VAL);
+ noway_assert(tree->gtRegNum == REG_EAX); // Also REG_EDX is setup with hi 32-bits
#elif defined(_TARGET_ARM_)
- genComputeReg(tree, needReg, RegSet::ANY_REG, RegSet::FREE_REG);
- noway_assert(tree->gtFlags & GTF_REG_VAL);
+ genComputeReg(tree, needReg, RegSet::ANY_REG, RegSet::FREE_REG);
+ noway_assert(tree->gtFlags & GTF_REG_VAL);
#else
- assert(!"Unsupported target for 64-bit multiply codegen");
+ assert(!"Unsupported target for 64-bit multiply codegen");
#endif
- /* Restore gtType, op1 and op2 from the change above */
+ /* Restore gtType, op1 and op2 from the change above */
- tree->gtType = TYP_LONG;
- tree->gtOp.gtOp1 = op1;
- tree->gtOp.gtOp2 = op2;
+ tree->gtType = TYP_LONG;
+ tree->gtOp.gtOp1 = op1;
+ tree->gtOp.gtOp2 = op2;
#if defined(_TARGET_X86_)
- /* The result is now in EDX:EAX */
- regPair = REG_PAIR_EAXEDX;
+ /* The result is now in EDX:EAX */
+ regPair = REG_PAIR_EAXEDX;
#elif defined(_TARGET_ARM_)
- regPair = tree->gtRegPair;
+ regPair = tree->gtRegPair;
#endif
- goto DONE;
+ goto DONE;
- case GT_LSH: helper = CORINFO_HELP_LLSH; goto SHIFT;
- case GT_RSH: helper = CORINFO_HELP_LRSH; goto SHIFT;
- case GT_RSZ: helper = CORINFO_HELP_LRSZ; goto SHIFT;
+ case GT_LSH:
+ helper = CORINFO_HELP_LLSH;
+ goto SHIFT;
+ case GT_RSH:
+ helper = CORINFO_HELP_LRSH;
+ goto SHIFT;
+ case GT_RSZ:
+ helper = CORINFO_HELP_LRSZ;
+ goto SHIFT;
- SHIFT:
+ SHIFT:
- noway_assert(op1->gtType == TYP_LONG);
- noway_assert(genActualType(op2->gtType) == TYP_INT);
+ noway_assert(op1->gtType == TYP_LONG);
+ noway_assert(genActualType(op2->gtType) == TYP_INT);
- /* Is the second operand a constant? */
+ /* Is the second operand a constant? */
- if (op2->gtOper == GT_CNS_INT)
- {
- unsigned int count = op2->gtIntCon.gtIconVal;
+ if (op2->gtOper == GT_CNS_INT)
+ {
+ unsigned int count = op2->gtIntCon.gtIconVal;
- /* Compute the left operand into a free register pair */
+ /* Compute the left operand into a free register pair */
- genCompIntoFreeRegPair(op1, avoidReg | op2->gtRsvdRegs, RegSet::FREE_REG);
- noway_assert(op1->gtFlags & GTF_REG_VAL);
+ genCompIntoFreeRegPair(op1, avoidReg | op2->gtRsvdRegs, RegSet::FREE_REG);
+ noway_assert(op1->gtFlags & GTF_REG_VAL);
- regPair = op1->gtRegPair;
- regLo = genRegPairLo(regPair);
- regHi = genRegPairHi(regPair);
+ regPair = op1->gtRegPair;
+ regLo = genRegPairLo(regPair);
+ regHi = genRegPairHi(regPair);
- /* Assume the value in the register pair is trashed. In some cases, though,
- a register might be set to zero, and we can use that information to improve
- some code generation.
- */
+ /* Assume the value in the register pair is trashed. In some cases, though,
+ a register might be set to zero, and we can use that information to improve
+ some code generation.
+ */
- regTracker.rsTrackRegTrash(regLo);
- regTracker.rsTrackRegTrash(regHi);
+ regTracker.rsTrackRegTrash(regLo);
+ regTracker.rsTrackRegTrash(regHi);
- /* Generate the appropriate shift instructions */
+ /* Generate the appropriate shift instructions */
- switch (oper)
- {
- case GT_LSH:
- if (count == 0)
- {
- // regHi, regLo are correct
- }
- else if (count < 32)
+ switch (oper)
{
+ case GT_LSH:
+ if (count == 0)
+ {
+ // regHi, regLo are correct
+ }
+ else if (count < 32)
+ {
#if defined(_TARGET_XARCH_)
- inst_RV_RV_IV(INS_shld, EA_4BYTE, regHi, regLo, count);
+ inst_RV_RV_IV(INS_shld, EA_4BYTE, regHi, regLo, count);
#elif defined(_TARGET_ARM_)
- inst_RV_SH(INS_SHIFT_LEFT_LOGICAL, EA_4BYTE, regHi, count);
- getEmitter()->emitIns_R_R_R_I(INS_OR, EA_4BYTE, regHi, regHi, regLo, 32 - count, INS_FLAGS_DONT_CARE, INS_OPTS_LSR);
-#else // _TARGET_*
- NYI("INS_shld");
+ inst_RV_SH(INS_SHIFT_LEFT_LOGICAL, EA_4BYTE, regHi, count);
+ getEmitter()->emitIns_R_R_R_I(INS_OR, EA_4BYTE, regHi, regHi, regLo, 32 - count,
+ INS_FLAGS_DONT_CARE, INS_OPTS_LSR);
+#else // _TARGET_*
+ NYI("INS_shld");
#endif // _TARGET_*
- inst_RV_SH(INS_SHIFT_LEFT_LOGICAL, EA_4BYTE, regLo, count);
- }
- else // count >= 32
- {
- assert(count >= 32);
- if (count < 64)
- {
-#if defined(_TARGET_ARM_)
- if (count == 32)
- {
- // mov low dword into high dword (i.e. shift left by 32-bits)
- inst_RV_RV(INS_mov, regHi, regLo);
+ inst_RV_SH(INS_SHIFT_LEFT_LOGICAL, EA_4BYTE, regLo, count);
}
- else
+ else // count >= 32
{
- assert(count > 32 && count < 64);
- getEmitter()->emitIns_R_R_I(INS_SHIFT_LEFT_LOGICAL, EA_4BYTE, regHi, regLo, count - 32);
+ assert(count >= 32);
+ if (count < 64)
+ {
+#if defined(_TARGET_ARM_)
+ if (count == 32)
+ {
+ // mov low dword into high dword (i.e. shift left by 32-bits)
+ inst_RV_RV(INS_mov, regHi, regLo);
+ }
+ else
+ {
+ assert(count > 32 && count < 64);
+ getEmitter()->emitIns_R_R_I(INS_SHIFT_LEFT_LOGICAL, EA_4BYTE, regHi, regLo,
+ count - 32);
+ }
+#else // _TARGET_*
+ // mov low dword into high dword (i.e. shift left by 32-bits)
+ inst_RV_RV(INS_mov, regHi, regLo);
+ if (count > 32)
+ {
+ // Shift high dword left by count - 32
+ inst_RV_SH(INS_SHIFT_LEFT_LOGICAL, EA_4BYTE, regHi, count - 32);
+ }
+#endif // _TARGET_*
+ }
+ else // count >= 64
+ {
+ assert(count >= 64);
+ genSetRegToIcon(regHi, 0);
+ }
+ genSetRegToIcon(regLo, 0);
}
-#else // _TARGET_*
- // mov low dword into high dword (i.e. shift left by 32-bits)
- inst_RV_RV(INS_mov, regHi, regLo);
- if (count > 32)
+ break;
+
+ case GT_RSH:
+ if (count == 0)
{
- // Shift high dword left by count - 32
- inst_RV_SH(INS_SHIFT_LEFT_LOGICAL, EA_4BYTE, regHi, count - 32);
+ // regHi, regLo are correct
}
-#endif // _TARGET_*
- }
- else // count >= 64
- {
- assert(count >= 64);
- genSetRegToIcon(regHi, 0);
- }
- genSetRegToIcon(regLo, 0);
- }
- break;
-
- case GT_RSH:
- if (count == 0)
- {
- // regHi, regLo are correct
- }
- else if (count < 32)
- {
+ else if (count < 32)
+ {
#if defined(_TARGET_XARCH_)
- inst_RV_RV_IV(INS_shrd, EA_4BYTE, regLo, regHi, count);
+ inst_RV_RV_IV(INS_shrd, EA_4BYTE, regLo, regHi, count);
#elif defined(_TARGET_ARM_)
- inst_RV_SH(INS_SHIFT_RIGHT_LOGICAL, EA_4BYTE, regLo, count);
- getEmitter()->emitIns_R_R_R_I(INS_OR, EA_4BYTE, regLo, regLo, regHi, 32 - count, INS_FLAGS_DONT_CARE, INS_OPTS_LSL);
-#else // _TARGET_*
- NYI("INS_shrd");
+ inst_RV_SH(INS_SHIFT_RIGHT_LOGICAL, EA_4BYTE, regLo, count);
+ getEmitter()->emitIns_R_R_R_I(INS_OR, EA_4BYTE, regLo, regLo, regHi, 32 - count,
+ INS_FLAGS_DONT_CARE, INS_OPTS_LSL);
+#else // _TARGET_*
+ NYI("INS_shrd");
#endif // _TARGET_*
- inst_RV_SH(INS_SHIFT_RIGHT_ARITHM, EA_4BYTE, regHi, count);
- }
- else // count >= 32
- {
- assert(count >= 32);
- if (count < 64)
- {
-#if defined(_TARGET_ARM_)
- if (count == 32)
- {
- // mov high dword into low dword (i.e. shift right by 32-bits)
- inst_RV_RV(INS_mov, regLo, regHi);
+ inst_RV_SH(INS_SHIFT_RIGHT_ARITHM, EA_4BYTE, regHi, count);
}
- else
+ else // count >= 32
{
- assert(count > 32 && count < 64);
- getEmitter()->emitIns_R_R_I(INS_SHIFT_RIGHT_ARITHM, EA_4BYTE, regLo, regHi, count - 32);
- }
-#else // _TARGET_*
- // mov high dword into low dword (i.e. shift right by 32-bits)
- inst_RV_RV(INS_mov, regLo, regHi);
- if (count > 32)
- {
- // Shift low dword right by count - 32
- inst_RV_SH(INS_SHIFT_RIGHT_ARITHM, EA_4BYTE, regLo, count - 32);
- }
+ assert(count >= 32);
+ if (count < 64)
+ {
+#if defined(_TARGET_ARM_)
+ if (count == 32)
+ {
+ // mov high dword into low dword (i.e. shift right by 32-bits)
+ inst_RV_RV(INS_mov, regLo, regHi);
+ }
+ else
+ {
+ assert(count > 32 && count < 64);
+ getEmitter()->emitIns_R_R_I(INS_SHIFT_RIGHT_ARITHM, EA_4BYTE, regLo, regHi,
+ count - 32);
+ }
+#else // _TARGET_*
+ // mov high dword into low dword (i.e. shift right by 32-bits)
+ inst_RV_RV(INS_mov, regLo, regHi);
+ if (count > 32)
+ {
+ // Shift low dword right by count - 32
+ inst_RV_SH(INS_SHIFT_RIGHT_ARITHM, EA_4BYTE, regLo, count - 32);
+ }
#endif // _TARGET_*
- }
+ }
- // Propagate sign bit in high dword
- inst_RV_SH(INS_SHIFT_RIGHT_ARITHM, EA_4BYTE, regHi, 31);
+ // Propagate sign bit in high dword
+ inst_RV_SH(INS_SHIFT_RIGHT_ARITHM, EA_4BYTE, regHi, 31);
- if (count >= 64)
- {
- // Propagate the sign from the high dword
- inst_RV_RV(INS_mov, regLo, regHi, TYP_INT);
- }
- }
- break;
+ if (count >= 64)
+ {
+ // Propagate the sign from the high dword
+ inst_RV_RV(INS_mov, regLo, regHi, TYP_INT);
+ }
+ }
+ break;
- case GT_RSZ:
- if (count == 0)
- {
- // regHi, regLo are correct
- }
- else if (count < 32)
- {
-#if defined(_TARGET_XARCH_)
- inst_RV_RV_IV(INS_shrd, EA_4BYTE, regLo, regHi, count);
-#elif defined(_TARGET_ARM_)
- inst_RV_SH(INS_SHIFT_RIGHT_LOGICAL, EA_4BYTE, regLo, count);
- getEmitter()->emitIns_R_R_R_I(INS_OR, EA_4BYTE, regLo, regLo, regHi, 32 - count, INS_FLAGS_DONT_CARE, INS_OPTS_LSL);
-#else // _TARGET_*
- NYI("INS_shrd");
-#endif // _TARGET_*
- inst_RV_SH(INS_SHIFT_RIGHT_LOGICAL, EA_4BYTE, regHi, count);
- }
- else // count >= 32
- {
- assert(count >= 32);
- if (count < 64)
- {
-#if defined(_TARGET_ARM_)
- if (count == 32)
+ case GT_RSZ:
+ if (count == 0)
{
- // mov high dword into low dword (i.e. shift right by 32-bits)
- inst_RV_RV(INS_mov, regLo, regHi);
+ // regHi, regLo are correct
}
- else
+ else if (count < 32)
{
- assert(count > 32 && count < 64);
- getEmitter()->emitIns_R_R_I(INS_SHIFT_RIGHT_LOGICAL, EA_4BYTE, regLo, regHi, count - 32);
+#if defined(_TARGET_XARCH_)
+ inst_RV_RV_IV(INS_shrd, EA_4BYTE, regLo, regHi, count);
+#elif defined(_TARGET_ARM_)
+ inst_RV_SH(INS_SHIFT_RIGHT_LOGICAL, EA_4BYTE, regLo, count);
+ getEmitter()->emitIns_R_R_R_I(INS_OR, EA_4BYTE, regLo, regLo, regHi, 32 - count,
+ INS_FLAGS_DONT_CARE, INS_OPTS_LSL);
+#else // _TARGET_*
+ NYI("INS_shrd");
+#endif // _TARGET_*
+ inst_RV_SH(INS_SHIFT_RIGHT_LOGICAL, EA_4BYTE, regHi, count);
}
-#else // _TARGET_*
- // mov high dword into low dword (i.e. shift right by 32-bits)
- inst_RV_RV(INS_mov, regLo, regHi);
- if (count > 32)
+ else // count >= 32
{
- // Shift low dword right by count - 32
- inst_RV_SH(INS_SHIFT_RIGHT_LOGICAL, EA_4BYTE, regLo, count - 32);
- }
+ assert(count >= 32);
+ if (count < 64)
+ {
+#if defined(_TARGET_ARM_)
+ if (count == 32)
+ {
+ // mov high dword into low dword (i.e. shift right by 32-bits)
+ inst_RV_RV(INS_mov, regLo, regHi);
+ }
+ else
+ {
+ assert(count > 32 && count < 64);
+ getEmitter()->emitIns_R_R_I(INS_SHIFT_RIGHT_LOGICAL, EA_4BYTE, regLo, regHi,
+ count - 32);
+ }
+#else // _TARGET_*
+ // mov high dword into low dword (i.e. shift right by 32-bits)
+ inst_RV_RV(INS_mov, regLo, regHi);
+ if (count > 32)
+ {
+ // Shift low dword right by count - 32
+ inst_RV_SH(INS_SHIFT_RIGHT_LOGICAL, EA_4BYTE, regLo, count - 32);
+ }
#endif // _TARGET_*
- }
- else // count >= 64
- {
- assert(count >= 64);
- genSetRegToIcon(regLo, 0);
- }
- genSetRegToIcon(regHi, 0);
+ }
+ else // count >= 64
+ {
+ assert(count >= 64);
+ genSetRegToIcon(regLo, 0);
+ }
+ genSetRegToIcon(regHi, 0);
+ }
+ break;
+
+ default:
+ noway_assert(!"Illegal oper for long shift");
+ break;
}
- break;
- default:
- noway_assert(!"Illegal oper for long shift");
- break;
+ goto DONE_SHF;
}
- goto DONE_SHF;
- }
-
- /* Which operand are we supposed to compute first? */
+ /* Which operand are we supposed to compute first? */
- assert((RBM_SHIFT_LNG & RBM_LNGARG_0) == 0);
+ assert((RBM_SHIFT_LNG & RBM_LNGARG_0) == 0);
- if (tree->gtFlags & GTF_REVERSE_OPS)
- {
- /* The second operand can't be a constant */
+ if (tree->gtFlags & GTF_REVERSE_OPS)
+ {
+ /* The second operand can't be a constant */
- noway_assert(op2->gtOper != GT_CNS_INT);
+ noway_assert(op2->gtOper != GT_CNS_INT);
- /* Load the shift count, hopefully into RBM_SHIFT */
- RegSet::ExactReg exactReg;
- if ((RBM_SHIFT_LNG & op1->gtRsvdRegs) == 0)
- exactReg = RegSet::EXACT_REG;
- else
- exactReg = RegSet::ANY_REG;
- genComputeReg(op2, RBM_SHIFT_LNG, exactReg, RegSet::KEEP_REG);
+ /* Load the shift count, hopefully into RBM_SHIFT */
+ RegSet::ExactReg exactReg;
+ if ((RBM_SHIFT_LNG & op1->gtRsvdRegs) == 0)
+ exactReg = RegSet::EXACT_REG;
+ else
+ exactReg = RegSet::ANY_REG;
+ genComputeReg(op2, RBM_SHIFT_LNG, exactReg, RegSet::KEEP_REG);
- /* Compute the left operand into REG_LNGARG_0 */
+ /* Compute the left operand into REG_LNGARG_0 */
- genComputeRegPair(op1, REG_LNGARG_0, avoidReg, RegSet::KEEP_REG, false);
- noway_assert(op1->gtFlags & GTF_REG_VAL);
+ genComputeRegPair(op1, REG_LNGARG_0, avoidReg, RegSet::KEEP_REG, false);
+ noway_assert(op1->gtFlags & GTF_REG_VAL);
- /* Lock op1 so that it doesn't get trashed */
+ /* Lock op1 so that it doesn't get trashed */
- regSet.rsLockUsedReg(RBM_LNGARG_0);
+ regSet.rsLockUsedReg(RBM_LNGARG_0);
- /* Make sure the shift count wasn't displaced */
+ /* Make sure the shift count wasn't displaced */
- genRecoverReg(op2, RBM_SHIFT_LNG, RegSet::KEEP_REG);
+ genRecoverReg(op2, RBM_SHIFT_LNG, RegSet::KEEP_REG);
- /* Lock op2 */
+ /* Lock op2 */
- regSet.rsLockUsedReg(RBM_SHIFT_LNG);
- }
- else
- {
- /* Compute the left operand into REG_LNGARG_0 */
+ regSet.rsLockUsedReg(RBM_SHIFT_LNG);
+ }
+ else
+ {
+ /* Compute the left operand into REG_LNGARG_0 */
- genComputeRegPair(op1, REG_LNGARG_0, avoidReg, RegSet::KEEP_REG, false);
- noway_assert(op1->gtFlags & GTF_REG_VAL);
+ genComputeRegPair(op1, REG_LNGARG_0, avoidReg, RegSet::KEEP_REG, false);
+ noway_assert(op1->gtFlags & GTF_REG_VAL);
- /* Compute the shift count into RBM_SHIFT */
+ /* Compute the shift count into RBM_SHIFT */
- genComputeReg(op2, RBM_SHIFT_LNG, RegSet::EXACT_REG, RegSet::KEEP_REG);
+ genComputeReg(op2, RBM_SHIFT_LNG, RegSet::EXACT_REG, RegSet::KEEP_REG);
- /* Lock op2 */
+ /* Lock op2 */
- regSet.rsLockUsedReg(RBM_SHIFT_LNG);
+ regSet.rsLockUsedReg(RBM_SHIFT_LNG);
- /* Make sure the value hasn't been displaced */
+ /* Make sure the value hasn't been displaced */
- genRecoverRegPair(op1, REG_LNGARG_0, RegSet::KEEP_REG);
+ genRecoverRegPair(op1, REG_LNGARG_0, RegSet::KEEP_REG);
- /* Lock op1 so that it doesn't get trashed */
+ /* Lock op1 so that it doesn't get trashed */
- regSet.rsLockUsedReg(RBM_LNGARG_0);
- }
+ regSet.rsLockUsedReg(RBM_LNGARG_0);
+ }
#ifndef _TARGET_X86_
- /* The generic helper is a C-routine and so it follows the full ABI */
- {
- /* Spill any callee-saved registers which are being used */
- regMaskTP spillRegs = RBM_CALLEE_TRASH & regSet.rsMaskUsed;
+ /* The generic helper is a C-routine and so it follows the full ABI */
+ {
+ /* Spill any callee-saved registers which are being used */
+ regMaskTP spillRegs = RBM_CALLEE_TRASH & regSet.rsMaskUsed;
- /* But do not spill our argument registers. */
- spillRegs &= ~(RBM_LNGARG_0 | RBM_SHIFT_LNG);
+ /* But do not spill our argument registers. */
+ spillRegs &= ~(RBM_LNGARG_0 | RBM_SHIFT_LNG);
- if (spillRegs)
- {
- regSet.rsSpillRegs(spillRegs);
+ if (spillRegs)
+ {
+ regSet.rsSpillRegs(spillRegs);
+ }
}
- }
#endif // !_TARGET_X86_
- /* Perform the shift by calling a helper function */
+ /* Perform the shift by calling a helper function */
- noway_assert(op1->gtRegPair == REG_LNGARG_0);
- noway_assert(op2->gtRegNum == REG_SHIFT_LNG);
- noway_assert((regSet.rsMaskLock & (RBM_LNGARG_0 | RBM_SHIFT_LNG)) == (RBM_LNGARG_0 | RBM_SHIFT_LNG));
+ noway_assert(op1->gtRegPair == REG_LNGARG_0);
+ noway_assert(op2->gtRegNum == REG_SHIFT_LNG);
+ noway_assert((regSet.rsMaskLock & (RBM_LNGARG_0 | RBM_SHIFT_LNG)) == (RBM_LNGARG_0 | RBM_SHIFT_LNG));
- genEmitHelperCall(helper,
- 0, // argSize
- EA_8BYTE); // retSize
+ genEmitHelperCall(helper,
+ 0, // argSize
+ EA_8BYTE); // retSize
#ifdef _TARGET_X86_
- /* The value in the register pair is trashed */
+ /* The value in the register pair is trashed */
- regTracker.rsTrackRegTrash(genRegPairLo(REG_LNGARG_0));
- regTracker.rsTrackRegTrash(genRegPairHi(REG_LNGARG_0));
-#else // _TARGET_X86_
- /* The generic helper is a C-routine and so it follows the full ABI */
- regTracker.rsTrackRegMaskTrash(RBM_CALLEE_TRASH);
+ regTracker.rsTrackRegTrash(genRegPairLo(REG_LNGARG_0));
+ regTracker.rsTrackRegTrash(genRegPairHi(REG_LNGARG_0));
+#else // _TARGET_X86_
+ /* The generic helper is a C-routine and so it follows the full ABI */
+ regTracker.rsTrackRegMaskTrash(RBM_CALLEE_TRASH);
#endif // _TARGET_X86_
- /* Release both operands */
+ /* Release both operands */
- regSet.rsUnlockUsedReg(RBM_LNGARG_0 | RBM_SHIFT_LNG);
- genReleaseRegPair(op1);
- genReleaseReg (op2);
+ regSet.rsUnlockUsedReg(RBM_LNGARG_0 | RBM_SHIFT_LNG);
+ genReleaseRegPair(op1);
+ genReleaseReg(op2);
- DONE_SHF:
+ DONE_SHF:
- noway_assert(op1->gtFlags & GTF_REG_VAL);
- regPair = op1->gtRegPair;
- goto DONE;
+ noway_assert(op1->gtFlags & GTF_REG_VAL);
+ regPair = op1->gtRegPair;
+ goto DONE;
- case GT_NEG:
- case GT_NOT:
+ case GT_NEG:
+ case GT_NOT:
- /* Generate the operand into some register pair */
+ /* Generate the operand into some register pair */
- genCompIntoFreeRegPair(op1, avoidReg, RegSet::FREE_REG);
- noway_assert(op1->gtFlags & GTF_REG_VAL);
+ genCompIntoFreeRegPair(op1, avoidReg, RegSet::FREE_REG);
+ noway_assert(op1->gtFlags & GTF_REG_VAL);
- regPair = op1->gtRegPair;
+ regPair = op1->gtRegPair;
- /* Figure out which registers the value is in */
+ /* Figure out which registers the value is in */
- regLo = genRegPairLo(regPair);
- regHi = genRegPairHi(regPair);
+ regLo = genRegPairLo(regPair);
+ regHi = genRegPairHi(regPair);
- /* The value in the register pair is about to be trashed */
+ /* The value in the register pair is about to be trashed */
- regTracker.rsTrackRegTrash(regLo);
- regTracker.rsTrackRegTrash(regHi);
+ regTracker.rsTrackRegTrash(regLo);
+ regTracker.rsTrackRegTrash(regHi);
- /* Unary "neg": negate the value in the register pair */
- if (oper == GT_NEG)
- {
+ /* Unary "neg": negate the value in the register pair */
+ if (oper == GT_NEG)
+ {
#ifdef _TARGET_ARM_
- // ARM doesn't have an opcode that sets the carry bit like
- // x86, so we can't use neg/addc/neg. Instead we use subtract
- // with carry. Too bad this uses an extra register.
+ // ARM doesn't have an opcode that sets the carry bit like
+ // x86, so we can't use neg/addc/neg. Instead we use subtract
+ // with carry. Too bad this uses an extra register.
- // Lock regLo and regHi so we don't pick them, and then pick
- // a third register to be our 0.
- regMaskTP regPairMask = genRegMask(regLo) | genRegMask(regHi);
- regSet.rsLockReg(regPairMask);
- regMaskTP regBest = RBM_ALLINT & ~avoidReg;
- regNumber regZero = genGetRegSetToIcon(0, regBest);
- regSet.rsUnlockReg(regPairMask);
+ // Lock regLo and regHi so we don't pick them, and then pick
+ // a third register to be our 0.
+ regMaskTP regPairMask = genRegMask(regLo) | genRegMask(regHi);
+ regSet.rsLockReg(regPairMask);
+ regMaskTP regBest = RBM_ALLINT & ~avoidReg;
+ regNumber regZero = genGetRegSetToIcon(0, regBest);
+ regSet.rsUnlockReg(regPairMask);
- inst_RV_IV(INS_rsb, regLo, 0, EA_4BYTE, INS_FLAGS_SET);
- getEmitter()->emitIns_R_R_R_I(INS_sbc, EA_4BYTE, regHi, regZero, regHi, 0);
+ inst_RV_IV(INS_rsb, regLo, 0, EA_4BYTE, INS_FLAGS_SET);
+ getEmitter()->emitIns_R_R_R_I(INS_sbc, EA_4BYTE, regHi, regZero, regHi, 0);
#elif defined(_TARGET_XARCH_)
- inst_RV (INS_NEG, regLo, TYP_LONG);
- inst_RV_IV(INS_ADDC, regHi, 0, emitActualTypeSize(TYP_LONG));
- inst_RV (INS_NEG, regHi, TYP_LONG);
+ inst_RV(INS_NEG, regLo, TYP_LONG);
+ inst_RV_IV(INS_ADDC, regHi, 0, emitActualTypeSize(TYP_LONG));
+ inst_RV(INS_NEG, regHi, TYP_LONG);
#else
- NYI("GT_NEG on TYP_LONG");
+ NYI("GT_NEG on TYP_LONG");
#endif
- }
- else
- {
- /* Unary "not": flip all the bits in the register pair */
+ }
+ else
+ {
+ /* Unary "not": flip all the bits in the register pair */
- inst_RV (INS_NOT, regLo, TYP_LONG);
- inst_RV (INS_NOT, regHi, TYP_LONG);
- }
+ inst_RV(INS_NOT, regLo, TYP_LONG);
+ inst_RV(INS_NOT, regHi, TYP_LONG);
+ }
- goto DONE;
+ goto DONE;
#if LONG_ASG_OPS
- case GT_ASG_OR : insLo = insHi = INS_OR ; goto ASG_OPR;
- case GT_ASG_XOR: insLo = insHi = INS_XOR; goto ASG_OPR;
- case GT_ASG_AND: insLo = insHi = INS_AND; goto ASG_OPR;
- case GT_ASG_SUB: insLo = INS_sub; insHi = INS_SUBC; goto ASG_OPR;
- case GT_ASG_ADD: insLo = INS_add; insHi = INS_ADDC; goto ASG_OPR;
-
- ASG_OPR:
-
- if (op2->gtOper == GT_CNS_LNG)
- {
- __int64 lval = op2->gtLngCon.gtLconVal;
+ case GT_ASG_OR:
+ insLo = insHi = INS_OR;
+ goto ASG_OPR;
+ case GT_ASG_XOR:
+ insLo = insHi = INS_XOR;
+ goto ASG_OPR;
+ case GT_ASG_AND:
+ insLo = insHi = INS_AND;
+ goto ASG_OPR;
+ case GT_ASG_SUB:
+ insLo = INS_sub;
+ insHi = INS_SUBC;
+ goto ASG_OPR;
+ case GT_ASG_ADD:
+ insLo = INS_add;
+ insHi = INS_ADDC;
+ goto ASG_OPR;
+
+ ASG_OPR:
+
+ if (op2->gtOper == GT_CNS_LNG)
+ {
+ __int64 lval = op2->gtLngCon.gtLconVal;
- /* Make the target addressable */
+ /* Make the target addressable */
- addrReg = genMakeAddressable(op1, needReg, RegSet::FREE_REG);
+ addrReg = genMakeAddressable(op1, needReg, RegSet::FREE_REG);
- /* Optimize some special cases */
+ /* Optimize some special cases */
- doLo =
- doHi = true;
+ doLo = doHi = true;
- /* Check for "(op1 AND -1)" and "(op1 [X]OR 0)" */
+ /* Check for "(op1 AND -1)" and "(op1 [X]OR 0)" */
- switch (oper)
- {
- case GT_ASG_AND:
- if ((int)(lval ) == -1) doLo = false;
- if ((int)(lval >> 32) == -1) doHi = false;
- break;
+ switch (oper)
+ {
+ case GT_ASG_AND:
+ if ((int)(lval) == -1)
+ doLo = false;
+ if ((int)(lval >> 32) == -1)
+ doHi = false;
+ break;
- case GT_ASG_OR:
- case GT_ASG_XOR:
- if (!(lval & 0x00000000FFFFFFFF)) doLo = false;
- if (!(lval & 0xFFFFFFFF00000000)) doHi = false;
- break;
- }
+ case GT_ASG_OR:
+ case GT_ASG_XOR:
+ if (!(lval & 0x00000000FFFFFFFF))
+ doLo = false;
+ if (!(lval & 0xFFFFFFFF00000000))
+ doHi = false;
+ break;
+ }
- if (doLo) inst_TT_IV(insLo, op1, (int)(lval ), 0);
- if (doHi) inst_TT_IV(insHi, op1, (int)(lval >> 32), 4);
+ if (doLo)
+ inst_TT_IV(insLo, op1, (int)(lval), 0);
+ if (doHi)
+ inst_TT_IV(insHi, op1, (int)(lval >> 32), 4);
- bool isArith = (oper == GT_ASG_ADD || oper == GT_ASG_SUB);
- if (doLo || doHi)
- tree->gtFlags |= GTF_ZSF_SET;
+ bool isArith = (oper == GT_ASG_ADD || oper == GT_ASG_SUB);
+ if (doLo || doHi)
+ tree->gtFlags |= GTF_ZSF_SET;
- genDoneAddressable(op1, addrReg, RegSet::FREE_REG);
- goto DONE_ASSG_REGS;
- }
+ genDoneAddressable(op1, addrReg, RegSet::FREE_REG);
+ goto DONE_ASSG_REGS;
+ }
- /* TODO: allow non-const long assignment operators */
+ /* TODO: allow non-const long assignment operators */
- noway_assert(!"non-const long asgop NYI");
+ noway_assert(!"non-const long asgop NYI");
#endif // LONG_ASG_OPS
- case GT_IND:
- case GT_NULLCHECK:
+ case GT_IND:
+ case GT_NULLCHECK:
{
- regMaskTP tmpMask;
- int hiFirst;
-
- regMaskTP availMask = RBM_ALLINT & ~needReg;
+ regMaskTP tmpMask;
+ int hiFirst;
+
+ regMaskTP availMask = RBM_ALLINT & ~needReg;
/* Make sure the operand is addressable */
@@ -14881,11 +14637,11 @@ SIMPLE_OR_LONG:
hiFirst = FALSE;
- if (tmpMask & addrReg)
+ if (tmpMask & addrReg)
{
/* Does one or both of the target registers overlap? */
- if ((tmpMask & addrReg) != tmpMask)
+ if ((tmpMask & addrReg) != tmpMask)
{
/* Only one register overlaps */
@@ -14893,12 +14649,12 @@ SIMPLE_OR_LONG:
/* If the low register overlaps, load the upper half first */
- if (addrReg & genRegMask(genRegPairLo(regPair)))
+ if (addrReg & genRegMask(genRegPairLo(regPair)))
hiFirst = TRUE;
}
else
{
- regMaskTP regFree;
+ regMaskTP regFree;
/* The register completely overlaps with the address */
@@ -14907,12 +14663,12 @@ SIMPLE_OR_LONG:
/* Can we pick another pair easily? */
regFree = regSet.rsRegMaskFree() & ~addrReg;
- if (needReg)
+ if (needReg)
regFree &= needReg;
/* More than one free register available? */
- if (regFree && !genMaxOneBit(regFree))
+ if (regFree && !genMaxOneBit(regFree))
{
regPair = regSet.rsPickRegPair(regFree);
tmpMask = genRegPairMask(regPair);
@@ -14926,12 +14682,12 @@ SIMPLE_OR_LONG:
// Grab one fresh reg, and use any one of addrReg
- if (regFree) // Try to follow 'needReg'
+ if (regFree) // Try to follow 'needReg'
regLo = regSet.rsGrabReg(regFree);
- else // Pick any reg besides addrReg
+ else // Pick any reg besides addrReg
regLo = regSet.rsGrabReg(RBM_ALLINT & ~addrReg);
- unsigned regBit = 0x1;
+ unsigned regBit = 0x1;
regNumber regNo;
for (regNo = REG_INT_FIRST; regNo <= REG_INT_LAST; regNo = REG_NEXT(regNo), regBit <<= 1)
@@ -14964,7 +14720,7 @@ SIMPLE_OR_LONG:
/* Load the target registers from where the value is */
- if (hiFirst)
+ if (hiFirst)
{
inst_RV_AT(ins_Load(TYP_INT), EA_4BYTE, TYP_INT, regHi, addr, 4);
regSet.rsLockReg(genRegMask(regHi));
@@ -14982,177 +14738,175 @@ SIMPLE_OR_LONG:
#ifdef _TARGET_ARM_
if (tree->gtFlags & GTF_IND_VOLATILE)
{
- // Emit a memory barrier instruction after the load
+ // Emit a memory barrier instruction after the load
instGen_MemoryBarrier();
}
#endif
genUpdateLife(tree);
genDoneAddressable(tree, addrReg, RegSet::FREE_REG);
-
}
- goto DONE;
+ goto DONE;
- case GT_CAST:
+ case GT_CAST:
- /* What are we casting from? */
+ /* What are we casting from? */
- switch (op1->gtType)
- {
- case TYP_BOOL:
- case TYP_BYTE:
- case TYP_CHAR:
- case TYP_SHORT:
- case TYP_INT:
- case TYP_UBYTE:
- case TYP_BYREF:
+ switch (op1->gtType)
{
- regMaskTP hiRegMask;
- regMaskTP loRegMask;
-
- // For an unsigned cast we don't need to sign-extend the 32 bit value
- if (tree->gtFlags & GTF_UNSIGNED)
+ case TYP_BOOL:
+ case TYP_BYTE:
+ case TYP_CHAR:
+ case TYP_SHORT:
+ case TYP_INT:
+ case TYP_UBYTE:
+ case TYP_BYREF:
{
- // Does needReg have exactly two bits on and thus
- // specifies the exact register pair that we want to use
- if (!genMaxOneBit(needReg))
- {
- regPair = regSet.rsFindRegPairNo(needReg);
- if (needReg != genRegPairMask(regPair))
- goto ANY_FREE_REG_UNSIGNED;
- loRegMask = genRegMask(genRegPairLo(regPair));
- if ((loRegMask & regSet.rsRegMaskCanGrab()) == 0)
- goto ANY_FREE_REG_UNSIGNED;
- hiRegMask = genRegMask(genRegPairHi(regPair));
- }
- else
+ regMaskTP hiRegMask;
+ regMaskTP loRegMask;
+
+ // For an unsigned cast we don't need to sign-extend the 32 bit value
+ if (tree->gtFlags & GTF_UNSIGNED)
{
-ANY_FREE_REG_UNSIGNED:
- loRegMask = needReg;
- hiRegMask = needReg;
- }
+ // Does needReg have exactly two bits on and thus
+ // specifies the exact register pair that we want to use
+ if (!genMaxOneBit(needReg))
+ {
+ regPair = regSet.rsFindRegPairNo(needReg);
+ if (needReg != genRegPairMask(regPair))
+ goto ANY_FREE_REG_UNSIGNED;
+ loRegMask = genRegMask(genRegPairLo(regPair));
+ if ((loRegMask & regSet.rsRegMaskCanGrab()) == 0)
+ goto ANY_FREE_REG_UNSIGNED;
+ hiRegMask = genRegMask(genRegPairHi(regPair));
+ }
+ else
+ {
+ ANY_FREE_REG_UNSIGNED:
+ loRegMask = needReg;
+ hiRegMask = needReg;
+ }
- genComputeReg(op1, loRegMask, RegSet::ANY_REG, RegSet::KEEP_REG);
- noway_assert(op1->gtFlags & GTF_REG_VAL);
+ genComputeReg(op1, loRegMask, RegSet::ANY_REG, RegSet::KEEP_REG);
+ noway_assert(op1->gtFlags & GTF_REG_VAL);
- regLo = op1->gtRegNum;
- loRegMask = genRegMask(regLo);
- regSet.rsLockUsedReg(loRegMask);
- regHi = regSet.rsPickReg(hiRegMask);
- regSet.rsUnlockUsedReg(loRegMask);
+ regLo = op1->gtRegNum;
+ loRegMask = genRegMask(regLo);
+ regSet.rsLockUsedReg(loRegMask);
+ regHi = regSet.rsPickReg(hiRegMask);
+ regSet.rsUnlockUsedReg(loRegMask);
- regPair = gen2regs2pair(regLo, regHi);
+ regPair = gen2regs2pair(regLo, regHi);
- // Move 0 to the higher word of the ULong
- genSetRegToIcon(regHi, 0, TYP_INT);
+ // Move 0 to the higher word of the ULong
+ genSetRegToIcon(regHi, 0, TYP_INT);
- /* We can now free up the operand */
- genReleaseReg(op1);
+ /* We can now free up the operand */
+ genReleaseReg(op1);
- goto DONE;
- }
+ goto DONE;
+ }
#ifdef _TARGET_XARCH_
- /* Cast of 'int' to 'long' --> Use cdq if EAX,EDX are available
- and we need the result to be in those registers.
- cdq is smaller so we use it for SMALL_CODE
- */
-
- if ((needReg & (RBM_EAX|RBM_EDX)) == (RBM_EAX|RBM_EDX) &&
- (regSet.rsRegMaskFree() & RBM_EDX) )
- {
- genCodeForTree(op1, RBM_EAX);
- regSet.rsMarkRegUsed(op1);
-
- /* If we have to spill EDX, might as well use the faster
- sar as the spill will increase code size anyway */
+ /* Cast of 'int' to 'long' --> Use cdq if EAX,EDX are available
+ and we need the result to be in those registers.
+ cdq is smaller so we use it for SMALL_CODE
+ */
- if (op1->gtRegNum != REG_EAX ||
- !(regSet.rsRegMaskFree() & RBM_EDX))
+ if ((needReg & (RBM_EAX | RBM_EDX)) == (RBM_EAX | RBM_EDX) &&
+ (regSet.rsRegMaskFree() & RBM_EDX))
{
- hiRegMask = regSet.rsRegMaskFree();
- goto USE_SAR_FOR_CAST;
- }
+ genCodeForTree(op1, RBM_EAX);
+ regSet.rsMarkRegUsed(op1);
- regSet.rsGrabReg (RBM_EDX);
- regTracker.rsTrackRegTrash(REG_EDX);
+ /* If we have to spill EDX, might as well use the faster
+ sar as the spill will increase code size anyway */
- /* Convert the int in EAX into a long in EDX:EAX */
+ if (op1->gtRegNum != REG_EAX || !(regSet.rsRegMaskFree() & RBM_EDX))
+ {
+ hiRegMask = regSet.rsRegMaskFree();
+ goto USE_SAR_FOR_CAST;
+ }
- instGen(INS_cdq);
+ regSet.rsGrabReg(RBM_EDX);
+ regTracker.rsTrackRegTrash(REG_EDX);
- /* The result is in EDX:EAX */
+ /* Convert the int in EAX into a long in EDX:EAX */
- regPair = REG_PAIR_EAXEDX;
- }
- else
-#endif
- {
- /* use the sar instruction to sign-extend a 32-bit integer */
+ instGen(INS_cdq);
- // Does needReg have exactly two bits on and thus
- // specifies the exact register pair that we want to use
- if (!genMaxOneBit(needReg))
- {
- regPair = regSet.rsFindRegPairNo(needReg);
- if ((regPair == REG_PAIR_NONE) || (needReg != genRegPairMask(regPair)))
- goto ANY_FREE_REG_SIGNED;
- loRegMask = genRegMask(genRegPairLo(regPair));
- if ((loRegMask & regSet.rsRegMaskCanGrab()) == 0)
- goto ANY_FREE_REG_SIGNED;
- hiRegMask = genRegMask(genRegPairHi(regPair));
+ /* The result is in EDX:EAX */
+
+ regPair = REG_PAIR_EAXEDX;
}
else
+#endif
{
-ANY_FREE_REG_SIGNED:
- loRegMask = needReg;
- hiRegMask = RBM_NONE;
- }
+ /* use the sar instruction to sign-extend a 32-bit integer */
- genComputeReg(op1, loRegMask, RegSet::ANY_REG, RegSet::KEEP_REG);
+ // Does needReg have exactly two bits on and thus
+ // specifies the exact register pair that we want to use
+ if (!genMaxOneBit(needReg))
+ {
+ regPair = regSet.rsFindRegPairNo(needReg);
+ if ((regPair == REG_PAIR_NONE) || (needReg != genRegPairMask(regPair)))
+ goto ANY_FREE_REG_SIGNED;
+ loRegMask = genRegMask(genRegPairLo(regPair));
+ if ((loRegMask & regSet.rsRegMaskCanGrab()) == 0)
+ goto ANY_FREE_REG_SIGNED;
+ hiRegMask = genRegMask(genRegPairHi(regPair));
+ }
+ else
+ {
+ ANY_FREE_REG_SIGNED:
+ loRegMask = needReg;
+ hiRegMask = RBM_NONE;
+ }
+
+ genComputeReg(op1, loRegMask, RegSet::ANY_REG, RegSet::KEEP_REG);
#ifdef _TARGET_XARCH_
-USE_SAR_FOR_CAST:
+ USE_SAR_FOR_CAST:
#endif
- noway_assert(op1->gtFlags & GTF_REG_VAL);
+ noway_assert(op1->gtFlags & GTF_REG_VAL);
- regLo = op1->gtRegNum;
- loRegMask = genRegMask(regLo);
- regSet.rsLockUsedReg(loRegMask);
- regHi = regSet.rsPickReg(hiRegMask);
- regSet.rsUnlockUsedReg(loRegMask);
+ regLo = op1->gtRegNum;
+ loRegMask = genRegMask(regLo);
+ regSet.rsLockUsedReg(loRegMask);
+ regHi = regSet.rsPickReg(hiRegMask);
+ regSet.rsUnlockUsedReg(loRegMask);
- regPair = gen2regs2pair(regLo, regHi);
+ regPair = gen2regs2pair(regLo, regHi);
#ifdef _TARGET_ARM_
- /* Copy the lo32 bits from regLo to regHi and sign-extend it */
- // Use one instruction instead of two
- getEmitter()->emitIns_R_R_I(INS_SHIFT_RIGHT_ARITHM, EA_4BYTE, regHi, regLo, 31);
+ /* Copy the lo32 bits from regLo to regHi and sign-extend it */
+ // Use one instruction instead of two
+ getEmitter()->emitIns_R_R_I(INS_SHIFT_RIGHT_ARITHM, EA_4BYTE, regHi, regLo, 31);
#else
- /* Copy the lo32 bits from regLo to regHi and sign-extend it */
- inst_RV_RV(INS_mov, regHi, regLo, TYP_INT);
- inst_RV_SH(INS_SHIFT_RIGHT_ARITHM, EA_4BYTE, regHi, 31);
+ /* Copy the lo32 bits from regLo to regHi and sign-extend it */
+ inst_RV_RV(INS_mov, regHi, regLo, TYP_INT);
+ inst_RV_SH(INS_SHIFT_RIGHT_ARITHM, EA_4BYTE, regHi, 31);
#endif
- /* The value in the upper register is trashed */
+ /* The value in the upper register is trashed */
- regTracker.rsTrackRegTrash(regHi);
- }
+ regTracker.rsTrackRegTrash(regHi);
+ }
- /* We can now free up the operand */
- genReleaseReg(op1);
+ /* We can now free up the operand */
+ genReleaseReg(op1);
- // conv.ovf.u8 could overflow if the original number was negative
- if (tree->gtOverflow() && TYP_ULONG == tree->CastToType())
- {
- regNumber hiReg = genRegPairHi(regPair);
- instGen_Compare_Reg_To_Zero(EA_4BYTE, hiReg); // set flags
- emitJumpKind jmpLTS = genJumpKindForOper(GT_LT, CK_SIGNED);
- genJumpToThrowHlpBlk(jmpLTS, SCK_OVERFLOW);
+ // conv.ovf.u8 could overflow if the original number was negative
+ if (tree->gtOverflow() && TYP_ULONG == tree->CastToType())
+ {
+ regNumber hiReg = genRegPairHi(regPair);
+ instGen_Compare_Reg_To_Zero(EA_4BYTE, hiReg); // set flags
+ emitJumpKind jmpLTS = genJumpKindForOper(GT_LT, CK_SIGNED);
+ genJumpToThrowHlpBlk(jmpLTS, SCK_OVERFLOW);
+ }
}
- }
- goto DONE;
+ goto DONE;
- case TYP_FLOAT:
- case TYP_DOUBLE:
+ case TYP_FLOAT:
+ case TYP_DOUBLE:
#if 0
/* Load the FP value onto the coprocessor stack */
@@ -15192,153 +14946,152 @@ USE_SAR_FOR_CAST:
compiler->tmpRlsTemp(temp);
goto DONE;
#else
- NO_WAY("Cast from TYP_FLOAT or TYP_DOUBLE supposed to be done via a helper call");
- break;
+ NO_WAY("Cast from TYP_FLOAT or TYP_DOUBLE supposed to be done via a helper call");
+ break;
#endif
- case TYP_LONG:
- case TYP_ULONG:
- {
- noway_assert(tree->gtOverflow()); // conv.ovf.u8 or conv.ovf.i8
+ case TYP_LONG:
+ case TYP_ULONG:
+ {
+ noway_assert(tree->gtOverflow()); // conv.ovf.u8 or conv.ovf.i8
- genComputeRegPair(op1, REG_PAIR_NONE, RBM_ALLINT & ~needReg, RegSet::FREE_REG);
- regPair = op1->gtRegPair;
+ genComputeRegPair(op1, REG_PAIR_NONE, RBM_ALLINT & ~needReg, RegSet::FREE_REG);
+ regPair = op1->gtRegPair;
- // Do we need to set the sign-flag, or can we checked if it is set?
- // and not do this "test" if so.
+ // Do we need to set the sign-flag, or can we checked if it is set?
+ // and not do this "test" if so.
- if (op1->gtFlags & GTF_REG_VAL)
- {
- regNumber hiReg = genRegPairHi(op1->gtRegPair);
- noway_assert(hiReg != REG_STK);
- instGen_Compare_Reg_To_Zero(EA_4BYTE, hiReg); // set flags
- }
- else
- {
- inst_TT_IV(INS_cmp, op1, 0, sizeof(int));
- }
+ if (op1->gtFlags & GTF_REG_VAL)
+ {
+ regNumber hiReg = genRegPairHi(op1->gtRegPair);
+ noway_assert(hiReg != REG_STK);
+ instGen_Compare_Reg_To_Zero(EA_4BYTE, hiReg); // set flags
+ }
+ else
+ {
+ inst_TT_IV(INS_cmp, op1, 0, sizeof(int));
+ }
- emitJumpKind jmpLTS = genJumpKindForOper(GT_LT, CK_SIGNED);
- genJumpToThrowHlpBlk(jmpLTS, SCK_OVERFLOW);
- }
- goto DONE;
+ emitJumpKind jmpLTS = genJumpKindForOper(GT_LT, CK_SIGNED);
+ genJumpToThrowHlpBlk(jmpLTS, SCK_OVERFLOW);
+ }
+ goto DONE;
- default:
-#ifdef DEBUG
- compiler->gtDispTree(tree);
+ default:
+#ifdef DEBUG
+ compiler->gtDispTree(tree);
#endif
- NO_WAY("unexpected cast to long");
- }
- break;
+ NO_WAY("unexpected cast to long");
+ }
+ break;
+ case GT_RETURN:
- case GT_RETURN:
+ /* TODO:
+ * This code is cloned from the regular processing of GT_RETURN values. We have to remember to
+ * call genPInvokeMethodEpilog anywhere that we have a GT_RETURN statement. We should really
+ * generate trees for the PInvoke prolog and epilog so we can remove these special cases.
+ */
- /* TODO:
- * This code is cloned from the regular processing of GT_RETURN values. We have to remember to
- * call genPInvokeMethodEpilog anywhere that we have a GT_RETURN statement. We should really
- * generate trees for the PInvoke prolog and epilog so we can remove these special cases.
- */
+ // TODO: this should be done AFTER we called exit mon so that
+ // we are sure that we don't have to keep 'this' alive
- // TODO: this should be done AFTER we called exit mon so that
- // we are sure that we don't have to keep 'this' alive
-
- if (compiler->info.compCallUnmanaged && (compiler->compCurBB == compiler->genReturnBB))
- {
- /* either it's an "empty" statement or the return statement
- of a synchronized method
- */
+ if (compiler->info.compCallUnmanaged && (compiler->compCurBB == compiler->genReturnBB))
+ {
+ /* either it's an "empty" statement or the return statement
+ of a synchronized method
+ */
- genPInvokeMethodEpilog();
- }
+ genPInvokeMethodEpilog();
+ }
#if CPU_LONG_USES_REGPAIR
- /* There must be a long return value */
+ /* There must be a long return value */
- noway_assert(op1);
+ noway_assert(op1);
- /* Evaluate the return value into EDX:EAX */
+ /* Evaluate the return value into EDX:EAX */
- genEvalIntoFreeRegPair(op1, REG_LNGRET, avoidReg);
+ genEvalIntoFreeRegPair(op1, REG_LNGRET, avoidReg);
- noway_assert(op1->gtFlags & GTF_REG_VAL);
- noway_assert(op1->gtRegPair == REG_LNGRET);
+ noway_assert(op1->gtFlags & GTF_REG_VAL);
+ noway_assert(op1->gtRegPair == REG_LNGRET);
#else
- NYI("64-bit return");
+ NYI("64-bit return");
#endif
#ifdef PROFILING_SUPPORTED
- //The profiling hook does not trash registers, so it's safe to call after we emit the code for
- //the GT_RETURN tree.
+ // The profiling hook does not trash registers, so it's safe to call after we emit the code for
+ // the GT_RETURN tree.
- if (compiler->compCurBB == compiler->genReturnBB)
- {
- genProfilingLeaveCallback();
- }
+ if (compiler->compCurBB == compiler->genReturnBB)
+ {
+ genProfilingLeaveCallback();
+ }
#endif
- return;
+ return;
- case GT_QMARK:
- noway_assert(!"inliner-generated ?: for longs NYI");
- NO_WAY("inliner-generated ?: for longs NYI");
- break;
+ case GT_QMARK:
+ noway_assert(!"inliner-generated ?: for longs NYI");
+ NO_WAY("inliner-generated ?: for longs NYI");
+ break;
- case GT_COMMA:
+ case GT_COMMA:
- if (tree->gtFlags & GTF_REVERSE_OPS)
- {
- // Generate op2
- genCodeForTreeLng(op2, needReg, avoidReg);
- genUpdateLife (op2);
+ if (tree->gtFlags & GTF_REVERSE_OPS)
+ {
+ // Generate op2
+ genCodeForTreeLng(op2, needReg, avoidReg);
+ genUpdateLife(op2);
- noway_assert(op2->gtFlags & GTF_REG_VAL);
+ noway_assert(op2->gtFlags & GTF_REG_VAL);
- regSet.rsMarkRegPairUsed(op2);
+ regSet.rsMarkRegPairUsed(op2);
- // Do side effects of op1
- genEvalSideEffects(op1);
+ // Do side effects of op1
+ genEvalSideEffects(op1);
- // Recover op2 if spilled
- genRecoverRegPair(op2, REG_PAIR_NONE, RegSet::KEEP_REG);
+ // Recover op2 if spilled
+ genRecoverRegPair(op2, REG_PAIR_NONE, RegSet::KEEP_REG);
- genReleaseRegPair(op2);
+ genReleaseRegPair(op2);
- genUpdateLife (tree);
+ genUpdateLife(tree);
- regPair = op2->gtRegPair;
- }
- else
- {
- noway_assert((tree->gtFlags & GTF_REVERSE_OPS) == 0);
+ regPair = op2->gtRegPair;
+ }
+ else
+ {
+ noway_assert((tree->gtFlags & GTF_REVERSE_OPS) == 0);
- /* Generate side effects of the first operand */
+ /* Generate side effects of the first operand */
- genEvalSideEffects(op1);
- genUpdateLife (op1);
+ genEvalSideEffects(op1);
+ genUpdateLife(op1);
- /* Is the value of the second operand used? */
+ /* Is the value of the second operand used? */
- if (tree->gtType == TYP_VOID)
- {
- /* The right operand produces no result */
+ if (tree->gtType == TYP_VOID)
+ {
+ /* The right operand produces no result */
- genEvalSideEffects(op2);
- genUpdateLife(tree);
- return;
- }
+ genEvalSideEffects(op2);
+ genUpdateLife(tree);
+ return;
+ }
- /* Generate the second operand, i.e. the 'real' value */
+ /* Generate the second operand, i.e. the 'real' value */
- genCodeForTreeLng(op2, needReg, avoidReg);
+ genCodeForTreeLng(op2, needReg, avoidReg);
- /* The result of 'op2' is also the final result */
+ /* The result of 'op2' is also the final result */
- regPair = op2->gtRegPair;
- }
+ regPair = op2->gtRegPair;
+ }
- goto DONE;
+ goto DONE;
- case GT_BOX:
+ case GT_BOX:
{
/* Generate the operand, i.e. the 'real' value */
@@ -15349,21 +15102,21 @@ USE_SAR_FOR_CAST:
regPair = op1->gtRegPair;
}
- goto DONE;
+ goto DONE;
- case GT_NOP:
- if (op1 == NULL)
- return;
+ case GT_NOP:
+ if (op1 == NULL)
+ return;
- genCodeForTreeLng(op1, needReg, avoidReg);
- regPair = op1->gtRegPair;
- goto DONE;
+ genCodeForTreeLng(op1, needReg, avoidReg);
+ regPair = op1->gtRegPair;
+ goto DONE;
- default:
- break;
+ default:
+ break;
}
-#ifdef DEBUG
+#ifdef DEBUG
compiler->gtDispTree(tree);
#endif
noway_assert(!"unexpected 64-bit operator");
@@ -15371,22 +15124,22 @@ USE_SAR_FOR_CAST:
/* See what kind of a special operator we have here */
- switch (oper)
+ switch (oper)
{
regMaskTP retMask;
- case GT_CALL:
- retMask = genCodeForCall(tree, true);
- if (retMask == RBM_NONE)
- regPair = REG_PAIR_NONE;
- else
- regPair = regSet.rsFindRegPairNo(retMask);
- break;
+ case GT_CALL:
+ retMask = genCodeForCall(tree, true);
+ if (retMask == RBM_NONE)
+ regPair = REG_PAIR_NONE;
+ else
+ regPair = regSet.rsFindRegPairNo(retMask);
+ break;
- default:
-#ifdef DEBUG
- compiler->gtDispTree(tree);
+ default:
+#ifdef DEBUG
+ compiler->gtDispTree(tree);
#endif
- NO_WAY("unexpected long operator");
+ NO_WAY("unexpected long operator");
}
DONE:
@@ -15403,33 +15156,30 @@ DONE:
#pragma warning(pop)
#endif
-
/*****************************************************************************
*
* Generate code for a mod of a long by an int.
*/
-regPairNo CodeGen::genCodeForLongModInt(GenTreePtr tree,
- regMaskTP needReg)
+regPairNo CodeGen::genCodeForLongModInt(GenTreePtr tree, regMaskTP needReg)
{
#ifdef _TARGET_X86_
- regPairNo regPair;
- regMaskTP addrReg;
+ regPairNo regPair;
+ regMaskTP addrReg;
- genTreeOps oper = tree->OperGet();
- GenTreePtr op1 = tree->gtOp.gtOp1;
- GenTreePtr op2 = tree->gtOp.gtOp2;
+ genTreeOps oper = tree->OperGet();
+ GenTreePtr op1 = tree->gtOp.gtOp1;
+ GenTreePtr op2 = tree->gtOp.gtOp2;
/* Codegen only for Unsigned MOD */
noway_assert(oper == GT_UMOD);
/* op2 must be a long constant in the range 2 to 0x3fffffff */
- noway_assert((op2->gtOper == GT_CNS_LNG) &&
- (op2->gtLngCon.gtLconVal >= 2) &&
- (op2->gtLngCon.gtLconVal <= 0x3fffffff));
- int val = (int) op2->gtLngCon.gtLconVal;
+ noway_assert((op2->gtOper == GT_CNS_LNG) && (op2->gtLngCon.gtLconVal >= 2) &&
+ (op2->gtLngCon.gtLconVal <= 0x3fffffff));
+ int val = (int)op2->gtLngCon.gtLconVal;
op2->ChangeOperConst(GT_CNS_INT); // it's effectively an integer constant
@@ -15438,7 +15188,7 @@ regPairNo CodeGen::genCodeForLongModInt(GenTreePtr tree,
/* Which operand are we supposed to compute first? */
- if (tree->gtFlags & GTF_REVERSE_OPS)
+ if (tree->gtFlags & GTF_REVERSE_OPS)
{
/* Compute the second operand into a scratch register, other
than EAX or EDX */
@@ -15447,9 +15197,7 @@ regPairNo CodeGen::genCodeForLongModInt(GenTreePtr tree,
/* Special case: if op2 is a local var we are done */
- if (op2->gtOper == GT_LCL_VAR ||
- op2->gtOper == GT_LCL_FLD ||
- op2->gtOper == GT_CLS_VAR)
+ if (op2->gtOper == GT_LCL_VAR || op2->gtOper == GT_LCL_FLD || op2->gtOper == GT_CLS_VAR)
{
addrReg = genMakeRvalueAddressable(op2, needReg, RegSet::KEEP_REG, false);
}
@@ -15486,9 +15234,7 @@ regPairNo CodeGen::genCodeForLongModInt(GenTreePtr tree,
/* Special case: if op2 is a local var we are done */
- if (op2->gtOper == GT_LCL_VAR ||
- op2->gtOper == GT_LCL_FLD ||
- op2->gtOper == GT_CLS_VAR)
+ if (op2->gtOper == GT_LCL_VAR || op2->gtOper == GT_LCL_FLD || op2->gtOper == GT_CLS_VAR)
{
addrReg = genMakeRvalueAddressable(op2, needReg, RegSet::KEEP_REG, false);
}
@@ -15530,7 +15276,7 @@ regPairNo CodeGen::genCodeForLongModInt(GenTreePtr tree,
This works because (a * 2^32 + b) % c = ((a % c) * 2^32 + b) % c
*/
- BasicBlock * lab_no_overflow = genCreateTempLabel();
+ BasicBlock* lab_no_overflow = genCreateTempLabel();
// grab a temporary register other than eax, edx, and op2->gtRegNum
@@ -15539,16 +15285,16 @@ regPairNo CodeGen::genCodeForLongModInt(GenTreePtr tree,
// EAX and tempReg will be trashed by the mov instructions. Doing
// this early won't hurt, and might prevent confusion in genSetRegToIcon.
- regTracker.rsTrackRegTrash (REG_PAIR_TMP_LO);
- regTracker.rsTrackRegTrash (tempReg);
+ regTracker.rsTrackRegTrash(REG_PAIR_TMP_LO);
+ regTracker.rsTrackRegTrash(tempReg);
inst_RV_RV(INS_cmp, REG_PAIR_TMP_HI, op2->gtRegNum);
- inst_JMP(EJ_jb ,lab_no_overflow);
+ inst_JMP(EJ_jb, lab_no_overflow);
inst_RV_RV(INS_mov, tempReg, REG_PAIR_TMP_LO, TYP_INT);
inst_RV_RV(INS_mov, REG_PAIR_TMP_LO, REG_PAIR_TMP_HI, TYP_INT);
genSetRegToIcon(REG_PAIR_TMP_HI, 0, TYP_INT);
- inst_TT(INS_UNSIGNED_DIVIDE, op2);
+ inst_TT(INS_UNSIGNED_DIVIDE, op2);
inst_RV_RV(INS_mov, REG_PAIR_TMP_LO, tempReg, TYP_INT);
// Jump point for no overflow divide
@@ -15561,11 +15307,10 @@ regPairNo CodeGen::genCodeForLongModInt(GenTreePtr tree,
/* EAX, EDX, tempReg and op2->gtRegNum are now trashed */
- regTracker.rsTrackRegTrash (REG_PAIR_TMP_LO);
- regTracker.rsTrackRegTrash (REG_PAIR_TMP_HI);
- regTracker.rsTrackRegTrash (tempReg);
- regTracker.rsTrackRegTrash (op2->gtRegNum);
-
+ regTracker.rsTrackRegTrash(REG_PAIR_TMP_LO);
+ regTracker.rsTrackRegTrash(REG_PAIR_TMP_HI);
+ regTracker.rsTrackRegTrash(tempReg);
+ regTracker.rsTrackRegTrash(op2->gtRegNum);
if (tree->gtFlags & GTF_MOD_INT_RESULT)
{
@@ -15608,12 +15353,12 @@ regPairNo CodeGen::genCodeForLongModInt(GenTreePtr tree,
unsigned CodeGen::genRegCountForLiveIntEnregVars(GenTreePtr tree)
{
unsigned regCount = 0;
-
+
VARSET_ITER_INIT(compiler, iter, compiler->compCurLife, varNum);
while (iter.NextElem(compiler, &varNum))
{
- unsigned lclNum = compiler->lvaTrackedToVarNum[varNum];
- LclVarDsc * varDsc = &compiler->lvaTable[lclNum];
+ unsigned lclNum = compiler->lvaTrackedToVarNum[varNum];
+ LclVarDsc* varDsc = &compiler->lvaTable[lclNum];
if (varDsc->lvRegister && !varTypeIsFloating(varDsc->TypeGet()))
{
@@ -15621,39 +15366,39 @@ unsigned CodeGen::genRegCountForLiveIntEnregVars(GenTreePtr tree)
if (varTypeIsLong(varDsc->TypeGet()))
{
- // For enregistered LONG/ULONG, the lower half should always be in a register.
+ // For enregistered LONG/ULONG, the lower half should always be in a register.
noway_assert(varDsc->lvRegNum != REG_STK);
- // If the LONG/ULONG is NOT paritally enregistered, then the higher half should be in a register as well.
+ // If the LONG/ULONG is NOT paritally enregistered, then the higher half should be in a register as
+ // well.
if (varDsc->lvOtherReg != REG_STK)
{
++regCount;
}
}
}
- }
-
+ }
+
return regCount;
-
}
/*****************************************************************************/
/*****************************************************************************/
-#if CPU_HAS_FP_SUPPORT
+#if CPU_HAS_FP_SUPPORT
/*****************************************************************************
*
* Generate code for a floating-point operation.
*/
-void CodeGen::genCodeForTreeFlt(GenTreePtr tree,
- regMaskTP needReg, /* = RBM_ALLFLOAT */
- regMaskTP bestReg) /* = RBM_NONE */
+void CodeGen::genCodeForTreeFlt(GenTreePtr tree,
+ regMaskTP needReg, /* = RBM_ALLFLOAT */
+ regMaskTP bestReg) /* = RBM_NONE */
{
genCodeForTreeFloat(tree, needReg, bestReg);
if (tree->OperGet() == GT_RETURN)
{
- //Make sure to get ALL THE EPILOG CODE
+ // Make sure to get ALL THE EPILOG CODE
// TODO: this should be done AFTER we called exit mon so that
// we are sure that we don't have to keep 'this' alive
@@ -15668,8 +15413,8 @@ void CodeGen::genCodeForTreeFlt(GenTreePtr tree,
}
#ifdef PROFILING_SUPPORTED
- //The profiling hook does not trash registers, so it's safe to call after we emit the code for
- //the GT_RETURN tree.
+ // The profiling hook does not trash registers, so it's safe to call after we emit the code for
+ // the GT_RETURN tree.
if (compiler->compCurBB == compiler->genReturnBB)
{
@@ -15680,23 +15425,21 @@ void CodeGen::genCodeForTreeFlt(GenTreePtr tree,
}
/*****************************************************************************/
-#endif//CPU_HAS_FP_SUPPORT
+#endif // CPU_HAS_FP_SUPPORT
/*****************************************************************************
*
* Generate a table switch - the switch value (0-based) is in register 'reg'.
*/
-void CodeGen::genTableSwitch(regNumber reg,
- unsigned jumpCnt,
- BasicBlock ** jumpTab)
+void CodeGen::genTableSwitch(regNumber reg, unsigned jumpCnt, BasicBlock** jumpTab)
{
- unsigned jmpTabBase;
+ unsigned jmpTabBase;
if (jumpCnt == 1)
{
- //In debug code, we don't optimize away the trivial switch statements. So we can get here with a
- //BBJ_SWITCH with only a default case. Therefore, don't generate the switch table.
+ // In debug code, we don't optimize away the trivial switch statements. So we can get here with a
+ // BBJ_SWITCH with only a default case. Therefore, don't generate the switch table.
noway_assert(compiler->opts.MinOpts() || compiler->opts.compDbgCode);
inst_JMP(EJ_jmp, jumpTab[0]);
return;
@@ -15710,7 +15453,6 @@ void CodeGen::genTableSwitch(regNumber reg,
const bool fDefaultFollows = (compiler->compCurBB->bbNext == jumpTab[jumpCnt - 1]);
const bool fHaveScratchReg = ((regSet.rsRegMaskFree() & genRegMask(reg)) != 0);
-
unsigned minSwitchTabJumpCnt = 2; // table is better than just 2 cmp/jcc
// This means really just a single cmp/jcc (aka a simple if/else)
@@ -15718,15 +15460,15 @@ void CodeGen::genTableSwitch(regNumber reg,
minSwitchTabJumpCnt++;
#ifdef _TARGET_ARM_
- // On the ARM for small switch tables we will
+ // On the ARM for small switch tables we will
// generate a sequence of compare and branch instructions
// because the code to load the base of the switch
// table is huge and hideous due to the relocation... :(
- //
+ //
minSwitchTabJumpCnt++;
if (fHaveScratchReg)
minSwitchTabJumpCnt++;
-
+
#endif // _TARGET_ARM_
if (jumpCnt < minSwitchTabJumpCnt)
@@ -15734,7 +15476,7 @@ void CodeGen::genTableSwitch(regNumber reg,
/* Does the first case label follow? */
emitJumpKind jmpEqual = genJumpKindForOper(GT_EQ, CK_SIGNED);
- if (fFirstCaseFollows)
+ if (fFirstCaseFollows)
{
/* Check for the default case */
inst_RV_IV(INS_cmp, reg, jumpCnt - 1, EA_4BYTE);
@@ -15757,7 +15499,7 @@ void CodeGen::genTableSwitch(regNumber reg,
inst_RV_RV(INS_mov, tmpReg, reg);
regTracker.rsTrackRegTrash(tmpReg);
reg = tmpReg;
- }
+ }
while (jumpCnt > 0)
{
@@ -15788,7 +15530,7 @@ void CodeGen::genTableSwitch(regNumber reg,
inst_RV_RV(INS_mov, tmpReg, reg);
regTracker.rsTrackRegTrash(tmpReg);
reg = tmpReg;
- }
+ }
while (jumpCnt > 0)
{
@@ -15803,7 +15545,8 @@ void CodeGen::genTableSwitch(regNumber reg,
}
}
- if ((fFirstCaseFollows || fDefaultFollows) && compiler->fgInDifferentRegions(compiler->compCurBB, compiler->compCurBB->bbNext))
+ if ((fFirstCaseFollows || fDefaultFollows) &&
+ compiler->fgInDifferentRegions(compiler->compCurBB, compiler->compCurBB->bbNext))
{
inst_JMP(EJ_jmp, compiler->compCurBB->bbNext);
}
@@ -15821,8 +15564,8 @@ void CodeGen::genTableSwitch(regNumber reg,
jmpTabBase = getEmitter()->emitBBTableDataGenBeg(jumpCnt - 1, false);
-#ifdef DEBUG
- if (compiler->opts.dspCode)
+#ifdef DEBUG
+ if (compiler->opts.dspCode)
printf("\n J_M%03u_DS%02u LABEL DWORD\n", Compiler::s_compMethodsCount, jmpTabBase);
#endif
@@ -15832,8 +15575,8 @@ void CodeGen::genTableSwitch(regNumber reg,
noway_assert(target->bbFlags & BBF_JMP_TARGET);
-#ifdef DEBUG
- if (compiler->opts.dspCode)
+#ifdef DEBUG
+ if (compiler->opts.dspCode)
printf(" DD L_M%03u_BB%02u\n", Compiler::s_compMethodsCount, target->bbNum);
#endif
@@ -15868,13 +15611,13 @@ void CodeGen::genTableSwitch(regNumber reg,
* Generate code for a switch statement.
*/
-void CodeGen::genCodeForSwitch(GenTreePtr tree)
+void CodeGen::genCodeForSwitch(GenTreePtr tree)
{
- unsigned jumpCnt;
- BasicBlock * * jumpTab;
+ unsigned jumpCnt;
+ BasicBlock** jumpTab;
- GenTreePtr oper;
- regNumber reg;
+ GenTreePtr oper;
+ regNumber reg;
noway_assert(tree->gtOper == GT_SWITCH);
oper = tree->gtOp.gtOp1;
@@ -15914,20 +15657,16 @@ void CodeGen::genCodeForSwitch(GenTreePtr tree)
*/
// inline
-void CodeGen::genEmitHelperCall(unsigned helper,
- int argSize,
- emitAttr retSize)
+void CodeGen::genEmitHelperCall(unsigned helper, int argSize, emitAttr retSize)
{
// Can we call the helper function directly
- void * addr = NULL, **pAddr = NULL;
+ void *addr = NULL, **pAddr = NULL;
#if defined(_TARGET_ARM_) && defined(DEBUG) && defined(PROFILING_SUPPORTED)
- // Don't ask VM if it hasn't requested ELT hooks
- if (!compiler->compProfilerHookNeeded &&
- compiler->opts.compJitELTHookEnabled &&
- (helper == CORINFO_HELP_PROF_FCN_ENTER ||
- helper == CORINFO_HELP_PROF_FCN_LEAVE ||
+ // Don't ask VM if it hasn't requested ELT hooks
+ if (!compiler->compProfilerHookNeeded && compiler->opts.compJitELTHookEnabled &&
+ (helper == CORINFO_HELP_PROF_FCN_ENTER || helper == CORINFO_HELP_PROF_FCN_LEAVE ||
helper == CORINFO_HELP_PROF_FCN_TAILCALL))
{
addr = compiler->compProfilerMethHnd;
@@ -15938,12 +15677,12 @@ void CodeGen::genEmitHelperCall(unsigned helper,
addr = compiler->compGetHelperFtn((CorInfoHelpFunc)helper, (void**)&pAddr);
}
-
#ifdef _TARGET_ARM_
if (!addr || !arm_Valid_Imm_For_BL((ssize_t)addr))
{
// Load the address into a register and call through a register
- regNumber indCallReg = regSet.rsGrabReg(RBM_ALLINT); // Grab an available register to use for the CALL indirection
+ regNumber indCallReg =
+ regSet.rsGrabReg(RBM_ALLINT); // Grab an available register to use for the CALL indirection
if (addr)
{
instGen_Set_Reg_To_Imm(EA_HANDLE_CNS_RELOC, indCallReg, (ssize_t)addr);
@@ -15954,66 +15693,49 @@ void CodeGen::genEmitHelperCall(unsigned helper,
regTracker.rsTrackRegTrash(indCallReg);
}
- getEmitter()->emitIns_Call(emitter::EC_INDIR_R,
- compiler->eeFindHelper(helper),
- INDEBUG_LDISASM_COMMA(nullptr)
- NULL, // addr
- argSize,
- retSize,
- gcInfo.gcVarPtrSetCur,
- gcInfo.gcRegGCrefSetCur,
- gcInfo.gcRegByrefSetCur,
- BAD_IL_OFFSET, // ilOffset
- indCallReg, // ireg
- REG_NA, 0, 0, // xreg, xmul, disp
- false, // isJump
- emitter::emitNoGChelper(helper),
- (CorInfoHelpFunc)helper == CORINFO_HELP_PROF_FCN_LEAVE);
+ getEmitter()->emitIns_Call(emitter::EC_INDIR_R, compiler->eeFindHelper(helper),
+ INDEBUG_LDISASM_COMMA(nullptr) NULL, // addr
+ argSize, retSize, gcInfo.gcVarPtrSetCur, gcInfo.gcRegGCrefSetCur,
+ gcInfo.gcRegByrefSetCur,
+ BAD_IL_OFFSET, // ilOffset
+ indCallReg, // ireg
+ REG_NA, 0, 0, // xreg, xmul, disp
+ false, // isJump
+ emitter::emitNoGChelper(helper),
+ (CorInfoHelpFunc)helper == CORINFO_HELP_PROF_FCN_LEAVE);
}
else
{
- getEmitter()->emitIns_Call(emitter::EC_FUNC_TOKEN,
- compiler->eeFindHelper(helper),
- INDEBUG_LDISASM_COMMA(nullptr)
- addr,
- argSize,
- retSize,
- gcInfo.gcVarPtrSetCur,
- gcInfo.gcRegGCrefSetCur,
- gcInfo.gcRegByrefSetCur,
- BAD_IL_OFFSET, REG_NA, REG_NA, 0, 0, /* ilOffset, ireg, xreg, xmul, disp */
- false, /* isJump */
- emitter::emitNoGChelper(helper),
- (CorInfoHelpFunc)helper == CORINFO_HELP_PROF_FCN_LEAVE);
+ getEmitter()->emitIns_Call(emitter::EC_FUNC_TOKEN, compiler->eeFindHelper(helper),
+ INDEBUG_LDISASM_COMMA(nullptr) addr, argSize, retSize, gcInfo.gcVarPtrSetCur,
+ gcInfo.gcRegGCrefSetCur, gcInfo.gcRegByrefSetCur, BAD_IL_OFFSET, REG_NA, REG_NA, 0,
+ 0, /* ilOffset, ireg, xreg, xmul, disp */
+ false, /* isJump */
+ emitter::emitNoGChelper(helper),
+ (CorInfoHelpFunc)helper == CORINFO_HELP_PROF_FCN_LEAVE);
}
#else
{
- emitter::EmitCallType callType = emitter::EC_FUNC_TOKEN;
+ emitter::EmitCallType callType = emitter::EC_FUNC_TOKEN;
if (!addr)
{
callType = emitter::EC_FUNC_TOKEN_INDIR;
- addr = pAddr;
+ addr = pAddr;
}
- getEmitter()->emitIns_Call(callType,
- compiler->eeFindHelper(helper),
- INDEBUG_LDISASM_COMMA(nullptr)
- addr,
- argSize,
- retSize,
- gcInfo.gcVarPtrSetCur,
- gcInfo.gcRegGCrefSetCur,
- gcInfo.gcRegByrefSetCur,
- BAD_IL_OFFSET, REG_NA, REG_NA, 0, 0, /* ilOffset, ireg, xreg, xmul, disp */
- false, /* isJump */
- emitter::emitNoGChelper(helper));
+ getEmitter()->emitIns_Call(callType, compiler->eeFindHelper(helper), INDEBUG_LDISASM_COMMA(nullptr) addr,
+ argSize, retSize, gcInfo.gcVarPtrSetCur, gcInfo.gcRegGCrefSetCur,
+ gcInfo.gcRegByrefSetCur, BAD_IL_OFFSET, REG_NA, REG_NA, 0,
+ 0, /* ilOffset, ireg, xreg, xmul, disp */
+ false, /* isJump */
+ emitter::emitNoGChelper(helper));
}
#endif
regTracker.rsTrashRegSet(RBM_CALLEE_TRASH);
- regTracker.rsTrashRegsForGCInterruptability();
+ regTracker.rsTrashRegsForGCInterruptability();
}
/*****************************************************************************
@@ -16022,7 +15744,7 @@ void CodeGen::genEmitHelperCall(unsigned helper,
* This function does not check if the register is marked as used, etc.
*/
-regMaskTP CodeGen::genPushRegs(regMaskTP regs, regMaskTP * byrefRegs, regMaskTP * noRefRegs)
+regMaskTP CodeGen::genPushRegs(regMaskTP regs, regMaskTP* byrefRegs, regMaskTP* noRefRegs)
{
*byrefRegs = RBM_NONE;
*noRefRegs = RBM_NONE;
@@ -16032,14 +15754,14 @@ regMaskTP CodeGen::genPushRegs(regMaskTP regs, regMaskTP * byrefRegs,
if (regs == RBM_NONE)
return RBM_NONE;
-#if FEATURE_FIXED_OUT_ARGS
+#if FEATURE_FIXED_OUT_ARGS
NYI("Don't call genPushRegs with real regs!");
return RBM_NONE;
#else // FEATURE_FIXED_OUT_ARGS
- noway_assert(genTypeStSz(TYP_REF) == genTypeStSz(TYP_I_IMPL));
+ noway_assert(genTypeStSz(TYP_REF) == genTypeStSz(TYP_I_IMPL));
noway_assert(genTypeStSz(TYP_BYREF) == genTypeStSz(TYP_I_IMPL));
regMaskTP pushedRegs = regs;
@@ -16056,14 +15778,12 @@ regMaskTP CodeGen::genPushRegs(regMaskTP regs, regMaskTP * byrefRegs,
{
type = TYP_REF;
}
- else
- if (regBit & gcInfo.gcRegByrefSetCur)
+ else if (regBit & gcInfo.gcRegByrefSetCur)
{
*byrefRegs |= regBit;
type = TYP_BYREF;
}
- else
- if (noRefRegs != NULL)
+ else if (noRefRegs != NULL)
{
*noRefRegs |= regBit;
type = TYP_I_IMPL;
@@ -16084,7 +15804,6 @@ regMaskTP CodeGen::genPushRegs(regMaskTP regs, regMaskTP * byrefRegs,
return pushedRegs;
#endif // FEATURE_FIXED_OUT_ARGS
-
}
/*****************************************************************************
@@ -16092,12 +15811,12 @@ regMaskTP CodeGen::genPushRegs(regMaskTP regs, regMaskTP * byrefRegs,
* Pop the registers pushed by genPushRegs()
*/
-void CodeGen::genPopRegs(regMaskTP regs, regMaskTP byrefRegs, regMaskTP noRefRegs)
+void CodeGen::genPopRegs(regMaskTP regs, regMaskTP byrefRegs, regMaskTP noRefRegs)
{
if (regs == RBM_NONE)
return;
-#if FEATURE_FIXED_OUT_ARGS
+#if FEATURE_FIXED_OUT_ARGS
NYI("Don't call genPopRegs with real regs!");
@@ -16106,9 +15825,9 @@ void CodeGen::genPopRegs(regMaskTP regs, regMaskTP byrefRegs, reg
noway_assert((regs & byrefRegs) == byrefRegs);
noway_assert((regs & noRefRegs) == noRefRegs);
// noway_assert((regs & regSet.rsRegMaskFree()) == regs); // Don't care. Caller is responsible for all this
- noway_assert((regs & (gcInfo.gcRegGCrefSetCur|gcInfo.gcRegByrefSetCur)) == RBM_NONE);
+ noway_assert((regs & (gcInfo.gcRegGCrefSetCur | gcInfo.gcRegByrefSetCur)) == RBM_NONE);
- noway_assert(genTypeStSz(TYP_REF) == genTypeStSz(TYP_INT));
+ noway_assert(genTypeStSz(TYP_REF) == genTypeStSz(TYP_INT));
noway_assert(genTypeStSz(TYP_BYREF) == genTypeStSz(TYP_INT));
// Walk the registers in the reverse order as genPushRegs()
@@ -16124,8 +15843,7 @@ void CodeGen::genPopRegs(regMaskTP regs, regMaskTP byrefRegs, reg
{
type = TYP_BYREF;
}
- else
- if (regBit & noRefRegs)
+ else if (regBit & noRefRegs)
{
type = TYP_INT;
}
@@ -16144,7 +15862,6 @@ void CodeGen::genPopRegs(regMaskTP regs, regMaskTP byrefRegs, reg
}
#endif // FEATURE_FIXED_OUT_ARGS
-
}
/*****************************************************************************
@@ -16153,13 +15870,13 @@ void CodeGen::genPopRegs(regMaskTP regs, regMaskTP byrefRegs, reg
* stuff pushed.
*/
-#if !FEATURE_FIXED_OUT_ARGS
+#if !FEATURE_FIXED_OUT_ARGS
#ifdef _PREFAST_
#pragma warning(push)
-#pragma warning(disable:21000) // Suppress PREFast warning about overly large function
+#pragma warning(disable : 21000) // Suppress PREFast warning about overly large function
#endif
-size_t CodeGen::genPushArgList(GenTreePtr call)
-{
+size_t CodeGen::genPushArgList(GenTreePtr call)
+{
GenTreeArgList* regArgs = call->gtCall.gtCallLateArgs;
size_t size = 0;
regMaskTP addrReg;
@@ -16168,7 +15885,7 @@ size_t CodeGen::genPushArgList(GenTreePtr call)
// Create a local, artificial GenTreeArgList that includes the gtCallObjp, if that exists, as first argument,
// so we can iterate over this argument list more uniformly.
// Need to provide a temporary non-null first argument here: if we use this, we'll replace it.
- GenTreeArgList firstForObjp(/*temp dummy arg*/call, call->gtCall.gtCallArgs);
+ GenTreeArgList firstForObjp(/*temp dummy arg*/ call, call->gtCall.gtCallArgs);
if (call->gtCall.gtCallObjp == NULL)
{
args = call->gtCall.gtCallArgs;
@@ -16176,16 +15893,16 @@ size_t CodeGen::genPushArgList(GenTreePtr call)
else
{
firstForObjp.Current() = call->gtCall.gtCallObjp;
- args = &firstForObjp;
+ args = &firstForObjp;
}
- GenTreePtr curr;
- var_types type;
- size_t opsz;
+ GenTreePtr curr;
+ var_types type;
+ size_t opsz;
for (; args; args = args->Rest())
{
- addrReg = DUMMY_INIT(RBM_CORRUPT); // to detect uninitialized use
+ addrReg = DUMMY_INIT(RBM_CORRUPT); // to detect uninitialized use
/* Get hold of the next argument value */
curr = args->Current();
@@ -16209,690 +15926,675 @@ size_t CodeGen::genPushArgList(GenTreePtr call)
switch (type)
{
- case TYP_BOOL:
- case TYP_BYTE:
- case TYP_SHORT:
- case TYP_CHAR:
- case TYP_UBYTE:
+ case TYP_BOOL:
+ case TYP_BYTE:
+ case TYP_SHORT:
+ case TYP_CHAR:
+ case TYP_UBYTE:
- /* Don't want to push a small value, make it a full word */
+ /* Don't want to push a small value, make it a full word */
- genCodeForTree(curr, 0);
+ genCodeForTree(curr, 0);
- __fallthrough; // now the value should be in a register ...
+ __fallthrough; // now the value should be in a register ...
- case TYP_INT:
- case TYP_REF:
- case TYP_BYREF:
-#if ! CPU_HAS_FP_SUPPORT
- case TYP_FLOAT:
+ case TYP_INT:
+ case TYP_REF:
+ case TYP_BYREF:
+#if !CPU_HAS_FP_SUPPORT
+ case TYP_FLOAT:
#endif
- if (curr->gtFlags & GTF_LATE_ARG)
- {
- assert(curr->gtOper == GT_ASG);
- /* one more argument will be passed in a register */
- noway_assert(intRegState.rsCurRegArgNum < MAX_REG_ARG);
-
- /* arg is passed in the register, nothing on the stack */
-
- opsz = 0;
-
- }
+ if (curr->gtFlags & GTF_LATE_ARG)
+ {
+ assert(curr->gtOper == GT_ASG);
+ /* one more argument will be passed in a register */
+ noway_assert(intRegState.rsCurRegArgNum < MAX_REG_ARG);
- /* Is this value a handle? */
+ /* arg is passed in the register, nothing on the stack */
- if (curr->gtOper == GT_CNS_INT && curr->IsIconHandle())
- {
- /* Emit a fixup for the push instruction */
-
- inst_IV_handle(INS_push, curr->gtIntCon.gtIconVal);
- genSinglePush();
+ opsz = 0;
+ }
- addrReg = 0;
- break;
- }
+ /* Is this value a handle? */
+ if (curr->gtOper == GT_CNS_INT && curr->IsIconHandle())
+ {
+ /* Emit a fixup for the push instruction */
- /* Is the value a constant? */
+ inst_IV_handle(INS_push, curr->gtIntCon.gtIconVal);
+ genSinglePush();
- if (curr->gtOper == GT_CNS_INT)
- {
+ addrReg = 0;
+ break;
+ }
-#if REDUNDANT_LOAD
- regNumber reg = regTracker.rsIconIsInReg(curr->gtIntCon.gtIconVal);
+ /* Is the value a constant? */
- if (reg != REG_NA)
+ if (curr->gtOper == GT_CNS_INT)
{
- inst_RV(INS_push, reg, TYP_INT);
- }
- else
-#endif
- {
- inst_IV(INS_push, curr->gtIntCon.gtIconVal);
- }
- /* If the type is TYP_REF, then this must be a "null". So we can
- treat it as a TYP_INT as we don't need to report it as a GC ptr */
+#if REDUNDANT_LOAD
+ regNumber reg = regTracker.rsIconIsInReg(curr->gtIntCon.gtIconVal);
- noway_assert(curr->TypeGet() == TYP_INT ||
- (varTypeIsGC(curr->TypeGet()) && curr->gtIntCon.gtIconVal == 0));
+ if (reg != REG_NA)
+ {
+ inst_RV(INS_push, reg, TYP_INT);
+ }
+ else
+#endif
+ {
+ inst_IV(INS_push, curr->gtIntCon.gtIconVal);
+ }
- genSinglePush();
+ /* If the type is TYP_REF, then this must be a "null". So we can
+ treat it as a TYP_INT as we don't need to report it as a GC ptr */
- addrReg = 0;
- break;
- }
+ noway_assert(curr->TypeGet() == TYP_INT ||
+ (varTypeIsGC(curr->TypeGet()) && curr->gtIntCon.gtIconVal == 0));
+ genSinglePush();
- if (curr->gtFlags & GTF_LATE_ARG)
- {
- /* This must be a register arg temp assignment */
+ addrReg = 0;
+ break;
+ }
- noway_assert(curr->gtOper == GT_ASG);
+ if (curr->gtFlags & GTF_LATE_ARG)
+ {
+ /* This must be a register arg temp assignment */
- /* Evaluate it to the temp */
+ noway_assert(curr->gtOper == GT_ASG);
- genCodeForTree(curr, 0);
+ /* Evaluate it to the temp */
- /* Increment the current argument register counter */
+ genCodeForTree(curr, 0);
- intRegState.rsCurRegArgNum++;
+ /* Increment the current argument register counter */
- addrReg = 0;
- }
- else
- {
- /* This is a 32-bit integer non-register argument */
+ intRegState.rsCurRegArgNum++;
- addrReg = genMakeRvalueAddressable(curr, 0, RegSet::KEEP_REG, false);
- inst_TT(INS_push, curr);
- genSinglePush();
- genDoneAddressable(curr, addrReg, RegSet::KEEP_REG);
+ addrReg = 0;
+ }
+ else
+ {
+ /* This is a 32-bit integer non-register argument */
- }
- break;
+ addrReg = genMakeRvalueAddressable(curr, 0, RegSet::KEEP_REG, false);
+ inst_TT(INS_push, curr);
+ genSinglePush();
+ genDoneAddressable(curr, addrReg, RegSet::KEEP_REG);
+ }
+ break;
- case TYP_LONG:
+ case TYP_LONG:
#if !CPU_HAS_FP_SUPPORT
- case TYP_DOUBLE:
+ case TYP_DOUBLE:
#endif
- /* Is the value a constant? */
+ /* Is the value a constant? */
- if (curr->gtOper == GT_CNS_LNG)
- {
- inst_IV(INS_push, (int)(curr->gtLngCon.gtLconVal >> 32));
- genSinglePush();
- inst_IV(INS_push, (int)(curr->gtLngCon.gtLconVal ));
- genSinglePush();
+ if (curr->gtOper == GT_CNS_LNG)
+ {
+ inst_IV(INS_push, (int)(curr->gtLngCon.gtLconVal >> 32));
+ genSinglePush();
+ inst_IV(INS_push, (int)(curr->gtLngCon.gtLconVal));
+ genSinglePush();
- addrReg = 0;
- }
- else
- {
- addrReg = genMakeAddressable(curr, 0, RegSet::FREE_REG);
+ addrReg = 0;
+ }
+ else
+ {
+ addrReg = genMakeAddressable(curr, 0, RegSet::FREE_REG);
- inst_TT(INS_push, curr, sizeof(int));
- genSinglePush();
- inst_TT(INS_push, curr);
- genSinglePush();
- }
- break;
+ inst_TT(INS_push, curr, sizeof(int));
+ genSinglePush();
+ inst_TT(INS_push, curr);
+ genSinglePush();
+ }
+ break;
-#if CPU_HAS_FP_SUPPORT
- case TYP_FLOAT:
- case TYP_DOUBLE:
+#if CPU_HAS_FP_SUPPORT
+ case TYP_FLOAT:
+ case TYP_DOUBLE:
#endif
#if FEATURE_STACK_FP_X87
- addrReg = genPushArgumentStackFP(curr);
+ addrReg = genPushArgumentStackFP(curr);
#else
- NYI("FP codegen");
- addrReg = 0;
+ NYI("FP codegen");
+ addrReg = 0;
#endif
- break;
+ break;
- case TYP_VOID:
+ case TYP_VOID:
- /* Is this a nothing node, deferred register argument? */
+ /* Is this a nothing node, deferred register argument? */
- if (curr->gtFlags & GTF_LATE_ARG)
- {
- GenTree* arg = curr;
- if (arg->gtOper == GT_COMMA)
+ if (curr->gtFlags & GTF_LATE_ARG)
{
- while (arg->gtOper == GT_COMMA)
+ GenTree* arg = curr;
+ if (arg->gtOper == GT_COMMA)
{
- GenTreePtr op1 = arg->gtOp.gtOp1;
- genEvalSideEffects(op1);
- genUpdateLife(op1);
- arg = arg->gtOp.gtOp2;
- }
- if (!arg->IsNothingNode())
- {
- genEvalSideEffects(arg);
- genUpdateLife(arg);
+ while (arg->gtOper == GT_COMMA)
+ {
+ GenTreePtr op1 = arg->gtOp.gtOp1;
+ genEvalSideEffects(op1);
+ genUpdateLife(op1);
+ arg = arg->gtOp.gtOp2;
+ }
+ if (!arg->IsNothingNode())
+ {
+ genEvalSideEffects(arg);
+ genUpdateLife(arg);
+ }
}
- }
- /* increment the register count and continue with the next argument */
+ /* increment the register count and continue with the next argument */
- intRegState.rsCurRegArgNum++;
+ intRegState.rsCurRegArgNum++;
- noway_assert(opsz == 0);
+ noway_assert(opsz == 0);
- addrReg = 0;
- break;
- }
+ addrReg = 0;
+ break;
+ }
- __fallthrough;
+ __fallthrough;
- case TYP_STRUCT:
- {
- GenTree* arg = curr;
- while (arg->gtOper == GT_COMMA)
+ case TYP_STRUCT:
{
- GenTreePtr op1 = arg->gtOp.gtOp1;
- genEvalSideEffects(op1);
- genUpdateLife(op1);
- arg = arg->gtOp.gtOp2;
- }
+ GenTree* arg = curr;
+ while (arg->gtOper == GT_COMMA)
+ {
+ GenTreePtr op1 = arg->gtOp.gtOp1;
+ genEvalSideEffects(op1);
+ genUpdateLife(op1);
+ arg = arg->gtOp.gtOp2;
+ }
- noway_assert(arg->gtOper == GT_OBJ
- || arg->gtOper == GT_MKREFANY
- || arg->gtOper == GT_IND);
- noway_assert((arg->gtFlags & GTF_REVERSE_OPS) == 0);
- noway_assert(addrReg == DUMMY_INIT(RBM_CORRUPT));
+ noway_assert(arg->gtOper == GT_OBJ || arg->gtOper == GT_MKREFANY || arg->gtOper == GT_IND);
+ noway_assert((arg->gtFlags & GTF_REVERSE_OPS) == 0);
+ noway_assert(addrReg == DUMMY_INIT(RBM_CORRUPT));
- if (arg->gtOper == GT_MKREFANY)
- {
- GenTreePtr op1 = arg->gtOp.gtOp1;
- GenTreePtr op2 = arg->gtOp.gtOp2;
+ if (arg->gtOper == GT_MKREFANY)
+ {
+ GenTreePtr op1 = arg->gtOp.gtOp1;
+ GenTreePtr op2 = arg->gtOp.gtOp2;
- addrReg = genMakeAddressable(op1, RBM_NONE, RegSet::KEEP_REG);
+ addrReg = genMakeAddressable(op1, RBM_NONE, RegSet::KEEP_REG);
- /* Is this value a handle? */
- if (op2->gtOper == GT_CNS_INT && op2->IsIconHandle())
- {
- /* Emit a fixup for the push instruction */
+ /* Is this value a handle? */
+ if (op2->gtOper == GT_CNS_INT && op2->IsIconHandle())
+ {
+ /* Emit a fixup for the push instruction */
- inst_IV_handle(INS_push, op2->gtIntCon.gtIconVal);
+ inst_IV_handle(INS_push, op2->gtIntCon.gtIconVal);
+ genSinglePush();
+ }
+ else
+ {
+ regMaskTP addrReg2 = genMakeRvalueAddressable(op2, 0, RegSet::KEEP_REG, false);
+ inst_TT(INS_push, op2);
+ genSinglePush();
+ genDoneAddressable(op2, addrReg2, RegSet::KEEP_REG);
+ }
+ addrReg = genKeepAddressable(op1, addrReg);
+ inst_TT(INS_push, op1);
genSinglePush();
+ genDoneAddressable(op1, addrReg, RegSet::KEEP_REG);
+
+ opsz = 2 * TARGET_POINTER_SIZE;
}
else
{
- regMaskTP addrReg2 = genMakeRvalueAddressable(op2, 0, RegSet::KEEP_REG, false);
- inst_TT(INS_push, op2);
- genSinglePush();
- genDoneAddressable(op2, addrReg2, RegSet::KEEP_REG);
-
- }
- addrReg = genKeepAddressable(op1, addrReg);
- inst_TT(INS_push, op1);
- genSinglePush();
- genDoneAddressable(op1, addrReg, RegSet::KEEP_REG);
+ noway_assert(arg->gtOper == GT_OBJ);
- opsz = 2*TARGET_POINTER_SIZE;
- }
- else
- {
- noway_assert(arg->gtOper == GT_OBJ);
-
- if (arg->gtObj.gtOp1->gtOper == GT_ADDR &&
- arg->gtObj.gtOp1->gtOp.gtOp1->gtOper == GT_LCL_VAR)
- {
- GenTreePtr structLocalTree = arg->gtObj.gtOp1->gtOp.gtOp1;
- unsigned structLclNum = structLocalTree->gtLclVarCommon.gtLclNum;
- LclVarDsc * varDsc = &compiler->lvaTable[structLclNum];
-
- // As much as we would like this to be a noway_assert, we can't because
- // there are some weird casts out there, and backwards compatiblity
- // dictates we do *NOT* start rejecting them now. lvaGetPromotion and
- // lvPromoted in general currently do not require the local to be
- // TYP_STRUCT, so this assert is really more about how we wish the world
- // was then some JIT invariant.
- assert((structLocalTree->TypeGet() == TYP_STRUCT) || compiler->compUnsafeCastUsed);
-
- Compiler::lvaPromotionType promotionType = compiler->lvaGetPromotionType(varDsc);
-
- if (varDsc->lvPromoted &&
- promotionType==Compiler::PROMOTION_TYPE_INDEPENDENT) // Otherwise it is guaranteed to live on stack.
+ if (arg->gtObj.gtOp1->gtOper == GT_ADDR && arg->gtObj.gtOp1->gtOp.gtOp1->gtOper == GT_LCL_VAR)
{
- assert(!varDsc->lvAddrExposed); // Compiler::PROMOTION_TYPE_INDEPENDENT ==> not exposed.
+ GenTreePtr structLocalTree = arg->gtObj.gtOp1->gtOp.gtOp1;
+ unsigned structLclNum = structLocalTree->gtLclVarCommon.gtLclNum;
+ LclVarDsc* varDsc = &compiler->lvaTable[structLclNum];
+
+ // As much as we would like this to be a noway_assert, we can't because
+ // there are some weird casts out there, and backwards compatiblity
+ // dictates we do *NOT* start rejecting them now. lvaGetPromotion and
+ // lvPromoted in general currently do not require the local to be
+ // TYP_STRUCT, so this assert is really more about how we wish the world
+ // was then some JIT invariant.
+ assert((structLocalTree->TypeGet() == TYP_STRUCT) || compiler->compUnsafeCastUsed);
+
+ Compiler::lvaPromotionType promotionType = compiler->lvaGetPromotionType(varDsc);
+
+ if (varDsc->lvPromoted &&
+ promotionType ==
+ Compiler::PROMOTION_TYPE_INDEPENDENT) // Otherwise it is guaranteed to live on stack.
+ {
+ assert(!varDsc->lvAddrExposed); // Compiler::PROMOTION_TYPE_INDEPENDENT ==> not exposed.
- addrReg = 0;
+ addrReg = 0;
- // Get the number of BYTES to copy to the stack
- opsz = roundUp(compiler->info.compCompHnd->getClassSize(arg->gtObj.gtClass), sizeof(void*));
- size_t bytesToBeCopied = opsz;
-
- // postponedFields is true if we have any postponed fields
- // Any field that does not start on a 4-byte boundary is a postponed field
- // Such a field is required to be a short or a byte
- //
- // postponedRegKind records the kind of scratch register we will
- // need to process the postponed fields
- // RBM_NONE means that we don't need a register
- //
- // expectedAlignedOffset records the aligned offset that
- // has to exist for a push to cover the postponed fields.
- // Since all promoted structs have the tightly packed property
- // we are guaranteed that we will have such a push
- //
- bool postponedFields = false;
- regMaskTP postponedRegKind = RBM_NONE;
- size_t expectedAlignedOffset = UINT_MAX;
-
- VARSET_TP* deadVarBits = NULL;
- compiler->GetPromotedStructDeathVars()->Lookup(structLocalTree, &deadVarBits);
-
- // Reverse loop, starts pushing from the end of the struct (i.e. the highest field offset)
- //
- for (int varNum = varDsc->lvFieldLclStart + varDsc->lvFieldCnt - 1;
- varNum >= (int) varDsc->lvFieldLclStart;
- varNum--)
- {
- LclVarDsc * fieldVarDsc = compiler->lvaTable + varNum;
-#ifdef DEBUG
- if (fieldVarDsc->lvExactSize == 2*sizeof(unsigned))
- {
- noway_assert(fieldVarDsc->lvFldOffset % (2*sizeof(unsigned)) == 0);
- noway_assert(fieldVarDsc->lvFldOffset + (2*sizeof(unsigned)) == bytesToBeCopied);
- }
-#endif
- // Whenever we see a stack-aligned fieldVarDsc then we use 4-byte push instruction(s)
- // For packed structs we will go back and store the unaligned bytes and shorts
- // in the next loop
+ // Get the number of BYTES to copy to the stack
+ opsz = roundUp(compiler->info.compCompHnd->getClassSize(arg->gtObj.gtClass), sizeof(void*));
+ size_t bytesToBeCopied = opsz;
+
+ // postponedFields is true if we have any postponed fields
+ // Any field that does not start on a 4-byte boundary is a postponed field
+ // Such a field is required to be a short or a byte
//
- if (fieldVarDsc->lvStackAligned())
- {
- if (fieldVarDsc->lvExactSize != 2*sizeof(unsigned) &&
- fieldVarDsc->lvFldOffset + sizeof(void*) != bytesToBeCopied)
- {
- // Might need 4-bytes paddings for fields other than LONG and DOUBLE.
- // Just push some junk (i.e EAX) on the stack.
- inst_RV(INS_push, REG_EAX, TYP_INT);
- genSinglePush();
+ // postponedRegKind records the kind of scratch register we will
+ // need to process the postponed fields
+ // RBM_NONE means that we don't need a register
+ //
+ // expectedAlignedOffset records the aligned offset that
+ // has to exist for a push to cover the postponed fields.
+ // Since all promoted structs have the tightly packed property
+ // we are guaranteed that we will have such a push
+ //
+ bool postponedFields = false;
+ regMaskTP postponedRegKind = RBM_NONE;
+ size_t expectedAlignedOffset = UINT_MAX;
- bytesToBeCopied -= sizeof(void*);
- }
+ VARSET_TP* deadVarBits = NULL;
+ compiler->GetPromotedStructDeathVars()->Lookup(structLocalTree, &deadVarBits);
- // If we have an expectedAlignedOffset make sure that this push instruction
- // is what we expect to cover the postponedFields
- //
- if (expectedAlignedOffset != UINT_MAX)
+ // Reverse loop, starts pushing from the end of the struct (i.e. the highest field offset)
+ //
+ for (int varNum = varDsc->lvFieldLclStart + varDsc->lvFieldCnt - 1;
+ varNum >= (int)varDsc->lvFieldLclStart; varNum--)
+ {
+ LclVarDsc* fieldVarDsc = compiler->lvaTable + varNum;
+#ifdef DEBUG
+ if (fieldVarDsc->lvExactSize == 2 * sizeof(unsigned))
{
- // This push must be for a small field
- noway_assert(fieldVarDsc->lvExactSize < 4);
- // The fldOffset for this push should be equal to the expectedAlignedOffset
- noway_assert(fieldVarDsc->lvFldOffset == expectedAlignedOffset);
- expectedAlignedOffset = UINT_MAX;
+ noway_assert(fieldVarDsc->lvFldOffset % (2 * sizeof(unsigned)) == 0);
+ noway_assert(fieldVarDsc->lvFldOffset + (2 * sizeof(unsigned)) == bytesToBeCopied);
}
-
- // Push the "upper half" of LONG var first
-
- if (isRegPairType(fieldVarDsc->lvType))
+#endif
+ // Whenever we see a stack-aligned fieldVarDsc then we use 4-byte push instruction(s)
+ // For packed structs we will go back and store the unaligned bytes and shorts
+ // in the next loop
+ //
+ if (fieldVarDsc->lvStackAligned())
{
- if (fieldVarDsc->lvOtherReg != REG_STK)
- {
- inst_RV(INS_push,
- fieldVarDsc->lvOtherReg,
- TYP_INT);
+ if (fieldVarDsc->lvExactSize != 2 * sizeof(unsigned) &&
+ fieldVarDsc->lvFldOffset + sizeof(void*) != bytesToBeCopied)
+ {
+ // Might need 4-bytes paddings for fields other than LONG and DOUBLE.
+ // Just push some junk (i.e EAX) on the stack.
+ inst_RV(INS_push, REG_EAX, TYP_INT);
genSinglePush();
-
- // Prepare the set of vars to be cleared from gcref/gcbyref set
- // in case they become dead after genUpdateLife.
- // genDoneAddressable() will remove dead gc vars by calling gcInfo.gcMarkRegSetNpt.
- // Although it is not addrReg, we just borrow the name here.
- addrReg |= genRegMask(fieldVarDsc->lvOtherReg);
+
+ bytesToBeCopied -= sizeof(void*);
}
- else
+
+ // If we have an expectedAlignedOffset make sure that this push instruction
+ // is what we expect to cover the postponedFields
+ //
+ if (expectedAlignedOffset != UINT_MAX)
{
- getEmitter()->emitIns_S(INS_push,
- EA_4BYTE,
- varNum,
- sizeof(void*));
- genSinglePush();
- }
+ // This push must be for a small field
+ noway_assert(fieldVarDsc->lvExactSize < 4);
+ // The fldOffset for this push should be equal to the expectedAlignedOffset
+ noway_assert(fieldVarDsc->lvFldOffset == expectedAlignedOffset);
+ expectedAlignedOffset = UINT_MAX;
+ }
- bytesToBeCopied -= sizeof(void*);
- }
+ // Push the "upper half" of LONG var first
- // Push the "upper half" of DOUBLE var if it is not enregistered.
-
- if (fieldVarDsc->lvType == TYP_DOUBLE)
- {
- if (!fieldVarDsc->lvRegister)
- {
- getEmitter()->emitIns_S(INS_push,
- EA_4BYTE,
- varNum,
- sizeof(void*));
- genSinglePush();
+ if (isRegPairType(fieldVarDsc->lvType))
+ {
+ if (fieldVarDsc->lvOtherReg != REG_STK)
+ {
+ inst_RV(INS_push, fieldVarDsc->lvOtherReg, TYP_INT);
+ genSinglePush();
+
+ // Prepare the set of vars to be cleared from gcref/gcbyref set
+ // in case they become dead after genUpdateLife.
+ // genDoneAddressable() will remove dead gc vars by calling
+ // gcInfo.gcMarkRegSetNpt.
+ // Although it is not addrReg, we just borrow the name here.
+ addrReg |= genRegMask(fieldVarDsc->lvOtherReg);
+ }
+ else
+ {
+ getEmitter()->emitIns_S(INS_push, EA_4BYTE, varNum, sizeof(void*));
+ genSinglePush();
+ }
+
+ bytesToBeCopied -= sizeof(void*);
}
- bytesToBeCopied -= sizeof(void*);
- }
-
- //
- // Push the field local.
- //
-
- if (fieldVarDsc->lvRegister)
- {
- if (!varTypeIsFloating(genActualType(fieldVarDsc->TypeGet())))
+ // Push the "upper half" of DOUBLE var if it is not enregistered.
+
+ if (fieldVarDsc->lvType == TYP_DOUBLE)
{
- inst_RV(INS_push,
- fieldVarDsc->lvRegNum,
- genActualType(fieldVarDsc->TypeGet()));
- genSinglePush();
+ if (!fieldVarDsc->lvRegister)
+ {
+ getEmitter()->emitIns_S(INS_push, EA_4BYTE, varNum, sizeof(void*));
+ genSinglePush();
+ }
- // Prepare the set of vars to be cleared from gcref/gcbyref set
- // in case they become dead after genUpdateLife.
- // genDoneAddressable() will remove dead gc vars by calling gcInfo.gcMarkRegSetNpt.
- // Although it is not addrReg, we just borrow the name here.
- addrReg |= genRegMask(fieldVarDsc->lvRegNum);
+ bytesToBeCopied -= sizeof(void*);
}
- else
- {
- // Must be TYP_FLOAT or TYP_DOUBLE
- noway_assert(fieldVarDsc->lvRegNum != REG_FPNONE);
-
- noway_assert(fieldVarDsc->lvExactSize == sizeof(unsigned) ||
- fieldVarDsc->lvExactSize == 2*sizeof(unsigned));
-
- inst_RV_IV(INS_sub, REG_SPBASE, fieldVarDsc->lvExactSize, EA_PTRSIZE);
-
- genSinglePush();
- if (fieldVarDsc->lvExactSize == 2*sizeof(unsigned))
- {
+
+ //
+ // Push the field local.
+ //
+
+ if (fieldVarDsc->lvRegister)
+ {
+ if (!varTypeIsFloating(genActualType(fieldVarDsc->TypeGet())))
+ {
+ inst_RV(INS_push, fieldVarDsc->lvRegNum,
+ genActualType(fieldVarDsc->TypeGet()));
genSinglePush();
+
+ // Prepare the set of vars to be cleared from gcref/gcbyref set
+ // in case they become dead after genUpdateLife.
+ // genDoneAddressable() will remove dead gc vars by calling
+ // gcInfo.gcMarkRegSetNpt.
+ // Although it is not addrReg, we just borrow the name here.
+ addrReg |= genRegMask(fieldVarDsc->lvRegNum);
}
-
-#if FEATURE_STACK_FP_X87
- GenTree* fieldTree = new (compiler, GT_REG_VAR) GenTreeLclVar(fieldVarDsc->lvType, varNum, BAD_IL_OFFSET);
- fieldTree->gtOper = GT_REG_VAR;
- fieldTree->gtRegNum = fieldVarDsc->lvRegNum;
- fieldTree->gtRegVar.gtRegNum = fieldVarDsc->lvRegNum;
- if ((arg->gtFlags & GTF_VAR_DEATH) != 0)
+ else
{
- if (fieldVarDsc->lvTracked &&
- (deadVarBits == NULL || VarSetOps::IsMember(compiler, *deadVarBits, fieldVarDsc->lvVarIndex)))
+ // Must be TYP_FLOAT or TYP_DOUBLE
+ noway_assert(fieldVarDsc->lvRegNum != REG_FPNONE);
+
+ noway_assert(fieldVarDsc->lvExactSize == sizeof(unsigned) ||
+ fieldVarDsc->lvExactSize == 2 * sizeof(unsigned));
+
+ inst_RV_IV(INS_sub, REG_SPBASE, fieldVarDsc->lvExactSize, EA_PTRSIZE);
+
+ genSinglePush();
+ if (fieldVarDsc->lvExactSize == 2 * sizeof(unsigned))
{
- fieldTree->gtFlags |= GTF_VAR_DEATH;
+ genSinglePush();
}
- }
- genCodeForTreeStackFP_Leaf(fieldTree);
-
- // Take reg to top of stack
-
- FlatFPX87_MoveToTOS(&compCurFPState, fieldTree->gtRegNum);
-
- // Pop it off to stack
- compCurFPState.Pop();
-
- getEmitter()->emitIns_AR_R(INS_fstp, EA_ATTR(fieldVarDsc->lvExactSize), REG_NA, REG_SPBASE, 0);
+
+#if FEATURE_STACK_FP_X87
+ GenTree* fieldTree = new (compiler, GT_REG_VAR)
+ GenTreeLclVar(fieldVarDsc->lvType, varNum, BAD_IL_OFFSET);
+ fieldTree->gtOper = GT_REG_VAR;
+ fieldTree->gtRegNum = fieldVarDsc->lvRegNum;
+ fieldTree->gtRegVar.gtRegNum = fieldVarDsc->lvRegNum;
+ if ((arg->gtFlags & GTF_VAR_DEATH) != 0)
+ {
+ if (fieldVarDsc->lvTracked &&
+ (deadVarBits == NULL ||
+ VarSetOps::IsMember(compiler, *deadVarBits,
+ fieldVarDsc->lvVarIndex)))
+ {
+ fieldTree->gtFlags |= GTF_VAR_DEATH;
+ }
+ }
+ genCodeForTreeStackFP_Leaf(fieldTree);
+
+ // Take reg to top of stack
+
+ FlatFPX87_MoveToTOS(&compCurFPState, fieldTree->gtRegNum);
+
+ // Pop it off to stack
+ compCurFPState.Pop();
+
+ getEmitter()->emitIns_AR_R(INS_fstp, EA_ATTR(fieldVarDsc->lvExactSize),
+ REG_NA, REG_SPBASE, 0);
#else
- NYI_FLAT_FP_X87("FP codegen");
+ NYI_FLAT_FP_X87("FP codegen");
#endif
+ }
+ }
+ else
+ {
+ getEmitter()->emitIns_S(INS_push,
+ (fieldVarDsc->TypeGet() == TYP_REF) ? EA_GCREF
+ : EA_4BYTE,
+ varNum, 0);
+ genSinglePush();
}
- }
- else
- {
- getEmitter()->emitIns_S(INS_push,
- (fieldVarDsc->TypeGet() == TYP_REF)?EA_GCREF:EA_4BYTE,
- varNum,
- 0);
- genSinglePush();
- }
- bytesToBeCopied -= sizeof(void*);
- }
- else // not stack aligned
- {
- noway_assert(fieldVarDsc->lvExactSize < 4);
+ bytesToBeCopied -= sizeof(void*);
+ }
+ else // not stack aligned
+ {
+ noway_assert(fieldVarDsc->lvExactSize < 4);
- // We will need to use a store byte or store word
- // to set this unaligned location
- postponedFields = true;
+ // We will need to use a store byte or store word
+ // to set this unaligned location
+ postponedFields = true;
- if (expectedAlignedOffset != UINT_MAX)
- {
- // This should never change until it is set back to UINT_MAX by an aligned offset
- noway_assert(expectedAlignedOffset == roundUp(fieldVarDsc->lvFldOffset, sizeof(void*)) - sizeof(void*));
- }
+ if (expectedAlignedOffset != UINT_MAX)
+ {
+ // This should never change until it is set back to UINT_MAX by an aligned
+ // offset
+ noway_assert(expectedAlignedOffset ==
+ roundUp(fieldVarDsc->lvFldOffset, sizeof(void*)) - sizeof(void*));
+ }
- expectedAlignedOffset = roundUp(fieldVarDsc->lvFldOffset, sizeof(void*)) - sizeof(void*);
+ expectedAlignedOffset =
+ roundUp(fieldVarDsc->lvFldOffset, sizeof(void*)) - sizeof(void*);
- noway_assert(expectedAlignedOffset < bytesToBeCopied);
+ noway_assert(expectedAlignedOffset < bytesToBeCopied);
- if (fieldVarDsc->lvRegister)
- {
- // Do we need to use a byte-able register?
- if (fieldVarDsc->lvExactSize == 1)
+ if (fieldVarDsc->lvRegister)
{
- // Did we enregister fieldVarDsc2 in a non byte-able register?
- if ((genRegMask(fieldVarDsc->lvRegNum) & RBM_BYTE_REGS) == 0)
+ // Do we need to use a byte-able register?
+ if (fieldVarDsc->lvExactSize == 1)
{
- // then we will need to grab a byte-able register
- postponedRegKind = RBM_BYTE_REGS;
+ // Did we enregister fieldVarDsc2 in a non byte-able register?
+ if ((genRegMask(fieldVarDsc->lvRegNum) & RBM_BYTE_REGS) == 0)
+ {
+ // then we will need to grab a byte-able register
+ postponedRegKind = RBM_BYTE_REGS;
+ }
}
}
- }
- else // not enregistered
- {
- if (fieldVarDsc->lvExactSize == 1)
+ else // not enregistered
{
- // We will need to grab a byte-able register
- postponedRegKind = RBM_BYTE_REGS;
- }
- else
- {
- // We will need to grab any scratch register
- if (postponedRegKind != RBM_BYTE_REGS)
- postponedRegKind = RBM_ALLINT;
+ if (fieldVarDsc->lvExactSize == 1)
+ {
+ // We will need to grab a byte-able register
+ postponedRegKind = RBM_BYTE_REGS;
+ }
+ else
+ {
+ // We will need to grab any scratch register
+ if (postponedRegKind != RBM_BYTE_REGS)
+ postponedRegKind = RBM_ALLINT;
+ }
}
}
}
- }
- // Now we've pushed all of the aligned fields.
- //
- // We should have pushed bytes equal to the entire struct
- noway_assert(bytesToBeCopied == 0);
-
- // We should have seen a push that covers every postponed field
- noway_assert(expectedAlignedOffset == UINT_MAX);
-
- // Did we have any postponed fields?
- if (postponedFields)
- {
- regNumber regNum = REG_STK; // means no register
-
- // If we needed a scratch register then grab it here
-
- if (postponedRegKind != RBM_NONE)
- regNum = regSet.rsGrabReg(postponedRegKind);
-
- // Forward loop, starts from the lowest field offset
+ // Now we've pushed all of the aligned fields.
//
- for (unsigned varNum = varDsc->lvFieldLclStart;
- varNum < varDsc->lvFieldLclStart + varDsc->lvFieldCnt;
- varNum++)
- {
- LclVarDsc * fieldVarDsc = compiler->lvaTable + varNum;
-
- // All stack aligned fields have already been pushed
- if (fieldVarDsc->lvStackAligned())
- continue;
+ // We should have pushed bytes equal to the entire struct
+ noway_assert(bytesToBeCopied == 0);
- // We have a postponed field
+ // We should have seen a push that covers every postponed field
+ noway_assert(expectedAlignedOffset == UINT_MAX);
- // It must be a byte or a short
- noway_assert(fieldVarDsc->lvExactSize < 4);
+ // Did we have any postponed fields?
+ if (postponedFields)
+ {
+ regNumber regNum = REG_STK; // means no register
+
+ // If we needed a scratch register then grab it here
- // Is the field enregistered?
- if (fieldVarDsc->lvRegister)
+ if (postponedRegKind != RBM_NONE)
+ regNum = regSet.rsGrabReg(postponedRegKind);
+
+ // Forward loop, starts from the lowest field offset
+ //
+ for (unsigned varNum = varDsc->lvFieldLclStart;
+ varNum < varDsc->lvFieldLclStart + varDsc->lvFieldCnt; varNum++)
{
- // Frequently we can just use that register
- regNumber tmpRegNum = fieldVarDsc->lvRegNum;
-
- // Do we need to use a byte-able register?
- if (fieldVarDsc->lvExactSize == 1)
+ LclVarDsc* fieldVarDsc = compiler->lvaTable + varNum;
+
+ // All stack aligned fields have already been pushed
+ if (fieldVarDsc->lvStackAligned())
+ continue;
+
+ // We have a postponed field
+
+ // It must be a byte or a short
+ noway_assert(fieldVarDsc->lvExactSize < 4);
+
+ // Is the field enregistered?
+ if (fieldVarDsc->lvRegister)
{
- // Did we enregister the field in a non byte-able register?
- if ((genRegMask(tmpRegNum) & RBM_BYTE_REGS) == 0)
+ // Frequently we can just use that register
+ regNumber tmpRegNum = fieldVarDsc->lvRegNum;
+
+ // Do we need to use a byte-able register?
+ if (fieldVarDsc->lvExactSize == 1)
{
- // then we will need to use the byte-able register 'regNum'
- noway_assert((genRegMask(regNum) & RBM_BYTE_REGS) != 0);
-
- // Copy the register that contains fieldVarDsc into 'regNum'
- getEmitter()->emitIns_R_R(INS_mov, EA_4BYTE, regNum, fieldVarDsc->lvRegNum);
- regTracker.rsTrackRegLclVar(regNum, varNum);
-
- // tmpRegNum is the register that we will extract the byte value from
- tmpRegNum = regNum;
+ // Did we enregister the field in a non byte-able register?
+ if ((genRegMask(tmpRegNum) & RBM_BYTE_REGS) == 0)
+ {
+ // then we will need to use the byte-able register 'regNum'
+ noway_assert((genRegMask(regNum) & RBM_BYTE_REGS) != 0);
+
+ // Copy the register that contains fieldVarDsc into 'regNum'
+ getEmitter()->emitIns_R_R(INS_mov, EA_4BYTE, regNum,
+ fieldVarDsc->lvRegNum);
+ regTracker.rsTrackRegLclVar(regNum, varNum);
+
+ // tmpRegNum is the register that we will extract the byte value from
+ tmpRegNum = regNum;
+ }
+ noway_assert((genRegMask(tmpRegNum) & RBM_BYTE_REGS) != 0);
}
- noway_assert((genRegMask(tmpRegNum) & RBM_BYTE_REGS) != 0);
- }
-
- getEmitter()->emitIns_AR_R (ins_Store(fieldVarDsc->TypeGet()),
- (emitAttr)fieldVarDsc->lvExactSize,
- tmpRegNum,
- REG_SPBASE,
- fieldVarDsc->lvFldOffset);
- }
- else // not enregistered
- {
- // We will copy the non-enregister fieldVar into our scratch register 'regNum'
-
- noway_assert(regNum != REG_STK);
- getEmitter()->emitIns_R_S (ins_Load(fieldVarDsc->TypeGet()),
- (emitAttr)fieldVarDsc->lvExactSize,
- regNum,
- varNum,
- 0);
-
- regTracker.rsTrackRegLclVar(regNum, varNum);
-
- // Store the value (byte or short) into the stack
-
- getEmitter()->emitIns_AR_R (ins_Store(fieldVarDsc->TypeGet()),
- (emitAttr)fieldVarDsc->lvExactSize,
- regNum,
- REG_SPBASE,
- fieldVarDsc->lvFldOffset);
- }
- }
- }
- genUpdateLife(structLocalTree);
- break;
- }
+ getEmitter()->emitIns_AR_R(ins_Store(fieldVarDsc->TypeGet()),
+ (emitAttr)fieldVarDsc->lvExactSize, tmpRegNum,
+ REG_SPBASE, fieldVarDsc->lvFldOffset);
+ }
+ else // not enregistered
+ {
+ // We will copy the non-enregister fieldVar into our scratch register 'regNum'
- }
+ noway_assert(regNum != REG_STK);
+ getEmitter()->emitIns_R_S(ins_Load(fieldVarDsc->TypeGet()),
+ (emitAttr)fieldVarDsc->lvExactSize, regNum, varNum,
+ 0);
- genCodeForTree(arg->gtObj.gtOp1, 0);
- noway_assert(arg->gtObj.gtOp1->gtFlags & GTF_REG_VAL);
- regNumber reg = arg->gtObj.gtOp1->gtRegNum;
- // Get the number of DWORDS to copy to the stack
- opsz = roundUp(compiler->info.compCompHnd->getClassSize(arg->gtObj.gtClass), sizeof(void*));
- unsigned slots = (unsigned)(opsz / sizeof(void*));
+ regTracker.rsTrackRegLclVar(regNum, varNum);
- BYTE* gcLayout = new (compiler, CMK_Codegen) BYTE[slots];
+ // Store the value (byte or short) into the stack
- compiler->info.compCompHnd->getClassGClayout(arg->gtObj.gtClass, gcLayout);
+ getEmitter()->emitIns_AR_R(ins_Store(fieldVarDsc->TypeGet()),
+ (emitAttr)fieldVarDsc->lvExactSize, regNum,
+ REG_SPBASE, fieldVarDsc->lvFldOffset);
+ }
+ }
+ }
+ genUpdateLife(structLocalTree);
- BOOL bNoneGC = TRUE;
- for (int i = slots - 1; i >= 0; --i)
- {
- if (gcLayout[i] != TYPE_GC_NONE)
- {
- bNoneGC = FALSE;
- break;
+ break;
+ }
}
- }
- /* passing large structures using movq instead of pushes does not increase codesize very much */
- unsigned movqLenMin = 8;
- unsigned movqLenMax = 64;
- unsigned curBBweight = compiler->compCurBB->getBBWeight(compiler);
+ genCodeForTree(arg->gtObj.gtOp1, 0);
+ noway_assert(arg->gtObj.gtOp1->gtFlags & GTF_REG_VAL);
+ regNumber reg = arg->gtObj.gtOp1->gtRegNum;
+ // Get the number of DWORDS to copy to the stack
+ opsz = roundUp(compiler->info.compCompHnd->getClassSize(arg->gtObj.gtClass), sizeof(void*));
+ unsigned slots = (unsigned)(opsz / sizeof(void*));
- if ((compiler->compCodeOpt() == Compiler::SMALL_CODE) || (curBBweight == BB_ZERO_WEIGHT))
- {
- // Don't bother with this optimization in
- // rarely run blocks or when optimizing for size
- movqLenMax = movqLenMin = 0;
- }
- else if (compiler->compCodeOpt() == Compiler::FAST_CODE)
- {
- // Be more aggressive when optimizing for speed
- movqLenMax *= 2;
- }
+ BYTE* gcLayout = new (compiler, CMK_Codegen) BYTE[slots];
- /* Adjust for BB weight */
- if (curBBweight >= (BB_LOOP_WEIGHT*BB_UNITY_WEIGHT)/2)
- {
- // Be more aggressive when we are inside a loop
- movqLenMax *= 2;
- }
+ compiler->info.compCompHnd->getClassGClayout(arg->gtObj.gtClass, gcLayout);
- if (compiler->opts.compCanUseSSE2 && bNoneGC &&
- (opsz >= movqLenMin) && (opsz <= movqLenMax))
- {
- JITLOG_THIS(compiler, (LL_INFO10000, "Using XMM instructions to pass %3d byte valuetype while compiling %s\n",
- opsz, compiler->info.compFullName));
+ BOOL bNoneGC = TRUE;
+ for (int i = slots - 1; i >= 0; --i)
+ {
+ if (gcLayout[i] != TYPE_GC_NONE)
+ {
+ bNoneGC = FALSE;
+ break;
+ }
+ }
- int stkDisp = (int)(unsigned)opsz;
- int curDisp = 0;
- regNumber xmmReg = REG_XMM0;
+ /* passing large structures using movq instead of pushes does not increase codesize very much */
+ unsigned movqLenMin = 8;
+ unsigned movqLenMax = 64;
+ unsigned curBBweight = compiler->compCurBB->getBBWeight(compiler);
- if (opsz & 0x4)
+ if ((compiler->compCodeOpt() == Compiler::SMALL_CODE) || (curBBweight == BB_ZERO_WEIGHT))
{
- stkDisp -= sizeof(void*);
- getEmitter()->emitIns_AR_R(INS_push, EA_4BYTE, REG_NA, reg, stkDisp);
- genSinglePush();
+ // Don't bother with this optimization in
+ // rarely run blocks or when optimizing for size
+ movqLenMax = movqLenMin = 0;
+ }
+ else if (compiler->compCodeOpt() == Compiler::FAST_CODE)
+ {
+ // Be more aggressive when optimizing for speed
+ movqLenMax *= 2;
}
- inst_RV_IV(INS_sub, REG_SPBASE, stkDisp, EA_PTRSIZE);
- genStackLevel += stkDisp;
-
- while (curDisp < stkDisp)
+ /* Adjust for BB weight */
+ if (curBBweight >= (BB_LOOP_WEIGHT * BB_UNITY_WEIGHT) / 2)
{
- getEmitter()->emitIns_R_AR(INS_movq, EA_8BYTE, xmmReg, reg, curDisp);
- getEmitter()->emitIns_AR_R(INS_movq, EA_8BYTE, xmmReg, REG_SPBASE, curDisp);
- curDisp += 2 * sizeof(void*);
+ // Be more aggressive when we are inside a loop
+ movqLenMax *= 2;
}
- noway_assert(curDisp == stkDisp);
- }
- else
- {
- for (int i = slots-1; i >= 0; --i)
+
+ if (compiler->opts.compCanUseSSE2 && bNoneGC && (opsz >= movqLenMin) && (opsz <= movqLenMax))
{
- emitAttr fieldSize;
- if (gcLayout[i] == TYPE_GC_NONE)
- fieldSize = EA_4BYTE;
- else if (gcLayout[i] == TYPE_GC_REF)
- fieldSize = EA_GCREF;
- else
+ JITLOG_THIS(compiler, (LL_INFO10000,
+ "Using XMM instructions to pass %3d byte valuetype while compiling %s\n",
+ opsz, compiler->info.compFullName));
+
+ int stkDisp = (int)(unsigned)opsz;
+ int curDisp = 0;
+ regNumber xmmReg = REG_XMM0;
+
+ if (opsz & 0x4)
{
- noway_assert(gcLayout[i] == TYPE_GC_BYREF);
- fieldSize = EA_BYREF;
+ stkDisp -= sizeof(void*);
+ getEmitter()->emitIns_AR_R(INS_push, EA_4BYTE, REG_NA, reg, stkDisp);
+ genSinglePush();
+ }
+
+ inst_RV_IV(INS_sub, REG_SPBASE, stkDisp, EA_PTRSIZE);
+ genStackLevel += stkDisp;
+
+ while (curDisp < stkDisp)
+ {
+ getEmitter()->emitIns_R_AR(INS_movq, EA_8BYTE, xmmReg, reg, curDisp);
+ getEmitter()->emitIns_AR_R(INS_movq, EA_8BYTE, xmmReg, REG_SPBASE, curDisp);
+ curDisp += 2 * sizeof(void*);
+ }
+ noway_assert(curDisp == stkDisp);
+ }
+ else
+ {
+ for (int i = slots - 1; i >= 0; --i)
+ {
+ emitAttr fieldSize;
+ if (gcLayout[i] == TYPE_GC_NONE)
+ fieldSize = EA_4BYTE;
+ else if (gcLayout[i] == TYPE_GC_REF)
+ fieldSize = EA_GCREF;
+ else
+ {
+ noway_assert(gcLayout[i] == TYPE_GC_BYREF);
+ fieldSize = EA_BYREF;
+ }
+ getEmitter()->emitIns_AR_R(INS_push, fieldSize, REG_NA, reg, i * sizeof(void*));
+ genSinglePush();
}
- getEmitter()->emitIns_AR_R(INS_push, fieldSize, REG_NA, reg, i*sizeof(void*));
- genSinglePush();
}
+ gcInfo.gcMarkRegSetNpt(genRegMask(reg)); // Kill the pointer in op1
}
- gcInfo.gcMarkRegSetNpt(genRegMask(reg)); // Kill the pointer in op1
+
+ addrReg = 0;
+ break;
}
-
- addrReg = 0;
- break;
- }
- default:
- noway_assert(!"unhandled/unexpected arg type");
- NO_WAY("unhandled/unexpected arg type");
+ default:
+ noway_assert(!"unhandled/unexpected arg type");
+ NO_WAY("unhandled/unexpected arg type");
}
/* Update the current set of live variables */
@@ -16901,7 +16603,7 @@ size_t CodeGen::genPushArgList(GenTreePtr call)
/* Update the current set of register pointers */
- noway_assert(addrReg != DUMMY_INIT(RBM_CORRUPT));
+ noway_assert(addrReg != DUMMY_INIT(RBM_CORRUPT));
genDoneAddressable(curr, addrReg, RegSet::FREE_REG);
/* Remember how much stuff we've pushed on the stack */
@@ -16910,7 +16612,6 @@ size_t CodeGen::genPushArgList(GenTreePtr call)
/* Update the current argument stack offset */
-
/* Continue with the next argument, if any more are present */
} // while args
@@ -16920,8 +16621,8 @@ size_t CodeGen::genPushArgList(GenTreePtr call)
for (args = regArgs; args; args = args->Rest())
{
curr = args->Current();
-
- assert(!curr->IsArgPlaceHolderNode()); // No place holders nodes are in the late args
+
+ assert(!curr->IsArgPlaceHolderNode()); // No place holders nodes are in the late args
fgArgTabEntryPtr curArgTabEntry = compiler->gtArgEntryByNode(call, curr);
assert(curArgTabEntry);
@@ -16932,21 +16633,17 @@ size_t CodeGen::genPushArgList(GenTreePtr call)
/* Evaluate the argument to a register [pair] */
- if (genTypeSize(genActualType(curr->TypeGet())) == sizeof(int))
+ if (genTypeSize(genActualType(curr->TypeGet())) == sizeof(int))
{
/* Check if this is the guess area for the resolve interface call
* Pass a size of EA_OFFSET*/
- if (curr->gtOper == GT_CLS_VAR && compiler->eeGetJitDataOffs(curr->gtClsVar.gtClsVarHnd) >= 0)
+ if (curr->gtOper == GT_CLS_VAR && compiler->eeGetJitDataOffs(curr->gtClsVar.gtClsVarHnd) >= 0)
{
- getEmitter()->emitIns_R_C(ins_Load(TYP_INT),
- EA_OFFSET,
- regNum,
- curr->gtClsVar.gtClsVarHnd,
- 0);
+ getEmitter()->emitIns_R_C(ins_Load(TYP_INT), EA_OFFSET, regNum, curr->gtClsVar.gtClsVarHnd, 0);
regTracker.rsTrackRegTrash(regNum);
-
+
/* The value is now in the appropriate register */
-
+
genMarkTreeInReg(curr, regNum);
}
else
@@ -16959,15 +16656,15 @@ size_t CodeGen::genPushArgList(GenTreePtr call)
/* If the register is already marked as used, it will become
multi-used. However, since it is a callee-trashed register,
we will have to spill it before the call anyway. So do it now */
-
+
if (regSet.rsMaskUsed & genRegMask(regNum))
{
noway_assert(genRegMask(regNum) & RBM_CALLEE_TRASH);
regSet.rsSpillReg(regNum);
}
-
+
/* Mark the register as 'used' */
-
+
regSet.rsMarkRegUsed(curr);
}
else
@@ -16980,12 +16677,12 @@ size_t CodeGen::genPushArgList(GenTreePtr call)
for (args = regArgs; args; args = args->Rest())
{
- curr = args->Current();
+ curr = args->Current();
assert(curr);
if (curr->gtFlags & GTF_SPILLED)
{
- if (isRegPairType(curr->gtType))
+ if (isRegPairType(curr->gtType))
{
regSet.rsUnspillRegPair(curr, genRegPairMask(curr->gtRegPair), RegSet::KEEP_REG);
}
@@ -17004,25 +16701,25 @@ size_t CodeGen::genPushArgList(GenTreePtr call)
#pragma warning(pop)
#endif
-#else // FEATURE_FIXED_OUT_ARGS
+#else // FEATURE_FIXED_OUT_ARGS
//
// ARM and AMD64 uses this method to pass the stack based args
//
// returns size pushed (always zero)
-size_t CodeGen::genPushArgList(GenTreePtr call)
+size_t CodeGen::genPushArgList(GenTreePtr call)
{
-
- GenTreeArgList* lateArgs = call->gtCall.gtCallLateArgs;
- GenTreePtr curr;
- var_types type;
- int argSize;
+
+ GenTreeArgList* lateArgs = call->gtCall.gtCallLateArgs;
+ GenTreePtr curr;
+ var_types type;
+ int argSize;
GenTreeArgList* args;
// Create a local, artificial GenTreeArgList that includes the gtCallObjp, if that exists, as first argument,
// so we can iterate over this argument list more uniformly.
// Need to provide a temporary non-null first argument here: if we use this, we'll replace it.
- GenTreeArgList objpArgList(/*temp dummy arg*/call, call->gtCall.gtCallArgs);
+ GenTreeArgList objpArgList(/*temp dummy arg*/ call, call->gtCall.gtCallArgs);
if (call->gtCall.gtCallObjp == NULL)
{
args = call->gtCall.gtCallArgs;
@@ -17030,7 +16727,7 @@ size_t CodeGen::genPushArgList(GenTreePtr call)
else
{
objpArgList.Current() = call->gtCall.gtCallObjp;
- args = &objpArgList;
+ args = &objpArgList;
}
for (; args; args = args->Rest())
@@ -17050,7 +16747,7 @@ size_t CodeGen::genPushArgList(GenTreePtr call)
// that go dead after this use of the variable in the argument list.
regMaskTP deadFieldVarRegs = RBM_NONE;
- argSize = TARGET_POINTER_SIZE; // The default size for an arg is one pointer-sized item
+ argSize = TARGET_POINTER_SIZE; // The default size for an arg is one pointer-sized item
if (curr->IsArgPlaceHolderNode())
{
@@ -17067,375 +16764,365 @@ size_t CodeGen::genPushArgList(GenTreePtr call)
switch (type)
{
- case TYP_DOUBLE:
- case TYP_LONG:
+ case TYP_DOUBLE:
+ case TYP_LONG:
#if defined(_TARGET_ARM_)
- argSize = (TARGET_POINTER_SIZE * 2);
+ argSize = (TARGET_POINTER_SIZE * 2);
- /* Is the value a constant? */
+ /* Is the value a constant? */
- if (curr->gtOper == GT_CNS_LNG)
- {
- assert((curr->gtFlags & GTF_LATE_ARG) == 0);
-
- int hiVal = (int) (curr->gtLngCon.gtLconVal >> 32);
- int loVal = (int) (curr->gtLngCon.gtLconVal & 0xffffffff);
+ if (curr->gtOper == GT_CNS_LNG)
+ {
+ assert((curr->gtFlags & GTF_LATE_ARG) == 0);
- instGen_Store_Imm_Into_Lcl(TYP_INT, EA_4BYTE, loVal,
- compiler->lvaOutgoingArgSpaceVar, argOffset);
+ int hiVal = (int)(curr->gtLngCon.gtLconVal >> 32);
+ int loVal = (int)(curr->gtLngCon.gtLconVal & 0xffffffff);
- instGen_Store_Imm_Into_Lcl(TYP_INT, EA_4BYTE, hiVal,
- compiler->lvaOutgoingArgSpaceVar, argOffset + 4);
+ instGen_Store_Imm_Into_Lcl(TYP_INT, EA_4BYTE, loVal, compiler->lvaOutgoingArgSpaceVar, argOffset);
- break;
- }
- else
- {
- genCodeForTree(curr, 0);
+ instGen_Store_Imm_Into_Lcl(TYP_INT, EA_4BYTE, hiVal, compiler->lvaOutgoingArgSpaceVar,
+ argOffset + 4);
- if (curr->gtFlags & GTF_LATE_ARG)
- {
- // The arg was assigned into a temp and
- // will be moved to the correct register or slot later
-
- argSize = 0; // nothing is passed on the stack
+ break;
}
else
{
- // The arg is passed in the outgoing argument area of the stack frame
- //
- assert(curr->gtOper != GT_ASG); // GTF_LATE_ARG should be set if this is the case
- assert(curr->gtFlags & GTF_REG_VAL); // should be enregistered after genCodeForTree(curr, 0)
+ genCodeForTree(curr, 0);
- if (type == TYP_LONG)
+ if (curr->gtFlags & GTF_LATE_ARG)
{
- regNumber regLo = genRegPairLo(curr->gtRegPair);
- regNumber regHi = genRegPairHi(curr->gtRegPair);
+ // The arg was assigned into a temp and
+ // will be moved to the correct register or slot later
- assert(regLo != REG_STK);
- inst_SA_RV(ins_Store(TYP_INT), argOffset, regLo, TYP_INT);
- if (regHi == REG_STK)
- {
- regHi = regSet.rsPickFreeReg();
- inst_RV_TT(ins_Load(TYP_INT), regHi, curr, 4);
- regTracker.rsTrackRegTrash(regHi);
- }
- inst_SA_RV(ins_Store(TYP_INT), argOffset+4, regHi, TYP_INT);
+ argSize = 0; // nothing is passed on the stack
}
- else // (type == TYP_DOUBLE)
+ else
{
- inst_SA_RV(ins_Store(type), argOffset, curr->gtRegNum, type);
+ // The arg is passed in the outgoing argument area of the stack frame
+ //
+ assert(curr->gtOper != GT_ASG); // GTF_LATE_ARG should be set if this is the case
+ assert(curr->gtFlags & GTF_REG_VAL); // should be enregistered after genCodeForTree(curr, 0)
+
+ if (type == TYP_LONG)
+ {
+ regNumber regLo = genRegPairLo(curr->gtRegPair);
+ regNumber regHi = genRegPairHi(curr->gtRegPair);
+
+ assert(regLo != REG_STK);
+ inst_SA_RV(ins_Store(TYP_INT), argOffset, regLo, TYP_INT);
+ if (regHi == REG_STK)
+ {
+ regHi = regSet.rsPickFreeReg();
+ inst_RV_TT(ins_Load(TYP_INT), regHi, curr, 4);
+ regTracker.rsTrackRegTrash(regHi);
+ }
+ inst_SA_RV(ins_Store(TYP_INT), argOffset + 4, regHi, TYP_INT);
+ }
+ else // (type == TYP_DOUBLE)
+ {
+ inst_SA_RV(ins_Store(type), argOffset, curr->gtRegNum, type);
+ }
}
}
- }
- break;
+ break;
#elif defined(_TARGET_64BIT_)
- __fallthrough;
+ __fallthrough;
#else
-#error "Unknown target for passing TYP_LONG argument using FIXED_ARGS"
+#error "Unknown target for passing TYP_LONG argument using FIXED_ARGS"
#endif
- case TYP_REF:
- case TYP_BYREF:
+ case TYP_REF:
+ case TYP_BYREF:
- case TYP_FLOAT:
- case TYP_INT:
- /* Is the value a constant? */
+ case TYP_FLOAT:
+ case TYP_INT:
+ /* Is the value a constant? */
- if (curr->gtOper == GT_CNS_INT)
- {
- assert(!(curr->gtFlags & GTF_LATE_ARG));
+ if (curr->gtOper == GT_CNS_INT)
+ {
+ assert(!(curr->gtFlags & GTF_LATE_ARG));
-#if REDUNDANT_LOAD
- regNumber reg = regTracker.rsIconIsInReg(curr->gtIntCon.gtIconVal);
+#if REDUNDANT_LOAD
+ regNumber reg = regTracker.rsIconIsInReg(curr->gtIntCon.gtIconVal);
- if (reg != REG_NA)
- {
- inst_SA_RV(ins_Store(type), argOffset, reg, type);
- }
- else
+ if (reg != REG_NA)
+ {
+ inst_SA_RV(ins_Store(type), argOffset, reg, type);
+ }
+ else
#endif
- {
- bool needReloc = compiler->opts.compReloc && curr->IsIconHandle();
- emitAttr attr = needReloc ? EA_HANDLE_CNS_RELOC : emitTypeSize(type);
- instGen_Store_Imm_Into_Lcl(type, attr, curr->gtIntCon.gtIconVal,
- compiler->lvaOutgoingArgSpaceVar, argOffset);
+ {
+ bool needReloc = compiler->opts.compReloc && curr->IsIconHandle();
+ emitAttr attr = needReloc ? EA_HANDLE_CNS_RELOC : emitTypeSize(type);
+ instGen_Store_Imm_Into_Lcl(type, attr, curr->gtIntCon.gtIconVal,
+ compiler->lvaOutgoingArgSpaceVar, argOffset);
+ }
+ break;
}
- break;
- }
- /* This is passed as a pointer-sized integer argument */
+ /* This is passed as a pointer-sized integer argument */
- genCodeForTree(curr, 0);
-
- // The arg has been evaluated now, but will be put in a register or pushed on the stack later.
- if (curr->gtFlags & GTF_LATE_ARG)
- {
+ genCodeForTree(curr, 0);
+
+ // The arg has been evaluated now, but will be put in a register or pushed on the stack later.
+ if (curr->gtFlags & GTF_LATE_ARG)
+ {
#ifdef _TARGET_ARM_
- argSize = 0; // nothing is passed on the stack
+ argSize = 0; // nothing is passed on the stack
#endif
- }
- else
- {
- // The arg is passed in the outgoing argument area of the stack frame
-
- assert(curr->gtOper != GT_ASG); // GTF_LATE_ARG should be set if this is the case
- assert(curr->gtFlags & GTF_REG_VAL); // should be enregistered after genCodeForTree(curr, 0)
- inst_SA_RV(ins_Store(type), argOffset, curr->gtRegNum, type);
-
- if ((genRegMask(curr->gtRegNum) & regSet.rsMaskUsed) == 0)
- gcInfo.gcMarkRegSetNpt(genRegMask(curr->gtRegNum));
- }
- break;
+ }
+ else
+ {
+ // The arg is passed in the outgoing argument area of the stack frame
- case TYP_VOID:
- /* Is this a nothing node, deferred register argument? */
+ assert(curr->gtOper != GT_ASG); // GTF_LATE_ARG should be set if this is the case
+ assert(curr->gtFlags & GTF_REG_VAL); // should be enregistered after genCodeForTree(curr, 0)
+ inst_SA_RV(ins_Store(type), argOffset, curr->gtRegNum, type);
- if (curr->gtFlags & GTF_LATE_ARG)
- {
- /* Handle side-effects */
-DEFERRED:
- if (curr->OperIsCopyBlkOp() || curr->OperGet() == GT_COMMA)
+ if ((genRegMask(curr->gtRegNum) & regSet.rsMaskUsed) == 0)
+ gcInfo.gcMarkRegSetNpt(genRegMask(curr->gtRegNum));
+ }
+ break;
+
+ case TYP_VOID:
+ /* Is this a nothing node, deferred register argument? */
+
+ if (curr->gtFlags & GTF_LATE_ARG)
{
-#ifdef _TARGET_ARM_
+ /* Handle side-effects */
+ DEFERRED:
+ if (curr->OperIsCopyBlkOp() || curr->OperGet() == GT_COMMA)
{
- GenTreePtr curArgNode = curArgTabEntry->node;
- var_types curRegArgType = curArgNode->gtType;
- assert(curRegArgType != TYP_UNDEF);
-
- if (curRegArgType == TYP_STRUCT)
+#ifdef _TARGET_ARM_
{
- // If the RHS of the COPYBLK is a promoted struct local, then the use of that
- // is an implicit use of all its field vars. If these are last uses, remember that,
- // so we can later update the GC compiler->info.
- if (curr->OperIsCopyBlkOp())
- deadFieldVarRegs |= genFindDeadFieldRegs(curr);
+ GenTreePtr curArgNode = curArgTabEntry->node;
+ var_types curRegArgType = curArgNode->gtType;
+ assert(curRegArgType != TYP_UNDEF);
+
+ if (curRegArgType == TYP_STRUCT)
+ {
+ // If the RHS of the COPYBLK is a promoted struct local, then the use of that
+ // is an implicit use of all its field vars. If these are last uses, remember that,
+ // so we can later update the GC compiler->info.
+ if (curr->OperIsCopyBlkOp())
+ deadFieldVarRegs |= genFindDeadFieldRegs(curr);
+ }
}
- }
#endif // _TARGET_ARM_
- genCodeForTree(curr, 0);
- }
- else
- {
- assert(curr->IsArgPlaceHolderNode() || curr->IsNothingNode());
- }
+ genCodeForTree(curr, 0);
+ }
+ else
+ {
+ assert(curr->IsArgPlaceHolderNode() || curr->IsNothingNode());
+ }
#if defined(_TARGET_ARM_)
- argSize = curArgTabEntry->numSlots * TARGET_POINTER_SIZE;
+ argSize = curArgTabEntry->numSlots * TARGET_POINTER_SIZE;
#endif
- }
- else
- {
- for (GenTree* arg = curr; arg->gtOper == GT_COMMA; arg = arg->gtOp.gtOp2)
+ }
+ else
{
- GenTreePtr op1 = arg->gtOp.gtOp1;
+ for (GenTree* arg = curr; arg->gtOper == GT_COMMA; arg = arg->gtOp.gtOp2)
+ {
+ GenTreePtr op1 = arg->gtOp.gtOp1;
- genEvalSideEffects(op1);
- genUpdateLife(op1);
+ genEvalSideEffects(op1);
+ genUpdateLife(op1);
+ }
}
- }
- break;
+ break;
#ifdef _TARGET_ARM_
- case TYP_STRUCT:
- {
- GenTree* arg = curr;
- while (arg->gtOper == GT_COMMA)
+ case TYP_STRUCT:
{
- GenTreePtr op1 = arg->gtOp.gtOp1;
- genEvalSideEffects(op1);
- genUpdateLife(op1);
- arg = arg->gtOp.gtOp2;
- }
- noway_assert((arg->OperGet() == GT_OBJ) || (arg->OperGet() == GT_MKREFANY));
-
- CORINFO_CLASS_HANDLE clsHnd;
- unsigned argAlign;
- unsigned slots;
- BYTE* gcLayout = NULL;
+ GenTree* arg = curr;
+ while (arg->gtOper == GT_COMMA)
+ {
+ GenTreePtr op1 = arg->gtOp.gtOp1;
+ genEvalSideEffects(op1);
+ genUpdateLife(op1);
+ arg = arg->gtOp.gtOp2;
+ }
+ noway_assert((arg->OperGet() == GT_OBJ) || (arg->OperGet() == GT_MKREFANY));
+
+ CORINFO_CLASS_HANDLE clsHnd;
+ unsigned argAlign;
+ unsigned slots;
+ BYTE* gcLayout = NULL;
+
+ // If the struct being passed is a OBJ of a local struct variable that is promoted (in the
+ // INDEPENDENT fashion, which doesn't require writes to be written through to the variable's
+ // home stack loc) "promotedStructLocalVarDesc" will be set to point to the local variable
+ // table entry for the promoted struct local. As we fill slots with the contents of a
+ // promoted struct, "bytesOfNextSlotOfCurPromotedStruct" will be the number of filled bytes
+ // that indicate another filled slot, and "nextPromotedStructFieldVar" will be the local
+ // variable number of the next field variable to be copied.
+ LclVarDsc* promotedStructLocalVarDesc = NULL;
+ GenTreePtr structLocalTree = NULL;
+ unsigned bytesOfNextSlotOfCurPromotedStruct = TARGET_POINTER_SIZE; // Size of slot.
+ unsigned nextPromotedStructFieldVar = BAD_VAR_NUM;
+ unsigned promotedStructOffsetOfFirstStackSlot = 0;
+ unsigned argOffsetOfFirstStackSlot = UINT32_MAX; // Indicates uninitialized.
+
+ if (arg->OperGet() == GT_OBJ)
+ {
+ clsHnd = arg->gtObj.gtClass;
+ unsigned originalSize = compiler->info.compCompHnd->getClassSize(clsHnd);
+ argAlign =
+ roundUp(compiler->info.compCompHnd->getClassAlignmentRequirement(clsHnd), TARGET_POINTER_SIZE);
+ argSize = (unsigned)(roundUp(originalSize, TARGET_POINTER_SIZE));
- // If the struct being passed is a OBJ of a local struct variable that is promoted (in the
- // INDEPENDENT fashion, which doesn't require writes to be written through to the variable's
- // home stack loc) "promotedStructLocalVarDesc" will be set to point to the local variable
- // table entry for the promoted struct local. As we fill slots with the contents of a
- // promoted struct, "bytesOfNextSlotOfCurPromotedStruct" will be the number of filled bytes
- // that indicate another filled slot, and "nextPromotedStructFieldVar" will be the local
- // variable number of the next field variable to be copied.
- LclVarDsc* promotedStructLocalVarDesc = NULL;
- GenTreePtr structLocalTree = NULL;
- unsigned bytesOfNextSlotOfCurPromotedStruct = TARGET_POINTER_SIZE; // Size of slot.
- unsigned nextPromotedStructFieldVar = BAD_VAR_NUM;
- unsigned promotedStructOffsetOfFirstStackSlot = 0;
- unsigned argOffsetOfFirstStackSlot = UINT32_MAX; // Indicates uninitialized.
-
- if (arg->OperGet() == GT_OBJ)
- {
- clsHnd = arg->gtObj.gtClass;
- unsigned originalSize = compiler->info.compCompHnd->getClassSize(clsHnd);
- argAlign = roundUp(compiler->info.compCompHnd->getClassAlignmentRequirement(clsHnd), TARGET_POINTER_SIZE);
- argSize = (unsigned)(roundUp(originalSize, TARGET_POINTER_SIZE));
-
- slots = (unsigned)(argSize / TARGET_POINTER_SIZE);
-
- gcLayout = new (compiler, CMK_Codegen) BYTE[slots];
-
- compiler->info.compCompHnd->getClassGClayout(clsHnd, gcLayout);
+ slots = (unsigned)(argSize / TARGET_POINTER_SIZE);
- // Are we loading a promoted struct local var?
- if (arg->gtObj.gtOp1->gtOper == GT_ADDR &&
- arg->gtObj.gtOp1->gtOp.gtOp1->gtOper == GT_LCL_VAR)
- {
- structLocalTree = arg->gtObj.gtOp1->gtOp.gtOp1;
- unsigned structLclNum = structLocalTree->gtLclVarCommon.gtLclNum;
- LclVarDsc * varDsc = &compiler->lvaTable[structLclNum];
-
- // As much as we would like this to be a noway_assert, we can't because
- // there are some weird casts out there, and backwards compatiblity
- // dictates we do *NOT* start rejecting them now. lvaGetPromotion and
- // lvPromoted in general currently do not require the local to be
- // TYP_STRUCT, so this assert is really more about how we wish the world
- // was then some JIT invariant.
- assert((structLocalTree->TypeGet() == TYP_STRUCT) || compiler->compUnsafeCastUsed);
+ gcLayout = new (compiler, CMK_Codegen) BYTE[slots];
- Compiler::lvaPromotionType promotionType = compiler->lvaGetPromotionType(varDsc);
+ compiler->info.compCompHnd->getClassGClayout(clsHnd, gcLayout);
- if (varDsc->lvPromoted &&
- promotionType == Compiler::PROMOTION_TYPE_INDEPENDENT) // Otherwise it is guaranteed to live
- // on stack.
+ // Are we loading a promoted struct local var?
+ if (arg->gtObj.gtOp1->gtOper == GT_ADDR && arg->gtObj.gtOp1->gtOp.gtOp1->gtOper == GT_LCL_VAR)
{
- assert(!varDsc->lvAddrExposed); // Compiler::PROMOTION_TYPE_INDEPENDENT ==> not exposed.
- promotedStructLocalVarDesc = varDsc;
- nextPromotedStructFieldVar = promotedStructLocalVarDesc->lvFieldLclStart;
+ structLocalTree = arg->gtObj.gtOp1->gtOp.gtOp1;
+ unsigned structLclNum = structLocalTree->gtLclVarCommon.gtLclNum;
+ LclVarDsc* varDsc = &compiler->lvaTable[structLclNum];
+
+ // As much as we would like this to be a noway_assert, we can't because
+ // there are some weird casts out there, and backwards compatiblity
+ // dictates we do *NOT* start rejecting them now. lvaGetPromotion and
+ // lvPromoted in general currently do not require the local to be
+ // TYP_STRUCT, so this assert is really more about how we wish the world
+ // was then some JIT invariant.
+ assert((structLocalTree->TypeGet() == TYP_STRUCT) || compiler->compUnsafeCastUsed);
+
+ Compiler::lvaPromotionType promotionType = compiler->lvaGetPromotionType(varDsc);
+
+ if (varDsc->lvPromoted &&
+ promotionType == Compiler::PROMOTION_TYPE_INDEPENDENT) // Otherwise it is guaranteed to live
+ // on stack.
+ {
+ assert(!varDsc->lvAddrExposed); // Compiler::PROMOTION_TYPE_INDEPENDENT ==> not exposed.
+ promotedStructLocalVarDesc = varDsc;
+ nextPromotedStructFieldVar = promotedStructLocalVarDesc->lvFieldLclStart;
+ }
}
}
- }
- else
- {
- noway_assert(arg->OperGet() == GT_MKREFANY);
+ else
+ {
+ noway_assert(arg->OperGet() == GT_MKREFANY);
- clsHnd = NULL;
- argAlign = TARGET_POINTER_SIZE;
- argSize = 2*TARGET_POINTER_SIZE;
- slots = 2;
- }
-
- // Any TYP_STRUCT argument that is passed in registers must be moved over to the LateArg list
- noway_assert(regNum == REG_STK);
+ clsHnd = NULL;
+ argAlign = TARGET_POINTER_SIZE;
+ argSize = 2 * TARGET_POINTER_SIZE;
+ slots = 2;
+ }
- // This code passes a TYP_STRUCT by value using the outgoing arg space var
- //
- if (arg->OperGet() == GT_OBJ)
- {
- regNumber regSrc = REG_STK;
- regNumber regTmp = REG_STK; // This will get set below if the obj is not of a promoted struct local.
- int cStackSlots = 0;
+ // Any TYP_STRUCT argument that is passed in registers must be moved over to the LateArg list
+ noway_assert(regNum == REG_STK);
- if (promotedStructLocalVarDesc == NULL)
+ // This code passes a TYP_STRUCT by value using the outgoing arg space var
+ //
+ if (arg->OperGet() == GT_OBJ)
{
- genComputeReg(arg->gtObj.gtOp1, 0, RegSet::ANY_REG, RegSet::KEEP_REG);
- noway_assert(arg->gtObj.gtOp1->gtFlags & GTF_REG_VAL);
- regSrc = arg->gtObj.gtOp1->gtRegNum;
- }
-
- // The number of bytes to add "argOffset" to get the arg offset of the current slot.
- int extraArgOffset = 0;
+ regNumber regSrc = REG_STK;
+ regNumber regTmp = REG_STK; // This will get set below if the obj is not of a promoted struct local.
+ int cStackSlots = 0;
- for (unsigned i = 0; i < slots; i++)
- {
- emitAttr fieldSize;
- if (gcLayout[i] == TYPE_GC_NONE)
- fieldSize = EA_PTRSIZE;
- else if (gcLayout[i] == TYPE_GC_REF)
- fieldSize = EA_GCREF;
- else
+ if (promotedStructLocalVarDesc == NULL)
{
- noway_assert(gcLayout[i] == TYPE_GC_BYREF);
- fieldSize = EA_BYREF;
+ genComputeReg(arg->gtObj.gtOp1, 0, RegSet::ANY_REG, RegSet::KEEP_REG);
+ noway_assert(arg->gtObj.gtOp1->gtFlags & GTF_REG_VAL);
+ regSrc = arg->gtObj.gtOp1->gtRegNum;
}
-
- // Pass the argument using the lvaOutgoingArgSpaceVar
- if (promotedStructLocalVarDesc != NULL)
+ // The number of bytes to add "argOffset" to get the arg offset of the current slot.
+ int extraArgOffset = 0;
+
+ for (unsigned i = 0; i < slots; i++)
{
- if (argOffsetOfFirstStackSlot == UINT32_MAX) argOffsetOfFirstStackSlot = argOffset;
+ emitAttr fieldSize;
+ if (gcLayout[i] == TYPE_GC_NONE)
+ fieldSize = EA_PTRSIZE;
+ else if (gcLayout[i] == TYPE_GC_REF)
+ fieldSize = EA_GCREF;
+ else
+ {
+ noway_assert(gcLayout[i] == TYPE_GC_BYREF);
+ fieldSize = EA_BYREF;
+ }
- regNumber maxRegArg = regNumber(MAX_REG_ARG);
- bool filledExtraSlot =
- genFillSlotFromPromotedStruct(arg,
- curArgTabEntry,
- promotedStructLocalVarDesc,
- fieldSize,
- &nextPromotedStructFieldVar,
- &bytesOfNextSlotOfCurPromotedStruct,
- /*pCurRegNum*/ &maxRegArg,
- /*argOffset*/ argOffset + extraArgOffset,
- /*fieldOffsetOfFirstStackSlot*/ promotedStructOffsetOfFirstStackSlot,
- argOffsetOfFirstStackSlot,
- &deadFieldVarRegs,
- &regTmp);
- extraArgOffset += TARGET_POINTER_SIZE;
- // If we filled an extra slot with an 8-byte value, skip a slot.
- if (filledExtraSlot)
+ // Pass the argument using the lvaOutgoingArgSpaceVar
+
+ if (promotedStructLocalVarDesc != NULL)
{
- i++;
- cStackSlots++;
+ if (argOffsetOfFirstStackSlot == UINT32_MAX)
+ argOffsetOfFirstStackSlot = argOffset;
+
+ regNumber maxRegArg = regNumber(MAX_REG_ARG);
+ bool filledExtraSlot = genFillSlotFromPromotedStruct(
+ arg, curArgTabEntry, promotedStructLocalVarDesc, fieldSize, &nextPromotedStructFieldVar,
+ &bytesOfNextSlotOfCurPromotedStruct,
+ /*pCurRegNum*/ &maxRegArg,
+ /*argOffset*/ argOffset + extraArgOffset,
+ /*fieldOffsetOfFirstStackSlot*/ promotedStructOffsetOfFirstStackSlot,
+ argOffsetOfFirstStackSlot, &deadFieldVarRegs, &regTmp);
extraArgOffset += TARGET_POINTER_SIZE;
+ // If we filled an extra slot with an 8-byte value, skip a slot.
+ if (filledExtraSlot)
+ {
+ i++;
+ cStackSlots++;
+ extraArgOffset += TARGET_POINTER_SIZE;
+ }
}
- }
- else
- {
- if (regTmp == REG_STK)
+ else
{
- regTmp = regSet.rsPickFreeReg();
+ if (regTmp == REG_STK)
+ {
+ regTmp = regSet.rsPickFreeReg();
+ }
+
+ getEmitter()->emitIns_R_AR(ins_Load(TYP_I_IMPL), fieldSize, regTmp, regSrc,
+ i * TARGET_POINTER_SIZE);
+
+ getEmitter()->emitIns_S_R(ins_Store(TYP_I_IMPL), fieldSize, regTmp,
+ compiler->lvaOutgoingArgSpaceVar,
+ argOffset + cStackSlots * TARGET_POINTER_SIZE);
+ regTracker.rsTrackRegTrash(regTmp);
}
+ cStackSlots++;
+ }
- getEmitter()->emitIns_R_AR(ins_Load(TYP_I_IMPL),
- fieldSize,
- regTmp,
- regSrc,
- i*TARGET_POINTER_SIZE);
-
- getEmitter()->emitIns_S_R(ins_Store(TYP_I_IMPL),
- fieldSize,
- regTmp,
- compiler->lvaOutgoingArgSpaceVar,
- argOffset+cStackSlots*TARGET_POINTER_SIZE);
- regTracker.rsTrackRegTrash(regTmp);
- }
- cStackSlots++;
+ if (promotedStructLocalVarDesc == NULL)
+ {
+ regSet.rsMarkRegFree(genRegMask(regSrc));
+ }
+ if (structLocalTree != NULL)
+ genUpdateLife(structLocalTree);
}
-
- if (promotedStructLocalVarDesc == NULL)
+ else
{
- regSet.rsMarkRegFree(genRegMask(regSrc));
+ assert(arg->OperGet() == GT_MKREFANY);
+ PushMkRefAnyArg(arg, curArgTabEntry, RBM_ALLINT);
+ argSize = (curArgTabEntry->numSlots * TARGET_POINTER_SIZE);
}
- if (structLocalTree != NULL) genUpdateLife(structLocalTree);
}
- else
- {
- assert(arg->OperGet() == GT_MKREFANY);
- PushMkRefAnyArg(arg, curArgTabEntry, RBM_ALLINT);
- argSize = (curArgTabEntry->numSlots * TARGET_POINTER_SIZE);
- }
- }
- break;
+ break;
#endif // _TARGET_ARM_
- default:
- assert(!"unhandled/unexpected arg type");
- NO_WAY("unhandled/unexpected arg type");
+ default:
+ assert(!"unhandled/unexpected arg type");
+ NO_WAY("unhandled/unexpected arg type");
}
/* Update the current set of live variables */
genUpdateLife(curr);
- // Now, if some copied field locals were enregistered, and they're now dead, update the set of
+ // Now, if some copied field locals were enregistered, and they're now dead, update the set of
// register holding gc pointers.
if (deadFieldVarRegs != 0)
gcInfo.gcMarkRegSetNpt(deadFieldVarRegs);
@@ -17447,38 +17134,38 @@ DEFERRED:
/* Continue with the next argument, if any more are present */
} // while (args)
-
if (lateArgs)
{
SetupLateArgs(call);
}
-
+
/* Return the total size pushed */
-
+
return 0;
}
#ifdef _TARGET_ARM_
-bool CodeGen::genFillSlotFromPromotedStruct(GenTreePtr arg,
- fgArgTabEntryPtr curArgTabEntry,
- LclVarDsc* promotedStructLocalVarDesc,
- emitAttr fieldSize,
- unsigned* pNextPromotedStructFieldVar,
- unsigned* pBytesOfNextSlotOfCurPromotedStruct,
- regNumber* pCurRegNum,
- int argOffset,
- int fieldOffsetOfFirstStackSlot,
- int argOffsetOfFirstStackSlot,
- regMaskTP* deadFieldVarRegs,
- regNumber* pRegTmp)
+bool CodeGen::genFillSlotFromPromotedStruct(GenTreePtr arg,
+ fgArgTabEntryPtr curArgTabEntry,
+ LclVarDsc* promotedStructLocalVarDesc,
+ emitAttr fieldSize,
+ unsigned* pNextPromotedStructFieldVar,
+ unsigned* pBytesOfNextSlotOfCurPromotedStruct,
+ regNumber* pCurRegNum,
+ int argOffset,
+ int fieldOffsetOfFirstStackSlot,
+ int argOffsetOfFirstStackSlot,
+ regMaskTP* deadFieldVarRegs,
+ regNumber* pRegTmp)
{
unsigned nextPromotedStructFieldVar = *pNextPromotedStructFieldVar;
- unsigned limitPromotedStructFieldVar = promotedStructLocalVarDesc->lvFieldLclStart + promotedStructLocalVarDesc->lvFieldCnt;
+ unsigned limitPromotedStructFieldVar =
+ promotedStructLocalVarDesc->lvFieldLclStart + promotedStructLocalVarDesc->lvFieldCnt;
unsigned bytesOfNextSlotOfCurPromotedStruct = *pBytesOfNextSlotOfCurPromotedStruct;
- regNumber curRegNum = *pCurRegNum;
- regNumber regTmp = *pRegTmp;
- bool filledExtraSlot = false;
+ regNumber curRegNum = *pCurRegNum;
+ regNumber regTmp = *pRegTmp;
+ bool filledExtraSlot = false;
if (nextPromotedStructFieldVar == limitPromotedStructFieldVar)
{
@@ -17494,38 +17181,45 @@ bool CodeGen::genFillSlotFromPromotedStruct(GenTreePtr arg,
// Does this field fill an entire slot, and does it go at the start of the slot?
// If so, things are easier...
- bool oneFieldFillsSlotFromStart =
- (fieldVarDsc->lvFldOffset < bytesOfNextSlotOfCurPromotedStruct) // The field should start in the current slot...
- && ((fieldVarDsc->lvFldOffset % 4) == 0) // at the start of the slot, and...
- && (nextPromotedStructFieldVar+1 == limitPromotedStructFieldVar // next field, if there is one, goes in the next slot.
- || compiler->lvaTable[nextPromotedStructFieldVar+1].lvFldOffset >= bytesOfNextSlotOfCurPromotedStruct);
+ bool oneFieldFillsSlotFromStart =
+ (fieldVarDsc->lvFldOffset < bytesOfNextSlotOfCurPromotedStruct) // The field should start in the current slot...
+ && ((fieldVarDsc->lvFldOffset % 4) == 0) // at the start of the slot, and...
+ && (nextPromotedStructFieldVar + 1 ==
+ limitPromotedStructFieldVar // next field, if there is one, goes in the next slot.
+ || compiler->lvaTable[nextPromotedStructFieldVar + 1].lvFldOffset >= bytesOfNextSlotOfCurPromotedStruct);
// Compute the proper size.
- if (fieldSize == EA_4BYTE) // Not a GC ref or byref.
+ if (fieldSize == EA_4BYTE) // Not a GC ref or byref.
{
switch (fieldVarDsc->lvExactSize)
{
- case 1: fieldSize = EA_1BYTE; break;
- case 2: fieldSize = EA_2BYTE; break;
- case 8:
- // An 8-byte field will be at an 8-byte-aligned offset unless explicit layout has been used,
- // in which case we should not have promoted the struct variable.
- noway_assert((fieldVarDsc->lvFldOffset % 8) == 0);
-
- // If the current reg number is not aligned, align it, and return to the calling loop, which will
- // consider that a filled slot and move on to the next argument register.
- if (curRegNum != MAX_REG_ARG && ((curRegNum % 2) != 0))
- {
- // We must update the slot target, however!
- bytesOfNextSlotOfCurPromotedStruct += 4;
- *pBytesOfNextSlotOfCurPromotedStruct = bytesOfNextSlotOfCurPromotedStruct;
- return false;
- }
- // Dest is an aligned pair of arg regs, if the struct type demands it.
- noway_assert((curRegNum % 2) == 0);
- // We leave the fieldSize as EA_4BYTE; but we must do 2 reg moves.
- break;
- default: assert(fieldVarDsc->lvExactSize == 4); break;
+ case 1:
+ fieldSize = EA_1BYTE;
+ break;
+ case 2:
+ fieldSize = EA_2BYTE;
+ break;
+ case 8:
+ // An 8-byte field will be at an 8-byte-aligned offset unless explicit layout has been used,
+ // in which case we should not have promoted the struct variable.
+ noway_assert((fieldVarDsc->lvFldOffset % 8) == 0);
+
+ // If the current reg number is not aligned, align it, and return to the calling loop, which will
+ // consider that a filled slot and move on to the next argument register.
+ if (curRegNum != MAX_REG_ARG && ((curRegNum % 2) != 0))
+ {
+ // We must update the slot target, however!
+ bytesOfNextSlotOfCurPromotedStruct += 4;
+ *pBytesOfNextSlotOfCurPromotedStruct = bytesOfNextSlotOfCurPromotedStruct;
+ return false;
+ }
+ // Dest is an aligned pair of arg regs, if the struct type demands it.
+ noway_assert((curRegNum % 2) == 0);
+ // We leave the fieldSize as EA_4BYTE; but we must do 2 reg moves.
+ break;
+ default:
+ assert(fieldVarDsc->lvExactSize == 4);
+ break;
}
}
else
@@ -17540,8 +17234,7 @@ bool CodeGen::genFillSlotFromPromotedStruct(GenTreePtr arg,
// however if it is in memory we can use an integer type TYP_I_IMPL
//
var_types fieldTypeForInstr = var_types(fieldVarDsc->lvType);
- if ((fieldVarDsc->lvType == TYP_LONG) ||
- (!fieldVarDsc->lvRegister && varTypeIsFloating(fieldTypeForInstr)))
+ if ((fieldVarDsc->lvType == TYP_LONG) || (!fieldVarDsc->lvRegister && varTypeIsFloating(fieldTypeForInstr)))
{
fieldTypeForInstr = TYP_I_IMPL;
}
@@ -17567,10 +17260,8 @@ bool CodeGen::genFillSlotFromPromotedStruct(GenTreePtr arg,
{
// Move the field var living in stack to dst.
getEmitter()->emitIns_R_S(ins_Load(fieldVarDsc->TypeGet()),
- fieldVarDsc->TypeGet() == TYP_DOUBLE ? EA_8BYTE : EA_4BYTE,
- curRegNum,
- nextPromotedStructFieldVar,
- 0);
+ fieldVarDsc->TypeGet() == TYP_DOUBLE ? EA_8BYTE : EA_4BYTE, curRegNum,
+ nextPromotedStructFieldVar, 0);
assert(genIsValidFloatReg(curRegNum)); // we don't use register tracking for FP
}
@@ -17582,7 +17273,7 @@ bool CodeGen::genFillSlotFromPromotedStruct(GenTreePtr arg,
if (fieldVarDsc->TypeGet() == TYP_DOUBLE)
{
bytesOfNextSlotOfCurPromotedStruct += 4;
- curRegNum = REG_NEXT(curRegNum);
+ curRegNum = REG_NEXT(curRegNum);
arg->gtRegNum = curRegNum;
regSet.SetUsedRegFloat(arg, true);
filledExtraSlot = true;
@@ -17614,18 +17305,18 @@ bool CodeGen::genFillSlotFromPromotedStruct(GenTreePtr arg,
{
// Source is register and Dest is register.
- instruction insCopy = INS_mov;
+ instruction insCopy = INS_mov;
if (varTypeIsFloating(fieldTypeForInstr))
{
if (fieldTypeForInstr == TYP_FLOAT)
{
- insCopy = INS_vmov_f2i;
+ insCopy = INS_vmov_f2i;
}
else
{
assert(fieldTypeForInstr == TYP_DOUBLE);
- insCopy = INS_vmov_d2i;
+ insCopy = INS_vmov_d2i;
}
}
@@ -17644,10 +17335,7 @@ bool CodeGen::genFillSlotFromPromotedStruct(GenTreePtr arg,
regTmp = regSet.rsPickFreeReg();
}
// Copy the second register to the temp reg.
- getEmitter()->emitIns_R_R(INS_mov,
- fieldSize,
- regTmp,
- otherRegNum);
+ getEmitter()->emitIns_R_R(INS_mov, fieldSize, regTmp, otherRegNum);
regTracker.rsTrackRegCopy(regTmp, otherRegNum);
otherRegNum = regTmp;
}
@@ -17656,11 +17344,8 @@ bool CodeGen::genFillSlotFromPromotedStruct(GenTreePtr arg,
if (fieldVarDsc->lvType == TYP_DOUBLE)
{
assert(curRegNum <= REG_R2);
- getEmitter()->emitIns_R_R_R(insCopy,
- fieldSize,
- curRegNum,
- genRegArgNext(curRegNum),
- fieldVarDsc->lvRegNum);
+ getEmitter()->emitIns_R_R_R(insCopy, fieldSize, curRegNum, genRegArgNext(curRegNum),
+ fieldVarDsc->lvRegNum);
regTracker.rsTrackRegTrash(curRegNum);
regTracker.rsTrackRegTrash(genRegArgNext(curRegNum));
}
@@ -17670,10 +17355,7 @@ bool CodeGen::genFillSlotFromPromotedStruct(GenTreePtr arg,
// It might be the case that it's already in the desired register; if so do nothing.
if (curRegNum != fieldVarDsc->lvRegNum)
{
- getEmitter()->emitIns_R_R(insCopy,
- fieldSize,
- curRegNum,
- fieldVarDsc->lvRegNum);
+ getEmitter()->emitIns_R_R(insCopy, fieldSize, curRegNum, fieldVarDsc->lvRegNum);
regTracker.rsTrackRegCopy(curRegNum, fieldVarDsc->lvRegNum);
}
}
@@ -17682,7 +17364,7 @@ bool CodeGen::genFillSlotFromPromotedStruct(GenTreePtr arg,
regSet.rsMarkArgRegUsedByPromotedFieldArg(arg, curRegNum, EA_IS_GCREF(fieldSize));
// Is there a second half of the value?
- if (fieldVarDsc->lvExactSize == 8)
+ if (fieldVarDsc->lvExactSize == 8)
{
curRegNum = genRegArgNext(curRegNum);
// The second dest reg must also be an argument register.
@@ -17700,22 +17382,18 @@ bool CodeGen::genFillSlotFromPromotedStruct(GenTreePtr arg,
// Apparently when we partially enregister, we allocate stack space for the full
// 8 bytes, and enregister the low half. Thus the final TARGET_POINTER_SIZE offset
// parameter, to get the high half.
- getEmitter()->emitIns_R_S(ins_Load(fieldTypeForInstr),
- fieldSize,
- curRegNum,
- nextPromotedStructFieldVar, TARGET_POINTER_SIZE);
+ getEmitter()->emitIns_R_S(ins_Load(fieldTypeForInstr), fieldSize, curRegNum,
+ nextPromotedStructFieldVar, TARGET_POINTER_SIZE);
regTracker.rsTrackRegTrash(curRegNum);
}
else
{
// The other half is in a register.
- // Again, it might be the case that it's already in the desired register; if so do nothing.
+ // Again, it might be the case that it's already in the desired register; if so do
+ // nothing.
if (curRegNum != otherRegNum)
{
- getEmitter()->emitIns_R_R(INS_mov,
- fieldSize,
- curRegNum,
- otherRegNum);
+ getEmitter()->emitIns_R_R(INS_mov, fieldSize, curRegNum, otherRegNum);
regTracker.rsTrackRegCopy(curRegNum, otherRegNum);
}
}
@@ -17732,13 +17410,10 @@ bool CodeGen::genFillSlotFromPromotedStruct(GenTreePtr arg,
// Source is register and Dest is memory (OutgoingArgSpace).
// Now write the srcReg into the right location in the outgoing argument list.
- getEmitter()->emitIns_S_R(ins_Store(fieldTypeForInstr),
- fieldSize,
- fieldVarDsc->lvRegNum,
- compiler->lvaOutgoingArgSpaceVar,
- fieldArgOffset);
+ getEmitter()->emitIns_S_R(ins_Store(fieldTypeForInstr), fieldSize, fieldVarDsc->lvRegNum,
+ compiler->lvaOutgoingArgSpaceVar, fieldArgOffset);
- if (fieldVarDsc->lvExactSize == 8)
+ if (fieldVarDsc->lvExactSize == 8)
{
// Now, if it's an 8-byte TYP_LONG, we have to do the second 4 bytes.
if (fieldVarDsc->lvType == TYP_LONG)
@@ -17753,31 +17428,25 @@ bool CodeGen::genFillSlotFromPromotedStruct(GenTreePtr arg,
// Apparently if we partially enregister, we allocate stack space for the full
// 8 bytes, and enregister the low half. Thus the final TARGET_POINTER_SIZE offset
// parameter, to get the high half.
- getEmitter()->emitIns_R_S(ins_Load(fieldTypeForInstr),
- fieldSize,
- regTmp,
- nextPromotedStructFieldVar, TARGET_POINTER_SIZE);
+ getEmitter()->emitIns_R_S(ins_Load(fieldTypeForInstr), fieldSize, regTmp,
+ nextPromotedStructFieldVar, TARGET_POINTER_SIZE);
regTracker.rsTrackRegTrash(regTmp);
- getEmitter()->emitIns_S_R(ins_Store(TYP_I_IMPL),
- fieldSize,
- regTmp,
- compiler->lvaOutgoingArgSpaceVar,
- fieldArgOffset + TARGET_POINTER_SIZE);
+ getEmitter()->emitIns_S_R(ins_Store(TYP_I_IMPL), fieldSize, regTmp,
+ compiler->lvaOutgoingArgSpaceVar,
+ fieldArgOffset + TARGET_POINTER_SIZE);
}
else
{
- getEmitter()->emitIns_S_R(ins_Store(TYP_I_IMPL),
- fieldSize,
- fieldVarDsc->lvOtherReg,
- compiler->lvaOutgoingArgSpaceVar,
- fieldArgOffset + TARGET_POINTER_SIZE);
+ getEmitter()->emitIns_S_R(ins_Store(TYP_I_IMPL), fieldSize, fieldVarDsc->lvOtherReg,
+ compiler->lvaOutgoingArgSpaceVar,
+ fieldArgOffset + TARGET_POINTER_SIZE);
}
}
// Record the fact that we filled in an extra register slot
filledExtraSlot = true;
}
}
- assert(fieldVarDsc->lvTracked); // Must be tracked, since it's enregistered...
+ assert(fieldVarDsc->lvTracked); // Must be tracked, since it's enregistered...
// If the fieldVar becomes dead, then declare the register not to contain a pointer value.
if (arg->gtFlags & GTF_VAR_DEATH)
{
@@ -17793,24 +17462,19 @@ bool CodeGen::genFillSlotFromPromotedStruct(GenTreePtr arg,
if (curRegNum != MAX_REG_ARG)
{
// Dest is reg.
- getEmitter()->emitIns_R_S(ins_Load(fieldTypeForInstr),
- fieldSize,
- curRegNum,
- nextPromotedStructFieldVar, 0);
+ getEmitter()->emitIns_R_S(ins_Load(fieldTypeForInstr), fieldSize, curRegNum,
+ nextPromotedStructFieldVar, 0);
regTracker.rsTrackRegTrash(curRegNum);
regSet.rsMarkArgRegUsedByPromotedFieldArg(arg, curRegNum, EA_IS_GCREF(fieldSize));
- if (fieldVarDsc->lvExactSize == 8)
+ if (fieldVarDsc->lvExactSize == 8)
{
noway_assert(fieldSize == EA_4BYTE);
curRegNum = genRegArgNext(curRegNum);
- noway_assert(curRegNum < MAX_REG_ARG); // Because of 8-byte alignment.
- getEmitter()->emitIns_R_S(ins_Load(TYP_I_IMPL),
- fieldSize,
- curRegNum,
- nextPromotedStructFieldVar,
- TARGET_POINTER_SIZE);
+ noway_assert(curRegNum < MAX_REG_ARG); // Because of 8-byte alignment.
+ getEmitter()->emitIns_R_S(ins_Load(TYP_I_IMPL), fieldSize, curRegNum,
+ nextPromotedStructFieldVar, TARGET_POINTER_SIZE);
regTracker.rsTrackRegTrash(curRegNum);
regSet.rsMarkArgRegUsedByPromotedFieldArg(arg, curRegNum, EA_IS_GCREF(fieldSize));
// Record the fact that we filled in an extra stack slot
@@ -17824,32 +17488,23 @@ bool CodeGen::genFillSlotFromPromotedStruct(GenTreePtr arg,
{
regTmp = regSet.rsPickFreeReg();
}
- getEmitter()->emitIns_R_S(ins_Load(fieldTypeForInstr),
- fieldSize,
- regTmp,
- nextPromotedStructFieldVar, 0);
+ getEmitter()->emitIns_R_S(ins_Load(fieldTypeForInstr), fieldSize, regTmp,
+ nextPromotedStructFieldVar, 0);
// Now write regTmp into the right location in the outgoing argument list.
- getEmitter()->emitIns_S_R(ins_Store(fieldTypeForInstr),
- fieldSize,
- regTmp,
- compiler->lvaOutgoingArgSpaceVar,
- fieldArgOffset);
+ getEmitter()->emitIns_S_R(ins_Store(fieldTypeForInstr), fieldSize, regTmp,
+ compiler->lvaOutgoingArgSpaceVar, fieldArgOffset);
// We overwrote "regTmp", so erase any previous value we recorded that it contained.
regTracker.rsTrackRegTrash(regTmp);
- if (fieldVarDsc->lvExactSize == 8)
+ if (fieldVarDsc->lvExactSize == 8)
{
- getEmitter()->emitIns_R_S(ins_Load(fieldTypeForInstr),
- fieldSize,
- regTmp,
- nextPromotedStructFieldVar, TARGET_POINTER_SIZE);
-
- getEmitter()->emitIns_S_R(ins_Store(TYP_I_IMPL),
- fieldSize,
- regTmp,
- compiler->lvaOutgoingArgSpaceVar,
- fieldArgOffset + TARGET_POINTER_SIZE);
+ getEmitter()->emitIns_R_S(ins_Load(fieldTypeForInstr), fieldSize, regTmp,
+ nextPromotedStructFieldVar, TARGET_POINTER_SIZE);
+
+ getEmitter()->emitIns_S_R(ins_Store(TYP_I_IMPL), fieldSize, regTmp,
+ compiler->lvaOutgoingArgSpaceVar,
+ fieldArgOffset + TARGET_POINTER_SIZE);
// Record the fact that we filled in an extra stack slot
filledExtraSlot = true;
}
@@ -17857,7 +17512,7 @@ bool CodeGen::genFillSlotFromPromotedStruct(GenTreePtr arg,
}
// Bump up the following if we filled in an extra slot
- if (filledExtraSlot)
+ if (filledExtraSlot)
bytesOfNextSlotOfCurPromotedStruct += 4;
// Go to the next field.
@@ -17868,15 +17523,16 @@ bool CodeGen::genFillSlotFromPromotedStruct(GenTreePtr arg,
}
else
{
- // The next field should have the same parent variable, and we should have put the field vars in order sorted by offset.
- assert(fieldVarDsc->lvIsStructField && compiler->lvaTable[nextPromotedStructFieldVar].lvIsStructField
- && fieldVarDsc->lvParentLcl == compiler->lvaTable[nextPromotedStructFieldVar].lvParentLcl
- && fieldVarDsc->lvFldOffset < compiler->lvaTable[nextPromotedStructFieldVar].lvFldOffset);
+ // The next field should have the same parent variable, and we should have put the field vars in order
+ // sorted by offset.
+ assert(fieldVarDsc->lvIsStructField && compiler->lvaTable[nextPromotedStructFieldVar].lvIsStructField &&
+ fieldVarDsc->lvParentLcl == compiler->lvaTable[nextPromotedStructFieldVar].lvParentLcl &&
+ fieldVarDsc->lvFldOffset < compiler->lvaTable[nextPromotedStructFieldVar].lvFldOffset);
fieldVarDsc = &compiler->lvaTable[nextPromotedStructFieldVar];
}
bytesOfNextSlotOfCurPromotedStruct += 4;
}
- else // oneFieldFillsSlotFromStart == false
+ else // oneFieldFillsSlotFromStart == false
{
// The current slot should contain more than one field.
// We'll construct a word in memory for the slot, then load it into a register.
@@ -17890,28 +17546,24 @@ bool CodeGen::genFillSlotFromPromotedStruct(GenTreePtr arg,
// If the argument goes to the stack, the offset in the outgoing arg area for the argument.
int fieldArgOffset = argOffsetOfFirstStackSlot + fieldVarDsc->lvFldOffset - fieldOffsetOfFirstStackSlot;
- noway_assert(argOffset == INT32_MAX || (argOffset <= fieldArgOffset && fieldArgOffset < argOffset + TARGET_POINTER_SIZE));
-
+ noway_assert(argOffset == INT32_MAX ||
+ (argOffset <= fieldArgOffset && fieldArgOffset < argOffset + TARGET_POINTER_SIZE));
+
if (fieldVarDsc->lvRegister)
{
if (curRegNum != MAX_REG_ARG)
{
noway_assert(compiler->lvaPromotedStructAssemblyScratchVar != BAD_VAR_NUM);
- getEmitter()->emitIns_S_R(ins_Store(fieldTypeForInstr),
- fieldSize,
- fieldVarDsc->lvRegNum,
- compiler->lvaPromotedStructAssemblyScratchVar,
- fieldVarDsc->lvFldOffset % 4);
+ getEmitter()->emitIns_S_R(ins_Store(fieldTypeForInstr), fieldSize, fieldVarDsc->lvRegNum,
+ compiler->lvaPromotedStructAssemblyScratchVar,
+ fieldVarDsc->lvFldOffset % 4);
}
else
{
// Dest is stack; write directly.
- getEmitter()->emitIns_S_R(ins_Store(fieldTypeForInstr),
- fieldSize,
- fieldVarDsc->lvRegNum,
- compiler->lvaOutgoingArgSpaceVar,
- fieldArgOffset);
+ getEmitter()->emitIns_S_R(ins_Store(fieldTypeForInstr), fieldSize, fieldVarDsc->lvRegNum,
+ compiler->lvaOutgoingArgSpaceVar, fieldArgOffset);
}
}
else
@@ -17923,29 +17575,22 @@ bool CodeGen::genFillSlotFromPromotedStruct(GenTreePtr arg,
{
regTmp = regSet.rsPickFreeReg();
}
- getEmitter()->emitIns_R_S(ins_Load(fieldTypeForInstr),
- fieldSize,
- regTmp,
- nextPromotedStructFieldVar, 0);
+ getEmitter()->emitIns_R_S(ins_Load(fieldTypeForInstr), fieldSize, regTmp,
+ nextPromotedStructFieldVar, 0);
regTracker.rsTrackRegTrash(regTmp);
if (curRegNum != MAX_REG_ARG)
- {
+ {
noway_assert(compiler->lvaPromotedStructAssemblyScratchVar != BAD_VAR_NUM);
- getEmitter()->emitIns_S_R(ins_Store(fieldTypeForInstr),
- fieldSize,
- regTmp,
- compiler->lvaPromotedStructAssemblyScratchVar,
- fieldVarDsc->lvFldOffset % 4);
+ getEmitter()->emitIns_S_R(ins_Store(fieldTypeForInstr), fieldSize, regTmp,
+ compiler->lvaPromotedStructAssemblyScratchVar,
+ fieldVarDsc->lvFldOffset % 4);
}
else
{
- getEmitter()->emitIns_S_R(ins_Store(fieldTypeForInstr),
- fieldSize,
- regTmp,
- compiler->lvaOutgoingArgSpaceVar,
- fieldArgOffset);
+ getEmitter()->emitIns_S_R(ins_Store(fieldTypeForInstr), fieldSize, regTmp,
+ compiler->lvaOutgoingArgSpaceVar, fieldArgOffset);
}
}
// Go to the next field.
@@ -17956,10 +17601,13 @@ bool CodeGen::genFillSlotFromPromotedStruct(GenTreePtr arg,
}
else
{
- // The next field should have the same parent variable, and we should have put the field vars in order sorted by offset.
- noway_assert(fieldVarDsc->lvIsStructField && compiler->lvaTable[nextPromotedStructFieldVar].lvIsStructField
- && fieldVarDsc->lvParentLcl == compiler->lvaTable[nextPromotedStructFieldVar].lvParentLcl
- && fieldVarDsc->lvFldOffset < compiler->lvaTable[nextPromotedStructFieldVar].lvFldOffset);
+ // The next field should have the same parent variable, and we should have put the field vars in
+ // order sorted by offset.
+ noway_assert(fieldVarDsc->lvIsStructField &&
+ compiler->lvaTable[nextPromotedStructFieldVar].lvIsStructField &&
+ fieldVarDsc->lvParentLcl ==
+ compiler->lvaTable[nextPromotedStructFieldVar].lvParentLcl &&
+ fieldVarDsc->lvFldOffset < compiler->lvaTable[nextPromotedStructFieldVar].lvFldOffset);
fieldVarDsc = &compiler->lvaTable[nextPromotedStructFieldVar];
}
}
@@ -17969,10 +17617,8 @@ bool CodeGen::genFillSlotFromPromotedStruct(GenTreePtr arg,
{
noway_assert(compiler->lvaPromotedStructAssemblyScratchVar != BAD_VAR_NUM);
- getEmitter()->emitIns_R_S(ins_Load(TYP_I_IMPL),
- EA_4BYTE,
- curRegNum,
- compiler->lvaPromotedStructAssemblyScratchVar, 0);
+ getEmitter()->emitIns_R_S(ins_Load(TYP_I_IMPL), EA_4BYTE, curRegNum,
+ compiler->lvaPromotedStructAssemblyScratchVar, 0);
regTracker.rsTrackRegTrash(curRegNum);
regSet.rsMarkArgRegUsedByPromotedFieldArg(arg, curRegNum, EA_IS_GCREF(fieldSize));
}
@@ -17982,10 +17628,10 @@ bool CodeGen::genFillSlotFromPromotedStruct(GenTreePtr arg,
}
// Write back the updates.
- *pNextPromotedStructFieldVar = nextPromotedStructFieldVar;
+ *pNextPromotedStructFieldVar = nextPromotedStructFieldVar;
*pBytesOfNextSlotOfCurPromotedStruct = bytesOfNextSlotOfCurPromotedStruct;
- *pCurRegNum = curRegNum;
- *pRegTmp = regTmp;
+ *pCurRegNum = curRegNum;
+ *pRegTmp = regTmp;
return filledExtraSlot;
}
@@ -17995,9 +17641,9 @@ regMaskTP CodeGen::genFindDeadFieldRegs(GenTreePtr cpBlk)
{
noway_assert(cpBlk->OperIsCopyBlkOp()); // Precondition.
GenTreePtr lst = cpBlk->gtOp.gtOp1;
- noway_assert(lst->OperGet() == GT_LIST); // Well-formedness.
+ noway_assert(lst->OperGet() == GT_LIST); // Well-formedness.
GenTreePtr rhs = lst->gtOp.gtOp2;
- regMaskTP res = 0;
+ regMaskTP res = 0;
if (rhs->OperGet() == GT_ADDR)
{
rhs = rhs->gtOp.gtOp1;
@@ -18024,23 +17670,22 @@ regMaskTP CodeGen::genFindDeadFieldRegs(GenTreePtr cpBlk)
return res;
}
-
void CodeGen::SetupLateArgs(GenTreePtr call)
{
GenTreeArgList* lateArgs;
- GenTreePtr curr;
+ GenTreePtr curr;
/* Generate the code to move the late arguments into registers */
for (lateArgs = call->gtCall.gtCallLateArgs; lateArgs; lateArgs = lateArgs->Rest())
{
- curr = lateArgs->Current();
+ curr = lateArgs->Current();
assert(curr);
fgArgTabEntryPtr curArgTabEntry = compiler->gtArgEntryByNode(call, curr);
assert(curArgTabEntry);
- regNumber regNum = curArgTabEntry->regNum;
- unsigned argOffset = curArgTabEntry->slotNum * TARGET_POINTER_SIZE;
+ regNumber regNum = curArgTabEntry->regNum;
+ unsigned argOffset = curArgTabEntry->slotNum * TARGET_POINTER_SIZE;
assert(isRegParamType(curr->TypeGet()));
assert(curr->gtType != TYP_VOID);
@@ -18065,7 +17710,7 @@ void CodeGen::SetupLateArgs(GenTreePtr call)
// variables register (like a GT_REG_VAR). This probably
// is caused by RegAlloc assuming the first operand would
// evaluate into another register.
- regMaskTP rsTemp = regSet.rsMaskVars & regSet.rsMaskUsed & RBM_CALLEE_TRASH;
+ regMaskTP rsTemp = regSet.rsMaskVars & regSet.rsMaskUsed & RBM_CALLEE_TRASH;
regMaskTP gcRegSavedByref = gcInfo.gcRegByrefSetCur & rsTemp;
regMaskTP gcRegSavedGCRef = gcInfo.gcRegGCrefSetCur & rsTemp;
regSet.RemoveMaskVars(rsTemp);
@@ -18094,13 +17739,9 @@ void CodeGen::SetupLateArgs(GenTreePtr call)
/* Check if this is the guess area for the resolve interface call
* Pass a size of EA_OFFSET*/
- if (curr->gtOper == GT_CLS_VAR && compiler->eeGetJitDataOffs(curr->gtClsVar.gtClsVarHnd) >= 0)
+ if (curr->gtOper == GT_CLS_VAR && compiler->eeGetJitDataOffs(curr->gtClsVar.gtClsVarHnd) >= 0)
{
- getEmitter()->emitIns_R_C(ins_Load(TYP_INT),
- EA_OFFSET,
- regNum,
- curr->gtClsVar.gtClsVarHnd,
- 0);
+ getEmitter()->emitIns_R_C(ins_Load(TYP_INT), EA_OFFSET, regNum, curr->gtClsVar.gtClsVarHnd, 0);
regTracker.rsTrackRegTrash(regNum);
/* The value is now in the appropriate register */
@@ -18120,10 +17761,11 @@ void CodeGen::SetupLateArgs(GenTreePtr call)
genUpdateLife(op1);
arg = arg->gtOp.gtOp2;
}
- noway_assert((arg->OperGet() == GT_OBJ) || (arg->OperGet() == GT_LCL_VAR) || (arg->OperGet() == GT_MKREFANY));
+ noway_assert((arg->OperGet() == GT_OBJ) || (arg->OperGet() == GT_LCL_VAR) ||
+ (arg->OperGet() == GT_MKREFANY));
// This code passes a TYP_STRUCT by value using
- // the argument registers first and
+ // the argument registers first and
// then the lvaOutgoingArgSpaceVar area.
//
@@ -18132,7 +17774,7 @@ void CodeGen::SetupLateArgs(GenTreePtr call)
unsigned firstStackSlot = 0;
unsigned argAlign = TARGET_POINTER_SIZE;
size_t originalSize = InferStructOpSizeAlign(arg, &argAlign);
-
+
unsigned slots = (unsigned)(roundUp(originalSize, TARGET_POINTER_SIZE) / TARGET_POINTER_SIZE);
assert(slots > 0);
@@ -18155,8 +17797,9 @@ void CodeGen::SetupLateArgs(GenTreePtr call)
if (curArgTabEntry->isHfaRegArg)
{
// HFA arguments that have been decided to go into registers fit the reg space.
- assert(regNum >= FIRST_FP_ARGREG && "HFA must go in FP register");
- assert(regNum + slots - 1 <= LAST_FP_ARGREG && "HFA argument doesn't fit entirely in FP argument registers");
+ assert(regNum >= FIRST_FP_ARGREG && "HFA must go in FP register");
+ assert(regNum + slots - 1 <= LAST_FP_ARGREG &&
+ "HFA argument doesn't fit entirely in FP argument registers");
firstStackSlot = slots;
}
else if (regNum + slots > MAX_REG_ARG)
@@ -18172,7 +17815,7 @@ void CodeGen::SetupLateArgs(GenTreePtr call)
if (curArgTabEntry->isHfaRegArg)
{
// Mask out the registers used by an HFA arg from the ones used to compute tree into.
- for (unsigned i = regNum; i < regNum + slots; i ++)
+ for (unsigned i = regNum; i < regNum + slots; i++)
{
regNeedMask &= ~genRegMask(regNumber(i));
}
@@ -18192,32 +17835,32 @@ void CodeGen::SetupLateArgs(GenTreePtr call)
// working on the second slot, "bytesOfNextSlotOfCurPromotedStruct" will be 8, the point at which we're
// done), and "nextPromotedStructFieldVar" will be the local variable number of the next field variable
// to be copied.
- LclVarDsc* promotedStructLocalVarDesc = NULL;
- unsigned bytesOfNextSlotOfCurPromotedStruct = 0; // Size of slot.
- unsigned nextPromotedStructFieldVar = BAD_VAR_NUM;
- GenTreePtr structLocalTree = NULL;
-
- BYTE * gcLayout = NULL;
- regNumber regSrc = REG_NA;
+ LclVarDsc* promotedStructLocalVarDesc = NULL;
+ unsigned bytesOfNextSlotOfCurPromotedStruct = 0; // Size of slot.
+ unsigned nextPromotedStructFieldVar = BAD_VAR_NUM;
+ GenTreePtr structLocalTree = NULL;
+
+ BYTE* gcLayout = NULL;
+ regNumber regSrc = REG_NA;
if (arg->gtOper == GT_OBJ)
{
// Are we loading a promoted struct local var?
- if (arg->gtObj.gtOp1->gtOper == GT_ADDR &&
- arg->gtObj.gtOp1->gtOp.gtOp1->gtOper == GT_LCL_VAR)
+ if (arg->gtObj.gtOp1->gtOper == GT_ADDR && arg->gtObj.gtOp1->gtOp.gtOp1->gtOper == GT_LCL_VAR)
{
- structLocalTree = arg->gtObj.gtOp1->gtOp.gtOp1;
- unsigned structLclNum = structLocalTree->gtLclVarCommon.gtLclNum;
- LclVarDsc * varDsc = &compiler->lvaTable[structLclNum];
+ structLocalTree = arg->gtObj.gtOp1->gtOp.gtOp1;
+ unsigned structLclNum = structLocalTree->gtLclVarCommon.gtLclNum;
+ LclVarDsc* varDsc = &compiler->lvaTable[structLclNum];
Compiler::lvaPromotionType promotionType = compiler->lvaGetPromotionType(varDsc);
- if (varDsc->lvPromoted &&
- promotionType==Compiler::PROMOTION_TYPE_INDEPENDENT) // Otherwise it is guaranteed to live on stack.
+ if (varDsc->lvPromoted && promotionType == Compiler::PROMOTION_TYPE_INDEPENDENT) // Otherwise it is
+ // guaranteed to
+ // live on stack.
{
// Fix 388395 ARM JitStress WP7
noway_assert(structLocalTree->TypeGet() == TYP_STRUCT);
- assert(!varDsc->lvAddrExposed); // Compiler::PROMOTION_TYPE_INDEPENDENT ==> not exposed.
+ assert(!varDsc->lvAddrExposed); // Compiler::PROMOTION_TYPE_INDEPENDENT ==> not exposed.
promotedStructLocalVarDesc = varDsc;
nextPromotedStructFieldVar = promotedStructLocalVarDesc->lvFieldLclStart;
}
@@ -18245,18 +17888,19 @@ void CodeGen::SetupLateArgs(GenTreePtr call)
unsigned varNum = arg->gtLclVarCommon.gtLclNum;
// Are we loading a promoted struct local var?
- structLocalTree = arg;
- unsigned structLclNum = structLocalTree->gtLclVarCommon.gtLclNum;
- LclVarDsc * varDsc = &compiler->lvaTable[structLclNum];
+ structLocalTree = arg;
+ unsigned structLclNum = structLocalTree->gtLclVarCommon.gtLclNum;
+ LclVarDsc* varDsc = &compiler->lvaTable[structLclNum];
noway_assert(structLocalTree->TypeGet() == TYP_STRUCT);
Compiler::lvaPromotionType promotionType = compiler->lvaGetPromotionType(varDsc);
- if (varDsc->lvPromoted &&
- promotionType==Compiler::PROMOTION_TYPE_INDEPENDENT) // Otherwise it is guaranteed to live on stack.
+ if (varDsc->lvPromoted && promotionType == Compiler::PROMOTION_TYPE_INDEPENDENT) // Otherwise it is
+ // guaranteed to live
+ // on stack.
{
- assert(!varDsc->lvAddrExposed); // Compiler::PROMOTION_TYPE_INDEPENDENT ==> not exposed.
+ assert(!varDsc->lvAddrExposed); // Compiler::PROMOTION_TYPE_INDEPENDENT ==> not exposed.
promotedStructLocalVarDesc = varDsc;
nextPromotedStructFieldVar = promotedStructLocalVarDesc->lvFieldLclStart;
}
@@ -18268,10 +17912,7 @@ void CodeGen::SetupLateArgs(GenTreePtr call)
if (slots > 1)
regNeedMask &= ~genRegMask(regSrc);
- getEmitter()->emitIns_R_S(INS_lea,
- EA_PTRSIZE,
- regSrc,
- varNum, 0);
+ getEmitter()->emitIns_R_S(INS_lea, EA_PTRSIZE, regSrc, varNum, 0);
regTracker.rsTrackRegTrash(regSrc);
gcLayout = compiler->lvaGetGcLayout(varNum);
}
@@ -18288,9 +17929,9 @@ void CodeGen::SetupLateArgs(GenTreePtr call)
{
argOffset += TARGET_POINTER_SIZE;
}
-
+
// Skip the copy loop below because we have already placed the argument in the right place
- slots = 0;
+ slots = 0;
gcLayout = NULL;
}
else
@@ -18304,28 +17945,30 @@ void CodeGen::SetupLateArgs(GenTreePtr call)
// We must do do the stack parts first, since those might need values
// from argument registers that will be overwritten in the portion of the
// loop that writes into the argument registers.
- bytesOfNextSlotOfCurPromotedStruct = (firstStackSlot+1) * TARGET_POINTER_SIZE;
+ bytesOfNextSlotOfCurPromotedStruct = (firstStackSlot + 1) * TARGET_POINTER_SIZE;
// Now find the var number of the first that starts in the first stack slot.
- unsigned fieldVarLim = promotedStructLocalVarDesc->lvFieldLclStart + promotedStructLocalVarDesc->lvFieldCnt;
- while (compiler->lvaTable[nextPromotedStructFieldVar].lvFldOffset < (firstStackSlot*TARGET_POINTER_SIZE)
- && nextPromotedStructFieldVar < fieldVarLim)
+ unsigned fieldVarLim =
+ promotedStructLocalVarDesc->lvFieldLclStart + promotedStructLocalVarDesc->lvFieldCnt;
+ while (compiler->lvaTable[nextPromotedStructFieldVar].lvFldOffset <
+ (firstStackSlot * TARGET_POINTER_SIZE) &&
+ nextPromotedStructFieldVar < fieldVarLim)
{
nextPromotedStructFieldVar++;
}
// If we reach the limit, meaning there is no field that goes even partly in the stack, only if the
// first stack slot is after the last slot.
- assert(nextPromotedStructFieldVar < fieldVarLim|| firstStackSlot >= slots);
+ assert(nextPromotedStructFieldVar < fieldVarLim || firstStackSlot >= slots);
}
-
- if (slots > 0) // the mkref case may have set "slots" to zero.
+
+ if (slots > 0) // the mkref case may have set "slots" to zero.
{
// First pass the stack portion of the struct (if any)
//
- int argOffsetOfFirstStackSlot = argOffset;
- for (unsigned i = firstStackSlot; i < slots; i++)
+ int argOffsetOfFirstStackSlot = argOffset;
+ for (unsigned i = firstStackSlot; i < slots; i++)
{
emitAttr fieldSize;
- if (gcLayout[i] == TYPE_GC_NONE)
+ if (gcLayout[i] == TYPE_GC_NONE)
fieldSize = EA_PTRSIZE;
else if (gcLayout[i] == TYPE_GC_REF)
fieldSize = EA_GCREF;
@@ -18341,19 +17984,14 @@ void CodeGen::SetupLateArgs(GenTreePtr call)
regNumber regTmp = REG_STK;
bool filledExtraSlot =
- genFillSlotFromPromotedStruct(arg,
- curArgTabEntry,
- promotedStructLocalVarDesc,
- fieldSize,
- &nextPromotedStructFieldVar,
+ genFillSlotFromPromotedStruct(arg, curArgTabEntry, promotedStructLocalVarDesc, fieldSize,
+ &nextPromotedStructFieldVar,
&bytesOfNextSlotOfCurPromotedStruct,
- /*pCurRegNum*/&maxRegArg,
- argOffset,
- /*fieldOffsetOfFirstStackSlot*/ firstStackSlot * TARGET_POINTER_SIZE,
- argOffsetOfFirstStackSlot,
- &deadFieldVarRegs,
- &regTmp);
- if (filledExtraSlot)
+ /*pCurRegNum*/ &maxRegArg, argOffset,
+ /*fieldOffsetOfFirstStackSlot*/ firstStackSlot *
+ TARGET_POINTER_SIZE,
+ argOffsetOfFirstStackSlot, &deadFieldVarRegs, &regTmp);
+ if (filledExtraSlot)
{
i++;
argOffset += TARGET_POINTER_SIZE;
@@ -18365,7 +18003,7 @@ void CodeGen::SetupLateArgs(GenTreePtr call)
// and although regSrc has been excluded from regNeedMask, regNeedMask is only a *hint*
// to regSet.rsPickFreeReg, so we need to be a little more forceful.
// Otherwise, just re-use the same register.
- //
+ //
regNumber regTmp = regSrc;
if (slots != 1)
{
@@ -18378,18 +18016,12 @@ void CodeGen::SetupLateArgs(GenTreePtr call)
regSet.rsUnlockReg(genRegMask(regSrc), regSrcUsed);
}
-
- getEmitter()->emitIns_R_AR(ins_Load(TYP_I_IMPL),
- fieldSize,
- regTmp,
- regSrc,
- i * TARGET_POINTER_SIZE);
-
- getEmitter()->emitIns_S_R(ins_Store(TYP_I_IMPL),
- fieldSize,
- regTmp,
- compiler->lvaOutgoingArgSpaceVar,
- argOffset);
+
+ getEmitter()->emitIns_R_AR(ins_Load(TYP_I_IMPL), fieldSize, regTmp, regSrc,
+ i * TARGET_POINTER_SIZE);
+
+ getEmitter()->emitIns_S_R(ins_Store(TYP_I_IMPL), fieldSize, regTmp,
+ compiler->lvaOutgoingArgSpaceVar, argOffset);
regTracker.rsTrackRegTrash(regTmp);
}
argOffset += TARGET_POINTER_SIZE;
@@ -18403,25 +18035,26 @@ void CodeGen::SetupLateArgs(GenTreePtr call)
nextPromotedStructFieldVar = promotedStructLocalVarDesc->lvFieldLclStart;
// Create a nested loop here so that the first time thru the loop
- // we setup all of the regArg registers except for possibly
+ // we setup all of the regArg registers except for possibly
// the one that would overwrite regSrc. Then in the final loop
// (if necessary) we just setup regArg/regSrc with the overwrite
//
- bool overwriteRegSrc=false;
- bool needOverwriteRegSrc=false;
- do {
+ bool overwriteRegSrc = false;
+ bool needOverwriteRegSrc = false;
+ do
+ {
if (needOverwriteRegSrc)
overwriteRegSrc = true;
for (unsigned i = 0; i < firstStackSlot; i++)
{
- regNumber regArg = (regNumber) (regNum+i);
+ regNumber regArg = (regNumber)(regNum + i);
if (overwriteRegSrc == false)
{
if (regArg == regSrc)
{
- needOverwriteRegSrc=true;
+ needOverwriteRegSrc = true;
continue;
}
}
@@ -18432,7 +18065,7 @@ void CodeGen::SetupLateArgs(GenTreePtr call)
}
emitAttr fieldSize;
- if (gcLayout[i] == TYPE_GC_NONE)
+ if (gcLayout[i] == TYPE_GC_NONE)
fieldSize = EA_PTRSIZE;
else if (gcLayout[i] == TYPE_GC_REF)
fieldSize = EA_GCREF;
@@ -18446,31 +18079,24 @@ void CodeGen::SetupLateArgs(GenTreePtr call)
if (promotedStructLocalVarDesc != NULL)
{
bool filledExtraSlot =
- genFillSlotFromPromotedStruct(arg,
- curArgTabEntry,
- promotedStructLocalVarDesc,
- fieldSize,
- &nextPromotedStructFieldVar,
- &bytesOfNextSlotOfCurPromotedStruct,
- /*pCurRegNum*/&regArg,
- /*argOffset*/ INT32_MAX,
- /*fieldOffsetOfFirstStackSlot*/ INT32_MAX,
+ genFillSlotFromPromotedStruct(arg, curArgTabEntry, promotedStructLocalVarDesc,
+ fieldSize, &nextPromotedStructFieldVar,
+ &bytesOfNextSlotOfCurPromotedStruct,
+ /*pCurRegNum*/ &regArg,
+ /*argOffset*/ INT32_MAX,
+ /*fieldOffsetOfFirstStackSlot*/ INT32_MAX,
/*argOffsetOfFirstStackSlot*/ INT32_MAX,
- &deadFieldVarRegs,
- &regTmp);
- if (filledExtraSlot)
+ &deadFieldVarRegs, &regTmp);
+ if (filledExtraSlot)
i++;
}
else
{
getEmitter()->emitIns_R_AR(ins_Load(curArgTabEntry->isHfaRegArg ? TYP_FLOAT : TYP_I_IMPL),
- fieldSize,
- regArg,
- regSrc,
- i*TARGET_POINTER_SIZE);
+ fieldSize, regArg, regSrc, i * TARGET_POINTER_SIZE);
}
regTracker.rsTrackRegTrash(regArg);
- }
+ }
} while (needOverwriteRegSrc != overwriteRegSrc);
}
@@ -18478,27 +18104,25 @@ void CodeGen::SetupLateArgs(GenTreePtr call)
{
regSet.rsMarkRegFree(genRegMask(regSrc));
}
-
- if (regNum != REG_STK && promotedStructLocalVarDesc == NULL) // If promoted, we already declared the regs
- // used.
+
+ if (regNum != REG_STK && promotedStructLocalVarDesc == NULL) // If promoted, we already declared the regs
+ // used.
{
arg->gtFlags |= GTF_REG_VAL;
for (unsigned i = 1; i < firstStackSlot; i++)
{
arg->gtRegNum = (regNumber)(regNum + i);
- curArgTabEntry->isHfaRegArg ? regSet.SetUsedRegFloat(arg, true)
- : regSet.rsMarkRegUsed(arg);
+ curArgTabEntry->isHfaRegArg ? regSet.SetUsedRegFloat(arg, true) : regSet.rsMarkRegUsed(arg);
}
arg->gtRegNum = regNum;
- curArgTabEntry->isHfaRegArg ? regSet.SetUsedRegFloat(arg, true)
- : regSet.rsMarkRegUsed(arg);
+ curArgTabEntry->isHfaRegArg ? regSet.SetUsedRegFloat(arg, true) : regSet.rsMarkRegUsed(arg);
}
// If we're doing struct promotion, the liveness of the promoted field vars may change after this use,
// so update liveness.
genUpdateLife(arg);
- // Now, if some copied field locals were enregistered, and they're now dead, update the set of
+ // Now, if some copied field locals were enregistered, and they're now dead, update the set of
// register holding gc pointers.
if (deadFieldVarRegs != RBM_NONE)
gcInfo.gcMarkRegSetNpt(deadFieldVarRegs);
@@ -18509,10 +18133,10 @@ void CodeGen::SetupLateArgs(GenTreePtr call)
{
// The arg is passed in the outgoing argument area of the stack frame
genCompIntoFreeRegPair(curr, RBM_NONE, RegSet::FREE_REG);
- assert(curr->gtFlags & GTF_REG_VAL); // should be enregistered after genCompIntoFreeRegPair(curr, 0)
+ assert(curr->gtFlags & GTF_REG_VAL); // should be enregistered after genCompIntoFreeRegPair(curr, 0)
- inst_SA_RV(ins_Store(TYP_INT), argOffset+0, genRegPairLo(curr->gtRegPair), TYP_INT);
- inst_SA_RV(ins_Store(TYP_INT), argOffset+4, genRegPairHi(curr->gtRegPair), TYP_INT);
+ inst_SA_RV(ins_Store(TYP_INT), argOffset + 0, genRegPairLo(curr->gtRegPair), TYP_INT);
+ inst_SA_RV(ins_Store(TYP_INT), argOffset + 4, genRegPairHi(curr->gtRegPair), TYP_INT);
}
else
{
@@ -18529,7 +18153,7 @@ void CodeGen::SetupLateArgs(GenTreePtr call)
// The arg is passed in the outgoing argument area of the stack frame
//
genCodeForTree(curr, 0);
- assert(curr->gtFlags & GTF_REG_VAL); // should be enregistered after genCodeForTree(curr, 0)
+ assert(curr->gtFlags & GTF_REG_VAL); // should be enregistered after genCodeForTree(curr, 0)
inst_SA_RV(ins_Store(curr->gtType), argOffset, curr->gtRegNum, curr->gtType);
@@ -18537,18 +18161,19 @@ void CodeGen::SetupLateArgs(GenTreePtr call)
gcInfo.gcMarkRegSetNpt(genRegMask(curr->gtRegNum));
}
else
- {
+ {
if (!varTypeIsFloating(curr->gtType))
{
genComputeReg(curr, genRegMask(regNum), RegSet::EXACT_REG, RegSet::FREE_REG, false);
assert(curr->gtRegNum == regNum);
regSet.rsMarkRegUsed(curr);
}
- else // varTypeIsFloating(curr->gtType)
+ else // varTypeIsFloating(curr->gtType)
{
if (genIsValidFloatReg(regNum))
{
- genComputeReg(curr, genRegMaskFloat(regNum, curr->gtType), RegSet::EXACT_REG, RegSet::FREE_REG, false);
+ genComputeReg(curr, genRegMaskFloat(regNum, curr->gtType), RegSet::EXACT_REG, RegSet::FREE_REG,
+ false);
assert(curr->gtRegNum == regNum);
regSet.rsMarkRegUsed(curr);
}
@@ -18557,7 +18182,7 @@ void CodeGen::SetupLateArgs(GenTreePtr call)
genCodeForTree(curr, 0);
// If we are loading a floating point type into integer registers
// then it must be for varargs.
- // genCodeForTree will load it into a floating point register,
+ // genCodeForTree will load it into a floating point register,
// now copy it into the correct integer register(s)
if (curr->TypeGet() == TYP_FLOAT)
{
@@ -18570,7 +18195,7 @@ void CodeGen::SetupLateArgs(GenTreePtr call)
#endif
regTracker.rsTrackRegTrash(regNum);
- curr->gtType = TYP_INT; // Change this to TYP_INT in case we need to spill this register
+ curr->gtType = TYP_INT; // Change this to TYP_INT in case we need to spill this register
curr->gtRegNum = regNum;
regSet.rsMarkRegUsed(curr);
}
@@ -18578,7 +18203,7 @@ void CodeGen::SetupLateArgs(GenTreePtr call)
{
assert(curr->TypeGet() == TYP_DOUBLE);
regNumber intRegNumLo = regNum;
- curr->gtType = TYP_LONG; // Change this to TYP_LONG in case we spill this
+ curr->gtType = TYP_LONG; // Change this to TYP_LONG in case we spill this
#ifdef _TARGET_ARM_
regNumber intRegNumHi = regNumber(intRegNumLo + 1);
assert(genRegMask(intRegNumHi) & RBM_CALLEE_TRASH);
@@ -18604,12 +18229,12 @@ void CodeGen::SetupLateArgs(GenTreePtr call)
for (lateArgs = call->gtCall.gtCallLateArgs; lateArgs; lateArgs = lateArgs->Rest())
{
- curr = lateArgs->Current();
+ curr = lateArgs->Current();
assert(curr);
if (curr->gtFlags & GTF_SPILLED)
{
- if (isRegPairType(curr->gtType))
+ if (isRegPairType(curr->gtType))
{
regSet.rsUnspillRegPair(curr, genRegPairMask(curr->gtRegPair), RegSet::KEEP_REG);
}
@@ -18621,7 +18246,6 @@ void CodeGen::SetupLateArgs(GenTreePtr call)
}
}
-
#ifdef _TARGET_ARM_
// 'Push' a single GT_MKREFANY argument onto a call's argument list
@@ -18630,23 +18254,21 @@ void CodeGen::SetupLateArgs(GenTreePtr call)
// regNum value will be equal to the the registers used to pass the
// the first part of the struct.
// If any part is to go onto the stack, we first generate the
-// value into a register specified by 'regNeedMask' and
+// value into a register specified by 'regNeedMask' and
// then store it to the out going argument area.
// When this method returns, both parts of the TypeReference have
// been pushed onto the stack, but *no* registers have been marked
// as 'in-use', that is the responsibility of the caller.
//
-void CodeGen::PushMkRefAnyArg ( GenTreePtr mkRefAnyTree,
- fgArgTabEntryPtr curArgTabEntry,
- regMaskTP regNeedMask)
+void CodeGen::PushMkRefAnyArg(GenTreePtr mkRefAnyTree, fgArgTabEntryPtr curArgTabEntry, regMaskTP regNeedMask)
{
- regNumber regNum = curArgTabEntry->regNum;
- regNumber regNum2;
+ regNumber regNum = curArgTabEntry->regNum;
+ regNumber regNum2;
assert(mkRefAnyTree->gtOper == GT_MKREFANY);
regMaskTP arg1RegMask = 0;
- int argOffset = curArgTabEntry->slotNum * TARGET_POINTER_SIZE;
+ int argOffset = curArgTabEntry->slotNum * TARGET_POINTER_SIZE;
- // Construct the TypedReference directly into the argument list of the call by
+ // Construct the TypedReference directly into the argument list of the call by
// 'pushing' the first field of the typed reference: the pointer.
// Do this by directly generating it into the argument register or outgoing arg area of the stack.
// Mark it as used so we don't trash it while generating the second field.
@@ -18693,9 +18315,9 @@ void CodeGen::PushMkRefAnyArg ( GenTreePtr mkRefAnyTree,
if (arg1RegMask != 0)
{
GenTreePtr op1 = mkRefAnyTree->gtOp.gtOp1;
- if (op1->gtFlags & GTF_SPILLED)
+ if (op1->gtFlags & GTF_SPILLED)
{
- /* The register that we loaded arg1 into has been spilled -- reload it back into the correct arg register */
+ /* The register that we loaded arg1 into has been spilled -- reload it back into the correct arg register */
regSet.rsUnspillReg(op1, arg1RegMask, RegSet::FREE_REG);
}
@@ -18707,10 +18329,9 @@ void CodeGen::PushMkRefAnyArg ( GenTreePtr mkRefAnyTree,
}
#endif // _TARGET_ARM_
-#endif // FEATURE_FIXED_OUT_ARGS
-
+#endif // FEATURE_FIXED_OUT_ARGS
-regMaskTP CodeGen::genLoadIndirectCallTarget(GenTreePtr call)
+regMaskTP CodeGen::genLoadIndirectCallTarget(GenTreePtr call)
{
assert((gtCallTypes)call->gtCall.gtCallType == CT_INDIRECT);
@@ -18723,50 +18344,47 @@ regMaskTP CodeGen::genLoadIndirectCallTarget(GenTreePtr call)
*/
struct
{
- GenTreePtr node;
- union
- {
- regNumber regNum;
- regPairNo regPair;
+ GenTreePtr node;
+ union {
+ regNumber regNum;
+ regPairNo regPair;
};
- }
- regArgTab[MAX_REG_ARG];
+ } regArgTab[MAX_REG_ARG];
/* Record the previously loaded arguments, if any */
- unsigned regIndex;
+ unsigned regIndex;
regMaskTP prefRegs = regSet.rsRegMaskFree();
- regMaskTP argRegs = RBM_NONE;
+ regMaskTP argRegs = RBM_NONE;
for (regIndex = 0; regIndex < MAX_REG_ARG; regIndex++)
{
- regMaskTP mask;
- regNumber regNum = genMapRegArgNumToRegNum(regIndex, TYP_INT);
- GenTreePtr argTree = regSet.rsUsedTree[regNum];
+ regMaskTP mask;
+ regNumber regNum = genMapRegArgNumToRegNum(regIndex, TYP_INT);
+ GenTreePtr argTree = regSet.rsUsedTree[regNum];
regArgTab[regIndex].node = argTree;
- if ((argTree != NULL) && (argTree->gtType != TYP_STRUCT)) // We won't spill the struct
+ if ((argTree != NULL) && (argTree->gtType != TYP_STRUCT)) // We won't spill the struct
{
assert(argTree->gtFlags & GTF_REG_VAL);
- if (isRegPairType(argTree->gtType))
+ if (isRegPairType(argTree->gtType))
{
regPairNo regPair = argTree->gtRegPair;
- assert(regNum == genRegPairHi(regPair) ||
- regNum == genRegPairLo(regPair));
+ assert(regNum == genRegPairHi(regPair) || regNum == genRegPairLo(regPair));
regArgTab[regIndex].regPair = regPair;
- mask = genRegPairMask(regPair);
+ mask = genRegPairMask(regPair);
}
else
{
assert(regNum == argTree->gtRegNum);
regArgTab[regIndex].regNum = regNum;
- mask = genRegMask(regNum);
+ mask = genRegMask(regNum);
}
assert(!(prefRegs & mask));
argRegs |= mask;
}
}
-
+
/* Record the register(s) used for the indirect call func ptr */
- fptrRegs = genMakeRvalueAddressable(call->gtCall.gtCallAddr, prefRegs, RegSet::KEEP_REG, false);
+ fptrRegs = genMakeRvalueAddressable(call->gtCall.gtCallAddr, prefRegs, RegSet::KEEP_REG, false);
/* If any of the previously loaded arguments were spilled, reload them */
@@ -18776,7 +18394,7 @@ regMaskTP CodeGen::genLoadIndirectCallTarget(GenTreePtr call)
if ((argTree != NULL) && (argTree->gtFlags & GTF_SPILLED))
{
assert(argTree->gtType != TYP_STRUCT); // We currently don't support spilling structs in argument registers
- if (isRegPairType(argTree->gtType))
+ if (isRegPairType(argTree->gtType))
{
regSet.rsUnspillRegPair(argTree, genRegPairMask(regArgTab[regIndex].regPair), RegSet::KEEP_REG);
}
@@ -18803,32 +18421,31 @@ regMaskTP CodeGen::genLoadIndirectCallTarget(GenTreePtr call)
#ifdef _PREFAST_
#pragma warning(push)
-#pragma warning(disable:21000) // Suppress PREFast warning about overly large function
+#pragma warning(disable : 21000) // Suppress PREFast warning about overly large function
#endif
-regMaskTP CodeGen::genCodeForCall(GenTreePtr call,
- bool valUsed)
+regMaskTP CodeGen::genCodeForCall(GenTreePtr call, bool valUsed)
{
- emitAttr retSize;
- size_t argSize;
- size_t args;
- regMaskTP retVal;
+ emitAttr retSize;
+ size_t argSize;
+ size_t args;
+ regMaskTP retVal;
emitter::EmitCallType emitCallType;
- unsigned saveStackLvl;
+ unsigned saveStackLvl;
- BasicBlock * returnLabel = DUMMY_INIT(NULL);
- LclVarDsc * frameListRoot = NULL;
+ BasicBlock* returnLabel = DUMMY_INIT(NULL);
+ LclVarDsc* frameListRoot = NULL;
- unsigned savCurIntArgReg;
- unsigned savCurFloatArgReg;
+ unsigned savCurIntArgReg;
+ unsigned savCurFloatArgReg;
- unsigned areg;
+ unsigned areg;
- regMaskTP fptrRegs = RBM_NONE;
- regMaskTP vptrMask = RBM_NONE;
+ regMaskTP fptrRegs = RBM_NONE;
+ regMaskTP vptrMask = RBM_NONE;
-#ifdef DEBUG
- unsigned stackLvl = getEmitter()->emitCurStackLvl;
+#ifdef DEBUG
+ unsigned stackLvl = getEmitter()->emitCurStackLvl;
if (compiler->verbose)
{
@@ -18838,8 +18455,8 @@ regMaskTP CodeGen::genCodeForCall(GenTreePtr call,
}
#endif
- gtCallTypes callType = (gtCallTypes)call->gtCall.gtCallType;
- IL_OFFSETX ilOffset = BAD_IL_OFFSET;
+ gtCallTypes callType = (gtCallTypes)call->gtCall.gtCallType;
+ IL_OFFSETX ilOffset = BAD_IL_OFFSET;
CORINFO_SIG_INFO* sigInfo = nullptr;
@@ -18886,7 +18503,6 @@ regMaskTP CodeGen::genCodeForCall(GenTreePtr call,
saveStackLvl = genStackLevel;
-
/*-------------------------------------------------------------------------
* Set up the registers and arguments
*/
@@ -18898,10 +18514,9 @@ regMaskTP CodeGen::genCodeForCall(GenTreePtr call,
/* We need to get a label for the return address with the proper stack depth. */
/* For the callee pops case (the default) that is before the args are pushed. */
- if ((call->gtFlags & GTF_CALL_UNMANAGED) &&
- !(call->gtFlags & GTF_CALL_POP_ARGS))
+ if ((call->gtFlags & GTF_CALL_UNMANAGED) && !(call->gtFlags & GTF_CALL_POP_ARGS))
{
- returnLabel = genCreateTempLabel();
+ returnLabel = genCreateTempLabel();
}
/*
@@ -18910,9 +18525,9 @@ regMaskTP CodeGen::genCodeForCall(GenTreePtr call,
*/
noway_assert(intRegState.rsCurRegArgNum <= MAX_REG_ARG);
- savCurIntArgReg = intRegState.rsCurRegArgNum;
- savCurFloatArgReg = floatRegState.rsCurRegArgNum;
- intRegState.rsCurRegArgNum = 0;
+ savCurIntArgReg = intRegState.rsCurRegArgNum;
+ savCurFloatArgReg = floatRegState.rsCurRegArgNum;
+ intRegState.rsCurRegArgNum = 0;
floatRegState.rsCurRegArgNum = 0;
/* Pass the arguments */
@@ -18941,41 +18556,41 @@ regMaskTP CodeGen::genCodeForCall(GenTreePtr call,
/* Make sure any callee-trashed registers are saved */
- regMaskTP calleeTrashedRegs = RBM_NONE;
+ regMaskTP calleeTrashedRegs = RBM_NONE;
#if GTF_CALL_REG_SAVE
- if (call->gtFlags & GTF_CALL_REG_SAVE)
+ if (call->gtFlags & GTF_CALL_REG_SAVE)
{
/* The return value reg(s) will definitely be trashed */
switch (call->gtType)
{
- case TYP_INT:
- case TYP_REF:
- case TYP_BYREF:
-#if!CPU_HAS_FP_SUPPORT
- case TYP_FLOAT:
+ case TYP_INT:
+ case TYP_REF:
+ case TYP_BYREF:
+#if !CPU_HAS_FP_SUPPORT
+ case TYP_FLOAT:
#endif
- calleeTrashedRegs = RBM_INTRET;
- break;
+ calleeTrashedRegs = RBM_INTRET;
+ break;
- case TYP_LONG:
-#if!CPU_HAS_FP_SUPPORT
- case TYP_DOUBLE:
+ case TYP_LONG:
+#if !CPU_HAS_FP_SUPPORT
+ case TYP_DOUBLE:
#endif
- calleeTrashedRegs = RBM_LNGRET;
- break;
+ calleeTrashedRegs = RBM_LNGRET;
+ break;
- case TYP_VOID:
+ case TYP_VOID:
#if CPU_HAS_FP_SUPPORT
- case TYP_FLOAT:
- case TYP_DOUBLE:
+ case TYP_FLOAT:
+ case TYP_DOUBLE:
#endif
- calleeTrashedRegs = 0;
- break;
+ calleeTrashedRegs = 0;
+ break;
- default:
- noway_assert(!"unhandled/unexpected type");
+ default:
+ noway_assert(!"unhandled/unexpected type");
}
}
else
@@ -18986,13 +18601,13 @@ regMaskTP CodeGen::genCodeForCall(GenTreePtr call,
/* Spill any callee-saved registers which are being used */
- regMaskTP spillRegs = calleeTrashedRegs & regSet.rsMaskUsed;
+ regMaskTP spillRegs = calleeTrashedRegs & regSet.rsMaskUsed;
/* We need to save all GC registers to the InlinedCallFrame.
Instead, just spill them to temps. */
if (call->gtFlags & GTF_CALL_UNMANAGED)
- spillRegs |= (gcInfo.gcRegGCrefSetCur|gcInfo.gcRegByrefSetCur) & regSet.rsMaskUsed;
+ spillRegs |= (gcInfo.gcRegGCrefSetCur | gcInfo.gcRegByrefSetCur) & regSet.rsMaskUsed;
// Ignore fptrRegs as it is needed only to perform the indirect call
@@ -19035,11 +18650,9 @@ regMaskTP CodeGen::genCodeForCall(GenTreePtr call,
retSize = EA_PTRSIZE;
-
- if (valUsed)
+ if (valUsed)
{
- if (call->gtType == TYP_REF ||
- call->gtType == TYP_ARRAY)
+ if (call->gtType == TYP_REF || call->gtType == TYP_ARRAY)
{
retSize = EA_GCREF;
}
@@ -19049,7 +18662,6 @@ regMaskTP CodeGen::genCodeForCall(GenTreePtr call,
}
}
-
/*-------------------------------------------------------------------------
* For caller-pop calls, the GC info will report the arguments as pending
arguments as the caller explicitly pops them. Also should be
@@ -19057,8 +18669,7 @@ regMaskTP CodeGen::genCodeForCall(GenTreePtr call,
call site (callee owns them)
*/
- args = (call->gtFlags & GTF_CALL_POP_ARGS) ? -int(argSize)
- : argSize;
+ args = (call->gtFlags & GTF_CALL_POP_ARGS) ? -int(argSize) : argSize;
#ifdef PROFILING_SUPPORTED
@@ -19070,11 +18681,9 @@ regMaskTP CodeGen::genCodeForCall(GenTreePtr call,
/* fire the event at the call site */
/* alas, right now I can only handle calls via a method handle */
- if (compiler->compIsProfilerHookNeeded() &&
- (callType == CT_USER_FUNC) &&
- call->gtCall.IsTailCall())
+ if (compiler->compIsProfilerHookNeeded() && (callType == CT_USER_FUNC) && call->gtCall.IsTailCall())
{
- unsigned saveStackLvl2 = genStackLevel;
+ unsigned saveStackLvl2 = genStackLevel;
//
// Push the profilerHandle
@@ -19088,8 +18697,8 @@ regMaskTP CodeGen::genCodeForCall(GenTreePtr call,
if (compiler->compProfilerMethHndIndirected)
{
- getEmitter()->emitIns_AR_R(INS_push, EA_PTR_DSP_RELOC, REG_NA, REG_NA,
- (ssize_t)compiler->compProfilerMethHnd);
+ getEmitter()->emitIns_AR_R(INS_push, EA_PTR_DSP_RELOC, REG_NA, REG_NA,
+ (ssize_t)compiler->compProfilerMethHnd);
}
else
{
@@ -19098,8 +18707,8 @@ regMaskTP CodeGen::genCodeForCall(GenTreePtr call,
genSinglePush();
genEmitHelperCall(CORINFO_HELP_PROF_FCN_TAILCALL,
- sizeof(int) * 1, // argSize
- EA_UNKNOWN); // retSize
+ sizeof(int) * 1, // argSize
+ EA_UNKNOWN); // retSize
//
// Adjust the number of stack slots used by this managed method if necessary.
@@ -19119,7 +18728,7 @@ regMaskTP CodeGen::genCodeForCall(GenTreePtr call,
// to disturb them and hence argument registers are locked here.
regMaskTP usedMask = RBM_NONE;
regSet.rsLockReg(RBM_ARG_REGS, &usedMask);
-
+
regNumber scratchReg = regSet.rsGrabReg(RBM_CALLEE_SAVED);
regSet.rsLockReg(genRegMask(scratchReg));
@@ -19128,7 +18737,7 @@ regMaskTP CodeGen::genCodeForCall(GenTreePtr call,
{
attr = EA_GCREF;
gcInfo.gcMarkRegSetGCref(scratchReg);
- }
+ }
else if (RBM_R0 & gcInfo.gcRegByrefSetCur)
{
attr = EA_BYREF;
@@ -19148,13 +18757,13 @@ regMaskTP CodeGen::genCodeForCall(GenTreePtr call,
regTracker.rsTrackRegTrash(REG_R0);
}
else
- {
+ {
instGen_Set_Reg_To_Imm(EA_4BYTE, REG_R0, (ssize_t)compiler->compProfilerMethHnd);
}
genEmitHelperCall(CORINFO_HELP_PROF_FCN_TAILCALL,
- 0, // argSize
- EA_UNKNOWN); // retSize
+ 0, // argSize
+ EA_UNKNOWN); // retSize
// Restore back to the state that existed before profiler callback
gcInfo.gcMarkRegSetNpt(scratchReg);
@@ -19162,10 +18771,9 @@ regMaskTP CodeGen::genCodeForCall(GenTreePtr call,
regTracker.rsTrackRegTrash(REG_R0);
regSet.rsUnlockReg(genRegMask(scratchReg));
regSet.rsUnlockReg(RBM_ARG_REGS, usedMask);
-#else
+#else
NYI("Pushing the profilerHandle & caller's sp for the profiler callout and locking any registers");
-#endif //_TARGET_X86_
-
+#endif //_TARGET_X86_
/* Restore the stack level */
genStackLevel = saveStackLvl2;
@@ -19173,8 +18781,6 @@ regMaskTP CodeGen::genCodeForCall(GenTreePtr call,
#endif // PROFILING_SUPPORTED
-
-
#ifdef DEBUG
/*-------------------------------------------------------------------------
* Generate an ESP check for the call
@@ -19182,14 +18788,16 @@ regMaskTP CodeGen::genCodeForCall(GenTreePtr call,
if (compiler->opts.compStackCheckOnCall
#if defined(USE_TRANSITION_THUNKS) || defined(USE_DYNAMIC_STACK_ALIGN)
- //check the stacks as frequently as possible
+ // check the stacks as frequently as possible
&& !call->IsHelperCall()
#else
&& call->gtCall.gtCallType == CT_USER_FUNC
#endif
- )
+ )
{
- noway_assert(compiler->lvaCallEspCheck != 0xCCCCCCCC && compiler->lvaTable[compiler->lvaCallEspCheck].lvDoNotEnregister && compiler->lvaTable[compiler->lvaCallEspCheck].lvOnFrame);
+ noway_assert(compiler->lvaCallEspCheck != 0xCCCCCCCC &&
+ compiler->lvaTable[compiler->lvaCallEspCheck].lvDoNotEnregister &&
+ compiler->lvaTable[compiler->lvaCallEspCheck].lvOnFrame);
getEmitter()->emitIns_S_R(ins_Store(TYP_I_IMPL), EA_PTRSIZE, REG_SPBASE, compiler->lvaCallEspCheck, 0);
}
#endif
@@ -19198,8 +18806,8 @@ regMaskTP CodeGen::genCodeForCall(GenTreePtr call,
* Generate the call
*/
- bool fPossibleSyncHelperCall = false;
- CorInfoHelpFunc helperNum = CORINFO_HELP_UNDEF; /* only initialized to avoid compiler C4701 warning */
+ bool fPossibleSyncHelperCall = false;
+ CorInfoHelpFunc helperNum = CORINFO_HELP_UNDEF; /* only initialized to avoid compiler C4701 warning */
bool fTailCallTargetIsVSD = false;
@@ -19210,27 +18818,29 @@ regMaskTP CodeGen::genCodeForCall(GenTreePtr call,
an indirect call.
*/
- if ((call->gtCall.gtCallMoreFlags & GTF_CALL_M_DELEGATE_INV) && !fTailCall)
+ if ((call->gtCall.gtCallMoreFlags & GTF_CALL_M_DELEGATE_INV) && !fTailCall)
{
noway_assert(call->gtCall.gtCallType == CT_USER_FUNC);
- assert((compiler->info.compCompHnd->getMethodAttribs(call->gtCall.gtCallMethHnd) & (CORINFO_FLG_DELEGATE_INVOKE|CORINFO_FLG_FINAL)) == (CORINFO_FLG_DELEGATE_INVOKE|CORINFO_FLG_FINAL));
+ assert((compiler->info.compCompHnd->getMethodAttribs(call->gtCall.gtCallMethHnd) &
+ (CORINFO_FLG_DELEGATE_INVOKE | CORINFO_FLG_FINAL)) ==
+ (CORINFO_FLG_DELEGATE_INVOKE | CORINFO_FLG_FINAL));
/* Find the offsets of the 'this' pointer and new target */
- CORINFO_EE_INFO * pInfo;
- unsigned instOffs; // offset of new 'this' pointer
- unsigned firstTgtOffs; // offset of first target to invoke
- const regNumber regThis = genGetThisArgReg(call);
+ CORINFO_EE_INFO* pInfo;
+ unsigned instOffs; // offset of new 'this' pointer
+ unsigned firstTgtOffs; // offset of first target to invoke
+ const regNumber regThis = genGetThisArgReg(call);
- pInfo = compiler->eeGetEEInfo();
- instOffs = pInfo->offsetOfDelegateInstance;
+ pInfo = compiler->eeGetEEInfo();
+ instOffs = pInfo->offsetOfDelegateInstance;
firstTgtOffs = pInfo->offsetOfDelegateFirstTarget;
// Grab an available register to use for the CALL indirection
- regNumber indCallReg = regSet.rsGrabReg(RBM_ALLINT);
+ regNumber indCallReg = regSet.rsGrabReg(RBM_ALLINT);
- // Save the invoke-target-function in indCallReg
+ // Save the invoke-target-function in indCallReg
// 'mov indCallReg, dword ptr [regThis + firstTgtOffs]'
getEmitter()->emitIns_R_AR(ins_Load(TYP_I_IMPL), EA_PTRSIZE, indCallReg, regThis, firstTgtOffs);
regTracker.rsTrackRegTrash(indCallReg);
@@ -19244,884 +18854,814 @@ regMaskTP CodeGen::genCodeForCall(GenTreePtr call,
/* Call through indCallReg */
getEmitter()->emitIns_Call(emitter::EC_INDIR_R,
- NULL, // methHnd
- INDEBUG_LDISASM_COMMA(sigInfo)
- NULL, // addr
- args,
- retSize,
- gcInfo.gcVarPtrSetCur,
- gcInfo.gcRegGCrefSetCur,
- gcInfo.gcRegByrefSetCur,
- ilOffset,
- indCallReg);
+ NULL, // methHnd
+ INDEBUG_LDISASM_COMMA(sigInfo) NULL, // addr
+ args, retSize, gcInfo.gcVarPtrSetCur, gcInfo.gcRegGCrefSetCur,
+ gcInfo.gcRegByrefSetCur, ilOffset, indCallReg);
}
else
- /*-------------------------------------------------------------------------
- * Virtual and interface calls
- */
+ /*-------------------------------------------------------------------------
+ * Virtual and interface calls
+ */
- switch (call->gtFlags & GTF_CALL_VIRT_KIND_MASK)
- {
- case GTF_CALL_VIRT_STUB:
+ switch (call->gtFlags & GTF_CALL_VIRT_KIND_MASK)
{
- regSet.rsSetRegsModified(RBM_VIRTUAL_STUB_PARAM);
+ case GTF_CALL_VIRT_STUB:
+ {
+ regSet.rsSetRegsModified(RBM_VIRTUAL_STUB_PARAM);
- // An x86 JIT which uses full stub dispatch must generate only
- // the following stub dispatch calls:
- //
- // (1) isCallRelativeIndirect:
- // call dword ptr [rel32] ; FF 15 ---rel32----
- // (2) isCallRelative:
- // call abc ; E8 ---rel32----
- // (3) isCallRegisterIndirect:
- // 3-byte nop ;
- // call dword ptr [eax] ; FF 10
- //
- // THIS IS VERY TIGHTLY TIED TO THE PREDICATES IN
- // vm\i386\cGenCpu.h, esp. isCallRegisterIndirect.
+ // An x86 JIT which uses full stub dispatch must generate only
+ // the following stub dispatch calls:
+ //
+ // (1) isCallRelativeIndirect:
+ // call dword ptr [rel32] ; FF 15 ---rel32----
+ // (2) isCallRelative:
+ // call abc ; E8 ---rel32----
+ // (3) isCallRegisterIndirect:
+ // 3-byte nop ;
+ // call dword ptr [eax] ; FF 10
+ //
+ // THIS IS VERY TIGHTLY TIED TO THE PREDICATES IN
+ // vm\i386\cGenCpu.h, esp. isCallRegisterIndirect.
- //
- // Please do not insert any Random NOPs while constructing this VSD call
- //
- getEmitter()->emitDisableRandomNops();
+ //
+ // Please do not insert any Random NOPs while constructing this VSD call
+ //
+ getEmitter()->emitDisableRandomNops();
- if (!fTailCall)
- {
- // This is code to set up an indirect call to a stub address computed
- // via dictionary lookup. However the dispatch stub receivers aren't set up
- // to accept such calls at the moment.
- if (callType == CT_INDIRECT)
+ if (!fTailCall)
{
- regNumber indReg;
+ // This is code to set up an indirect call to a stub address computed
+ // via dictionary lookup. However the dispatch stub receivers aren't set up
+ // to accept such calls at the moment.
+ if (callType == CT_INDIRECT)
+ {
+ regNumber indReg;
- // -------------------------------------------------------------------------
- // The importer decided we needed a stub call via a computed
- // stub dispatch address, i.e. an address which came from a dictionary lookup.
- // - The dictionary lookup produces an indirected address, suitable for call
- // via "call [REG_VIRTUAL_STUB_PARAM]"
- //
- // This combination will only be generated for shared generic code and when
- // stub dispatch is active.
+ // -------------------------------------------------------------------------
+ // The importer decided we needed a stub call via a computed
+ // stub dispatch address, i.e. an address which came from a dictionary lookup.
+ // - The dictionary lookup produces an indirected address, suitable for call
+ // via "call [REG_VIRTUAL_STUB_PARAM]"
+ //
+ // This combination will only be generated for shared generic code and when
+ // stub dispatch is active.
- // No need to null check the this pointer - the dispatch code will deal with this.
+ // No need to null check the this pointer - the dispatch code will deal with this.
- noway_assert(genStillAddressable(call->gtCall.gtCallAddr));
+ noway_assert(genStillAddressable(call->gtCall.gtCallAddr));
- // Now put the address in REG_VIRTUAL_STUB_PARAM.
- // This is typically a nop when the register used for
- // the gtCallAddr is REG_VIRTUAL_STUB_PARAM
- //
- inst_RV_TT(INS_mov, REG_VIRTUAL_STUB_PARAM, call->gtCall.gtCallAddr);
- regTracker.rsTrackRegTrash(REG_VIRTUAL_STUB_PARAM);
+ // Now put the address in REG_VIRTUAL_STUB_PARAM.
+ // This is typically a nop when the register used for
+ // the gtCallAddr is REG_VIRTUAL_STUB_PARAM
+ //
+ inst_RV_TT(INS_mov, REG_VIRTUAL_STUB_PARAM, call->gtCall.gtCallAddr);
+ regTracker.rsTrackRegTrash(REG_VIRTUAL_STUB_PARAM);
#if defined(_TARGET_X86_)
- // Emit enough bytes of nops so that this sequence can be distinguished
- // from other virtual stub dispatch calls.
- //
- // NOTE: THIS IS VERY TIGHTLY TIED TO THE PREDICATES IN
- // vm\i386\cGenCpu.h, esp. isCallRegisterIndirect.
- //
- getEmitter()->emitIns_Nop(3);
+ // Emit enough bytes of nops so that this sequence can be distinguished
+ // from other virtual stub dispatch calls.
+ //
+ // NOTE: THIS IS VERY TIGHTLY TIED TO THE PREDICATES IN
+ // vm\i386\cGenCpu.h, esp. isCallRegisterIndirect.
+ //
+ getEmitter()->emitIns_Nop(3);
- // Make the virtual stub call:
- // call [REG_VIRTUAL_STUB_PARAM]
- //
- emitCallType = emitter::EC_INDIR_ARD;
+ // Make the virtual stub call:
+ // call [REG_VIRTUAL_STUB_PARAM]
+ //
+ emitCallType = emitter::EC_INDIR_ARD;
- indReg = REG_VIRTUAL_STUB_PARAM;
- genDoneAddressable(call->gtCall.gtCallAddr, fptrRegs, RegSet::KEEP_REG);
+ indReg = REG_VIRTUAL_STUB_PARAM;
+ genDoneAddressable(call->gtCall.gtCallAddr, fptrRegs, RegSet::KEEP_REG);
#elif CPU_LOAD_STORE_ARCH // ARM doesn't allow us to use an indirection for the call
- genDoneAddressable(call->gtCall.gtCallAddr, fptrRegs, RegSet::KEEP_REG);
+ genDoneAddressable(call->gtCall.gtCallAddr, fptrRegs, RegSet::KEEP_REG);
- // Make the virtual stub call:
- // ldr indReg, [REG_VIRTUAL_STUB_PARAM]
- // call indReg
- //
- emitCallType = emitter::EC_INDIR_R;
+ // Make the virtual stub call:
+ // ldr indReg, [REG_VIRTUAL_STUB_PARAM]
+ // call indReg
+ //
+ emitCallType = emitter::EC_INDIR_R;
- // Now dereference [REG_VIRTUAL_STUB_PARAM] and put it in a new temp register 'indReg'
- //
- indReg = regSet.rsGrabReg(RBM_ALLINT & ~RBM_VIRTUAL_STUB_PARAM);
- assert(call->gtCall.gtCallAddr->gtFlags & GTF_REG_VAL);
- getEmitter()->emitIns_R_R_I(INS_ldr, EA_PTRSIZE, indReg, REG_VIRTUAL_STUB_PARAM, 0);
- regTracker.rsTrackRegTrash(indReg);
+ // Now dereference [REG_VIRTUAL_STUB_PARAM] and put it in a new temp register 'indReg'
+ //
+ indReg = regSet.rsGrabReg(RBM_ALLINT & ~RBM_VIRTUAL_STUB_PARAM);
+ assert(call->gtCall.gtCallAddr->gtFlags & GTF_REG_VAL);
+ getEmitter()->emitIns_R_R_I(INS_ldr, EA_PTRSIZE, indReg, REG_VIRTUAL_STUB_PARAM, 0);
+ regTracker.rsTrackRegTrash(indReg);
#else
-#error "Unknown target for VSD call"
-#endif
-
- getEmitter()->emitIns_Call(emitCallType,
- NULL, // methHnd
- INDEBUG_LDISASM_COMMA(sigInfo)
- NULL, // addr
- args,
- retSize,
- gcInfo.gcVarPtrSetCur,
- gcInfo.gcRegGCrefSetCur,
- gcInfo.gcRegByrefSetCur,
- ilOffset,
- indReg);
- }
- else
- {
- // -------------------------------------------------------------------------
- // Check for a direct stub call.
- //
+#error "Unknown target for VSD call"
+#endif
- // Get stub addr. This will return NULL if virtual call stubs are not active
- void *stubAddr = NULL;
+ getEmitter()->emitIns_Call(emitCallType,
+ NULL, // methHnd
+ INDEBUG_LDISASM_COMMA(sigInfo) NULL, // addr
+ args, retSize, gcInfo.gcVarPtrSetCur, gcInfo.gcRegGCrefSetCur,
+ gcInfo.gcRegByrefSetCur, ilOffset, indReg);
+ }
+ else
+ {
+ // -------------------------------------------------------------------------
+ // Check for a direct stub call.
+ //
- stubAddr = (void *) call->gtCall.gtStubCallStubAddr;
+ // Get stub addr. This will return NULL if virtual call stubs are not active
+ void* stubAddr = NULL;
- noway_assert(stubAddr != NULL);
+ stubAddr = (void*)call->gtCall.gtStubCallStubAddr;
- // -------------------------------------------------------------------------
- // Direct stub calls, though the stubAddr itself may still need to be
- // accesed via an indirection.
- //
+ noway_assert(stubAddr != NULL);
- // No need to null check - the dispatch code will deal with null this.
+ // -------------------------------------------------------------------------
+ // Direct stub calls, though the stubAddr itself may still need to be
+ // accesed via an indirection.
+ //
- emitter::EmitCallType callTypeStubAddr = emitter::EC_FUNC_ADDR;
- void* addr = stubAddr;
- int disp = 0;
- regNumber callReg = REG_NA;
+ // No need to null check - the dispatch code will deal with null this.
- if (call->gtCall.gtCallMoreFlags & GTF_CALL_M_VIRTSTUB_REL_INDIRECT)
- {
-#if CPU_LOAD_STORE_ARCH
- callReg = regSet.rsGrabReg(RBM_VIRTUAL_STUB_PARAM);
- noway_assert(callReg == REG_VIRTUAL_STUB_PARAM);
+ emitter::EmitCallType callTypeStubAddr = emitter::EC_FUNC_ADDR;
+ void* addr = stubAddr;
+ int disp = 0;
+ regNumber callReg = REG_NA;
- instGen_Set_Reg_To_Imm(EA_HANDLE_CNS_RELOC,REG_VIRTUAL_STUB_PARAM,(ssize_t)stubAddr);
- // The stub will write-back to this register, so don't track it
- regTracker.rsTrackRegTrash(REG_VIRTUAL_STUB_PARAM);
- getEmitter()->emitIns_R_R_I(INS_ldr, EA_PTRSIZE,REG_JUMP_THUNK_PARAM,REG_VIRTUAL_STUB_PARAM, 0);
- regTracker.rsTrackRegTrash(REG_JUMP_THUNK_PARAM);
- callTypeStubAddr = emitter::EC_INDIR_R;
- getEmitter()->emitIns_Call(emitter::EC_INDIR_R,
- NULL, // methHnd
- INDEBUG_LDISASM_COMMA(sigInfo)
- NULL, // addr
- args,
- retSize,
- gcInfo.gcVarPtrSetCur,
- gcInfo.gcRegGCrefSetCur,
- gcInfo.gcRegByrefSetCur,
- ilOffset,
- REG_JUMP_THUNK_PARAM);
+ if (call->gtCall.gtCallMoreFlags & GTF_CALL_M_VIRTSTUB_REL_INDIRECT)
+ {
+#if CPU_LOAD_STORE_ARCH
+ callReg = regSet.rsGrabReg(RBM_VIRTUAL_STUB_PARAM);
+ noway_assert(callReg == REG_VIRTUAL_STUB_PARAM);
+
+ instGen_Set_Reg_To_Imm(EA_HANDLE_CNS_RELOC, REG_VIRTUAL_STUB_PARAM, (ssize_t)stubAddr);
+ // The stub will write-back to this register, so don't track it
+ regTracker.rsTrackRegTrash(REG_VIRTUAL_STUB_PARAM);
+ getEmitter()->emitIns_R_R_I(INS_ldr, EA_PTRSIZE, REG_JUMP_THUNK_PARAM,
+ REG_VIRTUAL_STUB_PARAM, 0);
+ regTracker.rsTrackRegTrash(REG_JUMP_THUNK_PARAM);
+ callTypeStubAddr = emitter::EC_INDIR_R;
+ getEmitter()->emitIns_Call(emitter::EC_INDIR_R,
+ NULL, // methHnd
+ INDEBUG_LDISASM_COMMA(sigInfo) NULL, // addr
+ args, retSize, gcInfo.gcVarPtrSetCur, gcInfo.gcRegGCrefSetCur,
+ gcInfo.gcRegByrefSetCur, ilOffset, REG_JUMP_THUNK_PARAM);
#else
- // emit an indirect call
- callTypeStubAddr = emitter::EC_INDIR_C;
- addr = 0;
- disp = (ssize_t) stubAddr;
-#endif
-
- }
+ // emit an indirect call
+ callTypeStubAddr = emitter::EC_INDIR_C;
+ addr = 0;
+ disp = (ssize_t)stubAddr;
+#endif
+ }
#if CPU_LOAD_STORE_ARCH
- if (callTypeStubAddr != emitter::EC_INDIR_R)
+ if (callTypeStubAddr != emitter::EC_INDIR_R)
#endif
- {
- getEmitter()->emitIns_Call(callTypeStubAddr,
- call->gtCall.gtCallMethHnd,
- INDEBUG_LDISASM_COMMA(sigInfo)
- addr,
- args,
- retSize,
- gcInfo.gcVarPtrSetCur,
- gcInfo.gcRegGCrefSetCur,
- gcInfo.gcRegByrefSetCur,
- ilOffset,
- callReg,
- REG_NA,
- 0,
- disp);
+ {
+ getEmitter()->emitIns_Call(callTypeStubAddr, call->gtCall.gtCallMethHnd,
+ INDEBUG_LDISASM_COMMA(sigInfo) addr, args, retSize,
+ gcInfo.gcVarPtrSetCur, gcInfo.gcRegGCrefSetCur,
+ gcInfo.gcRegByrefSetCur, ilOffset, callReg, REG_NA, 0, disp);
+ }
}
}
- }
- else // tailCall is true
- {
+ else // tailCall is true
+ {
// Non-X86 tail calls materialize the null-check in fgMorphTailCall, when it
// moves the this pointer out of it's usual place and into the argument list.
#ifdef _TARGET_X86_
- // Generate "cmp ECX, [ECX]" to trap null pointers
- const regNumber regThis = genGetThisArgReg(call);
- getEmitter()->emitIns_AR_R(INS_cmp, EA_4BYTE, regThis, regThis, 0);
+ // Generate "cmp ECX, [ECX]" to trap null pointers
+ const regNumber regThis = genGetThisArgReg(call);
+ getEmitter()->emitIns_AR_R(INS_cmp, EA_4BYTE, regThis, regThis, 0);
#endif // _TARGET_X86_
- if (callType == CT_INDIRECT)
- {
- noway_assert(genStillAddressable(call->gtCall.gtCallAddr));
+ if (callType == CT_INDIRECT)
+ {
+ noway_assert(genStillAddressable(call->gtCall.gtCallAddr));
- // Now put the address in EAX.
- inst_RV_TT(INS_mov, REG_TAILCALL_ADDR, call->gtCall.gtCallAddr);
- regTracker.rsTrackRegTrash(REG_TAILCALL_ADDR);
+ // Now put the address in EAX.
+ inst_RV_TT(INS_mov, REG_TAILCALL_ADDR, call->gtCall.gtCallAddr);
+ regTracker.rsTrackRegTrash(REG_TAILCALL_ADDR);
- genDoneAddressable(call->gtCall.gtCallAddr, fptrRegs, RegSet::KEEP_REG);
- }
- else
- {
- // importer/EE should guarantee the indirection
- noway_assert(call->gtCall.gtCallMoreFlags & GTF_CALL_M_VIRTSTUB_REL_INDIRECT);
+ genDoneAddressable(call->gtCall.gtCallAddr, fptrRegs, RegSet::KEEP_REG);
+ }
+ else
+ {
+ // importer/EE should guarantee the indirection
+ noway_assert(call->gtCall.gtCallMoreFlags & GTF_CALL_M_VIRTSTUB_REL_INDIRECT);
- instGen_Set_Reg_To_Imm(EA_HANDLE_CNS_RELOC, REG_TAILCALL_ADDR, ssize_t(call->gtCall.gtStubCallStubAddr));
+ instGen_Set_Reg_To_Imm(EA_HANDLE_CNS_RELOC, REG_TAILCALL_ADDR,
+ ssize_t(call->gtCall.gtStubCallStubAddr));
+ }
+
+ fTailCallTargetIsVSD = true;
}
- fTailCallTargetIsVSD = true;
+ //
+ // OK to start inserting random NOPs again
+ //
+ getEmitter()->emitEnableRandomNops();
}
+ break;
- //
- // OK to start inserting random NOPs again
- //
- getEmitter()->emitEnableRandomNops();
- }
- break;
-
- case GTF_CALL_VIRT_VTABLE:
- // stub dispatching is off or this is not a virtual call (could be a tailcall)
- {
- regNumber vptrReg;
- unsigned vtabOffsOfIndirection;
- unsigned vtabOffsAfterIndirection;
+ case GTF_CALL_VIRT_VTABLE:
+ // stub dispatching is off or this is not a virtual call (could be a tailcall)
+ {
+ regNumber vptrReg;
+ unsigned vtabOffsOfIndirection;
+ unsigned vtabOffsAfterIndirection;
- noway_assert(callType == CT_USER_FUNC);
+ noway_assert(callType == CT_USER_FUNC);
- vptrReg = regSet.rsGrabReg(RBM_ALLINT); // Grab an available register to use for the CALL indirection
- vptrMask = genRegMask(vptrReg);
+ vptrReg =
+ regSet.rsGrabReg(RBM_ALLINT); // Grab an available register to use for the CALL indirection
+ vptrMask = genRegMask(vptrReg);
- /* The register no longer holds a live pointer value */
- gcInfo.gcMarkRegSetNpt(vptrMask);
+ /* The register no longer holds a live pointer value */
+ gcInfo.gcMarkRegSetNpt(vptrMask);
- // MOV vptrReg, [REG_CALL_THIS + offs]
- getEmitter()->emitIns_R_AR(ins_Load(TYP_I_IMPL), EA_PTRSIZE,
- vptrReg, genGetThisArgReg(call), VPTR_OFFS);
- regTracker.rsTrackRegTrash(vptrReg);
+ // MOV vptrReg, [REG_CALL_THIS + offs]
+ getEmitter()->emitIns_R_AR(ins_Load(TYP_I_IMPL), EA_PTRSIZE, vptrReg, genGetThisArgReg(call),
+ VPTR_OFFS);
+ regTracker.rsTrackRegTrash(vptrReg);
- noway_assert(vptrMask & ~call->gtCall.gtCallRegUsedMask);
+ noway_assert(vptrMask & ~call->gtCall.gtCallRegUsedMask);
- /* Get hold of the vtable offset (note: this might be expensive) */
+ /* Get hold of the vtable offset (note: this might be expensive) */
- compiler->info.compCompHnd->getMethodVTableOffset(call->gtCall.gtCallMethHnd, &vtabOffsOfIndirection, &vtabOffsAfterIndirection);
+ compiler->info.compCompHnd->getMethodVTableOffset(call->gtCall.gtCallMethHnd,
+ &vtabOffsOfIndirection,
+ &vtabOffsAfterIndirection);
- /* Get the appropriate vtable chunk */
+ /* Get the appropriate vtable chunk */
- /* The register no longer holds a live pointer value */
- gcInfo.gcMarkRegSetNpt(vptrMask);
+ /* The register no longer holds a live pointer value */
+ gcInfo.gcMarkRegSetNpt(vptrMask);
- // MOV vptrReg, [REG_CALL_IND_SCRATCH + vtabOffsOfIndirection]
- getEmitter()->emitIns_R_AR(ins_Load(TYP_I_IMPL), EA_PTRSIZE,
- vptrReg, vptrReg, vtabOffsOfIndirection);
+ // MOV vptrReg, [REG_CALL_IND_SCRATCH + vtabOffsOfIndirection]
+ getEmitter()->emitIns_R_AR(ins_Load(TYP_I_IMPL), EA_PTRSIZE, vptrReg, vptrReg,
+ vtabOffsOfIndirection);
- /* Call through the appropriate vtable slot */
+ /* Call through the appropriate vtable slot */
- if (fTailCall)
- {
- /* Load the function address: "[vptrReg+vtabOffs] -> reg_intret" */
+ if (fTailCall)
+ {
+ /* Load the function address: "[vptrReg+vtabOffs] -> reg_intret" */
- getEmitter()->emitIns_R_AR(ins_Load(TYP_I_IMPL), EA_PTRSIZE, REG_TAILCALL_ADDR,
- vptrReg, vtabOffsAfterIndirection);
- }
- else
- {
+ getEmitter()->emitIns_R_AR(ins_Load(TYP_I_IMPL), EA_PTRSIZE, REG_TAILCALL_ADDR, vptrReg,
+ vtabOffsAfterIndirection);
+ }
+ else
+ {
#if CPU_LOAD_STORE_ARCH
- getEmitter()->emitIns_R_AR(ins_Load(TYP_I_IMPL), EA_PTRSIZE, vptrReg, vptrReg, vtabOffsAfterIndirection);
-
- getEmitter()->emitIns_Call(emitter::EC_INDIR_R,
- call->gtCall.gtCallMethHnd,
- INDEBUG_LDISASM_COMMA(sigInfo)
- NULL, // addr
- args,
- retSize,
- gcInfo.gcVarPtrSetCur,
- gcInfo.gcRegGCrefSetCur,
- gcInfo.gcRegByrefSetCur,
- ilOffset,
- vptrReg); // ireg
+ getEmitter()->emitIns_R_AR(ins_Load(TYP_I_IMPL), EA_PTRSIZE, vptrReg, vptrReg,
+ vtabOffsAfterIndirection);
+
+ getEmitter()->emitIns_Call(emitter::EC_INDIR_R, call->gtCall.gtCallMethHnd,
+ INDEBUG_LDISASM_COMMA(sigInfo) NULL, // addr
+ args, retSize, gcInfo.gcVarPtrSetCur, gcInfo.gcRegGCrefSetCur,
+ gcInfo.gcRegByrefSetCur, ilOffset,
+ vptrReg); // ireg
#else
- getEmitter()->emitIns_Call(emitter::EC_FUNC_VIRTUAL,
- call->gtCall.gtCallMethHnd,
- INDEBUG_LDISASM_COMMA(sigInfo)
- NULL, // addr
- args,
- retSize,
- gcInfo.gcVarPtrSetCur,
- gcInfo.gcRegGCrefSetCur,
- gcInfo.gcRegByrefSetCur,
- ilOffset,
- vptrReg, // ireg
- REG_NA, // xreg
- 0, // xmul
- vtabOffsAfterIndirection); // disp
+ getEmitter()->emitIns_Call(emitter::EC_FUNC_VIRTUAL, call->gtCall.gtCallMethHnd,
+ INDEBUG_LDISASM_COMMA(sigInfo) NULL, // addr
+ args, retSize, gcInfo.gcVarPtrSetCur, gcInfo.gcRegGCrefSetCur,
+ gcInfo.gcRegByrefSetCur, ilOffset,
+ vptrReg, // ireg
+ REG_NA, // xreg
+ 0, // xmul
+ vtabOffsAfterIndirection); // disp
#endif // CPU_LOAD_STORE_ARCH
- }
- }
- break;
-
- case GTF_CALL_NONVIRT:
- {
- //------------------------ Non-virtual/Indirect calls -------------------------
- // Lots of cases follow
- // - Direct P/Invoke calls
- // - Indirect calls to P/Invoke functions via the P/Invoke stub
- // - Direct Helper calls
- // - Indirect Helper calls
- // - Direct calls to known addresses
- // - Direct calls where address is accessed by one or two indirections
- // - Indirect calls to computed addresses
- // - Tailcall versions of all of the above
+ }
+ }
+ break;
- CORINFO_METHOD_HANDLE methHnd = call->gtCall.gtCallMethHnd;
+ case GTF_CALL_NONVIRT:
+ {
+ //------------------------ Non-virtual/Indirect calls -------------------------
+ // Lots of cases follow
+ // - Direct P/Invoke calls
+ // - Indirect calls to P/Invoke functions via the P/Invoke stub
+ // - Direct Helper calls
+ // - Indirect Helper calls
+ // - Direct calls to known addresses
+ // - Direct calls where address is accessed by one or two indirections
+ // - Indirect calls to computed addresses
+ // - Tailcall versions of all of the above
+ CORINFO_METHOD_HANDLE methHnd = call->gtCall.gtCallMethHnd;
- //------------------------------------------------------
- // Non-virtual/Indirect calls: Insert a null check on the "this" pointer if needed
- //
- // For (final and private) functions which were called with
- // invokevirtual, but which we call directly, we need to
- // dereference the object pointer to make sure it's not NULL.
- //
+ //------------------------------------------------------
+ // Non-virtual/Indirect calls: Insert a null check on the "this" pointer if needed
+ //
+ // For (final and private) functions which were called with
+ // invokevirtual, but which we call directly, we need to
+ // dereference the object pointer to make sure it's not NULL.
+ //
- if (call->gtFlags & GTF_CALL_NULLCHECK)
- {
- /* Generate "cmp ECX, [ECX]" to trap null pointers */
- const regNumber regThis = genGetThisArgReg(call);
+ if (call->gtFlags & GTF_CALL_NULLCHECK)
+ {
+ /* Generate "cmp ECX, [ECX]" to trap null pointers */
+ const regNumber regThis = genGetThisArgReg(call);
#if CPU_LOAD_STORE_ARCH
- regNumber indReg = regSet.rsGrabReg(RBM_ALLINT); // Grab an available register to use for the indirection
- getEmitter()->emitIns_R_R_I(INS_ldr, EA_4BYTE, indReg, regThis, 0);
- regTracker.rsTrackRegTrash(indReg);
+ regNumber indReg =
+ regSet.rsGrabReg(RBM_ALLINT); // Grab an available register to use for the indirection
+ getEmitter()->emitIns_R_R_I(INS_ldr, EA_4BYTE, indReg, regThis, 0);
+ regTracker.rsTrackRegTrash(indReg);
#else
- getEmitter()->emitIns_AR_R(INS_cmp, EA_4BYTE, regThis, regThis, 0);
+ getEmitter()->emitIns_AR_R(INS_cmp, EA_4BYTE, regThis, regThis, 0);
#endif
- }
-
- if (call->gtFlags & GTF_CALL_UNMANAGED)
- {
- //------------------------------------------------------
- // Non-virtual/Indirect calls: PInvoke calls.
+ }
- noway_assert(compiler->info.compCallUnmanaged != 0);
+ if (call->gtFlags & GTF_CALL_UNMANAGED)
+ {
+ //------------------------------------------------------
+ // Non-virtual/Indirect calls: PInvoke calls.
- /* args shouldn't be greater than 64K */
+ noway_assert(compiler->info.compCallUnmanaged != 0);
- noway_assert((argSize&0xffff0000) == 0);
+ /* args shouldn't be greater than 64K */
- /* Remember the varDsc for the callsite-epilog */
+ noway_assert((argSize & 0xffff0000) == 0);
- frameListRoot = &compiler->lvaTable[compiler->info.compLvFrameListRoot];
+ /* Remember the varDsc for the callsite-epilog */
- // exact codegen is required
- getEmitter()->emitDisableRandomNops();
+ frameListRoot = &compiler->lvaTable[compiler->info.compLvFrameListRoot];
- int nArgSize = 0;
+ // exact codegen is required
+ getEmitter()->emitDisableRandomNops();
- regNumber indCallReg = REG_NA;
+ int nArgSize = 0;
- if (callType == CT_INDIRECT)
- {
- noway_assert(genStillAddressable(call->gtCall.gtCallAddr));
+ regNumber indCallReg = REG_NA;
- if (call->gtCall.gtCallAddr->gtFlags & GTF_REG_VAL)
- indCallReg = call->gtCall.gtCallAddr->gtRegNum;
+ if (callType == CT_INDIRECT)
+ {
+ noway_assert(genStillAddressable(call->gtCall.gtCallAddr));
- nArgSize = (call->gtFlags & GTF_CALL_POP_ARGS) ? 0 : (int)argSize;
- methHnd = 0;
- }
- else
- {
- noway_assert(callType == CT_USER_FUNC);
- }
+ if (call->gtCall.gtCallAddr->gtFlags & GTF_REG_VAL)
+ indCallReg = call->gtCall.gtCallAddr->gtRegNum;
- regNumber tcbReg;
- tcbReg = genPInvokeCallProlog(frameListRoot, nArgSize, methHnd, returnLabel);
+ nArgSize = (call->gtFlags & GTF_CALL_POP_ARGS) ? 0 : (int)argSize;
+ methHnd = 0;
+ }
+ else
+ {
+ noway_assert(callType == CT_USER_FUNC);
+ }
- void* addr = NULL;
+ regNumber tcbReg;
+ tcbReg = genPInvokeCallProlog(frameListRoot, nArgSize, methHnd, returnLabel);
- if (callType == CT_INDIRECT)
- {
- /* Double check that the callee didn't use/trash the
- registers holding the call target.
- */
- noway_assert(tcbReg != indCallReg);
+ void* addr = NULL;
- if (indCallReg == REG_NA)
+ if (callType == CT_INDIRECT)
{
- indCallReg = regSet.rsGrabReg(RBM_ALLINT); // Grab an available register to use for the CALL indirection
-
- /* Please note that this even works with tcbReg == REG_EAX.
- tcbReg contains an interesting value only if frameListRoot is
- an enregistered local that stays alive across the call
- (certainly not EAX). If frameListRoot has been moved into
- EAX, we can trash it since it won't survive across the call
- anyways.
+ /* Double check that the callee didn't use/trash the
+ registers holding the call target.
*/
+ noway_assert(tcbReg != indCallReg);
- inst_RV_TT(INS_mov, indCallReg, call->gtCall.gtCallAddr);
- regTracker.rsTrackRegTrash(indCallReg);
- }
-
- emitCallType = emitter::EC_INDIR_R;
- }
- else
- {
- noway_assert(callType == CT_USER_FUNC);
-
- void* pAddr;
- addr = compiler->info.compCompHnd->getAddressOfPInvokeFixup(methHnd, (void**)&pAddr);
- if (addr != NULL)
- {
-#if CPU_LOAD_STORE_ARCH
- // Load the address into a register, indirect it and call through a register
- indCallReg = regSet.rsGrabReg(RBM_ALLINT); // Grab an available register to use for the CALL indirection
- instGen_Set_Reg_To_Imm(EA_HANDLE_CNS_RELOC, indCallReg, (ssize_t)addr);
- getEmitter()->emitIns_R_R_I(INS_ldr, EA_PTRSIZE, indCallReg, indCallReg, 0);
- regTracker.rsTrackRegTrash(indCallReg);
- // Now make the call "call indCallReg"
-
- getEmitter()->emitIns_Call(emitter::EC_INDIR_R,
- methHnd, // methHnd
- INDEBUG_LDISASM_COMMA(sigInfo) // sigInfo
- NULL, // addr
- args,
- retSize,
- gcInfo.gcVarPtrSetCur,
- gcInfo.gcRegGCrefSetCur,
- gcInfo.gcRegByrefSetCur,
- ilOffset,
- indCallReg);
+ if (indCallReg == REG_NA)
+ {
+ indCallReg = regSet.rsGrabReg(RBM_ALLINT); // Grab an available register to use for the CALL
+ // indirection
+
+ /* Please note that this even works with tcbReg == REG_EAX.
+ tcbReg contains an interesting value only if frameListRoot is
+ an enregistered local that stays alive across the call
+ (certainly not EAX). If frameListRoot has been moved into
+ EAX, we can trash it since it won't survive across the call
+ anyways.
+ */
+
+ inst_RV_TT(INS_mov, indCallReg, call->gtCall.gtCallAddr);
+ regTracker.rsTrackRegTrash(indCallReg);
+ }
emitCallType = emitter::EC_INDIR_R;
- break;
-#else
- emitCallType = emitter::EC_FUNC_TOKEN_INDIR;
- indCallReg = REG_NA;
-#endif
}
else
{
- // Double-indirection. Load the address into a register
- // and call indirectly through a register
- indCallReg = regSet.rsGrabReg(RBM_ALLINT); // Grab an available register to use for the CALL indirection
+ noway_assert(callType == CT_USER_FUNC);
+
+ void* pAddr;
+ addr = compiler->info.compCompHnd->getAddressOfPInvokeFixup(methHnd, (void**)&pAddr);
+ if (addr != NULL)
+ {
+#if CPU_LOAD_STORE_ARCH
+ // Load the address into a register, indirect it and call through a register
+ indCallReg = regSet.rsGrabReg(RBM_ALLINT); // Grab an available register to use for the CALL
+ // indirection
+ instGen_Set_Reg_To_Imm(EA_HANDLE_CNS_RELOC, indCallReg, (ssize_t)addr);
+ getEmitter()->emitIns_R_R_I(INS_ldr, EA_PTRSIZE, indCallReg, indCallReg, 0);
+ regTracker.rsTrackRegTrash(indCallReg);
+ // Now make the call "call indCallReg"
+
+ getEmitter()->emitIns_Call(emitter::EC_INDIR_R,
+ methHnd, // methHnd
+ INDEBUG_LDISASM_COMMA(sigInfo) // sigInfo
+ NULL, // addr
+ args,
+ retSize, gcInfo.gcVarPtrSetCur, gcInfo.gcRegGCrefSetCur,
+ gcInfo.gcRegByrefSetCur, ilOffset, indCallReg);
+
+ emitCallType = emitter::EC_INDIR_R;
+ break;
+#else
+ emitCallType = emitter::EC_FUNC_TOKEN_INDIR;
+ indCallReg = REG_NA;
+#endif
+ }
+ else
+ {
+ // Double-indirection. Load the address into a register
+ // and call indirectly through a register
+ indCallReg = regSet.rsGrabReg(RBM_ALLINT); // Grab an available register to use for the CALL
+ // indirection
#if CPU_LOAD_STORE_ARCH
- instGen_Set_Reg_To_Imm(EA_HANDLE_CNS_RELOC, indCallReg, (ssize_t)pAddr);
- getEmitter()->emitIns_R_R_I(INS_ldr, EA_PTRSIZE, indCallReg, indCallReg, 0);
- getEmitter()->emitIns_R_R_I(INS_ldr, EA_PTRSIZE, indCallReg, indCallReg, 0);
- regTracker.rsTrackRegTrash(indCallReg);
+ instGen_Set_Reg_To_Imm(EA_HANDLE_CNS_RELOC, indCallReg, (ssize_t)pAddr);
+ getEmitter()->emitIns_R_R_I(INS_ldr, EA_PTRSIZE, indCallReg, indCallReg, 0);
+ getEmitter()->emitIns_R_R_I(INS_ldr, EA_PTRSIZE, indCallReg, indCallReg, 0);
+ regTracker.rsTrackRegTrash(indCallReg);
- emitCallType = emitter::EC_INDIR_R;
+ emitCallType = emitter::EC_INDIR_R;
#else
- getEmitter()->emitIns_R_AI(INS_mov,
- EA_PTR_DSP_RELOC,
- indCallReg,
- (ssize_t)pAddr);
- regTracker.rsTrackRegTrash(indCallReg);
- emitCallType = emitter::EC_INDIR_ARD;
+ getEmitter()->emitIns_R_AI(INS_mov, EA_PTR_DSP_RELOC, indCallReg, (ssize_t)pAddr);
+ regTracker.rsTrackRegTrash(indCallReg);
+ emitCallType = emitter::EC_INDIR_ARD;
#endif // CPU_LOAD_STORE_ARCH
+ }
}
- }
- getEmitter()->emitIns_Call(emitCallType,
- compiler->eeMarkNativeTarget(methHnd),
- INDEBUG_LDISASM_COMMA(sigInfo)
- addr,
- args,
- retSize,
- gcInfo.gcVarPtrSetCur,
- gcInfo.gcRegGCrefSetCur,
- gcInfo.gcRegByrefSetCur,
- ilOffset,
- indCallReg);
+ getEmitter()->emitIns_Call(emitCallType, compiler->eeMarkNativeTarget(methHnd),
+ INDEBUG_LDISASM_COMMA(sigInfo) addr, args, retSize,
+ gcInfo.gcVarPtrSetCur, gcInfo.gcRegGCrefSetCur, gcInfo.gcRegByrefSetCur,
+ ilOffset, indCallReg);
- if (callType == CT_INDIRECT)
- genDoneAddressable(call->gtCall.gtCallAddr, fptrRegs, RegSet::KEEP_REG);
+ if (callType == CT_INDIRECT)
+ genDoneAddressable(call->gtCall.gtCallAddr, fptrRegs, RegSet::KEEP_REG);
- getEmitter()->emitEnableRandomNops();
-
- // Done with PInvoke calls
- break;
- }
+ getEmitter()->emitEnableRandomNops();
- if (callType == CT_INDIRECT)
- {
- noway_assert(genStillAddressable(call->gtCall.gtCallAddr));
+ // Done with PInvoke calls
+ break;
+ }
- if (call->gtCall.gtCallCookie)
+ if (callType == CT_INDIRECT)
{
- //------------------------------------------------------
- // Non-virtual indirect calls via the P/Invoke stub
+ noway_assert(genStillAddressable(call->gtCall.gtCallAddr));
- GenTreePtr cookie = call->gtCall.gtCallCookie;
- GenTreePtr target = call->gtCall.gtCallAddr;
+ if (call->gtCall.gtCallCookie)
+ {
+ //------------------------------------------------------
+ // Non-virtual indirect calls via the P/Invoke stub
+
+ GenTreePtr cookie = call->gtCall.gtCallCookie;
+ GenTreePtr target = call->gtCall.gtCallAddr;
- noway_assert((call->gtFlags & GTF_CALL_POP_ARGS) == 0);
+ noway_assert((call->gtFlags & GTF_CALL_POP_ARGS) == 0);
- noway_assert(cookie->gtOper == GT_CNS_INT ||
- cookie->gtOper == GT_IND && cookie->gtOp.gtOp1->gtOper == GT_CNS_INT);
+ noway_assert(cookie->gtOper == GT_CNS_INT ||
+ cookie->gtOper == GT_IND && cookie->gtOp.gtOp1->gtOper == GT_CNS_INT);
- noway_assert(args == argSize);
+ noway_assert(args == argSize);
#if defined(_TARGET_X86_)
- /* load eax with the real target */
+ /* load eax with the real target */
- inst_RV_TT(INS_mov, REG_EAX, target);
- regTracker.rsTrackRegTrash(REG_EAX);
+ inst_RV_TT(INS_mov, REG_EAX, target);
+ regTracker.rsTrackRegTrash(REG_EAX);
- if (cookie->gtOper == GT_CNS_INT)
- inst_IV_handle(INS_push, cookie->gtIntCon.gtIconVal);
- else
- inst_TT(INS_push, cookie);
+ if (cookie->gtOper == GT_CNS_INT)
+ inst_IV_handle(INS_push, cookie->gtIntCon.gtIconVal);
+ else
+ inst_TT(INS_push, cookie);
- /* Keep track of ESP for EBP-less frames */
- genSinglePush();
+ /* Keep track of ESP for EBP-less frames */
+ genSinglePush();
- argSize += sizeof(void *);
+ argSize += sizeof(void*);
#elif defined(_TARGET_ARM_)
- // Ensure that we spill these registers (if caller saved) in the prolog
- regSet.rsSetRegsModified(RBM_PINVOKE_COOKIE_PARAM | RBM_PINVOKE_TARGET_PARAM);
+ // Ensure that we spill these registers (if caller saved) in the prolog
+ regSet.rsSetRegsModified(RBM_PINVOKE_COOKIE_PARAM | RBM_PINVOKE_TARGET_PARAM);
- // ARM: load r12 with the real target
- // X64: load r10 with the real target
- inst_RV_TT(INS_mov, REG_PINVOKE_TARGET_PARAM, target);
- regTracker.rsTrackRegTrash(REG_PINVOKE_TARGET_PARAM);
+ // ARM: load r12 with the real target
+ // X64: load r10 with the real target
+ inst_RV_TT(INS_mov, REG_PINVOKE_TARGET_PARAM, target);
+ regTracker.rsTrackRegTrash(REG_PINVOKE_TARGET_PARAM);
- // ARM: load r4 with the pinvoke VASigCookie
- // X64: load r11 with the pinvoke VASigCookie
- if (cookie->gtOper == GT_CNS_INT)
- inst_RV_IV(INS_mov, REG_PINVOKE_COOKIE_PARAM, cookie->gtIntCon.gtIconVal, EA_HANDLE_CNS_RELOC);
- else
- inst_RV_TT(INS_mov, REG_PINVOKE_COOKIE_PARAM, cookie);
- regTracker.rsTrackRegTrash(REG_PINVOKE_COOKIE_PARAM);
+ // ARM: load r4 with the pinvoke VASigCookie
+ // X64: load r11 with the pinvoke VASigCookie
+ if (cookie->gtOper == GT_CNS_INT)
+ inst_RV_IV(INS_mov, REG_PINVOKE_COOKIE_PARAM, cookie->gtIntCon.gtIconVal,
+ EA_HANDLE_CNS_RELOC);
+ else
+ inst_RV_TT(INS_mov, REG_PINVOKE_COOKIE_PARAM, cookie);
+ regTracker.rsTrackRegTrash(REG_PINVOKE_COOKIE_PARAM);
- noway_assert(args == argSize);
+ noway_assert(args == argSize);
- // Ensure that we don't trash any of these registers if we have to load
- // the helper call target into a register to invoke it.
- regMaskTP regsUsed;
- regSet.rsLockReg(call->gtCall.gtCallRegUsedMask|RBM_PINVOKE_TARGET_PARAM|RBM_PINVOKE_COOKIE_PARAM, &regsUsed);
+ // Ensure that we don't trash any of these registers if we have to load
+ // the helper call target into a register to invoke it.
+ regMaskTP regsUsed;
+ regSet.rsLockReg(call->gtCall.gtCallRegUsedMask | RBM_PINVOKE_TARGET_PARAM |
+ RBM_PINVOKE_COOKIE_PARAM,
+ &regsUsed);
#else
- NYI("Non-virtual indirect calls via the P/Invoke stub");
+ NYI("Non-virtual indirect calls via the P/Invoke stub");
#endif
- args = argSize;
- noway_assert((size_t)(int)args == args);
+ args = argSize;
+ noway_assert((size_t)(int)args == args);
- genEmitHelperCall(CORINFO_HELP_PINVOKE_CALLI, (int)args, retSize);
+ genEmitHelperCall(CORINFO_HELP_PINVOKE_CALLI, (int)args, retSize);
#if defined(_TARGET_ARM_)
- regSet.rsUnlockReg(call->gtCall.gtCallRegUsedMask|RBM_PINVOKE_TARGET_PARAM|RBM_PINVOKE_COOKIE_PARAM, regsUsed);
+ regSet.rsUnlockReg(call->gtCall.gtCallRegUsedMask | RBM_PINVOKE_TARGET_PARAM |
+ RBM_PINVOKE_COOKIE_PARAM,
+ regsUsed);
#endif
#ifdef _TARGET_ARM_
- // genEmitHelperCall doesn't record all registers a helper call would trash.
- regTracker.rsTrackRegTrash(REG_PINVOKE_COOKIE_PARAM);
+ // genEmitHelperCall doesn't record all registers a helper call would trash.
+ regTracker.rsTrackRegTrash(REG_PINVOKE_COOKIE_PARAM);
#endif
-
- }
- else
- {
- //------------------------------------------------------
- // Non-virtual indirect calls
-
- if (fTailCall)
- {
- inst_RV_TT(INS_mov, REG_TAILCALL_ADDR, call->gtCall.gtCallAddr);
- regTracker.rsTrackRegTrash(REG_TAILCALL_ADDR);
}
else
- instEmit_indCall(call, args, retSize);
- }
+ {
+ //------------------------------------------------------
+ // Non-virtual indirect calls
- genDoneAddressable(call->gtCall.gtCallAddr, fptrRegs, RegSet::KEEP_REG);
+ if (fTailCall)
+ {
+ inst_RV_TT(INS_mov, REG_TAILCALL_ADDR, call->gtCall.gtCallAddr);
+ regTracker.rsTrackRegTrash(REG_TAILCALL_ADDR);
+ }
+ else
+ instEmit_indCall(call, args, retSize);
+ }
- // Done with indirect calls
- break;
- }
+ genDoneAddressable(call->gtCall.gtCallAddr, fptrRegs, RegSet::KEEP_REG);
- //------------------------------------------------------
- // Non-virtual direct/indirect calls: Work out if the address of the
- // call is known at JIT time (if not it is either an indirect call
- // or the address must be accessed via an single/double indirection)
+ // Done with indirect calls
+ break;
+ }
- noway_assert(callType == CT_USER_FUNC || callType == CT_HELPER);
+ //------------------------------------------------------
+ // Non-virtual direct/indirect calls: Work out if the address of the
+ // call is known at JIT time (if not it is either an indirect call
+ // or the address must be accessed via an single/double indirection)
- void * addr;
- InfoAccessType accessType;
+ noway_assert(callType == CT_USER_FUNC || callType == CT_HELPER);
- helperNum = compiler->eeGetHelperNum(methHnd);
+ void* addr;
+ InfoAccessType accessType;
- if (callType == CT_HELPER)
- {
- noway_assert(helperNum != CORINFO_HELP_UNDEF);
+ helperNum = compiler->eeGetHelperNum(methHnd);
- void * pAddr;
- addr = compiler->compGetHelperFtn(helperNum, (void**)&pAddr);
+ if (callType == CT_HELPER)
+ {
+ noway_assert(helperNum != CORINFO_HELP_UNDEF);
- accessType = IAT_VALUE;
+ void* pAddr;
+ addr = compiler->compGetHelperFtn(helperNum, (void**)&pAddr);
- if (!addr)
- {
- accessType = IAT_PVALUE;
- addr = pAddr;
- }
- }
- else
- {
- noway_assert(helperNum == CORINFO_HELP_UNDEF);
+ accessType = IAT_VALUE;
- CORINFO_ACCESS_FLAGS aflags = CORINFO_ACCESS_ANY;
+ if (!addr)
+ {
+ accessType = IAT_PVALUE;
+ addr = pAddr;
+ }
+ }
+ else
+ {
+ noway_assert(helperNum == CORINFO_HELP_UNDEF);
- if (call->gtCall.gtCallMoreFlags & GTF_CALL_M_NONVIRT_SAME_THIS)
- aflags = (CORINFO_ACCESS_FLAGS)(aflags | CORINFO_ACCESS_THIS);
+ CORINFO_ACCESS_FLAGS aflags = CORINFO_ACCESS_ANY;
- if ((call->gtFlags & GTF_CALL_NULLCHECK) == 0)
- aflags = (CORINFO_ACCESS_FLAGS)(aflags | CORINFO_ACCESS_NONNULL);
+ if (call->gtCall.gtCallMoreFlags & GTF_CALL_M_NONVIRT_SAME_THIS)
+ aflags = (CORINFO_ACCESS_FLAGS)(aflags | CORINFO_ACCESS_THIS);
- CORINFO_CONST_LOOKUP addrInfo;
- compiler->info.compCompHnd->getFunctionEntryPoint(methHnd, &addrInfo, aflags);
+ if ((call->gtFlags & GTF_CALL_NULLCHECK) == 0)
+ aflags = (CORINFO_ACCESS_FLAGS)(aflags | CORINFO_ACCESS_NONNULL);
- accessType = addrInfo.accessType;
- addr = addrInfo.addr;
- }
+ CORINFO_CONST_LOOKUP addrInfo;
+ compiler->info.compCompHnd->getFunctionEntryPoint(methHnd, &addrInfo, aflags);
- if (fTailCall)
- {
- noway_assert(callType == CT_USER_FUNC);
+ accessType = addrInfo.accessType;
+ addr = addrInfo.addr;
+ }
- switch (accessType)
+ if (fTailCall)
{
- case IAT_VALUE:
- //------------------------------------------------------
- // Non-virtual direct calls to known addressess
- //
- instGen_Set_Reg_To_Imm(EA_HANDLE_CNS_RELOC, REG_TAILCALL_ADDR, (ssize_t)addr);
- break;
+ noway_assert(callType == CT_USER_FUNC);
- case IAT_PVALUE:
- //------------------------------------------------------
- // Non-virtual direct calls to addresses accessed by
- // a single indirection.
- //
- // For tailcalls we place the target address in REG_TAILCALL_ADDR
- CLANG_FORMAT_COMMENT_ANCHOR;
+ switch (accessType)
+ {
+ case IAT_VALUE:
+ //------------------------------------------------------
+ // Non-virtual direct calls to known addressess
+ //
+ instGen_Set_Reg_To_Imm(EA_HANDLE_CNS_RELOC, REG_TAILCALL_ADDR, (ssize_t)addr);
+ break;
+
+ case IAT_PVALUE:
+ //------------------------------------------------------
+ // Non-virtual direct calls to addresses accessed by
+ // a single indirection.
+ //
+ // For tailcalls we place the target address in REG_TAILCALL_ADDR
+ CLANG_FORMAT_COMMENT_ANCHOR;
#if CPU_LOAD_STORE_ARCH
- {
- regNumber indReg = REG_TAILCALL_ADDR;
- instGen_Set_Reg_To_Imm(EA_HANDLE_CNS_RELOC, indReg, (ssize_t)addr);
- getEmitter()->emitIns_R_R_I(INS_ldr, EA_4BYTE, indReg, indReg, 0);
- regTracker.rsTrackRegTrash(indReg);
- }
+ {
+ regNumber indReg = REG_TAILCALL_ADDR;
+ instGen_Set_Reg_To_Imm(EA_HANDLE_CNS_RELOC, indReg, (ssize_t)addr);
+ getEmitter()->emitIns_R_R_I(INS_ldr, EA_4BYTE, indReg, indReg, 0);
+ regTracker.rsTrackRegTrash(indReg);
+ }
#else
- getEmitter()->emitIns_R_AI(INS_mov, EA_PTR_DSP_RELOC, REG_TAILCALL_ADDR,
- (ssize_t)addr);
- regTracker.rsTrackRegTrash(REG_TAILCALL_ADDR);
+ getEmitter()->emitIns_R_AI(INS_mov, EA_PTR_DSP_RELOC, REG_TAILCALL_ADDR, (ssize_t)addr);
+ regTracker.rsTrackRegTrash(REG_TAILCALL_ADDR);
#endif
- break;
+ break;
- case IAT_PPVALUE:
- //------------------------------------------------------
- // Non-virtual direct calls to addresses accessed by
- // a double indirection.
- //
- // For tailcalls we place the target address in REG_TAILCALL_ADDR
- CLANG_FORMAT_COMMENT_ANCHOR;
+ case IAT_PPVALUE:
+ //------------------------------------------------------
+ // Non-virtual direct calls to addresses accessed by
+ // a double indirection.
+ //
+ // For tailcalls we place the target address in REG_TAILCALL_ADDR
+ CLANG_FORMAT_COMMENT_ANCHOR;
#if CPU_LOAD_STORE_ARCH
- {
- regNumber indReg = REG_TAILCALL_ADDR;
- instGen_Set_Reg_To_Imm(EA_HANDLE_CNS_RELOC, indReg, (ssize_t)addr);
- getEmitter()->emitIns_R_R_I(INS_ldr, EA_4BYTE, indReg, indReg, 0);
- getEmitter()->emitIns_R_R_I(INS_ldr, EA_4BYTE, indReg, indReg, 0);
- regTracker.rsTrackRegTrash(indReg);
- }
+ {
+ regNumber indReg = REG_TAILCALL_ADDR;
+ instGen_Set_Reg_To_Imm(EA_HANDLE_CNS_RELOC, indReg, (ssize_t)addr);
+ getEmitter()->emitIns_R_R_I(INS_ldr, EA_4BYTE, indReg, indReg, 0);
+ getEmitter()->emitIns_R_R_I(INS_ldr, EA_4BYTE, indReg, indReg, 0);
+ regTracker.rsTrackRegTrash(indReg);
+ }
#else
- getEmitter()->emitIns_R_AI(INS_mov, EA_PTR_DSP_RELOC, REG_TAILCALL_ADDR,
- (ssize_t)addr);
- getEmitter()->emitIns_R_AR(ins_Load(TYP_I_IMPL), EA_PTRSIZE, REG_TAILCALL_ADDR,
- REG_TAILCALL_ADDR, 0);
- regTracker.rsTrackRegTrash(REG_TAILCALL_ADDR);
+ getEmitter()->emitIns_R_AI(INS_mov, EA_PTR_DSP_RELOC, REG_TAILCALL_ADDR, (ssize_t)addr);
+ getEmitter()->emitIns_R_AR(ins_Load(TYP_I_IMPL), EA_PTRSIZE, REG_TAILCALL_ADDR,
+ REG_TAILCALL_ADDR, 0);
+ regTracker.rsTrackRegTrash(REG_TAILCALL_ADDR);
#endif
- break;
+ break;
- default:
- noway_assert(!"Bad accessType");
- break;
+ default:
+ noway_assert(!"Bad accessType");
+ break;
+ }
}
- }
- else
- {
- switch (accessType)
+ else
{
- regNumber indCallReg;
+ switch (accessType)
+ {
+ regNumber indCallReg;
- case IAT_VALUE:
- //------------------------------------------------------
- // Non-virtual direct calls to known addressess
- //
- // The vast majority of calls end up here.... Wouldn't
- // it be nice if they all did!
- CLANG_FORMAT_COMMENT_ANCHOR;
+ case IAT_VALUE:
+ //------------------------------------------------------
+ // Non-virtual direct calls to known addressess
+ //
+ // The vast majority of calls end up here.... Wouldn't
+ // it be nice if they all did!
+ CLANG_FORMAT_COMMENT_ANCHOR;
#ifdef _TARGET_ARM_
- if (!arm_Valid_Imm_For_BL((ssize_t)addr))
- {
- // Load the address into a register and call through a register
- indCallReg = regSet.rsGrabReg(RBM_ALLINT); // Grab an available register to use for the CALL indirection
- instGen_Set_Reg_To_Imm(EA_HANDLE_CNS_RELOC, indCallReg, (ssize_t)addr);
-
- getEmitter()->emitIns_Call(emitter::EC_INDIR_R,
- methHnd,
- INDEBUG_LDISASM_COMMA(sigInfo)
- NULL, // addr
- args,
- retSize,
- gcInfo.gcVarPtrSetCur,
- gcInfo.gcRegGCrefSetCur,
- gcInfo.gcRegByrefSetCur,
- ilOffset,
- indCallReg, // ireg
- REG_NA, 0, 0, // xreg, xmul, disp
- false, // isJump
- emitter::emitNoGChelper(helperNum));
- }
- else
+ if (!arm_Valid_Imm_For_BL((ssize_t)addr))
+ {
+ // Load the address into a register and call through a register
+ indCallReg = regSet.rsGrabReg(RBM_ALLINT); // Grab an available register to use for the
+ // CALL indirection
+ instGen_Set_Reg_To_Imm(EA_HANDLE_CNS_RELOC, indCallReg, (ssize_t)addr);
+
+ getEmitter()->emitIns_Call(emitter::EC_INDIR_R, methHnd,
+ INDEBUG_LDISASM_COMMA(sigInfo) NULL, // addr
+ args, retSize, gcInfo.gcVarPtrSetCur,
+ gcInfo.gcRegGCrefSetCur, gcInfo.gcRegByrefSetCur, ilOffset,
+ indCallReg, // ireg
+ REG_NA, 0, 0, // xreg, xmul, disp
+ false, // isJump
+ emitter::emitNoGChelper(helperNum));
+ }
+ else
#endif
- {
- getEmitter()->emitIns_Call(emitter::EC_FUNC_TOKEN,
- methHnd,
- INDEBUG_LDISASM_COMMA(sigInfo)
- addr,
- args,
- retSize,
- gcInfo.gcVarPtrSetCur,
- gcInfo.gcRegGCrefSetCur,
- gcInfo.gcRegByrefSetCur,
- ilOffset,
- REG_NA, REG_NA, 0, 0, /* ireg, xreg, xmul, disp */
- false, /* isJump */
- emitter::emitNoGChelper(helperNum));
- }
- break;
+ {
+ getEmitter()->emitIns_Call(emitter::EC_FUNC_TOKEN, methHnd,
+ INDEBUG_LDISASM_COMMA(sigInfo) addr, args, retSize,
+ gcInfo.gcVarPtrSetCur, gcInfo.gcRegGCrefSetCur,
+ gcInfo.gcRegByrefSetCur, ilOffset, REG_NA, REG_NA, 0,
+ 0, /* ireg, xreg, xmul, disp */
+ false, /* isJump */
+ emitter::emitNoGChelper(helperNum));
+ }
+ break;
- case IAT_PVALUE:
- //------------------------------------------------------
- // Non-virtual direct calls to addresses accessed by
- // a single indirection.
- //
+ case IAT_PVALUE:
+ //------------------------------------------------------
+ // Non-virtual direct calls to addresses accessed by
+ // a single indirection.
+ //
- // Load the address into a register, load indirect and call through a register
- CLANG_FORMAT_COMMENT_ANCHOR;
+ // Load the address into a register, load indirect and call through a register
+ CLANG_FORMAT_COMMENT_ANCHOR;
#if CPU_LOAD_STORE_ARCH
- indCallReg = regSet.rsGrabReg(RBM_ALLINT); // Grab an available register to use for the CALL indirection
+ indCallReg = regSet.rsGrabReg(RBM_ALLINT); // Grab an available register to use for the CALL
+ // indirection
- instGen_Set_Reg_To_Imm(EA_HANDLE_CNS_RELOC, indCallReg, (ssize_t)addr);
- getEmitter()->emitIns_R_R_I(INS_ldr, EA_PTRSIZE, indCallReg, indCallReg, 0);
- regTracker.rsTrackRegTrash(indCallReg);
+ instGen_Set_Reg_To_Imm(EA_HANDLE_CNS_RELOC, indCallReg, (ssize_t)addr);
+ getEmitter()->emitIns_R_R_I(INS_ldr, EA_PTRSIZE, indCallReg, indCallReg, 0);
+ regTracker.rsTrackRegTrash(indCallReg);
- emitCallType = emitter::EC_INDIR_R;
- addr = NULL;
+ emitCallType = emitter::EC_INDIR_R;
+ addr = NULL;
#else
- emitCallType = emitter::EC_FUNC_TOKEN_INDIR;
- indCallReg = REG_NA;
+ emitCallType = emitter::EC_FUNC_TOKEN_INDIR;
+ indCallReg = REG_NA;
#endif // CPU_LOAD_STORE_ARCH
- getEmitter()->emitIns_Call( emitCallType,
- methHnd,
- INDEBUG_LDISASM_COMMA(sigInfo)
- addr,
- args,
- retSize,
- gcInfo.gcVarPtrSetCur,
- gcInfo.gcRegGCrefSetCur,
- gcInfo.gcRegByrefSetCur,
- ilOffset,
- indCallReg, // ireg
- REG_NA, 0, 0, // xreg, xmul, disp
- false, /* isJump */
- emitter::emitNoGChelper(helperNum));
- break;
+ getEmitter()->emitIns_Call(emitCallType, methHnd, INDEBUG_LDISASM_COMMA(sigInfo) addr, args,
+ retSize, gcInfo.gcVarPtrSetCur, gcInfo.gcRegGCrefSetCur,
+ gcInfo.gcRegByrefSetCur, ilOffset,
+ indCallReg, // ireg
+ REG_NA, 0, 0, // xreg, xmul, disp
+ false, /* isJump */
+ emitter::emitNoGChelper(helperNum));
+ break;
- case IAT_PPVALUE:
- {
- //------------------------------------------------------
- // Non-virtual direct calls to addresses accessed by
- // a double indirection.
- //
- // Double-indirection. Load the address into a register
- // and call indirectly through the register
+ case IAT_PPVALUE:
+ {
+ //------------------------------------------------------
+ // Non-virtual direct calls to addresses accessed by
+ // a double indirection.
+ //
+ // Double-indirection. Load the address into a register
+ // and call indirectly through the register
- noway_assert(helperNum == CORINFO_HELP_UNDEF);
+ noway_assert(helperNum == CORINFO_HELP_UNDEF);
- // Grab an available register to use for the CALL indirection
- indCallReg = regSet.rsGrabReg(RBM_ALLINT);
+ // Grab an available register to use for the CALL indirection
+ indCallReg = regSet.rsGrabReg(RBM_ALLINT);
#if CPU_LOAD_STORE_ARCH
- instGen_Set_Reg_To_Imm(EA_HANDLE_CNS_RELOC, indCallReg, (ssize_t)addr);
- getEmitter()->emitIns_R_R_I(INS_ldr, EA_PTRSIZE, indCallReg, indCallReg, 0);
- getEmitter()->emitIns_R_R_I(INS_ldr, EA_PTRSIZE, indCallReg, indCallReg, 0);
- regTracker.rsTrackRegTrash(indCallReg);
+ instGen_Set_Reg_To_Imm(EA_HANDLE_CNS_RELOC, indCallReg, (ssize_t)addr);
+ getEmitter()->emitIns_R_R_I(INS_ldr, EA_PTRSIZE, indCallReg, indCallReg, 0);
+ getEmitter()->emitIns_R_R_I(INS_ldr, EA_PTRSIZE, indCallReg, indCallReg, 0);
+ regTracker.rsTrackRegTrash(indCallReg);
- emitCallType = emitter::EC_INDIR_R;
+ emitCallType = emitter::EC_INDIR_R;
#else
- getEmitter()->emitIns_R_AI(INS_mov, EA_PTR_DSP_RELOC,
- indCallReg,
- (ssize_t)addr);
- regTracker.rsTrackRegTrash(indCallReg);
+ getEmitter()->emitIns_R_AI(INS_mov, EA_PTR_DSP_RELOC, indCallReg, (ssize_t)addr);
+ regTracker.rsTrackRegTrash(indCallReg);
- emitCallType = emitter::EC_INDIR_ARD;
+ emitCallType = emitter::EC_INDIR_ARD;
#endif // CPU_LOAD_STORE_ARCH
- getEmitter()->emitIns_Call(emitCallType,
- methHnd,
- INDEBUG_LDISASM_COMMA(sigInfo)
- NULL, // addr
- args,
- retSize,
- gcInfo.gcVarPtrSetCur,
- gcInfo.gcRegGCrefSetCur,
- gcInfo.gcRegByrefSetCur,
- ilOffset,
- indCallReg, // ireg
- REG_NA, 0, 0, // xreg, xmul, disp
- false, // isJump
- emitter::emitNoGChelper(helperNum));
- }
- break;
+ getEmitter()->emitIns_Call(emitCallType, methHnd,
+ INDEBUG_LDISASM_COMMA(sigInfo) NULL, // addr
+ args, retSize, gcInfo.gcVarPtrSetCur, gcInfo.gcRegGCrefSetCur,
+ gcInfo.gcRegByrefSetCur, ilOffset,
+ indCallReg, // ireg
+ REG_NA, 0, 0, // xreg, xmul, disp
+ false, // isJump
+ emitter::emitNoGChelper(helperNum));
+ }
+ break;
- default:
- noway_assert(!"Bad accessType");
- break;
- }
+ default:
+ noway_assert(!"Bad accessType");
+ break;
+ }
- // tracking of region protected by the monitor in synchronized methods
- if ((helperNum != CORINFO_HELP_UNDEF) && (compiler->info.compFlags & CORINFO_FLG_SYNCH))
- {
- fPossibleSyncHelperCall = true;
+ // tracking of region protected by the monitor in synchronized methods
+ if ((helperNum != CORINFO_HELP_UNDEF) && (compiler->info.compFlags & CORINFO_FLG_SYNCH))
+ {
+ fPossibleSyncHelperCall = true;
+ }
}
}
- }
- break;
-
- default:
- noway_assert(!"strange call type");
- break;
+ break;
- }
+ default:
+ noway_assert(!"strange call type");
+ break;
+ }
/*-------------------------------------------------------------------------
* For tailcalls, REG_INTRET contains the address of the target function,
@@ -20138,26 +19678,25 @@ regMaskTP CodeGen::genCodeForCall(GenTreePtr call,
#ifdef _TARGET_X86_
noway_assert(0 <= (ssize_t)args); // caller-pop args not supported for tailcall
-
// Push the count of the incoming stack arguments
- unsigned nOldStkArgs = (unsigned)((compiler->compArgSize - (intRegState.rsCalleeRegArgCount * sizeof(void *)))/sizeof(void*));
+ unsigned nOldStkArgs =
+ (unsigned)((compiler->compArgSize - (intRegState.rsCalleeRegArgCount * sizeof(void*))) / sizeof(void*));
getEmitter()->emitIns_I(INS_push, EA_4BYTE, nOldStkArgs);
genSinglePush(); // Keep track of ESP for EBP-less frames
args += sizeof(void*);
// Push the count of the outgoing stack arguments
- getEmitter()->emitIns_I(INS_push, EA_4BYTE, argSize/sizeof(void*));
+ getEmitter()->emitIns_I(INS_push, EA_4BYTE, argSize / sizeof(void*));
genSinglePush(); // Keep track of ESP for EBP-less frames
args += sizeof(void*);
// Push info about the callee-saved registers to be restored
// For now, we always spill all registers if compiler->compTailCallUsed
- DWORD calleeSavedRegInfo =
- 1 | // always restore EDI,ESI,EBX
- (fTailCallTargetIsVSD ? 0x2 : 0x0); // Stub dispatch flag
+ DWORD calleeSavedRegInfo = 1 | // always restore EDI,ESI,EBX
+ (fTailCallTargetIsVSD ? 0x2 : 0x0); // Stub dispatch flag
getEmitter()->emitIns_I(INS_push, EA_4BYTE, calleeSavedRegInfo);
genSinglePush(); // Keep track of ESP for EBP-less frames
args += sizeof(void*);
@@ -20170,9 +19709,9 @@ regMaskTP CodeGen::genCodeForCall(GenTreePtr call,
#else // _TARGET_X86_
- args = 0;
+ args = 0;
retSize = EA_UNKNOWN;
-
+
#endif // _TARGET_X86_
if (compiler->getNeedsGSSecurityCookie())
@@ -20187,7 +19726,6 @@ regMaskTP CodeGen::genCodeForCall(GenTreePtr call,
// Now call the helper
genEmitHelperCall(CORINFO_HELP_TAILCALL, (int)args, retSize);
-
}
/*-------------------------------------------------------------------------
@@ -20210,12 +19748,12 @@ regMaskTP CodeGen::genCodeForCall(GenTreePtr call,
#ifdef _TARGET_ARM_
if (regSet.rsUsedTree[areg] == NULL)
{
- noway_assert(areg % 2 == 1 && (((areg+1) >= MAX_REG_ARG) ||
- (regSet.rsUsedTree[areg+1]->TypeGet() == TYP_STRUCT) ||
- (genTypeStSz(regSet.rsUsedTree[areg+1]->TypeGet()) == 2)));
+ noway_assert(areg % 2 == 1 &&
+ (((areg + 1) >= MAX_REG_ARG) || (regSet.rsUsedTree[areg + 1]->TypeGet() == TYP_STRUCT) ||
+ (genTypeStSz(regSet.rsUsedTree[areg + 1]->TypeGet()) == 2)));
continue;
}
-#endif
+#endif
regSet.rsMarkRegFree(curArgMask);
@@ -20247,21 +19785,21 @@ regMaskTP CodeGen::genCodeForCall(GenTreePtr call,
/* restore the old argument register status */
- intRegState.rsCurRegArgNum = savCurIntArgReg;
+ intRegState.rsCurRegArgNum = savCurIntArgReg;
floatRegState.rsCurRegArgNum = savCurFloatArgReg;
noway_assert(intRegState.rsCurRegArgNum <= MAX_REG_ARG);
/* Mark all trashed registers as such */
- if (calleeTrashedRegs)
+ if (calleeTrashedRegs)
regTracker.rsTrashRegSet(calleeTrashedRegs);
regTracker.rsTrashRegsForGCInterruptability();
-#ifdef DEBUG
+#ifdef DEBUG
- if (!(call->gtFlags & GTF_CALL_POP_ARGS))
+ if (!(call->gtFlags & GTF_CALL_POP_ARGS))
{
if (compiler->verbose)
{
@@ -20313,39 +19851,38 @@ regMaskTP CodeGen::genCodeForCall(GenTreePtr call,
/* No trashed registers may possibly hold a pointer at this point */
CLANG_FORMAT_COMMENT_ANCHOR;
-#ifdef DEBUG
+#ifdef DEBUG
- regMaskTP ptrRegs = (gcInfo.gcRegGCrefSetCur|gcInfo.gcRegByrefSetCur) & (calleeTrashedRegs & RBM_ALLINT) & ~regSet.rsMaskVars & ~vptrMask;
- if (ptrRegs)
+ regMaskTP ptrRegs = (gcInfo.gcRegGCrefSetCur | gcInfo.gcRegByrefSetCur) & (calleeTrashedRegs & RBM_ALLINT) &
+ ~regSet.rsMaskVars & ~vptrMask;
+ if (ptrRegs)
{
// A reg may be dead already. The assertion is too strong.
- LclVarDsc *varDsc;
- unsigned varNum;
-
+ LclVarDsc* varDsc;
+ unsigned varNum;
+
// use compiler->compCurLife
- for (varNum = 0, varDsc = compiler->lvaTable;
- varNum < compiler->lvaCount && ptrRegs != 0;
- varNum++ , varDsc++)
+ for (varNum = 0, varDsc = compiler->lvaTable; varNum < compiler->lvaCount && ptrRegs != 0; varNum++, varDsc++)
{
/* Ignore the variable if it's not tracked, not in a register, or a floating-point type */
- if (!varDsc->lvTracked)
+ if (!varDsc->lvTracked)
continue;
- if (!varDsc->lvRegister)
+ if (!varDsc->lvRegister)
continue;
- if (varDsc->IsFloatRegType())
+ if (varDsc->IsFloatRegType())
continue;
/* Get hold of the index and the bitmask for the variable */
- unsigned varIndex = varDsc->lvVarIndex;
+ unsigned varIndex = varDsc->lvVarIndex;
/* Is this variable live currently? */
- if (!VarSetOps::IsMember(compiler, compiler->compCurLife, varIndex))
+ if (!VarSetOps::IsMember(compiler, compiler->compCurLife, varIndex))
{
- regNumber regNum = varDsc->lvRegNum;
- regMaskTP regMask = genRegMask(regNum);
+ regNumber regNum = varDsc->lvRegNum;
+ regMaskTP regMask = genRegMask(regNum);
if (varDsc->lvType == TYP_REF || varDsc->lvType == TYP_BYREF)
ptrRegs &= ~regMask;
@@ -20369,27 +19906,24 @@ regMaskTP CodeGen::genCodeForCall(GenTreePtr call,
if (fPossibleSyncHelperCall)
{
- switch (helperNum) {
- case CORINFO_HELP_MON_ENTER:
- case CORINFO_HELP_MON_ENTER_STATIC:
- noway_assert(compiler->syncStartEmitCookie == NULL);
- compiler->syncStartEmitCookie = getEmitter()->emitAddLabel(
- gcInfo.gcVarPtrSetCur,
- gcInfo.gcRegGCrefSetCur,
- gcInfo.gcRegByrefSetCur);
- noway_assert(compiler->syncStartEmitCookie != NULL);
- break;
- case CORINFO_HELP_MON_EXIT:
- case CORINFO_HELP_MON_EXIT_STATIC:
- noway_assert(compiler->syncEndEmitCookie == NULL);
- compiler->syncEndEmitCookie = getEmitter()->emitAddLabel(
- gcInfo.gcVarPtrSetCur,
- gcInfo.gcRegGCrefSetCur,
- gcInfo.gcRegByrefSetCur);
- noway_assert(compiler->syncEndEmitCookie != NULL);
- break;
- default:
- break;
+ switch (helperNum)
+ {
+ case CORINFO_HELP_MON_ENTER:
+ case CORINFO_HELP_MON_ENTER_STATIC:
+ noway_assert(compiler->syncStartEmitCookie == NULL);
+ compiler->syncStartEmitCookie =
+ getEmitter()->emitAddLabel(gcInfo.gcVarPtrSetCur, gcInfo.gcRegGCrefSetCur, gcInfo.gcRegByrefSetCur);
+ noway_assert(compiler->syncStartEmitCookie != NULL);
+ break;
+ case CORINFO_HELP_MON_EXIT:
+ case CORINFO_HELP_MON_EXIT_STATIC:
+ noway_assert(compiler->syncEndEmitCookie == NULL);
+ compiler->syncEndEmitCookie =
+ getEmitter()->emitAddLabel(gcInfo.gcVarPtrSetCur, gcInfo.gcRegGCrefSetCur, gcInfo.gcRegByrefSetCur);
+ noway_assert(compiler->syncEndEmitCookie != NULL);
+ break;
+ default:
+ break;
}
}
#endif // _TARGET_X86_
@@ -20402,15 +19936,12 @@ regMaskTP CodeGen::genCodeForCall(GenTreePtr call,
if (getInlinePInvokeCheckEnabled())
{
noway_assert(compiler->lvaInlinedPInvokeFrameVar != BAD_VAR_NUM);
- BasicBlock * esp_check;
+ BasicBlock* esp_check;
- CORINFO_EE_INFO * pInfo = compiler->eeGetEEInfo();
+ CORINFO_EE_INFO* pInfo = compiler->eeGetEEInfo();
/* mov ecx, dword ptr [frame.callSiteTracker] */
- getEmitter()->emitIns_R_S (INS_mov,
- EA_4BYTE,
- REG_ARG_0,
- compiler->lvaInlinedPInvokeFrameVar,
+ getEmitter()->emitIns_R_S(INS_mov, EA_4BYTE, REG_ARG_0, compiler->lvaInlinedPInvokeFrameVar,
pInfo->inlinedCallFrameInfo.offsetOfCallSiteSP);
regTracker.rsTrackRegTrash(REG_ARG_0);
@@ -20420,10 +19951,7 @@ regMaskTP CodeGen::genCodeForCall(GenTreePtr call,
{
if (argSize)
{
- getEmitter()->emitIns_R_I (INS_add,
- EA_PTRSIZE,
- REG_ARG_0,
- argSize);
+ getEmitter()->emitIns_R_I(INS_add, EA_PTRSIZE, REG_ARG_0, argSize);
}
}
/* cmp ecx, esp */
@@ -20457,41 +19985,33 @@ regMaskTP CodeGen::genCodeForCall(GenTreePtr call,
// take care of the cdecl argument popping here as well but the stack depth tracking logic
// makes this very hard, i.e. it needs to "see" the actual pop.
- CORINFO_EE_INFO *pInfo = compiler->eeGetEEInfo();
+ CORINFO_EE_INFO* pInfo = compiler->eeGetEEInfo();
if (argSize == 0 || (call->gtFlags & GTF_CALL_POP_ARGS))
{
/* mov esp, dword ptr [frame.callSiteTracker] */
- getEmitter()->emitIns_R_S (ins_Load(TYP_I_IMPL),
- EA_PTRSIZE,
- REG_SPBASE,
+ getEmitter()->emitIns_R_S(ins_Load(TYP_I_IMPL), EA_PTRSIZE, REG_SPBASE,
compiler->lvaInlinedPInvokeFrameVar,
pInfo->inlinedCallFrameInfo.offsetOfCallSiteSP);
}
else
{
/* mov ecx, dword ptr [frame.callSiteTracker] */
- getEmitter()->emitIns_R_S (ins_Load(TYP_I_IMPL),
- EA_PTRSIZE,
- REG_ARG_0,
+ getEmitter()->emitIns_R_S(ins_Load(TYP_I_IMPL), EA_PTRSIZE, REG_ARG_0,
compiler->lvaInlinedPInvokeFrameVar,
pInfo->inlinedCallFrameInfo.offsetOfCallSiteSP);
regTracker.rsTrackRegTrash(REG_ARG_0);
/* lea esp, [ecx + argSize] */
- getEmitter()->emitIns_R_AR (INS_lea,
- EA_PTRSIZE,
- REG_SPBASE,
- REG_ARG_0,
- (int)argSize);
+ getEmitter()->emitIns_R_AR(INS_lea, EA_PTRSIZE, REG_SPBASE, REG_ARG_0, (int)argSize);
}
}
}
#endif // _TARGET_X86_
- if (call->gtFlags & GTF_CALL_POP_ARGS)
+ if (call->gtFlags & GTF_CALL_POP_ARGS)
{
- noway_assert(args == (size_t)-(int)argSize);
+ noway_assert(args == (size_t) - (int)argSize);
if (argSize)
{
@@ -20499,7 +20019,7 @@ regMaskTP CodeGen::genCodeForCall(GenTreePtr call,
}
}
- if (pseudoStackLvl)
+ if (pseudoStackLvl)
{
noway_assert(call->gtType == TYP_VOID);
@@ -20508,30 +20028,28 @@ regMaskTP CodeGen::genCodeForCall(GenTreePtr call,
instGen(INS_nop);
}
-
-
/* What does the function return? */
retVal = RBM_NONE;
switch (call->gtType)
{
- case TYP_REF:
- case TYP_ARRAY:
- case TYP_BYREF:
- gcInfo.gcMarkRegPtrVal(REG_INTRET, call->TypeGet());
+ case TYP_REF:
+ case TYP_ARRAY:
+ case TYP_BYREF:
+ gcInfo.gcMarkRegPtrVal(REG_INTRET, call->TypeGet());
- __fallthrough;
+ __fallthrough;
- case TYP_INT:
-#if!CPU_HAS_FP_SUPPORT
- case TYP_FLOAT:
+ case TYP_INT:
+#if !CPU_HAS_FP_SUPPORT
+ case TYP_FLOAT:
#endif
- retVal = RBM_INTRET;
- break;
+ retVal = RBM_INTRET;
+ break;
#ifdef _TARGET_ARM_
- case TYP_STRUCT:
+ case TYP_STRUCT:
{
assert(call->gtCall.gtRetClsHnd != NULL);
assert(compiler->IsHfa(call->gtCall.gtRetClsHnd));
@@ -20543,25 +20061,25 @@ regMaskTP CodeGen::genCodeForCall(GenTreePtr call,
break;
#endif
- case TYP_LONG:
-#if!CPU_HAS_FP_SUPPORT
- case TYP_DOUBLE:
+ case TYP_LONG:
+#if !CPU_HAS_FP_SUPPORT
+ case TYP_DOUBLE:
#endif
- retVal = RBM_LNGRET;
- break;
+ retVal = RBM_LNGRET;
+ break;
#if CPU_HAS_FP_SUPPORT
- case TYP_FLOAT:
- case TYP_DOUBLE:
+ case TYP_FLOAT:
+ case TYP_DOUBLE:
- break;
+ break;
#endif
- case TYP_VOID:
- break;
+ case TYP_VOID:
+ break;
- default:
- noway_assert(!"unexpected/unhandled fn return type");
+ default:
+ noway_assert(!"unexpected/unhandled fn return type");
}
// We now have to generate the "call epilog" (if it was a call to unmanaged code).
@@ -20576,7 +20094,7 @@ regMaskTP CodeGen::genCodeForCall(GenTreePtr call,
{
if (frameListRoot->lvRegister)
{
- bool isBorn = false;
+ bool isBorn = false;
bool isDying = true;
genUpdateRegLife(frameListRoot, isBorn, isDying DEBUGARG(call));
}
@@ -20585,14 +20103,16 @@ regMaskTP CodeGen::genCodeForCall(GenTreePtr call,
#ifdef DEBUG
if (compiler->opts.compStackCheckOnCall
#if defined(USE_TRANSITION_THUNKS) || defined(USE_DYNAMIC_STACK_ALIGN)
- //check the stack as frequently as possible
+ // check the stack as frequently as possible
&& !call->IsHelperCall()
#else
&& call->gtCall.gtCallType == CT_USER_FUNC
#endif
- )
+ )
{
- noway_assert(compiler->lvaCallEspCheck != 0xCCCCCCCC && compiler->lvaTable[compiler->lvaCallEspCheck].lvDoNotEnregister && compiler->lvaTable[compiler->lvaCallEspCheck].lvOnFrame);
+ noway_assert(compiler->lvaCallEspCheck != 0xCCCCCCCC &&
+ compiler->lvaTable[compiler->lvaCallEspCheck].lvDoNotEnregister &&
+ compiler->lvaTable[compiler->lvaCallEspCheck].lvOnFrame);
if (argSize > 0)
{
getEmitter()->emitIns_R_R(INS_mov, EA_4BYTE, REG_ARG_0, REG_SPBASE);
@@ -20603,8 +20123,8 @@ regMaskTP CodeGen::genCodeForCall(GenTreePtr call,
else
getEmitter()->emitIns_S_R(INS_cmp, EA_4BYTE, REG_SPBASE, compiler->lvaCallEspCheck, 0);
- BasicBlock * esp_check = genCreateTempLabel();
- emitJumpKind jmpEqual = genJumpKindForOper(GT_EQ, CK_SIGNED);
+ BasicBlock* esp_check = genCreateTempLabel();
+ emitJumpKind jmpEqual = genJumpKindForOper(GT_EQ, CK_SIGNED);
inst_JMP(jmpEqual, esp_check);
getEmitter()->emitIns(INS_BREAKPOINT);
genDefineTempLabel(esp_check);
@@ -20618,7 +20138,7 @@ regMaskTP CodeGen::genCodeForCall(GenTreePtr call,
if (call->gtType == TYP_FLOAT || call->gtType == TYP_DOUBLE)
{
// Restore return node if necessary
- if (call->gtFlags & GTF_SPILLED)
+ if (call->gtFlags & GTF_SPILLED)
{
UnspillFloat(call);
}
@@ -20644,7 +20164,6 @@ regMaskTP CodeGen::genCodeForCall(GenTreePtr call,
#pragma warning(pop)
#endif
-
/*****************************************************************************
*
* Create and record GC Info for the function.
@@ -20664,25 +20183,22 @@ CodeGen::genCreateAndStoreGCInfo(unsigned codeSize, unsigned prologSize, unsigne
}
#ifdef JIT32_GCENCODER
-void* CodeGen::genCreateAndStoreGCInfoJIT32(unsigned codeSize, unsigned prologSize, unsigned epilogSize DEBUGARG(void* codePtr))
+void* CodeGen::genCreateAndStoreGCInfoJIT32(unsigned codeSize,
+ unsigned prologSize,
+ unsigned epilogSize DEBUGARG(void* codePtr))
{
- BYTE headerBuf[64];
- InfoHdr header;
+ BYTE headerBuf[64];
+ InfoHdr header;
int s_cached;
-#ifdef DEBUG
- size_t headerSize =
+#ifdef DEBUG
+ size_t headerSize =
#endif
- compiler->compInfoBlkSize = gcInfo.gcInfoBlockHdrSave(headerBuf,
- 0,
- codeSize,
- prologSize,
- epilogSize,
- &header,
- &s_cached);
+ compiler->compInfoBlkSize =
+ gcInfo.gcInfoBlockHdrSave(headerBuf, 0, codeSize, prologSize, epilogSize, &header, &s_cached);
size_t argTabOffset = 0;
- size_t ptrMapSize = gcInfo.gcPtrTableSize(header, codeSize, &argTabOffset);
+ size_t ptrMapSize = gcInfo.gcPtrTableSize(header, codeSize, &argTabOffset);
#if DISPLAY_SIZES
@@ -20703,7 +20219,7 @@ void* CodeGen::genCreateAndStoreGCInfoJIT32(unsigned codeSize, unsigned prologS
/* Allocate the info block for the method */
- compiler->compInfoBlkAddr = (BYTE *) compiler->info.compCompHnd->allocGCInfo(compiler->compInfoBlkSize);
+ compiler->compInfoBlkAddr = (BYTE*)compiler->info.compCompHnd->allocGCInfo(compiler->compInfoBlkSize);
#if 0 // VERBOSE_SIZES
// TODO-Review: 'dataSize', below, is not defined
@@ -20729,24 +20245,20 @@ void* CodeGen::genCreateAndStoreGCInfoJIT32(unsigned codeSize, unsigned prologS
/* Create the method info block: header followed by GC tracking tables */
- compiler->compInfoBlkAddr += gcInfo.gcInfoBlockHdrSave(compiler->compInfoBlkAddr, -1,
- codeSize,
- prologSize,
- epilogSize,
- &header,
- &s_cached);
+ compiler->compInfoBlkAddr +=
+ gcInfo.gcInfoBlockHdrSave(compiler->compInfoBlkAddr, -1, codeSize, prologSize, epilogSize, &header, &s_cached);
assert(compiler->compInfoBlkAddr == (BYTE*)infoPtr + headerSize);
compiler->compInfoBlkAddr = gcInfo.gcPtrTableSave(compiler->compInfoBlkAddr, header, codeSize, &argTabOffset);
assert(compiler->compInfoBlkAddr == (BYTE*)infoPtr + headerSize + ptrMapSize);
-#ifdef DEBUG
+#ifdef DEBUG
- if (0)
+ if (0)
{
- BYTE * temp = (BYTE *)infoPtr;
- unsigned size = compiler->compInfoBlkAddr - temp;
- BYTE * ptab = temp + headerSize;
+ BYTE* temp = (BYTE*)infoPtr;
+ unsigned size = compiler->compInfoBlkAddr - temp;
+ BYTE* ptab = temp + headerSize;
noway_assert(size == headerSize + ptrMapSize);
@@ -20754,14 +20266,14 @@ void* CodeGen::genCreateAndStoreGCInfoJIT32(unsigned codeSize, unsigned prologS
for (unsigned i = 0; i < size; i++)
{
- if (temp == ptab)
+ if (temp == ptab)
{
printf("\nMethod info block - ptrtab [%u bytes]:", ptrMapSize);
- printf("\n %04X: %*c", i & ~0xF, 3*(i&0xF), ' ');
+ printf("\n %04X: %*c", i & ~0xF, 3 * (i & 0xF), ' ');
}
else
{
- if (!(i % 16))
+ if (!(i % 16))
printf("\n %04X: ", i);
}
@@ -20775,9 +20287,9 @@ void* CodeGen::genCreateAndStoreGCInfoJIT32(unsigned codeSize, unsigned prologS
#if DUMP_GC_TABLES
- if (compiler->opts.dspGCtbls)
+ if (compiler->opts.dspGCtbls)
{
- const BYTE *base = (BYTE *)infoPtr;
+ const BYTE* base = (BYTE*)infoPtr;
unsigned size;
unsigned methodSize;
InfoHdr dumpHeader;
@@ -20789,19 +20301,18 @@ void* CodeGen::genCreateAndStoreGCInfoJIT32(unsigned codeSize, unsigned prologS
// printf("size of header encoding is %3u\n", size);
printf("\n");
- if (compiler->opts.dspGCtbls)
+ if (compiler->opts.dspGCtbls)
{
- base += size;
- size = gcInfo.gcDumpPtrTable(base, dumpHeader, methodSize);
+ base += size;
+ size = gcInfo.gcDumpPtrTable(base, dumpHeader, methodSize);
// printf("size of pointer table is %3u\n", size);
printf("\n");
- noway_assert(compiler->compInfoBlkAddr == (base+size));
+ noway_assert(compiler->compInfoBlkAddr == (base + size));
}
-
}
#ifdef DEBUG
- if (jitOpts.testMask & 128)
+ if (jitOpts.testMask & 128)
{
for (unsigned offs = 0; offs < codeSize; offs++)
{
@@ -20813,17 +20324,18 @@ void* CodeGen::genCreateAndStoreGCInfoJIT32(unsigned codeSize, unsigned prologS
/* Make sure we ended up generating the expected number of bytes */
- noway_assert(compiler->compInfoBlkAddr == (BYTE *)infoPtr + compiler->compInfoBlkSize);
+ noway_assert(compiler->compInfoBlkAddr == (BYTE*)infoPtr + compiler->compInfoBlkSize);
return infoPtr;
}
#else // JIT32_GCENCODER
-void CodeGen::genCreateAndStoreGCInfoX64(unsigned codeSize, unsigned prologSize DEBUGARG(void* codePtr))
+void CodeGen::genCreateAndStoreGCInfoX64(unsigned codeSize, unsigned prologSize DEBUGARG(void* codePtr))
{
- IAllocator* allowZeroAlloc = new (compiler, CMK_GC) AllowZeroAllocator(compiler->getAllocatorGC());
- GcInfoEncoder* gcInfoEncoder = new (compiler, CMK_GC) GcInfoEncoder(compiler->info.compCompHnd, compiler->info.compMethodInfo, allowZeroAlloc, NOMEM);
+ IAllocator* allowZeroAlloc = new (compiler, CMK_GC) AllowZeroAllocator(compiler->getAllocatorGC());
+ GcInfoEncoder* gcInfoEncoder = new (compiler, CMK_GC)
+ GcInfoEncoder(compiler->info.compCompHnd, compiler->info.compMethodInfo, allowZeroAlloc, NOMEM);
assert(gcInfoEncoder);
// Follow the code pattern of the x86 gc info encoder (genCreateAndStoreGCInfoJIT32).
@@ -20838,39 +20350,40 @@ void CodeGen::genCreateAndStoreGCInfoX64(unsigned codeSize, unsig
gcInfoEncoder->Build();
- //GC Encoder automatically puts the GC info in the right spot using ICorJitInfo::allocGCInfo(size_t)
- //let's save the values anyway for debugging purposes
+ // GC Encoder automatically puts the GC info in the right spot using ICorJitInfo::allocGCInfo(size_t)
+ // let's save the values anyway for debugging purposes
compiler->compInfoBlkAddr = gcInfoEncoder->Emit();
- compiler->compInfoBlkSize = 0; //not exposed by the GCEncoder interface
+ compiler->compInfoBlkSize = 0; // not exposed by the GCEncoder interface
}
#endif
-
/*****************************************************************************
* For CEE_LOCALLOC
*/
-regNumber CodeGen::genLclHeap(GenTreePtr size)
+regNumber CodeGen::genLclHeap(GenTreePtr size)
{
noway_assert((genActualType(size->gtType) == TYP_INT) || (genActualType(size->gtType) == TYP_I_IMPL));
// regCnt is a register used to hold both
// the amount to stack alloc (either in bytes or pointer sized words)
// and the final stack alloc address to return as the result
- //
- regNumber regCnt = DUMMY_INIT(REG_CORRUPT);
- var_types type = genActualType(size->gtType);
- emitAttr easz = emitTypeSize(type);
+ //
+ regNumber regCnt = DUMMY_INIT(REG_CORRUPT);
+ var_types type = genActualType(size->gtType);
+ emitAttr easz = emitTypeSize(type);
#ifdef DEBUG
// Verify ESP
if (compiler->opts.compStackCheckOnRet)
{
- noway_assert(compiler->lvaReturnEspCheck != 0xCCCCCCCC && compiler->lvaTable[compiler->lvaReturnEspCheck].lvDoNotEnregister && compiler->lvaTable[compiler->lvaReturnEspCheck].lvOnFrame);
+ noway_assert(compiler->lvaReturnEspCheck != 0xCCCCCCCC &&
+ compiler->lvaTable[compiler->lvaReturnEspCheck].lvDoNotEnregister &&
+ compiler->lvaTable[compiler->lvaReturnEspCheck].lvOnFrame);
getEmitter()->emitIns_S_R(INS_cmp, EA_PTRSIZE, REG_SPBASE, compiler->lvaReturnEspCheck, 0);
- BasicBlock * esp_check = genCreateTempLabel();
- emitJumpKind jmpEqual = genJumpKindForOper(GT_EQ, CK_SIGNED);
+ BasicBlock* esp_check = genCreateTempLabel();
+ emitJumpKind jmpEqual = genJumpKindForOper(GT_EQ, CK_SIGNED);
inst_JMP(jmpEqual, esp_check);
getEmitter()->emitIns(INS_BREAKPOINT);
genDefineTempLabel(esp_check);
@@ -20880,45 +20393,46 @@ regNumber CodeGen::genLclHeap(GenTreePtr size)
noway_assert(isFramePointerUsed());
noway_assert(genStackLevel == 0); // Can't have anything on the stack
- BasicBlock* endLabel = NULL;
+ BasicBlock* endLabel = NULL;
#if FEATURE_FIXED_OUT_ARGS
- bool stackAdjusted = false;
+ bool stackAdjusted = false;
#endif
if (size->IsCnsIntOrI())
{
#if FEATURE_FIXED_OUT_ARGS
// If we have an outgoing arg area then we must adjust the SP
- // essentially popping off the outgoing arg area,
+ // essentially popping off the outgoing arg area,
// We will restore it right before we return from this method
//
- if (compiler->lvaOutgoingArgSpaceSize > 0)
+ if (compiler->lvaOutgoingArgSpaceSize > 0)
{
- assert((compiler->lvaOutgoingArgSpaceSize % STACK_ALIGN) == 0); // This must be true for the stack to remain aligned
+ assert((compiler->lvaOutgoingArgSpaceSize % STACK_ALIGN) ==
+ 0); // This must be true for the stack to remain aligned
inst_RV_IV(INS_add, REG_SPBASE, compiler->lvaOutgoingArgSpaceSize, EA_PTRSIZE);
stackAdjusted = true;
}
#endif
size_t amount = size->gtIntCon.gtIconVal;
-
+
// Convert amount to be properly STACK_ALIGN and count of DWORD_PTRs
- amount += (STACK_ALIGN - 1);
+ amount += (STACK_ALIGN - 1);
amount &= ~(STACK_ALIGN - 1);
- amount >>= STACK_ALIGN_SHIFT; // amount is number of pointer-sized words to locAlloc
- size->gtIntCon.gtIconVal = amount; // update the GT_CNS value in the node
-
+ amount >>= STACK_ALIGN_SHIFT; // amount is number of pointer-sized words to locAlloc
+ size->gtIntCon.gtIconVal = amount; // update the GT_CNS value in the node
+
/* If amount is zero then return null in RegCnt */
if (amount == 0)
{
- regCnt = regSet.rsGrabReg(RBM_ALLINT);
+ regCnt = regSet.rsGrabReg(RBM_ALLINT);
instGen_Set_Reg_To_Zero(EA_PTRSIZE, regCnt);
goto DONE;
}
-
+
/* For small allocations we will generate up to six push 0 inline */
if (amount <= 6)
{
- regCnt = regSet.rsGrabReg(RBM_ALLINT);
+ regCnt = regSet.rsGrabReg(RBM_ALLINT);
#if CPU_LOAD_STORE_ARCH
regNumber regZero = regSet.rsGrabReg(RBM_ALLINT & ~genRegMask(regCnt));
// Set 'regZero' to zero
@@ -20928,32 +20442,32 @@ regNumber CodeGen::genLclHeap(GenTreePtr size)
while (amount != 0)
{
#if CPU_LOAD_STORE_ARCH
- inst_IV(INS_push, (unsigned) genRegMask(regZero));
+ inst_IV(INS_push, (unsigned)genRegMask(regZero));
#else
- inst_IV(INS_push_hide, 0); // push_hide means don't track the stack
+ inst_IV(INS_push_hide, 0); // push_hide means don't track the stack
#endif
amount--;
}
-
+
regTracker.rsTrackRegTrash(regCnt);
// --- move regCnt, ESP
inst_RV_RV(INS_mov, regCnt, REG_SPBASE, TYP_I_IMPL);
goto DONE;
}
- else
+ else
{
if (!compiler->info.compInitMem)
{
- // Re-bias amount to be number of bytes to adjust the SP
+ // Re-bias amount to be number of bytes to adjust the SP
amount <<= STACK_ALIGN_SHIFT;
- size->gtIntCon.gtIconVal = amount; // update the GT_CNS value in the node
- if (amount < compiler->eeGetPageSize()) // must be < not <=
+ size->gtIntCon.gtIconVal = amount; // update the GT_CNS value in the node
+ if (amount < compiler->eeGetPageSize()) // must be < not <=
{
- // Since the size is a page or less, simply adjust ESP
-
+ // Since the size is a page or less, simply adjust ESP
+
// ESP might already be in the guard page, must touch it BEFORE
// the alloc, not after.
- regCnt = regSet.rsGrabReg(RBM_ALLINT);
+ regCnt = regSet.rsGrabReg(RBM_ALLINT);
inst_RV_RV(INS_mov, regCnt, REG_SPBASE, TYP_I_IMPL);
#if CPU_LOAD_STORE_ARCH
regNumber regTmp = regSet.rsGrabReg(RBM_ALLINT & ~genRegMask(regCnt));
@@ -20968,7 +20482,7 @@ regNumber CodeGen::genLclHeap(GenTreePtr size)
goto DONE;
}
}
- }
+ }
}
// Compute the size of the block to allocate
@@ -20978,12 +20492,13 @@ regNumber CodeGen::genLclHeap(GenTreePtr size)
#if FEATURE_FIXED_OUT_ARGS
// If we have an outgoing arg area then we must adjust the SP
- // essentially popping off the outgoing arg area,
+ // essentially popping off the outgoing arg area,
// We will restore it right before we return from this method
//
if ((compiler->lvaOutgoingArgSpaceSize > 0) && !stackAdjusted)
{
- assert((compiler->lvaOutgoingArgSpaceSize % STACK_ALIGN) == 0); // This must be true for the stack to remain aligned
+ assert((compiler->lvaOutgoingArgSpaceSize % STACK_ALIGN) ==
+ 0); // This must be true for the stack to remain aligned
inst_RV_IV(INS_add, REG_SPBASE, compiler->lvaOutgoingArgSpaceSize, EA_PTRSIZE);
stackAdjusted = true;
}
@@ -21001,7 +20516,7 @@ regNumber CodeGen::genLclHeap(GenTreePtr size)
inst_JMP(jmpEqual, endLabel);
// Align to STACK_ALIGN
- inst_RV_IV(INS_add, regCnt, (STACK_ALIGN - 1), emitActualTypeSize(type));
+ inst_RV_IV(INS_add, regCnt, (STACK_ALIGN - 1), emitActualTypeSize(type));
if (compiler->info.compInitMem)
{
@@ -21021,7 +20536,8 @@ regNumber CodeGen::genLclHeap(GenTreePtr size)
}
}
- BasicBlock* loop; loop = genCreateTempLabel();
+ BasicBlock* loop;
+ loop = genCreateTempLabel();
if (compiler->info.compInitMem)
{
@@ -21033,8 +20549,8 @@ regNumber CodeGen::genLclHeap(GenTreePtr size)
CLANG_FORMAT_COMMENT_ANCHOR;
#if defined(_TARGET_ARM_)
- regNumber regZero1 = regSet.rsGrabReg(RBM_ALLINT & ~genRegMask(regCnt));
- regNumber regZero2 = regSet.rsGrabReg(RBM_ALLINT & ~genRegMask(regCnt) & ~genRegMask(regZero1));
+ regNumber regZero1 = regSet.rsGrabReg(RBM_ALLINT & ~genRegMask(regCnt));
+ regNumber regZero2 = regSet.rsGrabReg(RBM_ALLINT & ~genRegMask(regCnt) & ~genRegMask(regZero1));
// Set 'regZero1' and 'regZero2' to zero
instGen_Set_Reg_To_Zero(EA_PTRSIZE, regZero1);
instGen_Set_Reg_To_Zero(EA_PTRSIZE, regZero2);
@@ -21045,13 +20561,13 @@ regNumber CodeGen::genLclHeap(GenTreePtr size)
#if defined(_TARGET_X86_)
- inst_IV(INS_push_hide, 0); // --- push 0
+ inst_IV(INS_push_hide, 0); // --- push 0
// Are we done?
inst_RV(INS_dec, regCnt, type);
#elif defined(_TARGET_ARM_)
- inst_IV(INS_push, (unsigned) (genRegMask(regZero1) | genRegMask(regZero2)));
+ inst_IV(INS_push, (unsigned)(genRegMask(regZero1) | genRegMask(regZero2)));
// Are we done?
inst_RV_IV(INS_sub, regCnt, 2, emitActualTypeSize(type), INS_FLAGS_SET);
@@ -21120,7 +20636,7 @@ regNumber CodeGen::genLclHeap(GenTreePtr size)
// decrement of the ESP - we do the subtraction in another reg
// instead of adjusting ESP directly.
- regNumber regTemp = regSet.rsPickReg();
+ regNumber regTemp = regSet.rsPickReg();
// Tickle the decremented value, and move back to ESP,
// note that it has to be done BEFORE the update of ESP since
@@ -21140,7 +20656,8 @@ regNumber CodeGen::genLclHeap(GenTreePtr size)
inst_RV_IV(INS_sub, regTemp, compiler->eeGetPageSize(), EA_PTRSIZE);
inst_RV_RV(INS_mov, REG_SPBASE, regTemp, TYP_I_IMPL);
- genRecoverReg(size, RBM_ALLINT, RegSet::KEEP_REG); // not purely the 'size' tree anymore; though it is derived from 'size'
+ genRecoverReg(size, RBM_ALLINT,
+ RegSet::KEEP_REG); // not purely the 'size' tree anymore; though it is derived from 'size'
noway_assert(size->gtFlags & GTF_REG_VAL);
regCnt = size->gtRegNum;
inst_RV_RV(INS_cmp, REG_SPBASE, regCnt, TYP_I_IMPL);
@@ -21153,7 +20670,7 @@ regNumber CodeGen::genLclHeap(GenTreePtr size)
regSet.rsMarkRegFree(genRegMask(regCnt));
DONE:
-
+
noway_assert(regCnt != DUMMY_INIT(REG_CORRUPT));
if (endLabel != NULL)
@@ -21162,18 +20679,18 @@ DONE:
#if FEATURE_FIXED_OUT_ARGS
// If we have an outgoing arg area then we must readjust the SP
//
- if (stackAdjusted)
+ if (stackAdjusted)
{
assert(compiler->lvaOutgoingArgSpaceSize > 0);
- assert((compiler->lvaOutgoingArgSpaceSize % STACK_ALIGN) == 0); // This must be true for the stack to remain aligned
+ assert((compiler->lvaOutgoingArgSpaceSize % STACK_ALIGN) ==
+ 0); // This must be true for the stack to remain aligned
inst_RV_IV(INS_sub, REG_SPBASE, compiler->lvaOutgoingArgSpaceSize, EA_PTRSIZE);
}
#endif
/* Write the lvaShadowSPfirst stack frame slot */
noway_assert(compiler->lvaLocAllocSPvar != BAD_VAR_NUM);
- getEmitter()->emitIns_S_R(ins_Store(TYP_I_IMPL), EA_PTRSIZE, REG_SPBASE,
- compiler->lvaLocAllocSPvar, 0);
+ getEmitter()->emitIns_S_R(ins_Store(TYP_I_IMPL), EA_PTRSIZE, REG_SPBASE, compiler->lvaLocAllocSPvar, 0);
#if STACK_PROBES
// Don't think it is worth it the codegen complexity to embed this
@@ -21188,7 +20705,9 @@ DONE:
// Update new ESP
if (compiler->opts.compStackCheckOnRet)
{
- noway_assert(compiler->lvaReturnEspCheck != 0xCCCCCCCC && compiler->lvaTable[compiler->lvaReturnEspCheck].lvDoNotEnregister && compiler->lvaTable[compiler->lvaReturnEspCheck].lvOnFrame);
+ noway_assert(compiler->lvaReturnEspCheck != 0xCCCCCCCC &&
+ compiler->lvaTable[compiler->lvaReturnEspCheck].lvDoNotEnregister &&
+ compiler->lvaTable[compiler->lvaReturnEspCheck].lvOnFrame);
getEmitter()->emitIns_S_R(ins_Store(TYP_I_IMPL), EA_PTRSIZE, REG_SPBASE, compiler->lvaReturnEspCheck, 0);
}
#endif
@@ -21196,7 +20715,6 @@ DONE:
return regCnt;
}
-
/*****************************************************************************/
#ifdef DEBUGGING_SUPPORT
/*****************************************************************************
@@ -21205,13 +20723,13 @@ DONE:
* Called for every scope info piece to record by the main genSetScopeInfo()
*/
-void CodeGen::genSetScopeInfo (unsigned which,
- UNATIVE_OFFSET startOffs,
- UNATIVE_OFFSET length,
- unsigned varNum,
- unsigned LVnum,
- bool avail,
- Compiler::siVarLoc& varLoc)
+void CodeGen::genSetScopeInfo(unsigned which,
+ UNATIVE_OFFSET startOffs,
+ UNATIVE_OFFSET length,
+ unsigned varNum,
+ unsigned LVnum,
+ bool avail,
+ Compiler::siVarLoc& varLoc)
{
/* We need to do some mapping while reporting back these variables */
@@ -21224,10 +20742,8 @@ void CodeGen::genSetScopeInfo (unsigned which,
// Is this a varargs function?
- if (compiler->info.compIsVarArgs &&
- varNum != compiler->lvaVarargsHandleArg &&
- varNum < compiler->info.compArgsCount &&
- !compiler->lvaTable[varNum].lvIsRegArg)
+ if (compiler->info.compIsVarArgs && varNum != compiler->lvaVarargsHandleArg &&
+ varNum < compiler->info.compArgsCount && !compiler->lvaTable[varNum].lvIsRegArg)
{
noway_assert(varLoc.vlType == Compiler::VLT_STK || varLoc.vlType == Compiler::VLT_STK2);
@@ -21249,12 +20765,12 @@ void CodeGen::genSetScopeInfo (unsigned which,
unsigned varOffset = compiler->lvaTable[varNum].lvStkOffs;
noway_assert(cookieOffset < varOffset);
- unsigned offset = varOffset - cookieOffset;
- unsigned stkArgSize = compiler->compArgSize - intRegState.rsCalleeRegArgCount * sizeof(void *);
+ unsigned offset = varOffset - cookieOffset;
+ unsigned stkArgSize = compiler->compArgSize - intRegState.rsCalleeRegArgCount * sizeof(void*);
noway_assert(offset < stkArgSize);
offset = stkArgSize - offset;
- varLoc.vlType = Compiler::VLT_FIXED_VA;
+ varLoc.vlType = Compiler::VLT_FIXED_VA;
varLoc.vlFixedVarArg.vlfvOffset = offset;
}
@@ -21274,15 +20790,15 @@ void CodeGen::genSetScopeInfo (unsigned which,
// Hang on to this compiler->info.
- TrnslLocalVarInfo &tlvi = genTrnslLocalVarInfo[which];
+ TrnslLocalVarInfo& tlvi = genTrnslLocalVarInfo[which];
- tlvi.tlviVarNum = ilVarNum;
- tlvi.tlviLVnum = LVnum;
- tlvi.tlviName = name;
- tlvi.tlviStartPC = startOffs;
- tlvi.tlviLength = length;
- tlvi.tlviAvailable = avail;
- tlvi.tlviVarLoc = varLoc;
+ tlvi.tlviVarNum = ilVarNum;
+ tlvi.tlviLVnum = LVnum;
+ tlvi.tlviName = name;
+ tlvi.tlviStartPC = startOffs;
+ tlvi.tlviLength = length;
+ tlvi.tlviAvailable = avail;
+ tlvi.tlviVarLoc = varLoc;
#endif // DEBUG
@@ -21290,7 +20806,7 @@ void CodeGen::genSetScopeInfo (unsigned which,
}
/*****************************************************************************/
-#endif // DEBUGGING_SUPPORT
+#endif // DEBUGGING_SUPPORT
/*****************************************************************************/
/*****************************************************************************
@@ -21302,13 +20818,13 @@ void CodeGen::genSetScopeInfo (unsigned which,
* constant operand, and one that's in a register. Thus, the only thing we
* need to determine is whether the register holding op1 is dead.
*/
-bool CodeGen::genRegTrashable(regNumber reg, GenTreePtr tree)
+bool CodeGen::genRegTrashable(regNumber reg, GenTreePtr tree)
{
- regMaskTP vars;
- regMaskTP mask = genRegMask(reg);
+ regMaskTP vars;
+ regMaskTP mask = genRegMask(reg);
- if (regSet.rsMaskUsed & mask)
- return false;
+ if (regSet.rsMaskUsed & mask)
+ return false;
assert(tree->gtOper == GT_ADD);
GenTreePtr regValTree = tree->gtOp.gtOp1;
@@ -21326,260 +20842,255 @@ bool CodeGen::genRegTrashable(regNumber reg, GenTreePtr tree)
if (regValTree->IsRegVar() && !regValTree->IsRegVarDeath())
return false;
else
- return true;
+ return true;
}
- /*****************************************************************************/
- //
- // This method calculates the USE and DEF values for a statement.
- // It also calls fgSetRngChkTarget for the statement.
- //
- // We refactor out this code from fgPerBlockLocalVarLiveness
- // and add QMARK logics to it.
- //
- // NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE
- //
- // The usage of this method is very limited.
- // We should only call it for the first node in the statement or
- // for the node after the GTF_RELOP_QMARK node.
- //
- // NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE
-
-
- /*
- Since a GT_QMARK tree can take two paths (i.e. the thenTree Path or the elseTree path),
- when we calculate its fgCurDefSet and fgCurUseSet, we need to combine the results
- from both trees.
-
- Note that the GT_QMARK trees are threaded as shown below with nodes 1 to 11
- linked by gtNext.
-
- The algorithm we use is:
- (1) We walk these nodes according the the evaluation order (i.e. from node 1 to node 11).
- (2) When we see the GTF_RELOP_QMARK node, we know we are about to split the path.
- We cache copies of current fgCurDefSet and fgCurUseSet.
- (The fact that it is recursively calling itself is for nested QMARK case,
- where we need to remember multiple copies of fgCurDefSet and fgCurUseSet.)
- (3) We walk the thenTree.
- (4) When we see GT_COLON node, we know that we just finished the thenTree.
- We then make a copy of the current fgCurDefSet and fgCurUseSet,
- restore them to the ones before the thenTree, and then continue walking
- the elseTree.
- (5) When we see the GT_QMARK node, we know we just finished the elseTree.
- So we combine the results from the thenTree and elseTree and then return.
-
-
- +--------------------+
- | GT_QMARK 11|
- +----------+---------+
- |
- *
- / \
- / \
- / \
- +---------------------+ +--------------------+
- | GT_<cond> 3 | | GT_COLON 7 |
- | w/ GTF_RELOP_QMARK | | w/ GTF_COLON_COND |
- +----------+----------+ +---------+----------+
- | |
- * *
- / \ / \
- / \ / \
- / \ / \
- 2 1 thenTree 6 elseTree 10
- x | |
- / * *
- +----------------+ / / \ / \
- |prevExpr->gtNext+------/ / \ / \
- +----------------+ / \ / \
- 5 4 9 8
+/*****************************************************************************/
+//
+// This method calculates the USE and DEF values for a statement.
+// It also calls fgSetRngChkTarget for the statement.
+//
+// We refactor out this code from fgPerBlockLocalVarLiveness
+// and add QMARK logics to it.
+//
+// NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE
+//
+// The usage of this method is very limited.
+// We should only call it for the first node in the statement or
+// for the node after the GTF_RELOP_QMARK node.
+//
+// NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE
+
+/*
+ Since a GT_QMARK tree can take two paths (i.e. the thenTree Path or the elseTree path),
+ when we calculate its fgCurDefSet and fgCurUseSet, we need to combine the results
+ from both trees.
+
+ Note that the GT_QMARK trees are threaded as shown below with nodes 1 to 11
+ linked by gtNext.
+
+ The algorithm we use is:
+ (1) We walk these nodes according the the evaluation order (i.e. from node 1 to node 11).
+ (2) When we see the GTF_RELOP_QMARK node, we know we are about to split the path.
+ We cache copies of current fgCurDefSet and fgCurUseSet.
+ (The fact that it is recursively calling itself is for nested QMARK case,
+ where we need to remember multiple copies of fgCurDefSet and fgCurUseSet.)
+ (3) We walk the thenTree.
+ (4) When we see GT_COLON node, we know that we just finished the thenTree.
+ We then make a copy of the current fgCurDefSet and fgCurUseSet,
+ restore them to the ones before the thenTree, and then continue walking
+ the elseTree.
+ (5) When we see the GT_QMARK node, we know we just finished the elseTree.
+ So we combine the results from the thenTree and elseTree and then return.
+
+
+ +--------------------+
+ | GT_QMARK 11|
+ +----------+---------+
+ |
+ *
+ / \
+ / \
+ / \
+ +---------------------+ +--------------------+
+ | GT_<cond> 3 | | GT_COLON 7 |
+ | w/ GTF_RELOP_QMARK | | w/ GTF_COLON_COND |
+ +----------+----------+ +---------+----------+
+ | |
+ * *
+ / \ / \
+ / \ / \
+ / \ / \
+ 2 1 thenTree 6 elseTree 10
+ x | |
+ / * *
+ +----------------+ / / \ / \
+ |prevExpr->gtNext+------/ / \ / \
+ +----------------+ / \ / \
+ 5 4 9 8
- */
+*/
-GenTreePtr Compiler::fgLegacyPerStatementLocalVarLiveness(GenTreePtr startNode, // The node to start walking with.
- GenTreePtr relopNode, // The node before the startNode.
- // (It should either be NULL or
- // a GTF_RELOP_QMARK node.)
- GenTreePtr asgdLclVar
- )
+GenTreePtr Compiler::fgLegacyPerStatementLocalVarLiveness(GenTreePtr startNode, // The node to start walking with.
+ GenTreePtr relopNode, // The node before the startNode.
+ // (It should either be NULL or
+ // a GTF_RELOP_QMARK node.)
+ GenTreePtr asgdLclVar)
{
GenTreePtr tree;
- VARSET_TP VARSET_INIT(this, defSet_BeforeSplit, fgCurDefSet); // Store the current fgCurDefSet and fgCurUseSet so
- VARSET_TP VARSET_INIT(this, useSet_BeforeSplit, fgCurUseSet); // we can restore then before entering the elseTree.
+ VARSET_TP VARSET_INIT(this, defSet_BeforeSplit, fgCurDefSet); // Store the current fgCurDefSet and fgCurUseSet so
+ VARSET_TP VARSET_INIT(this, useSet_BeforeSplit, fgCurUseSet); // we can restore then before entering the elseTree.
bool heapUse_BeforeSplit = fgCurHeapUse;
bool heapDef_BeforeSplit = fgCurHeapDef;
bool heapHavoc_BeforeSplit = fgCurHeapHavoc;
- VARSET_TP VARSET_INIT_NOCOPY(defSet_AfterThenTree, VarSetOps::MakeEmpty(this)); // These two variables will store the USE and DEF sets after
- VARSET_TP VARSET_INIT_NOCOPY(useSet_AfterThenTree, VarSetOps::MakeEmpty(this)); // evaluating the thenTree.
+ VARSET_TP VARSET_INIT_NOCOPY(defSet_AfterThenTree, VarSetOps::MakeEmpty(this)); // These two variables will store
+ // the USE and DEF sets after
+ VARSET_TP VARSET_INIT_NOCOPY(useSet_AfterThenTree, VarSetOps::MakeEmpty(this)); // evaluating the thenTree.
bool heapUse_AfterThenTree = fgCurHeapUse;
bool heapDef_AfterThenTree = fgCurHeapDef;
bool heapHavoc_AfterThenTree = fgCurHeapHavoc;
// relopNode is either NULL or a GTF_RELOP_QMARK node.
- assert(!relopNode ||
- (relopNode->OperKind() & GTK_RELOP) && (relopNode->gtFlags & GTF_RELOP_QMARK)
- );
+ assert(!relopNode || (relopNode->OperKind() & GTK_RELOP) && (relopNode->gtFlags & GTF_RELOP_QMARK));
// If relopNode is NULL, then the startNode must be the 1st node of the statement.
// If relopNode is non-NULL, then the startNode must be the node right after the GTF_RELOP_QMARK node.
- assert( (!relopNode && startNode == compCurStmt->gtStmt.gtStmtList) ||
- (relopNode && startNode == relopNode->gtNext)
- );
+ assert((!relopNode && startNode == compCurStmt->gtStmt.gtStmtList) ||
+ (relopNode && startNode == relopNode->gtNext));
for (tree = startNode; tree; tree = tree->gtNext)
{
switch (tree->gtOper)
{
- case GT_QMARK:
-
- // This must be a GT_QMARK node whose GTF_RELOP_QMARK node is recursively calling us.
- noway_assert(relopNode && tree->gtOp.gtOp1 == relopNode);
+ case GT_QMARK:
- // By the time we see a GT_QMARK, we must have finished processing the elseTree.
- // So it's the time to combine the results
- // from the the thenTree and the elseTree, and then return.
+ // This must be a GT_QMARK node whose GTF_RELOP_QMARK node is recursively calling us.
+ noway_assert(relopNode && tree->gtOp.gtOp1 == relopNode);
- VarSetOps::IntersectionD(this, fgCurDefSet, defSet_AfterThenTree);
- VarSetOps::UnionD(this, fgCurUseSet, useSet_AfterThenTree);
+ // By the time we see a GT_QMARK, we must have finished processing the elseTree.
+ // So it's the time to combine the results
+ // from the the thenTree and the elseTree, and then return.
- fgCurHeapDef = fgCurHeapDef && heapDef_AfterThenTree;
- fgCurHeapHavoc = fgCurHeapHavoc && heapHavoc_AfterThenTree;
- fgCurHeapUse = fgCurHeapUse || heapUse_AfterThenTree;
+ VarSetOps::IntersectionD(this, fgCurDefSet, defSet_AfterThenTree);
+ VarSetOps::UnionD(this, fgCurUseSet, useSet_AfterThenTree);
- // Return the GT_QMARK node itself so the caller can continue from there.
- // NOTE: the caller will get to the next node by doing the "tree = tree->gtNext"
- // in the "for" statement.
- goto _return;
+ fgCurHeapDef = fgCurHeapDef && heapDef_AfterThenTree;
+ fgCurHeapHavoc = fgCurHeapHavoc && heapHavoc_AfterThenTree;
+ fgCurHeapUse = fgCurHeapUse || heapUse_AfterThenTree;
- case GT_COLON:
- // By the time we see GT_COLON, we must have just walked the thenTree.
- // So we need to do two things here.
- // (1) Save the current fgCurDefSet and fgCurUseSet so that later we can combine them
- // with the result from the elseTree.
- // (2) Restore fgCurDefSet and fgCurUseSet to the points before the thenTree is walked.
- // and then continue walking the elseTree.
- VarSetOps::Assign(this, defSet_AfterThenTree, fgCurDefSet);
- VarSetOps::Assign(this, useSet_AfterThenTree, fgCurUseSet);
+ // Return the GT_QMARK node itself so the caller can continue from there.
+ // NOTE: the caller will get to the next node by doing the "tree = tree->gtNext"
+ // in the "for" statement.
+ goto _return;
- heapDef_AfterThenTree = fgCurHeapDef;
- heapHavoc_AfterThenTree = fgCurHeapHavoc;
- heapUse_AfterThenTree = fgCurHeapUse;
+ case GT_COLON:
+ // By the time we see GT_COLON, we must have just walked the thenTree.
+ // So we need to do two things here.
+ // (1) Save the current fgCurDefSet and fgCurUseSet so that later we can combine them
+ // with the result from the elseTree.
+ // (2) Restore fgCurDefSet and fgCurUseSet to the points before the thenTree is walked.
+ // and then continue walking the elseTree.
+ VarSetOps::Assign(this, defSet_AfterThenTree, fgCurDefSet);
+ VarSetOps::Assign(this, useSet_AfterThenTree, fgCurUseSet);
- VarSetOps::Assign(this, fgCurDefSet, defSet_BeforeSplit);
- VarSetOps::Assign(this, fgCurUseSet, useSet_BeforeSplit);
+ heapDef_AfterThenTree = fgCurHeapDef;
+ heapHavoc_AfterThenTree = fgCurHeapHavoc;
+ heapUse_AfterThenTree = fgCurHeapUse;
- fgCurHeapDef = heapDef_BeforeSplit;
- fgCurHeapHavoc = heapHavoc_BeforeSplit;
- fgCurHeapUse = heapUse_BeforeSplit;
+ VarSetOps::Assign(this, fgCurDefSet, defSet_BeforeSplit);
+ VarSetOps::Assign(this, fgCurUseSet, useSet_BeforeSplit);
- break;
+ fgCurHeapDef = heapDef_BeforeSplit;
+ fgCurHeapHavoc = heapHavoc_BeforeSplit;
+ fgCurHeapUse = heapUse_BeforeSplit;
- case GT_LCL_VAR:
- case GT_LCL_FLD:
- case GT_LCL_VAR_ADDR:
- case GT_LCL_FLD_ADDR:
- case GT_STORE_LCL_VAR:
- case GT_STORE_LCL_FLD:
- fgMarkUseDef(tree->AsLclVarCommon(), asgdLclVar);
- break;
+ break;
- case GT_CLS_VAR:
- // For Volatile indirection, first mutate the global heap
- // see comments in ValueNum.cpp (under case GT_CLS_VAR)
- // This models Volatile reads as def-then-use of the heap.
- // and allows for a CSE of a subsequent non-volatile read
- if ((tree->gtFlags & GTF_FLD_VOLATILE) != 0)
- {
- // For any Volatile indirection, we must handle it as a
- // definition of the global heap
- fgCurHeapDef = true;
+ case GT_LCL_VAR:
+ case GT_LCL_FLD:
+ case GT_LCL_VAR_ADDR:
+ case GT_LCL_FLD_ADDR:
+ case GT_STORE_LCL_VAR:
+ case GT_STORE_LCL_FLD:
+ fgMarkUseDef(tree->AsLclVarCommon(), asgdLclVar);
+ break;
- }
- // If the GT_CLS_VAR is the lhs of an assignment, we'll handle it as a heap def, when we get to assignment.
- // Otherwise, we treat it as a use here.
- if (!fgCurHeapDef && (tree->gtFlags & GTF_CLS_VAR_ASG_LHS) == 0)
- {
- fgCurHeapUse = true;
- }
- break;
+ case GT_CLS_VAR:
+ // For Volatile indirection, first mutate the global heap
+ // see comments in ValueNum.cpp (under case GT_CLS_VAR)
+ // This models Volatile reads as def-then-use of the heap.
+ // and allows for a CSE of a subsequent non-volatile read
+ if ((tree->gtFlags & GTF_FLD_VOLATILE) != 0)
+ {
+ // For any Volatile indirection, we must handle it as a
+ // definition of the global heap
+ fgCurHeapDef = true;
+ }
+ // If the GT_CLS_VAR is the lhs of an assignment, we'll handle it as a heap def, when we get to
+ // assignment.
+ // Otherwise, we treat it as a use here.
+ if (!fgCurHeapDef && (tree->gtFlags & GTF_CLS_VAR_ASG_LHS) == 0)
+ {
+ fgCurHeapUse = true;
+ }
+ break;
- case GT_IND:
- // For Volatile indirection, first mutate the global heap
- // see comments in ValueNum.cpp (under case GT_CLS_VAR)
- // This models Volatile reads as def-then-use of the heap.
- // and allows for a CSE of a subsequent non-volatile read
- if ((tree->gtFlags & GTF_IND_VOLATILE) != 0)
- {
- // For any Volatile indirection, we must handle it as a
- // definition of the global heap
- fgCurHeapDef = true;
- }
+ case GT_IND:
+ // For Volatile indirection, first mutate the global heap
+ // see comments in ValueNum.cpp (under case GT_CLS_VAR)
+ // This models Volatile reads as def-then-use of the heap.
+ // and allows for a CSE of a subsequent non-volatile read
+ if ((tree->gtFlags & GTF_IND_VOLATILE) != 0)
+ {
+ // For any Volatile indirection, we must handle it as a
+ // definition of the global heap
+ fgCurHeapDef = true;
+ }
- // If the GT_IND is the lhs of an assignment, we'll handle it
- // as a heap def, when we get to assignment.
- // Otherwise, we treat it as a use here.
- if ((tree->gtFlags & GTF_IND_ASG_LHS) == 0)
- {
- GenTreeLclVarCommon* dummyLclVarTree = NULL;
- bool dummyIsEntire = false;
- GenTreePtr addrArg = tree->gtOp.gtOp1->gtEffectiveVal(/*commaOnly*/true);
- if (!addrArg->DefinesLocalAddr(this, /*width doesn't matter*/0, &dummyLclVarTree, &dummyIsEntire))
+ // If the GT_IND is the lhs of an assignment, we'll handle it
+ // as a heap def, when we get to assignment.
+ // Otherwise, we treat it as a use here.
+ if ((tree->gtFlags & GTF_IND_ASG_LHS) == 0)
{
- if (!fgCurHeapDef)
+ GenTreeLclVarCommon* dummyLclVarTree = NULL;
+ bool dummyIsEntire = false;
+ GenTreePtr addrArg = tree->gtOp.gtOp1->gtEffectiveVal(/*commaOnly*/ true);
+ if (!addrArg->DefinesLocalAddr(this, /*width doesn't matter*/ 0, &dummyLclVarTree, &dummyIsEntire))
{
- fgCurHeapUse = true;
+ if (!fgCurHeapDef)
+ {
+ fgCurHeapUse = true;
+ }
+ }
+ else
+ {
+ // Defines a local addr
+ assert(dummyLclVarTree != nullptr);
+ fgMarkUseDef(dummyLclVarTree->AsLclVarCommon(), asgdLclVar);
}
}
- else
- {
- // Defines a local addr
- assert(dummyLclVarTree != nullptr);
- fgMarkUseDef(dummyLclVarTree->AsLclVarCommon(), asgdLclVar);
- }
- }
- break;
+ break;
// These should have been morphed away to become GT_INDs:
- case GT_FIELD:
- case GT_INDEX:
- unreached();
- break;
+ case GT_FIELD:
+ case GT_INDEX:
+ unreached();
+ break;
// We'll assume these are use-then-defs of the heap.
- case GT_LOCKADD:
- case GT_XADD:
- case GT_XCHG:
- case GT_CMPXCHG:
- if (!fgCurHeapDef)
- {
- fgCurHeapUse = true;
- }
- fgCurHeapDef = true;
- fgCurHeapHavoc = true;
- break;
+ case GT_LOCKADD:
+ case GT_XADD:
+ case GT_XCHG:
+ case GT_CMPXCHG:
+ if (!fgCurHeapDef)
+ {
+ fgCurHeapUse = true;
+ }
+ fgCurHeapDef = true;
+ fgCurHeapHavoc = true;
+ break;
- case GT_MEMORYBARRIER:
- // Simliar to any Volatile indirection, we must handle this as a definition of the global heap
- fgCurHeapDef = true;
- break;
+ case GT_MEMORYBARRIER:
+ // Simliar to any Volatile indirection, we must handle this as a definition of the global heap
+ fgCurHeapDef = true;
+ break;
// For now, all calls read/write the heap, the latter in its entirety. Might tighten this case later.
- case GT_CALL:
+ case GT_CALL:
{
- GenTreeCall* call = tree->AsCall();
- bool modHeap = true;
+ GenTreeCall* call = tree->AsCall();
+ bool modHeap = true;
if (call->gtCallType == CT_HELPER)
{
CorInfoHelpFunc helpFunc = eeGetHelperNum(call->gtCallMethHnd);
- if ( !s_helperCallProperties.MutatesHeap(helpFunc)
- && !s_helperCallProperties.MayRunCctor(helpFunc))
+ if (!s_helperCallProperties.MutatesHeap(helpFunc) && !s_helperCallProperties.MayRunCctor(helpFunc))
{
modHeap = false;
}
@@ -21590,66 +21101,67 @@ GenTreePtr Compiler::fgLegacyPerStatementLocalVarLiveness(GenTreePtr startNode,
{
fgCurHeapUse = true;
}
- fgCurHeapDef = true;
+ fgCurHeapDef = true;
fgCurHeapHavoc = true;
}
}
- // If this is a p/invoke unmanaged call or if this is a tail-call
- // and we have an unmanaged p/invoke call in the method,
- // then we're going to run the p/invoke epilog.
- // So we mark the FrameRoot as used by this instruction.
- // This ensures that the block->bbVarUse will contain
- // the FrameRoot local var if is it a tracked variable.
+ // If this is a p/invoke unmanaged call or if this is a tail-call
+ // and we have an unmanaged p/invoke call in the method,
+ // then we're going to run the p/invoke epilog.
+ // So we mark the FrameRoot as used by this instruction.
+ // This ensures that the block->bbVarUse will contain
+ // the FrameRoot local var if is it a tracked variable.
- if (tree->gtCall.IsUnmanaged() || (tree->gtCall.IsTailCall() && info.compCallUnmanaged))
- {
- /* Get the TCB local and mark it as used */
+ if (tree->gtCall.IsUnmanaged() || (tree->gtCall.IsTailCall() && info.compCallUnmanaged))
+ {
+ /* Get the TCB local and mark it as used */
- noway_assert(info.compLvFrameListRoot < lvaCount);
+ noway_assert(info.compLvFrameListRoot < lvaCount);
- LclVarDsc* varDsc = &lvaTable[info.compLvFrameListRoot];
+ LclVarDsc* varDsc = &lvaTable[info.compLvFrameListRoot];
- if (varDsc->lvTracked)
- {
- if (!VarSetOps::IsMember(this, fgCurDefSet, varDsc->lvVarIndex))
+ if (varDsc->lvTracked)
{
- VarSetOps::AddElemD(this, fgCurUseSet, varDsc->lvVarIndex);
+ if (!VarSetOps::IsMember(this, fgCurDefSet, varDsc->lvVarIndex))
+ {
+ VarSetOps::AddElemD(this, fgCurUseSet, varDsc->lvVarIndex);
+ }
}
}
- }
- break;
+ break;
- default:
+ default:
- // Determine whether it defines a heap location.
- if (tree->OperIsAssignment() || tree->OperIsBlkOp())
- {
- GenTreeLclVarCommon* dummyLclVarTree = NULL;
- if (!tree->DefinesLocal(this, &dummyLclVarTree))
+ // Determine whether it defines a heap location.
+ if (tree->OperIsAssignment() || tree->OperIsBlkOp())
{
- // If it doesn't define a local, then it might update the heap.
- fgCurHeapDef = true;
+ GenTreeLclVarCommon* dummyLclVarTree = NULL;
+ if (!tree->DefinesLocal(this, &dummyLclVarTree))
+ {
+ // If it doesn't define a local, then it might update the heap.
+ fgCurHeapDef = true;
+ }
}
- }
-
- // Are we seeing a GT_<cond> for a GT_QMARK node?
- if ( (tree->OperKind() & GTK_RELOP) &&
- (tree->gtFlags & GTF_RELOP_QMARK)
- ) {
- // We are about to enter the parallel paths (i.e. the thenTree and the elseTree).
- // Recursively call fgLegacyPerStatementLocalVarLiveness.
- // At the very beginning of fgLegacyPerStatementLocalVarLiveness, we will cache the values of the current
- // fgCurDefSet and fgCurUseSet into local variables defSet_BeforeSplit and useSet_BeforeSplit.
- // The cached values will be used to restore fgCurDefSet and fgCurUseSet once we see the GT_COLON node.
- tree = fgLegacyPerStatementLocalVarLiveness(tree->gtNext, tree, asgdLclVar);
- // We must have been returned here after seeing a GT_QMARK node.
- noway_assert(tree->gtOper == GT_QMARK);
- }
+ // Are we seeing a GT_<cond> for a GT_QMARK node?
+ if ((tree->OperKind() & GTK_RELOP) && (tree->gtFlags & GTF_RELOP_QMARK))
+ {
+ // We are about to enter the parallel paths (i.e. the thenTree and the elseTree).
+ // Recursively call fgLegacyPerStatementLocalVarLiveness.
+ // At the very beginning of fgLegacyPerStatementLocalVarLiveness, we will cache the values of the
+ // current
+ // fgCurDefSet and fgCurUseSet into local variables defSet_BeforeSplit and useSet_BeforeSplit.
+ // The cached values will be used to restore fgCurDefSet and fgCurUseSet once we see the GT_COLON
+ // node.
+ tree = fgLegacyPerStatementLocalVarLiveness(tree->gtNext, tree, asgdLclVar);
+
+ // We must have been returned here after seeing a GT_QMARK node.
+ noway_assert(tree->gtOper == GT_QMARK);
+ }
- break;
+ break;
}
}
@@ -21682,25 +21194,25 @@ _return:
* +20h Saved value of EBP method prolog
*/
-regMaskTP CodeGen::genPInvokeMethodProlog(regMaskTP initRegs)
+regMaskTP CodeGen::genPInvokeMethodProlog(regMaskTP initRegs)
{
assert(compiler->compGeneratingProlog);
noway_assert(!compiler->opts.ShouldUsePInvokeHelpers());
noway_assert(compiler->info.compCallUnmanaged);
- CORINFO_EE_INFO * pInfo = compiler->eeGetEEInfo();
+ CORINFO_EE_INFO* pInfo = compiler->eeGetEEInfo();
noway_assert(compiler->lvaInlinedPInvokeFrameVar != BAD_VAR_NUM);
/* let's find out if compLvFrameListRoot is enregistered */
- LclVarDsc * varDsc = &compiler->lvaTable[compiler->info.compLvFrameListRoot];
+ LclVarDsc* varDsc = &compiler->lvaTable[compiler->info.compLvFrameListRoot];
noway_assert(!varDsc->lvIsParam);
noway_assert(varDsc->lvType == TYP_I_IMPL);
DWORD threadTlsIndex, *pThreadTlsIndex;
- threadTlsIndex = compiler->info.compCompHnd->getThreadTLSIndex((void**) &pThreadTlsIndex);
+ threadTlsIndex = compiler->info.compCompHnd->getThreadTLSIndex((void**)&pThreadTlsIndex);
#if defined(_TARGET_X86_)
if (threadTlsIndex == (DWORD)-1 || pInfo->osType != CORINFO_WINNT)
#else
@@ -21711,11 +21223,8 @@ regMaskTP CodeGen::genPInvokeMethodProlog(regMaskTP initRegs)
// InlinedCallFrame vptr through indirections, we'll call only one helper.
// The helper takes frame address in REG_PINVOKE_FRAME, returns TCB in REG_PINVOKE_TCB
// and uses REG_PINVOKE_SCRATCH as scratch register.
- getEmitter()->emitIns_R_S (INS_lea,
- EA_PTRSIZE,
- REG_PINVOKE_FRAME,
- compiler->lvaInlinedPInvokeFrameVar,
- pInfo->inlinedCallFrameInfo.offsetOfFrameVptr);
+ getEmitter()->emitIns_R_S(INS_lea, EA_PTRSIZE, REG_PINVOKE_FRAME, compiler->lvaInlinedPInvokeFrameVar,
+ pInfo->inlinedCallFrameInfo.offsetOfFrameVptr);
regTracker.rsTrackRegTrash(REG_PINVOKE_FRAME);
// We're about to trask REG_PINVOKE_TCB, it better not be in use!
@@ -21723,11 +21232,11 @@ regMaskTP CodeGen::genPInvokeMethodProlog(regMaskTP initRegs)
// Don't use the argument registers (including the special argument in
// REG_PINVOKE_FRAME) for computing the target address.
- regSet.rsLockReg(RBM_ARG_REGS|RBM_PINVOKE_FRAME);
+ regSet.rsLockReg(RBM_ARG_REGS | RBM_PINVOKE_FRAME);
genEmitHelperCall(CORINFO_HELP_INIT_PINVOKE_FRAME, 0, EA_UNKNOWN);
- regSet.rsUnlockReg(RBM_ARG_REGS|RBM_PINVOKE_FRAME);
+ regSet.rsUnlockReg(RBM_ARG_REGS | RBM_PINVOKE_FRAME);
if (varDsc->lvRegister)
{
@@ -21747,18 +21256,15 @@ regMaskTP CodeGen::genPInvokeMethodProlog(regMaskTP initRegs)
else
{
// move TCB to its stack location
- getEmitter()->emitIns_S_R (ins_Store(TYP_I_IMPL),
- EA_PTRSIZE,
- REG_PINVOKE_TCB,
- compiler->info.compLvFrameListRoot,
- 0);
+ getEmitter()->emitIns_S_R(ins_Store(TYP_I_IMPL), EA_PTRSIZE, REG_PINVOKE_TCB,
+ compiler->info.compLvFrameListRoot, 0);
}
// We are done, the rest of this function deals with the inlined case.
return initRegs;
}
- regNumber regTCB;
+ regNumber regTCB;
if (varDsc->lvRegister)
{
@@ -21784,33 +21290,22 @@ regMaskTP CodeGen::genPInvokeMethodProlog(regMaskTP initRegs)
if (threadTlsIndex < 64)
{
// mov reg, FS:[0xE10+threadTlsIndex*4]
- getEmitter()->emitIns_R_C (ins_Load(TYP_I_IMPL),
- EA_PTRSIZE,
- regTCB,
- FLD_GLOBAL_FS,
- WIN_NT_TLS_OFFSET + threadTlsIndex * sizeof(int));
+ getEmitter()->emitIns_R_C(ins_Load(TYP_I_IMPL), EA_PTRSIZE, regTCB, FLD_GLOBAL_FS,
+ WIN_NT_TLS_OFFSET + threadTlsIndex * sizeof(int));
regTracker.rsTrackRegTrash(regTCB);
}
else
{
noway_assert(pInfo->osMajor >= 5);
- DWORD basePtr = WIN_NT5_TLS_HIGHOFFSET;
+ DWORD basePtr = WIN_NT5_TLS_HIGHOFFSET;
threadTlsIndex -= 64;
// mov reg, FS:[0x2c] or mov reg, fs:[0xf94]
// mov reg, [reg+threadTlsIndex*4]
- getEmitter()->emitIns_R_C (ins_Load(TYP_I_IMPL),
- EA_PTRSIZE,
- regTCB,
- FLD_GLOBAL_FS,
- basePtr);
- getEmitter()->emitIns_R_AR(ins_Load(TYP_I_IMPL),
- EA_PTRSIZE,
- regTCB,
- regTCB,
- threadTlsIndex*sizeof(int));
+ getEmitter()->emitIns_R_C(ins_Load(TYP_I_IMPL), EA_PTRSIZE, regTCB, FLD_GLOBAL_FS, basePtr);
+ getEmitter()->emitIns_R_AR(ins_Load(TYP_I_IMPL), EA_PTRSIZE, regTCB, regTCB, threadTlsIndex * sizeof(int));
regTracker.rsTrackRegTrash(regTCB);
}
#endif
@@ -21819,92 +21314,67 @@ regMaskTP CodeGen::genPInvokeMethodProlog(regMaskTP initRegs)
if (!varDsc->lvRegister)
{
- getEmitter()->emitIns_S_R (ins_Store(TYP_I_IMPL),
- EA_PTRSIZE,
- regTCB,
- compiler->info.compLvFrameListRoot,
- 0);
+ getEmitter()->emitIns_S_R(ins_Store(TYP_I_IMPL), EA_PTRSIZE, regTCB, compiler->info.compLvFrameListRoot, 0);
}
/* set frame's vptr */
- const void * inlinedCallFrameVptr, **pInlinedCallFrameVptr;
- inlinedCallFrameVptr = compiler->info.compCompHnd->getInlinedCallFrameVptr((void**) &pInlinedCallFrameVptr);
+ const void *inlinedCallFrameVptr, **pInlinedCallFrameVptr;
+ inlinedCallFrameVptr = compiler->info.compCompHnd->getInlinedCallFrameVptr((void**)&pInlinedCallFrameVptr);
noway_assert(inlinedCallFrameVptr != NULL); // if we have the TLS index, vptr must also be known
- instGen_Store_Imm_Into_Lcl(TYP_I_IMPL, EA_HANDLE_CNS_RELOC, (ssize_t) inlinedCallFrameVptr,
- compiler->lvaInlinedPInvokeFrameVar,
- pInfo->inlinedCallFrameInfo.offsetOfFrameVptr,
+ instGen_Store_Imm_Into_Lcl(TYP_I_IMPL, EA_HANDLE_CNS_RELOC, (ssize_t)inlinedCallFrameVptr,
+ compiler->lvaInlinedPInvokeFrameVar, pInfo->inlinedCallFrameInfo.offsetOfFrameVptr,
REG_PINVOKE_SCRATCH);
// Set the GSCookie
- GSCookie gsCookie, * pGSCookie;
+ GSCookie gsCookie, *pGSCookie;
compiler->info.compCompHnd->getGSCookie(&gsCookie, &pGSCookie);
noway_assert(gsCookie != 0); // if we have the TLS index, GS cookie must also be known
- instGen_Store_Imm_Into_Lcl(TYP_I_IMPL, EA_PTRSIZE, (ssize_t) gsCookie,
- compiler->lvaInlinedPInvokeFrameVar,
- pInfo->inlinedCallFrameInfo.offsetOfGSCookie,
- REG_PINVOKE_SCRATCH);
+ instGen_Store_Imm_Into_Lcl(TYP_I_IMPL, EA_PTRSIZE, (ssize_t)gsCookie, compiler->lvaInlinedPInvokeFrameVar,
+ pInfo->inlinedCallFrameInfo.offsetOfGSCookie, REG_PINVOKE_SCRATCH);
/* Get current frame root (mov reg2, [reg+offsetOfThreadFrame]) and
set next field in frame */
- getEmitter()->emitIns_R_AR (ins_Load(TYP_I_IMPL),
- EA_PTRSIZE,
- REG_PINVOKE_SCRATCH,
- regTCB,
- pInfo->offsetOfThreadFrame);
+ getEmitter()->emitIns_R_AR(ins_Load(TYP_I_IMPL), EA_PTRSIZE, REG_PINVOKE_SCRATCH, regTCB,
+ pInfo->offsetOfThreadFrame);
regTracker.rsTrackRegTrash(REG_PINVOKE_SCRATCH);
- getEmitter()->emitIns_S_R (ins_Store(TYP_I_IMPL),
- EA_PTRSIZE,
- REG_PINVOKE_SCRATCH,
- compiler->lvaInlinedPInvokeFrameVar,
- pInfo->inlinedCallFrameInfo.offsetOfFrameLink);
+ getEmitter()->emitIns_S_R(ins_Store(TYP_I_IMPL), EA_PTRSIZE, REG_PINVOKE_SCRATCH,
+ compiler->lvaInlinedPInvokeFrameVar, pInfo->inlinedCallFrameInfo.offsetOfFrameLink);
- noway_assert(isFramePointerUsed()); // Setup of Pinvoke frame currently requires an EBP style frame
+ noway_assert(isFramePointerUsed()); // Setup of Pinvoke frame currently requires an EBP style frame
/* set EBP value in frame */
- getEmitter()->emitIns_S_R (ins_Store(TYP_I_IMPL),
- EA_PTRSIZE,
- genFramePointerReg(),
- compiler->lvaInlinedPInvokeFrameVar,
- pInfo->inlinedCallFrameInfo.offsetOfCalleeSavedFP);
+ getEmitter()->emitIns_S_R(ins_Store(TYP_I_IMPL), EA_PTRSIZE, genFramePointerReg(),
+ compiler->lvaInlinedPInvokeFrameVar, pInfo->inlinedCallFrameInfo.offsetOfCalleeSavedFP);
/* reset track field in frame */
- instGen_Store_Imm_Into_Lcl(TYP_I_IMPL, EA_PTRSIZE, 0,
- compiler->lvaInlinedPInvokeFrameVar,
- pInfo->inlinedCallFrameInfo.offsetOfReturnAddress,
- REG_PINVOKE_SCRATCH);
+ instGen_Store_Imm_Into_Lcl(TYP_I_IMPL, EA_PTRSIZE, 0, compiler->lvaInlinedPInvokeFrameVar,
+ pInfo->inlinedCallFrameInfo.offsetOfReturnAddress, REG_PINVOKE_SCRATCH);
/* get address of our frame */
- getEmitter()->emitIns_R_S (INS_lea,
- EA_PTRSIZE,
- REG_PINVOKE_SCRATCH,
- compiler->lvaInlinedPInvokeFrameVar,
- pInfo->inlinedCallFrameInfo.offsetOfFrameVptr);
+ getEmitter()->emitIns_R_S(INS_lea, EA_PTRSIZE, REG_PINVOKE_SCRATCH, compiler->lvaInlinedPInvokeFrameVar,
+ pInfo->inlinedCallFrameInfo.offsetOfFrameVptr);
regTracker.rsTrackRegTrash(REG_PINVOKE_SCRATCH);
/* now "push" our N/direct frame */
- getEmitter()->emitIns_AR_R (ins_Store(TYP_I_IMPL),
- EA_PTRSIZE,
- REG_PINVOKE_SCRATCH,
- regTCB,
- pInfo->offsetOfThreadFrame);
+ getEmitter()->emitIns_AR_R(ins_Store(TYP_I_IMPL), EA_PTRSIZE, REG_PINVOKE_SCRATCH, regTCB,
+ pInfo->offsetOfThreadFrame);
return initRegs;
}
-
/*****************************************************************************
* Unchain the InlinedCallFrame.
* Technically, this is not part of the epilog; it is called when we are generating code for a GT_RETURN node
* or tail call.
*/
-void CodeGen::genPInvokeMethodEpilog()
+void CodeGen::genPInvokeMethodEpilog()
{
noway_assert(compiler->info.compCallUnmanaged);
noway_assert(!compiler->opts.ShouldUsePInvokeHelpers());
@@ -21912,22 +21382,21 @@ void CodeGen::genPInvokeMethodEpilog()
(compiler->compTailCallUsed && (compiler->compCurBB->bbJumpKind == BBJ_THROW)) ||
(compiler->compJmpOpUsed && (compiler->compCurBB->bbFlags & BBF_HAS_JMP)));
- CORINFO_EE_INFO * pInfo = compiler->eeGetEEInfo();
+ CORINFO_EE_INFO* pInfo = compiler->eeGetEEInfo();
noway_assert(compiler->lvaInlinedPInvokeFrameVar != BAD_VAR_NUM);
getEmitter()->emitDisableRandomNops();
- //debug check to make sure that we're not using ESI and/or EDI across this call, except for
- //compLvFrameListRoot.
+ // debug check to make sure that we're not using ESI and/or EDI across this call, except for
+ // compLvFrameListRoot.
unsigned regTrashCheck = 0;
/* XXX Tue 5/29/2007
* We explicitly add interference for these in CodeGen::rgPredictRegUse. If you change the code
* sequence or registers used, make sure to update the interference for compiler->genReturnLocal.
*/
- LclVarDsc * varDsc = &compiler->lvaTable[compiler->info.compLvFrameListRoot];
- regNumber reg;
- regNumber reg2 = REG_PINVOKE_FRAME;
-
+ LclVarDsc* varDsc = &compiler->lvaTable[compiler->info.compLvFrameListRoot];
+ regNumber reg;
+ regNumber reg2 = REG_PINVOKE_FRAME;
//
// Two cases for epilog invocation:
@@ -21948,7 +21417,8 @@ void CodeGen::genPInvokeMethodEpilog()
{
#if FEATURE_FIXED_OUT_ARGS
// Save the register in the reserved local var slot.
- getEmitter()->emitIns_S_R(ins_Store(TYP_I_IMPL), EA_PTRSIZE, REG_PINVOKE_TCB, compiler->lvaPInvokeFrameRegSaveVar, 0);
+ getEmitter()->emitIns_S_R(ins_Store(TYP_I_IMPL), EA_PTRSIZE, REG_PINVOKE_TCB,
+ compiler->lvaPInvokeFrameRegSaveVar, 0);
#else
inst_RV(INS_push, REG_PINVOKE_TCB, TYP_I_IMPL);
#endif
@@ -21957,7 +21427,8 @@ void CodeGen::genPInvokeMethodEpilog()
{
#if FEATURE_FIXED_OUT_ARGS
// Save the register in the reserved local var slot.
- getEmitter()->emitIns_S_R(ins_Store(TYP_I_IMPL), EA_PTRSIZE, REG_PINVOKE_FRAME, compiler->lvaPInvokeFrameRegSaveVar, REGSIZE_BYTES);
+ getEmitter()->emitIns_S_R(ins_Store(TYP_I_IMPL), EA_PTRSIZE, REG_PINVOKE_FRAME,
+ compiler->lvaPInvokeFrameRegSaveVar, REGSIZE_BYTES);
#else
inst_RV(INS_push, REG_PINVOKE_FRAME, TYP_I_IMPL);
#endif
@@ -21976,11 +21447,8 @@ void CodeGen::genPInvokeMethodEpilog()
{
/* mov esi, [tcb address] */
- getEmitter()->emitIns_R_S (ins_Load(TYP_I_IMPL),
- EA_PTRSIZE,
- REG_PINVOKE_TCB,
- compiler->info.compLvFrameListRoot,
- 0);
+ getEmitter()->emitIns_R_S(ins_Load(TYP_I_IMPL), EA_PTRSIZE, REG_PINVOKE_TCB, compiler->info.compLvFrameListRoot,
+ 0);
regTracker.rsTrackRegTrash(REG_PINVOKE_TCB);
reg = REG_PINVOKE_TCB;
@@ -21989,31 +21457,23 @@ void CodeGen::genPInvokeMethodEpilog()
/* mov edi, [ebp-frame.next] */
- getEmitter()->emitIns_R_S (ins_Load(TYP_I_IMPL),
- EA_PTRSIZE,
- reg2,
- compiler->lvaInlinedPInvokeFrameVar,
+ getEmitter()->emitIns_R_S(ins_Load(TYP_I_IMPL), EA_PTRSIZE, reg2, compiler->lvaInlinedPInvokeFrameVar,
pInfo->inlinedCallFrameInfo.offsetOfFrameLink);
regTracker.rsTrackRegTrash(reg2);
/* mov [esi+offsetOfThreadFrame], edi */
- getEmitter()->emitIns_AR_R (ins_Store(TYP_I_IMPL),
- EA_PTRSIZE,
- reg2,
- reg,
- pInfo->offsetOfThreadFrame);
+ getEmitter()->emitIns_AR_R(ins_Store(TYP_I_IMPL), EA_PTRSIZE, reg2, reg, pInfo->offsetOfThreadFrame);
noway_assert(!(regSet.rsMaskUsed & regTrashCheck));
- if (compiler->genReturnLocal != BAD_VAR_NUM &&
- compiler->lvaTable[compiler->genReturnLocal].lvTracked &&
+ if (compiler->genReturnLocal != BAD_VAR_NUM && compiler->lvaTable[compiler->genReturnLocal].lvTracked &&
compiler->lvaTable[compiler->genReturnLocal].lvRegister)
{
- //really make sure we're not clobbering compiler->genReturnLocal.
- noway_assert(!(genRegMask(compiler->lvaTable[compiler->genReturnLocal].lvRegNum)
- & ( (varDsc->lvRegister ? genRegMask(varDsc->lvRegNum) : 0)
- | RBM_PINVOKE_TCB | RBM_PINVOKE_FRAME)));
+ // really make sure we're not clobbering compiler->genReturnLocal.
+ noway_assert(
+ !(genRegMask(compiler->lvaTable[compiler->genReturnLocal].lvRegNum) &
+ ((varDsc->lvRegister ? genRegMask(varDsc->lvRegNum) : 0) | RBM_PINVOKE_TCB | RBM_PINVOKE_FRAME)));
}
(void)regTrashCheck;
@@ -22025,7 +21485,8 @@ void CodeGen::genPInvokeMethodEpilog()
{
#if FEATURE_FIXED_OUT_ARGS
// Restore the register from the reserved local var slot.
- getEmitter()->emitIns_R_S(ins_Load(TYP_I_IMPL), EA_PTRSIZE, REG_PINVOKE_FRAME, compiler->lvaPInvokeFrameRegSaveVar, REGSIZE_BYTES);
+ getEmitter()->emitIns_R_S(ins_Load(TYP_I_IMPL), EA_PTRSIZE, REG_PINVOKE_FRAME,
+ compiler->lvaPInvokeFrameRegSaveVar, REGSIZE_BYTES);
#else
inst_RV(INS_pop, REG_PINVOKE_FRAME, TYP_I_IMPL);
#endif
@@ -22035,7 +21496,8 @@ void CodeGen::genPInvokeMethodEpilog()
{
#if FEATURE_FIXED_OUT_ARGS
// Restore the register from the reserved local var slot.
- getEmitter()->emitIns_R_S(ins_Load(TYP_I_IMPL), EA_PTRSIZE, REG_PINVOKE_TCB, compiler->lvaPInvokeFrameRegSaveVar, 0);
+ getEmitter()->emitIns_R_S(ins_Load(TYP_I_IMPL), EA_PTRSIZE, REG_PINVOKE_TCB,
+ compiler->lvaPInvokeFrameRegSaveVar, 0);
#else
inst_RV(INS_pop, REG_PINVOKE_TCB, TYP_I_IMPL);
#endif
@@ -22045,7 +21507,6 @@ void CodeGen::genPInvokeMethodEpilog()
getEmitter()->emitEnableRandomNops();
}
-
/*****************************************************************************
This function emits the call-site prolog for direct calls to unmanaged code.
It does all the necessary setup of the InlinedCallFrame.
@@ -22056,10 +21517,10 @@ void CodeGen::genPInvokeMethodEpilog()
(it could be either enregistered or loaded into one of the scratch registers)
*/
-regNumber CodeGen::genPInvokeCallProlog(LclVarDsc* frameListRoot,
- int argSize,
- CORINFO_METHOD_HANDLE methodToken,
- BasicBlock* returnLabel)
+regNumber CodeGen::genPInvokeCallProlog(LclVarDsc* frameListRoot,
+ int argSize,
+ CORINFO_METHOD_HANDLE methodToken,
+ BasicBlock* returnLabel)
{
// Some stack locals might be 'cached' in registers, we need to trash them
// from the regTracker *and* also ensure the gc tracker does not consider
@@ -22076,9 +21537,8 @@ regNumber CodeGen::genPInvokeCallProlog(LclVarDsc* frameList
deadRegs &= regSet.rsMaskVars;
if (deadRegs)
{
- for (LclVarDsc * varDsc = compiler->lvaTable;
- ((varDsc < (compiler->lvaTable + compiler->lvaCount)) && deadRegs);
- varDsc++ )
+ for (LclVarDsc* varDsc = compiler->lvaTable;
+ ((varDsc < (compiler->lvaTable + compiler->lvaCount)) && deadRegs); varDsc++)
{
if (!varDsc->lvTracked || !varDsc->lvRegister)
continue;
@@ -22105,7 +21565,7 @@ regNumber CodeGen::genPInvokeCallProlog(LclVarDsc* frameList
/* Since we are using the InlinedCallFrame, we should have spilled all
GC pointers to it - even from callee-saved registers */
- noway_assert(((gcInfo.gcRegGCrefSetCur|gcInfo.gcRegByrefSetCur) & ~RBM_ARG_REGS) == 0);
+ noway_assert(((gcInfo.gcRegGCrefSetCur | gcInfo.gcRegByrefSetCur) & ~RBM_ARG_REGS) == 0);
/* must specify only one of these parameters */
noway_assert((argSize == 0) || (methodToken == NULL));
@@ -22120,26 +21580,23 @@ regNumber CodeGen::genPInvokeCallProlog(LclVarDsc* frameList
*/
- CORINFO_EE_INFO * pInfo = compiler->eeGetEEInfo();
+ CORINFO_EE_INFO* pInfo = compiler->eeGetEEInfo();
noway_assert(compiler->lvaInlinedPInvokeFrameVar != BAD_VAR_NUM);
-
+
/* mov dword ptr [frame.callSiteTarget], value */
if (methodToken == NULL)
{
/* mov dword ptr [frame.callSiteTarget], argSize */
- instGen_Store_Imm_Into_Lcl(TYP_INT, EA_4BYTE, argSize,
- compiler->lvaInlinedPInvokeFrameVar,
+ instGen_Store_Imm_Into_Lcl(TYP_INT, EA_4BYTE, argSize, compiler->lvaInlinedPInvokeFrameVar,
pInfo->inlinedCallFrameInfo.offsetOfCallTarget);
}
else
{
- void * embedMethHnd, * pEmbedMethHnd;
+ void *embedMethHnd, *pEmbedMethHnd;
- embedMethHnd = (void*)compiler->info.compCompHnd->embedMethodHandle(
- methodToken,
- &pEmbedMethHnd);
+ embedMethHnd = (void*)compiler->info.compCompHnd->embedMethodHandle(methodToken, &pEmbedMethHnd);
noway_assert((!embedMethHnd) != (!pEmbedMethHnd));
@@ -22147,9 +21604,9 @@ regNumber CodeGen::genPInvokeCallProlog(LclVarDsc* frameList
{
/* mov dword ptr [frame.callSiteTarget], "MethodDesc" */
- instGen_Store_Imm_Into_Lcl(TYP_I_IMPL, EA_HANDLE_CNS_RELOC, (ssize_t) embedMethHnd,
- compiler->lvaInlinedPInvokeFrameVar,
- pInfo->inlinedCallFrameInfo.offsetOfCallTarget);
+ instGen_Store_Imm_Into_Lcl(TYP_I_IMPL, EA_HANDLE_CNS_RELOC, (ssize_t)embedMethHnd,
+ compiler->lvaInlinedPInvokeFrameVar,
+ pInfo->inlinedCallFrameInfo.offsetOfCallTarget);
}
else
{
@@ -22159,20 +21616,14 @@ regNumber CodeGen::genPInvokeCallProlog(LclVarDsc* frameList
regNumber reg = regSet.rsPickFreeReg();
#if CPU_LOAD_STORE_ARCH
- instGen_Set_Reg_To_Imm (EA_HANDLE_CNS_RELOC,
- reg,
- (ssize_t) pEmbedMethHnd);
+ instGen_Set_Reg_To_Imm(EA_HANDLE_CNS_RELOC, reg, (ssize_t)pEmbedMethHnd);
getEmitter()->emitIns_R_AR(ins_Load(TYP_I_IMPL), EA_PTRSIZE, reg, reg, 0);
-#else // !CPU_LOAD_STORE_ARCH
- getEmitter()->emitIns_R_AI(ins_Load(TYP_I_IMPL), EA_PTR_DSP_RELOC,
- reg, (ssize_t) pEmbedMethHnd);
+#else // !CPU_LOAD_STORE_ARCH
+ getEmitter()->emitIns_R_AI(ins_Load(TYP_I_IMPL), EA_PTR_DSP_RELOC, reg, (ssize_t)pEmbedMethHnd);
#endif // !CPU_LOAD_STORE_ARCH
regTracker.rsTrackRegTrash(reg);
- getEmitter()->emitIns_S_R (ins_Store(TYP_I_IMPL),
- EA_PTRSIZE,
- reg,
- compiler->lvaInlinedPInvokeFrameVar,
- pInfo->inlinedCallFrameInfo.offsetOfCallTarget);
+ getEmitter()->emitIns_S_R(ins_Store(TYP_I_IMPL), EA_PTRSIZE, reg, compiler->lvaInlinedPInvokeFrameVar,
+ pInfo->inlinedCallFrameInfo.offsetOfCallTarget);
}
}
@@ -22188,44 +21639,29 @@ regNumber CodeGen::genPInvokeCallProlog(LclVarDsc* frameList
/* mov reg, dword ptr [tcb address] */
- getEmitter()->emitIns_R_S (ins_Load(TYP_I_IMPL),
- EA_PTRSIZE,
- tcbReg,
- (unsigned)(frameListRoot - compiler->lvaTable),
- 0);
+ getEmitter()->emitIns_R_S(ins_Load(TYP_I_IMPL), EA_PTRSIZE, tcbReg,
+ (unsigned)(frameListRoot - compiler->lvaTable), 0);
regTracker.rsTrackRegTrash(tcbReg);
}
#ifdef _TARGET_X86_
/* mov dword ptr [frame.callSiteTracker], esp */
- getEmitter()->emitIns_S_R (ins_Store(TYP_I_IMPL),
- EA_PTRSIZE,
- REG_SPBASE,
- compiler->lvaInlinedPInvokeFrameVar,
+ getEmitter()->emitIns_S_R(ins_Store(TYP_I_IMPL), EA_PTRSIZE, REG_SPBASE, compiler->lvaInlinedPInvokeFrameVar,
pInfo->inlinedCallFrameInfo.offsetOfCallSiteSP);
#endif // _TARGET_X86_
#if CPU_LOAD_STORE_ARCH
regNumber tmpReg = regSet.rsGrabReg(RBM_ALLINT & ~genRegMask(tcbReg));
- getEmitter()->emitIns_J_R (INS_adr,
- EA_PTRSIZE,
- returnLabel,
- tmpReg);
+ getEmitter()->emitIns_J_R(INS_adr, EA_PTRSIZE, returnLabel, tmpReg);
regTracker.rsTrackRegTrash(tmpReg);
- getEmitter()->emitIns_S_R (ins_Store(TYP_I_IMPL),
- EA_PTRSIZE,
- tmpReg,
- compiler->lvaInlinedPInvokeFrameVar,
- pInfo->inlinedCallFrameInfo.offsetOfReturnAddress);
-#else // !CPU_LOAD_STORE_ARCH
+ getEmitter()->emitIns_S_R(ins_Store(TYP_I_IMPL), EA_PTRSIZE, tmpReg, compiler->lvaInlinedPInvokeFrameVar,
+ pInfo->inlinedCallFrameInfo.offsetOfReturnAddress);
+#else // !CPU_LOAD_STORE_ARCH
/* mov dword ptr [frame.callSiteReturnAddress], label */
- getEmitter()->emitIns_J_S (ins_Store(TYP_I_IMPL),
- EA_PTRSIZE,
- returnLabel,
- compiler->lvaInlinedPInvokeFrameVar,
- pInfo->inlinedCallFrameInfo.offsetOfReturnAddress);
+ getEmitter()->emitIns_J_S(ins_Store(TYP_I_IMPL), EA_PTRSIZE, returnLabel, compiler->lvaInlinedPInvokeFrameVar,
+ pInfo->inlinedCallFrameInfo.offsetOfReturnAddress);
#endif // !CPU_LOAD_STORE_ARCH
#if CPU_LOAD_STORE_ARCH
@@ -22233,19 +21669,11 @@ regNumber CodeGen::genPInvokeCallProlog(LclVarDsc* frameList
noway_assert(tmpReg != tcbReg);
- getEmitter()->emitIns_AR_R(ins_Store(TYP_BYTE),
- EA_1BYTE,
- tmpReg,
- tcbReg,
- pInfo->offsetOfGCState);
-#else // !CPU_LOAD_STORE_ARCH
+ getEmitter()->emitIns_AR_R(ins_Store(TYP_BYTE), EA_1BYTE, tmpReg, tcbReg, pInfo->offsetOfGCState);
+#else // !CPU_LOAD_STORE_ARCH
/* mov byte ptr [tcbReg+offsetOfGcState], 0 */
- getEmitter()->emitIns_I_AR (ins_Store(TYP_BYTE),
- EA_1BYTE,
- 0,
- tcbReg,
- pInfo->offsetOfGCState);
+ getEmitter()->emitIns_I_AR(ins_Store(TYP_BYTE), EA_1BYTE, 0, tcbReg, pInfo->offsetOfGCState);
#endif // !CPU_LOAD_STORE_ARCH
return tcbReg;
@@ -22275,18 +21703,17 @@ regNumber CodeGen::genPInvokeCallProlog(LclVarDsc* frameList
@f:
*/
-void CodeGen::genPInvokeCallEpilog(LclVarDsc * frameListRoot,
- regMaskTP retVal)
+void CodeGen::genPInvokeCallEpilog(LclVarDsc* frameListRoot, regMaskTP retVal)
{
- BasicBlock * clab_nostop;
- CORINFO_EE_INFO * pInfo = compiler->eeGetEEInfo();
- regNumber reg2;
- regNumber reg3;
+ BasicBlock* clab_nostop;
+ CORINFO_EE_INFO* pInfo = compiler->eeGetEEInfo();
+ regNumber reg2;
+ regNumber reg3;
#ifdef _TARGET_ARM_
reg3 = REG_R3;
#else
- reg3 = REG_EDX;
+ reg3 = REG_EDX;
#endif
getEmitter()->emitDisableRandomNops();
@@ -22309,38 +21736,27 @@ void CodeGen::genPInvokeCallEpilog(LclVarDsc * frameListRoot,
reg2 = REG_ECX;
#endif
- getEmitter()->emitIns_R_S (ins_Load(TYP_I_IMPL),
- EA_PTRSIZE,
- reg2,
- (unsigned)(frameListRoot - compiler->lvaTable),
- 0);
+ getEmitter()->emitIns_R_S(ins_Load(TYP_I_IMPL), EA_PTRSIZE, reg2,
+ (unsigned)(frameListRoot - compiler->lvaTable), 0);
regTracker.rsTrackRegTrash(reg2);
}
-
#ifdef _TARGET_ARM_
/* mov r3, 1 */
/* strb [r2+offsetOfGcState], r3 */
instGen_Set_Reg_To_Imm(EA_PTRSIZE, reg3, 1);
- getEmitter()->emitIns_AR_R (ins_Store(TYP_BYTE),
- EA_1BYTE,
- reg3,
- reg2,
- pInfo->offsetOfGCState);
+ getEmitter()->emitIns_AR_R(ins_Store(TYP_BYTE), EA_1BYTE, reg3, reg2, pInfo->offsetOfGCState);
#else
/* mov byte ptr [tcb+offsetOfGcState], 1 */
- getEmitter()->emitIns_I_AR (ins_Store(TYP_BYTE),
- EA_1BYTE,
- 1,
- reg2,
- pInfo->offsetOfGCState);
+ getEmitter()->emitIns_I_AR(ins_Store(TYP_BYTE), EA_1BYTE, 1, reg2, pInfo->offsetOfGCState);
#endif
/* test global flag (we return to managed code) */
- LONG * addrOfCaptureThreadGlobal, **pAddrOfCaptureThreadGlobal;
+ LONG *addrOfCaptureThreadGlobal, **pAddrOfCaptureThreadGlobal;
- addrOfCaptureThreadGlobal = compiler->info.compCompHnd->getAddrOfCaptureThreadGlobal((void**) &pAddrOfCaptureThreadGlobal);
+ addrOfCaptureThreadGlobal =
+ compiler->info.compCompHnd->getAddrOfCaptureThreadGlobal((void**)&pAddrOfCaptureThreadGlobal);
noway_assert((!addrOfCaptureThreadGlobal) != (!pAddrOfCaptureThreadGlobal));
// Can we directly use addrOfCaptureThreadGlobal?
@@ -22348,52 +21764,26 @@ void CodeGen::genPInvokeCallEpilog(LclVarDsc * frameListRoot,
if (addrOfCaptureThreadGlobal)
{
#ifdef _TARGET_ARM_
- instGen_Set_Reg_To_Imm (EA_HANDLE_CNS_RELOC,
- reg3,
- (ssize_t)addrOfCaptureThreadGlobal);
- getEmitter()->emitIns_R_R_I (ins_Load(TYP_INT),
- EA_4BYTE,
- reg3,
- reg3,
- 0);
+ instGen_Set_Reg_To_Imm(EA_HANDLE_CNS_RELOC, reg3, (ssize_t)addrOfCaptureThreadGlobal);
+ getEmitter()->emitIns_R_R_I(ins_Load(TYP_INT), EA_4BYTE, reg3, reg3, 0);
regTracker.rsTrackRegTrash(reg3);
- getEmitter()->emitIns_R_I (INS_cmp,
- EA_4BYTE,
- reg3,
- 0);
+ getEmitter()->emitIns_R_I(INS_cmp, EA_4BYTE, reg3, 0);
#else
- getEmitter()->emitIns_C_I (INS_cmp,
- EA_PTR_DSP_RELOC,
- FLD_GLOBAL_DS,
- (ssize_t) addrOfCaptureThreadGlobal,
- 0);
+ getEmitter()->emitIns_C_I(INS_cmp, EA_PTR_DSP_RELOC, FLD_GLOBAL_DS, (ssize_t)addrOfCaptureThreadGlobal, 0);
#endif
}
else
{
#ifdef _TARGET_ARM_
- instGen_Set_Reg_To_Imm (EA_HANDLE_CNS_RELOC,
- reg3,
- (ssize_t)pAddrOfCaptureThreadGlobal);
- getEmitter()->emitIns_R_R_I (ins_Load(TYP_INT),
- EA_4BYTE,
- reg3,
- reg3,
- 0);
+ instGen_Set_Reg_To_Imm(EA_HANDLE_CNS_RELOC, reg3, (ssize_t)pAddrOfCaptureThreadGlobal);
+ getEmitter()->emitIns_R_R_I(ins_Load(TYP_INT), EA_4BYTE, reg3, reg3, 0);
regTracker.rsTrackRegTrash(reg3);
- getEmitter()->emitIns_R_R_I (ins_Load(TYP_INT),
- EA_4BYTE,
- reg3,
- reg3,
- 0);
- getEmitter()->emitIns_R_I (INS_cmp,
- EA_4BYTE,
- reg3,
- 0);
+ getEmitter()->emitIns_R_R_I(ins_Load(TYP_INT), EA_4BYTE, reg3, reg3, 0);
+ getEmitter()->emitIns_R_I(INS_cmp, EA_4BYTE, reg3, 0);
#else // !_TARGET_ARM_
getEmitter()->emitIns_R_AI(ins_Load(TYP_I_IMPL), EA_PTR_DSP_RELOC, REG_ECX,
- (ssize_t)pAddrOfCaptureThreadGlobal);
+ (ssize_t)pAddrOfCaptureThreadGlobal);
regTracker.rsTrackRegTrash(REG_ECX);
getEmitter()->emitIns_I_AR(INS_cmp, EA_4BYTE, 0, REG_ECX, 0);
@@ -22409,10 +21799,10 @@ void CodeGen::genPInvokeCallEpilog(LclVarDsc * frameListRoot,
inst_JMP(jmpEqual, clab_nostop);
#ifdef _TARGET_ARM_
- // The helper preserves the return value on ARM
+// The helper preserves the return value on ARM
#else
/* save return value (if necessary) */
- if (retVal != RBM_NONE)
+ if (retVal != RBM_NONE)
{
if (retVal == RBM_INTRET || retVal == RBM_LNGRET)
{
@@ -22432,16 +21822,15 @@ void CodeGen::genPInvokeCallEpilog(LclVarDsc * frameListRoot,
/* emit the call to the EE-helper that stops for GC (or other reasons) */
- genEmitHelperCall(CORINFO_HELP_STOP_FOR_GC,
- 0, /* argSize */
- EA_UNKNOWN); /* retSize */
+ genEmitHelperCall(CORINFO_HELP_STOP_FOR_GC, 0, /* argSize */
+ EA_UNKNOWN); /* retSize */
#ifdef _TARGET_ARM_
- // The helper preserves the return value on ARM
+// The helper preserves the return value on ARM
#else
/* restore return value (if necessary) */
- if (retVal != RBM_NONE)
+ if (retVal != RBM_NONE)
{
if (retVal == RBM_INTRET || retVal == RBM_LNGRET)
{
@@ -22473,9 +21862,8 @@ void CodeGen::genPInvokeCallEpilog(LclVarDsc * frameListRoot,
/* mov dword ptr [frame.callSiteTracker], 0 */
- instGen_Store_Imm_Into_Lcl(TYP_I_IMPL, EA_PTRSIZE, 0,
- compiler->lvaInlinedPInvokeFrameVar,
- pInfo->inlinedCallFrameInfo.offsetOfReturnAddress);
+ instGen_Store_Imm_Into_Lcl(TYP_I_IMPL, EA_PTRSIZE, 0, compiler->lvaInlinedPInvokeFrameVar,
+ pInfo->inlinedCallFrameInfo.offsetOfReturnAddress);
getEmitter()->emitEnableRandomNops();
}
@@ -22486,7 +21874,7 @@ void CodeGen::genPInvokeCallEpilog(LclVarDsc * frameListRoot,
* TRACKING OF FLAGS
*****************************************************************************/
-void CodeGen::genFlagsEqualToNone()
+void CodeGen::genFlagsEqualToNone()
{
genFlagsEqReg = REG_NA;
genFlagsEqVar = (unsigned)-1;
@@ -22499,8 +21887,7 @@ void CodeGen::genFlagsEqualToNone()
* contents of the given register.
*/
-void CodeGen::genFlagsEqualToReg(GenTreePtr tree,
- regNumber reg)
+void CodeGen::genFlagsEqualToReg(GenTreePtr tree, regNumber reg)
{
genFlagsEqLoc.CaptureLocation(getEmitter());
genFlagsEqReg = reg;
@@ -22524,8 +21911,7 @@ void CodeGen::genFlagsEqualToReg(GenTreePtr tree,
* contents of the given local variable.
*/
-void CodeGen::genFlagsEqualToVar(GenTreePtr tree,
- unsigned var)
+void CodeGen::genFlagsEqualToVar(GenTreePtr tree, unsigned var)
{
genFlagsEqLoc.CaptureLocation(getEmitter());
genFlagsEqVar = var;
@@ -22552,9 +21938,9 @@ void CodeGen::genFlagsEqualToVar(GenTreePtr tree,
* true .. the zero flag (ZF) and sign flag (SF) is set
*/
-bool CodeGen::genFlagsAreReg(regNumber reg)
+bool CodeGen::genFlagsAreReg(regNumber reg)
{
- if ((genFlagsEqReg == reg) && genFlagsEqLoc.IsCurrentLocation(getEmitter()))
+ if ((genFlagsEqReg == reg) && genFlagsEqLoc.IsCurrentLocation(getEmitter()))
{
return true;
}
@@ -22562,9 +21948,9 @@ bool CodeGen::genFlagsAreReg(regNumber reg)
return false;
}
-bool CodeGen::genFlagsAreVar(unsigned var)
+bool CodeGen::genFlagsAreVar(unsigned var)
{
- if ((genFlagsEqVar == var) && genFlagsEqLoc.IsCurrentLocation(getEmitter()))
+ if ((genFlagsEqVar == var) && genFlagsEqLoc.IsCurrentLocation(getEmitter()))
{
return true;
}
@@ -22576,8 +21962,7 @@ bool CodeGen::genFlagsAreVar(unsigned var)
* This utility function returns true iff the execution path from "from"
* (inclusive) to "to" (exclusive) contains a death of the given var
*/
-bool
-CodeGen::genContainsVarDeath(GenTreePtr from, GenTreePtr to, unsigned varNum)
+bool CodeGen::genContainsVarDeath(GenTreePtr from, GenTreePtr to, unsigned varNum)
{
GenTreePtr tree;
for (tree = from; tree != NULL && tree != to; tree = tree->gtNext)
@@ -22585,8 +21970,9 @@ CodeGen::genContainsVarDeath(GenTreePtr from, GenTreePtr to, unsigned varNum)
if (tree->IsLocal() && (tree->gtFlags & GTF_VAR_DEATH))
{
unsigned dyingVarNum = tree->gtLclVarCommon.gtLclNum;
- if (dyingVarNum == varNum) return true;
- LclVarDsc * varDsc = &(compiler->lvaTable[varNum]);
+ if (dyingVarNum == varNum)
+ return true;
+ LclVarDsc* varDsc = &(compiler->lvaTable[varNum]);
if (varDsc->lvPromoted)
{
assert(varDsc->lvType == TYP_STRUCT);