Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 6 additions & 8 deletions clang/lib/CodeGen/CGBlocks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down
64 changes: 49 additions & 15 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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);
}
}
Expand Down
12 changes: 12 additions & 0 deletions clang/lib/CodeGen/CodeGenModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
5 changes: 5 additions & 0 deletions clang/test/CodeGen/blocks.c
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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.
Expand Down
Loading