mcrosier created this revision.
mcrosier added reviewers: majnemer, doug.gregor, ddunbar, chandlerc, 
bob.wilson, rnk, krememek.
mcrosier added a subscriber: cfe-commits.

The changes adds support for -fno-builtin-foo options.

This addresses PR4941 and rdar://6756912.

Please take a look.

 Chad

I have no idea who would be best to review this patch, so I've added those that 
I thought might be interested.  Feel free to remove yourself if that's not the 
case.

http://reviews.llvm.org/D15195

Files:
  include/clang/Basic/Builtins.h
  include/clang/Basic/LangOptions.h
  include/clang/Driver/Options.td
  include/clang/Frontend/CodeGenOptions.h
  lib/Basic/Builtins.cpp
  lib/Basic/LangOptions.cpp
  lib/CodeGen/BackendUtil.cpp
  lib/CodeGen/CGCall.cpp
  lib/CodeGen/CGVTables.cpp
  lib/CodeGen/CodeGenModule.cpp
  lib/CodeGen/CodeGenModule.h
  lib/Driver/Tools.cpp
  lib/Frontend/CodeGenOptions.cpp
  lib/Frontend/CompilerInvocation.cpp
  test/CodeGen/2007-04-14-FNoBuiltin.c
  test/CodeGen/libcalls-complex.c
  test/CodeGen/libcalls-fno-builtin.c
  test/CodeGen/nobuiltin.c
  test/Sema/implicit-builtin-freestanding.c

Index: test/Sema/implicit-builtin-freestanding.c
===================================================================
--- test/Sema/implicit-builtin-freestanding.c
+++ test/Sema/implicit-builtin-freestanding.c
@@ -1,4 +1,6 @@
 // RUN: %clang_cc1 -fsyntax-only -verify -ffreestanding %s
+// RUN: %clang_cc1 -fsyntax-only -verify -fno-builtin %s
+// RUN: %clang_cc1 -fsyntax-only -verify -fno-builtin-malloc %s
 // expected-no-diagnostics
 
 int malloc(int a) { return a; }
Index: test/CodeGen/nobuiltin.c
===================================================================
--- test/CodeGen/nobuiltin.c
+++ test/CodeGen/nobuiltin.c
@@ -1,8 +1,17 @@
 // RUN: %clang_cc1 -fno-builtin -O1 -S -o - %s | FileCheck %s
+// RUN: %clang_cc1 -fno-builtin-memset -O1 -S -o - %s | FileCheck -check-prefix=MEMSET %s
 
 void PR13497() {
   char content[2];
   // make sure we don't optimize this call to strcpy()
   // CHECK: __strcpy_chk
   __builtin___strcpy_chk(content, "", 1);
 }
+
+void PR4941(char *s) {
+  // Make sure we don't optimize this loop to a memset().
+  // MEMSET-LABEL: PR4941:
+  // MEMSET-NOT: memset
+  for (unsigned i = 0; i < 8192; ++i)
+    s[i] = 0;
+}
Index: test/CodeGen/libcalls-fno-builtin.c
===================================================================
--- test/CodeGen/libcalls-fno-builtin.c
+++ test/CodeGen/libcalls-fno-builtin.c
@@ -1,4 +1,11 @@
 // RUN: %clang_cc1 -S -O3 -fno-builtin -o - %s | FileCheck %s
+// RUN: %clang_cc1 -S -O3 -fno-builtin-ceil -fno-builtin-copysign -fno-builtin-cos \
+// RUN:  -fno-builtin-fabs -fno-builtin-floor -fno-builtin-strcat -fno-builtin-strncat \
+// RUN:  -fno-builtin-strchr -fno-builtin-strrchr -fno-builtin-strcmp -fno-builtin-strncmp \
+// RUN:  -fno-builtin-strcpy -fno-builtin-stpcpy -fno-builtin-strncpy -fno-builtin-strlen \
+// RUN:  -fno-builtin-strpbrk -fno-builtin-strspn -fno-builtin-strtod -fno-builtin-strtof \
+// RUN:  -fno-builtin-strtold -fno-builtin-strtol -fno-builtin-strtoll -fno-builtin-strtoul \
+// RUN:  -fno-builtin-strtoull -o - %s | FileCheck %s
 // rdar://10551066
 
 typedef __SIZE_TYPE__ size_t;
