forked from dotnet/runtime
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[LoongArch64] Simplify flags for passing struct in registers. (dotnet…
…#102041) Change-Id: Idbe644c0bc5baeb53a53e16731824e28aacf67a0
- Loading branch information
1 parent
3fbdc8e
commit 106183a
Showing
5 changed files
with
139 additions
and
817 deletions.
There are no files selected for viewing
255 changes: 95 additions & 160 deletions
255
src/coreclr/tools/Common/JitInterface/LoongArch64PassStructInRegister.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,192 +1,127 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Diagnostics; | ||
using ILCompiler; | ||
using Internal.TypeSystem; | ||
using static Internal.JitInterface.StructFloatFieldInfoFlags; | ||
|
||
namespace Internal.JitInterface | ||
{ | ||
|
||
internal static class LoongArch64PassStructInRegister | ||
{ | ||
public static uint GetLoongArch64PassStructInRegisterFlags(TypeDesc typeDesc) | ||
private const int | ||
ENREGISTERED_PARAMTYPE_MAXSIZE = 16, | ||
TARGET_POINTER_SIZE = 8; | ||
|
||
private static bool HandleInlineArray(int elementTypeIndex, int nElements, Span<StructFloatFieldInfoFlags> types, ref int typeIndex) | ||
{ | ||
FieldDesc firstField = null; | ||
uint floatFieldFlags = (uint)StructFloatFieldInfoFlags.STRUCT_NO_FLOAT_FIELD; | ||
int numIntroducedFields = 0; | ||
foreach (FieldDesc field in typeDesc.GetFields()) | ||
int nFlattenedFieldsPerElement = typeIndex - elementTypeIndex; | ||
if (nFlattenedFieldsPerElement == 0) | ||
return true; | ||
|
||
Debug.Assert(nFlattenedFieldsPerElement == 1 || nFlattenedFieldsPerElement == 2); | ||
|
||
if (nElements > 2) | ||
return false; | ||
|
||
if (nElements == 2) | ||
{ | ||
if (!field.IsStatic) | ||
{ | ||
firstField ??= field; | ||
numIntroducedFields++; | ||
} | ||
if (typeIndex + nFlattenedFieldsPerElement > 2) | ||
return false; | ||
|
||
Debug.Assert(elementTypeIndex == 0); | ||
Debug.Assert(typeIndex == 1); | ||
types[typeIndex++] = types[elementTypeIndex]; // duplicate the array element type | ||
} | ||
return true; | ||
} | ||
|
||
if ((numIntroducedFields == 0) || (numIntroducedFields > 2) || (typeDesc.GetElementSize().AsInt > 16)) | ||
private static bool FlattenFieldTypes(TypeDesc td, Span<StructFloatFieldInfoFlags> types, ref int typeIndex) | ||
{ | ||
IEnumerable<FieldDesc> fields = td.GetFields(); | ||
int nFields = 0; | ||
int elementTypeIndex = typeIndex; | ||
FieldDesc prevField = null; | ||
foreach (FieldDesc field in fields) | ||
{ | ||
return (uint)StructFloatFieldInfoFlags.STRUCT_NO_FLOAT_FIELD; | ||
} | ||
if (field.IsStatic) | ||
continue; | ||
nFields++; | ||
|
||
MetadataType mdType = typeDesc as MetadataType; | ||
Debug.Assert(mdType != null); | ||
if (prevField != null && prevField.Offset.AsInt + prevField.FieldType.GetElementSize().AsInt > field.Offset.AsInt) | ||
return false; // overlapping fields | ||
|
||
TypeDesc firstFieldElementType = firstField.FieldType; | ||
int firstFieldSize = firstFieldElementType.GetElementSize().AsInt; | ||
prevField = field; | ||
|
||
bool hasImpliedRepeatedFields = mdType.HasImpliedRepeatedFields(); | ||
TypeFlags category = field.FieldType.Category; | ||
if (category == TypeFlags.ValueType) | ||
{ | ||
TypeDesc nested = field.FieldType; | ||
if (!FlattenFieldTypes(nested, types, ref typeIndex)) | ||
return false; | ||
} | ||
else if (field.FieldType.GetElementSize().AsInt <= TARGET_POINTER_SIZE) | ||
{ | ||
if (typeIndex >= 2) | ||
return false; | ||
|
||
if (hasImpliedRepeatedFields) | ||
{ | ||
numIntroducedFields = typeDesc.GetElementSize().AsInt / firstFieldSize; | ||
if (numIntroducedFields > 2) | ||
StructFloatFieldInfoFlags type = | ||
(category is TypeFlags.Single or TypeFlags.Double ? STRUCT_FLOAT_FIELD_FIRST : (StructFloatFieldInfoFlags)0) | | ||
(field.FieldType.GetElementSize().AsInt == TARGET_POINTER_SIZE ? STRUCT_FIRST_FIELD_SIZE_IS8 : (StructFloatFieldInfoFlags)0); | ||
types[typeIndex++] = type; | ||
} | ||
else | ||
{ | ||
return (uint)StructFloatFieldInfoFlags.STRUCT_NO_FLOAT_FIELD; | ||
return false; | ||
} | ||
} | ||
|
||
int fieldIndex = 0; | ||
foreach (FieldDesc field in typeDesc.GetFields()) | ||
if ((td as MetadataType).HasImpliedRepeatedFields()) | ||
{ | ||
if (field.IsStatic) | ||
{ | ||
continue; | ||
} | ||
Debug.Assert(nFields == 1); | ||
int nElements = td.GetElementSize().AsInt / prevField.FieldType.GetElementSize().AsInt; | ||
if (!HandleInlineArray(elementTypeIndex, nElements, types, ref typeIndex)) | ||
return false; | ||
} | ||
return true; | ||
} | ||
|
||
Debug.Assert(fieldIndex < numIntroducedFields); | ||
public static uint GetLoongArch64PassStructInRegisterFlags(TypeDesc td) | ||
{ | ||
if (td.GetElementSize().AsInt > ENREGISTERED_PARAMTYPE_MAXSIZE) | ||
return (uint)STRUCT_NO_FLOAT_FIELD; | ||
|
||
switch (field.FieldType.Category) | ||
{ | ||
case TypeFlags.Double: | ||
{ | ||
if (numIntroducedFields == 1) | ||
{ | ||
floatFieldFlags = (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_ONLY_ONE; | ||
} | ||
else if (fieldIndex == 0) | ||
{ | ||
floatFieldFlags = (uint)StructFloatFieldInfoFlags.STRUCT_FIRST_FIELD_DOUBLE; | ||
} | ||
else if ((floatFieldFlags & (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_FIRST) != 0) | ||
{ | ||
floatFieldFlags ^= (uint)StructFloatFieldInfoFlags.STRUCT_MERGE_FIRST_SECOND_8; | ||
} | ||
else | ||
{ | ||
floatFieldFlags |= (uint)StructFloatFieldInfoFlags.STRUCT_SECOND_FIELD_DOUBLE; | ||
} | ||
} | ||
break; | ||
|
||
case TypeFlags.Single: | ||
{ | ||
if (numIntroducedFields == 1) | ||
{ | ||
floatFieldFlags = (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_ONLY_ONE; | ||
} | ||
else if (fieldIndex == 0) | ||
{ | ||
floatFieldFlags = (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_FIRST; | ||
} | ||
else if ((floatFieldFlags & (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_FIRST) != 0) | ||
{ | ||
floatFieldFlags ^= (uint)StructFloatFieldInfoFlags.STRUCT_MERGE_FIRST_SECOND; | ||
} | ||
else | ||
{ | ||
floatFieldFlags |= (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_SECOND; | ||
} | ||
} | ||
break; | ||
|
||
case TypeFlags.ValueType: | ||
//case TypeFlags.Class: | ||
//case TypeFlags.Array: | ||
//case TypeFlags.SzArray: | ||
{ | ||
uint floatFieldFlags2 = GetLoongArch64PassStructInRegisterFlags(field.FieldType); | ||
if (numIntroducedFields == 1) | ||
{ | ||
floatFieldFlags = floatFieldFlags2; | ||
} | ||
else if (field.FieldType.GetElementSize().AsInt > 8) | ||
{ | ||
return (uint)StructFloatFieldInfoFlags.STRUCT_NO_FLOAT_FIELD; | ||
} | ||
else if (fieldIndex == 0) | ||
{ | ||
if ((floatFieldFlags2 & (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_ONLY_ONE) != 0) | ||
{ | ||
floatFieldFlags = (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_FIRST; | ||
} | ||
if (field.FieldType.GetElementSize().AsInt == 8) | ||
{ | ||
floatFieldFlags |= (uint)StructFloatFieldInfoFlags.STRUCT_FIRST_FIELD_SIZE_IS8; | ||
} | ||
} | ||
else | ||
{ | ||
Debug.Assert(fieldIndex == 1); | ||
if ((floatFieldFlags2 & (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_ONLY_ONE) != 0) | ||
{ | ||
floatFieldFlags |= (uint)StructFloatFieldInfoFlags.STRUCT_MERGE_FIRST_SECOND; | ||
} | ||
if (field.FieldType.GetElementSize().AsInt == 8) | ||
{ | ||
floatFieldFlags |= (uint)StructFloatFieldInfoFlags.STRUCT_SECOND_FIELD_SIZE_IS8; | ||
} | ||
|
||
floatFieldFlags2 = floatFieldFlags & ((uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_FIRST | (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_SECOND); | ||
if (floatFieldFlags2 == 0) | ||
{ | ||
floatFieldFlags = (uint)StructFloatFieldInfoFlags.STRUCT_NO_FLOAT_FIELD; | ||
} | ||
else if (floatFieldFlags2 == ((uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_FIRST | (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_SECOND)) | ||
{ | ||
floatFieldFlags ^= ((uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_ONLY_TWO | (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_FIRST | (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_SECOND); | ||
} | ||
} | ||
} | ||
break; | ||
|
||
default: | ||
{ | ||
if ((numIntroducedFields == 2) && (field.FieldType.Category == TypeFlags.Class)) | ||
{ | ||
return (uint)StructFloatFieldInfoFlags.STRUCT_NO_FLOAT_FIELD; | ||
} | ||
|
||
if (field.FieldType.GetElementSize().AsInt == 8) | ||
{ | ||
if (numIntroducedFields > 1) | ||
{ | ||
if (fieldIndex == 0) | ||
{ | ||
floatFieldFlags = (uint)StructFloatFieldInfoFlags.STRUCT_FIRST_FIELD_SIZE_IS8; | ||
} | ||
else if ((floatFieldFlags & (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_FIRST) != 0) | ||
{ | ||
floatFieldFlags |= (uint)StructFloatFieldInfoFlags.STRUCT_SECOND_FIELD_SIZE_IS8; | ||
} | ||
else | ||
{ | ||
floatFieldFlags = (uint)StructFloatFieldInfoFlags.STRUCT_NO_FLOAT_FIELD; | ||
} | ||
} | ||
} | ||
else if (fieldIndex == 1) | ||
{ | ||
floatFieldFlags = (floatFieldFlags & (uint)StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_FIRST) > 0 ? floatFieldFlags : (uint)StructFloatFieldInfoFlags.STRUCT_NO_FLOAT_FIELD; | ||
} | ||
break; | ||
} | ||
} | ||
Span<StructFloatFieldInfoFlags> types = stackalloc StructFloatFieldInfoFlags[] { | ||
STRUCT_NO_FLOAT_FIELD, STRUCT_NO_FLOAT_FIELD | ||
}; | ||
int nFields = 0; | ||
if (!FlattenFieldTypes(td, types, ref nFields) || nFields == 0) | ||
return (uint)STRUCT_NO_FLOAT_FIELD; | ||
|
||
fieldIndex++; | ||
} | ||
Debug.Assert(nFields == 1 || nFields == 2); | ||
|
||
Debug.Assert((uint)(STRUCT_FLOAT_FIELD_SECOND | STRUCT_SECOND_FIELD_SIZE_IS8) | ||
== (uint)(STRUCT_FLOAT_FIELD_FIRST | STRUCT_FIRST_FIELD_SIZE_IS8) << 1, | ||
"SECOND flags need to be FIRST shifted by 1"); | ||
StructFloatFieldInfoFlags flags = types[0] | (StructFloatFieldInfoFlags)((uint)types[1] << 1); | ||
|
||
const StructFloatFieldInfoFlags bothFloat = STRUCT_FLOAT_FIELD_FIRST | STRUCT_FLOAT_FIELD_SECOND; | ||
if ((flags & bothFloat) == 0) | ||
return (uint)STRUCT_NO_FLOAT_FIELD; | ||
|
||
return floatFieldFlags; | ||
if ((flags & bothFloat) == bothFloat) | ||
{ | ||
Debug.Assert(nFields == 2); | ||
flags ^= (bothFloat | STRUCT_FLOAT_FIELD_ONLY_TWO); // replace bothFloat with ONLY_TWO | ||
} | ||
else if (nFields == 1) | ||
{ | ||
Debug.Assert((flags & STRUCT_FLOAT_FIELD_FIRST) != 0); | ||
flags ^= (STRUCT_FLOAT_FIELD_FIRST | STRUCT_FLOAT_FIELD_ONLY_ONE); // replace FIRST with ONLY_ONE | ||
} | ||
return (uint)flags; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.