llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Amr Hesham (AmrDeveloper) <details> <summary>Changes</summary> This change adds support for the OpaqueValueExpr for Complex & Scalar Issue: https://github.com/llvm/llvm-project/issues/141365 --- Full diff: https://github.com/llvm/llvm-project/pull/157331.diff 5 Files Affected: - (modified) clang/lib/CIR/CodeGen/CIRGenExpr.cpp (+28) - (modified) clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp (+6-3) - (modified) clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp (+9) - (modified) clang/lib/CIR/CodeGen/CIRGenFunction.h (+8) - (added) clang/test/CIR/CodeGen/opaque.cpp (+96) ``````````diff diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp index d8c7903a4888d..9047bee54475f 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp @@ -1376,6 +1376,34 @@ LValue CIRGenFunction::emitMaterializeTemporaryExpr( return makeAddrLValue(object, m->getType(), AlignmentSource::Decl); } +LValue +CIRGenFunction::getOrCreateOpaqueLValueMapping(const OpaqueValueExpr *e) { + assert(OpaqueValueMapping::shouldBindAsLValue(e)); + + llvm::DenseMap<const OpaqueValueExpr *, LValue>::iterator it = + opaqueLValues.find(e); + + if (it != opaqueLValues.end()) + return it->second; + + assert(e->isUnique() && "LValue for a nonunique OVE hasn't been emitted"); + return emitLValue(e->getSourceExpr()); +} + +RValue +CIRGenFunction::getOrCreateOpaqueRValueMapping(const OpaqueValueExpr *e) { + assert(!OpaqueValueMapping::shouldBindAsLValue(e)); + + llvm::DenseMap<const OpaqueValueExpr *, RValue>::iterator it = + opaqueRValues.find(e); + + if (it != opaqueRValues.end()) + return it->second; + + assert(e->isUnique() && "RValue for a nonunique OVE hasn't been emitted"); + return emitAnyExpr(e->getSourceExpr()); +} + LValue CIRGenFunction::emitCompoundLiteralLValue(const CompoundLiteralExpr *e) { if (e->isFileScope()) { cgm.errorNYI(e->getSourceRange(), "emitCompoundLiteralLValue: FileScope"); diff --git a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp index d678ea0212aa5..b247376b17004 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp @@ -128,9 +128,12 @@ class ComplexExprEmitter : public StmtVisitor<ComplexExprEmitter, mlir::Value> { return emitLoadOfLValue(me); } mlir::Value VisitOpaqueValueExpr(OpaqueValueExpr *e) { - cgf.cgm.errorNYI(e->getExprLoc(), - "ComplexExprEmitter VisitOpaqueValueExpr"); - return {}; + if (e->isGLValue()) + return emitLoadOfLValue(cgf.getOrCreateOpaqueLValueMapping(e), + e->getExprLoc()); + + // Otherwise, assume the mapping is the scalar directly. + return cgf.getOrCreateOpaqueRValueMapping(e).getValue(); } mlir::Value VisitPseudoObjectExpr(PseudoObjectExpr *e) { diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp index 754ef79392916..2261e24fe44c2 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp @@ -193,6 +193,15 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> { return emitNullValue(e->getType(), cgf.getLoc(e->getSourceRange())); } + mlir::Value VisitOpaqueValueExpr(OpaqueValueExpr *e) { + if (e->isGLValue()) + return emitLoadOfLValue(cgf.getOrCreateOpaqueLValueMapping(e), + e->getExprLoc()); + + // Otherwise, assume the mapping is the scalar directly. + return cgf.getOrCreateOpaqueRValueMapping(e).getValue(); + } + mlir::Value VisitCastExpr(CastExpr *e); mlir::Value VisitCallExpr(const CallExpr *e); diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h index de9e3541ed840..44f56aec15662 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -702,6 +702,14 @@ class CIRGenFunction : public CIRGenTypeCache { Address getAddrOfBitFieldStorage(LValue base, const clang::FieldDecl *field, mlir::Type fieldType, unsigned index); + /// Given an opaque value expression, return its LValue mapping if it exists, + /// otherwise create one. + LValue getOrCreateOpaqueLValueMapping(const OpaqueValueExpr *e); + + /// Given an opaque value expression, return its RValue mapping if it exists, + /// otherwise create one. + RValue getOrCreateOpaqueRValueMapping(const OpaqueValueExpr *e); + /// Load the value for 'this'. This function is only valid while generating /// code for an C++ member function. /// FIXME(cir): this should return a mlir::Value! diff --git a/clang/test/CIR/CodeGen/opaque.cpp b/clang/test/CIR/CodeGen/opaque.cpp new file mode 100644 index 0000000000000..75aed922c3153 --- /dev/null +++ b/clang/test/CIR/CodeGen/opaque.cpp @@ -0,0 +1,96 @@ +// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR +// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM +// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -Wno-unused-value -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG + +void foo() { + int a; + int b = 1 ?: a; +} + +// CIR: %[[A_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["a"] +// CIR: %[[B_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["b", init] +// CIR: %[[CONST_1:.*]] = cir.const #cir.int<1> : !s32i +// CIR: cir.store{{.*}} %[[CONST_1]], %[[B_ADDR]] : !s32i, !cir.ptr<!s32i> + +// LLVM: %[[A_ADDR:.*]] = alloca i32, i64 1, align 4 +// LLVM: %[[B_ADDR:.*]] = alloca i32, i64 1, align 4 +// LLVM: store i32 1, ptr %[[B_ADDR]], align 4 + +// OGCG: %[[A_ADDR:.*]] = alloca i32, align 4 +// OGCG: %[[B_ADDR:.*]] = alloca i32, align 4 +// OGCG: store i32 1, ptr %[[B_ADDR]], align 4 + +void foo2() { + float _Complex a; + float b = 1.0f ?: __real__ a; +} + +// CIR: %[[A_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["a"] +// CIR: %[[B_ADDR:.*]] = cir.alloca !cir.float, !cir.ptr<!cir.float>, ["b", init] +// CIR: %[[CONST_1:.*]] = cir.const #cir.fp<1.000000e+00> : !cir.float +// CIR: cir.store{{.*}} %[[CONST_1]], %[[B_ADDR]] : !cir.float, !cir.ptr<!cir.float> + +// LLVM: %[[A_ADDR:.*]] = alloca { float, float }, i64 1, align 4 +// LLVM: %[[B_ADDR:.*]] = alloca float, i64 1, align 4 +// LLVM: store float 1.000000e+00, ptr %[[B_ADDR]], align 4 + +// OGCG: %[[A_ADDR:.*]] = alloca { float, float }, align 4 +// OGCG: %[[B_ADDR:.*]] = alloca float, align 4 +// OGCG: store float 1.000000e+00, ptr %[[B_ADDR]], align 4 + +void foo3() { + int a; + int b; + int c = a ?: b; +} + +// CIR: %[[A_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["a"] +// CIR: %[[B_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["b"] +// CIR: %[[C_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["c", init] +// CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[A_ADDR]] : !cir.ptr<!s32i>, !s32i +// CIR: %[[A_BOOL:.*]] = cir.cast(int_to_bool, %[[TMP_A]] : !s32i), !cir.bool +// CIR: %[[RESULT:.*]] = cir.ternary(%[[A_BOOL]], true { +// CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[A_ADDR]] : !cir.ptr<!s32i>, !s32i +// CIR: cir.yield %[[TMP_A]] : !s32i +// CIR: }, false { +// CIR: %[[TMP_B:.*]] = cir.load{{.*}} %[[B_ADDR]] : !cir.ptr<!s32i>, !s32i +// CIR: cir.yield %[[TMP_B]] : !s32i +// CIR: }) : (!cir.bool) -> !s32i +// CIR: cir.store{{.*}} %[[RESULT]], %[[C_ADDR]] : !s32i, !cir.ptr<!s32i> + +// LLVM: %[[A_ADDR:.*]] = alloca i32, i64 1, align 4 +// LLVM: %[[B_ADDR:.*]] = alloca i32, i64 1, align 4 +// LLVM: %[[C_ADDR:.*]] = alloca i32, i64 1, align 4 +// LLVM: %[[TMP_A:.*]] = load i32, ptr %[[A_ADDR]], align 4 +// LLVM: %[[COND:.*]] = icmp ne i32 %[[TMP_A]], 0 +// LLVM: br i1 %[[COND]], label %[[COND_TRUE:.*]], label %[[COND_FALSE:.*]] +// LLVM: [[COND_TRUE]]: +// LLVM: %[[TMP_A:.*]] = load i32, ptr %[[A_ADDR]], align 4 +// LLVM: br label %[[COND_RESULT:.*]] +// LLVM: [[COND_FALSE]]: +// LLVM: %[[TMP_B:.*]] = load i32, ptr %[[B_ADDR]], align 4 +// LLVM: br label %[[COND_RESULT]] +// LLVM: [[COND_RESULT]]: +// LLVM: %[[RESULT:.*]] = phi i32 [ %[[TMP_B]], %[[COND_FALSE]] ], [ %[[TMP_A]], %[[COND_TRUE]] ] +// LLVM: br label %[[COND_END:.*]] +// LLVM: [[COND_END]]: +// LLVM: store i32 %[[RESULT]], ptr %[[C_ADDR]], align 4 + +// OGCG: %[[A_ADDR:.*]] = alloca i32, align 4 +// OGCG: %[[B_ADDR:.*]] = alloca i32, align 4 +// OGCG: %[[C_ADDR:.*]] = alloca i32, align 4 +// OGCG: %[[TMP_A:.*]] = load i32, ptr %[[A_ADDR]], align 4 +// OGCG: %[[A_BOOL:.*]] = icmp ne i32 %[[TMP_A]], 0 +// OGCG: br i1 %[[A_BOOL]], label %[[COND_TRUE:.*]], label %[[COND_FALSE:.*]] +// OGCG: [[COND_TRUE]]: +// OGCG: %[[TMP_A:.*]] = load i32, ptr %[[A_ADDR]], align 4 +// OGCG: br label %[[COND_END:.*]] +// OGCG: [[COND_FALSE]]: +// OGCG: %[[TMP_B:.*]] = load i32, ptr %[[B_ADDR]], align 4 +// OGCG: br label %[[COND_END]] +// OGCG: [[COND_END]]: +// OGCG: %[[RESULT:.*]] = phi i32 [ %[[TMP_A]], %[[COND_TRUE]] ], [ %[[TMP_B]], %[[COND_FALSE]] ] +// OGCG: store i32 %[[RESULT]], ptr %[[C_ADDR]], align 4 `````````` </details> https://github.com/llvm/llvm-project/pull/157331 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits