Skip to content

Commit fa67855

Browse files
authored
[CIR] Handle FunctionToPointerDecay casts (#153657) (#154060)
Add upstream support for handling implicit FunctionToPointerDecay casts
1 parent 2421929 commit fa67855

File tree

3 files changed

+132
-14
lines changed

3 files changed

+132
-14
lines changed

clang/lib/CIR/CodeGen/CIRGenExpr.cpp

Lines changed: 83 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -73,21 +73,54 @@ Address CIRGenFunction::emitPointerWithAlignment(const Expr *expr,
7373

7474
// Casts:
7575
if (auto const *ce = dyn_cast<CastExpr>(expr)) {
76-
if (isa<ExplicitCastExpr>(ce)) {
77-
cgm.errorNYI(expr->getSourceRange(),
78-
"emitPointerWithAlignment: explicit cast");
79-
return Address::invalid();
80-
}
76+
if (const auto *ece = dyn_cast<ExplicitCastExpr>(ce))
77+
cgm.emitExplicitCastExprType(ece);
8178

8279
switch (ce->getCastKind()) {
8380
// Non-converting casts (but not C's implicit conversion from void*).
8481
case CK_BitCast:
8582
case CK_NoOp:
8683
case CK_AddressSpaceConversion: {
87-
cgm.errorNYI(expr->getSourceRange(),
88-
"emitPointerWithAlignment: noop cast");
89-
return Address::invalid();
90-
} break;
84+
if (const auto *ptrTy =
85+
ce->getSubExpr()->getType()->getAs<PointerType>()) {
86+
if (ptrTy->getPointeeType()->isVoidType())
87+
break;
88+
89+
LValueBaseInfo innerBaseInfo;
90+
assert(!cir::MissingFeatures::opTBAA());
91+
Address addr =
92+
emitPointerWithAlignment(ce->getSubExpr(), &innerBaseInfo);
93+
if (baseInfo)
94+
*baseInfo = innerBaseInfo;
95+
96+
if (isa<ExplicitCastExpr>(ce)) {
97+
LValueBaseInfo targetTypeBaseInfo;
98+
99+
const QualType pointeeType = expr->getType()->getPointeeType();
100+
const CharUnits align =
101+
cgm.getNaturalTypeAlignment(pointeeType, &targetTypeBaseInfo);
102+
103+
// If the source l-value is opaque, honor the alignment of the
104+
// casted-to type.
105+
if (innerBaseInfo.getAlignmentSource() != AlignmentSource::Decl) {
106+
if (baseInfo)
107+
baseInfo->mergeForCast(targetTypeBaseInfo);
108+
addr = Address(addr.getPointer(), addr.getElementType(), align);
109+
}
110+
}
111+
112+
assert(!cir::MissingFeatures::sanitizers());
113+
114+
const mlir::Type eltTy =
115+
convertTypeForMem(expr->getType()->getPointeeType());
116+
addr = getBuilder().createElementBitCast(getLoc(expr->getSourceRange()),
117+
addr, eltTy);
118+
assert(!cir::MissingFeatures::addressSpace());
119+
120+
return addr;
121+
}
122+
break;
123+
}
91124

92125
// Array-to-pointer decay. TODO(cir): BaseInfo and TBAAInfo.
93126
case CK_ArrayToPointerDecay:
@@ -551,6 +584,37 @@ RValue CIRGenFunction::emitLoadOfLValue(LValue lv, SourceLocation loc) {
551584
return RValue::get(nullptr);
552585
}
553586

587+
static cir::FuncOp emitFunctionDeclPointer(CIRGenModule &cgm, GlobalDecl gd) {
588+
assert(!cir::MissingFeatures::weakRefReference());
589+
return cgm.getAddrOfFunction(gd);
590+
}
591+
592+
static LValue emitFunctionDeclLValue(CIRGenFunction &cgf, const Expr *e,
593+
GlobalDecl gd) {
594+
const FunctionDecl *fd = cast<FunctionDecl>(gd.getDecl());
595+
cir::FuncOp funcOp = emitFunctionDeclPointer(cgf.cgm, gd);
596+
mlir::Location loc = cgf.getLoc(e->getSourceRange());
597+
CharUnits align = cgf.getContext().getDeclAlign(fd);
598+
599+
assert(!cir::MissingFeatures::sanitizers());
600+
601+
mlir::Type fnTy = funcOp.getFunctionType();
602+
mlir::Type ptrTy = cir::PointerType::get(fnTy);
603+
mlir::Value addr = cgf.getBuilder().create<cir::GetGlobalOp>(
604+
loc, ptrTy, funcOp.getSymName());
605+
606+
if (funcOp.getFunctionType() != cgf.convertType(fd->getType())) {
607+
fnTy = cgf.convertType(fd->getType());
608+
ptrTy = cir::PointerType::get(fnTy);
609+
610+
addr = cir::CastOp::create(cgf.getBuilder(), addr.getLoc(), ptrTy,
611+
cir::CastKind::bitcast, addr);
612+
}
613+
614+
return cgf.makeAddrLValue(Address(addr, fnTy, align), e->getType(),
615+
AlignmentSource::Decl);
616+
}
617+
554618
LValue CIRGenFunction::emitDeclRefLValue(const DeclRefExpr *e) {
555619
const NamedDecl *nd = e->getDecl();
556620
QualType ty = e->getType();
@@ -607,6 +671,16 @@ LValue CIRGenFunction::emitDeclRefLValue(const DeclRefExpr *e) {
607671
return emitLValue(bd->getBinding());
608672
}
609673

674+
if (const auto *fd = dyn_cast<FunctionDecl>(nd)) {
675+
LValue lv = emitFunctionDeclLValue(*this, e, fd);
676+
677+
// Emit debuginfo for the function declaration if the target wants to.
678+
if (getContext().getTargetInfo().allowDebugInfoForExternalRef())
679+
assert(!cir::MissingFeatures::generateDebugInfo());
680+
681+
return lv;
682+
}
683+
610684
cgm.errorNYI(e->getSourceRange(), "emitDeclRefLValue: unhandled decl type");
611685
return LValue();
612686
}
@@ -1401,11 +1475,6 @@ RValue CIRGenFunction::emitAnyExpr(const Expr *e, AggValueSlot aggSlot) {
14011475
llvm_unreachable("bad evaluation kind");
14021476
}
14031477

1404-
static cir::FuncOp emitFunctionDeclPointer(CIRGenModule &cgm, GlobalDecl gd) {
1405-
assert(!cir::MissingFeatures::weakRefReference());
1406-
return cgm.getAddrOfFunction(gd);
1407-
}
1408-
14091478
// Detect the unusual situation where an inline version is shadowed by a
14101479
// non-inline version. In that case we should pick the external one
14111480
// everywhere. That's GCC behavior too.

clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1905,6 +1905,8 @@ mlir::Value ScalarExprEmitter::VisitCastExpr(CastExpr *ce) {
19051905
cgf.getLoc(subExpr->getSourceRange()), cgf.convertType(destTy),
19061906
Visit(subExpr));
19071907
}
1908+
case CK_FunctionToPointerDecay:
1909+
return cgf.emitLValue(subExpr).getPointer();
19081910

19091911
default:
19101912
cgf.getCIRGenModule().errorNYI(subExpr->getSourceRange(),
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-cir %s -o %t.cir
2+
// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
3+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll
4+
// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM
5+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -emit-llvm %s -o %t.ll
6+
// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG
7+
8+
void f(void);
9+
10+
void f1() {
11+
(void (*)())f;
12+
}
13+
14+
void f2() {
15+
(*(void (*)(void))f)();
16+
}
17+
18+
void test_lvalue_cast() {
19+
(*(void (*)(int))f)(42);
20+
}
21+
22+
// CIR-LABEL: cir.func{{.*}} @f()
23+
// CIR: cir.func{{.*}} @f1()
24+
// CIR: cir.return{{.*}}
25+
26+
// CIR-LABEL: cir.func{{.*}} @f2()
27+
// CIR: cir.call @f() : () -> ()
28+
29+
// CIR-LABEL: cir.func{{.*}} @test_lvalue_cast()
30+
// CIR: %[[S0:.+]] = {{.*}}@f : !cir.ptr<!cir.func<()>>{{.*}}
31+
// CIR: %[[S1:.+]] = cir.cast{{.*}}%[[S0]] : !cir.ptr<!cir.func<()>>{{.*}}
32+
// CIR: %[[S2:.+]] = cir.const #cir.int<42> : !s32i
33+
// CIR: cir.call %[[S1]](%[[S2]]) : (!cir.ptr<!cir.func<(!s32i)>>, !s32i) -> ()
34+
35+
// LLVM-LABEL: define{{.*}} void @f1()
36+
// LLVM: ret void
37+
// LLVM: define{{.*}} void @f2()
38+
// LLVM: call void @f()
39+
// LLVM: define{{.*}} void @test_lvalue_cast()
40+
// LLVM: call void @f(i32 42)
41+
42+
// OGCG-LABEL: define{{.*}} void @f1()
43+
// OGCG: ret void
44+
// OGCG: define{{.*}} void @f2()
45+
// OGCG: call void @f()
46+
// OGCG: define{{.*}} void @test_lvalue_cast()
47+
// OGCG: call void @f(i32 noundef 42)

0 commit comments

Comments
 (0)