diff --git a/src/coreclr/jit/codegencommon.cpp b/src/coreclr/jit/codegencommon.cpp index f3e4fe5db1c25a..7706b63f509c84 100644 --- a/src/coreclr/jit/codegencommon.cpp +++ b/src/coreclr/jit/codegencommon.cpp @@ -1822,8 +1822,19 @@ void CodeGen::genEmitCallWithCurrentGC(EmitCallParams& params) } assert(numRegs == 2); - info.returnValueLoc.storeVariableInRegisters(retDesc->GetABIReturnReg(0, call->GetUnmanagedCallConv()), - retDesc->GetABIReturnReg(1, call->GetUnmanagedCallConv())); + regNumber reg1 = retDesc->GetABIReturnReg(0, call->GetUnmanagedCallConv()); + regNumber reg2 = retDesc->GetABIReturnReg(1, call->GetUnmanagedCallConv()); + + // VLT_REG_REG can only encode integer registers. On platforms where structs + // can be returned in a mix of int and float registers (SysV x64, RISC-V), + // skip recording if any register is not an int register. + // TODO: Supporting this case is tracked by https://github.com/dotnet/runtime/issues/129344 + if (!genIsValidIntReg(reg1) || !genIsValidIntReg(reg2)) + { + return; + } + + info.returnValueLoc.storeVariableInRegisters(reg1, reg2); } else if (varTypeIsFloating(call)) { @@ -1831,12 +1842,17 @@ void CodeGen::genEmitCallWithCurrentGC(EmitCallParams& params) info.returnValueLoc.vlType = VLT_FPSTK; info.returnValueLoc.vlFPstk.vlfReg = 0; #else - info.returnValueLoc.storeVariableInRegisters(REG_FLOATRET, REG_NA); + // VLT_REG_FP uses a 0-based FP register index; the DBI adds the + // platform-specific XMM0/V0 base when converting to CorDebugRegister. + info.returnValueLoc.vlType = VLT_REG_FP; + info.returnValueLoc.vlReg.vlrReg = (regNumber)(REG_FLOATRET - REG_FP_FIRST); #endif } else if (varTypeUsesFloatReg(call)) { - info.returnValueLoc.storeVariableInRegisters(REG_FLOATRET, REG_NA); + // VLT_REG_FP uses a 0-based FP register index. + info.returnValueLoc.vlType = VLT_REG_FP; + info.returnValueLoc.vlReg.vlrReg = (regNumber)(REG_FLOATRET - REG_FP_FIRST); } else { diff --git a/src/coreclr/jit/ee_il_dll.cpp b/src/coreclr/jit/ee_il_dll.cpp index 6c3ca0e2a35bba..8d0338f8d59fe3 100644 --- a/src/coreclr/jit/ee_il_dll.cpp +++ b/src/coreclr/jit/ee_il_dll.cpp @@ -894,7 +894,6 @@ void Compiler::eeDispVar(ICorDebugInfo::NativeVarInfo* var) { case CodeGenInterface::VLT_REG: case CodeGenInterface::VLT_REG_BYREF: - case CodeGenInterface::VLT_REG_FP: printf("%s", getRegName(var->loc.vlReg.vlrReg)); if (var->loc.vlType == (ICorDebugInfo::VarLocType)CodeGenInterface::VLT_REG_BYREF) { @@ -902,6 +901,10 @@ void Compiler::eeDispVar(ICorDebugInfo::NativeVarInfo* var) } break; + case CodeGenInterface::VLT_REG_FP: + printf("%s", getRegName((regNumber)(var->loc.vlReg.vlrReg + REG_FP_FIRST))); + break; + case CodeGenInterface::VLT_STK: case CodeGenInterface::VLT_STK_BYREF: if ((int)var->loc.vlStk.vlsBaseReg != (int)ICorDebugInfo::REGNUM_AMBIENT_SP) diff --git a/src/coreclr/jit/scopeinfo.cpp b/src/coreclr/jit/scopeinfo.cpp index e5dd272c33b9a4..a336b8d3872a02 100644 --- a/src/coreclr/jit/scopeinfo.cpp +++ b/src/coreclr/jit/scopeinfo.cpp @@ -158,6 +158,9 @@ bool CodeGenInterface::siVarLoc::vlIsOnStack() const // void CodeGenInterface::siVarLoc::storeVariableInRegisters(regNumber reg, regNumber otherReg) { + assert(genIsValidIntReg(reg)); + assert(otherReg == REG_NA || genIsValidIntReg(otherReg)); + if (otherReg == REG_NA) { // Only one register is used @@ -409,10 +412,10 @@ void CodeGenInterface::siVarLoc::siFillRegisterVarLoc( #ifdef TARGET_64BIT case TYP_FLOAT: case TYP_DOUBLE: - // TODO-AMD64-Bug: ndp\clr\src\inc\corinfo.h has a definition of RegNum that only goes up to R15, - // so no XMM registers can get debug information. + // VLT_REG_FP uses a 0-based FP register index; the DBI adds the + // platform-specific XMM0/V0 base when converting to CorDebugRegister. this->vlType = VLT_REG_FP; - this->vlReg.vlrReg = varDsc->GetRegNum(); + this->vlReg.vlrReg = (regNumber)(varDsc->GetRegNum() - REG_FP_FIRST); break; #else // !TARGET_64BIT @@ -442,12 +445,9 @@ void CodeGenInterface::siVarLoc::siFillRegisterVarLoc( { this->vlType = VLT_REG_FP; - // TODO-AMD64-Bug: ndp\clr\src\inc\corinfo.h has a definition of RegNum that only goes up to R15, - // so no XMM registers can get debug information. - // - // Note: Need to initialize vlrReg field, otherwise during jit dump hitting an assert - // in eeDispVar() --> getRegName() that regNumber is valid. - this->vlReg.vlrReg = varDsc->GetRegNum(); + // VLT_REG_FP uses a 0-based FP register index; the DBI adds the + // platform-specific XMM0/V0 base when converting to CorDebugRegister. + this->vlReg.vlrReg = (regNumber)(varDsc->GetRegNum() - REG_FP_FIRST); break; } #endif // FEATURE_SIMD @@ -1736,7 +1736,25 @@ void CodeGen::psiBegProlog() if (reg1 != REG_NA) { - varLocation.storeVariableInRegisters(reg1, reg2); + if (genIsValidFloatReg(reg1)) + { + // FP parameter in XMM/V register — encode as VLT_REG_FP with + // 0-based FP register index. + varLocation.vlType = VLT_REG_FP; + varLocation.vlReg.vlrReg = (regNumber)(reg1 - REG_FP_FIRST); + } + else + { + // Integer register parameter. On SysV x64, the second segment + // may be in an XMM register for mixed struct passing — drop it + // since VLT_REG_REG cannot encode FP registers. + // TODO: Supporting this case is tracked by https://github.com/dotnet/runtime/issues/129344 + if (reg2 != REG_NA && !genIsValidIntReg(reg2)) + { + reg2 = REG_NA; + } + varLocation.storeVariableInRegisters(reg1, reg2); + } } else {