diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -5034,7 +5034,16 @@ const FunctionDecl *FD = cast(GD.getDecl()); if (auto builtinID = FD->getBuiltinID()) { + std::string NoBuiltinFD = ("no-builtin-" + FD->getName()).str(); + std::string NoBuiltins = "no-builtins"; std::string FDInlineName = (FD->getName() + ".inline").str(); + + bool IsPredefinedLibFunction = + CGF.getContext().BuiltinInfo.isPredefinedLibFunction(builtinID); + bool HasAttributeNoBuiltin = + CGF.CurFn->getAttributes().hasFnAttr(NoBuiltinFD) || + CGF.CurFn->getAttributes().hasFnAttr(NoBuiltins); + // When directing calling an inline builtin, call it through it's mangled // name to make it clear it's not the actual builtin. if (CGF.CurFn->getName() != FDInlineName && @@ -5054,8 +5063,11 @@ // Replaceable builtins provide their own implementation of a builtin. If we // are in an inline builtin implementation, avoid trivial infinite - // recursion. - else + // recursion. Honor __attribute__((no_builtin("foo"))) or + // __attribute((no_builtin("*"))) on the current function unless foo is + // not a predefined library function which means we must generate the + // builtin no matter what. + else if (!IsPredefinedLibFunction || !HasAttributeNoBuiltin) return CGCallee::forBuiltin(builtinID, FD); } diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -1142,7 +1142,8 @@ if (!S.checkStringLiteralArgumentAttr(AL, I, BuiltinName, &LiteralLoc)) return; - if (Builtin::Context::isBuiltinFunc(BuiltinName)) + bool ParsedAttrIsWildCard = BuiltinName == kWildcard; + if (Builtin::Context::isBuiltinFunc(BuiltinName) || ParsedAttrIsWildCard) AddBuiltinName(BuiltinName); else S.Diag(LiteralLoc, diag::warn_attribute_no_builtin_invalid_builtin_name) diff --git a/clang/test/CodeGen/no-builtin-2.c b/clang/test/CodeGen/no-builtin-2.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/no-builtin-2.c @@ -0,0 +1,63 @@ +// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s + +typedef typeof(sizeof(0)) size_t; + +void bar(char *s); +void *memset(void *s, int c, size_t n); +void *memcpy(void *d, const void *s, size_t n); +void *memmove(void *d, const void *s, size_t n); + +// CHECK: define{{.*}} void @foo1({{.*}}) #[[NO_NOBUILTIN:[0-9]+]] +// CHECK: call void @bar +// CHECK: call void @llvm.memset +// CHECK: call void @llvm.memcpy +// CHECK: call void @llvm.memmove +void foo1(char *s, char *d, size_t n) { + bar(s); + memset(s, 0, n); + memcpy(d, s, n); + memmove(d, s, n); +} + +// CHECK: define{{.*}} void @foo2({{.*}}) #[[NOBUILTIN_MEMSET:[0-9]+]] +// CHECK: call void @bar +// CHECK: {{.*}}call {{.*}} @memset +// CHECK: call void @llvm.memcpy +// CHECK: call void @llvm.memmove +void foo2(char *s, char *d, size_t n) __attribute__((no_builtin("memset"))) { + bar(s); + memset(s, 1, n); + memcpy(d, s, n); + memmove(d, s, n); +} + +// CHECK: define{{.*}} void @foo3({{.*}}) #[[NOBUILTIN_MEMSET_MEMCPY:[0-9]+]] +// CHECK: call void @bar +// CHECK: {{.*}}call {{.*}} @memset +// CHECK: {{.*}}call {{.*}} @memcpy +// CHECK: call void @llvm.memmove +void foo3(char *s, char *d, size_t n) __attribute__((no_builtin("memset", "memcpy"))) { + bar(s); + memset(s, 2, n); + memcpy(d, s, n); + memmove(d, s, n); +} + +// CHECK: define{{.*}} void @foo4({{.*}}) #[[NOBUILTINS:[0-9]+]] +// CHECK: call void @bar +// CHECK: {{.*}}call {{.*}} @memset +// CHECK: {{.*}}call {{.*}} @memcpy +// CHECK: {{.*}}call {{.*}} @memmove +void foo4(char *s, char *d, size_t n) __attribute__((no_builtin("*"))) { + bar(s); + memset(s, 2, n); + memcpy(d, s, n); + memmove(s, d, n); +} + +// CHECK-NOT: attributes #[[NO_NOBUILTIN]] = {{{.*}}"no-builtin-memset"{{.*}}} +// CHECK-NOT: attributes #[[NO_NOBUILTIN]] = {{{.*}}"no-builtin-memcpy"{{.*}}"no-builtin-memset"{{.*}}} +// CHECK-NOT: attributes #[[NO_NOBUILTIN]] = {{{.*}}"no-builtins"{{.*}}} +// CHECK: attributes #[[NOBUILTIN_MEMSET]] = {{{.*}}"no-builtin-memset"{{.*}}} +// CHECK: attributes #[[NOBUILTIN_MEMSET_MEMCPY]] = {{{.*}}"no-builtin-memcpy"{{.*}}"no-builtin-memset"{{.*}}} +// CHECK: attributes #[[NOBUILTINS]] = {{{.*}}"no-builtins"{{.*}}}