Skip to content

Commit 02e348b

Browse files
authored
[LoongArch64] Simplify flags for passing struct in registers. (#102041)
Change-Id: Idbe644c0bc5baeb53a53e16731824e28aacf67a0
1 parent 279dbe1 commit 02e348b

File tree

5 files changed

+139
-817
lines changed

5 files changed

+139
-817
lines changed
Lines changed: 95 additions & 160 deletions
Original file line numberDiff line numberDiff line change
@@ -1,192 +1,127 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33
using System;
4+
using System.Collections.Generic;
45
using System.Diagnostics;
56
using ILCompiler;
67
using Internal.TypeSystem;
8+
using static Internal.JitInterface.StructFloatFieldInfoFlags;
79

810
namespace Internal.JitInterface
911
{
10-
1112
internal static class LoongArch64PassStructInRegister
1213
{
13-
public static uint GetLoongArch64PassStructInRegisterFlags(TypeDesc typeDesc)
14+
private const int
15+
ENREGISTERED_PARAMTYPE_MAXSIZE = 16,
16+
TARGET_POINTER_SIZE = 8;
17+
18+
private static bool HandleInlineArray(int elementTypeIndex, int nElements, Span<StructFloatFieldInfoFlags> types, ref int typeIndex)
1419
{
15-
FieldDesc firstField = null;
16-
uint floatFieldFlags = (uint)StructFloatFieldInfoFlags.STRUCT_NO_FLOAT_FIELD;
17-
int numIntroducedFields = 0;
18-
foreach (FieldDesc field in typeDesc.GetFields())
20+
int nFlattenedFieldsPerElement = typeIndex - elementTypeIndex;
21+
if (nFlattenedFieldsPerElement == 0)
22+
return true;
23+
24+
Debug.Assert(nFlattenedFieldsPerElement == 1 || nFlattenedFieldsPerElement == 2);
25+
26+
if (nElements > 2)
27+
return false;
28+
29+
if (nElements == 2)
1930
{
20-
if (!field.IsStatic)
21-
{
22-
firstField ??= field;
23-
numIntroducedFields++;
24-
}
31+
if (typeIndex + nFlattenedFieldsPerElement > 2)
32+
return false;
33+
34+
Debug.Assert(elementTypeIndex == 0);
35+
Debug.Assert(typeIndex == 1);
36+
types[typeIndex++] = types[elementTypeIndex]; // duplicate the array element type
2537
}
38+
return true;
39+
}
2640

27-
if ((numIntroducedFields == 0) || (numIntroducedFields > 2) || (typeDesc.GetElementSize().AsInt > 16))
41+
private static bool FlattenFieldTypes(TypeDesc td, Span<StructFloatFieldInfoFlags> types, ref int typeIndex)
42+
{
43+
IEnumerable<FieldDesc> fields = td.GetFields();
44+
int nFields = 0;
45+
int elementTypeIndex = typeIndex;
46+
FieldDesc prevField = null;
47+
foreach (FieldDesc field in fields)
2848
{
29-
return (uint)StructFloatFieldInfoFlags.STRUCT_NO_FLOAT_FIELD;
30-
}
49+
if (field.IsStatic)
50+
continue;
51+
nFields++;
3152

32-
MetadataType mdType = typeDesc as MetadataType;
33-
Debug.Assert(mdType != null);
53+
if (prevField != null && prevField.Offset.AsInt + prevField.FieldType.GetElementSize().AsInt > field.Offset.AsInt)
54+
return false; // overlapping fields
3455

35-
TypeDesc firstFieldElementType = firstField.FieldType;
36-
int firstFieldSize = firstFieldElementType.GetElementSize().AsInt;
56+
prevField = field;
3757

38-
bool hasImpliedRepeatedFields = mdType.HasImpliedRepeatedFields();
58+
TypeFlags category = field.FieldType.Category;
59+
if (category == TypeFlags.ValueType)
60+
{
61+
TypeDesc nested = field.FieldType;
62+
if (!FlattenFieldTypes(nested, types, ref typeIndex))
63+
return false;
64+
}
65+
else if (field.FieldType.GetElementSize().AsInt <= TARGET_POINTER_SIZE)
66+
{
67+
if (typeIndex >= 2)
68+
return false;
3969

40-
if (hasImpliedRepeatedFields)
41-
{
42-
numIntroducedFields = typeDesc.GetElementSize().AsInt / firstFieldSize;
43-
if (numIntroducedFields > 2)
70+
StructFloatFieldInfoFlags type =
71+
(category is TypeFlags.Single or TypeFlags.Double ? STRUCT_FLOAT_FIELD_FIRST : (StructFloatFieldInfoFlags)0) |
72+
(field.FieldType.GetElementSize().AsInt == TARGET_POINTER_SIZE ? STRUCT_FIRST_FIELD_SIZE_IS8 : (StructFloatFieldInfoFlags)0);
73+
types[typeIndex++] = type;
74+
}
75+
else
4476
{
45-
return (uint)StructFloatFieldInfoFlags.STRUCT_NO_FLOAT_FIELD;
77+
return false;
4678
}
4779
}
4880

49-
int fieldIndex = 0;
50-
foreach (FieldDesc field in typeDesc.GetFields())
81+
if ((td as MetadataType).HasImpliedRepeatedFields())
5182
{
52-
if (field.IsStatic)
53-
{
54-
continue;
55-
}
83+
Debug.Assert(nFields == 1);
84+
int nElements = td.GetElementSize().AsInt / prevField.FieldType.GetElementSize().AsInt;
85+
if (!HandleInlineArray(elementTypeIndex, nElements, types, ref typeIndex))
86+
return false;
87+
}
88+
return true;
89+
}
5690

57-
Debug.Assert(fieldIndex < numIntroducedFields);
91+
public static uint GetLoongArch64PassStructInRegisterFlags(TypeDesc td)
92+
{
93+
if (td.GetElementSize().AsInt > ENREGISTERED_PARAMTYPE_MAXSIZE)
94+
return (uint)STRUCT_NO_FLOAT_FIELD;
5895

59-
switch (field.FieldType.Category)
60-
{
61-
case TypeFlags.Double:
62-
{
63-
if (numIntroducedFields == 1)
64-
{
65-
floatFieldFlags = (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_ONLY_ONE;
66-
}
67-
else if (fieldIndex == 0)
68-
{
69-
floatFieldFlags = (uint)StructFloatFieldInfoFlags.STRUCT_FIRST_FIELD_DOUBLE;
70-
}
71-
else if ((floatFieldFlags & (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_FIRST) != 0)
72-
{
73-
floatFieldFlags ^= (uint)StructFloatFieldInfoFlags.STRUCT_MERGE_FIRST_SECOND_8;
74-
}
75-
else
76-
{
77-
floatFieldFlags |= (uint)StructFloatFieldInfoFlags.STRUCT_SECOND_FIELD_DOUBLE;
78-
}
79-
}
80-
break;
81-
82-
case TypeFlags.Single:
83-
{
84-
if (numIntroducedFields == 1)
85-
{
86-
floatFieldFlags = (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_ONLY_ONE;
87-
}
88-
else if (fieldIndex == 0)
89-
{
90-
floatFieldFlags = (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_FIRST;
91-
}
92-
else if ((floatFieldFlags & (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_FIRST) != 0)
93-
{
94-
floatFieldFlags ^= (uint)StructFloatFieldInfoFlags.STRUCT_MERGE_FIRST_SECOND;
95-
}
96-
else
97-
{
98-
floatFieldFlags |= (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_SECOND;
99-
}
100-
}
101-
break;
102-
103-
case TypeFlags.ValueType:
104-
//case TypeFlags.Class:
105-
//case TypeFlags.Array:
106-
//case TypeFlags.SzArray:
107-
{
108-
uint floatFieldFlags2 = GetLoongArch64PassStructInRegisterFlags(field.FieldType);
109-
if (numIntroducedFields == 1)
110-
{
111-
floatFieldFlags = floatFieldFlags2;
112-
}
113-
else if (field.FieldType.GetElementSize().AsInt > 8)
114-
{
115-
return (uint)StructFloatFieldInfoFlags.STRUCT_NO_FLOAT_FIELD;
116-
}
117-
else if (fieldIndex == 0)
118-
{
119-
if ((floatFieldFlags2 & (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_ONLY_ONE) != 0)
120-
{
121-
floatFieldFlags = (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_FIRST;
122-
}
123-
if (field.FieldType.GetElementSize().AsInt == 8)
124-
{
125-
floatFieldFlags |= (uint)StructFloatFieldInfoFlags.STRUCT_FIRST_FIELD_SIZE_IS8;
126-
}
127-
}
128-
else
129-
{
130-
Debug.Assert(fieldIndex == 1);
131-
if ((floatFieldFlags2 & (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_ONLY_ONE) != 0)
132-
{
133-
floatFieldFlags |= (uint)StructFloatFieldInfoFlags.STRUCT_MERGE_FIRST_SECOND;
134-
}
135-
if (field.FieldType.GetElementSize().AsInt == 8)
136-
{
137-
floatFieldFlags |= (uint)StructFloatFieldInfoFlags.STRUCT_SECOND_FIELD_SIZE_IS8;
138-
}
139-
140-
floatFieldFlags2 = floatFieldFlags & ((uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_FIRST | (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_SECOND);
141-
if (floatFieldFlags2 == 0)
142-
{
143-
floatFieldFlags = (uint)StructFloatFieldInfoFlags.STRUCT_NO_FLOAT_FIELD;
144-
}
145-
else if (floatFieldFlags2 == ((uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_FIRST | (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_SECOND))
146-
{
147-
floatFieldFlags ^= ((uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_ONLY_TWO | (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_FIRST | (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_SECOND);
148-
}
149-
}
150-
}
151-
break;
152-
153-
default:
154-
{
155-
if ((numIntroducedFields == 2) && (field.FieldType.Category == TypeFlags.Class))
156-
{
157-
return (uint)StructFloatFieldInfoFlags.STRUCT_NO_FLOAT_FIELD;
158-
}
159-
160-
if (field.FieldType.GetElementSize().AsInt == 8)
161-
{
162-
if (numIntroducedFields > 1)
163-
{
164-
if (fieldIndex == 0)
165-
{
166-
floatFieldFlags = (uint)StructFloatFieldInfoFlags.STRUCT_FIRST_FIELD_SIZE_IS8;
167-
}
168-
else if ((floatFieldFlags & (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_FIRST) != 0)
169-
{
170-
floatFieldFlags |= (uint)StructFloatFieldInfoFlags.STRUCT_SECOND_FIELD_SIZE_IS8;
171-
}
172-
else
173-
{
174-
floatFieldFlags = (uint)StructFloatFieldInfoFlags.STRUCT_NO_FLOAT_FIELD;
175-
}
176-
}
177-
}
178-
else if (fieldIndex == 1)
179-
{
180-
floatFieldFlags = (floatFieldFlags & (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_FIRST) > 0 ? floatFieldFlags : (uint)StructFloatFieldInfoFlags.STRUCT_NO_FLOAT_FIELD;
181-
}
182-
break;
183-
}
184-
}
96+
Span<StructFloatFieldInfoFlags> types = stackalloc StructFloatFieldInfoFlags[] {
97+
STRUCT_NO_FLOAT_FIELD, STRUCT_NO_FLOAT_FIELD
98+
};
99+
int nFields = 0;
100+
if (!FlattenFieldTypes(td, types, ref nFields) || nFields == 0)
101+
return (uint)STRUCT_NO_FLOAT_FIELD;
185102

186-
fieldIndex++;
187-
}
103+
Debug.Assert(nFields == 1 || nFields == 2);
104+
105+
Debug.Assert((uint)(STRUCT_FLOAT_FIELD_SECOND | STRUCT_SECOND_FIELD_SIZE_IS8)
106+
== (uint)(STRUCT_FLOAT_FIELD_FIRST | STRUCT_FIRST_FIELD_SIZE_IS8) << 1,
107+
"SECOND flags need to be FIRST shifted by 1");
108+
StructFloatFieldInfoFlags flags = types[0] | (StructFloatFieldInfoFlags)((uint)types[1] << 1);
109+
110+
const StructFloatFieldInfoFlags bothFloat = STRUCT_FLOAT_FIELD_FIRST | STRUCT_FLOAT_FIELD_SECOND;
111+
if ((flags & bothFloat) == 0)
112+
return (uint)STRUCT_NO_FLOAT_FIELD;
188113

189-
return floatFieldFlags;
114+
if ((flags & bothFloat) == bothFloat)
115+
{
116+
Debug.Assert(nFields == 2);
117+
flags ^= (bothFloat | STRUCT_FLOAT_FIELD_ONLY_TWO); // replace bothFloat with ONLY_TWO
118+
}
119+
else if (nFields == 1)
120+
{
121+
Debug.Assert((flags & STRUCT_FLOAT_FIELD_FIRST) != 0);
122+
flags ^= (STRUCT_FLOAT_FIELD_FIRST | STRUCT_FLOAT_FIELD_ONLY_ONE); // replace FIRST with ONLY_ONE
123+
}
124+
return (uint)flags;
190125
}
191126
}
192127
}

src/coreclr/vm/callingconvention.h

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1692,17 +1692,7 @@ int ArgIteratorTemplate<ARGITERATOR_BASE>::GetNextOffset()
16921692
}
16931693
else
16941694
{
1695-
MethodTable* pMethodTable = nullptr;
1696-
1697-
if (!thValueType.IsTypeDesc())
1698-
pMethodTable = thValueType.AsMethodTable();
1699-
else
1700-
{
1701-
_ASSERTE(thValueType.IsNativeValueType());
1702-
pMethodTable = thValueType.AsNativeValueType();
1703-
}
1704-
_ASSERTE(pMethodTable != nullptr);
1705-
flags = MethodTable::GetLoongArch64PassStructInRegisterFlags((CORINFO_CLASS_HANDLE)pMethodTable);
1695+
flags = MethodTable::GetLoongArch64PassStructInRegisterFlags(thValueType);
17061696
if (flags & STRUCT_HAS_FLOAT_FIELDS_MASK)
17071697
{
17081698
cFPRegs = (flags & STRUCT_FLOAT_FIELD_ONLY_TWO) ? 2 : 1;
@@ -2019,9 +2009,7 @@ void ArgIteratorTemplate<ARGITERATOR_BASE>::ComputeReturnFlags()
20192009
if (size <= ENREGISTERED_RETURNTYPE_INTEGER_MAXSIZE)
20202010
{
20212011
assert(!thValueType.IsTypeDesc());
2022-
2023-
MethodTable *pMethodTable = thValueType.AsMethodTable();
2024-
flags = (MethodTable::GetLoongArch64PassStructInRegisterFlags((CORINFO_CLASS_HANDLE)pMethodTable) & 0xff) << RETURN_FP_SIZE_SHIFT;
2012+
flags = (MethodTable::GetLoongArch64PassStructInRegisterFlags(thValueType) & 0xff) << RETURN_FP_SIZE_SHIFT;
20252013
break;
20262014
}
20272015
#elif defined(TARGET_RISCV64)

src/coreclr/vm/jitinterface.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9632,7 +9632,7 @@ uint32_t CEEInfo::getLoongArch64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE c
96329632
uint32_t size = STRUCT_NO_FLOAT_FIELD;
96339633

96349634
#if defined(TARGET_LOONGARCH64)
9635-
size = (uint32_t)MethodTable::GetLoongArch64PassStructInRegisterFlags(cls);
9635+
size = (uint32_t)MethodTable::GetLoongArch64PassStructInRegisterFlags(TypeHandle(cls));
96369636
#endif
96379637

96389638
EE_TO_JIT_TRANSITION_LEAF();

0 commit comments

Comments
 (0)