[CIR] Upstream support for function-level variable decompositions (#151073)
This implements support for structured bindings on a function scope level. It does not add support for global structured bindings.
This commit is contained in:
parent
99d70e09a9
commit
8a5d363123
@ -217,6 +217,7 @@ struct MissingFeatures {
|
||||
static bool intrinsics() { return false; }
|
||||
static bool isMemcpyEquivalentSpecialMember() { return false; }
|
||||
static bool isTrivialCtorOrDtor() { return false; }
|
||||
static bool lambdaCaptures() { return false; }
|
||||
static bool lambdaFieldToName() { return false; }
|
||||
static bool loopInfoStack() { return false; }
|
||||
static bool lowerAggregateLoadStore() { return false; }
|
||||
|
@ -520,7 +520,7 @@ void CIRGenFunction::emitExprAsInit(const Expr *init, const ValueDecl *d,
|
||||
llvm_unreachable("bad evaluation kind");
|
||||
}
|
||||
|
||||
void CIRGenFunction::emitDecl(const Decl &d) {
|
||||
void CIRGenFunction::emitDecl(const Decl &d, bool evaluateConditionDecl) {
|
||||
switch (d.getKind()) {
|
||||
case Decl::BuiltinTemplate:
|
||||
case Decl::TranslationUnit:
|
||||
@ -608,11 +608,14 @@ void CIRGenFunction::emitDecl(const Decl &d) {
|
||||
case Decl::UsingDirective: // using namespace X; [C++]
|
||||
assert(!cir::MissingFeatures::generateDebugInfo());
|
||||
return;
|
||||
case Decl::Var: {
|
||||
case Decl::Var:
|
||||
case Decl::Decomposition: {
|
||||
const VarDecl &vd = cast<VarDecl>(d);
|
||||
assert(vd.isLocalVarDecl() &&
|
||||
"Should not see file-scope variables inside a function!");
|
||||
emitVarDecl(vd);
|
||||
if (evaluateConditionDecl)
|
||||
maybeEmitDeferredVarDeclInit(&vd);
|
||||
return;
|
||||
}
|
||||
case Decl::OpenACCDeclare:
|
||||
@ -632,7 +635,6 @@ void CIRGenFunction::emitDecl(const Decl &d) {
|
||||
case Decl::ImplicitConceptSpecialization:
|
||||
case Decl::TopLevelStmt:
|
||||
case Decl::UsingPack:
|
||||
case Decl::Decomposition: // This could be moved to join Decl::Var
|
||||
case Decl::OMPDeclareReduction:
|
||||
case Decl::OMPDeclareMapper:
|
||||
cgm.errorNYI(d.getSourceRange(),
|
||||
@ -797,3 +799,11 @@ void CIRGenFunction::emitAutoVarTypeCleanup(
|
||||
assert(!cir::MissingFeatures::ehCleanupFlags());
|
||||
ehStack.pushCleanup<DestroyObject>(cleanupKind, addr, type, destroyer);
|
||||
}
|
||||
|
||||
void CIRGenFunction::maybeEmitDeferredVarDeclInit(const VarDecl *vd) {
|
||||
if (auto *dd = dyn_cast_if_present<DecompositionDecl>(vd)) {
|
||||
for (auto *b : dd->flat_bindings())
|
||||
if (auto *hd = b->getHoldingVar())
|
||||
emitVarDecl(*hd);
|
||||
}
|
||||
}
|
||||
|
@ -584,6 +584,15 @@ LValue CIRGenFunction::emitDeclRefLValue(const DeclRefExpr *e) {
|
||||
return lv;
|
||||
}
|
||||
|
||||
if (const auto *bd = dyn_cast<BindingDecl>(nd)) {
|
||||
if (e->refersToEnclosingVariableOrCapture()) {
|
||||
assert(!cir::MissingFeatures::lambdaCaptures());
|
||||
cgm.errorNYI(e->getSourceRange(), "emitDeclRefLValue: lambda captures");
|
||||
return LValue();
|
||||
}
|
||||
return emitLValue(bd->getBinding());
|
||||
}
|
||||
|
||||
cgm.errorNYI(e->getSourceRange(), "emitDeclRefLValue: unhandled decl type");
|
||||
return LValue();
|
||||
}
|
||||
|
@ -870,6 +870,8 @@ public:
|
||||
void emitAutoVarTypeCleanup(const AutoVarEmission &emission,
|
||||
clang::QualType::DestructionKind dtorKind);
|
||||
|
||||
void maybeEmitDeferredVarDeclInit(const VarDecl *vd);
|
||||
|
||||
void emitBaseInitializer(mlir::Location loc, const CXXRecordDecl *classDecl,
|
||||
CXXCtorInitializer *baseInit);
|
||||
|
||||
@ -1059,7 +1061,7 @@ public:
|
||||
|
||||
void emitCompoundStmtWithoutScope(const clang::CompoundStmt &s);
|
||||
|
||||
void emitDecl(const clang::Decl &d);
|
||||
void emitDecl(const clang::Decl &d, bool evaluateConditionDecl = false);
|
||||
mlir::LogicalResult emitDeclStmt(const clang::DeclStmt &s);
|
||||
LValue emitDeclRefLValue(const clang::DeclRefExpr *e);
|
||||
|
||||
|
@ -1308,8 +1308,13 @@ void CIRGenModule::emitTopLevelDecl(Decl *decl) {
|
||||
break;
|
||||
}
|
||||
|
||||
case Decl::Var: {
|
||||
case Decl::Var:
|
||||
case Decl::Decomposition: {
|
||||
auto *vd = cast<VarDecl>(decl);
|
||||
if (isa<DecompositionDecl>(decl)) {
|
||||
errorNYI(decl->getSourceRange(), "global variable decompositions");
|
||||
break;
|
||||
}
|
||||
emitGlobal(vd);
|
||||
break;
|
||||
}
|
||||
|
@ -363,8 +363,8 @@ mlir::LogicalResult CIRGenFunction::emitIfStmt(const IfStmt &s) {
|
||||
mlir::LogicalResult CIRGenFunction::emitDeclStmt(const DeclStmt &s) {
|
||||
assert(builder.getInsertionBlock() && "expected valid insertion point");
|
||||
|
||||
for (const Decl *I : s.decls())
|
||||
emitDecl(*I);
|
||||
for (const Decl *i : s.decls())
|
||||
emitDecl(*i, /*evaluateConditionDecl=*/true);
|
||||
|
||||
return mlir::success();
|
||||
}
|
||||
@ -875,7 +875,7 @@ mlir::LogicalResult CIRGenFunction::emitSwitchStmt(const clang::SwitchStmt &s) {
|
||||
return mlir::failure();
|
||||
|
||||
if (s.getConditionVariable())
|
||||
emitDecl(*s.getConditionVariable());
|
||||
emitDecl(*s.getConditionVariable(), /*evaluateConditionDecl=*/true);
|
||||
|
||||
mlir::Value condV = emitScalarExpr(s.getCond());
|
||||
|
||||
|
55
clang/test/CIR/CodeGen/variable-decomposition.cpp
Normal file
55
clang/test/CIR/CodeGen/variable-decomposition.cpp
Normal file
@ -0,0 +1,55 @@
|
||||
// RUN: %clang_cc1 -std=c++17 -triple x86_64-pc-linux-gnu -fclangir -emit-cir %s -o %t.cir
|
||||
// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
|
||||
// RUN: %clang_cc1 -std=c++17 -triple x86_64-pc-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll
|
||||
// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s
|
||||
// RUN: %clang_cc1 -std=c++17 -triple x86_64-pc-linux-gnu -emit-llvm %s -o %t.ll
|
||||
// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s
|
||||
|
||||
struct some_struct {
|
||||
int a;
|
||||
float b;
|
||||
};
|
||||
|
||||
float function() {
|
||||
auto[a, b] = some_struct{1, 2.f};
|
||||
|
||||
return a + b;
|
||||
}
|
||||
|
||||
// CIR-LABEL: cir.func dso_local @_Z8functionv() -> !cir.float
|
||||
// CIR: %[[RETVAL:.+]] = cir.alloca !cir.float, !cir.ptr<!cir.float>, ["__retval"]
|
||||
// CIR: %[[STRUCT:.+]] = cir.alloca !rec_some_struct, !cir.ptr<!rec_some_struct>, [""]
|
||||
// CIR: %[[MEMBER_A:.+]] = cir.get_member %[[STRUCT]][0] {name = "a"} : !cir.ptr<!rec_some_struct> -> !cir.ptr<!s32i>
|
||||
// CIR: %[[LOAD_A:.+]] = cir.load align(4) %[[MEMBER_A]] : !cir.ptr<!s32i>, !s32i
|
||||
// CIR: %[[CAST_A:.+]] = cir.cast(int_to_float, %[[LOAD_A]] : !s32i), !cir.float
|
||||
// CIR: %[[MEMBER_B:.+]] = cir.get_member %[[STRUCT]][1] {name = "b"} : !cir.ptr<!rec_some_struct> -> !cir.ptr<!cir.float>
|
||||
// CIR: %[[LOAD_B:.+]] = cir.load align(4) %[[MEMBER_B]] : !cir.ptr<!cir.float>, !cir.float
|
||||
// CIR: %[[ADD:.+]] = cir.binop(add, %[[CAST_A]], %[[LOAD_B]]) : !cir.float
|
||||
// CIR: cir.store %[[ADD]], %[[RETVAL]] : !cir.float, !cir.ptr<!cir.float>
|
||||
// CIR: %[[RET:.+]] = cir.load %[[RETVAL]] : !cir.ptr<!cir.float>, !cir.float
|
||||
// CIR: cir.return %[[RET]] : !cir.float
|
||||
|
||||
// LLVM-LABEL: define dso_local float @_Z8functionv()
|
||||
// LLVM: %[[RETVAL:.+]] = alloca float, i64 1
|
||||
// LLVM: %[[STRUCT:.+]] = alloca %struct.some_struct, i64 1
|
||||
// LLVM: %[[GEP_A:.+]] = getelementptr %struct.some_struct, ptr %[[STRUCT]], i32 0, i32 0
|
||||
// LLVM: %[[LOAD_A:.+]] = load i32, ptr %[[GEP_A]]
|
||||
// LLVM: %[[CAST_A:.+]] = sitofp i32 %[[LOAD_A]] to float
|
||||
// LLVM: %[[GEP_B:.+]] = getelementptr %struct.some_struct, ptr %[[STRUCT]], i32 0, i32 1
|
||||
// LLVM: %[[LOAD_B:.+]] = load float, ptr %[[GEP_B]]
|
||||
// LLVM: %[[ADD:.+]] = fadd float %[[CAST_A]], %[[LOAD_B]]
|
||||
// LLVM: store float %[[ADD]], ptr %[[RETVAL]]
|
||||
// LLVM: %[[RET:.+]] = load float, ptr %[[RETVAL]]
|
||||
// LLVM: ret float %[[RET]]
|
||||
|
||||
// OGCG: @__const._Z8functionv.{{.*}} = private unnamed_addr constant %struct.some_struct { i32 1, float 2.000000e+00 }
|
||||
// OGCG-LABEL: define dso_local noundef float @_Z8functionv()
|
||||
// OGCG: %[[STRUCT:.+]] = alloca %struct.some_struct
|
||||
// OGCG: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[STRUCT]], ptr align 4 @__const._Z8functionv.{{.*}}, i64 8, i1 false)
|
||||
// OGCG: %[[GEP_A:.+]] = getelementptr inbounds nuw %struct.some_struct, ptr %[[STRUCT]], i32 0, i32 0
|
||||
// OGCG: %[[LOAD_A:.+]] = load i32, ptr %[[GEP_A]]
|
||||
// OGCG: %[[CAST_A:.+]] = sitofp i32 %[[LOAD_A]] to float
|
||||
// OGCG: %[[GEP_B:.+]] = getelementptr inbounds nuw %struct.some_struct, ptr %[[STRUCT]], i32 0, i32 1
|
||||
// OGCG: %[[LOAD_B:.+]] = load float, ptr %[[GEP_B]]
|
||||
// OGCG: %[[ADD:.+]] = fadd float %[[CAST_A]], %[[LOAD_B]]
|
||||
// OGCG: ret float %[[ADD]]
|
Loading…
x
Reference in New Issue
Block a user