-
Notifications
You must be signed in to change notification settings - Fork 14.8k
[CIR] Upstream support for l-value references #138001
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
This adds basic support for handling reference values.
@llvm/pr-subscribers-clangir @llvm/pr-subscribers-clang Author: Andy Kaylor (andykaylor) ChangesThis adds basic support for handling reference values. Full diff: https://github.com/llvm/llvm-project/pull/138001.diff 4 Files Affected:
diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
index ff14798b9d34c..080209ca04b4c 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -439,7 +439,13 @@ LValue CIRGenFunction::emitDeclRefLValue(const DeclRefExpr *e) {
cgm.errorNYI(e->getSourceRange(), "emitDeclRefLValue: static local");
}
- return makeAddrLValue(addr, ty, AlignmentSource::Type);
+ // Drill into reference types.
+ LValue lv =
+ vd->getType()->isReferenceType()
+ ? emitLoadOfReferenceLValue(addr, getLoc(e->getSourceRange()),
+ vd->getType(), AlignmentSource::Decl)
+ : makeAddrLValue(addr, ty, AlignmentSource::Decl);
+ return lv;
}
cgm.errorNYI(e->getSourceRange(), "emitDeclRefLValue: unhandled decl type");
@@ -1065,6 +1071,34 @@ mlir::Value CIRGenFunction::emitAlloca(StringRef name, mlir::Type ty,
return addr;
}
+Address CIRGenFunction::emitLoadOfReference(LValue refLVal, mlir::Location loc,
+ LValueBaseInfo *pointeeBaseInfo) {
+ if (refLVal.isVolatile())
+ cgm.errorNYI(loc, "load of volatile reference");
+
+ cir::LoadOp load =
+ builder.create<cir::LoadOp>(loc, refLVal.getAddress().getElementType(),
+ refLVal.getAddress().getPointer());
+
+ assert(!cir::MissingFeatures::opTBAA());
+
+ QualType pointeeType = refLVal.getType()->getPointeeType();
+ CharUnits align = cgm.getNaturalTypeAlignment(pointeeType, pointeeBaseInfo);
+ return Address(load, convertTypeForMem(pointeeType), align);
+}
+
+LValue CIRGenFunction::emitLoadOfReferenceLValue(Address refAddr,
+ mlir::Location loc,
+ QualType refTy,
+ AlignmentSource source) {
+ LValue refLVal = makeAddrLValue(refAddr, refTy, LValueBaseInfo(source));
+ LValueBaseInfo pointeeBaseInfo;
+ assert(!cir::MissingFeatures::opTBAA());
+ Address pointeeAddr = emitLoadOfReference(refLVal, loc, &pointeeBaseInfo);
+ return makeAddrLValue(pointeeAddr, refLVal.getType()->getPointeeType(),
+ pointeeBaseInfo);
+}
+
mlir::Value CIRGenFunction::createDummyValue(mlir::Location loc,
clang::QualType qt) {
mlir::Type t = convertType(qt);
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index 592d39930089d..b4e1d24e0feda 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -560,6 +560,11 @@ class CIRGenFunction : public CIRGenTypeCache {
/// returning the rvalue.
RValue emitLoadOfLValue(LValue lv, SourceLocation loc);
+ Address emitLoadOfReference(LValue refLVal, mlir::Location loc,
+ LValueBaseInfo *pointeeBaseInfo);
+ LValue emitLoadOfReferenceLValue(Address refAddr, mlir::Location loc,
+ QualType refTy, AlignmentSource source);
+
/// EmitLoadOfScalar - Load a scalar value from an address, taking
/// care to appropriately convert from the memory representation to
/// the LLVM value representation. The l-value must be a simple
diff --git a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
index de8ea0bd92158..98c9398fd4d94 100644
--- a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
@@ -381,6 +381,16 @@ mlir::Type CIRGenTypes::convertType(QualType type) {
break;
}
+ case Type::LValueReference:
+ case Type::RValueReference: {
+ const ReferenceType *refTy = cast<ReferenceType>(ty);
+ QualType elemTy = refTy->getPointeeType();
+ auto pointeeType = convertTypeForMem(elemTy);
+ resultType = builder.getPointerTo(pointeeType);
+ assert(resultType && "Cannot get pointer type?");
+ break;
+ }
+
case Type::Pointer: {
const PointerType *ptrTy = cast<PointerType>(ty);
QualType elemTy = ptrTy->getPointeeType();
diff --git a/clang/test/CIR/CodeGen/basic.cpp b/clang/test/CIR/CodeGen/basic.cpp
index 1f289e905dd09..cf3fab5de510e 100644
--- a/clang/test/CIR/CodeGen/basic.cpp
+++ b/clang/test/CIR/CodeGen/basic.cpp
@@ -102,3 +102,20 @@ size_type max_size() {
// CHECK: %3 = cir.cast(integral, %2 : !s32i), !u64i
// CHECK: %4 = cir.const #cir.int<8> : !u64i
// CHECK: %5 = cir.binop(div, %3, %4) : !u64i
+
+void ref_arg(int &x) {
+ int y = x;
+ x = 3;
+}
+
+// CHECK: cir.func @_Z7ref_argRi(%[[ARG:.*]]: !cir.ptr<!s32i> {{.*}})
+// CHECK: %[[X_REF_ADDR:.*]] = cir.alloca !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>, ["x", init, const] {alignment = 8 : i64}
+// CHECK: %[[Y_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["y", init] {alignment = 4 : i64}
+// CHECK: cir.store %[[ARG]], %[[X_REF_ADDR]] : !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>
+// CHECK: %[[X_REF:.*]] = cir.load %[[X_REF_ADDR]] : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
+// CHECK: %[[Y:.*]] = cir.load %[[X_REF]] : !cir.ptr<!s32i>, !s32i
+// CHECK: cir.store %[[Y]], %[[Y_ADDR]] : !s32i, !cir.ptr<!s32i>
+// CHECK: %[[THREE:.*]] = cir.const #cir.int<3> : !s32i
+// CHECK: %[[X_REF:.*]] = cir.load %[[X_REF_ADDR]] : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
+// CHECK: cir.store %[[THREE]], %[[X_REF]] : !s32i, !cir.ptr<!s32i>
+// CHECK: cir.return
|
void ref_arg(int &x) { | ||
int y = x; | ||
x = 3; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we also have tests for 'function that returns reference'?
ClassTy &foo();
ClassTy &&foo();
And perhaps int &z = x
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After looking into it a bit more, I don't want to handle r-value references yet. It needs more handling. The other cases are added along with the little extra support they required.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, sounds good. Please change the title then to say "Upstream support for L-Value References"
void ref_arg(int &x) { | ||
int y = x; | ||
x = 3; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, sounds good. Please change the title then to say "Upstream support for L-Value References"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome! LGTM
This adds basic support for handling reference values.
This adds basic support for handling reference values.
This adds basic support for handling reference values.
This adds basic support for handling reference values.
This adds basic support for handling reference values.
This adds basic support for handling reference values.