Skip to content

Commit 7af92bf

Browse files
committed
[CIR] Add emitNullConstant support for records
This includes member data attribute in to enable and existing test. LLVM lowering is follow up work. Fixes XFAIL in ../clang/test/CIR/CodeGen/nonzeroinit-struct.cpp
1 parent b626e81 commit 7af92bf

File tree

5 files changed

+51
-42
lines changed

5 files changed

+51
-42
lines changed

clang/lib/CIR/CodeGen/CIRGenCXXABI.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,10 @@ bool CIRGenCXXABI::isZeroInitializable(const MemberPointerType *MPT) {
8686
return true;
8787
}
8888

89+
mlir::TypedAttr CIRGenCXXABI::emitNullMemberPointer(clang::QualType T) {
90+
llvm_unreachable("NYI");
91+
}
92+
8993
CharUnits CIRGenCXXABI::getArrayCookieSize(const CXXNewExpr *E) {
9094
if (!requiresArrayCookie(E))
9195
return CharUnits::Zero();

clang/lib/CIR/CodeGen/CIRGenCXXABI.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,9 @@ class CIRGenCXXABI {
292292
return true;
293293
}
294294

295+
/// Create a null member pointer of the given type.
296+
virtual mlir::TypedAttr emitNullMemberPointer(clang::QualType T);
297+
295298
/// Gets the offsets of all the virtual base pointers in a given class.
296299
virtual std::vector<CharUnits> getVBPtrOffsets(const CXXRecordDecl *RD);
297300

clang/lib/CIR/CodeGen/CIRGenExprConst.cpp

Lines changed: 18 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1733,20 +1733,21 @@ static mlir::TypedAttr emitNullConstant(CIRGenModule &CGM, const RecordDecl *rd,
17331733
}
17341734

17351735
// Fill in all the fields.
1736-
for (const auto *Field : rd->fields()) {
1736+
for (const auto *field : rd->fields()) {
17371737
// Fill in non-bitfields. (Bitfields always use a zero pattern, which we
17381738
// will fill in later.)
1739-
if (!Field->isBitField() &&
1740-
!isEmptyFieldForLayout(CGM.getASTContext(), Field)) {
1741-
llvm_unreachable("NYI");
1739+
if (!field->isBitField() &&
1740+
!isEmptyFieldForLayout(CGM.getASTContext(), field)) {
1741+
unsigned fieldIndex = layout.getCIRFieldNo(field);
1742+
elements[fieldIndex] = CGM.emitNullConstant(field->getType());
17421743
}
17431744

17441745
// For unions, stop after the first named field.
17451746
if (rd->isUnion()) {
1746-
if (Field->getIdentifier())
1747+
if (field->getIdentifier())
17471748
break;
1748-
if (const auto *FieldRD = Field->getType()->getAsRecordDecl())
1749-
if (FieldRD->findFirstNamedDataMember())
1749+
if (const auto *fieldRD = field->getType()->getAsRecordDecl())
1750+
if (fieldRD->findFirstNamedDataMember())
17501751
break;
17511752
}
17521753
}
@@ -1780,27 +1781,8 @@ mlir::Attribute ConstantEmitter::tryEmitPrivateForVarInit(const VarDecl &D) {
17801781
if (const CXXConstructExpr *E =
17811782
dyn_cast_or_null<CXXConstructExpr>(D.getInit())) {
17821783
const CXXConstructorDecl *CD = E->getConstructor();
1783-
// FIXME: we should probably model this more closely to C++ than
1784-
// just emitting a global with zero init (mimic what we do for trivial
1785-
// assignments and whatnots). Since this is for globals shouldn't
1786-
// be a problem for the near future.
1787-
if (CD->isTrivial() && CD->isDefaultConstructor()) {
1788-
const auto *cxxrd =
1789-
cast<CXXRecordDecl>(Ty->getAs<RecordType>()->getDecl());
1790-
// Some cases, such as member pointer members, can't be zero
1791-
// initialized. These are "zero-initialized" in the language standard
1792-
// sense, but the target ABI may require that a literal value other
1793-
// than zero be used in the initializer to make clear that a pointer
1794-
// with the value zero is not what is intended. The classic codegen
1795-
// goes through emitNullConstant for those cases but generates a
1796-
// non-zero constant. We can't quite do that here because we need an
1797-
// attribute and not a value, but something like that can be
1798-
// implemented.
1799-
if (!CGM.getTypes().isZeroInitializable(cxxrd)) {
1800-
llvm_unreachable("NYI");
1801-
}
1802-
return cir::ZeroAttr::get(CGM.convertType(D.getType()));
1803-
}
1784+
if (CD->isTrivial() && CD->isDefaultConstructor())
1785+
return CGM.emitNullConstant(D.getType());
18041786
}
18051787
}
18061788
}
@@ -1820,8 +1802,11 @@ mlir::Attribute ConstantEmitter::tryEmitPrivateForVarInit(const VarDecl &D) {
18201802

18211803
// Try to emit the initializer. Note that this can allow some things that
18221804
// are not allowed by tryEmitPrivateForMemory alone.
1823-
if (auto value = D.evaluateValue())
1805+
if (auto value = D.evaluateValue()) {
1806+
assert(!value->allowConstexprUnknown() &&
1807+
"Constexpr unknown values are not allowed in CodeGen");
18241808
return tryEmitPrivateForMemory(*value, destType);
1809+
}
18251810

18261811
return nullptr;
18271812
}
@@ -2109,14 +2094,14 @@ mlir::TypedAttr CIRGenModule::emitNullConstant(QualType T) {
21092094
llvm_unreachable("NYI");
21102095
}
21112096

2112-
if (T->getAs<clang::RecordType>())
2113-
llvm_unreachable("NYI");
2097+
if (const RecordType *rt = T->getAs<RecordType>())
2098+
return ::emitNullConstant(*this, rt->getDecl(), /*complete object*/
2099+
true);
21142100

21152101
assert(T->isMemberDataPointerType() &&
21162102
"Should only see pointers to data members here!");
21172103

2118-
llvm_unreachable("NYI");
2119-
return {};
2104+
return getCXXABI().emitNullMemberPointer(T);
21202105
}
21212106

21222107
mlir::Value CIRGenModule::emitMemberPointerConstant(const UnaryOperator *E) {

clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ class CIRGenItaniumCXXABI : public CIRGenCXXABI {
123123

124124
bool classifyReturnType(CIRGenFunctionInfo &FI) const override;
125125
bool isZeroInitializable(const MemberPointerType *MPT) override;
126+
mlir::TypedAttr emitNullMemberPointer(clang::QualType T) override;
126127

127128
AddedStructorArgCounts
128129
buildStructorSignature(GlobalDecl GD,
@@ -2749,6 +2750,21 @@ bool CIRGenItaniumCXXABI::isZeroInitializable(const MemberPointerType *MPT) {
27492750
return MPT->isMemberFunctionPointer();
27502751
}
27512752

2753+
mlir::TypedAttr CIRGenItaniumCXXABI::emitNullMemberPointer(clang::QualType T) {
2754+
auto *MPT = T->getAs<MemberPointerType>();
2755+
// Itanium C++ ABI 2.3:
2756+
// A NULL pointer is represented as -1.
2757+
//
2758+
// Note that CIR uses a DataMemberAttr without member_index to get
2759+
// #cir.data_member<null>, lowering shall later transform it into -1.
2760+
if (MPT->isMemberDataPointer())
2761+
return cir::DataMemberAttr::get(
2762+
cast<cir::DataMemberType>(CGM.convertType(T)));
2763+
2764+
// Create an annon struct with two constant int of CGM.PtrDiffTy size.
2765+
llvm_unreachable("NYI");
2766+
}
2767+
27522768
/// The Itanium ABI always places an offset to the complete object
27532769
/// at entry -2 in the vtable.
27542770
void CIRGenItaniumCXXABI::emitVirtualObjectDelete(
Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,23 @@
11
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
22
// RUN: FileCheck --input-file=%t.cir %s
33

4-
// This case is not yet implemented.
5-
// XFAIL: *
4+
// TODO: Lower #cir.data_member<null> to -1 for LLVM (in the itanium ABI context).
5+
// RUN-DISABLE: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll
6+
// RUN-DISABLE: FileCheck --input-file=%t.ll -check-prefix=LLVM %s
67

78
struct Other {
8-
int x;
9+
int x;
910
};
1011

1112
struct Trivial {
12-
int x;
13-
double y;
14-
decltype(&Other::x) ptr;
13+
int x;
14+
double y;
15+
decltype(&Other::x) ptr;
1516
};
1617

1718
// This case has a trivial default constructor, but can't be zero-initialized.
1819
Trivial t;
1920

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}>
21+
// CHECK: !rec_Trivial = !cir.record<struct "Trivial" {!s32i, !cir.double, !cir.data_member<!s32i in !rec_Other>} #cir.record.decl.ast>
22+
// CHECK: cir.global external @t = #cir.const_record<{#cir.int<0> : !s32i, #cir.fp<0.000000e+00> : !cir.double,
23+
// CHECK-SAME: #cir.data_member<null> : !cir.data_member<!s32i in !rec_Other>}> : !rec_Trivial

0 commit comments

Comments
 (0)