diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h index 5f32abca70baa..567c79a27c07b 100644 --- a/clang/include/clang/CIR/MissingFeatures.h +++ b/clang/include/clang/CIR/MissingFeatures.h @@ -226,6 +226,7 @@ struct MissingFeatures { static bool cleanupAppendInsts() { return false; } static bool cleanupBranchThrough() { return false; } static bool cleanupIndexAndBIAdjustment() { return false; } + static bool cleanupWithPreservedValues() { return false; } static bool cleanupsToDeactivate() { return false; } static bool constEmitterAggILE() { return false; } static bool constEmitterArrayILE() { return false; } diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp index 885a32cf16862..f1be14222434f 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp @@ -921,6 +921,13 @@ LValue CIRGenFunction::emitLValue(const Expr *e) { case Expr::CXXOperatorCallExprClass: case Expr::UserDefinedLiteralClass: return emitCallExprLValue(cast(e)); + case Expr::ExprWithCleanupsClass: { + const auto *cleanups = cast(e); + RunCleanupsScope scope(*this); + LValue lv = emitLValue(cleanups->getSubExpr()); + assert(!cir::MissingFeatures::cleanupWithPreservedValues()); + return lv; + } case Expr::ParenExprClass: return emitLValue(cast(e)->getSubExpr()); case Expr::GenericSelectionExprClass: diff --git a/clang/test/CIR/CodeGen/temporary-materialization.cpp b/clang/test/CIR/CodeGen/temporary-materialization.cpp new file mode 100644 index 0000000000000..b936ddfe20bf5 --- /dev/null +++ b/clang/test/CIR/CodeGen/temporary-materialization.cpp @@ -0,0 +1,86 @@ +// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR +// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=LLVM +// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG + +int make_int(); + +int test() { + const int &x = make_int(); + return x; +} + +// CIR: cir.func {{.*}} @_Z4testv() +// CIR: %[[TEMP_SLOT:.*]] = cir.alloca !s32i, !cir.ptr, ["ref.tmp0", init] +// CIR-NEXT: %[[X:.*]] = cir.alloca !cir.ptr, !cir.ptr>, ["x", init, const] +// CIR-NEXT: %[[TEMP_VALUE:.*]] = cir.call @_Z8make_intv() : () -> !s32i +// CIR-NEXT: cir.store{{.*}} %[[TEMP_VALUE]], %[[TEMP_SLOT]] +// CIR-NEXT: cir.store{{.*}} %[[TEMP_SLOT]], %[[X]] + +// LLVM: define {{.*}} i32 @_Z4testv() +// LLVM: %[[RETVAL:.*]] = alloca i32 +// LLVM: %[[TEMP_SLOT:.*]] = alloca i32 +// LLVM: %[[X:.*]] = alloca ptr +// LLVM: %[[TEMP_VALUE:.*]] = call i32 @_Z8make_intv() +// LLVM: store i32 %[[TEMP_VALUE]], ptr %[[TEMP_SLOT]] +// LLVM: store ptr %[[TEMP_SLOT]], ptr %[[X]] + +// OGCG: define {{.*}} i32 @_Z4testv() +// OGCG: %[[X:.*]] = alloca ptr +// OGCG: %[[TEMP_SLOT:.*]] = alloca i32 +// OGCG: %[[TEMP_VALUE:.*]] = call noundef i32 @_Z8make_intv() +// OGCG: store i32 %[[TEMP_VALUE]], ptr %[[TEMP_SLOT]] +// OGCG: store ptr %[[TEMP_SLOT]], ptr %[[X]] + +int test_scoped() { + int x = make_int(); + { + const int &y = make_int(); + x = y; + } + return x; +} + +// CIR: cir.func {{.*}} @_Z11test_scopedv() +// CIR: %[[X:.*]] = cir.alloca !s32i, !cir.ptr, ["x", init] +// CIR: cir.scope { +// CIR-NEXT: %[[TEMP_SLOT:.*]] = cir.alloca !s32i, !cir.ptr, ["ref.tmp0", init] +// CIR-NEXT: %[[Y_ADDR:.*]] = cir.alloca !cir.ptr, !cir.ptr>, ["y", init, const] +// CIR-NEXT: %[[TEMP_VALUE:.*]] = cir.call @_Z8make_intv() : () -> !s32i +// CIR-NEXT: cir.store{{.*}} %[[TEMP_VALUE]], %[[TEMP_SLOT]] : !s32i, !cir.ptr +// CIR-NEXT: cir.store{{.*}} %[[TEMP_SLOT]], %[[Y_ADDR]] : !cir.ptr, !cir.ptr> +// CIR-NEXT: %[[Y_REF:.*]] = cir.load %[[Y_ADDR]] : !cir.ptr>, !cir.ptr +// CIR-NEXT: %[[Y_VALUE:.*]] = cir.load{{.*}} %[[Y_REF]] : !cir.ptr, !s32i +// CIR-NEXT: cir.store{{.*}} %[[Y_VALUE]], %[[X]] : !s32i, !cir.ptr +// CIR-NEXT: } + +// LLVM: define {{.*}} i32 @_Z11test_scopedv() +// LLVM: %[[TEMP_SLOT:.*]] = alloca i32 +// LLVM: %[[Y_ADDR:.*]] = alloca ptr +// LLVM: %[[RETVAL:.*]] = alloca i32 +// LLVM: %[[X:.*]] = alloca i32 +// LLVM: %[[TEMP_VALUE1:.*]] = call i32 @_Z8make_intv() +// LLVM: store i32 %[[TEMP_VALUE1]], ptr %[[X]] +// LLVM: br label %[[SCOPE_LABEL:.*]] +// LLVM: [[SCOPE_LABEL]]: +// LLVM: %[[TEMP_VALUE2:.*]] = call i32 @_Z8make_intv() +// LLVM: store i32 %[[TEMP_VALUE2]], ptr %[[TEMP_SLOT]] +// LLVM: store ptr %[[TEMP_SLOT]], ptr %[[Y_ADDR]] +// LLVM: %[[Y_REF:.*]] = load ptr, ptr %[[Y_ADDR]] +// LLVM: %[[Y_VALUE:.*]] = load i32, ptr %[[Y_REF]] +// LLVM: store i32 %[[Y_VALUE]], ptr %[[X]] + +// OGCG: define {{.*}} i32 @_Z11test_scopedv() +// OGCG: %[[X:.*]] = alloca i32 +// OGCG: %[[Y_ADDR:.*]] = alloca ptr +// OGCG: %[[TEMP_SLOT:.*]] = alloca i32 +// OGCG: %[[TEMP_VALUE1:.*]] = call noundef i32 @_Z8make_intv() +// OGCG: store i32 %[[TEMP_VALUE1]], ptr %[[X]] +// OGCG: %[[TEMP_VALUE2:.*]] = call noundef i32 @_Z8make_intv() +// OGCG: store i32 %[[TEMP_VALUE2]], ptr %[[TEMP_SLOT]] +// OGCG: store ptr %[[TEMP_SLOT]], ptr %[[Y_ADDR]] +// OGCG: %[[Y_REF:.*]] = load ptr, ptr %[[Y_ADDR]] +// OGCG: %[[Y_VALUE:.*]] = load i32, ptr %[[Y_REF]] +// OGCG: store i32 %[[Y_VALUE]], ptr %[[X]]