diff --git a/clang/lib/CodeGen/CGCall.h b/clang/lib/CodeGen/CGCall.h --- a/clang/lib/CodeGen/CGCall.h +++ b/clang/lib/CodeGen/CGCall.h @@ -395,6 +395,11 @@ bool isExternallyDestructed() const { return IsExternallyDestructed; } }; +/// If \p F "target-features" are incompatible with the \p TargetOpts features, +/// it is correct to drop the function. \return true if \p F is dropped +bool dropFunctionWithIncompatibleAttributes(llvm::Function &F, + const TargetOptions &TargetOpts); + /// Helper to add attributes to \p F according to the CodeGenOptions and /// LangOptions without requiring a CodeGenModule to be constructed. void mergeDefaultFunctionDefinitionAttributes(llvm::Function &F, diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -2111,6 +2111,26 @@ TargetOpts, WillInternalize); } +bool CodeGen::dropFunctionWithIncompatibleAttributes( + llvm::Function &F, const TargetOptions &TargetOpts) { + auto FFeatures = F.getFnAttribute("target-features"); + if (!FFeatures.isValid()) + return false; + + const auto &TFeatures = TargetOpts.FeatureMap; + for (StringRef Feature : llvm::split(FFeatures.getValueAsString(), ',')) { + bool EnabledForFunc = Feature[0] == '+'; + StringRef Name = Feature.substr(1); + auto TEntry = TFeatures.find(Name); + if (TEntry != TFeatures.end() && TEntry->second != EnabledForFunc) { + F.replaceAllUsesWith(llvm::ConstantPointerNull::get(F.getType())); + F.eraseFromParent(); + return true; + } + } + return false; +} + void CodeGenModule::getTrivialDefaultFunctionAttributes( StringRef Name, bool HasOptnone, bool AttrOnCallSite, llvm::AttrBuilder &FuncAttrs) { diff --git a/clang/lib/CodeGen/CodeGenAction.cpp b/clang/lib/CodeGen/CodeGenAction.cpp --- a/clang/lib/CodeGen/CodeGenAction.cpp +++ b/clang/lib/CodeGen/CodeGenAction.cpp @@ -267,11 +267,13 @@ for (auto &LM : LinkModules) { assert(LM.Module && "LinkModule does not actually have a module"); if (LM.PropagateAttrs) - for (Function &F : *LM.Module) { + for (Function &F : llvm::make_early_inc_range(*LM.Module)) { // Skip intrinsics. Keep consistent with how intrinsics are created // in LLVM IR. if (F.isIntrinsic()) continue; + if (CodeGen::dropFunctionWithIncompatibleAttributes(F, TargetOpts)) + continue; CodeGen::mergeDefaultFunctionDefinitionAttributes( F, CodeGenOpts, LangOpts, TargetOpts, LM.Internalize); } diff --git a/clang/test/CodeGen/link-builtin-bitcode.c b/clang/test/CodeGen/link-builtin-bitcode.c --- a/clang/test/CodeGen/link-builtin-bitcode.c +++ b/clang/test/CodeGen/link-builtin-bitcode.c @@ -4,11 +4,11 @@ // RUN: %clang_cc1 -triple amdgcn-- -target-cpu gfx90a -emit-llvm-bc -o %t.bc %s // RUN: %clang_cc1 -triple amdgcn-- -target-cpu gfx90a -emit-llvm \ -// RUN: -mlink-builtin-bitcode %t-lib.bc -o - %t.bc | FileCheck %s --check-prefixes=CHECK,CPU +// RUN: -mlink-builtin-bitcode %t-lib.bc -o - %t.bc | FileCheck %s // RUN: %clang_cc1 -triple amdgcn-- -target-cpu gfx90a -emit-llvm-bc -o %t.bc %s // RUN: %clang_cc1 -triple amdgcn-- -target-cpu gfx90a -emit-llvm \ -// RUN: -mlink-builtin-bitcode %t-lib.no-cpu.bc -o - %t.bc | FileCheck %s --check-prefixes=CHECK,NOCPU +// RUN: -mlink-builtin-bitcode %t-lib.no-cpu.bc -o - %t.bc | FileCheck %s #ifdef BITCODE int no_attr(void) { return 42; } @@ -40,11 +40,8 @@ // CHECK-LABEL: define internal i32 @attr_not_in_target // CHECK-SAME: () #[[ATTR_EXTEND:[0-9]+]] { -// CHECK-LABEL: @attr_incompatible -// CHECK-SAME: () #[[ATTR_INCOMPATIBLE:[0-9]+]] { +// CHECK-NOT: @attr_incompatible // CHECK: attributes #[[ATTR_BAR]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="gfx90a" "target-features"="+16-bit-insts,+atomic-buffer-global-pk-add-f16-insts,+atomic-fadd-rtn-insts,+ci-insts,+dl-insts,+dot1-insts,+dot10-insts,+dot2-insts,+dot3-insts,+dot4-insts,+dot5-insts,+dot6-insts,+dot7-insts,+dpp,+gfx8-insts,+gfx9-insts,+gfx90a-insts,+mai-insts,+s-memrealtime,+s-memtime-inst,+wavefrontsize64" } // CHECK: attributes #[[ATTR_COMPATIBLE]] = { convergent noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="gfx90a" "target-features"="+16-bit-insts,+atomic-buffer-global-pk-add-f16-insts,+atomic-fadd-rtn-insts,+ci-insts,+dl-insts,+dot1-insts,+dot10-insts,+dot2-insts,+dot3-insts,+dot4-insts,+dot5-insts,+dot6-insts,+dot7-insts,+dpp,+gfx8-insts,+gfx9-insts,+gfx90a-insts,+gws,+image-insts,+mai-insts,+s-memrealtime,+s-memtime-inst,+wavefrontsize64" } // CHECK: attributes #[[ATTR_EXTEND]] = { convergent noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="gfx90a" "target-features"="+16-bit-insts,+atomic-buffer-global-pk-add-f16-insts,+atomic-fadd-rtn-insts,+ci-insts,+dl-insts,+dot1-insts,+dot10-insts,+dot2-insts,+dot3-insts,+dot4-insts,+dot5-insts,+dot6-insts,+dot7-insts,+dpp,+gfx8-insts,+gfx9-insts,+gfx90a-insts,+gws,+image-insts,+mai-insts,+s-memrealtime,+s-memtime-inst,+wavefrontsize64,+extended-image-insts" } -// CPU: attributes #[[ATTR_INCOMPATIBLE]] = { convergent noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="gfx90a" "target-features"="+16-bit-insts,+ci-insts,+dpp,+gfx8-insts,+s-memrealtime,+s-memtime-inst,+wavefrontsize64,-gfx9-insts" } -// NOCPU: attributes #[[ATTR_INCOMPATIBLE]] = { convergent noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="gfx90a" "target-features"="-gfx9-insts" }