Skip to content

Commit d7d993c

Browse files
bruteforceboylanza
authored andcommitted
[CIR][ABI][AArch64][Lowering] Support structures with padding (#1118)
The title describes the purpose of the PR. It adds initial support for structures with padding to the call convention lowering for AArch64. I have also _initial support_ for the missing feature [FinishLayout](https://github.com/llvm/clangir/blob/5c5d58402bebdb1e851fb055f746662d4e7eb586/clang/lib/AST/RecordLayoutBuilder.cpp#L786) for records, and the logic is gotten from the original codegen. Finally, I added a test for verification.
1 parent ef73619 commit d7d993c

File tree

4 files changed

+92
-13
lines changed

4 files changed

+92
-13
lines changed

clang/include/clang/CIR/MissingFeatures.h

-3
Original file line numberDiff line numberDiff line change
@@ -404,9 +404,6 @@ struct MissingFeatures {
404404
// specs. We should make it always present.
405405
static bool makeTripleAlwaysPresent() { return false; }
406406

407-
// This Itanium bit is currently being skipped in cir.
408-
static bool itaniumRecordLayoutBuilderFinishLayout() { return false; }
409-
410407
static bool mustProgress() { return false; }
411408

412409
static bool skipTempCopy() { return false; }

clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerFunction.cpp

+27-1
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,31 @@ mlir::Value emitAddressAtOffset(LowerFunction &LF, mlir::Value addr,
347347
return addr;
348348
}
349349

350+
/// Creates a coerced value from \param src having a type of \param ty which is
351+
/// a non primitive type
352+
mlir::Value createCoercedNonPrimitive(mlir::Value src, mlir::Type ty,
353+
LowerFunction &LF) {
354+
if (auto load = mlir::dyn_cast<LoadOp>(src.getDefiningOp())) {
355+
auto &bld = LF.getRewriter();
356+
auto addr = load.getAddr();
357+
358+
auto oldAlloca = mlir::dyn_cast<AllocaOp>(addr.getDefiningOp());
359+
auto alloca = bld.create<AllocaOp>(
360+
src.getLoc(), bld.getType<PointerType>(ty), ty,
361+
/*name=*/llvm::StringRef(""), oldAlloca.getAlignmentAttr());
362+
363+
auto tySize = LF.LM.getDataLayout().getTypeStoreSize(ty);
364+
createMemCpy(LF, alloca, addr, tySize.getFixedValue());
365+
366+
auto newLoad = bld.create<LoadOp>(src.getLoc(), alloca.getResult());
367+
bld.replaceAllOpUsesWith(load, newLoad);
368+
369+
return newLoad;
370+
}
371+
372+
cir_cconv_unreachable("NYI");
373+
}
374+
350375
/// After the calling convention is lowered, an ABI-agnostic type might have to
351376
/// be loaded back to its ABI-aware couterpart so it may be returned. If they
352377
/// differ, we have to do a coerced load. A coerced load, which means to load a
@@ -370,7 +395,8 @@ mlir::Value castReturnValue(mlir::Value Src, mlir::Type Ty, LowerFunction &LF) {
370395

371396
auto intTy = mlir::dyn_cast<IntType>(Ty);
372397
if (intTy && !intTy.isPrimitive())
373-
cir_cconv_unreachable("non-primitive types NYI");
398+
return createCoercedNonPrimitive(Src, Ty, LF);
399+
374400
llvm::TypeSize DstSize = LF.LM.getDataLayout().getTypeAllocSize(Ty);
375401

376402
// FIXME(cir): Do we need the EnterStructPointerForCoercedAccess routine here?

clang/lib/CIR/Dialect/Transforms/TargetLowering/RecordLayoutBuilder.cpp

+35-8
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,9 @@ class ItaniumRecordLayoutBuilder {
223223
/// Initialize record layout for the given record decl.
224224
void initializeLayout(const Type Ty);
225225

226+
/// Finalize record layout. Adjust record size based on the alignment.
227+
void finishLayout(const StructType D);
228+
226229
uint64_t getDataSizeInBits() const { return DataSize; }
227230

228231
void setDataSize(clang::CharUnits NewSize) {
@@ -243,8 +246,7 @@ void ItaniumRecordLayoutBuilder::layout(const StructType RT) {
243246
// FIXME(cir): Handle virtual-related layouts.
244247
cir_cconv_assert(!cir::MissingFeatures::getCXXRecordBases());
245248

246-
cir_cconv_assert(
247-
!cir::MissingFeatures::itaniumRecordLayoutBuilderFinishLayout());
249+
finishLayout(RT);
248250
}
249251

250252
void ItaniumRecordLayoutBuilder::initializeLayout(const mlir::Type Ty) {
@@ -478,6 +480,31 @@ void ItaniumRecordLayoutBuilder::layoutFields(const StructType D) {
478480
}
479481
}
480482

483+
void ItaniumRecordLayoutBuilder::finishLayout(const StructType D) {
484+
// If we have any remaining field tail padding, include that in the overall
485+
// size.
486+
setSize(std::max(getSizeInBits(), (uint64_t)Context.toBits(PaddedFieldSize)));
487+
488+
// Finally, round the size of the record up to the alignment of the
489+
// record itself.
490+
uint64_t unpaddedSize = getSizeInBits() - UnfilledBitsInLastUnit;
491+
uint64_t unpackedSizeInBits =
492+
llvm::alignTo(getSizeInBits(), Context.toBits(UnpackedAlignment));
493+
494+
uint64_t roundedSize = llvm::alignTo(
495+
getSizeInBits(),
496+
Context.toBits(!Context.getTargetInfo().defaultsToAIXPowerAlignment()
497+
? Alignment
498+
: PreferredAlignment));
499+
500+
if (UseExternalLayout) {
501+
cir_cconv_unreachable("NYI");
502+
}
503+
504+
// Set the size to the final size.
505+
setSize(roundedSize);
506+
}
507+
481508
void ItaniumRecordLayoutBuilder::UpdateAlignment(
482509
clang::CharUnits NewAlignment, clang::CharUnits UnpackedNewAlignment,
483510
clang::CharUnits PreferredNewAlignment) {
@@ -521,13 +548,13 @@ void ItaniumRecordLayoutBuilder::checkFieldPadding(
521548

522549
// Warn if padding was introduced to the struct/class.
523550
if (!IsUnion && Offset > UnpaddedOffset) {
524-
unsigned PadSize = Offset - UnpaddedOffset;
525-
// bool InBits = true;
526-
if (PadSize % CharBitNum == 0) {
527-
PadSize = PadSize / CharBitNum;
528-
// InBits = false;
551+
unsigned padSize = Offset - UnpaddedOffset;
552+
bool inBits = true;
553+
if (padSize % CharBitNum == 0) {
554+
padSize = padSize / CharBitNum;
555+
inBits = false;
529556
}
530-
cir_cconv_assert(cir::MissingFeatures::bitFieldPaddingDiagnostics());
557+
cir_cconv_assert(!cir::MissingFeatures::bitFieldPaddingDiagnostics());
531558
}
532559
if (isPacked && Offset != UnpackedOffset) {
533560
HasPackedField = true;

clang/test/CIR/CallConvLowering/AArch64/aarch64-cc-structs.c

+30-1
Original file line numberDiff line numberDiff line change
@@ -204,4 +204,33 @@ GT_128 call_and_get_gt_128() {
204204
// LLVM: %[[#V2:]] = alloca [2 x i64], i64 1, align 8
205205
// LLVM: store [2 x i64] %[[#ARG]], ptr %[[#V2]], align 8
206206
// LLVM: call void @llvm.memcpy.p0.p0.i64(ptr %[[#V1]], ptr %[[#V2]], i64 12, i1 false)
207-
void passS(S s) {}
207+
void passS(S s) {}
208+
209+
typedef struct {
210+
uint8_t a;
211+
uint16_t b;
212+
uint8_t c;
213+
} S_PAD;
214+
215+
// CHECK: cir.func {{.*@ret_s_pad}}() -> !u48i
216+
// CHECK: %[[#V0:]] = cir.alloca !ty_S_PAD, !cir.ptr<!ty_S_PAD>, ["__retval"] {alignment = 2 : i64}
217+
// CHECK: %[[#V1:]] = cir.load %[[#V0]] : !cir.ptr<!ty_S_PAD>, !ty_S_PAD
218+
// CHECK: %[[#V2:]] = cir.alloca !u48i, !cir.ptr<!u48i>, [""] {alignment = 2 : i64}
219+
// CHECK: %[[#V3:]] = cir.cast(bitcast, %[[#V0]] : !cir.ptr<!ty_S_PAD>)
220+
// CHECK: %[[#V4:]] = cir.cast(bitcast, %[[#V2:]] : !cir.ptr<!u48i>), !cir.ptr<!void>
221+
// CHECK: %[[#V5:]] = cir.const #cir.int<6> : !u64i
222+
// CHECK: cir.libc.memcpy %[[#V5]] bytes from %[[#V3]] to %[[#V4]] : !u64i, !cir.ptr<!void>
223+
// CHECK: %[[#V6:]] = cir.load %[[#V2]] : !cir.ptr<!u48i>
224+
// CHECK: cir.return %[[#V6]]
225+
226+
// LLVM: i48 @ret_s_pad()
227+
// LLVM: %[[#V1:]] = alloca %struct.S_PAD, i64 1, align 2
228+
// LLVM: %[[#V2:]] = load %struct.S_PAD, ptr %[[#V1]], align 2
229+
// LLVM: %[[#V3:]] = alloca i48, i64 1, align 2
230+
// LLVM: call void @llvm.memcpy.p0.p0.i64(ptr %[[#V3]], ptr %[[#V1]], i64 6, i1 false)
231+
// LLVM: %[[#V4:]] = load i48, ptr %[[#V3]]
232+
// LLVM: ret i48 %[[#V4]]
233+
S_PAD ret_s_pad() {
234+
S_PAD s;
235+
return s;
236+
}

0 commit comments

Comments
 (0)