[CIR] Implement non-odr use of reference type lowering (#185720)

This is used somewhat rarely, but is a pretty simple emission of
pointers, and ends up using infrastructure we already have.
Additionally, this is the first use of `getNaturalTypeAlignment` that
uses the `pointee` argument, so this adds the implementation there,
which includes some alignment work for CXXRecordDecls, so this
implements that as well.
This commit is contained in:
Erich Keane 2026-03-11 06:26:13 -07:00 committed by GitHub
parent 1ea11e4262
commit 8a25f9534a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 56 additions and 6 deletions

View File

@ -206,7 +206,6 @@ struct MissingFeatures {
static bool aggValueSlotGC() { return false; }
static bool aggValueSlotMayOverlap() { return false; }
static bool aggValueSlotVolatile() { return false; }
static bool alignCXXRecordDecl() { return false; }
static bool allocToken() { return false; }
static bool appleArm64CXXABI() { return false; }
static bool appleKext() { return false; }

View File

@ -902,8 +902,17 @@ LValue CIRGenFunction::emitDeclRefLValue(const DeclRefExpr *e) {
addr = addr.withElementType(builder, varTy);
}
} else {
cgm.errorNYI(e->getSourceRange(),
"emitDeclRefLValue: non-odr reference type");
// Should we be using the alignment of the constant pointer we emitted?
CharUnits alignment =
cgm.getNaturalTypeAlignment(e->getType(),
/*BaseInfo=*/nullptr,
/*forPointeeType=*/true);
// Classic codegen passes TBAA as null-ptr to the above function, so it
// probably needs to deal with that.
assert(!cir::MissingFeatures::opTBAA());
mlir::Value ptrVal = getBuilder().getConstant(
getLoc(e->getSourceRange()), mlir::cast<mlir::TypedAttr>(val));
addr = makeNaturalAddressForPointer(ptrVal, ty, alignment);
}
return makeAddrLValue(addr, ty, AlignmentSource::Decl);
}

View File

@ -176,7 +176,8 @@ CharUnits CIRGenModule::getClassPointerAlignment(const CXXRecordDecl *rd) {
}
CharUnits CIRGenModule::getNaturalTypeAlignment(QualType t,
LValueBaseInfo *baseInfo) {
LValueBaseInfo *baseInfo,
bool forPointeeType) {
assert(!cir::MissingFeatures::opTBAA());
// FIXME: This duplicates logic in ASTContext::getTypeAlignIfKnown, but
@ -193,6 +194,8 @@ CharUnits CIRGenModule::getNaturalTypeAlignment(QualType t,
}
}
bool alignForArray = t->isArrayType();
// Analyze the base element type, so we don't get confused by incomplete
// array types.
t = astContext.getBaseElementType(t);
@ -213,10 +216,13 @@ CharUnits CIRGenModule::getNaturalTypeAlignment(QualType t,
*baseInfo = LValueBaseInfo(AlignmentSource::Type);
CharUnits alignment;
const CXXRecordDecl *rd = nullptr;
if (t.getQualifiers().hasUnaligned()) {
alignment = CharUnits::One();
} else if (forPointeeType && !alignForArray &&
(rd = t->getAsCXXRecordDecl())) {
alignment = getClassPointerAlignment(rd);
} else {
assert(!cir::MissingFeatures::alignCXXRecordDecl());
alignment = astContext.getTypeAlignInChars(t);
}

View File

@ -396,7 +396,8 @@ public:
/// FIXME: this could likely be a common helper and not necessarily related
/// with codegen.
clang::CharUnits getNaturalTypeAlignment(clang::QualType t,
LValueBaseInfo *baseInfo = nullptr);
LValueBaseInfo *baseInfo = nullptr,
bool forPointeeType = false);
/// Returns the minimum object size for an object of the given class type
/// (or a class derived from it).

View File

@ -0,0 +1,35 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll
// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM
static int a[10]{};
// CIR: cir.global "private" internal dso_local @_ZL1a = #cir.zero : !cir.array<!s32i x 10> {alignment = 16 : i64}
// LLVM: @_ZL1a = internal global [10 x i32] zeroinitializer, align 16
struct NonTrivialDestructor {
~NonTrivialDestructor();
};
struct BiggerNonTrivialDestructor {
int array[12];
~BiggerNonTrivialDestructor();
};
void use() {
for (int i : a) {}
// This happens 3x (range + begin + end), but they all use the same code, sox
// only test it 1x. Ensure the alignment is correct.
// CIR: %[[GLOBAL_A:.*]] = cir.const #cir.global_view<@_ZL1a> : !cir.ptr<!cir.array<!s32i x 10>>
// CIR: cir.store align(8) %[[GLOBAL_A]], %{{.*}} : !cir.ptr<!cir.array<!s32i x 10>>, !cir.ptr<!cir.ptr<!cir.array<!s32i x 10>>>
// LLVM: store ptr getelementptr inbounds nuw (i8, ptr @_ZL1a, i64 40), ptr %{{.*}}, align 8
// Make sure we get alignment correct here.
NonTrivialDestructor a;
// CIR-DAG: cir.call @_ZN20NonTrivialDestructorD1Ev{{.*}}llvm.align = 1
// LLVM-DAG: call void @_ZN20NonTrivialDestructorD1Ev(ptr {{.*}}align 1
BiggerNonTrivialDestructor b;
// CIR-DAG: cir.call @_ZN26BiggerNonTrivialDestructorD1Ev{{.*}}llvm.align = 4
// LLVM-DAG: call void @_ZN26BiggerNonTrivialDestructorD1Ev(ptr {{.*}}align 4
}