Author: Andy Kaylor
Date: 2025-04-30T14:51:45-07:00
New Revision: df6d1cf4c2e9660967a53498a991ef9c1915c61e

URL: 
https://github.com/llvm/llvm-project/commit/df6d1cf4c2e9660967a53498a991ef9c1915c61e
DIFF: 
https://github.com/llvm/llvm-project/commit/df6d1cf4c2e9660967a53498a991ef9c1915c61e.diff

LOG: [CIR] Upstream support for l-value references (#138001)

This adds basic support for handling reference values.

Added: 
    

Modified: 
    clang/lib/CIR/CodeGen/CIRGenDecl.cpp
    clang/lib/CIR/CodeGen/CIRGenExpr.cpp
    clang/lib/CIR/CodeGen/CIRGenFunction.h
    clang/lib/CIR/CodeGen/CIRGenStmt.cpp
    clang/lib/CIR/CodeGen/CIRGenTypes.cpp
    clang/test/CIR/CodeGen/basic.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp 
b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
index f16671cc3f522..90498cd18f46b 100644
--- a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
@@ -90,8 +90,13 @@ void CIRGenFunction::emitAutoVarInit(
   // If this local has an initializer, emit it now.
   const Expr *init = d.getInit();
 
-  if (!type.isPODType(getContext())) {
-    cgm.errorNYI(d.getSourceRange(), "emitAutoVarInit: non-POD type");
+  // Initialize the variable here if it doesn't have a initializer and it is a
+  // C struct that is non-trivial to initialize or an array containing such a
+  // struct.
+  if (!init && type.isNonTrivialToPrimitiveDefaultInitialize() ==
+                   QualType::PDIK_Struct) {
+    cgm.errorNYI(d.getSourceRange(),
+                 "emitAutoVarInit: non-trivial to default initialize");
     return;
   }
 
@@ -240,7 +245,10 @@ void CIRGenFunction::emitExprAsInit(const Expr *init, 
const ValueDecl *d,
   QualType type = d->getType();
 
   if (type->isReferenceType()) {
-    cgm.errorNYI(init->getSourceRange(), "emitExprAsInit: reference type");
+    RValue rvalue = emitReferenceBindingToExpr(init);
+    if (capturedByInit)
+      cgm.errorNYI(init->getSourceRange(), "emitExprAsInit: captured by init");
+    emitStoreThroughLValue(rvalue, lvalue);
     return;
   }
   switch (CIRGenFunction::getEvaluationKind(type)) {

diff  --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
index ff14798b9d34c..a50e1fd18c807 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,45 @@ mlir::Value CIRGenFunction::emitAlloca(StringRef name, 
mlir::Type ty,
   return addr;
 }
 
+RValue CIRGenFunction::emitReferenceBindingToExpr(const Expr *e) {
+  // Emit the expression as an lvalue.
+  LValue lv = emitLValue(e);
+  assert(lv.isSimple());
+  mlir::Value value = lv.getPointer();
+
+  assert(!cir::MissingFeatures::sanitizers());
+
+  return RValue::get(value);
+}
+
+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..d50abfcfbc867 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
@@ -587,6 +592,9 @@ class CIRGenFunction : public CIRGenTypeCache {
   Address emitPointerWithAlignment(const clang::Expr *expr,
                                    LValueBaseInfo *baseInfo);
 
+  /// Emits a reference binding to the passed in expression.
+  RValue emitReferenceBindingToExpr(const Expr *e);
+
   mlir::LogicalResult emitReturnStmt(const clang::ReturnStmt &s);
 
   /// Emit a conversion from the specified type to the specified destination

diff  --git a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp 
b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
index 31e29e7828156..dffa71046df1d 100644
--- a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
@@ -384,8 +384,10 @@ mlir::LogicalResult CIRGenFunction::emitReturnStmt(const 
ReturnStmt &s) {
   } else if (cast<FunctionDecl>(curGD.getDecl())
                  ->getReturnType()
                  ->isReferenceType()) {
-    getCIRGenModule().errorNYI(s.getSourceRange(),
-                               "function return type that is a reference");
+    // If this function returns a reference, take the address of the
+    // expression rather than the value.
+    RValue result = emitReferenceBindingToExpr(rv);
+    builder.createStore(loc, result.getScalarVal(), *fnRetAlloca);
   } else {
     mlir::Value value = nullptr;
     switch (CIRGenFunction::getEvaluationKind(rv->getType())) {

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..b5b3e36b4aa08 100644
--- a/clang/test/CIR/CodeGen/basic.cpp
+++ b/clang/test/CIR/CodeGen/basic.cpp
@@ -102,3 +102,42 @@ 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
+
+short gs;
+short &return_ref() {
+  return gs;
+}
+
+// CHECK: cir.func @_Z10return_refv() -> !cir.ptr<!s16i>
+// CHECK:   %[[RETVAL_ADDR:.*]] = cir.alloca !cir.ptr<!s16i>, 
!cir.ptr<!cir.ptr<!s16i>>, ["__retval"] {alignment = 8 : i64}
+// CHECK:   %[[GS_ADDR:.*]] = cir.get_global @gs : !cir.ptr<!s16i>
+// CHECK:   cir.store %[[GS_ADDR]], %[[RETVAL_ADDR]] : !cir.ptr<!s16i>, 
!cir.ptr<!cir.ptr<!s16i>>
+// CHECK:   %[[RETVAL:.*]] = cir.load %[[RETVAL_ADDR]] : 
!cir.ptr<!cir.ptr<!s16i>>, !cir.ptr<!s16i>
+// CHECK:   cir.return %[[RETVAL]] : !cir.ptr<!s16i>
+
+void ref_local(short x) {
+  short &y = x;
+}
+
+// CHECK: cir.func @_Z9ref_locals(%[[ARG:.*]]: !s16i {{.*}})
+// CHECK:   %[[X_ADDR:.*]] = cir.alloca !s16i, !cir.ptr<!s16i>, ["x", init] 
{alignment = 2 : i64}
+// CHECK:   %[[Y_REF_ADDR:.*]] = cir.alloca !cir.ptr<!s16i>, 
!cir.ptr<!cir.ptr<!s16i>>, ["y", init, const] {alignment = 8 : i64}
+// CHECK:   cir.store %[[ARG]], %[[X_ADDR]] : !s16i, !cir.ptr<!s16i>
+// CHECK:   cir.store %[[X_ADDR]], %[[Y_REF_ADDR]] : !cir.ptr<!s16i>, 
!cir.ptr<!cir.ptr<!s16i>>


        
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to