[clang codegen] Add CreateRuntimeFunction overload that takes a clang type. (#113506)

Correctly computing the LLVM types/attributes is complicated in general,
so add a variant which does that for you.
This commit is contained in:
Eli Friedman 2024-11-14 14:35:40 -08:00 committed by GitHub
parent 691bd184e6
commit 6bd3f2e898
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 72 additions and 23 deletions

View File

@ -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;

View File

@ -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);
}
}

View File

@ -1247,11 +1247,23 @@ public:
/// 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);

View File

@ -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.