gchatelet updated this revision to Diff 222163.
gchatelet added a comment.
- Update documentation and rebase
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D68028/new/
https://reviews.llvm.org/D68028
Files:
clang/include/clang/Basic/Attr.td
clang/include/clang/Basic/AttrDocs.td
clang/include/clang/Sema/Sema.h
clang/lib/CodeGen/CGCall.cpp
clang/lib/Sema/SemaDeclAttr.cpp
clang/test/CodeGen/no-builtin.c
clang/test/Misc/pragma-attribute-supported-attributes-list.test
clang/test/Sema/no-builtin.c
Index: clang/test/Sema/no-builtin.c
===================================================================
--- /dev/null
+++ clang/test/Sema/no-builtin.c
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -S -emit-llvm -o - -verify %s
+
+void foo() __attribute__((no_builtin)) {} // expected-error {{'no_builtin' attribute takes at least 1 argument}}
+
+void bar() __attribute__((no_builtin())) {} // expected-error {{'no_builtin' attribute takes at least 1 argument}}
+
+void invalid_builtin() __attribute__((no_builtin("not_a_builtin"))) {} // expected-error {{use of unknown builtin not_a_builtin}}
+
+int __attribute__((no_builtin("*"))) variable; // expected-warning {{'no_builtin' attribute only applies to functions}}
Index: clang/test/Misc/pragma-attribute-supported-attributes-list.test
===================================================================
--- clang/test/Misc/pragma-attribute-supported-attributes-list.test
+++ clang/test/Misc/pragma-attribute-supported-attributes-list.test
@@ -74,6 +74,7 @@
// CHECK-NEXT: NSConsumed (SubjectMatchRule_variable_is_parameter)
// CHECK-NEXT: NSConsumesSelf (SubjectMatchRule_objc_method)
// CHECK-NEXT: Naked (SubjectMatchRule_function)
+// CHECK-NEXT: NoBuiltin (SubjectMatchRule_function)
// CHECK-NEXT: NoCommon (SubjectMatchRule_variable)
// CHECK-NEXT: NoDebug (SubjectMatchRule_type_alias, SubjectMatchRule_hasType_functionType, SubjectMatchRule_objc_method, SubjectMatchRule_variable_not_is_parameter)
// CHECK-NEXT: NoDestroy (SubjectMatchRule_variable)
Index: clang/test/CodeGen/no-builtin.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/no-builtin.c
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -S -emit-llvm -o - %s | FileCheck %s
+
+// CHECK-LABEL: define void @foo_no_mempcy() #0
+void foo_no_mempcy() __attribute__((no_builtin("memcpy"))) {}
+
+// CHECK-LABEL: define void @foo_no_builtins() #1
+void foo_no_builtins() __attribute__((no_builtin("*"))) {}
+
+// CHECK-LABEL: define void @foo_no_mempcy_memset() #2
+void foo_no_mempcy_memset() __attribute__((no_builtin("memset", "memcpy"))) {}
+
+// CHECK-LABEL: define void @separate_attrs() #2
+void separate_attrs() __attribute__((no_builtin("memset"))) __attribute__((no_builtin("memcpy"))) {}
+
+// CHECK-LABEL: define void @wildcard_wins() #1
+void wildcard_wins() __attribute__((no_builtin("memset"))) __attribute__((no_builtin("*"))) __attribute__((no_builtin("memcpy"))) {}
+
+// CHECK: attributes #0 = {{{.*}}"no-builtin-memcpy"{{.*}}}
+// CHECK: attributes #1 = {{{.*}}"no-builtins"{{.*}}}
+// CHECK: attributes #2 = {{{.*}}"no-builtin-memcpy"{{.*}}"no-builtin-memset"{{.*}}}
Index: clang/lib/Sema/SemaDeclAttr.cpp
===================================================================
--- clang/lib/Sema/SemaDeclAttr.cpp
+++ clang/lib/Sema/SemaDeclAttr.cpp
@@ -1068,6 +1068,62 @@
S.Context, AL, Cond, Msg, DiagType, ArgDependent, cast<NamedDecl>(D)));
}
+NoBuiltinAttr *
+Sema::mergeNoBuiltinAttr(Sema &S, Decl *D, const AttributeCommonInfo &CI,
+ llvm::ArrayRef<StringRef> FunctionNames) {
+ const StringRef Wildcard = "*";
+ llvm::SmallSetVector<StringRef, 8> FunctionNamesSet;
+
+ // Insert previous NoBuiltin attributes.
+ if (D->hasAttr<NoBuiltinAttr>())
+ for (StringRef FunctionName : D->getAttr<NoBuiltinAttr>()->functionNames())
+ FunctionNamesSet.insert(FunctionName);
+ // Insert new NoBuiltin attributes.
+ for (StringRef FunctionName : FunctionNames)
+ FunctionNamesSet.insert(FunctionName);
+
+ // Wildcard is a superset of all builtins, we keep only this one.
+ if (FunctionNamesSet.count(Wildcard) > 0) {
+ FunctionNamesSet.clear();
+ FunctionNamesSet.insert(Wildcard);
+ }
+
+ assert((FunctionNamesSet.count(Wildcard) == 0) ||
+ (FunctionNamesSet.size() == 1) && "Wildcard must be on its own");
+
+ llvm::SmallVector<StringRef, 8> UniqFunctionNames =
+ FunctionNamesSet.takeVector();
+ llvm::sort(UniqFunctionNames);
+
+ if (D->hasAttr<NoBuiltinAttr>())
+ D->dropAttr<NoBuiltinAttr>();
+
+ return ::new (S.Context) NoBuiltinAttr(
+ S.Context, CI, UniqFunctionNames.data(), UniqFunctionNames.size());
+}
+
+static void handleNoBuiltin(Sema &S, Decl *D, const ParsedAttr &AL) {
+ if (!checkAttributeAtLeastNumArgs(S, AL, 1))
+ return;
+
+ llvm::SmallVector<StringRef, 8> FunctionNames;
+ for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I) {
+ StringRef FunctionName;
+ SourceLocation LiteralLoc;
+ if (!S.checkStringLiteralArgumentAttr(AL, I, FunctionName, &LiteralLoc))
+ return;
+
+ bool IsValidBuiltin = Builtin::Context::isBuiltinFunc(FunctionName.data());
+ bool IsValidFunctionName = FunctionName == "*" || IsValidBuiltin;
+ if (!IsValidFunctionName)
+ S.Diag(LiteralLoc, diag::warn_builtin_unknown) << FunctionName;
+
+ FunctionNames.push_back(FunctionName);
+ }
+
+ D->addAttr(S.mergeNoBuiltinAttr(S, D, AL, FunctionNames));
+}
+
static void handlePassObjectSizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (D->hasAttr<PassObjectSizeAttr>()) {
S.Diag(D->getBeginLoc(), diag::err_attribute_only_once_per_parameter) << AL;
@@ -6578,6 +6634,9 @@
case ParsedAttr::AT_DiagnoseIf:
handleDiagnoseIfAttr(S, D, AL);
break;
+ case ParsedAttr::AT_NoBuiltin:
+ handleNoBuiltin(S, D, AL);
+ break;
case ParsedAttr::AT_ExtVectorType:
handleExtVectorTypeAttr(S, D, AL);
break;
Index: clang/lib/CodeGen/CGCall.cpp
===================================================================
--- clang/lib/CodeGen/CGCall.cpp
+++ clang/lib/CodeGen/CGCall.cpp
@@ -1849,6 +1849,18 @@
FuncAttrs.addAttribute(llvm::Attribute::NoDuplicate);
if (TargetDecl->hasAttr<ConvergentAttr>())
FuncAttrs.addAttribute(llvm::Attribute::Convergent);
+ if (const auto *Attr = TargetDecl->getAttr<NoBuiltinAttr>()) {
+ bool HasWildcard = llvm::is_contained(Attr->functionNames(), "*");
+ if (HasWildcard)
+ FuncAttrs.addAttribute("no-builtins");
+ else
+ for (StringRef FunctionName : Attr->functionNames()) {
+ SmallString<32> AttributeName;
+ AttributeName += "no-builtin-";
+ AttributeName += FunctionName;
+ FuncAttrs.addAttribute(AttributeName);
+ }
+ }
if (const FunctionDecl *Fn = dyn_cast<FunctionDecl>(TargetDecl)) {
AddAttributesFromFunctionProtoType(
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -2684,6 +2684,9 @@
MSInheritanceAttr *
mergeMSInheritanceAttr(Decl *D, const AttributeCommonInfo &CI, bool BestCase,
MSInheritanceAttr::Spelling SemanticSpelling);
+ NoBuiltinAttr *mergeNoBuiltinAttr(Sema &S, Decl *D,
+ const AttributeCommonInfo &CI,
+ llvm::ArrayRef<StringRef> FunctionNames);
FormatAttr *mergeFormatAttr(Decl *D, const AttributeCommonInfo &CI,
IdentifierInfo *Format, int FormatIdx,
int FirstArg);
Index: clang/include/clang/Basic/AttrDocs.td
===================================================================
--- clang/include/clang/Basic/AttrDocs.td
+++ clang/include/clang/Basic/AttrDocs.td
@@ -4391,3 +4391,37 @@
}];
}
+
+def NoBuiltinDocs : Documentation {
+ let Category = DocCatFunction;
+ let Content = [{
+.. Note:: This attribute is not yet fully implemented, it is validated but has
+no effect on the generated code.
+
+The ``__attribute__((no_builtin))`` is similar to the ``-fno-builtin`` flag
+except it is specific to the body of a function.
+
+It accepts one or more strings corresponding to the name of the builtin
+(e.g. "memcpy", "memset") or "*" which disables all builtins at once.
+
+.. code-block:: c++
+
+ // The compiler is not allowed to replace parts of foo's body with builtins.
+ void foo(char* data, size_t count) __attribute__((no_builtin("*"))) {
+ // The compiler is not allowed to convert the loop into
+ // `__builtin_memset(data, 0xFE, count);`.
+ for (size_t i = 0; i < count; ++i)
+ data[i] = 0xFE;
+ }
+
+ // The compiler is not allowed to replace parts of bar's body with the memcpy
+ // builtin.
+ void bar(char* data, size_t count) __attribute__((no_builtin("memcpy"))) {
+ // The compiler is allowed to convert the loop into
+ // `__builtin_memset(data, 0xFE, count);` but cannot generate any
+ // `__builtin_memcpy`
+ for (size_t i = 0; i < count; ++i)
+ data[i] = 0xFE;
+ }
+ }];
+}
Index: clang/include/clang/Basic/Attr.td
===================================================================
--- clang/include/clang/Basic/Attr.td
+++ clang/include/clang/Basic/Attr.td
@@ -3392,3 +3392,10 @@
let Subjects = SubjectList<[NonParmVar, Function, Block, ObjCMethod]>;
let Documentation = [ObjCExternallyRetainedDocs];
}
+
+def NoBuiltin : InheritableAttr {
+ let Spellings = [Clang<"no_builtin">];
+ let Args = [VariadicStringArgument<"FunctionNames">];
+ let Subjects = SubjectList<[Function]>;
+ let Documentation = [NoBuiltinDocs];
+}
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits