@@ -26,4 +26,185 @@ const regMaskTP fltArgMasks[] = {RBM_F0, RBM_F1, RBM_F2, RBM_F3, RBM_F4, RBM_F5,
26
26
27
27
static_assert_no_msg (RBM_ALLDOUBLE == (RBM_ALLDOUBLE_HIGH >> 1 ));
28
28
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
+
29
210
#endif // TARGET_ARM
0 commit comments