Skip to content

Commit

Permalink
Merge LoongArch and RISC-V AOT calculation of FpStructInRegistersInfo…
Browse files Browse the repository at this point in the history
… because they were identical. Move it to Common\Internal/Runtime because it's no longer exposed in JIT interface.
  • Loading branch information
tomeksowi committed Jul 11, 2024
1 parent f064eb6 commit d4be92c
Show file tree
Hide file tree
Showing 8 changed files with 99 additions and 288 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,90 @@

namespace Internal.JitInterface
{
internal static class LoongArch64PassStructInRegister
// StructFloatFieldInfoFlags: used on LoongArch64 and RISC-V architecture as a legacy representation of
// FpStructInRegistersInfo, returned by FpStructInRegistersInfo.ToOldFlags()
//
// `STRUCT_NO_FLOAT_FIELD` means structs are not passed using the float register(s).
//
// Otherwise, and only for structs with no more than two fields and a total struct size no larger
// than two pointers:
//
// The lowest four bits denote the floating-point info:
// bit 0: `1` means there is only one float or double field within the struct.
// bit 1: `1` means only the first field is floating-point type.
// bit 2: `1` means only the second field is floating-point type.
// bit 3: `1` means the two fields are both floating-point type.
// The bits[5:4] denoting whether the field size is 8-bytes:
// bit 4: `1` means the first field's size is 8.
// bit 5: `1` means the second field's size is 8.
//
// Note that bit 0 and 3 cannot both be set.
[Flags]
public enum StructFloatFieldInfoFlags
{
STRUCT_NO_FLOAT_FIELD = 0x0,
STRUCT_FLOAT_FIELD_ONLY_ONE = 0x1,
STRUCT_FLOAT_FIELD_ONLY_TWO = 0x8,
STRUCT_FLOAT_FIELD_FIRST = 0x2,
STRUCT_FLOAT_FIELD_SECOND = 0x4,
STRUCT_FIRST_FIELD_SIZE_IS8 = 0x10,
STRUCT_SECOND_FIELD_SIZE_IS8 = 0x20,
};


// Bitfields for FpStructInRegistersInfo.flags
[Flags]
public enum FpStruct
{
// Positions of flags and bitfields
PosOnlyOne = 0,
PosBothFloat = 1,
PosFloatInt = 2,
PosIntFloat = 3,
PosSizeShift1st = 4, // 2 bits
PosSizeShift2nd = 6, // 2 bits

UseIntCallConv = 0, // struct is passed according to integer calling convention

// The flags and bitfields
OnlyOne = 1 << PosOnlyOne, // has only one field, which is floating-point
BothFloat = 1 << PosBothFloat, // has two fields, both are floating-point
FloatInt = 1 << PosFloatInt, // has two fields, 1st is floating and 2nd is integer
IntFloat = 1 << PosIntFloat, // has two fields, 2nd is floating and 1st is integer
SizeShift1stMask = 0b11 << PosSizeShift1st, // log2(size) of 1st field
SizeShift2ndMask = 0b11 << PosSizeShift2nd, // log2(size) of 2nd field
// Note: flags OnlyOne, BothFloat, FloatInt, and IntFloat are mutually exclusive
}

// On RISC-V and LoongArch a struct with up to two non-empty fields, at least one of them floating-point,
// can be passed in registers according to hardware FP calling convention. FpStructInRegistersInfo represents
// passing information for such parameters.
public struct FpStructInRegistersInfo
{
public FpStruct flags;
public uint offset1st;
public uint offset2nd;

public uint SizeShift1st() { return (uint)((int)flags >> (int)FpStruct.PosSizeShift1st) & 0b11; }

public uint SizeShift2nd() { return (uint)((int)flags >> (int)FpStruct.PosSizeShift2nd) & 0b11; }

public uint Size1st() { return 1u << (int)SizeShift1st(); }
public uint Size2nd() { return 1u << (int)SizeShift2nd(); }

public StructFloatFieldInfoFlags ToOldFlags()
{
return
((flags & FpStruct.OnlyOne) != 0 ? StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_ONLY_ONE : 0) |
((flags & FpStruct.BothFloat) != 0 ? StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_ONLY_TWO : 0) |
((flags & FpStruct.FloatInt) != 0 ? StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_FIRST : 0) |
((flags & FpStruct.IntFloat) != 0 ? StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_SECOND : 0) |
((SizeShift1st() == 3) ? StructFloatFieldInfoFlags.STRUCT_FIRST_FIELD_SIZE_IS8 : 0) |
((SizeShift2nd() == 3) ? StructFloatFieldInfoFlags.STRUCT_SECOND_FIELD_SIZE_IS8 : 0);
}
}

internal static class RiscVLoongArch64FpStruct
{
private const int
ENREGISTERED_PARAMTYPE_MAXSIZE = 16,
Expand Down Expand Up @@ -125,8 +208,10 @@ private static bool FlattenFields(TypeDesc td, uint offset, ref FpStructInRegist

private static bool IsAligned(uint val, uint alignment) => 0 == (val & (alignment - 1));

public static FpStructInRegistersInfo GetLoongArch64PassFpStructInRegistersInfo(TypeDesc td)
public static FpStructInRegistersInfo GetFpStructInRegistersInfo(TypeDesc td, TargetArchitecture arch)
{
Debug.Assert(arch is TargetArchitecture.RiscV64 or TargetArchitecture.LoongArch64);

if (td.GetElementSize().AsInt > ENREGISTERED_PARAMTYPE_MAXSIZE)
return new FpStructInRegistersInfo{};

Expand Down
19 changes: 2 additions & 17 deletions src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3456,23 +3456,8 @@ private void getSwiftLowering(CORINFO_CLASS_STRUCT_* structHnd, ref CORINFO_SWIF

private void getFpStructLowering(CORINFO_CLASS_STRUCT_* structHnd, ref CORINFO_FPSTRUCT_LOWERING lowering)
{
TypeDesc typeDesc = HandleToObject(structHnd);
var target = _compilation.TypeSystemContext.Target;
FpStructInRegistersInfo info;
if (target.Architecture is TargetArchitecture.RiscV64)
{
info = RiscV64PassFpStructInRegisters.GetRiscV64PassFpStructInRegistersInfo(typeDesc);
}
else if (target.Architecture is TargetArchitecture.LoongArch64)
{
info = LoongArch64PassStructInRegister.GetLoongArch64PassFpStructInRegistersInfo(typeDesc);
}
else
{
Debug.Assert(false, "Unsupported architecture for getFpStructInRegistersInfo");
return;
}

FpStructInRegistersInfo info = RiscVLoongArch64FpStruct.GetFpStructInRegistersInfo(
HandleToObject(structHnd), _compilation.TypeSystemContext.Target.Architecture);
if (info.flags != FpStruct.UseIntCallConv)
{
lowering = new CORINFO_FPSTRUCT_LOWERING {
Expand Down
83 changes: 0 additions & 83 deletions src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1221,89 +1221,6 @@ public struct SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR
public byte eightByteOffsets1;
};

// StructFloatFieldInfoFlags: used on LoongArch64 and RISC-V architecture as a legacy representation of
// FpStructInRegistersInfo, returned by FpStructInRegistersInfo.ToOldFlags()
//
// `STRUCT_NO_FLOAT_FIELD` means structs are not passed using the float register(s).
//
// Otherwise, and only for structs with no more than two fields and a total struct size no larger
// than two pointers:
//
// The lowest four bits denote the floating-point info:
// bit 0: `1` means there is only one float or double field within the struct.
// bit 1: `1` means only the first field is floating-point type.
// bit 2: `1` means only the second field is floating-point type.
// bit 3: `1` means the two fields are both floating-point type.
// The bits[5:4] denoting whether the field size is 8-bytes:
// bit 4: `1` means the first field's size is 8.
// bit 5: `1` means the second field's size is 8.
//
// Note that bit 0 and 3 cannot both be set.
[Flags]
public enum StructFloatFieldInfoFlags
{
STRUCT_NO_FLOAT_FIELD = 0x0,
STRUCT_FLOAT_FIELD_ONLY_ONE = 0x1,
STRUCT_FLOAT_FIELD_ONLY_TWO = 0x8,
STRUCT_FLOAT_FIELD_FIRST = 0x2,
STRUCT_FLOAT_FIELD_SECOND = 0x4,
STRUCT_FIRST_FIELD_SIZE_IS8 = 0x10,
STRUCT_SECOND_FIELD_SIZE_IS8 = 0x20,
};


// Bitfields for FpStructInRegistersInfo.flags
[Flags]
public enum FpStruct
{
// Positions of flags and bitfields
PosOnlyOne = 0,
PosBothFloat = 1,
PosFloatInt = 2,
PosIntFloat = 3,
PosSizeShift1st = 4, // 2 bits
PosSizeShift2nd = 6, // 2 bits

UseIntCallConv = 0, // struct is passed according to integer calling convention

// The flags and bitfields
OnlyOne = 1 << PosOnlyOne, // has only one field, which is floating-point
BothFloat = 1 << PosBothFloat, // has two fields, both are floating-point
FloatInt = 1 << PosFloatInt, // has two fields, 1st is floating and 2nd is integer
IntFloat = 1 << PosIntFloat, // has two fields, 2nd is floating and 1st is integer
SizeShift1stMask = 0b11 << PosSizeShift1st, // log2(size) of 1st field
SizeShift2ndMask = 0b11 << PosSizeShift2nd, // log2(size) of 2nd field
// Note: flags OnlyOne, BothFloat, FloatInt, and IntFloat are mutually exclusive
}

// On RISC-V and LoongArch a struct with up to two non-empty fields, at least one of them floating-point,
// can be passed in registers according to hardware FP calling convention. FpStructInRegistersInfo represents
// passing information for such parameters.
public struct FpStructInRegistersInfo
{
public FpStruct flags;
public uint offset1st;
public uint offset2nd;

public uint SizeShift1st() { return (uint)((int)flags >> (int)FpStruct.PosSizeShift1st) & 0b11; }

public uint SizeShift2nd() { return (uint)((int)flags >> (int)FpStruct.PosSizeShift2nd) & 0b11; }

public uint Size1st() { return 1u << (int)SizeShift1st(); }
public uint Size2nd() { return 1u << (int)SizeShift2nd(); }

public StructFloatFieldInfoFlags ToOldFlags()
{
return
((flags & FpStruct.OnlyOne) != 0 ? StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_ONLY_ONE : 0) |
((flags & FpStruct.BothFloat) != 0 ? StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_ONLY_TWO : 0) |
((flags & FpStruct.FloatInt) != 0 ? StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_FIRST : 0) |
((flags & FpStruct.IntFloat) != 0 ? StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_SECOND : 0) |
((SizeShift1st() == 3) ? StructFloatFieldInfoFlags.STRUCT_FIRST_FIELD_SIZE_IS8 : 0) |
((SizeShift2nd() == 3) ? StructFloatFieldInfoFlags.STRUCT_SECOND_FIELD_SIZE_IS8 : 0);
}
}

// DEBUGGER DATA
public enum MappingTypes
{
Expand Down

This file was deleted.

Loading

0 comments on commit d4be92c

Please sign in to comment.