From e2529c3a2f2289571e164f074dbbabe8cc78fc90 Mon Sep 17 00:00:00 2001 From: Hyeongseok Oh Date: Tue, 1 Aug 2017 17:42:56 +0900 Subject: [PATCH] [RyuJIT/ARM32] Tailcall: passing struct argument Fix bug in tailcall(jmp) to pass struct argument Remove NYI for HFA struct passing --- src/jit/codegenarmarch.cpp | 118 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 116 insertions(+), 2 deletions(-) diff --git a/src/jit/codegenarmarch.cpp b/src/jit/codegenarmarch.cpp index f40c33c..3f540e8 100644 --- a/src/jit/codegenarmarch.cpp +++ b/src/jit/codegenarmarch.cpp @@ -2226,7 +2226,23 @@ void CodeGen::genJmpMethod(GenTreePtr jmp) 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. @@ -2272,6 +2288,7 @@ void CodeGen::genJmpMethod(GenTreePtr jmp) regNumber argReg = varDsc->lvArgReg; // incoming arg register regNumber argRegNext = REG_NA; +#ifdef _TARGET_ARM64_ if (varDsc->lvRegNum != argReg) { var_types loadType = TYP_UNDEF; @@ -2299,7 +2316,6 @@ void CodeGen::genJmpMethod(GenTreePtr jmp) { if (varDsc->lvIsHfa()) { - NYI_ARM("CodeGen::genJmpMethod with multireg HFA arg"); NYI_ARM64("CodeGen::genJmpMethod with multireg HFA arg"); } @@ -2339,6 +2355,104 @@ void CodeGen::genJmpMethod(GenTreePtr jmp) 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, -- 2.7.4