Skip to content

Commit ebedb14

Browse files
committed
[CIR] Upstream support for function-level variable decompositions
This implements support for structured bindings on a function scope level. It does not add support for global structured bindings.
1 parent 9e0dc4f commit ebedb14

File tree

5 files changed

+73
-3
lines changed

5 files changed

+73
-3
lines changed

clang/include/clang/CIR/MissingFeatures.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,7 @@ struct MissingFeatures {
217217
static bool intrinsics() { return false; }
218218
static bool isMemcpyEquivalentSpecialMember() { return false; }
219219
static bool isTrivialCtorOrDtor() { return false; }
220+
static bool lambdaCaptures() { return false; }
220221
static bool lambdaFieldToName() { return false; }
221222
static bool loopInfoStack() { return false; }
222223
static bool lowerAggregateLoadStore() { return false; }

clang/lib/CIR/CodeGen/CIRGenDecl.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -608,11 +608,16 @@ void CIRGenFunction::emitDecl(const Decl &d) {
608608
case Decl::UsingDirective: // using namespace X; [C++]
609609
assert(!cir::MissingFeatures::generateDebugInfo());
610610
return;
611-
case Decl::Var: {
611+
case Decl::Var:
612+
case Decl::Decomposition: {
612613
const VarDecl &vd = cast<VarDecl>(d);
613614
assert(vd.isLocalVarDecl() &&
614615
"Should not see file-scope variables inside a function!");
615616
emitVarDecl(vd);
617+
if (auto *dd = dyn_cast<DecompositionDecl>(&vd))
618+
for (BindingDecl *b : dd->bindings())
619+
if (VarDecl *hd = b->getHoldingVar())
620+
emitVarDecl(*hd);
616621
return;
617622
}
618623
case Decl::OpenACCDeclare:
@@ -632,7 +637,6 @@ void CIRGenFunction::emitDecl(const Decl &d) {
632637
case Decl::ImplicitConceptSpecialization:
633638
case Decl::TopLevelStmt:
634639
case Decl::UsingPack:
635-
case Decl::Decomposition: // This could be moved to join Decl::Var
636640
case Decl::OMPDeclareReduction:
637641
case Decl::OMPDeclareMapper:
638642
cgm.errorNYI(d.getSourceRange(),

clang/lib/CIR/CodeGen/CIRGenExpr.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -584,6 +584,11 @@ LValue CIRGenFunction::emitDeclRefLValue(const DeclRefExpr *e) {
584584
return lv;
585585
}
586586

587+
if (const auto *bd = dyn_cast<BindingDecl>(nd)) {
588+
assert(!e->refersToEnclosingVariableOrCapture() && !cir::MissingFeatures::lambdaCaptures());
589+
return emitLValue(bd->getBinding());
590+
}
591+
587592
cgm.errorNYI(e->getSourceRange(), "emitDeclRefLValue: unhandled decl type");
588593
return LValue();
589594
}

clang/lib/CIR/CodeGen/CIRGenModule.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1308,8 +1308,13 @@ void CIRGenModule::emitTopLevelDecl(Decl *decl) {
13081308
break;
13091309
}
13101310

1311-
case Decl::Var: {
1311+
case Decl::Var:
1312+
case Decl::Decomposition: {
13121313
auto *vd = cast<VarDecl>(decl);
1314+
if(isa<DecompositionDecl>(decl)) {
1315+
errorNYI(decl->getSourceRange(), "global variable decompositions");
1316+
break;
1317+
}
13131318
emitGlobal(vd);
13141319
break;
13151320
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// RUN: %clang_cc1 -std=c++17 -triple x86_64-pc-linux-gnu -fclangir -emit-cir %s -o %t.cir
2+
// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
3+
// RUN: %clang_cc1 -std=c++17 -triple x86_64-pc-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll
4+
// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s
5+
// RUN: %clang_cc1 -std=c++17 -triple x86_64-pc-linux-gnu -emit-llvm %s -o %t.ll
6+
// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s
7+
8+
struct some_struct {
9+
int a;
10+
float b;
11+
};
12+
13+
float function() {
14+
auto[a, b] = some_struct{1, 2.f};
15+
16+
return a + b;
17+
}
18+
19+
// CIR-LABEL: cir.func dso_local @_Z8functionv() -> !cir.float
20+
// CIR: %[[RETVAL:.+]] = cir.alloca !cir.float, !cir.ptr<!cir.float>, ["__retval"]
21+
// CIR: %[[STRUCT:.+]] = cir.alloca !rec_some_struct, !cir.ptr<!rec_some_struct>, [""]
22+
// CIR: %[[MEMBER_A:.+]] = cir.get_member %[[STRUCT]][0] {name = "a"} : !cir.ptr<!rec_some_struct> -> !cir.ptr<!s32i>
23+
// CIR: %[[LOAD_A:.+]] = cir.load align(4) %[[MEMBER_A]] : !cir.ptr<!s32i>, !s32i
24+
// CIR: %[[CAST_A:.+]] = cir.cast(int_to_float, %[[LOAD_A]] : !s32i), !cir.float
25+
// CIR: %[[MEMBER_B:.+]] = cir.get_member %[[STRUCT]][1] {name = "b"} : !cir.ptr<!rec_some_struct> -> !cir.ptr<!cir.float>
26+
// CIR: %[[LOAD_B:.+]] = cir.load align(4) %[[MEMBER_B]] : !cir.ptr<!cir.float>, !cir.float
27+
// CIR: %[[ADD:.+]] = cir.binop(add, %[[CAST_A]], %[[LOAD_B]]) : !cir.float
28+
// CIR: cir.store %[[ADD]], %[[RETVAL]] : !cir.float, !cir.ptr<!cir.float>
29+
// CIR: %[[RET:.+]] = cir.load %[[RETVAL]] : !cir.ptr<!cir.float>, !cir.float
30+
// CIR: cir.return %[[RET]] : !cir.float
31+
32+
// LLVM-LABEL: define dso_local float @_Z8functionv()
33+
// LLVM: %[[RETVAL:.+]] = alloca float, i64 1
34+
// LLVM: %[[STRUCT:.+]] = alloca %struct.some_struct, i64 1
35+
// LLVM: %[[GEP_A:.+]] = getelementptr %struct.some_struct, ptr %[[STRUCT]], i32 0, i32 0
36+
// LLVM: %[[LOAD_A:.+]] = load i32, ptr %[[GEP_A]]
37+
// LLVM: %[[CAST_A:.+]] = sitofp i32 %[[LOAD_A]] to float
38+
// LLVM: %[[GEP_B:.+]] = getelementptr %struct.some_struct, ptr %[[STRUCT]], i32 0, i32 1
39+
// LLVM: %[[LOAD_B:.+]] = load float, ptr %[[GEP_B]]
40+
// LLVM: %[[ADD:.+]] = fadd float %[[CAST_A]], %[[LOAD_B]]
41+
// LLVM: store float %[[ADD]], ptr %[[RETVAL]]
42+
// LLVM: %[[RET:.+]] = load float, ptr %[[RETVAL]]
43+
// LLVM: ret float %[[RET]]
44+
45+
// OGCG: @__const._Z8functionv.{{.*}} = private unnamed_addr constant %struct.some_struct { i32 1, float 2.000000e+00 }
46+
// OGCG-LABEL: define dso_local noundef float @_Z8functionv()
47+
// OGCG: %[[STRUCT:.+]] = alloca %struct.some_struct
48+
// OGCG: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[STRUCT]], ptr align 4 @__const._Z8functionv.{{.*}}, i64 8, i1 false)
49+
// OGCG: %[[GEP_A:.+]] = getelementptr inbounds nuw %struct.some_struct, ptr %[[STRUCT]], i32 0, i32 0
50+
// OGCG: %[[LOAD_A:.+]] = load i32, ptr %[[GEP_A]]
51+
// OGCG: %[[CAST_A:.+]] = sitofp i32 %[[LOAD_A]] to float
52+
// OGCG: %[[GEP_B:.+]] = getelementptr inbounds nuw %struct.some_struct, ptr %[[STRUCT]], i32 0, i32 1
53+
// OGCG: %[[LOAD_B:.+]] = load float, ptr %[[GEP_B]]
54+
// OGCG: %[[ADD:.+]] = fadd float %[[CAST_A]], %[[LOAD_B]]
55+
// OGCG: ret float %[[ADD]]

0 commit comments

Comments
 (0)