Index: include/llvm/IR/Instructions.h
===================================================================
--- include/llvm/IR/Instructions.h	(revision 181984)
+++ include/llvm/IR/Instructions.h	(working copy)
@@ -1288,6 +1288,12 @@
     return AttributeList.getParamAlignment(i);
   }
 
+  /// \brief Return true if the call should not be treated as a call to a
+  /// builtin.
+  bool isNoBuiltin() const {
+    return hasFnAttr(Attribute::NoBuiltin) && !hasFnAttr(Attribute::Builtin);
+  }
+
   /// \brief Return true if the call should not be inlined.
   bool isNoInline() const { return hasFnAttr(Attribute::NoInline); }
   void setIsNoInline() {
@@ -3034,6 +3040,12 @@
     return AttributeList.getParamAlignment(i);
   }
 
+  /// \brief Return true if the call should not be treated as a call to a
+  /// builtin.
+  bool isNoBuiltin() const {
+    return hasFnAttr(Attribute::NoBuiltin) && !hasFnAttr(Attribute::Builtin);
+  }
+
   /// \brief Return true if the call should not be inlined.
   bool isNoInline() const { return hasFnAttr(Attribute::NoInline); }
   void setIsNoInline() {
Index: include/llvm/IR/Attributes.h
===================================================================
--- include/llvm/IR/Attributes.h	(revision 181984)
+++ include/llvm/IR/Attributes.h	(working copy)
@@ -67,6 +67,8 @@
                            ///< stored as log2 of alignment with +1 bias
                            ///< 0 means unaligned (different from align(1))
     AlwaysInline,          ///< inline=always
+    Builtin,               ///< Callee is recognized as a builtin, despite
+                           ///< nobuiltin attribute on its declaration
     ByVal,                 ///< Pass structure by value
     InlineHint,            ///< Source said inlining was desirable
     InReg,                 ///< Force argument to be passed in register
Index: include/llvm/Support/CallSite.h
===================================================================
--- include/llvm/Support/CallSite.h	(revision 181984)
+++ include/llvm/Support/CallSite.h	(working copy)
@@ -198,6 +198,12 @@
     CALLSITE_DELEGATE_GETTER(getParamAlignment(i));
   }
 
+  /// \brief Return true if the call should not be treated as a call to a
+  /// builtin.
+  bool isNoBuiltin() const {
+    CALLSITE_DELEGATE_GETTER(isNoBuiltin());
+  }
+
   /// @brief Return true if the call should not be inlined.
   bool isNoInline() const {
     CALLSITE_DELEGATE_GETTER(isNoInline());
Index: docs/LangRef.rst
===================================================================
--- docs/LangRef.rst	(revision 181984)
+++ docs/LangRef.rst	(working copy)
@@ -807,6 +807,12 @@
     This attribute indicates that the inliner should attempt to inline
     this function into callers whenever possible, ignoring any active
     inlining size threshold for this caller.
+``builtin``
+    This indicates that the callee function at a call site should be
+    recognized as a built-in function, even though the function's
+    declaration uses the ``nobuiltin`` attribute. This is only
+    valid at call sites for direct calls to functions which are declared
+    with the ``nobuiltin`` attribute.
 ``nonlazybind``
     This attribute suppresses lazy symbol binding for the function. This
     may make calls to the function faster, at the cost of extra program
@@ -823,8 +829,9 @@
     This indicates that the callee function at a call site is not
     recognized as a built-in function. LLVM will retain the original call
     and not replace it with equivalent code based on the semantics of the
-    built-in function. This is only valid at call sites, not on function
-    declarations or definitions.
+    built-in function, unless the call site uses the ``builtin``
+    attribute. This is valid at call sites and on function declarations
+    and definitions.
 ``noduplicate``
     This attribute indicates that calls to the function cannot be
     duplicated. A call to a ``noduplicate`` function may be moved
Index: lib/IR/Attributes.cpp
===================================================================
--- lib/IR/Attributes.cpp	(revision 181984)
+++ lib/IR/Attributes.cpp	(working copy)
@@ -157,6 +157,8 @@
     return "sanitize_address";
   if (hasAttribute(Attribute::AlwaysInline))
     return "alwaysinline";
+  if (hasAttribute(Attribute::Builtin))
+    return "builtin";
   if (hasAttribute(Attribute::ByVal))
     return "byval";
   if (hasAttribute(Attribute::InlineHint))
@@ -396,6 +398,7 @@
   case Attribute::SanitizeMemory:  return 1ULL << 37;
   case Attribute::NoBuiltin:       return 1ULL << 38;
   case Attribute::Returned:        return 1ULL << 39;
+  case Attribute::Builtin:         return 1ULL << 40;
   }
   llvm_unreachable("Unsupported attribute type");
 }
Index: lib/IR/Verifier.cpp
===================================================================
--- lib/IR/Verifier.cpp	(revision 181984)
+++ lib/IR/Verifier.cpp	(working copy)
@@ -692,6 +692,7 @@
         I->getKindAsEnum() == Attribute::SanitizeMemory ||
         I->getKindAsEnum() == Attribute::MinSize ||
         I->getKindAsEnum() == Attribute::NoDuplicate ||
