Skip to content

Commit a37de7e

Browse files
andykaylorlanza
authored andcommitted
[CIR] Add code to detect non-zero-initializable records (llvm#1603)
There are some cases where we're currently using the zero attribute to initialize global variables for records that aren't properly zero-initializable. We weren't checking for that, and we also weren't properly calculating zero-initializability for records. This patch addresses both of these issues. This doesn't actually handle the case where the record isn't zero-initializable. It just reports it as NYI. It does add a comment about what needs to be done.
1 parent 13e8c78 commit a37de7e

File tree

3 files changed

+59
-2
lines changed

3 files changed

+59
-2
lines changed

clang/lib/CIR/CodeGen/CIRGenExprConst.cpp

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1718,17 +1718,33 @@ mlir::Attribute ConstantEmitter::tryEmitPrivateForVarInit(const VarDecl &D) {
17181718
// initialization of memory to all NULLs.
17191719
if (!D.hasLocalStorage()) {
17201720
QualType Ty = CGM.getASTContext().getBaseElementType(D.getType());
1721-
if (Ty->isRecordType())
1721+
if (Ty->isRecordType()) {
17221722
if (const CXXConstructExpr *E =
17231723
dyn_cast_or_null<CXXConstructExpr>(D.getInit())) {
17241724
const CXXConstructorDecl *CD = E->getConstructor();
17251725
// FIXME: we should probably model this more closely to C++ than
17261726
// just emitting a global with zero init (mimic what we do for trivial
17271727
// assignments and whatnots). Since this is for globals shouldn't
17281728
// be a problem for the near future.
1729-
if (CD->isTrivial() && CD->isDefaultConstructor())
1729+
if (CD->isTrivial() && CD->isDefaultConstructor()) {
1730+
const auto *cxxrd =
1731+
cast<CXXRecordDecl>(Ty->getAs<RecordType>()->getDecl());
1732+
// Some cases, such as member pointer members, can't be zero
1733+
// initialized. These are "zero-initialized" in the language standard
1734+
// sense, but the target ABI may require that a literal value other
1735+
// than zero be used in the initializer to make clear that a pointer
1736+
// with the value zero is not what is intended. The classic codegen
1737+
// goes through emitNullConstant for those cases but generates a
1738+
// non-zero constant. We can't quite do that here because we need an
1739+
// attribute and not a value, but something like that can be
1740+
// implemented.
1741+
if (!CGM.getTypes().isZeroInitializable(cxxrd)) {
1742+
llvm_unreachable("NYI");
1743+
}
17301744
return cir::ZeroAttr::get(CGM.convertType(D.getType()));
1745+
}
17311746
}
1747+
}
17321748
}
17331749
InConstantContext = D.hasConstantInitialization();
17341750

clang/lib/CIR/CodeGen/CIRRecordLayoutBuilder.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,7 @@ void CIRRecordLowering::lower(bool nonVirtualBaseType) {
300300
insertPadding();
301301
members.pop_back();
302302

303+
calculateZeroInit();
303304
fillOutputFields();
304305
computeVolatileBitfields();
305306
}
@@ -628,6 +629,24 @@ void CIRRecordLowering::accumulateFields() {
628629
}
629630
}
630631

632+
void CIRRecordLowering::calculateZeroInit() {
633+
for (const MemberInfo &member : members) {
634+
if (member.kind == MemberInfo::InfoKind::Field) {
635+
if (!member.fieldDecl || isZeroInitializable(member.fieldDecl))
636+
continue;
637+
IsZeroInitializable = IsZeroInitializableAsBase = false;
638+
return;
639+
} else if (member.kind == MemberInfo::InfoKind::Base ||
640+
member.kind == MemberInfo::InfoKind::VBase) {
641+
if (isZeroInitializable(member.cxxRecordDecl))
642+
continue;
643+
IsZeroInitializable = false;
644+
if (member.kind == MemberInfo::InfoKind::Base)
645+
IsZeroInitializableAsBase = false;
646+
}
647+
}
648+
}
649+
631650
void CIRRecordLowering::determinePacked(bool NVBaseType) {
632651
if (isPacked)
633652
return;
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
2+
// RUN: FileCheck --input-file=%t.cir %s
3+
4+
// This case is not yet implemented.
5+
// XFAIL: *
6+
7+
struct Other {
8+
int x;
9+
};
10+
11+
struct Trivial {
12+
int x;
13+
double y;
14+
decltype(&Other::x) ptr;
15+
};
16+
17+
// This case has a trivial default constructor, but can't be zero-initialized.
18+
Trivial t;
19+
20+
// The type is wrong on the last member here. It needs to be initialized to -1,
21+
// but I don't know what that will look like.
22+
// CHECK: cir.global {{.*}} @t = #cir.const_record<{#cir.int<0> : !s32i, #cir.fp<0.000000e+00> : !cir.double, #cir.int<-1> : !s64i}>

0 commit comments

Comments
 (0)