Skip to content

Commit e874e6c

Browse files
andykaylorIanWood1
authored andcommitted
[CIR] Upstream support for l-value references (llvm#138001)
This adds basic support for handling reference values.
1 parent a215c84 commit e874e6c

File tree

6 files changed

+118
-6
lines changed

6 files changed

+118
-6
lines changed

clang/lib/CIR/CodeGen/CIRGenDecl.cpp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,13 @@ void CIRGenFunction::emitAutoVarInit(
9090
// If this local has an initializer, emit it now.
9191
const Expr *init = d.getInit();
9292

93-
if (!type.isPODType(getContext())) {
94-
cgm.errorNYI(d.getSourceRange(), "emitAutoVarInit: non-POD type");
93+
// Initialize the variable here if it doesn't have a initializer and it is a
94+
// C struct that is non-trivial to initialize or an array containing such a
95+
// struct.
96+
if (!init && type.isNonTrivialToPrimitiveDefaultInitialize() ==
97+
QualType::PDIK_Struct) {
98+
cgm.errorNYI(d.getSourceRange(),
99+
"emitAutoVarInit: non-trivial to default initialize");
95100
return;
96101
}
97102

@@ -240,7 +245,10 @@ void CIRGenFunction::emitExprAsInit(const Expr *init, const ValueDecl *d,
240245
QualType type = d->getType();
241246

242247
if (type->isReferenceType()) {
243-
cgm.errorNYI(init->getSourceRange(), "emitExprAsInit: reference type");
248+
RValue rvalue = emitReferenceBindingToExpr(init);
249+
if (capturedByInit)
250+
cgm.errorNYI(init->getSourceRange(), "emitExprAsInit: captured by init");
251+
emitStoreThroughLValue(rvalue, lvalue);
244252
return;
245253
}
246254
switch (CIRGenFunction::getEvaluationKind(type)) {

clang/lib/CIR/CodeGen/CIRGenExpr.cpp

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -439,7 +439,13 @@ LValue CIRGenFunction::emitDeclRefLValue(const DeclRefExpr *e) {
439439
cgm.errorNYI(e->getSourceRange(), "emitDeclRefLValue: static local");
440440
}
441441

442-
return makeAddrLValue(addr, ty, AlignmentSource::Type);
442+
// Drill into reference types.
443+
LValue lv =
444+
vd->getType()->isReferenceType()
445+
? emitLoadOfReferenceLValue(addr, getLoc(e->getSourceRange()),
446+
vd->getType(), AlignmentSource::Decl)
447+
: makeAddrLValue(addr, ty, AlignmentSource::Decl);
448+
return lv;
443449
}
444450

445451
cgm.errorNYI(e->getSourceRange(), "emitDeclRefLValue: unhandled decl type");
@@ -1065,6 +1071,45 @@ mlir::Value CIRGenFunction::emitAlloca(StringRef name, mlir::Type ty,
10651071
return addr;
10661072
}
10671073

1074+
RValue CIRGenFunction::emitReferenceBindingToExpr(const Expr *e) {
1075+
// Emit the expression as an lvalue.
1076+
LValue lv = emitLValue(e);
1077+
assert(lv.isSimple());
1078+
mlir::Value value = lv.getPointer();
1079+
1080+
assert(!cir::MissingFeatures::sanitizers());
1081+
1082+
return RValue::get(value);
1083+
}
1084+
1085+
Address CIRGenFunction::emitLoadOfReference(LValue refLVal, mlir::Location loc,
1086+
LValueBaseInfo *pointeeBaseInfo) {
1087+
if (refLVal.isVolatile())
1088+
cgm.errorNYI(loc, "load of volatile reference");
1089+
1090+
cir::LoadOp load =
1091+
builder.create<cir::LoadOp>(loc, refLVal.getAddress().getElementType(),
1092+
refLVal.getAddress().getPointer());
1093+
1094+
assert(!cir::MissingFeatures::opTBAA());
1095+
1096+
QualType pointeeType = refLVal.getType()->getPointeeType();
1097+
CharUnits align = cgm.getNaturalTypeAlignment(pointeeType, pointeeBaseInfo);
1098+
return Address(load, convertTypeForMem(pointeeType), align);
1099+
}
1100+
1101+
LValue CIRGenFunction::emitLoadOfReferenceLValue(Address refAddr,
1102+
mlir::Location loc,
1103+
QualType refTy,
1104+
AlignmentSource source) {
1105+
LValue refLVal = makeAddrLValue(refAddr, refTy, LValueBaseInfo(source));
1106+
LValueBaseInfo pointeeBaseInfo;
1107+
assert(!cir::MissingFeatures::opTBAA());
1108+
Address pointeeAddr = emitLoadOfReference(refLVal, loc, &pointeeBaseInfo);
1109+
return makeAddrLValue(pointeeAddr, refLVal.getType()->getPointeeType(),
1110+
pointeeBaseInfo);
1111+
}
1112+
10681113
mlir::Value CIRGenFunction::createDummyValue(mlir::Location loc,
10691114
clang::QualType qt) {
10701115
mlir::Type t = convertType(qt);

clang/lib/CIR/CodeGen/CIRGenFunction.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,11 @@ class CIRGenFunction : public CIRGenTypeCache {
560560
/// returning the rvalue.
561561
RValue emitLoadOfLValue(LValue lv, SourceLocation loc);
562562

563+
Address emitLoadOfReference(LValue refLVal, mlir::Location loc,
564+
LValueBaseInfo *pointeeBaseInfo);
565+
LValue emitLoadOfReferenceLValue(Address refAddr, mlir::Location loc,
566+
QualType refTy, AlignmentSource source);
567+
563568
/// EmitLoadOfScalar - Load a scalar value from an address, taking
564569
/// care to appropriately convert from the memory representation to
565570
/// the LLVM value representation. The l-value must be a simple
@@ -587,6 +592,9 @@ class CIRGenFunction : public CIRGenTypeCache {
587592
Address emitPointerWithAlignment(const clang::Expr *expr,
588593
LValueBaseInfo *baseInfo);
589594

595+
/// Emits a reference binding to the passed in expression.
596+
RValue emitReferenceBindingToExpr(const Expr *e);
597+
590598
mlir::LogicalResult emitReturnStmt(const clang::ReturnStmt &s);
591599

592600
/// Emit a conversion from the specified type to the specified destination

clang/lib/CIR/CodeGen/CIRGenStmt.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -384,8 +384,10 @@ mlir::LogicalResult CIRGenFunction::emitReturnStmt(const ReturnStmt &s) {
384384
} else if (cast<FunctionDecl>(curGD.getDecl())
385385
->getReturnType()
386386
->isReferenceType()) {
387-
getCIRGenModule().errorNYI(s.getSourceRange(),
388-
"function return type that is a reference");
387+
// If this function returns a reference, take the address of the
388+
// expression rather than the value.
389+
RValue result = emitReferenceBindingToExpr(rv);
390+
builder.createStore(loc, result.getScalarVal(), *fnRetAlloca);
389391
} else {
390392
mlir::Value value = nullptr;
391393
switch (CIRGenFunction::getEvaluationKind(rv->getType())) {

clang/lib/CIR/CodeGen/CIRGenTypes.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,16 @@ mlir::Type CIRGenTypes::convertType(QualType type) {
381381
break;
382382
}
383383

384+
case Type::LValueReference:
385+
case Type::RValueReference: {
386+
const ReferenceType *refTy = cast<ReferenceType>(ty);
387+
QualType elemTy = refTy->getPointeeType();
388+
auto pointeeType = convertTypeForMem(elemTy);
389+
resultType = builder.getPointerTo(pointeeType);
390+
assert(resultType && "Cannot get pointer type?");
391+
break;
392+
}
393+
384394
case Type::Pointer: {
385395
const PointerType *ptrTy = cast<PointerType>(ty);
386396
QualType elemTy = ptrTy->getPointeeType();

clang/test/CIR/CodeGen/basic.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,3 +102,42 @@ size_type max_size() {
102102
// CHECK: %3 = cir.cast(integral, %2 : !s32i), !u64i
103103
// CHECK: %4 = cir.const #cir.int<8> : !u64i
104104
// CHECK: %5 = cir.binop(div, %3, %4) : !u64i
105+
106+
void ref_arg(int &x) {
107+
int y = x;
108+
x = 3;
109+
}
110+
111+
// CHECK: cir.func @_Z7ref_argRi(%[[ARG:.*]]: !cir.ptr<!s32i> {{.*}})
112+
// CHECK: %[[X_REF_ADDR:.*]] = cir.alloca !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>, ["x", init, const] {alignment = 8 : i64}
113+
// CHECK: %[[Y_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["y", init] {alignment = 4 : i64}
114+
// CHECK: cir.store %[[ARG]], %[[X_REF_ADDR]] : !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>
115+
// CHECK: %[[X_REF:.*]] = cir.load %[[X_REF_ADDR]] : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
116+
// CHECK: %[[Y:.*]] = cir.load %[[X_REF]] : !cir.ptr<!s32i>, !s32i
117+
// CHECK: cir.store %[[Y]], %[[Y_ADDR]] : !s32i, !cir.ptr<!s32i>
118+
// CHECK: %[[THREE:.*]] = cir.const #cir.int<3> : !s32i
119+
// CHECK: %[[X_REF:.*]] = cir.load %[[X_REF_ADDR]] : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
120+
// CHECK: cir.store %[[THREE]], %[[X_REF]] : !s32i, !cir.ptr<!s32i>
121+
// CHECK: cir.return
122+
123+
short gs;
124+
short &return_ref() {
125+
return gs;
126+
}
127+
128+
// CHECK: cir.func @_Z10return_refv() -> !cir.ptr<!s16i>
129+
// CHECK: %[[RETVAL_ADDR:.*]] = cir.alloca !cir.ptr<!s16i>, !cir.ptr<!cir.ptr<!s16i>>, ["__retval"] {alignment = 8 : i64}
130+
// CHECK: %[[GS_ADDR:.*]] = cir.get_global @gs : !cir.ptr<!s16i>
131+
// CHECK: cir.store %[[GS_ADDR]], %[[RETVAL_ADDR]] : !cir.ptr<!s16i>, !cir.ptr<!cir.ptr<!s16i>>
132+
// CHECK: %[[RETVAL:.*]] = cir.load %[[RETVAL_ADDR]] : !cir.ptr<!cir.ptr<!s16i>>, !cir.ptr<!s16i>
133+
// CHECK: cir.return %[[RETVAL]] : !cir.ptr<!s16i>
134+
135+
void ref_local(short x) {
136+
short &y = x;
137+
}
138+
139+
// CHECK: cir.func @_Z9ref_locals(%[[ARG:.*]]: !s16i {{.*}})
140+
// CHECK: %[[X_ADDR:.*]] = cir.alloca !s16i, !cir.ptr<!s16i>, ["x", init] {alignment = 2 : i64}
141+
// CHECK: %[[Y_REF_ADDR:.*]] = cir.alloca !cir.ptr<!s16i>, !cir.ptr<!cir.ptr<!s16i>>, ["y", init, const] {alignment = 8 : i64}
142+
// CHECK: cir.store %[[ARG]], %[[X_ADDR]] : !s16i, !cir.ptr<!s16i>
143+
// CHECK: cir.store %[[X_ADDR]], %[[Y_REF_ADDR]] : !cir.ptr<!s16i>, !cir.ptr<!cir.ptr<!s16i>>

0 commit comments

Comments
 (0)