Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
c2c2bba
First, add a bunch of failing tests
tomeksowi May 2, 2024
03d4b23
Reduce empty megabyte field to 32k as msvc caps size of arguments at 64k
tomeksowi May 6, 2024
4403c4b
Don't stop calculating flags if struct size > 16 bytes
tomeksowi May 6, 2024
bf81116
Classify empty structs on x64 like padding
tomeksowi May 8, 2024
60ad834
Quell C-linkage warnings just in case
tomeksowi May 8, 2024
9064784
Add Pack=1 to bypass a known problem with field alignment requirement…
tomeksowi May 9, 2024
002c4b2
Merge branch 'main' into empty-struct-passing
tomeksowi May 10, 2024
b02c913
Check `size > 16` only when passing parameters according to integer c…
tomeksowi May 10, 2024
0fde22d
Don't assume struct size > 16 means return by implicit ref to a retur…
tomeksowi May 13, 2024
f89a68d
Don't assume if struct size > 16, IsArgPassedByRef should return true…
tomeksowi May 13, 2024
f5e3930
Adjust ArgIterator.GetNextOffset() for crossgen2 to be the same as th…
tomeksowi May 14, 2024
0a5ce05
Adjust crossgen2 version of ComputeReturnFlags (ComputeReturnValueTre…
tomeksowi May 14, 2024
6a3118b
Adjust IsArgPassedByRef for crossgen2 with native version for VM. Als…
tomeksowi May 14, 2024
0a1a7ff
Don't assume struct (size > 16) means pass by reference in Compiler::…
tomeksowi May 14, 2024
9aa2d10
Add a test for a single-float struct padded with empty struct field
tomeksowi May 14, 2024
9d9d0e2
Relax checks so the new test cases JIT without false positive assertions
tomeksowi May 16, 2024
983d423
New structure to store information about passing structs according to…
tomeksowi May 16, 2024
8366470
Implement GetRiscV64PassFPStructInfo for now with checks against exis…
tomeksowi May 17, 2024
c3e8578
Rename to match similar functions on other architectures
tomeksowi May 20, 2024
c2dd449
Use bitfields to keep the most important flags for decision making pa…
tomeksowi May 20, 2024
0d81d68
Fix JIT for structs with single float padded with empty structs
tomeksowi May 20, 2024
ec8d404
Replace bitfields with manual flags to avoid potential portability pr…
tomeksowi May 21, 2024
98e1861
Update C# version of GetRiscV64PassFpStructInRegistersInfo
tomeksowi May 21, 2024
623a2a6
Replace getRISCV64PassStructInRegisterFlags with getRiscV64PassFpStru…
tomeksowi May 21, 2024
f550c22
Fix offset assignment in C# GetRiscV64PassFpStructInRegistersInfo
tomeksowi May 22, 2024
338e244
Use enregistered struct field offsets in JIT new ABI classifiers
tomeksowi May 22, 2024
894fccd
Merge branch 'main' into empty-struct-passing
tomeksowi May 22, 2024
4cdd228
Fix build: formatting and using static ordering
tomeksowi May 22, 2024
99ec678
Include GC info in FpStructInRegistersInfo like on System V. While it…
tomeksowi May 23, 2024
b5e1cdc
Nicer size shift calculation routine
tomeksowi May 23, 2024
95e787d
Fix build
tomeksowi May 24, 2024
48e7944
Fix Empty8Float test
tomeksowi May 28, 2024
7102f31
Add EmptyFloatEmpty5(U)Byte tests
tomeksowi May 28, 2024
e5d67cd
Increase field visibility to match other tests
tomeksowi May 29, 2024
e25552e
Fix EmptyFloatEmpty5(U)Byte and LongEmptyDouble tests by using correc…
tomeksowi May 31, 2024
28a88b3
Fix LongEmptyGDoubleByImplicitRef and the rest of tests in StructABI …
tomeksowi Jun 4, 2024
123eaaf
Make tests harder
tomeksowi Jun 4, 2024
1a85e0b
Improve logging for GetRiscV64PassFpStructInRegistersInfo, similar to…
tomeksowi Jun 5, 2024
6163536
Format fix
tomeksowi Jun 5, 2024
6dc499d
Fix test EchoArrayOfEmptiesFloatDouble by returning FpStruct{ UseIntC…
tomeksowi Jun 5, 2024
afd95cd
Fix false positive marking a struct split between register and stack
tomeksowi Jun 6, 2024
de83bc7
Add more tests for cases where structs eligible for hardware floating…
tomeksowi Jun 6, 2024
978e851
Fix test EchoEmptyFloatEmpty5ByteSplitRiscV
tomeksowi Jun 6, 2024
dab9167
Remove LclVarDsc::lvIs4Field{1,2} because they were write-only
tomeksowi Jun 6, 2024
2d24bee
Fix ArgIteratorTemplate::GetNextOffset() for struct{Arr[], float}
tomeksowi Jun 6, 2024
9eb6b00
Merge branch 'main' into getnextoffset-for-struct-ptr-float
tomeksowi Jun 7, 2024
d3e974c
Merge branch 'getnextoffset-for-struct-ptr-float' into empty-struct-p…
tomeksowi Jun 7, 2024
a0ccb2a
Merge branch 'main' into empty-struct-passing
tomeksowi Jun 7, 2024
f469ef5
Fix arm32 build by reverting to using cSlotsToEnregister in lclvars.
tomeksowi Jun 10, 2024
811f947
Add failing tests for hardware floating-point calling convention by r…
tomeksowi Jun 10, 2024
b6bef68
Merge branch 'main' into empty-struct-passing
tomeksowi Jun 10, 2024
ac2670b
Fix small struct passing to calls by reflection: CopyStructToRegister…
tomeksowi Jun 11, 2024
76533b6
Fix FP structs returned from calls by reflection
tomeksowi Jun 12, 2024
c7e8a11
Fix the rest of the reflection tests by properly determining whether …
tomeksowi Jun 12, 2024
16b549f
Update crossgen2 C# version of ArgIterator to changes on the native side
tomeksowi Jun 14, 2024
3389bcf
Fix copying structs returned by hardware floating-point calling conve…
tomeksowi Jun 14, 2024
d4f81be
Merge branch 'main' into empty-struct-passing
tomeksowi Jun 14, 2024
7551d35
Merge branch 'main' into empty-struct-passing
tomeksowi Jun 18, 2024
4d2e2cb
Add signedness to integer field FpStructPassInRegistersInfo
tomeksowi Jun 21, 2024
907ac95
Better flag names
tomeksowi Jun 21, 2024
892ec22
Improve explanation why RISC-V can't use genActualType in genParamSta…
tomeksowi Jun 21, 2024
e73450e
Take signedness into account in CopyStructToRegisters
tomeksowi Jun 21, 2024
717cd59
Remove IsSize(1st|2nd)8 because they weren't used much
tomeksowi Jun 21, 2024
64de193
Improve getter names in FpStructInRegistersInfo
tomeksowi Jun 21, 2024
d2d1841
Add comment to fix JIT to AssignClassifiedEightByteTypes
tomeksowi Jun 21, 2024
47f9d87
Add helpers for IntKind and flag names to FpStructInRegistersInfo
tomeksowi Jun 21, 2024
09c0b38
Merge branch 'main' into empty-struct-passing
tomeksowi Jun 21, 2024
8d6a102
Fix C# build: Enum values should be on separate lines
tomeksowi Jun 21, 2024
5ebd2af
Merge branch 'main' into empty-struct-passing
tomeksowi Jun 21, 2024
7036dc0
Make a logging wrapper Compiler::GetPassFpStructInRegistersInfo, simi…
tomeksowi Jun 21, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Fix small struct passing to calls by reflection: CopyStructToRegister…
…s is now aware of field offsets and widths
  • Loading branch information
tomeksowi committed Jun 11, 2024
commit ac2670ba9cfa5693ae159b5e4c81c2bd77f67de2
88 changes: 31 additions & 57 deletions src/coreclr/vm/argdestination.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,72 +106,46 @@ class ArgDestination
#endif // TARGET_RISCV64

_ASSERTE(IsStructPassedInRegs());
_ASSERTE(fieldBytes <= 16);
_ASSERTE(destOffset == 0);
LOONGARCH64_ONLY(_ASSERTE(fieldBytes <= 16);)

int argOfs = TransitionBlock::GetOffsetOfFloatArgumentRegisters() + m_argLocDescForStructInRegs->m_idxFloatReg * 8;
using namespace FpStruct;
FpStructInRegistersInfo info = m_argLocDescForStructInRegs->m_structFields;
_ASSERTE(m_argLocDescForStructInRegs->m_cFloatReg == ((info.flags & BothFloat) ? 2 : 1));
_ASSERTE(m_argLocDescForStructInRegs->m_cGenReg == ((info.flags & (Float1st | Float2nd)) ? 1 : 0));

if (m_argLocDescForStructInRegs->m_structFields == STRUCT_FLOAT_FIELD_ONLY_TWO)
{ // struct with two floats.
_ASSERTE(m_argLocDescForStructInRegs->m_cFloatReg == 2);
_ASSERTE(m_argLocDescForStructInRegs->m_cGenReg == 0);
*(INT64*)((char*)m_base + argOfs) = NanBox | *(INT32*)src;
*(INT64*)((char*)m_base + argOfs + 8) = NanBox | *((INT32*)src + 1);
}
else if ((m_argLocDescForStructInRegs->m_structFields & STRUCT_FLOAT_FIELD_FIRST) != 0)
{ // the first field is float or double.
_ASSERTE(m_argLocDescForStructInRegs->m_cFloatReg == 1);
_ASSERTE(m_argLocDescForStructInRegs->m_cGenReg == 1);
_ASSERTE((m_argLocDescForStructInRegs->m_structFields & STRUCT_FLOAT_FIELD_SECOND) == 0);//the second field is integer.
int floatRegOffset = TransitionBlock::GetOffsetOfFloatArgumentRegisters() +
m_argLocDescForStructInRegs->m_idxFloatReg * FLOAT_REGISTER_SIZE;
INT64* floatReg = (INT64*)((char*)m_base + floatRegOffset);

if ((m_argLocDescForStructInRegs->m_structFields & STRUCT_FIRST_FIELD_SIZE_IS8) == 0)
{
*(INT64*)((char*)m_base + argOfs) = NanBox | *(INT32*)src; // the first field is float
}
else
{
*(UINT64*)((char*)m_base + argOfs) = *(UINT64*)src; // the first field is double.
}
if (info.flags & (OnlyOne | BothFloat | Float1st)) // copy first floating field
{
void* field = (char*)src + info.offset1st;
*floatReg++ = info.IsSize1st8() ? *(INT64*)field : NanBox | *(INT32*)field;
}

argOfs = TransitionBlock::GetOffsetOfArgumentRegisters() + m_argLocDescForStructInRegs->m_idxGenReg * 8;
if ((m_argLocDescForStructInRegs->m_structFields & STRUCT_HAS_8BYTES_FIELDS_MASK) != 0)
{
*(UINT64*)((char*)m_base + argOfs) = *((UINT64*)src + 1);
}
else
{
*(INT64*)((char*)m_base + argOfs) = *((INT32*)src + 1); // the second field is int32.
}
if (info.flags & (BothFloat | Float2nd)) // copy second floating field
{
void* field = (char*)src + info.offset2nd;
*floatReg = info.IsSize2nd8() ? *(INT64*)field : NanBox | *(INT32*)field;
}
else if ((m_argLocDescForStructInRegs->m_structFields & STRUCT_FLOAT_FIELD_SECOND) != 0)
{ // the second field is float or double.
_ASSERTE(m_argLocDescForStructInRegs->m_cFloatReg == 1);
_ASSERTE(m_argLocDescForStructInRegs->m_cGenReg == 1);
_ASSERTE((m_argLocDescForStructInRegs->m_structFields & STRUCT_FLOAT_FIELD_FIRST) == 0);//the first field is integer.

// destOffset - nonzero when copying values into Nullable<T>, it is the offset of the T value inside of the Nullable<T>.
// here the first field maybe Nullable.
if ((m_argLocDescForStructInRegs->m_structFields & STRUCT_HAS_8BYTES_FIELDS_MASK) == 0)
{
// the second field is float.
*(INT64*)((char*)m_base + argOfs) = NanBox | (destOffset == 0 ? *((INT32*)src + 1) : *(INT32*)src);
}
else
{
// the second field is double.
*(UINT64*)((char*)m_base + argOfs) = destOffset == 0 ? *((UINT64*)src + 1) : *(UINT64*)src;
}

if (0 == destOffset)
if (info.flags & (Float1st | Float2nd)) // copy integer field
{
int intRegOffset = TransitionBlock::GetOffsetOfArgumentRegisters() +
m_argLocDescForStructInRegs->m_idxGenReg * TARGET_POINTER_SIZE;
INT64* intReg = (INT64*)((char*)m_base + intRegOffset);

void* field = (char*)src + ((info.flags & Float2nd) ? info.offset1st : info.offset2nd);
switch ((info.flags & Float2nd) ? info.GetSizeShift1st() : info.GetSizeShift2nd())
{
// NOTE: here ignoring the first size.
argOfs = TransitionBlock::GetOffsetOfArgumentRegisters() + m_argLocDescForStructInRegs->m_idxGenReg * 8;
*(UINT64*)((char*)m_base + argOfs) = *(UINT64*)src;
case 0: *intReg = *(INT8* )field; break;
case 1: *intReg = *(INT16*)field; break;
case 2: *intReg = *(INT32*)field; break;
case 3: *intReg = *(INT64*)field; break;
default: _ASSERTE(false);
}
}
else
{
_ASSERTE(!"---------UNReachable-------LoongArch64/RISC-V64!!!");
}
}
#endif // !DACCESS_COMPILE

Expand Down
20 changes: 9 additions & 11 deletions src/coreclr/vm/callingconvention.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ struct ArgLocDesc
int m_byteStackIndex; // Stack offset in bytes (or -1)
int m_byteStackSize; // Stack size in bytes
#if defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
int m_structFields; // Struct field info when using Float-register except two-doubles case.
FpStructInRegistersInfo m_structFields; // Struct field info when using floating-point register(s)
#endif

#if defined(UNIX_AMD64_ABI)
Expand Down Expand Up @@ -97,7 +97,7 @@ struct ArgLocDesc
m_hfaFieldSize = 0;
#endif // defined(TARGET_ARM64)
#if defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
m_structFields = STRUCT_NO_FLOAT_FIELD;
m_structFields = {};
#endif
#if defined(UNIX_AMD64_ABI)
m_eeClass = NULL;
Expand Down Expand Up @@ -1844,7 +1844,7 @@ int ArgIteratorTemplate<ARGITERATOR_BASE>::GetNextOffset()
m_argLocDescForStructInRegs.m_idxGenReg = m_idxGenReg;
m_argLocDescForStructInRegs.m_cGenReg = 1;

m_argLocDescForStructInRegs.m_structFields = info.ToOldFlags();
m_argLocDescForStructInRegs.m_structFields = info;
m_hasArgLocDescForStructInRegs = true;

int regOffset = (info.flags & FpStruct::Float2nd)
Expand All @@ -1858,18 +1858,16 @@ int ArgIteratorTemplate<ARGITERATOR_BASE>::GetNextOffset()
else if (cFPRegs + m_idxFPReg <= NUM_ARGUMENT_REGISTERS)
{
int regOffset = TransitionBlock::GetOffsetOfFloatArgumentRegisters() + m_idxFPReg * FLOAT_REGISTER_SIZE;
if (info.flags == (FpStruct::BothFloat | (2 << FpStruct::PosSizeShift1st) | (2 << FpStruct::PosSizeShift2nd)))

if ((info.flags & (FpStruct::BothFloat | FpStruct::OnlyOne))
&& (info.offset1st != 0 || info.offset2nd != FLOAT_REGISTER_SIZE))
{
// Struct with two single-float fields
assert(info.GetSize1st() == sizeof(float));
assert(info.GetSize2nd() == sizeof(float));
// Struct with one or two floating-point fields laid out differently than in TransitionBlock::FloatArgumentRegisters
m_argLocDescForStructInRegs.Init();
m_argLocDescForStructInRegs.m_idxFloatReg = m_idxFPReg;
m_argLocDescForStructInRegs.m_cFloatReg = 2;
assert(cFPRegs == 2);
assert(argSize == 2 * sizeof(float));
m_argLocDescForStructInRegs.m_cFloatReg = cFPRegs;

m_argLocDescForStructInRegs.m_structFields = info.ToOldFlags();
m_argLocDescForStructInRegs.m_structFields = info;
m_hasArgLocDescForStructInRegs = true;
}
m_idxFPReg += cFPRegs;
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/vm/comdelegate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ class ShuffleIterator
if (m_currentFloatRegIndex < m_argLocDesc->m_cFloatReg)
{
#if defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
if ((m_argLocDesc->m_structFields & STRUCT_FLOAT_FIELD_SECOND) && (m_currentGenRegIndex < m_argLocDesc->m_cGenReg))
if ((m_argLocDesc->m_structFields.flags & FpStruct::Float2nd) && (m_currentGenRegIndex < m_argLocDesc->m_cGenReg))
{
// the first field is integer so just skip this.
}
Expand Down
15 changes: 8 additions & 7 deletions src/coreclr/vm/riscv64/profiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,13 +111,14 @@ LPVOID ProfileArgIterator::CopyStructFromRegisters(const ArgLocDesc* sir)
_ASSERTE(m_handle);
PROFILE_PLATFORM_SPECIFIC_DATA* pData = reinterpret_cast<PROFILE_PLATFORM_SPECIFIC_DATA*>(m_handle);

StructFloatFieldInfoFlags flags = sir->m_structFields.ToOldFlags();
struct { bool isFloat, is8; } fields[] = {
{ (bool) (sir->m_structFields & (STRUCT_FLOAT_FIELD_FIRST | STRUCT_FLOAT_FIELD_ONLY_TWO | STRUCT_FLOAT_FIELD_ONLY_ONE)),
(bool) (sir->m_structFields & STRUCT_FIRST_FIELD_SIZE_IS8) },
{ (bool) (sir->m_structFields & (STRUCT_FLOAT_FIELD_SECOND | STRUCT_FLOAT_FIELD_ONLY_TWO)),
(bool) (sir->m_structFields & STRUCT_SECOND_FIELD_SIZE_IS8) },
{ (bool) (flags & (STRUCT_FLOAT_FIELD_FIRST | STRUCT_FLOAT_FIELD_ONLY_TWO | STRUCT_FLOAT_FIELD_ONLY_ONE)),
(bool) (flags & STRUCT_FIRST_FIELD_SIZE_IS8) },
{ (bool) (flags & (STRUCT_FLOAT_FIELD_SECOND | STRUCT_FLOAT_FIELD_ONLY_TWO)),
(bool) (flags & STRUCT_SECOND_FIELD_SIZE_IS8) },
};
int fieldCount = (sir->m_structFields & STRUCT_FLOAT_FIELD_ONLY_ONE) ? 1 : 2;
int fieldCount = (flags & STRUCT_FLOAT_FIELD_ONLY_ONE) ? 1 : 2;
UINT64 bufferPosBegin = m_bufferPos;
const double *fRegBegin = &pData->floatArgumentRegisters.f[sir->m_idxFloatReg], *fReg = fRegBegin;
const double *fRegEnd = &pData->floatArgumentRegisters.f[0] + NUM_FLOAT_ARGUMENT_REGISTERS;
Expand Down Expand Up @@ -185,7 +186,7 @@ LPVOID ProfileArgIterator::GetNextArgAddr()
// If both fields are in registers of same kind (either float or general) and both are 8 bytes, no need to copy.
// We can get away with returning a ptr to argumentRegisters since the struct would have the same layout.
if ((sir->m_cFloatReg ^ sir->m_cGenReg) != 2 ||
(sir->m_structFields & STRUCT_HAS_8BYTES_FIELDS_MASK) != STRUCT_HAS_8BYTES_FIELDS_MASK)
(sir->m_structFields.ToOldFlags() & STRUCT_HAS_8BYTES_FIELDS_MASK) != STRUCT_HAS_8BYTES_FIELDS_MASK)
{
return CopyStructFromRegisters(sir);
}
Expand Down Expand Up @@ -317,7 +318,7 @@ LPVOID ProfileArgIterator::GetReturnBufferAddr(void)
sir.m_cGenReg = -1;
sir.m_byteStackIndex = 0;
sir.m_byteStackSize = -1;
sir.m_structFields = fpReturnSize;
sir.m_structFields = FpStructInRegistersInfo::FromOldFlags((StructFloatFieldInfoFlags)fpReturnSize);
return CopyStructFromRegisters(&sir);
}

Expand Down