[clang] [clang codegen] Add CreateRuntimeFunction overload that takes a clang type. (PR #113506)
Eli Friedman via cfe-commits
cfe-commits at lists.llvm.org
Wed Nov 13 13:42:24 PST 2024
https://github.com/efriedma-quic updated https://github.com/llvm/llvm-project/pull/113506
>From 7f259d75f18422fff05ac11526b5a0a1b73312fd Mon Sep 17 00:00:00 2001
From: Eli Friedman <efriedma at quicinc.com>
Date: Wed, 23 Oct 2024 16:12:27 -0700
Subject: [PATCH] [clang codegen] Add CreateRuntimeFunction overload that takes
a clang type.
Correctly computing the LLVM types/attributes is complicated in general,
so add a variant which does that for you.
---
clang/lib/CodeGen/CGBlocks.cpp | 14 +++----
clang/lib/CodeGen/CodeGenModule.cpp | 64 ++++++++++++++++++++++-------
clang/lib/CodeGen/CodeGenModule.h | 12 ++++++
clang/test/CodeGen/blocks.c | 5 +++
4 files changed, 72 insertions(+), 23 deletions(-)
diff --git a/clang/lib/CodeGen/CGBlocks.cpp b/clang/lib/CodeGen/CGBlocks.cpp
index bfa9b0a2f836bc..1c46bac4bb232d 100644
--- a/clang/lib/CodeGen/CGBlocks.cpp
+++ b/clang/lib/CodeGen/CGBlocks.cpp
@@ -2837,10 +2837,9 @@ llvm::FunctionCallee CodeGenModule::getBlockObjectDispose() {
if (BlockObjectDispose)
return BlockObjectDispose;
- llvm::Type *args[] = { Int8PtrTy, Int32Ty };
- llvm::FunctionType *fty
- = llvm::FunctionType::get(VoidTy, args, false);
- BlockObjectDispose = CreateRuntimeFunction(fty, "_Block_object_dispose");
+ QualType args[] = {Context.VoidPtrTy, Context.IntTy};
+ BlockObjectDispose =
+ CreateRuntimeFunction(Context.VoidTy, args, "_Block_object_dispose");
configureBlocksRuntimeObject(
*this, cast<llvm::Constant>(BlockObjectDispose.getCallee()));
return BlockObjectDispose;
@@ -2850,10 +2849,9 @@ llvm::FunctionCallee CodeGenModule::getBlockObjectAssign() {
if (BlockObjectAssign)
return BlockObjectAssign;
- llvm::Type *args[] = { Int8PtrTy, Int8PtrTy, Int32Ty };
- llvm::FunctionType *fty
- = llvm::FunctionType::get(VoidTy, args, false);
- BlockObjectAssign = CreateRuntimeFunction(fty, "_Block_object_assign");
+ QualType args[] = {Context.VoidPtrTy, Context.VoidPtrTy, Context.IntTy};
+ BlockObjectAssign =
+ CreateRuntimeFunction(Context.VoidTy, args, "_Block_object_assign");
configureBlocksRuntimeObject(
*this, cast<llvm::Constant>(BlockObjectAssign.getCallee()));
return BlockObjectAssign;
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index ba376f9ecfacde..e1537e8ba350bb 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -4903,6 +4903,52 @@ GetRuntimeFunctionDecl(ASTContext &C, StringRef Name) {
return nullptr;
}
+static void setWindowsItaniumDLLImport(CodeGenModule &CGM, bool Local,
+ llvm::Function *F, StringRef Name) {
+ // In Windows Itanium environments, try to mark runtime functions
+ // dllimport. For Mingw and MSVC, don't. We don't really know if the user
+ // will link their standard library statically or dynamically. Marking
+ // functions imported when they are not imported can cause linker errors
+ // and warnings.
+ if (!Local && CGM.getTriple().isWindowsItaniumEnvironment() &&
+ !CGM.getCodeGenOpts().LTOVisibilityPublicStd) {
+ const FunctionDecl *FD = GetRuntimeFunctionDecl(CGM.getContext(), Name);
+ if (!FD || FD->hasAttr<DLLImportAttr>()) {
+ F->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass);
+ F->setLinkage(llvm::GlobalValue::ExternalLinkage);
+ }
+ }
+}
+
+llvm::FunctionCallee CodeGenModule::CreateRuntimeFunction(
+ QualType ReturnTy, ArrayRef<QualType> ArgTys, StringRef Name,
+ llvm::AttributeList ExtraAttrs, bool Local, bool AssumeConvergent) {
+ if (AssumeConvergent) {
+ ExtraAttrs =
+ ExtraAttrs.addFnAttribute(VMContext, llvm::Attribute::Convergent);
+ }
+
+ QualType FTy = Context.getFunctionType(ReturnTy, ArgTys,
+ FunctionProtoType::ExtProtoInfo());
+ const CGFunctionInfo &Info = getTypes().arrangeFreeFunctionType(
+ Context.getCanonicalType(FTy).castAs<FunctionProtoType>());
+ auto *ConvTy = getTypes().GetFunctionType(Info);
+ llvm::Constant *C = GetOrCreateLLVMFunction(
+ Name, ConvTy, GlobalDecl(), /*ForVTable=*/false,
+ /*DontDefer=*/false, /*IsThunk=*/false, ExtraAttrs);
+
+ if (auto *F = dyn_cast<llvm::Function>(C)) {
+ if (F->empty()) {
+ SetLLVMFunctionAttributes(GlobalDecl(), Info, F, /*IsThunk*/ false);
+ // FIXME: Set calling-conv properly in ExtProtoInfo
+ F->setCallingConv(getRuntimeCC());
+ setWindowsItaniumDLLImport(*this, Local, F, Name);
+ setDSOLocal(F);
+ }
+ }
+ return {ConvTy, C};
+}
+
/// CreateRuntimeFunction - Create a new runtime function with the specified
/// type and name.
llvm::FunctionCallee
@@ -4922,24 +4968,12 @@ CodeGenModule::CreateRuntimeFunction(llvm::FunctionType *FTy, StringRef Name,
if (auto *F = dyn_cast<llvm::Function>(C)) {
if (F->empty()) {
F->setCallingConv(getRuntimeCC());
-
- // In Windows Itanium environments, try to mark runtime functions
- // dllimport. For Mingw and MSVC, don't. We don't really know if the user
- // will link their standard library statically or dynamically. Marking
- // functions imported when they are not imported can cause linker errors
- // and warnings.
- if (!Local && getTriple().isWindowsItaniumEnvironment() &&
- !getCodeGenOpts().LTOVisibilityPublicStd) {
- const FunctionDecl *FD = GetRuntimeFunctionDecl(Context, Name);
- if (!FD || FD->hasAttr<DLLImportAttr>()) {
- F->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass);
- F->setLinkage(llvm::GlobalValue::ExternalLinkage);
- }
- }
+ setWindowsItaniumDLLImport(*this, Local, F, Name);
setDSOLocal(F);
// FIXME: We should use CodeGenModule::SetLLVMFunctionAttributes() instead
// of trying to approximate the attributes using the LLVM function
- // signature. This requires revising the API of CreateRuntimeFunction().
+ // signature. The other overload of CreateRuntimeFunction does this; it
+ // should be used for new code.
markRegisterParameterAttributes(F);
}
}
diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h
index 8d5787769382f6..741b0f17da6584 100644
--- a/clang/lib/CodeGen/CodeGenModule.h
+++ b/clang/lib/CodeGen/CodeGenModule.h
@@ -1247,11 +1247,23 @@ class CodeGenModule : public CodeGenTypeCache {
/// Create or return a runtime function declaration with the specified type
/// and name. If \p AssumeConvergent is true, the call will have the
/// convergent attribute added.
+ ///
+ /// For new code, please use the overload that takes a QualType; it sets
+ /// function attributes more accurately.
llvm::FunctionCallee
CreateRuntimeFunction(llvm::FunctionType *Ty, StringRef Name,
llvm::AttributeList ExtraAttrs = llvm::AttributeList(),
bool Local = false, bool AssumeConvergent = false);
+ /// Create or return a runtime function declaration with the specified type
+ /// and name. If \p AssumeConvergent is true, the call will have the
+ /// convergent attribute added.
+ llvm::FunctionCallee
+ CreateRuntimeFunction(QualType ReturnTy, ArrayRef<QualType> ArgTys,
+ StringRef Name,
+ llvm::AttributeList ExtraAttrs = llvm::AttributeList(),
+ bool Local = false, bool AssumeConvergent = false);
+
/// Create a new runtime global variable with the specified type and name.
llvm::Constant *CreateRuntimeVariable(llvm::Type *Ty,
StringRef Name);
diff --git a/clang/test/CodeGen/blocks.c b/clang/test/CodeGen/blocks.c
index d508de9c9f8014..d104078a9816cc 100644
--- a/clang/test/CodeGen/blocks.c
+++ b/clang/test/CodeGen/blocks.c
@@ -1,5 +1,6 @@
// RUN: %clang_cc1 -triple i386-unknown-unknown %s -emit-llvm -Wno-strict-prototypes -o - -fblocks | FileCheck --check-prefix=CHECK --check-prefix=SIG_STR %s
// RUN: %clang_cc1 -triple i386-unknown-unknown %s -emit-llvm -Wno-strict-prototypes -o - -fblocks -fdisable-block-signature-string | FileCheck --check-prefix=CHECK --check-prefix=NO_SIG_STR %s
+// RUN: %clang_cc1 -triple s390x-unknown-unknown %s -emit-llvm -Wno-strict-prototypes -o - -fblocks | FileCheck --check-prefix=SYSTEMZ %s
// SIG_STR: @[[STR:.*]] = private unnamed_addr constant [6 x i8] c"v4@?0\00", align 1
// SIG_STR: @{{.*}} = internal constant { ptr, i32, i32, ptr, ptr } { ptr @_NSConcreteGlobalBlock, i32 1342177280, i32 0, ptr @f_block_invoke, ptr @{{.*}} }, align 4
@@ -50,6 +51,8 @@ void (^test1)(void) = ^(void) {
// CHECK-NEXT: call void @_Block_object_assign(ptr %[[V5]], ptr %[[BLOCKCOPY_SRC]], i32 8)
// CHECK-NEXT: ret void
+// SYSTEMZ: declare void @_Block_object_assign(ptr noundef, ptr noundef, i32 noundef signext)
+
// CHECK-LABEL: define linkonce_odr hidden void @__destroy_helper_block_4_20r(ptr noundef %0) unnamed_addr
// CHECK: %[[_ADDR:.*]] = alloca ptr, align 4
// CHECK-NEXT: store ptr %0, ptr %[[_ADDR]], align 4
@@ -59,6 +62,8 @@ void (^test1)(void) = ^(void) {
// CHECK-NEXT: call void @_Block_object_dispose(ptr %[[V3]], i32 8)
// CHECK-NEXT: ret void
+// SYSTEMZ: declare void @_Block_object_dispose(ptr noundef, i32 noundef signext)
+
typedef double ftype(double);
// It's not clear that we *should* support this syntax, but until that decision
// is made, we should support it properly and not crash.
More information about the cfe-commits
mailing list