diff --git a/llvm/include/llvm/IR/FixedMetadataKinds.def b/llvm/include/llvm/IR/FixedMetadataKinds.def --- a/llvm/include/llvm/IR/FixedMetadataKinds.def +++ b/llvm/include/llvm/IR/FixedMetadataKinds.def @@ -42,3 +42,4 @@ LLVM_FIXED_MD_KIND(MD_vcall_visibility, "vcall_visibility", 28) LLVM_FIXED_MD_KIND(MD_noundef, "noundef", 29) LLVM_FIXED_MD_KIND(MD_annotation, "annotation", 30) +LLVM_FIXED_MD_KIND(MD_implementedby, "implementedby", 31) \ No newline at end of file diff --git a/llvm/lib/Transforms/IPO/GlobalOpt.cpp b/llvm/lib/Transforms/IPO/GlobalOpt.cpp --- a/llvm/lib/Transforms/IPO/GlobalOpt.cpp +++ b/llvm/lib/Transforms/IPO/GlobalOpt.cpp @@ -45,6 +45,7 @@ #include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/Metadata.h" #include "llvm/IR/Module.h" #include "llvm/IR/Operator.h" #include "llvm/IR/Type.h" @@ -2395,17 +2396,33 @@ bool Changed = false; + SmallPtrSet ImplementedByUses; std::vector AllCallsCold; for (Module::iterator FI = M.begin(), E = M.end(); FI != E;) { Function *F = &*FI++; if (hasOnlyColdCalls(*F, GetBFI)) AllCallsCold.push_back(F); + + auto MD = F->getMetadata(LLVMContext::MD_implementedby); + if (MD) { + ImplementedByUses.insert(F); + auto Impl = + cast(cast(MD)->getOperand(0))->getValue(); + if (auto F2 = dyn_cast(Impl)) + ImplementedByUses.insert(F2); + } } // Optimize functions. for (Module::iterator FI = M.begin(), E = M.end(); FI != E; ) { Function *F = &*FI++; + // Don't perform global opt on functions used within implemented by + // we neither want theses functions deleted, nor with a different + // calling convention. + if (ImplementedByUses.count(F)) + continue; + // Don't perform global opt pass on naked functions; we don't want fast // calling conventions for naked functions. if (F->hasFnAttribute(Attribute::Naked)) diff --git a/llvm/test/Transforms/GlobalOpt/implemented_by.ll b/llvm/test/Transforms/GlobalOpt/implemented_by.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/implemented_by.ll @@ -0,0 +1,26 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s + +declare !implementedby !0 double @llvm.sin.f64(double) +; CHECK: declare !implementedby [[sinimpl:.+]] double @llvm.sin.f64 +declare double @sin(double) + +define internal double @mycos(double %x) { + ret double %x +} +; Calling convention is not changed +; CHECK: define internal double @mycos(double %x) + +declare !implementedby !1 double @llvm.cos.f64(double) +; CHECK: declare !implementedby [[cosimpl:.+]] double @llvm.cos.f64 + +define double @cos(double %x) !implementedby !1 { + ret double %x +} +; CHECK: define double @cos{{.+}} !implementedby [[cosimpl]] { + +!0 = !{double(double)* @sin} +!1 = !{double(double)* @mycos} + +; CHECK: [[sinimpl]] = !{double (double)* @sin} +; CHECK: [[cosimpl]] = !{double (double)* @mycos} +