+        I->getKindAsEnum() == Attribute::Builtin ||
         I->getKindAsEnum() == Attribute::NoBuiltin) {
       if (!isFunction)
           CheckFailed("Attribute '" + I->getKindAsString() +
@@ -1434,6 +1435,14 @@
               "Function has metadata parameter but isn't an intrinsic", I);
   }
 
+  // If the call site has the 'builtin' attribute, verify that it's applied
+  // to a direct call to a function with the 'nobuiltin' attribute.
+  if (CS.hasFnAttr(Attribute::Builtin))
+    Assert1(CS.getCalledFunction() &&
+            CS.getCalledFunction()->hasFnAttribute(Attribute::NoBuiltin),
+            "Attribute 'builtin' can only be used in a call to a function with "
+            "the 'nobuiltin' attribute", I);
+
   visitInstruction(*I);
 }
 
Index: lib/Analysis/MemoryBuiltins.cpp
===================================================================
--- lib/Analysis/MemoryBuiltins.cpp	(revision 181984)
+++ lib/Analysis/MemoryBuiltins.cpp	(working copy)
@@ -77,7 +77,7 @@
   if (!CS.getInstruction())
     return 0;
 
-  if (CS.hasFnAttr(Attribute::NoBuiltin))
+  if (CS.isNoBuiltin())
     return 0;
 
   Function *Callee = CS.getCalledFunction();
Index: lib/AsmParser/LLParser.cpp
===================================================================
--- lib/AsmParser/LLParser.cpp	(revision 181984)
+++ lib/AsmParser/LLParser.cpp	(working copy)
@@ -810,13 +810,13 @@
   assert(Lex.getKind() == lltok::AttrGrpID);
   unsigned VarID = Lex.getUIntVal();
   std::vector<unsigned> unused;
-  LocTy NoBuiltinLoc;
+  LocTy BuiltinLoc;
   Lex.Lex();
 
   if (ParseToken(lltok::equal, "expected '=' here") ||
       ParseToken(lltok::lbrace, "expected '{' here") ||
       ParseFnAttributeValuePairs(NumberedAttrBuilders[VarID], unused, true,
-                                 NoBuiltinLoc) ||
+                                 BuiltinLoc) ||
       ParseToken(lltok::rbrace, "expected end of attribute group"))
     return true;
 
@@ -830,15 +830,15 @@
 ///   ::= <attr> | <attr> '=' <value>
 bool LLParser::ParseFnAttributeValuePairs(AttrBuilder &B,
                                           std::vector<unsigned> &FwdRefAttrGrps,
-                                          bool inAttrGrp, LocTy &NoBuiltinLoc) {
+                                          bool inAttrGrp, LocTy &BuiltinLoc) {
   bool HaveError = false;
 
   B.clear();
 
   while (true) {
     lltok::Kind Token = Lex.getKind();
-    if (Token == lltok::kw_nobuiltin)
-      NoBuiltinLoc = Lex.getLoc();
+    if (Token == lltok::kw_builtin)
+      BuiltinLoc = Lex.getLoc();
     switch (Token) {
     default:
       if (!inAttrGrp) return HaveError;
@@ -909,6 +909,7 @@
       continue;
     }
     case lltok::kw_alwaysinline:      B.addAttribute(Attribute::AlwaysInline); break;
+    case lltok::kw_builtin:           B.addAttribute(Attribute::Builtin); break;
     case lltok::kw_inlinehint:        B.addAttribute(Attribute::InlineHint); break;
     case lltok::kw_minsize:           B.addAttribute(Attribute::MinSize); break;
     case lltok::kw_naked:             B.addAttribute(Attribute::Naked); break;
@@ -1164,6 +1165,7 @@
 
     case lltok::kw_alignstack:
     case lltok::kw_alwaysinline:
+    case lltok::kw_builtin:
     case lltok::kw_inlinehint:
     case lltok::kw_minsize:
     case lltok::kw_naked:
@@ -1222,6 +1224,7 @@
 
     case lltok::kw_alignstack:
     case lltok::kw_alwaysinline:
+    case lltok::kw_builtin:
     case lltok::kw_inlinehint:
     case lltok::kw_minsize:
     case lltok::kw_naked:
@@ -2981,7 +2984,7 @@
   bool isVarArg;
   AttrBuilder FuncAttrs;
   std::vector<unsigned> FwdRefAttrGrps;
-  LocTy NoBuiltinLoc;
+  LocTy BuiltinLoc;
   std::string Section;
   unsigned Alignment;
   std::string GC;
@@ -2992,7 +2995,7 @@
       ParseOptionalToken(lltok::kw_unnamed_addr, UnnamedAddr,
                          &UnnamedAddrLoc) ||
       ParseFnAttributeValuePairs(FuncAttrs, FwdRefAttrGrps, false,
-                                 NoBuiltinLoc) ||
+                                 BuiltinLoc) ||
       (EatIfPresent(lltok::kw_section) &&
        ParseStringConstant(Section)) ||
       ParseOptionalAlignment(Alignment) ||
@@ -3000,8 +3003,8 @@
        ParseStringConstant(GC)))
     return true;
 
