@@ -24,4 +24,216 @@ const regNumber fltArgRegs [] = {REG_F0, REG_F1, REG_F2, REG_F3, REG_F4, REG_F5,
2424const regMaskTP fltArgMasks[] = {RBM_F0, RBM_F1, RBM_F2, RBM_F3, RBM_F4, RBM_F5, RBM_F6, RBM_F7 };
2525// clang-format on
2626
27+ // -----------------------------------------------------------------------------
28+ // LoongArch64Classifier:
29+ // Construct a new instance of the LoongArch64 ABI classifier.
30+ //
31+ // Parameters:
32+ // info - Info about the method being classified.
33+ //
34+ LoongArch64Classifier::LoongArch64Classifier (const ClassifierInfo& info)
35+ : m_info(info)
36+ , m_intRegs(intArgRegs, ArrLen(intArgRegs))
37+ , m_floatRegs(fltArgRegs, ArrLen(fltArgRegs))
38+ {
39+ }
40+
41+ // -----------------------------------------------------------------------------
42+ // Classify:
43+ // Classify a parameter for the LoongArch64 ABI.
44+ //
45+ // Parameters:
46+ // comp - Compiler instance
47+ // type - The type of the parameter
48+ // structLayout - The layout of the struct. Expected to be non-null if
49+ // varTypeIsStruct(type) is true.
50+ // wellKnownParam - Well known type of the parameter (if it may affect its ABI classification)
51+ //
52+ // Returns:
53+ // Classification information for the parameter.
54+ //
55+ ABIPassingInformation LoongArch64Classifier::Classify (Compiler* comp,
56+ var_types type,
57+ ClassLayout* structLayout,
58+ WellKnownArg wellKnownParam)
59+ {
60+ assert (!m_info.IsVarArgs );
61+
62+ unsigned passedSize;
63+ unsigned slots = 0 ;
64+ var_types argRegTypeInStruct1 = TYP_UNKNOWN;
65+ var_types argRegTypeInStruct2 = TYP_UNKNOWN;
66+
67+ bool canPassArgInRegisters = false ;
68+ if (varTypeIsStruct (type))
69+ {
70+ passedSize = structLayout->GetSize ();
71+ if (passedSize > MAX_PASS_MULTIREG_BYTES)
72+ {
73+ slots = 1 ; // Passed by implicit byref
74+ passedSize = TARGET_POINTER_SIZE;
75+ canPassArgInRegisters = m_intRegs.Count () > 0 ;
76+ }
77+ else
78+ {
79+ assert (!structLayout->IsBlockLayout ());
80+
81+ uint32_t floatFlags;
82+ CORINFO_CLASS_HANDLE typeHnd = structLayout->GetClassHandle ();
83+
84+ floatFlags = comp->info .compCompHnd ->getLoongArch64PassStructInRegisterFlags (typeHnd);
85+
86+ if ((floatFlags & STRUCT_HAS_FLOAT_FIELDS_MASK) != 0 )
87+ {
88+ if ((floatFlags & STRUCT_FLOAT_FIELD_ONLY_ONE) != 0 )
89+ {
90+ assert (passedSize <= TARGET_POINTER_SIZE);
91+
92+ slots = 1 ;
93+ canPassArgInRegisters = m_floatRegs.Count () > 0 ;
94+
95+ argRegTypeInStruct1 = (passedSize == 8 ) ? TYP_DOUBLE : TYP_FLOAT;
96+ }
97+ else if ((floatFlags & STRUCT_FLOAT_FIELD_ONLY_TWO) != 0 )
98+ {
99+ slots = 2 ;
100+ canPassArgInRegisters = m_floatRegs.Count () >= 2 ;
101+
102+ argRegTypeInStruct1 = (floatFlags & STRUCT_FIRST_FIELD_SIZE_IS8) ? TYP_DOUBLE : TYP_FLOAT;
103+ argRegTypeInStruct2 = (floatFlags & STRUCT_SECOND_FIELD_SIZE_IS8) ? TYP_DOUBLE : TYP_FLOAT;
104+ }
105+ else if ((floatFlags & STRUCT_FLOAT_FIELD_FIRST) != 0 )
106+ {
107+ slots = 1 ;
108+ canPassArgInRegisters = (m_floatRegs.Count () > 0 ) && (m_intRegs.Count () > 0 );
109+
110+ argRegTypeInStruct1 = (floatFlags & STRUCT_FIRST_FIELD_SIZE_IS8) ? TYP_DOUBLE : TYP_FLOAT;
111+ argRegTypeInStruct2 = (floatFlags & STRUCT_SECOND_FIELD_SIZE_IS8) ? TYP_LONG : TYP_INT;
112+ }
113+ else if ((floatFlags & STRUCT_FLOAT_FIELD_SECOND) != 0 )
114+ {
115+ slots = 1 ;
116+ canPassArgInRegisters = (m_floatRegs.Count () > 0 ) && (m_intRegs.Count () > 0 );
117+
118+ argRegTypeInStruct1 = (floatFlags & STRUCT_FIRST_FIELD_SIZE_IS8) ? TYP_LONG : TYP_INT;
119+ argRegTypeInStruct2 = (floatFlags & STRUCT_SECOND_FIELD_SIZE_IS8) ? TYP_DOUBLE : TYP_FLOAT;
120+ }
121+
122+ assert ((slots == 1 ) || (slots == 2 ));
123+
124+ if (!canPassArgInRegisters)
125+ {
126+ m_floatRegs.Clear ();
127+ slots = (passedSize + TARGET_POINTER_SIZE - 1 ) / TARGET_POINTER_SIZE;
128+ // On LoongArch64, if there aren't any remaining floating-point registers to pass the argument,
129+ // integer registers (if any) are used instead.
130+ canPassArgInRegisters = m_intRegs.Count () >= slots;
131+
132+ argRegTypeInStruct1 = TYP_UNKNOWN;
133+ argRegTypeInStruct2 = TYP_UNKNOWN;
134+ }
135+ }
136+ else
137+ {
138+ slots = (passedSize + TARGET_POINTER_SIZE - 1 ) / TARGET_POINTER_SIZE;
139+ canPassArgInRegisters = m_intRegs.Count () >= slots;
140+ }
141+
142+ if (!canPassArgInRegisters && (slots == 2 ))
143+ {
144+ // Here a struct-arg which needs two registers but only one integer register available,
145+ // it has to be split.
146+ if (m_intRegs.Count () > 0 )
147+ {
148+ canPassArgInRegisters = true ;
149+ }
150+ }
151+ }
152+ }
153+ else
154+ {
155+ assert (genTypeSize (type) <= TARGET_POINTER_SIZE);
156+
157+ slots = 1 ;
158+ passedSize = genTypeSize (type);
159+ if (varTypeIsFloating (type))
160+ {
161+ canPassArgInRegisters = m_floatRegs.Count () > 0 ;
162+ if (!canPassArgInRegisters)
163+ {
164+ m_floatRegs.Clear ();
165+ canPassArgInRegisters = m_intRegs.Count () > 0 ;
166+ }
167+ }
168+ else
169+ {
170+ canPassArgInRegisters = m_intRegs.Count () > 0 ;
171+ }
172+ }
173+
174+ ABIPassingInformation info;
175+ if (canPassArgInRegisters)
176+ {
177+ info.NumSegments = slots;
178+ info.Segments = new (comp, CMK_ABI) ABIPassingSegment[slots];
179+ if (argRegTypeInStruct1 != TYP_UNKNOWN)
180+ {
181+ RegisterQueue* regs = varTypeIsFloating (argRegTypeInStruct1) ? &m_floatRegs : &m_intRegs;
182+ assert (regs->Count () > 0 );
183+
184+ passedSize = genTypeSize (argRegTypeInStruct1);
185+ info.Segments [0 ] = ABIPassingSegment::InRegister (regs->Dequeue (), 0 , passedSize);
186+
187+ if (argRegTypeInStruct2 != TYP_UNKNOWN)
188+ {
189+ unsigned slotSize = genTypeSize (argRegTypeInStruct2);
190+
191+ regs = varTypeIsFloating (argRegTypeInStruct2) ? &m_floatRegs : &m_intRegs;
192+ assert (regs->Count () > 0 );
193+
194+ passedSize = max (passedSize, slotSize);
195+ info.Segments [1 ] = ABIPassingSegment::InRegister (regs->Dequeue (), passedSize, slotSize);
196+ }
197+ }
198+ else
199+ {
200+ RegisterQueue* regs = varTypeIsFloating (type) ? &m_floatRegs : &m_intRegs;
201+ unsigned slotSize = min (passedSize, (unsigned )TARGET_POINTER_SIZE);
202+ info.Segments [0 ] = ABIPassingSegment::InRegister (regs->Dequeue (), 0 , slotSize);
203+ if (slots == 2 )
204+ {
205+ assert (varTypeIsStruct (type));
206+ assert (passedSize > TARGET_POINTER_SIZE);
207+ unsigned tailSize = passedSize - slotSize;
208+ if (m_intRegs.Count () > 0 )
209+ {
210+ info.Segments [1 ] = ABIPassingSegment::InRegister (m_intRegs.Dequeue (), slotSize, tailSize);
211+ }
212+ else
213+ {
214+ assert (m_intRegs.Count () == 0 );
215+ assert (m_stackArgSize == 0 );
216+ info.Segments [1 ] = ABIPassingSegment::OnStack (0 , TARGET_POINTER_SIZE, tailSize);
217+ m_stackArgSize += TARGET_POINTER_SIZE;
218+ }
219+ }
220+ }
221+ }
222+ else
223+ {
224+ assert ((m_stackArgSize % TARGET_POINTER_SIZE) == 0 );
225+
226+ info = ABIPassingInformation::FromSegment (comp, ABIPassingSegment::OnStack (m_stackArgSize, 0 , passedSize));
227+
228+ m_stackArgSize += roundUp (passedSize, TARGET_POINTER_SIZE);
229+
230+ // As soon as we pass something on stack we cannot go back and
231+ // enregister something else.
232+ // The float had been cleared before and only integer type go here.
233+ m_intRegs.Clear ();
234+ }
235+
236+ return info;
237+ }
238+
27239#endif // TARGET_LOONGARCH64
0 commit comments