|
1 | 1 | // Licensed to the .NET Foundation under one or more agreements.
|
2 | 2 | // The .NET Foundation licenses this file to you under the MIT license.
|
3 | 3 | using System;
|
| 4 | +using System.Collections.Generic; |
4 | 5 | using System.Diagnostics;
|
5 | 6 | using ILCompiler;
|
6 | 7 | using Internal.TypeSystem;
|
| 8 | +using static Internal.JitInterface.StructFloatFieldInfoFlags; |
7 | 9 |
|
8 | 10 | namespace Internal.JitInterface
|
9 | 11 | {
|
10 |
| - |
11 | 12 | internal static class LoongArch64PassStructInRegister
|
12 | 13 | {
|
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) |
14 | 19 | {
|
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) |
19 | 30 | {
|
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 |
25 | 37 | }
|
| 38 | + return true; |
| 39 | + } |
26 | 40 |
|
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) |
28 | 48 | {
|
29 |
| - return (uint)StructFloatFieldInfoFlags.STRUCT_NO_FLOAT_FIELD; |
30 |
| - } |
| 49 | + if (field.IsStatic) |
| 50 | + continue; |
| 51 | + nFields++; |
31 | 52 |
|
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 |
34 | 55 |
|
35 |
| - TypeDesc firstFieldElementType = firstField.FieldType; |
36 |
| - int firstFieldSize = firstFieldElementType.GetElementSize().AsInt; |
| 56 | + prevField = field; |
37 | 57 |
|
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; |
39 | 69 |
|
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 |
44 | 76 | {
|
45 |
| - return (uint)StructFloatFieldInfoFlags.STRUCT_NO_FLOAT_FIELD; |
| 77 | + return false; |
46 | 78 | }
|
47 | 79 | }
|
48 | 80 |
|
49 |
| - int fieldIndex = 0; |
50 |
| - foreach (FieldDesc field in typeDesc.GetFields()) |
| 81 | + if ((td as MetadataType).HasImpliedRepeatedFields()) |
51 | 82 | {
|
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 | + } |
56 | 90 |
|
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; |
58 | 95 |
|
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; |
185 | 102 |
|
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; |
188 | 113 |
|
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; |
190 | 125 | }
|
191 | 126 | }
|
192 | 127 | }
|
0 commit comments