Skip to content

Commit ab1765d

Browse files
authored
[CIR] Upstream trivial constructor const handling (#164849)
This adds handling for records with trivial constructors in CIR's ConstExprEmitter.
1 parent 1297bf2 commit ab1765d

File tree

4 files changed

+72
-5
lines changed

4 files changed

+72
-5
lines changed

clang/include/clang/CIR/MissingFeatures.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,7 @@ struct MissingFeatures {
231231
static bool coverageMapping() { return false; }
232232
static bool createInvariantGroup() { return false; }
233233
static bool createProfileWeightsForLoop() { return false; }
234+
static bool ctorConstLvalueToRvalueConversion() { return false; }
234235
static bool ctorMemcpyizer() { return false; }
235236
static bool cudaSupport() { return false; }
236237
static bool cxxRecordStaticMembers() { return false; }

clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -362,8 +362,7 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
362362
cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitCXXTypeidExpr");
363363
}
364364
void VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *e) {
365-
cgf.cgm.errorNYI(e->getSourceRange(),
366-
"AggExprEmitter: VisitMaterializeTemporaryExpr");
365+
Visit(e->getSubExpr());
367366
}
368367
void VisitOpaqueValueExpr(OpaqueValueExpr *e) {
369368
cgf.cgm.errorNYI(e->getSourceRange(),

clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1078,9 +1078,32 @@ class ConstExprEmitter
10781078

10791079
mlir::Attribute VisitCXXConstructExpr(CXXConstructExpr *e, QualType ty) {
10801080
if (!e->getConstructor()->isTrivial())
1081-
return nullptr;
1082-
cgm.errorNYI(e->getBeginLoc(), "trivial constructor const handling");
1083-
return {};
1081+
return {};
1082+
1083+
// Only default and copy/move constructors can be trivial.
1084+
if (e->getNumArgs()) {
1085+
assert(e->getNumArgs() == 1 && "trivial ctor with > 1 argument");
1086+
assert(e->getConstructor()->isCopyOrMoveConstructor() &&
1087+
"trivial ctor has argument but isn't a copy/move ctor");
1088+
1089+
Expr *arg = e->getArg(0);
1090+
assert(cgm.getASTContext().hasSameUnqualifiedType(ty, arg->getType()) &&
1091+
"argument to copy ctor is of wrong type");
1092+
1093+
// Look through the temporary; it's just converting the value to an lvalue
1094+
// to pass it to the constructor.
1095+
if (auto const *mte = dyn_cast<MaterializeTemporaryExpr>(arg))
1096+
return Visit(mte->getSubExpr(), ty);
1097+
1098+
// TODO: Investigate whether there are cases that can fall through to here
1099+
// that need to be handled. This is missing in classic codegen also.
1100+
assert(!cir::MissingFeatures::ctorConstLvalueToRvalueConversion());
1101+
1102+
// Don't try to support arbitrary lvalue-to-rvalue conversions for now.
1103+
return {};
1104+
}
1105+
1106+
return cgm.getBuilder().getZeroInitAttr(cgm.convertType(ty));
10841107
}
10851108

10861109
mlir::Attribute VisitStringLiteral(StringLiteral *e, QualType t) {
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++11 -fclangir -emit-cir %s -o %t.cir
2+
// RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR
3+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++11 -fclangir -emit-llvm %s -o %t-cir.ll
4+
// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=LLVM
5+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++11 -emit-llvm %s -o %t.ll
6+
// RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG
7+
8+
struct StructWithDefaultCtor {
9+
int n;
10+
};
11+
12+
StructWithDefaultCtor defCtor = StructWithDefaultCtor();
13+
14+
// CIR: cir.global {{.*}} @defCtor = #cir.zero : !rec_StructWithDefaultCtor
15+
// LLVM: @defCtor = global %struct.StructWithDefaultCtor zeroinitializer
16+
// OGCG: @defCtor = global %struct.StructWithDefaultCtor zeroinitializer
17+
18+
struct StructWithCtorArg {
19+
double value;
20+
StructWithCtorArg(const double& x) : value(x) {}
21+
};
22+
23+
StructWithCtorArg withArg = 0.0;
24+
25+
// CIR: cir.global {{.*}} @withArg = #cir.zero : !rec_StructWithCtorArg
26+
// LLVM: @withArg = global %struct.StructWithCtorArg zeroinitializer
27+
// OGCG: @withArg = global %struct.StructWithCtorArg zeroinitializer
28+
29+
// CIR: cir.func {{.*}} @__cxx_global_var_init()
30+
// CIR: %[[TMP0:.*]] = cir.alloca !cir.double, !cir.ptr<!cir.double>, ["ref.tmp0"]
31+
// CIR: %[[WITH_ARG:.*]] = cir.get_global @withArg : !cir.ptr<!rec_StructWithCtorArg>
32+
// CIR: %[[ZERO:.*]] = cir.const #cir.fp<0.000000e+00> : !cir.double
33+
// CIR: cir.store{{.*}} %[[ZERO]], %[[TMP0]] : !cir.double, !cir.ptr<!cir.double>
34+
// CIR: cir.call @_ZN17StructWithCtorArgC1ERKd(%[[WITH_ARG]], %[[TMP0]]) : (!cir.ptr<!rec_StructWithCtorArg>, !cir.ptr<!cir.double>) -> ()
35+
36+
// LLVM: define {{.*}} void @__cxx_global_var_init()
37+
// LLVM: %[[TMP0:.*]] = alloca double
38+
// LLVM: store double 0.000000e+00, ptr %[[TMP0]]
39+
// LLVM: call void @_ZN17StructWithCtorArgC1ERKd(ptr @withArg, ptr %[[TMP0]])
40+
41+
// OGCG: define {{.*}} void @__cxx_global_var_init()
42+
// OGCG: %[[TMP0:.*]] = alloca double
43+
// OGCG: store double 0.000000e+00, ptr %[[TMP0]]
44+
// OGCG: call void @_ZN17StructWithCtorArgC1ERKd(ptr {{.*}} @withArg, ptr {{.*}} %[[TMP0]])

0 commit comments

Comments
 (0)