Skip to content

Commit

Permalink
[LoongArch64] Simplify flags for passing struct in registers. (#102041)
Browse files Browse the repository at this point in the history
Change-Id: Idbe644c0bc5baeb53a53e16731824e28aacf67a0
  • Loading branch information
LuckyXu-HF committed May 9, 2024
1 parent 279dbe1 commit 02e348b
Show file tree
Hide file tree
Showing 5 changed files with 139 additions and 817 deletions.
255 changes: 95 additions & 160 deletions src/coreclr/tools/Common/JitInterface/LoongArch64PassStructInRegister.cs
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;
}
}
}
16 changes: 2 additions & 14 deletions src/coreclr/vm/callingconvention.h
Original file line number Diff line number Diff line change
Expand Up @@ -1692,17 +1692,7 @@ int ArgIteratorTemplate<ARGITERATOR_BASE>::GetNextOffset()
}
else
{
MethodTable* pMethodTable = nullptr;

if (!thValueType.IsTypeDesc())
pMethodTable = thValueType.AsMethodTable();
else
{
_ASSERTE(thValueType.IsNativeValueType());
pMethodTable = thValueType.AsNativeValueType();
}
_ASSERTE(pMethodTable != nullptr);
flags = MethodTable::GetLoongArch64PassStructInRegisterFlags((CORINFO_CLASS_HANDLE)pMethodTable);
flags = MethodTable::GetLoongArch64PassStructInRegisterFlags(thValueType);
if (flags & STRUCT_HAS_FLOAT_FIELDS_MASK)
{
cFPRegs = (flags & STRUCT_FLOAT_FIELD_ONLY_TWO) ? 2 : 1;
Expand Down Expand Up @@ -2019,9 +2009,7 @@ void ArgIteratorTemplate<ARGITERATOR_BASE>::ComputeReturnFlags()
if (size <= ENREGISTERED_RETURNTYPE_INTEGER_MAXSIZE)
{
assert(!thValueType.IsTypeDesc());

MethodTable *pMethodTable = thValueType.AsMethodTable();
flags = (MethodTable::GetLoongArch64PassStructInRegisterFlags((CORINFO_CLASS_HANDLE)pMethodTable) & 0xff) << RETURN_FP_SIZE_SHIFT;
flags = (MethodTable::GetLoongArch64PassStructInRegisterFlags(thValueType) & 0xff) << RETURN_FP_SIZE_SHIFT;
break;
}
#elif defined(TARGET_RISCV64)
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/vm/jitinterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9632,7 +9632,7 @@ uint32_t CEEInfo::getLoongArch64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE c
uint32_t size = STRUCT_NO_FLOAT_FIELD;

#if defined(TARGET_LOONGARCH64)
size = (uint32_t)MethodTable::GetLoongArch64PassStructInRegisterFlags(cls);
size = (uint32_t)MethodTable::GetLoongArch64PassStructInRegisterFlags(TypeHandle(cls));
#endif

EE_TO_JIT_TRANSITION_LEAF();
Expand Down
Loading

0 comments on commit 02e348b

Please sign in to comment.