Skip to content

Commit a160ec9

Browse files
committed
Add check for base class and test for unions
1 parent 483efe5 commit a160ec9

File tree

4 files changed

+119
-8
lines changed

4 files changed

+119
-8
lines changed

clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "CIRGenConstantEmitter.h"
1515
#include "CIRGenFunction.h"
1616
#include "CIRGenModule.h"
17+
#include "CIRGenRecordLayout.h"
1718
#include "mlir/IR/Attributes.h"
1819
#include "mlir/IR/BuiltinAttributeInterfaces.h"
1920
#include "mlir/IR/BuiltinAttributes.h"
@@ -364,17 +365,29 @@ mlir::Attribute ConstantEmitter::tryEmitPrivateForVarInit(const VarDecl &d) {
364365
// initialization of memory to all NULLs.
365366
if (!d.hasLocalStorage()) {
366367
QualType ty = cgm.getASTContext().getBaseElementType(d.getType());
367-
if (ty->isRecordType())
368-
if (const CXXConstructExpr *e =
369-
dyn_cast_or_null<CXXConstructExpr>(d.getInit())) {
368+
if (ty->isRecordType()) {
369+
if (const auto *e = dyn_cast_or_null<CXXConstructExpr>(d.getInit())) {
370370
const CXXConstructorDecl *cd = e->getConstructor();
371371
// FIXME: we should probably model this more closely to C++ than
372372
// just emitting a global with zero init (mimic what we do for trivial
373373
// assignments and whatnots). Since this is for globals shouldn't
374374
// be a problem for the near future.
375-
if (cd->isTrivial() && cd->isDefaultConstructor())
375+
if (cd->isTrivial() && cd->isDefaultConstructor()) {
376+
const auto *cxxrd =
377+
cast<CXXRecordDecl>(ty->getAs<RecordType>()->getDecl());
378+
if (cxxrd->getNumBases() != 0) {
379+
// There may not be anything additional to do here, but this will
380+
// force us to pause and test this path when it is supported.
381+
cgm.errorNYI("tryEmitPrivateForVarInit: cxx record with bases");
382+
return {};
383+
}
384+
assert(cgm.getTypes()
385+
.getCIRGenRecordLayout(cxxrd)
386+
.isZeroInitializable());
376387
return cir::ZeroAttr::get(cgm.convertType(d.getType()));
388+
}
377389
}
390+
}
378391
}
379392
inConstantContext = d.hasConstantInitialization();
380393

clang/lib/CIR/CodeGen/CIRGenRecordLayout.h

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,23 @@ class CIRGenRecordLayout {
3333
/// field no. This info is populated by the record builder.
3434
llvm::DenseMap<const clang::FieldDecl *, unsigned> fieldIdxMap;
3535

36+
/// False if any direct or indirect subobject of this class, when considered
37+
/// as a complete object, requires a non-zero bitpattern when
38+
/// zero-initialized.
39+
LLVM_PREFERRED_TYPE(bool)
40+
unsigned zeroInitializable : 1;
41+
42+
/// False if any direct or indirect subobject of this class, when considered
43+
/// as a base subobject, requires a non-zero bitpattern when zero-initialized.
44+
LLVM_PREFERRED_TYPE(bool)
45+
unsigned zeroInitializableAsBase : 1;
46+
3647
public:
37-
CIRGenRecordLayout(cir::RecordType completeObjectType)
38-
: completeObjectType(completeObjectType) {}
48+
CIRGenRecordLayout(cir::RecordType completeObjectType, bool zeroInitializable,
49+
bool zeroInitializableAsBase)
50+
: completeObjectType(completeObjectType),
51+
zeroInitializable(zeroInitializable),
52+
zeroInitializableAsBase(zeroInitializableAsBase) {}
3953

4054
/// Return the "complete object" LLVM type associated with
4155
/// this record.
@@ -47,6 +61,14 @@ class CIRGenRecordLayout {
4761
assert(fieldIdxMap.count(fd) && "Invalid field for record!");
4862
return fieldIdxMap.lookup(fd);
4963
}
64+
65+
/// Check whether this struct can be C++ zero-initialized
66+
/// with a zeroinitializer.
67+
bool isZeroInitializable() const { return zeroInitializable; }
68+
69+
/// Check whether this struct can be C++ zero-initialized
70+
/// with a zeroinitializer when considered as a base subobject.
71+
bool isZeroInitializableAsBase() const { return zeroInitializableAsBase; }
5072
};
5173

5274
} // namespace clang::CIRGen

clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ struct CIRRecordLowering final {
7777
return astContext.toCharUnitsFromBits(bitOffset);
7878
}
7979

80+
void calculateZeroInit();
81+
8082
CharUnits getSize(mlir::Type Ty) {
8183
return CharUnits::fromQuantity(dataLayout.layout.getTypeSize(Ty));
8284
}
@@ -183,7 +185,7 @@ void CIRRecordLowering::lower() {
183185

184186
accumulateFields();
185187

186-
if (auto const *cxxRecordDecl = dyn_cast<CXXRecordDecl>(recordDecl)) {
188+
if (const auto *cxxRecordDecl = dyn_cast<CXXRecordDecl>(recordDecl)) {
187189
if (cxxRecordDecl->getNumBases() > 0) {
188190
CIRGenModule &cgm = cirGenTypes.getCGModule();
189191
cgm.errorNYI(recordDecl->getSourceRange(),
@@ -244,6 +246,19 @@ void CIRRecordLowering::accumulateFields() {
244246
}
245247
}
246248

249+
void CIRRecordLowering::calculateZeroInit() {
250+
for (const MemberInfo &member : members) {
251+
if (member.kind == MemberInfo::InfoKind::Field) {
252+
if (!member.fieldDecl || isZeroInitializable(member.fieldDecl))
253+
continue;
254+
zeroInitializable = zeroInitializableAsBase = false;
255+
return;
256+
}
257+
// TODO(cir): handle base types
258+
assert(!cir::MissingFeatures::cxxSupport());
259+
}
260+
}
261+
247262
void CIRRecordLowering::determinePacked() {
248263
if (packed)
249264
return;
@@ -315,7 +330,9 @@ CIRGenTypes::computeRecordLayout(const RecordDecl *rd, cir::RecordType *ty) {
315330
assert(!cir::MissingFeatures::astRecordDeclAttr());
316331
ty->complete(lowering.fieldTypes, lowering.packed, lowering.padded);
317332

318-
auto rl = std::make_unique<CIRGenRecordLayout>(ty ? *ty : cir::RecordType());
333+
auto rl = std::make_unique<CIRGenRecordLayout>(
334+
ty ? *ty : cir::RecordType(), (bool)lowering.zeroInitializable,
335+
(bool)lowering.zeroInitializableAsBase);
319336

320337
assert(!cir::MissingFeatures::recordZeroInit());
321338
assert(!cir::MissingFeatures::cxxSupport());

clang/test/CIR/CodeGen/union.cpp

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
2+
// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
3+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll
4+
// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s
5+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
6+
// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s
7+
8+
// Should generate a union type with all members preserved.
9+
union U {
10+
bool b;
11+
short s;
12+
int i;
13+
float f;
14+
double d;
15+
};
16+
// CIR: !rec_U = !cir.record<union "U" {!cir.bool, !s16i, !s32i, !cir.float, !cir.double}>
17+
// LLVM: %union.U = type { double }
18+
// OGCG: %union.U = type { double }
19+
20+
void shouldGenerateUnionAccess(union U u) {
21+
u.b = true;
22+
u.b;
23+
u.i = 1;
24+
u.i;
25+
u.f = 0.1F;
26+
u.f;
27+
u.d = 0.1;
28+
u.d;
29+
}
30+
// CIR: cir.func {{.*}}shouldGenerateUnionAccess
31+
// CIR: %[[#BASE:]] = cir.get_member %0[0] {name = "b"} : !cir.ptr<!rec_U> -> !cir.ptr<!cir.bool>
32+
// CIR: cir.store %{{.+}}, %[[#BASE]] : !cir.bool, !cir.ptr<!cir.bool>
33+
// CIR: cir.get_member %0[0] {name = "b"} : !cir.ptr<!rec_U> -> !cir.ptr<!cir.bool>
34+
// CIR: %[[#BASE:]] = cir.get_member %0[2] {name = "i"} : !cir.ptr<!rec_U> -> !cir.ptr<!s32i>
35+
// CIR: cir.store %{{.+}}, %[[#BASE]] : !s32i, !cir.ptr<!s32i>
36+
// CIR: %[[#BASE:]] = cir.get_member %0[2] {name = "i"} : !cir.ptr<!rec_U> -> !cir.ptr<!s32i>
37+
// CIR: %[[#BASE:]] = cir.get_member %0[3] {name = "f"} : !cir.ptr<!rec_U> -> !cir.ptr<!cir.float>
38+
// CIR: cir.store %{{.+}}, %[[#BASE]] : !cir.float, !cir.ptr<!cir.float>
39+
// CIR: %[[#BASE:]] = cir.get_member %0[3] {name = "f"} : !cir.ptr<!rec_U> -> !cir.ptr<!cir.float>
40+
// CIR: %[[#BASE:]] = cir.get_member %0[4] {name = "d"} : !cir.ptr<!rec_U> -> !cir.ptr<!cir.double>
41+
// CIR: cir.store %{{.+}}, %[[#BASE]] : !cir.double, !cir.ptr<!cir.double>
42+
// CIR: %[[#BASE:]] = cir.get_member %0[4] {name = "d"} : !cir.ptr<!rec_U> -> !cir.ptr<!cir.double>
43+
44+
// LLVM: define {{.*}}shouldGenerateUnionAccess
45+
// LLVM: %[[BASE:.*]] = alloca %union.U
46+
// LLVM: store %union.U %{{.*}}, ptr %[[BASE]]
47+
// LLVM: store i8 1, ptr %[[BASE]]
48+
// LLVM: store i32 1, ptr %[[BASE]]
49+
// LLVM: store float 0x3FB99999A0000000, ptr %[[BASE]]
50+
// LLVM: store double 1.000000e-01, ptr %[[BASE]]
51+
52+
// OGCG: define {{.*}}shouldGenerateUnionAccess
53+
// OGCG: %[[BASE:.*]] = alloca %union.U
54+
// OGCG: %[[DIVE:.*]] = getelementptr inbounds nuw %union.U, ptr %[[BASE]], i32 0, i32 0
55+
// OGCG: store i64 %{{.*}}, ptr %[[DIVE]]
56+
// OGCG: store i8 1, ptr %[[BASE]]
57+
// OGCG: store i32 1, ptr %[[BASE]]
58+
// OGCG: store float 0x3FB99999A0000000, ptr %[[BASE]]
59+
// OGCG: store double 1.000000e-01, ptr %[[BASE]]

0 commit comments

Comments
 (0)