llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Justin Riddell (Arghnews) <details> <summary>Changes</summary> Add upstream support for handling implicit FunctionToPointerDecay casts in ClangIR, for task #<!-- -->153657, migrate code from clangir repo Passes `check-clang` test target, have run `git-clang-format` from repo as instructed Appreciate any feedback Notes: - Omitted `clang::CIRGen::TBAAAccessInfo` from `emitPointerWithAlignment` as it looks like a large task to include that and not necessary - Omitted `KnownNonNull_t` param too, although this is much smaller but would have to alter all sites where it's currently used in clangir, in llvm - Copied `emitFunctionDeclLValue` from clangir - Have just used the simple example test given in the task + the existing `function-to-pointer-decay.c` test, maybe the CHECKs can be improved or more test cases are needed (if so please specify what, am a CIR noob) - Left `llvm_unreachable("NYI");` as those rather than a longer string, other instances in file have the same --- Full diff: https://github.com/llvm/llvm-project/pull/154060.diff 3 Files Affected: - (modified) clang/lib/CIR/CodeGen/CIRGenExpr.cpp (+86-14) - (modified) clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp (+2) - (added) clang/test/CIR/CodeGen/function-to-pointer-decay.c (+25) ``````````diff diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp index 8bcca6f5d1803..e8a25b6f9ecf4 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp @@ -73,21 +73,59 @@ Address CIRGenFunction::emitPointerWithAlignment(const Expr *expr, // Casts: if (auto const *ce = dyn_cast<CastExpr>(expr)) { - if (isa<ExplicitCastExpr>(ce)) { - cgm.errorNYI(expr->getSourceRange(), - "emitPointerWithAlignment: explicit cast"); - return Address::invalid(); - } + if (const auto *ece = dyn_cast<ExplicitCastExpr>(ce)) + cgm.emitExplicitCastExprType(ece); switch (ce->getCastKind()) { // Non-converting casts (but not C's implicit conversion from void*). case CK_BitCast: case CK_NoOp: case CK_AddressSpaceConversion: { - cgm.errorNYI(expr->getSourceRange(), - "emitPointerWithAlignment: noop cast"); - return Address::invalid(); - } break; + if (const auto *ptrTy = + ce->getSubExpr()->getType()->getAs<PointerType>()) { + if (ptrTy->getPointeeType()->isVoidType()) + break; + + LValueBaseInfo innerBaseInfo; + Address addr = + emitPointerWithAlignment(ce->getSubExpr(), &innerBaseInfo); + if (baseInfo) + *baseInfo = innerBaseInfo; + + if (isa<ExplicitCastExpr>(ce)) { + LValueBaseInfo targetTypeBaseInfo; + + const QualType pointeeType = expr->getType()->getPointeeType(); + const CharUnits align = + cgm.getNaturalTypeAlignment(pointeeType, &targetTypeBaseInfo); + + // If the source l-value is opaque, honor the alignment of the + // casted-to type. + if (innerBaseInfo.getAlignmentSource() != AlignmentSource::Decl) { + if (baseInfo) + baseInfo->mergeForCast(targetTypeBaseInfo); + addr = Address(addr.getPointer(), addr.getElementType(), align); + } + } + + if (sanOpts.has(SanitizerKind::CFIUnrelatedCast) && + ce->getCastKind() == CK_BitCast) { + if (expr->getType()->getAs<PointerType>()) + llvm_unreachable("NYI"); + } + + const auto eltTy = convertTypeForMem(expr->getType()->getPointeeType()); + addr = getBuilder().createElementBitCast(getLoc(expr->getSourceRange()), + addr, eltTy); + if (ce->getCastKind() == CK_AddressSpaceConversion) { + assert(!cir::MissingFeatures::addressSpace()); + llvm_unreachable("NYI"); + } + + return addr; + } + break; + } // Array-to-pointer decay. TODO(cir): BaseInfo and TBAAInfo. case CK_ArrayToPointerDecay: { @@ -553,6 +591,35 @@ RValue CIRGenFunction::emitLoadOfLValue(LValue lv, SourceLocation loc) { return RValue::get(nullptr); } +static cir::FuncOp emitFunctionDeclPointer(CIRGenModule &cgm, GlobalDecl gd) { + assert(!cir::MissingFeatures::weakRefReference()); + return cgm.getAddrOfFunction(gd); +} + +static LValue emitFunctionDeclLValue(CIRGenFunction &CGF, const Expr *E, + GlobalDecl GD) { + const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl()); + auto funcOp = emitFunctionDeclPointer(CGF.cgm, GD); + auto loc = CGF.getLoc(E->getSourceRange()); + CharUnits align = CGF.getContext().getDeclAlign(FD); + + mlir::Type fnTy = funcOp.getFunctionType(); + auto ptrTy = cir::PointerType::get(fnTy); + mlir::Value addr = CGF.getBuilder().create<cir::GetGlobalOp>( + loc, ptrTy, funcOp.getSymName()); + + if (funcOp.getFunctionType() != CGF.convertType(FD->getType())) { + fnTy = CGF.convertType(FD->getType()); + ptrTy = cir::PointerType::get(fnTy); + + addr = CGF.getBuilder().create<cir::CastOp>(addr.getLoc(), ptrTy, + cir::CastKind::bitcast, addr); + } + + return CGF.makeAddrLValue(Address(addr, fnTy, align), E->getType(), + AlignmentSource::Decl); +} + LValue CIRGenFunction::emitDeclRefLValue(const DeclRefExpr *e) { const NamedDecl *nd = e->getDecl(); QualType ty = e->getType(); @@ -609,6 +676,16 @@ LValue CIRGenFunction::emitDeclRefLValue(const DeclRefExpr *e) { return emitLValue(bd->getBinding()); } + if (const auto *FD = dyn_cast<FunctionDecl>(nd)) { + LValue LV = emitFunctionDeclLValue(*this, e, FD); + + // Emit debuginfo for the function declaration if the target wants to. + if (getContext().getTargetInfo().allowDebugInfoForExternalRef()) + assert(!cir::MissingFeatures::generateDebugInfo()); + + return LV; + } + cgm.errorNYI(e->getSourceRange(), "emitDeclRefLValue: unhandled decl type"); return LValue(); } @@ -1386,11 +1463,6 @@ RValue CIRGenFunction::emitAnyExpr(const Expr *e, AggValueSlot aggSlot) { llvm_unreachable("bad evaluation kind"); } -static cir::FuncOp emitFunctionDeclPointer(CIRGenModule &cgm, GlobalDecl gd) { - assert(!cir::MissingFeatures::weakRefReference()); - return cgm.getAddrOfFunction(gd); -} - // Detect the unusual situation where an inline version is shadowed by a // non-inline version. In that case we should pick the external one // everywhere. That's GCC behavior too. diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp index 8649bab91ce8e..bdda362818784 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp @@ -1879,6 +1879,8 @@ mlir::Value ScalarExprEmitter::VisitCastExpr(CastExpr *ce) { cgf.getLoc(subExpr->getSourceRange()), cgf.convertType(destTy), Visit(subExpr)); } + case CK_FunctionToPointerDecay: + return cgf.emitLValue(subExpr).getPointer(); default: cgf.getCIRGenModule().errorNYI(subExpr->getSourceRange(), diff --git a/clang/test/CIR/CodeGen/function-to-pointer-decay.c b/clang/test/CIR/CodeGen/function-to-pointer-decay.c new file mode 100644 index 0000000000000..96c4294ef2466 --- /dev/null +++ b/clang/test/CIR/CodeGen/function-to-pointer-decay.c @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o - | FileCheck %s + +int f1(); +void f2() { + int (*t)() = f1; +} + +// CHECK: cir.func {{.*}}@f2() +// CHECK: %[[SLOT:.*]] = cir.alloca +// CHECK: %[[F1:.+]] = cir.get_global @f1 +// CHECK: cir.store {{.*}} %[[F1]], %[[SLOT]] : {{.*}} + +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o - | FileCheck %s + +void f(void); + +void test_call_lvalue_cast() { + (*(void (*)(int))f)(42); +} + +// CHECK: cir.func {{.*}}@test_call_lvalue_cast() +// CHECK: [[F:%.+]] = cir.get_global @f +// CHECK: [[CASTED:%.+]] = cir.cast(bitcast, [[F]] +// CHECK: [[CONST:%.+]] = cir.const #cir.int<42> +// CHECK: cir.call [[CASTED]]([[CONST]]) `````````` </details> https://github.com/llvm/llvm-project/pull/154060 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits