|
9 | 9 |
|
10 | 10 | namespace Internal.JitInterface
|
11 | 11 | {
|
12 |
| - internal static class LoongArch64PassStructInRegister |
| 12 | + // StructFloatFieldInfoFlags: used on LoongArch64 and RISC-V architecture as a legacy representation of |
| 13 | + // FpStructInRegistersInfo, returned by FpStructInRegistersInfo.ToOldFlags() |
| 14 | + // |
| 15 | + // `STRUCT_NO_FLOAT_FIELD` means structs are not passed using the float register(s). |
| 16 | + // |
| 17 | + // Otherwise, and only for structs with no more than two fields and a total struct size no larger |
| 18 | + // than two pointers: |
| 19 | + // |
| 20 | + // The lowest four bits denote the floating-point info: |
| 21 | + // bit 0: `1` means there is only one float or double field within the struct. |
| 22 | + // bit 1: `1` means only the first field is floating-point type. |
| 23 | + // bit 2: `1` means only the second field is floating-point type. |
| 24 | + // bit 3: `1` means the two fields are both floating-point type. |
| 25 | + // The bits[5:4] denoting whether the field size is 8-bytes: |
| 26 | + // bit 4: `1` means the first field's size is 8. |
| 27 | + // bit 5: `1` means the second field's size is 8. |
| 28 | + // |
| 29 | + // Note that bit 0 and 3 cannot both be set. |
| 30 | + [Flags] |
| 31 | + public enum StructFloatFieldInfoFlags |
| 32 | + { |
| 33 | + STRUCT_NO_FLOAT_FIELD = 0x0, |
| 34 | + STRUCT_FLOAT_FIELD_ONLY_ONE = 0x1, |
| 35 | + STRUCT_FLOAT_FIELD_ONLY_TWO = 0x8, |
| 36 | + STRUCT_FLOAT_FIELD_FIRST = 0x2, |
| 37 | + STRUCT_FLOAT_FIELD_SECOND = 0x4, |
| 38 | + STRUCT_FIRST_FIELD_SIZE_IS8 = 0x10, |
| 39 | + STRUCT_SECOND_FIELD_SIZE_IS8 = 0x20, |
| 40 | + }; |
| 41 | + |
| 42 | + |
| 43 | + // Bitfields for FpStructInRegistersInfo.flags |
| 44 | + [Flags] |
| 45 | + public enum FpStruct |
| 46 | + { |
| 47 | + // Positions of flags and bitfields |
| 48 | + PosOnlyOne = 0, |
| 49 | + PosBothFloat = 1, |
| 50 | + PosFloatInt = 2, |
| 51 | + PosIntFloat = 3, |
| 52 | + PosSizeShift1st = 4, // 2 bits |
| 53 | + PosSizeShift2nd = 6, // 2 bits |
| 54 | + |
| 55 | + UseIntCallConv = 0, // struct is passed according to integer calling convention |
| 56 | + |
| 57 | + // The flags and bitfields |
| 58 | + OnlyOne = 1 << PosOnlyOne, // has only one field, which is floating-point |
| 59 | + BothFloat = 1 << PosBothFloat, // has two fields, both are floating-point |
| 60 | + FloatInt = 1 << PosFloatInt, // has two fields, 1st is floating and 2nd is integer |
| 61 | + IntFloat = 1 << PosIntFloat, // has two fields, 2nd is floating and 1st is integer |
| 62 | + SizeShift1stMask = 0b11 << PosSizeShift1st, // log2(size) of 1st field |
| 63 | + SizeShift2ndMask = 0b11 << PosSizeShift2nd, // log2(size) of 2nd field |
| 64 | + // Note: flags OnlyOne, BothFloat, FloatInt, and IntFloat are mutually exclusive |
| 65 | + } |
| 66 | + |
| 67 | + // On RISC-V and LoongArch a struct with up to two non-empty fields, at least one of them floating-point, |
| 68 | + // can be passed in registers according to hardware FP calling convention. FpStructInRegistersInfo represents |
| 69 | + // passing information for such parameters. |
| 70 | + public struct FpStructInRegistersInfo |
| 71 | + { |
| 72 | + public FpStruct flags; |
| 73 | + public uint offset1st; |
| 74 | + public uint offset2nd; |
| 75 | + |
| 76 | + public uint SizeShift1st() { return (uint)((int)flags >> (int)FpStruct.PosSizeShift1st) & 0b11; } |
| 77 | + |
| 78 | + public uint SizeShift2nd() { return (uint)((int)flags >> (int)FpStruct.PosSizeShift2nd) & 0b11; } |
| 79 | + |
| 80 | + public uint Size1st() { return 1u << (int)SizeShift1st(); } |
| 81 | + public uint Size2nd() { return 1u << (int)SizeShift2nd(); } |
| 82 | + |
| 83 | + public StructFloatFieldInfoFlags ToOldFlags() |
| 84 | + { |
| 85 | + return |
| 86 | + ((flags & FpStruct.OnlyOne) != 0 ? StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_ONLY_ONE : 0) | |
| 87 | + ((flags & FpStruct.BothFloat) != 0 ? StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_ONLY_TWO : 0) | |
| 88 | + ((flags & FpStruct.FloatInt) != 0 ? StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_FIRST : 0) | |
| 89 | + ((flags & FpStruct.IntFloat) != 0 ? StructFloatFieldInfoFlags.STRUCT_FLOAT_FIELD_SECOND : 0) | |
| 90 | + ((SizeShift1st() == 3) ? StructFloatFieldInfoFlags.STRUCT_FIRST_FIELD_SIZE_IS8 : 0) | |
| 91 | + ((SizeShift2nd() == 3) ? StructFloatFieldInfoFlags.STRUCT_SECOND_FIELD_SIZE_IS8 : 0); |
| 92 | + } |
| 93 | + } |
| 94 | + |
| 95 | + internal static class RiscVLoongArch64FpStruct |
13 | 96 | {
|
14 | 97 | private const int
|
15 | 98 | ENREGISTERED_PARAMTYPE_MAXSIZE = 16,
|
@@ -125,8 +208,10 @@ private static bool FlattenFields(TypeDesc td, uint offset, ref FpStructInRegist
|
125 | 208 |
|
126 | 209 | private static bool IsAligned(uint val, uint alignment) => 0 == (val & (alignment - 1));
|
127 | 210 |
|
128 |
| - public static FpStructInRegistersInfo GetLoongArch64PassFpStructInRegistersInfo(TypeDesc td) |
| 211 | + public static FpStructInRegistersInfo GetFpStructInRegistersInfo(TypeDesc td, TargetArchitecture arch) |
129 | 212 | {
|
| 213 | + Debug.Assert(arch is TargetArchitecture.RiscV64 or TargetArchitecture.LoongArch64); |
| 214 | + |
130 | 215 | if (td.GetElementSize().AsInt > ENREGISTERED_PARAMTYPE_MAXSIZE)
|
131 | 216 | return new FpStructInRegistersInfo{};
|
132 | 217 |
|
|
0 commit comments