jdoerfert created this revision.
jdoerfert added reviewers: JonChesterfield, aaron.ballman, jhuber6.
Herald added a subscriber: bollu.
Herald added a project: clang.
jdoerfert requested review of this revision.
Herald added a subscriber: sstefan1.
The `assume` attribute is a way to provide additional, arbitrary
information to the optimizer. For now, assumptions are restricted to
strings which will be accumulated for a function and emitted as comma
separated string function attribute. The key of the LLVM-IR function
attribute is `llvm.assume`. Similar to `llvm.assume` and
`__builtin_assume`, the `assume` attribute provides a user defined
assumption to the compiler.
A follow up patch will introduce an LLVM-core API to query the
assumptions attached to a function. We also expect to add more options,
e.g., expression arguments, to the `assume` attribute later on.
The `omp [begin] asssumes` pragma will leverage this attribute and
expose the functionality in the absence of OpenMP.
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D91979
Files:
clang/docs/LanguageExtensions.rst
clang/include/clang/Basic/Attr.td
clang/include/clang/Basic/AttrDocs.td
clang/lib/CodeGen/CGCall.cpp
clang/lib/Sema/SemaDeclAttr.cpp
clang/test/CodeGen/assume_attr.c
clang/test/CodeGenCXX/assume_attr.cpp
Index: clang/test/CodeGenCXX/assume_attr.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGenCXX/assume_attr.cpp
@@ -0,0 +1,120 @@
+// RUN: %clang_cc1 -emit-llvm -triple i386-linux-gnu %s -o - | FileCheck %s
+// RUN: %clang_cc1 -x c++ -emit-pch -o %t %s
+// RUN: %clang_cc1 -include-pch %t %s -emit-llvm -o - | FileCheck %s
+// expected-no-diagnostics
+
+#ifndef HEADER
+#define HEADER
+
+/// foo: declarations only
+
+__attribute__((assume("foo:before1"))) void foo();
+
+__attribute__((assume("foo:before2")))
+__attribute__((assume("foo:before3"))) void
+foo();
+
+/// baz: static function declarations and a definition
+
+__attribute__((assume("baz:before1"))) static void baz();
+
+__attribute__((assume("baz:before2")))
+__attribute__((assume("baz:before3"))) static void
+baz();
+
+// Definition
+__attribute__((assume("baz:def1,baz:def2"))) static void baz() { foo(); }
+
+__attribute__((assume("baz:after"))) static void baz();
+
+/// bar: external function declarations and a definition
+
+__attribute__((assume("bar:before1"))) void bar();
+
+__attribute__((assume("bar:before2")))
+__attribute__((assume("bar:before3"))) void
+bar();
+
+// Definition
+__attribute__((assume("bar:def1,bar:def2"))) void bar() { baz(); }
+
+__attribute__((assume("bar:after"))) void bar();
+
+/// back to foo
+
+__attribute__((assume("foo:after"))) void foo();
+
+/// class tests
+class C {
+ __attribute__((assume("C:private_method"))) void private_method();
+ __attribute__((assume("C:private_static"))) static void private_static();
+
+public:
+ __attribute__((assume("C:public_method1"))) void public_method();
+ __attribute__((assume("C:public_static1"))) static void public_static();
+};
+
+__attribute__((assume("C:public_method2"))) void C::public_method() {
+ private_method();
+}
+
+__attribute__((assume("C:public_static2"))) void C::public_static() {
+ private_static();
+}
+
+/// template tests
+template <typename T>
+__attribute__((assume("template_func<T>"))) void template_func() {}
+
+template <>
+__attribute__((assume("template_func<float>"))) void template_func<float>() {}
+
+template <>
+void template_func<int>() {}
+
+template <typename T>
+struct S {
+ __attribute__((assume("S<T>::method"))) void method();
+};
+
+template <>
+__attribute__((assume("S<float>::method"))) void S<float>::method() {}
+
+template <>
+void S<int>::method() {}
+
+// CHECK: define void @_Z3barv() #0
+// CHECK: define internal void @_ZL3bazv() #1
+// CHECK: define void @_ZN1C13public_methodEv(%class.C* %this) #2
+// CHECK: declare void @_ZN1C14private_methodEv(%class.C*) #3
+// CHECK: define void @_ZN1C13public_staticEv() #4
+// CHECK: declare void @_ZN1C14private_staticEv() #5
+// CHECK: define void @_Z13template_funcIfEvv() #6
+// CHECK: define void @_Z13template_funcIiEvv() #7
+// CHECK: define void @_ZN1SIfE6methodEv(%struct.S* %this) #8
+// CHECK: define void @_ZN1SIiE6methodEv(%struct.S.0* %this) #9
+// CHECK: declare void @_Z3foov() #10
+// CHECK: attributes #0
+// CHECK-SAME: "llvm.assume"="bar:before1,bar:before2,bar:before3,bar:def1,bar:def2"
+// CHECK: attributes #1
+// CHECK-SAME: "llvm.assume"="baz:before1,baz:before2,baz:before3,baz:def1,baz:def2,baz:after"
+// CHECK: attributes #2
+// CHECK-SAME: "llvm.assume"="C:public_method1,C:public_method2"
+// CHECK: attributes #3
+// CHECK-SAME: "llvm.assume"="C:private_method"
+// CHECK: attributes #4
+// CHECK-SAME: "llvm.assume"="C:public_static1,C:public_static2"
+// CHECK: attributes #5
+// CHECK-SAME: "llvm.assume"="C:private_static"
+// CHECK: attributes #6
+// CHECK-SAME: "llvm.assume"="template_func<T>,template_func<float>"
+// CHECK: attributes #7
+// CHECK-SAME: "llvm.assume"="template_func<T>"
+// CHECK: attributes #8
+// CHECK-SAME: "llvm.assume"="S<T>::method,S<float>::method"
+// CHECK: attributes #9
+// CHECK-SAME: "llvm.assume"="S<T>::method"
+// CHECK: attributes #10
+// CHECK-SAME: "llvm.assume"="foo:before1,foo:before2,foo:before3"
+
+#endif
Index: clang/test/CodeGen/assume_attr.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/assume_attr.c
@@ -0,0 +1,59 @@
+// RUN: %clang_cc1 -emit-llvm -triple i386-linux-gnu %s -o - | FileCheck %s
+// RUN: %clang_cc1 -x c -emit-pch -o %t %s
+// RUN: %clang_cc1 -include-pch %t %s -emit-llvm -o - | FileCheck %s
+// expected-no-diagnostics
+
+// TODO: for "foo" and "bar", "after" is not added as it appears "after" the first use or definition respectively. There might be a way to allow that.
+
+// CHECK: define{{.*}} void @bar() #0
+// CHECK: define{{.*}} void @baz() #1
+// CHECK: declare{{.*}} void @foo() #2
+// CHECK: attributes #0
+// CHECK-SAME: "llvm.assume"="bar:before1,bar:before2,bar:before3,bar:def1,bar:def2"
+// CHECK: attributes #1
+// CHECK-SAME: "llvm.assume"="baz:before1,baz:before2,baz:before3,baz:def1,baz:def2,baz:after"
+// CHECK: attributes #2
+// CHECK-SAME: "llvm.assume"="foo:before1,foo:before2,foo:before3"
+
+#ifndef HEADER
+#define HEADER
+
+/// foo: declarations only
+
+__attribute__((assume("foo:before1"))) void foo(void);
+
+__attribute__((assume("foo:before2")))
+__attribute__((assume("foo:before3"))) void
+foo(void);
+
+/// baz: static function declarations and a definition
+
+__attribute__((assume("baz:before1"))) static void baz(void);
+
+__attribute__((assume("baz:before2")))
+__attribute__((assume("baz:before3"))) static void
+baz(void);
+
+// Definition
+__attribute__((assume("baz:def1,baz:def2"))) static void baz(void) { foo(); }
+
+__attribute__((assume("baz:after"))) static void baz(void);
+
+/// bar: external function declarations and a definition
+
+__attribute__((assume("bar:before1"))) void bar(void);
+
+__attribute__((assume("bar:before2")))
+__attribute__((assume("bar:before3"))) void
+bar(void);
+
+// Definition
+__attribute__((assume("bar:def1,bar:def2"))) void bar(void) { baz(); }
+
+__attribute__((assume("bar:after"))) void bar(void);
+
+/// back to foo
+
+__attribute__((assume("foo:after"))) void foo(void);
+
+#endif
Index: clang/lib/Sema/SemaDeclAttr.cpp
===================================================================
--- clang/lib/Sema/SemaDeclAttr.cpp
+++ clang/lib/Sema/SemaDeclAttr.cpp
@@ -7727,6 +7727,9 @@
case ParsedAttr::AT_Unavailable:
handleAttrWithMessage<UnavailableAttr>(S, D, AL);
break;
+ case ParsedAttr::AT_Assumption:
+ handleAttrWithMessage<AssumptionAttr>(S, D, AL);
+ break;
case ParsedAttr::AT_ObjCDirect:
handleObjCDirectAttr(S, D, AL);
break;
Index: clang/lib/CodeGen/CGCall.cpp
===================================================================
--- clang/lib/CodeGen/CGCall.cpp
+++ clang/lib/CodeGen/CGCall.cpp
@@ -2016,6 +2016,18 @@
llvm::toStringRef(CodeGenOpts.UniformWGSize));
}
}
+
+ std::string AssumptionValueStr;
+ for (AssumptionAttr *AssumptionA :
+ TargetDecl->specific_attrs<AssumptionAttr>()) {
+ std::string AS = AssumptionA->getAssumption().str();
+ if (!AS.empty() && !AssumptionValueStr.empty())
+ AssumptionValueStr += ",";
+ AssumptionValueStr += AS;
+ }
+
+ if (!AssumptionValueStr.empty())
+ FuncAttrs.addAttribute("llvm.assume", AssumptionValueStr);
}
// Attach "no-builtins" attributes to:
Index: clang/include/clang/Basic/AttrDocs.td
===================================================================
--- clang/include/clang/Basic/AttrDocs.td
+++ clang/include/clang/Basic/AttrDocs.td
@@ -3918,6 +3918,27 @@
}];
}
+def AssumptionDocs : Documentation {
+ let Category = DocCatFunction;
+ let Heading = "assume";
+ let Content = [{
+Clang supports the ``__attribute__((assume("assumption")))`` attribute to
+provide additional information to the optimizer. The string-literal, here
+"assumption", will be attached to the function declaration such that later
+analysis and optimization passes can assume the "assumption" to hold.
+This is similar to :ref:`__builtin_assume <langext-__builtin_assume>` but instead of an
+expression that can be assumed to be non-zero, the assumption is expressed as
+a string and it holds for the entire function.
+
+A function can have multiple assume attributes and they propagate from prior
+declarations to later definitions. Multiple assumptions are aggregated into a
+single comma separated string. Thus, one can provide multiple assumptions via
+a comma separated string, i.a.,
+``__attribute__((assume("assumption1,assumption2")))``.
+
+}];
+}
+
def NoStackProtectorDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
Index: clang/include/clang/Basic/Attr.td
===================================================================
--- clang/include/clang/Basic/Attr.td
+++ clang/include/clang/Basic/Attr.td
@@ -3464,6 +3464,14 @@
}];
}
+def Assumption : InheritableAttr {
+ let Spellings = [Clang<"assume">];
+ let Subjects = SubjectList<[Function]>;
+ let InheritEvenIfAlreadyPresent = 1;
+ let Documentation = [AssumptionDocs];
+ let Args = [StringArgument<"Assumption">];
+}
+
def InternalLinkage : InheritableAttr {
let Spellings = [Clang<"internal_linkage">];
let Subjects = SubjectList<[Var, Function, CXXRecord]>;
Index: clang/docs/LanguageExtensions.rst
===================================================================
--- clang/docs/LanguageExtensions.rst
+++ clang/docs/LanguageExtensions.rst
@@ -1740,6 +1740,8 @@
<langext-vectors>` instead of builtins, in order to reduce the number of
builtins that we need to implement.
+.. _langext-__builtin_assume:
+
``__builtin_assume``
------------------------------
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits