@@ -26,4 +26,185 @@ const regMaskTP fltArgMasks[] = {RBM_F0, RBM_F1, RBM_F2, RBM_F3, RBM_F4, RBM_F5,
2626
2727static_assert_no_msg (RBM_ALLDOUBLE == (RBM_ALLDOUBLE_HIGH >> 1 ));
2828
29+ // -----------------------------------------------------------------------------
30+ // Arm32Classifier:
31+ // Construct a new instance of the arm32 ABI classifier.
32+ //
33+ // Parameters:
34+ // info - Info about the method being classified.
35+ //
36+ Arm32Classifier::Arm32Classifier (const ClassifierInfo& info) : m_info(info)
37+ {
38+ }
39+
40+ // -----------------------------------------------------------------------------
41+ // Classify:
42+ // Classify a parameter for the arm32 ABI.
43+ //
44+ // Parameters:
45+ // comp - Compiler instance
46+ // type - The type of the parameter
47+ // structLayout - The layout of the struct. Expected to be non-null if
48+ // varTypeIsStruct(type) is true.
49+ // wellKnownParam - Well known type of the parameter (if it may affect its ABI classification)
50+ //
51+ // Returns:
52+ // Classification information for the parameter.
53+ //
54+ ABIPassingInformation Arm32Classifier::Classify (Compiler* comp,
55+ var_types type,
56+ ClassLayout* structLayout,
57+ WellKnownArg wellKnownParam)
58+ {
59+ if (!comp->opts .compUseSoftFP )
60+ {
61+ if (varTypeIsStruct (type))
62+ {
63+ var_types hfaType = comp->GetHfaType (structLayout->GetClassHandle ());
64+
65+ if (hfaType != TYP_UNDEF)
66+ {
67+ unsigned slots = structLayout->GetSize () / genTypeSize (hfaType);
68+ return ClassifyFloat (comp, hfaType, slots);
69+ }
70+ }
71+
72+ if (varTypeIsFloating (type))
73+ {
74+ return ClassifyFloat (comp, type, 1 );
75+ }
76+ }
77+
78+ unsigned alignment = 4 ;
79+ if ((type == TYP_LONG) || (type == TYP_DOUBLE) ||
80+ ((type == TYP_STRUCT) &&
81+ (comp->info .compCompHnd ->getClassAlignmentRequirement (structLayout->GetClassHandle ()) == 8 )))
82+ {
83+ alignment = 8 ;
84+ m_nextIntReg = roundUp (m_nextIntReg, 2 );
85+ }
86+
87+ unsigned size = type == TYP_STRUCT ? structLayout->GetSize () : genTypeSize (type);
88+ unsigned alignedSize = roundUp (size, alignment);
89+
90+ unsigned numInRegs = min (alignedSize / 4 , 4 - m_nextIntReg);
91+ bool anyOnStack = numInRegs < (alignedSize / 4 );
92+
93+ // If we already passed anything on stack (due to float args) then we
94+ // cannot split an arg.
95+ if ((numInRegs > 0 ) && anyOnStack && (m_stackArgSize != 0 ))
96+ {
97+ numInRegs = 0 ;
98+ }
99+
100+ ABIPassingInformation info;
101+ info.NumSegments = numInRegs + (anyOnStack ? 1 : 0 );
102+ info.Segments = new (comp, CMK_ABI) ABIPassingSegment[info.NumSegments ];
103+
104+ for (unsigned i = 0 ; i < numInRegs; i++)
105+ {
106+ unsigned endOffs = min ((i + 1 ) * 4 , size);
107+ info.Segments [i] =
108+ ABIPassingSegment::InRegister (static_cast <regNumber>(static_cast <unsigned >(REG_R0) + m_nextIntReg + i),
109+ i * 4 , endOffs - (i * 4 ));
110+ }
111+
112+ m_nextIntReg += numInRegs;
113+
114+ if (anyOnStack)
115+ {
116+ m_stackArgSize = roundUp (m_stackArgSize, alignment);
117+ unsigned stackSize = size - (numInRegs * 4 );
118+ info.Segments [numInRegs] = ABIPassingSegment::OnStack (m_stackArgSize, 0 , stackSize);
119+ m_stackArgSize += roundUp (stackSize, 4 );
120+
121+ // As soon as any int arg goes on stack we cannot put anything else in
122+ // int registers. This situation can happen if an arg would normally be
123+ // split but wasn't because a float arg was already passed on stack.
124+ m_nextIntReg = 4 ;
125+ }
126+
127+ return info;
128+ }
129+
130+ // -----------------------------------------------------------------------------
131+ // ClassifyFloat:
132+ // Classify a parameter that uses float registers.
133+ //
134+ // Parameters:
135+ // comp - Compiler instance
136+ // type - The type of the parameter
137+ // numElems - Number of elements for the parameter.
138+ //
139+ // Returns:
140+ // Classification information for the parameter.
141+ //
142+ // Remarks:
143+ // Float parameters can require multiple registers; the double registers are
144+ // overlaid on top of the float registers so that d0 = s0, s1, d1 = s2, s3
145+ // etc. This means that allocating a double register automatically makes the
146+ // two corresponding float registers unavailable.
147+ //
148+ // The ABI also supports HFAs that similarly require multiple registers for
149+ // passing. When multiple registers are required for a single argument they
150+ // must always be allocated into consecutive float registers. However,
151+ // backfilling is allowed. For example, a signature like
152+ // Foo(float x, double y, float z) allocates x in REG_F0 = s0, y in REG_F2 =
153+ // d1, z in REG_F1 = s1.
154+ //
155+ ABIPassingInformation Arm32Classifier::ClassifyFloat (Compiler* comp, var_types type, unsigned numElems)
156+ {
157+ assert ((type == TYP_FLOAT) || (type == TYP_DOUBLE));
158+
159+ unsigned numConsecutive = type == TYP_FLOAT ? numElems : (numElems * 2 );
160+
161+ // Find the first start index that has a consecutive run of
162+ // 'numConsecutive' bits set.
163+ unsigned startRegMask = m_floatRegs;
164+ for (unsigned i = 1 ; i < numConsecutive; i++)
165+ {
166+ startRegMask &= m_floatRegs >> i;
167+ }
168+
169+ // Doubles can only start at even indices.
170+ if (type == TYP_DOUBLE)
171+ {
172+ startRegMask &= 0b0101010101010101 ;
173+ }
174+
175+ if (startRegMask != 0 )
176+ {
177+ unsigned startRegIndex = BitOperations::TrailingZeroCount (startRegMask);
178+ unsigned usedRegsMask = ((1 << numConsecutive) - 1 ) << startRegIndex;
179+ // First consecutive run of numConsecutive bits start at startRegIndex
180+ assert ((m_floatRegs & usedRegsMask) == usedRegsMask);
181+
182+ m_floatRegs ^= usedRegsMask;
183+ ABIPassingInformation info;
184+ info.NumSegments = numElems;
185+ info.Segments = new (comp, CMK_ABI) ABIPassingSegment[numElems];
186+ unsigned numRegsPerElem = type == TYP_FLOAT ? 1 : 2 ;
187+ for (unsigned i = 0 ; i < numElems; i++)
188+ {
189+ regNumber reg = static_cast <regNumber>(static_cast <unsigned >(REG_F0) + startRegIndex + i * numRegsPerElem);
190+ info.Segments [i] = ABIPassingSegment::InRegister (reg, i * genTypeSize (type), genTypeSize (type));
191+ }
192+
193+ return info;
194+ }
195+ else
196+ {
197+ // As soon as any float arg goes on stack no other float arg can go in a register.
198+ m_floatRegs = 0 ;
199+
200+ m_stackArgSize = roundUp (m_stackArgSize, genTypeSize (type));
201+ ABIPassingInformation info =
202+ ABIPassingInformation::FromSegment (comp, ABIPassingSegment::OnStack (m_stackArgSize, 0 ,
203+ numElems * genTypeSize (type)));
204+ m_stackArgSize += numElems * genTypeSize (type);
205+
206+ return info;
207+ }
208+ }
209+
29210#endif // TARGET_ARM
0 commit comments