var_types storeType = genActualType(varDsc->TypeGet());
emitAttr storeSize = emitActualTypeSize(storeType);
- getEmitter()->emitIns_S_R(ins_Store(storeType), storeSize, varDsc->lvRegNum, varNum, 0);
+#ifdef _TARGET_ARM_
+ if (varDsc->TypeGet() == TYP_LONG)
+ {
+ // long - at least the low half must be enregistered
+ 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));
+ }
+ }
+ else
+#endif // _TARGET_ARM_
+ {
+ getEmitter()->emitIns_S_R(ins_Store(storeType), storeSize, varDsc->lvRegNum, varNum, 0);
+ }
// Update lvRegNum life and GC info to indicate lvRegNum is dead and varDsc stack slot is going live.
// Note that we cannot modify varDsc->lvRegNum here because another basic block may not be expecting it.
// Therefore manually update life of varDsc->lvRegNum.
regNumber argReg = varDsc->lvArgReg; // incoming arg register
regNumber argRegNext = REG_NA;
+#ifdef _TARGET_ARM64_
if (varDsc->lvRegNum != argReg)
{
var_types loadType = TYP_UNDEF;
{
if (varDsc->lvIsHfa())
{
- NYI_ARM("CodeGen::genJmpMethod with multireg HFA arg");
NYI_ARM64("CodeGen::genJmpMethod with multireg HFA arg");
}
firstArgVarNum = varNum;
}
}
+#else
+ bool twoParts = false;
+ var_types loadType = TYP_UNDEF;
+ if (varDsc->TypeGet() == TYP_LONG)
+ {
+ twoParts = true;
+ }
+ else if (varDsc->TypeGet() == TYP_DOUBLE)
+ {
+ if (compiler->info.compIsVarArgs || compiler->opts.compUseSoftFP)
+ {
+ twoParts = true;
+ }
+ }
+
+ if (twoParts)
+ {
+ argRegNext = genRegArgNext(argReg);
+
+ if (varDsc->lvRegNum != argReg)
+ {
+ getEmitter()->emitIns_R_S(INS_ldr, EA_PTRSIZE, argReg, varNum, 0);
+ getEmitter()->emitIns_R_S(INS_ldr, EA_PTRSIZE, argRegNext, varNum, REGSIZE_BYTES);
+ }
+
+ if (compiler->info.compIsVarArgs)
+ {
+ fixedIntArgMask |= genRegMask(argReg);
+ fixedIntArgMask |= genRegMask(argRegNext);
+ }
+ }
+ else if (varDsc->lvIsHfaRegArg())
+ {
+ loadType = varDsc->GetHfaType();
+ regNumber fieldReg = argReg;
+ emitAttr loadSize = emitActualTypeSize(loadType);
+ unsigned maxSize = min(varDsc->lvSize(), (LAST_FP_ARGREG + 1 - argReg) * REGSIZE_BYTES);
+
+ for (unsigned ofs = 0; ofs < maxSize; ofs += (unsigned)loadSize)
+ {
+ if (varDsc->lvRegNum != argReg)
+ {
+ getEmitter()->emitIns_R_S(ins_Load(loadType), loadSize, fieldReg, varNum, ofs);
+ }
+ assert(genIsValidFloatReg(fieldReg)); // we don't use register tracking for FP
+ fieldReg = regNextOfType(fieldReg, loadType);
+ }
+ }
+ else if (varTypeIsStruct(varDsc))
+ {
+ regNumber slotReg = argReg;
+ unsigned maxSize = min(varDsc->lvSize(), (REG_ARG_LAST + 1 - argReg) * REGSIZE_BYTES);
+
+ for (unsigned ofs = 0; ofs < maxSize; ofs += REGSIZE_BYTES)
+ {
+ unsigned idx = ofs / REGSIZE_BYTES;
+ loadType = compiler->getJitGCType(varDsc->lvGcLayout[idx]);
+
+ if (varDsc->lvRegNum != argReg)
+ {
+ emitAttr loadSize = emitActualTypeSize(loadType);
+
+ getEmitter()->emitIns_R_S(ins_Load(loadType), loadSize, slotReg, varNum, ofs);
+ }
+
+ regSet.AddMaskVars(genRegMask(slotReg));
+ gcInfo.gcMarkRegPtrVal(slotReg, loadType);
+ if (genIsValidIntReg(slotReg) && compiler->info.compIsVarArgs)
+ {
+ fixedIntArgMask |= genRegMask(slotReg);
+ }
+
+ slotReg = genRegArgNext(slotReg);
+ }
+ }
+ else
+ {
+ loadType = compiler->mangleVarArgsType(genActualType(varDsc->TypeGet()));
+
+ if (varDsc->lvRegNum != argReg)
+ {
+ getEmitter()->emitIns_R_S(ins_Load(loadType), emitTypeSize(loadType), argReg, varNum, 0);
+ }
+
+ regSet.AddMaskVars(genRegMask(argReg));
+ gcInfo.gcMarkRegPtrVal(argReg, loadType);
+
+ if (genIsValidIntReg(argReg) && compiler->info.compIsVarArgs)
+ {
+ fixedIntArgMask |= genRegMask(argReg);
+ }
+ }
+
+ if (compiler->lvaIsGCTracked(varDsc))
+ {
+ VarSetOps::RemoveElemD(compiler, gcInfo.gcVarPtrSetCur, varNum);
+ }
+#endif
}
// Jmp call to a vararg method - if the method has fewer than fixed arguments that can be max size of reg,