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