14
14
15
15
#include " ../IR/MissingFeatures.h"
16
16
#include " LoweringPrepareItaniumCXXABI.h"
17
+ #include " clang/AST/CharUnits.h"
17
18
#include " clang/CIR/Dialect/IR/CIRTypes.h"
18
19
19
20
#include < assert.h>
@@ -67,6 +68,8 @@ LoweringPrepareAArch64CXXABI::lowerAAPCSVAArg(cir::CIRBaseBuilderTy &builder,
67
68
assert (!cir::MissingFeatures::classifyArgumentTypeForAArch64 ());
68
69
// indirect arg passing would expect one more level of pointer dereference.
69
70
assert (!cir::MissingFeatures::handleAArch64Indirect ());
71
+ // false as a place holder for now, as we don't have a way to query
72
+ bool isIndirect = false ;
70
73
assert (!cir::MissingFeatures::supportgetCoerceToTypeForAArch64 ());
71
74
// we don't convert to LLVM Type here as we are lowering to CIR here.
72
75
// so baseTy is the just type of the result of va_arg.
@@ -82,7 +85,7 @@ LoweringPrepareAArch64CXXABI::lowerAAPCSVAArg(cir::CIRBaseBuilderTy &builder,
82
85
if (Kind == AArch64ABIKind::AAPCSSoft) {
83
86
llvm_unreachable (" AAPCSSoft cir.var_arg lowering NYI" );
84
87
}
85
- bool IsFPR = mlir::cir::isAnyFloatingPointType (opResTy );
88
+ bool IsFPR = mlir::cir::isAnyFloatingPointType (baseTy );
86
89
87
90
// The AArch64 va_list type and handling is specified in the Procedure Call
88
91
// Standard, section B.4:
@@ -111,13 +114,19 @@ LoweringPrepareAArch64CXXABI::lowerAAPCSVAArg(cir::CIRBaseBuilderTy &builder,
111
114
// though anyone passing 2GB of arguments, each at most 16 bytes, deserves
112
115
// whatever they get).
113
116
114
- assert (!cir::MissingFeatures::handleAArch64Indirect ());
115
117
assert (!cir::MissingFeatures::supportTySizeQueryForAArch64 ());
116
118
assert (!cir::MissingFeatures::supportTyAlignQueryForAArch64 ());
119
+ // One is just place holder for now, as we don't have a way to query
120
+ // type size and alignment.
121
+ clang::CharUnits tySize = clang::CharUnits::One ();
122
+ clang::CharUnits tyAlign = clang::CharUnits::One ();
123
+ ;
124
+
117
125
// indirectness, type size and type alignment all
118
126
// decide regSize, but they are all ABI defined
119
127
// thus need ABI lowering query system.
120
- int regSize = 8 ;
128
+ assert (!cir::MissingFeatures::handleAArch64Indirect ());
129
+ int regSize = isIndirect ? 8 : tySize.getQuantity ();
121
130
int regTopIndex;
122
131
mlir::Value regOffsP;
123
132
mlir::cir::LoadOp regOffs;
@@ -160,9 +169,10 @@ LoweringPrepareAArch64CXXABI::lowerAAPCSVAArg(cir::CIRBaseBuilderTy &builder,
160
169
// Integer arguments may need to correct register alignment (for example a
161
170
// "struct { __int128 a; };" gets passed in x_2N, x_{2N+1}). In this case we
162
171
// align __gr_offs to calculate the potential address.
163
- if (!IsFPR) {
172
+ if (!IsFPR && !isIndirect && tyAlign. getQuantity () > 8 ) {
164
173
assert (!cir::MissingFeatures::handleAArch64Indirect ());
165
174
assert (!cir::MissingFeatures::supportTyAlignQueryForAArch64 ());
175
+ llvm_unreachable (" register alignment correction NYI" );
166
176
}
167
177
168
178
// Update the gr_offs/vr_offs pointer for next call to va_arg on this va_list.
@@ -193,6 +203,49 @@ LoweringPrepareAArch64CXXABI::lowerAAPCSVAArg(cir::CIRBaseBuilderTy &builder,
193
203
auto i8Ty = mlir::IntegerType::get (builder.getContext (), 8 );
194
204
auto i8PtrTy = mlir::cir::PointerType::get (builder.getContext (), i8Ty);
195
205
auto castRegTop = builder.createBitcast (regTop, i8PtrTy);
206
+ auto resAsInt8P = builder.create <mlir::cir::PtrStrideOp>(
207
+ loc, castRegTop.getType (), castRegTop, regOffs);
208
+
209
+ if (isIndirect) {
210
+ assert (!cir::MissingFeatures::handleAArch64Indirect ());
211
+ llvm_unreachable (" indirect arg passing NYI" );
212
+ }
213
+
214
+ // TODO: isHFA, numMembers and base should be query result from query
215
+ uint64_t numMembers = 0 ;
216
+ assert (!cir::MissingFeatures::supportisHomogeneousAggregateQueryForAArch64 ());
217
+ bool isHFA = false ;
218
+ assert (!cir::MissingFeatures::supportisEndianQueryForAArch64 ());
219
+ // TODO: endianess should be query result from ABI info
220
+ bool isBigEndian = false ;
221
+ assert (!cir::MissingFeatures::supportisAggregateTypeForABIAArch64 ());
222
+ // TODO: isAggregateTypeForABI should be query result from ABI info
223
+ bool isAggregateTypeForABI = false ;
224
+ if (isHFA && numMembers > 1 ) {
225
+ // Homogeneous aggregates passed in registers will have their elements split
226
+ // and stored 16-bytes apart regardless of size (they're notionally in qN,
227
+ // qN+1, ...). We reload and store into a temporary local variable
228
+ // contiguously.
229
+ assert (!isIndirect && " Homogeneous aggregates should be passed directly" );
230
+ llvm_unreachable (" Homogeneous aggregates NYI" );
231
+ } else {
232
+ assert (!cir::MissingFeatures::supportTyAlignQueryForAArch64 ());
233
+ // TODO: slotSize should be query result about alignment.
234
+ clang::CharUnits slotSize = clang::CharUnits::fromQuantity (8 );
235
+ if (isBigEndian && !isIndirect && (isHFA || isAggregateTypeForABI) &&
236
+ tySize < slotSize) {
237
+ clang::CharUnits offset = slotSize - tySize;
238
+ auto offsetConst = builder.create <mlir::cir::ConstantOp>(
239
+ loc, regOffs.getType (),
240
+ mlir::cir::IntAttr::get (regOffs.getType (), offset.getQuantity ()));
241
+
242
+ resAsInt8P = builder.create <mlir::cir::PtrStrideOp>(
243
+ loc, castRegTop.getType (), resAsInt8P, offsetConst);
244
+ }
245
+ }
246
+
247
+ auto resAsVoidP = builder.createBitcast (resAsInt8P, regTop.getType ());
248
+
196
249
// On big-endian platforms, the value will be right-aligned in its stack slot.
197
250
// and we also need to think about other ABI lowering concerns listed below.
198
251
assert (!cir::MissingFeatures::handleBigEndian ());
@@ -201,9 +254,6 @@ LoweringPrepareAArch64CXXABI::lowerAAPCSVAArg(cir::CIRBaseBuilderTy &builder,
201
254
assert (!cir::MissingFeatures::supportTySizeQueryForAArch64 ());
202
255
assert (!cir::MissingFeatures::supportTyAlignQueryForAArch64 ());
203
256
204
- auto resAsInt8P = builder.create <mlir::cir::PtrStrideOp>(
205
- loc, castRegTop.getType (), castRegTop, regOffs);
206
- auto resAsVoidP = builder.createBitcast (resAsInt8P, regTop.getType ());
207
257
builder.create <mlir::cir::BrOp>(loc, mlir::ValueRange{resAsVoidP}, contBlock);
208
258
209
259
// =======================================
@@ -216,25 +266,57 @@ LoweringPrepareAArch64CXXABI::lowerAAPCSVAArg(cir::CIRBaseBuilderTy &builder,
216
266
auto ptrDiffTy =
217
267
mlir::cir::IntType::get (builder.getContext (), 64 , /* signed=*/ false );
218
268
269
+ assert (!cir::MissingFeatures::handleAArch64Indirect ());
270
+ assert (!cir::MissingFeatures::supportTyAlignQueryForAArch64 ());
271
+ // Again, stack arguments may need realignment. In this case both integer and
272
+ // floating-point ones might be affected.
273
+ if (!isIndirect && tyAlign.getQuantity () > 8 ) {
274
+ // TODO: this algorithm requres casting from ptr type to int type, then
275
+ // back to ptr type thus needs careful handling. NYI now.
276
+ llvm_unreachable (" alignment greater than 8 NYI" );
277
+ }
278
+
279
+ // All stack slots are multiples of 8 bytes.
280
+ clang::CharUnits stackSlotSize = clang::CharUnits::fromQuantity (8 );
281
+ clang::CharUnits stackSize;
282
+ if (isIndirect)
283
+ stackSize = stackSlotSize;
284
+ else
285
+ stackSize = tySize.alignTo (stackSlotSize);
286
+
219
287
// On big-endian platforms, the value will be right-aligned in its stack slot
220
288
// Also, the consideration involves type size and alignment, arg indirectness
221
289
// which are all ABI defined thus need ABI lowering query system.
222
290
// The implementation we have now supports most common cases which assumes
223
291
// no indirectness, no alignment greater than 8, and little endian.
224
292
assert (!cir::MissingFeatures::handleBigEndian ());
225
- assert (!cir::MissingFeatures::handleAArch64Indirect ());
226
- assert (!cir::MissingFeatures::supportTyAlignQueryForAArch64 ());
227
293
assert (!cir::MissingFeatures::supportTySizeQueryForAArch64 ());
228
294
229
- auto eight = builder.create <mlir::cir::ConstantOp>(
230
- loc, ptrDiffTy, mlir::cir::IntAttr::get (ptrDiffTy, 8 ));
295
+ auto stackSizeC = builder.create <mlir::cir::ConstantOp>(
296
+ loc, ptrDiffTy,
297
+ mlir::cir::IntAttr::get (ptrDiffTy, stackSize.getQuantity ()));
231
298
auto castStack = builder.createBitcast (onStackPtr, i8PtrTy);
232
299
// Write the new value of __stack for the next call to va_arg
233
300
auto newStackAsi8Ptr = builder.create <mlir::cir::PtrStrideOp>(
234
- loc, castStack.getType (), castStack, eight );
301
+ loc, castStack.getType (), castStack, stackSizeC );
235
302
auto newStack = builder.createBitcast (newStackAsi8Ptr, onStackPtr.getType ());
236
303
builder.createStore (loc, newStack, stackP);
237
- builder.create <mlir::cir::BrOp>(loc, mlir::ValueRange{onStackPtr}, contBlock);
304
+
305
+ if (isBigEndian && !isAggregateTypeForABI && tySize < stackSlotSize) {
306
+ clang::CharUnits offset = stackSlotSize - tySize;
307
+ auto offsetConst = builder.create <mlir::cir::ConstantOp>(
308
+ loc, ptrDiffTy,
309
+ mlir::cir::IntAttr::get (ptrDiffTy, offset.getQuantity ()));
310
+ auto offsetStackAsi8Ptr = builder.create <mlir::cir::PtrStrideOp>(
311
+ loc, castStack.getType (), castStack, offsetConst);
312
+ auto onStackPtrBE =
313
+ builder.createBitcast (offsetStackAsi8Ptr, onStackPtr.getType ());
314
+ builder.create <mlir::cir::BrOp>(loc, mlir::ValueRange{onStackPtrBE},
315
+ contBlock);
316
+ } else {
317
+ builder.create <mlir::cir::BrOp>(loc, mlir::ValueRange{onStackPtr},
318
+ contBlock);
319
+ }
238
320
239
321
// generate additional instructions for end block
240
322
builder.setInsertionPoint (op);
@@ -246,6 +328,9 @@ LoweringPrepareAArch64CXXABI::lowerAAPCSVAArg(cir::CIRBaseBuilderTy &builder,
246
328
auto res = builder.create <mlir::cir::LoadOp>(loc, castResP);
247
329
// there would be another level of ptr dereference if indirect arg passing
248
330
assert (!cir::MissingFeatures::handleAArch64Indirect ());
331
+ if (isIndirect) {
332
+ res = builder.create <mlir::cir::LoadOp>(loc, res.getResult ());
333
+ }
249
334
return res.getResult ();
250
335
}
251
336
0 commit comments