Index: test/CodeGen/libcalls-complex.c
===================================================================
--- test/CodeGen/libcalls-complex.c
+++ test/CodeGen/libcalls-complex.c
@@ -1,4 +1,7 @@
 // RUN: %clang_cc1 -fno-builtin -emit-llvm -o - %s -triple i386-unknown-unknown | FileCheck -check-prefix CHECK-YES %s
+// RUN: %clang_cc1 -fno-builtin-crealf -fno-builtin-creal -fno-builtin-creall \
+// RUN:  -fno-builtin-cimagf  -fno-builtin-cimag -fno-builtin-cimagl -emit-llvm \
+// RUN:  -o - %s -triple i386-unknown-unknown | FileCheck -check-prefix CHECK-YES %s
 // RUN: %clang_cc1 -emit-llvm -o - %s -triple i386-unknown-unknown | FileCheck -check-prefix CHECK-NO %s
 
 extern float crealf(float _Complex);
Index: test/CodeGen/2007-04-14-FNoBuiltin.c
===================================================================
--- test/CodeGen/2007-04-14-FNoBuiltin.c
+++ test/CodeGen/2007-04-14-FNoBuiltin.c
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -emit-llvm %s -O2 -fno-builtin -o - | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm %s -O2 -fno-builtin-printf -o - | FileCheck %s
 // Check that -fno-builtin is honored.
 
 extern int printf(const char*, ...);
Index: lib/Frontend/CompilerInvocation.cpp
===================================================================
--- lib/Frontend/CompilerInvocation.cpp
+++ lib/Frontend/CompilerInvocation.cpp
@@ -8,13 +8,14 @@
 //===----------------------------------------------------------------------===//
 
 #include "TestModuleFileExtension.h"
-#include "clang/Frontend/CompilerInvocation.h"
+#include "clang/Basic/Builtins.h"
 #include "clang/Basic/FileManager.h"
 #include "clang/Basic/Version.h"
 #include "clang/Config/config.h"
 #include "clang/Driver/DriverDiagnostic.h"
 #include "clang/Driver/Options.h"
 #include "clang/Driver/Util.h"
+#include "clang/Frontend/CompilerInvocation.h"
 #include "clang/Frontend/FrontendDiagnostic.h"
 #include "clang/Frontend/LangStandard.h"
 #include "clang/Frontend/Utils.h"
@@ -135,6 +136,20 @@
   }
 }
 
+static std::vector<std::string> getAllNoBuiltinFuncValues(ArgList &Args) {
+  SmallVector<const char *, 8> Values;
+  for (const auto &Arg : Args) {
+    const Option &O = Arg->getOption();
+    if (O.matches(options::OPT_fno_builtin_)) {
+      const char *FuncName = Arg->getValue();
+      if (Builtin::Context::isBuiltinFunc(FuncName))
+        Values.push_back(FuncName);
+      // FIXME: We could warn about invalid/unsupported -fno-builtin-*.
+    }
+  }
+  return std::vector<std::string>(Values.begin(), Values.end());
+}
+
 static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
                               DiagnosticsEngine &Diags) {
   using namespace options;
@@ -432,6 +447,8 @@
   Opts.OptimizeSize = getOptimizationLevelSize(Args);
   Opts.SimplifyLibCalls = !(Args.hasArg(OPT_fno_builtin) ||
                             Args.hasArg(OPT_ffreestanding));
+  if (Opts.SimplifyLibCalls)
+    Opts.NoBuiltinFuncs = getAllNoBuiltinFuncValues(Args);
   Opts.UnrollLoops =
       Args.hasFlag(OPT_funroll_loops, OPT_fno_unroll_loops,
                    (Opts.OptimizationLevel > 1 && !Opts.OptimizeSize));
@@ -1640,6 +1657,8 @@
   Opts.ShortEnums = Args.hasArg(OPT_fshort_enums);
   Opts.Freestanding = Args.hasArg(OPT_ffreestanding);
   Opts.NoBuiltin = Args.hasArg(OPT_fno_builtin) || Opts.Freestanding;
+  if (!Opts.NoBuiltin)
+    Opts.NoBuiltinFuncs = getAllNoBuiltinFuncValues(Args);
   Opts.NoMathBuiltin = Args.hasArg(OPT_fno_math_builtin);
   Opts.AssumeSaneOperatorNew = !Args.hasArg(OPT_fno_assume_sane_operator_new);
   Opts.SizedDeallocation = Args.hasArg(OPT_fsized_deallocation);
Index: lib/Frontend/CodeGenOptions.cpp
===================================================================
--- lib/Frontend/CodeGenOptions.cpp
+++ lib/Frontend/CodeGenOptions.cpp
@@ -21,4 +21,12 @@
   memcpy(CoverageVersion, "402*", 4);
 }
 
+bool CodeGenOptions::isNoBuiltinFunc(const char *Name) const {
+  StringRef FuncName(Name);
+  for (unsigned i = 0, e = NoBuiltinFuncs.size(); i != e; ++i)
+    if (FuncName.equals(NoBuiltinFuncs[i]))
+      return true;
+  return false;
+}
+
 }  // end namespace clang
Index: lib/Driver/Tools.cpp
===================================================================
--- lib/Driver/Tools.cpp
+++ lib/Driver/Tools.cpp
@@ -4583,11 +4583,33 @@
       A->render(Args, CmdArgs);
   }
 
-  // -fbuiltin is default unless -mkernel is used
-  if (!Args.hasFlag(options::OPT_fbuiltin, options::OPT_fno_builtin,
-                    !Args.hasArg(options::OPT_mkernel)))
+  // -fbuiltin is default unless -mkernel is used.
+  bool UseBuiltins =
+      Args.hasFlag(options::OPT_fbuiltin, options::OPT_fno_builtin,
+                   !Args.hasArg(options::OPT_mkernel));
+  if (!UseBuiltins)
     CmdArgs.push_back("-fno-builtin");
 
+  // -ffreestanding implies -fno-builtin.
+  if (Args.hasArg(options::OPT_ffreestanding))
+    UseBuiltins = false;
+
+  // Process the -fno-builtin-* options.
+  for (const auto &Arg : Args) {
+    const Option &O = Arg->getOption();
+    if (!O.matches(options::OPT_fno_builtin_))
+      continue;
+
+    Arg->claim();
+    // If -fno-builtin is specified, then there's no need to pass the option to
+    // the frontend.
+    if (!UseBuiltins)
+      continue;
+
+    StringRef FuncName = Arg->getValue();
+    CmdArgs.push_back(Args.MakeArgString("-fno-builtin-" + FuncName));
+  }
+
   if (!Args.hasFlag(options::OPT_fassume_sane_operator_new,
                     options::OPT_fno_assume_sane_operator_new))
     CmdArgs.push_back("-fno-assume-sane-operator-new");
Index: lib/CodeGen/CodeGenModule.h
===================================================================
--- lib/CodeGen/CodeGenModule.h
+++ lib/CodeGen/CodeGenModule.h
@@ -967,13 +967,14 @@
   /// Get the LLVM attributes and calling convention to use for a particular
   /// function type.
   ///
+  /// \param Name - The function name.
   /// \param Info - The function type information.
   /// \param CalleeInfo - The callee information these attributes are being
   /// constructed for. If valid, the attributes applied to this decl may
   /// contribute to the function attributes and calling convention.
   /// \param PAL [out] - On return, the attribute list to use.
   /// \param CallingConv [out] - On return, the LLVM calling convention to use.
-  void ConstructAttributeList(const CGFunctionInfo &Info,
+  void ConstructAttributeList(StringRef Name, const CGFunctionInfo &Info,
                               CGCalleeInfo CalleeInfo, AttributeListType &PAL,
                               unsigned &CallingConv, bool AttrOnCallSite);
 
Index: lib/CodeGen/CodeGenModule.cpp
===================================================================
--- lib/CodeGen/CodeGenModule.cpp
+++ lib/CodeGen/CodeGenModule.cpp
@@ -746,7 +746,8 @@
                                               llvm::Function *F) {
   unsigned CallingConv;
   AttributeListType AttributeList;
-  ConstructAttributeList(Info, D, AttributeList, CallingConv, false);
+  ConstructAttributeList(F->getName(), Info, D, AttributeList, CallingConv,
+                         false);
   F->setAttributes(llvm::AttributeSet::get(getLLVMContext(), AttributeList));
   F->setCallingConv(static_cast<llvm::CallingConv::ID>(CallingConv));
 }
Index: lib/CodeGen/CGVTables.cpp
===================================================================
--- lib/CodeGen/CGVTables.cpp
+++ lib/CodeGen/CGVTables.cpp
@@ -378,8 +378,8 @@
   // Apply the standard set of call attributes.
   unsigned CallingConv;
   CodeGen::AttributeListType AttributeList;
-  CGM.ConstructAttributeList(*CurFnInfo, MD, AttributeList, CallingConv,
-                             /*AttrOnCallSite=*/true);
+  CGM.ConstructAttributeList(Callee->getName(), *CurFnInfo, MD, AttributeList,
+                             CallingConv, /*AttrOnCallSite=*/true);
   llvm::AttributeSet Attrs =
       llvm::AttributeSet::get(getLLVMContext(), AttributeList);
   Call->setAttributes(Attrs);
Index: lib/CodeGen/CGCall.cpp
===================================================================
--- lib/CodeGen/CGCall.cpp
+++ lib/CodeGen/CGCall.cpp
@@ -1402,11 +1402,9 @@
     FuncAttrs.addAttribute(llvm::Attribute::NoUnwind);
 }
 
-void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
-                                           CGCalleeInfo CalleeInfo,
-                                           AttributeListType &PAL,
-                                           unsigned &CallingConv,
-                                           bool AttrOnCallSite) {
+void CodeGenModule::ConstructAttributeList(
+    StringRef Name, const CGFunctionInfo &FI, CGCalleeInfo CalleeInfo,
+    AttributeListType &PAL, unsigned &CallingConv, bool AttrOnCallSite) {
   llvm::AttrBuilder FuncAttrs;
   llvm::AttrBuilder RetAttrs;
   bool HasOptnone = false;
@@ -1481,7 +1479,8 @@
 
   if (AttrOnCallSite) {
     // Attributes that should go on the call site only.
-    if (!CodeGenOpts.SimplifyLibCalls)
+    if (!CodeGenOpts.SimplifyLibCalls ||
+        CodeGenOpts.isNoBuiltinFunc(Name.data()))
       FuncAttrs.addAttribute(llvm::Attribute::NoBuiltin);
     if (!CodeGenOpts.TrapFuncName.empty())
       FuncAttrs.addAttribute("trap-func-name", CodeGenOpts.TrapFuncName);
@@ -3422,8 +3421,9 @@
 
   unsigned CallingConv;
   CodeGen::AttributeListType AttributeList;
-  CGM.ConstructAttributeList(CallInfo, CalleeInfo, AttributeList, CallingConv,
-                             true);
+  CGM.ConstructAttributeList(Callee->getName(), CallInfo, CalleeInfo,
+                             AttributeList, CallingConv,
+                             /*AttrOnCallSite=*/true);
   llvm::AttributeSet Attrs = llvm::AttributeSet::get(getLLVMContext(),
                                                      AttributeList);
 
Index: lib/CodeGen/BackendUtil.cpp
===================================================================
--- lib/CodeGen/BackendUtil.cpp
+++ lib/CodeGen/BackendUtil.cpp
@@ -248,6 +248,13 @@
   TargetLibraryInfoImpl *TLII = new TargetLibraryInfoImpl(TargetTriple);
   if (!CodeGenOpts.SimplifyLibCalls)
     TLII->disableAllFunctions();
+  else {
+    // Disable individual libc/libm calls in TargetLibraryInfo.
+    LibFunc::Func F;
+    for (auto &FuncName : CodeGenOpts.getNoBuiltinFuncs())
+      if (TLII->getLibFunc(FuncName, F))
+        TLII->setUnavailable(F);
+  }
 
   switch (CodeGenOpts.getVecLib()) {
   case CodeGenOptions::Accelerate:
Index: lib/Basic/LangOptions.cpp
===================================================================
--- lib/Basic/LangOptions.cpp
+++ lib/Basic/LangOptions.cpp
@@ -11,6 +11,7 @@
 //
 //===----------------------------------------------------------------------===//
 #include "clang/Basic/LangOptions.h"
+#include "llvm/ADT/StringRef.h"
 
 using namespace clang;
 
@@ -36,3 +37,10 @@
   ImplementationOfModule.clear();
 }
 
+bool LangOptions::isNoBuiltinFunc(const char *Name) const {
+  StringRef FuncName(Name);
+  for (unsigned i = 0, e = NoBuiltinFuncs.size(); i != e; ++i)
+    if (FuncName.equals(NoBuiltinFuncs[i]))
+      return true;
+  return false;
+}
Index: lib/Basic/Builtins.cpp
===================================================================
--- lib/Basic/Builtins.cpp
+++ lib/Basic/Builtins.cpp
@@ -48,10 +48,20 @@
     AuxTSRecords = AuxTarget->getTargetBuiltins();
 }
 
+bool Builtin::Context::isBuiltinFunc(const char *Name) {
+  StringRef FuncName(Name);
+  for (unsigned i = Builtin::NotBuiltin + 1; i != Builtin::FirstTSBuiltin; ++i)
+    if (FuncName.equals(BuiltinInfo[i].Name))
+      return strchr(BuiltinInfo[i].Attributes, 'f') != nullptr;
+
+  return false;
+}
+
 bool Builtin::Context::builtinIsSupported(const Builtin::Info &BuiltinInfo,
                                           const LangOptions &LangOpts) {
-  bool BuiltinsUnsupported = LangOpts.NoBuiltin &&
-                             strchr(BuiltinInfo.Attributes, 'f');
+  bool BuiltinsUnsupported =
+      (LangOpts.NoBuiltin || LangOpts.isNoBuiltinFunc(BuiltinInfo.Name)) &&
+      strchr(BuiltinInfo.Attributes, 'f');
   bool MathBuiltinsUnsupported =
     LangOpts.NoMathBuiltin && BuiltinInfo.HeaderName &&
     llvm::StringRef(BuiltinInfo.HeaderName).equals("math.h");
Index: include/clang/Frontend/CodeGenOptions.h
===================================================================
--- include/clang/Frontend/CodeGenOptions.h
+++ include/clang/Frontend/CodeGenOptions.h
@@ -207,6 +207,9 @@
   /// Set of sanitizer checks that trap rather than diagnose.
   SanitizerSet SanitizeTrap;
 
+  /// \brief A list of all -fno-builtin-* function names (e.g., memset).
+  std::vector<std::string> NoBuiltinFuncs;
+
 public:
   // Define accessors/mutators for code generation options of enumeration type.
 #define CODEGENOPT(Name, Bits, Default)
@@ -216,6 +219,14 @@
 #include "clang/Frontend/CodeGenOptions.def"
 
   CodeGenOptions();
+
+  /// \brief Is this a libc/libm function that is no longer recognized as a
+  /// builtin because a -fno-builtin-* option has been specified?
+  bool isNoBuiltinFunc(const char *Name) const;
+
+  const std::vector<std::string> &getNoBuiltinFuncs() const {
+    return NoBuiltinFuncs;
+  }
 };
 
 }  // end namespace clang
Index: include/clang/Driver/Options.td
===================================================================
--- include/clang/Driver/Options.td
+++ include/clang/Driver/Options.td
@@ -790,7 +790,7 @@
 def fno_borland_extensions : Flag<["-"], "fno-borland-extensions">, Group<f_Group>;
 def fno_builtin : Flag<["-"], "fno-builtin">, Group<f_Group>, Flags<[CC1Option]>,
   HelpText<"Disable implicit builtin knowledge of functions">;
-def fno_builtin_ : Joined<["-"], "fno-builtin-">, Group<clang_ignored_f_Group>,
+def fno_builtin_ : Joined<["-"], "fno-builtin-">, Group<f_Group>, Flags<[CC1Option]>,
   HelpText<"Disable implicit builtin knowledge of a specific function">;
 def fno_math_builtin : Flag<["-"], "fno-math-builtin">, Group<f_Group>, Flags<[CC1Option]>,
   HelpText<"Disable implicit builtin knowledge of math functions">;
Index: include/clang/Basic/LangOptions.h
===================================================================
--- include/clang/Basic/LangOptions.h
+++ include/clang/Basic/LangOptions.h
@@ -108,7 +108,10 @@
 
   /// \brief Options for parsing comments.
   CommentOptions CommentOpts;
-  
+
+  /// \brief A list of all -fno-builtin-* function names (e.g., memset).
+  std::vector<std::string> NoBuiltinFuncs;
+
   LangOptions();
 
   // Define accessors/mutators for language options of enumeration type.
@@ -134,6 +137,10 @@
   /// \brief Reset all of the options that are not considered when building a
   /// module.
   void resetNonModularOptions();
+
+  /// \brief Is this a libc/libm function that is no longer recognized as a
+  /// builtin because a -fno-builtin-* option has been specified?
+  bool isNoBuiltinFunc(const char *Name) const;
 };
 
 /// \brief Floating point control options
Index: include/clang/Basic/Builtins.h
===================================================================
--- include/clang/Basic/Builtins.h
+++ include/clang/Basic/Builtins.h
@@ -192,6 +192,10 @@
   /// for AuxTarget).
   unsigned getAuxBuiltinID(unsigned ID) const { return ID - TSRecords.size(); }
 
+  /// Returns true if this is a libc/libm function without the '__builtin_'
+  /// prefix.
+  static bool isBuiltinFunc(const char *Name);
+
 private:
   const Info &getRecord(unsigned ID) const;
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to