Skip to content

Commit 91d666b

Browse files
authored
[CIR] Upstream support for calling functions via member expressions (#164518)
This adds support for calling functions via class member access expressions.
1 parent 6939b36 commit 91d666b

File tree

2 files changed

+92
-4
lines changed

2 files changed

+92
-4
lines changed

clang/lib/CIR/CodeGen/CIRGenExpr.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1820,10 +1820,12 @@ CIRGenCallee CIRGenFunction::emitCallee(const clang::Expr *e) {
18201820
// Resolve direct calls.
18211821
const auto *funcDecl = cast<FunctionDecl>(declRef->getDecl());
18221822
return emitDirectCallee(funcDecl);
1823-
} else if (isa<MemberExpr>(e)) {
1824-
cgm.errorNYI(e->getSourceRange(),
1825-
"emitCallee: call to member function is NYI");
1826-
return {};
1823+
} else if (auto me = dyn_cast<MemberExpr>(e)) {
1824+
if (const auto *fd = dyn_cast<FunctionDecl>(me->getMemberDecl())) {
1825+
emitIgnoredExpr(me->getBase());
1826+
return emitDirectCallee(fd);
1827+
}
1828+
// Else fall through to the indirect reference handling below.
18271829
} else if (auto *pde = dyn_cast<CXXPseudoDestructorExpr>(e)) {
18281830
return CIRGenCallee::forPseudoDestructor(pde);
18291831
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
// RUN: %clang_cc1 -std=c++20 -triple aarch64-none-linux-android21 -fclangir -emit-cir %s -o %t.cir
2+
// RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR
3+
// RUN: %clang_cc1 -std=c++20 -triple aarch64-none-linux-android21 -fclangir -emit-llvm %s -o %t-cir.ll
4+
// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=LLVM
5+
// RUN: %clang_cc1 -std=c++20 -triple aarch64-none-linux-android21 -emit-llvm %s -o %t.ll
6+
// RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG
7+
8+
class A {
9+
public:
10+
static char *b(int);
11+
};
12+
13+
int h=0;
14+
15+
class F {
16+
public:
17+
const char *b();
18+
A g;
19+
};
20+
21+
const char *F::b() { return g.b(h); }
22+
23+
void fn1() { F f1; }
24+
25+
// CIR: cir.func {{.*}} @_ZN1F1bEv
26+
// CIR: %[[H_PTR:.*]] = cir.get_global @h : !cir.ptr<!s32i>
27+
// CIR: %[[H_VAL:.*]] = cir.load{{.*}} %[[H_PTR]] : !cir.ptr<!s32i>, !s32i
28+
// CIR: %[[RET:.*]] = cir.call @_ZN1A1bEi(%[[H_VAL]]) : (!s32i) -> !cir.ptr<!s8i>
29+
30+
// LLVM: define {{.*}} ptr @_ZN1F1bEv
31+
// LLVM: %[[VAR_H:.*]] = load i32, ptr @h
32+
// LLVM: %[[RET:.*]] = call ptr @_ZN1A1bEi(i32 %[[VAR_H]])
33+
34+
// OGCG: define {{.*}} ptr @_ZN1F1bEv
35+
// OGCG: %[[VAR_H:.*]] = load i32, ptr @h
36+
// OGCG: %[[RET:.*]] = call noundef ptr @_ZN1A1bEi(i32 noundef %[[VAR_H]])
37+
38+
class B {
39+
public:
40+
B();
41+
int (&indirect_callee_int_ref)(int);
42+
};
43+
44+
class C {
45+
public:
46+
int call_indirect(int v) { return inner.indirect_callee_int_ref(v); };
47+
B inner;
48+
};
49+
50+
void fn2() { C c1; c1.call_indirect(2); }
51+
52+
// CIR: cir.func {{.*}} @_ZN1C13call_indirectEi(%[[THIS_ARG:.*]]: !cir.ptr<!rec_C> {{.*}}, %[[V_ARG:.*]]: !s32i {{.*}}) -> !s32i
53+
// CIR: %[[THIS_ADDR:.*]] = cir.alloca !cir.ptr<!rec_C>, !cir.ptr<!cir.ptr<!rec_C>>, ["this", init]
54+
// CIR: %[[V_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["v", init]
55+
// CIR: cir.store %[[THIS_ARG]], %[[THIS_ADDR]]
56+
// CIR: cir.store %[[V_ARG]], %[[V_ADDR]]
57+
// CIR: %[[THIS:.*]] = cir.load %[[THIS_ADDR]]
58+
// CIR: %[[INNER:.*]] = cir.get_member %[[THIS]][0] {name = "inner"} : !cir.ptr<!rec_C> -> !cir.ptr<!rec_B>
59+
// CIR: %[[INDIRECT_CALLEE_PTR:.*]] = cir.get_member %[[INNER]][0] {name = "indirect_callee_int_ref"}
60+
// CIR: %[[INDIRECT_CALLEE:.*]] = cir.load %[[INDIRECT_CALLEE_PTR]]
61+
// CIR: %[[V:.*]] = cir.load{{.*}} %[[V_ADDR]] : !cir.ptr<!s32i>, !s32i
62+
// CIR: %[[RET:.*]] = cir.call %[[INDIRECT_CALLEE]](%[[V]])
63+
64+
// LLVM: define {{.*}} i32 @_ZN1C13call_indirectEi(ptr %[[THIS_ARG:.*]], i32 %[[V_ARG:.*]])
65+
// LLVM: %[[THIS_ADDR:.*]] = alloca ptr
66+
// LLVM: %[[V_ADDR:.*]] = alloca i32
67+
// LLVM: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]]
68+
// LLVM: store i32 %[[V_ARG]], ptr %[[V_ADDR]]
69+
// LLVM: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]]
70+
// LLVM: %[[INNER:.*]] = getelementptr %class.C, ptr %[[THIS]], i32 0, i32 0
71+
// LLVM: %[[INDIRECT_CALLEE_PTR:.*]] = getelementptr %class.B, ptr %[[INNER]], i32 0, i32 0
72+
// LLVM: %[[INDIRECT_CALLEE:.*]] = load ptr, ptr %[[INDIRECT_CALLEE_PTR]]
73+
// LLVM: %[[V:.*]] = load i32, ptr %[[V_ADDR]]
74+
// LLVM: %[[RET:.*]] = call i32 %[[INDIRECT_CALLEE]](i32 %[[V]])
75+
76+
// OGCG: define {{.*}} i32 @_ZN1C13call_indirectEi(ptr {{.*}} %[[THIS_ARG:.*]], i32 {{.*}} %[[V_ARG:.*]])
77+
// OGCG: %[[THIS_ADDR:.*]] = alloca ptr
78+
// OGCG: %[[V_ADDR:.*]] = alloca i32
79+
// OGCG: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]]
80+
// OGCG: store i32 %[[V_ARG]], ptr %[[V_ADDR]]
81+
// OGCG: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]]
82+
// OGCG: %[[INNER:.*]] = getelementptr inbounds nuw %class.C, ptr %[[THIS]], i32 0, i32 0
83+
// OGCG: %[[INDIRECT_CALLEE_PTR:.*]] = getelementptr inbounds nuw %class.B, ptr %[[INNER]], i32 0, i32 0
84+
// OGCG: %[[INDIRECT_CALLEE:.*]] = load ptr, ptr %[[INDIRECT_CALLEE_PTR]]
85+
// OGCG: %[[V:.*]] = load i32, ptr %[[V_ADDR]]
86+
// OGCG: %[[RET:.*]] = call noundef i32 %[[INDIRECT_CALLEE]](i32 noundef %[[V]])

0 commit comments

Comments
 (0)