-  if (FuncAttrs.contains(Attribute::NoBuiltin))
-    return Error(NoBuiltinLoc, "'nobuiltin' attribute not valid on function");
+  if (FuncAttrs.contains(Attribute::Builtin))
+    return Error(BuiltinLoc, "'builtin' attribute not valid on function");
 
   // If the alignment was parsed as an attribute, move to the alignment field.
   if (FuncAttrs.hasAlignmentAttr()) {
@@ -3516,7 +3519,7 @@
   LocTy CallLoc = Lex.getLoc();
   AttrBuilder RetAttrs, FnAttrs;
   std::vector<unsigned> FwdRefAttrGrps;
-  LocTy NoBuiltinLoc;
+  LocTy BuiltinLoc;
   CallingConv::ID CC;
   Type *RetType = 0;
   LocTy RetTypeLoc;
@@ -3530,7 +3533,7 @@
       ParseValID(CalleeID) ||
       ParseParameterList(ArgList, PFS) ||
       ParseFnAttributeValuePairs(FnAttrs, FwdRefAttrGrps, false,
-                                 NoBuiltinLoc) ||
+                                 BuiltinLoc) ||
       ParseToken(lltok::kw_to, "expected 'to' in invoke") ||
       ParseTypeAndBasicBlock(NormalBB, PFS) ||
       ParseToken(lltok::kw_unwind, "expected 'unwind' in invoke") ||
@@ -3925,7 +3928,7 @@
                          bool isTail) {
   AttrBuilder RetAttrs, FnAttrs;
   std::vector<unsigned> FwdRefAttrGrps;
-  LocTy NoBuiltinLoc;
+  LocTy BuiltinLoc;
   CallingConv::ID CC;
   Type *RetType = 0;
   LocTy RetTypeLoc;
@@ -3940,7 +3943,7 @@
       ParseValID(CalleeID) ||
       ParseParameterList(ArgList, PFS) ||
       ParseFnAttributeValuePairs(FnAttrs, FwdRefAttrGrps, false,
-                                 NoBuiltinLoc))
+                                 BuiltinLoc))
     return true;
 
   // If RetType is a non-function pointer type, then this is the short syntax
Index: lib/AsmParser/LLLexer.cpp
===================================================================
--- lib/AsmParser/LLLexer.cpp	(revision 181984)
+++ lib/AsmParser/LLLexer.cpp	(working copy)
@@ -563,6 +563,7 @@
   KEYWORD(attributes);
 
   KEYWORD(alwaysinline);
+  KEYWORD(builtin);
   KEYWORD(byval);
   KEYWORD(inlinehint);
   KEYWORD(inreg);
Index: lib/AsmParser/LLParser.h
===================================================================
--- lib/AsmParser/LLParser.h	(revision 181984)
+++ lib/AsmParser/LLParser.h	(working copy)
@@ -242,7 +242,7 @@
     bool ParseUnnamedAttrGrp();
     bool ParseFnAttributeValuePairs(AttrBuilder &B,
                                     std::vector<unsigned> &FwdRefAttrGrps,
-                                    bool inAttrGrp, LocTy &NoBuiltinLoc);
+                                    bool inAttrGrp, LocTy &BuiltinLoc);
 
     // Type Parsing.
     bool ParseType(Type *&Result, bool AllowVoid = false);
Index: lib/AsmParser/LLToken.h
===================================================================
--- lib/AsmParser/LLToken.h	(revision 181984)
+++ lib/AsmParser/LLToken.h	(working copy)
@@ -95,6 +95,7 @@
     kw_attributes,
     kw_alwaysinline,
     kw_sanitize_address,
+    kw_builtin,
     kw_byval,
     kw_inlinehint,
     kw_inreg,
Index: lib/Transforms/Utils/SimplifyLibCalls.cpp
===================================================================
--- lib/Transforms/Utils/SimplifyLibCalls.cpp	(revision 181984)
+++ lib/Transforms/Utils/SimplifyLibCalls.cpp	(working copy)
@@ -1940,7 +1940,7 @@
 }
 
 Value *LibCallSimplifier::optimizeCall(CallInst *CI) {
-  if (CI->hasFnAttr(Attribute::NoBuiltin)) return 0;
+  if (CI->isNoBuiltin()) return 0;
   return Impl->optimizeCall(CI);
 }
 
Index: lib/Transforms/Scalar/SimplifyLibCalls.cpp
===================================================================
--- lib/Transforms/Scalar/SimplifyLibCalls.cpp	(revision 181984)
+++ lib/Transforms/Scalar/SimplifyLibCalls.cpp	(working copy)
@@ -153,7 +153,7 @@
     for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ) {
       // Ignore non-calls.
       CallInst *CI = dyn_cast<CallInst>(I++);
-      if (!CI || CI->hasFnAttr(Attribute::NoBuiltin)) continue;
+      if (!CI || CI->isNoBuiltin()) continue;
 
       // Ignore indirect calls and calls to non-external functions.
       Function *Callee = CI->getCalledFunction();
