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 cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits