On Tue, Aug 26, 2014 at 11:35 AM, Hal Finkel <[email protected]> wrote:
> ----- Original Message -----
>> From: "Aaron Ballman" <[email protected]>
>> To: [email protected]
>> Cc: "Hal Finkel" <[email protected]>, "Michael Spencer" 
>> <[email protected]>, "Richard Smith"
>> <[email protected]>, "Alexey Bataev" <[email protected]>, "llvm cfe" 
>> <[email protected]>,
>> "nurmukhametov alex" <[email protected]>
>> Sent: Tuesday, August 26, 2014 9:58:50 AM
>> Subject: Re: [PATCH] align_value attribute in Clang
>>
>> On Mon, Aug 25, 2014 at 4:51 PM, [email protected] <[email protected]>
>> wrote:
>> > An updated patch, accounting for review comments -- but this does
>> > not yet properly treat the attribute as a type attribute (so that
>> > it will be inherited by auto, etc.). I still need to work on that
>> > aspect, and I'll post another revision once I have those semantics
>> > working.
>> >
>> > http://reviews.llvm.org/D4635
>> >
>> > Files:
>> >   include/clang/Basic/Attr.td
>> >   include/clang/Basic/AttrDocs.td
>> >   include/clang/Basic/DiagnosticSemaKinds.td
>> >   include/clang/Sema/AttributeList.h
>> >   include/clang/Sema/Sema.h
>> >   lib/CodeGen/CGCall.cpp
>> >   lib/Sema/SemaDeclAttr.cpp
>> >   lib/Sema/SemaTemplateInstantiateDecl.cpp
>> >   test/CodeGen/align_value.cpp
>> >   test/Sema/align_value.c
>> >   test/SemaCXX/align_value.cpp
>>
>> This patch looks like it's coming along nicely! Comments below.
>>
>> > Index: include/clang/Basic/Attr.td
>> > ===================================================================
>> > --- include/clang/Basic/Attr.td
>> > +++ include/clang/Basic/Attr.td
>> > @@ -354,6 +354,23 @@
>> >    let Documentation = [Undocumented];
>> >  }
>> >
>> > +def AlignValue : Attr {
>> > +  let Spellings = [
>> > +                   // Unfortunately, this is semantically an
>> > assertion, not a
>> > +                   // directive (something else must ensure the
>> > alignment), so
>> > +                   // aligned_value is a probably a better name.
>> > We might want
>> > +                   // to add an aligned_value spelling in the
>> > future (and a
>> > +                   // corresponding C++ attribute), but this can
>> > be done later
>> > +                   // once we decide if we also want them to have
>> > +                   // slightly-different semantics than Intel's
>> > align_value.
>> > +                   GNU<"align_value">
>> > +                   // Intel's compiler on Windows also supports:
>> > +                   // , Declspec<"align_value">
>> > +                  ];
>> > +  let Args = [ExprArgument<"Alignment">];
>> > +  let Documentation = [AlignValueDocs];
>>
>> Since it may apply only to typedefs and variables, would it make
>> sense
>> to add a Subjects?
>>
>> > +}
>> > +
>> >  def AlignMac68k : InheritableAttr {
>> >    // This attribute has no spellings as it is only ever created
>> >    implicitly.
>> >    let Spellings = [];
>> > Index: include/clang/Basic/AttrDocs.td
>> > ===================================================================
>> > --- include/clang/Basic/AttrDocs.td
>> > +++ include/clang/Basic/AttrDocs.td
>> > @@ -987,6 +987,25 @@
>> >    }];
>> >  }
>> >
>> > +def AlignValueDocs : Documentation {
>> > +  let Category = DocCatType;
>> > +  let Content = [{
>> > +The align_value attribute can be added to the typedef of a pointer
>> > type or the
>> > +declaration of a variable of pointer or reference type. It
>> > specifies that the
>> > +pointer will point to, or the reference will bind to, only objects
>> > with at
>> > +least the provided alignment. This alignment value must be some
>> > positive power
>> > +of 2.
>> > +
>> > +   .. code-block:: c
>> > +
>> > +     typedef double * aligned_double_ptr
>> > __attribute__((align_value(64)));
>> > +     void foo(double & x  __attribute__((align_value(128)),
>> > +              aligned_double_ptr y) { ... }
>> > +
>> > +A C++ attribute clang::align_value is also provided.
>>
>> This doesn't appear to be the case judging by the spelling for the
>> attribute. There's no CXX11 spelling specified.
>
> Thanks, docs got out of sync after I changes my mind about adding the C++ 
> attribute in this patch :(

No worries!

>
>>
>> > +  }];
>> > +}
>> > +
>> >  def MSInheritanceDocs : Documentation {
>> >    let Category = DocCatType;
>> >    let Heading = "__single_inhertiance, __multiple_inheritance,
>> >    __virtual_inheritance";
>> > Index: include/clang/Basic/DiagnosticSemaKinds.td
>> > ===================================================================
>> > --- include/clang/Basic/DiagnosticSemaKinds.td
>> > +++ include/clang/Basic/DiagnosticSemaKinds.td
>> > @@ -1908,8 +1908,12 @@
>> >    "Neon vector size must be 64 or 128 bits">;
>> >  def err_attribute_unsupported : Error<
>> >    "%0 attribute is not supported for this target">;
>> > +// The err_*_attribute_argument_not_int are seperate because
>> > they're used by
>> > +// VerifyIntegerConstantExpression.
>> >  def err_aligned_attribute_argument_not_int : Error<
>> >    "'aligned' attribute requires integer constant">;
>> > +def err_align_value_attribute_argument_not_int : Error<
>> > +  "'align_value' attribute requires integer constant">;
>> >  def err_alignas_attribute_wrong_decl_type : Error<
>> >    "%0 attribute cannot be applied to a %select{function
>> >    parameter|"
>> >    "variable with 'register' storage class|'catch'
>> >    variable|bit-field}1">;
>> > @@ -1945,6 +1949,9 @@
>> >  def warn_attribute_return_pointers_only : Warning<
>> >    "%0 attribute only applies to return values that are pointers">,
>> >    InGroup<IgnoredAttributes>;
>> > +def warn_attribute_pointer_or_reference_only : Warning<
>> > +  "%0 attribute only applies to a pointer or reference (%1 is
>> > invalid)">,
>> > +  InGroup<IgnoredAttributes>;
>> >  def err_attribute_no_member_pointers : Error<
>> >    "%0 attribute cannot be used with pointers to members">;
>> >  def err_attribute_invalid_implicit_this_argument : Error<
>> > @@ -2181,7 +2188,7 @@
>> >    "functions, methods and blocks|functions, methods, and classes|"
>> >    "functions, methods, and parameters|classes|variables|methods|"
>> >    "variables, functions and labels|fields and global
>> >    variables|structs|"
>> > -  "variables, functions and tag types|thread-local variables|"
>> > +  "variables and tag types|thread-local variables|"
>>
>> This change seems somewhat unrelated to this patch -- your attribute
>> doesn't appertain to tags, but typedefs. I think you may want to add
>> a
>> new entry to this for "typedefs and variables" instead.
>
> Does "tag type" mean an empty struct?

Tag type means class, struct, union or enum (corresponds to a TagDecl).

>
>>
>> >    "variables and fields|variables, data members and tag types|"
>> >    "types and namespaces|Objective-C interfaces|methods and
>> >    properties|"
>> >    "struct or union|struct, union or class|types|"
>> > Index: include/clang/Sema/AttributeList.h
>> > ===================================================================
>> > --- include/clang/Sema/AttributeList.h
>> > +++ include/clang/Sema/AttributeList.h
>> > @@ -827,7 +827,7 @@
>> >    ExpectedVariableFunctionOrLabel,
>> >    ExpectedFieldOrGlobalVar,
>> >    ExpectedStruct,
>> > -  ExpectedVariableFunctionOrTag,
>> > +  ExpectedVariableOrTag,
>> >    ExpectedTLSVar,
>> >    ExpectedVariableOrField,
>> >    ExpectedVariableFieldOrTag,
>> > Index: include/clang/Sema/Sema.h
>> > ===================================================================
>> > --- include/clang/Sema/Sema.h
>> > +++ include/clang/Sema/Sema.h
>> > @@ -7328,6 +7328,11 @@
>> >    void AddAlignedAttr(SourceRange AttrRange, Decl *D,
>> >    TypeSourceInfo *T,
>> >                        unsigned SpellingListIndex, bool
>> >                        IsPackExpansion);
>> >
>> > +  /// AddAlignValueAttr - Adds an align_value attribute to a
>> > particular
>> > +  /// declaration.
>> > +  void AddAlignValueAttr(SourceRange AttrRange, Decl *D, Expr *E,
>> > +                         unsigned SpellingListIndex);
>> > +
>> >    // OpenMP directives and clauses.
>> >  private:
>> >    void *VarDataSharingAttributesStack;
>> > Index: lib/CodeGen/CGCall.cpp
>> > ===================================================================
>> > --- lib/CodeGen/CGCall.cpp
>> > +++ lib/CodeGen/CGCall.cpp
>> > @@ -1617,6 +1617,25 @@
>> >                                                    AI->getArgNo() +
>> >                                                    1,
>> >                                                    
>> > llvm::Attribute::NonNull));
>> >            }
>> > +
>> > +          const auto *AVAttr = PVD->getAttr<AlignValueAttr>();
>> > +          if (!AVAttr)
>> > +            if (const auto *TOTy = dyn_cast<TypedefType>(OTy))
>> > +              AVAttr = TOTy->getDecl()->getAttr<AlignValueAttr>();
>> > +          if (AVAttr) {
>> > +            llvm::Value *AlignmentValue =
>> > +              EmitScalarExpr(AVAttr->getAlignment());
>> > +            llvm::ConstantInt *AlignmentCI =
>> > +              cast<llvm::ConstantInt>(AlignmentValue);
>> > +            unsigned Alignment =
>> > +              std::min((unsigned) AlignmentCI->getZExtValue(),
>> > +                       +llvm::Value::MaximumAlignment);
>>
>> Why the +?
>
> Because it forces evaluation in order to prevent debug builds from having a 
> link time dependency on Value.o. It appears this way everywhere in the 
> codebase (both in Clang and in LLVM). We should probably fix this somehow, 
> but I'm not sure how, and that's a separate matter.

Huh, neat, I hadn't noticed that. Thank you for the education!

>
>>
>> > +
>> > +            llvm::AttrBuilder Attrs;
>> > +            Attrs.addAlignmentAttr(Alignment);
>> > +            AI->addAttr(llvm::AttributeSet::get(getLLVMContext(),
>> > +                                                  AI->getArgNo() +
>> > 1, Attrs));
>> > +          }
>> >          }
>> >
>> >          if (Arg->getType().isRestrictQualified())
>> > Index: lib/Sema/SemaDeclAttr.cpp
>> > ===================================================================
>> > --- lib/Sema/SemaDeclAttr.cpp
>> > +++ lib/Sema/SemaDeclAttr.cpp
>> > @@ -2691,6 +2691,61 @@
>> >                            Attr.getAttributeSpellingListIndex()));
>> >  }
>> >
>> > +static void handleAlignValueAttr(Sema &S, Decl *D,
>> > +                                   const AttributeList &Attr) {
>>
>> Formatting?
>>
>> > +  S.AddAlignValueAttr(Attr.getRange(), D, Attr.getArgAsExpr(0),
>> > +                      Attr.getAttributeSpellingListIndex());
>> > +}
>> > +
>> > +void Sema::AddAlignValueAttr(SourceRange AttrRange, Decl *D, Expr
>> > *E,
>> > +                             unsigned SpellingListIndex) {
>> > +  AlignValueAttr TmpAttr(AttrRange, Context, E,
>> > SpellingListIndex);
>> > +  SourceLocation AttrLoc = AttrRange.getBegin();
>> > +
>> > +  QualType T;
>> > +  if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D))
>> > +    T = TD->getUnderlyingType();
>> > +  else if (ValueDecl *VD = dyn_cast<ValueDecl>(D))
>> > +    T = VD->getType();
>> > +  else {
>> > +    Diag(D->getLocation(), diag::err_attribute_wrong_decl_type)
>> > +      << AttrRange << &TmpAttr /*TmpAttr.getName()*/ <<
>> > ExpectedVariableOrTag;
>> > +    return;
>> > +  }
>>
>> If you added the proper subjects to the attribute definition, you
>> should be able to drop the else clause here. Also the diagnostic type
>> is wrong (as described above). How this should be changed is to add
>> the new diagnostic text, update AttributeList.h properly, and then
>> make a quick change in ClangAttrEmitter.cpp (since I suspect typedef
>> or variable is a reasonable combination we may want to reuse). If
>> that's more work than you'd like to do, you can skip the
>> ClangAttrEmitter.cpp part, and manually specify the diagnostic option
>> in Attr.td.
>
> Will do. Looks like I'm missing tests for this anyway.
>
>>
>> > +
>> > +  if (!T->isDependentType() && !T->isAnyPointerType() &&
>> > +      !T->isReferenceType() && !T->isMemberPointerType()) {
>> > +    Diag(AttrLoc, diag::warn_attribute_pointer_or_reference_only)
>> > +      << &TmpAttr /*TmpAttr.getName()*/ << T <<
>> > D->getSourceRange();
>> > +    return;
>> > +  }
>> > +
>> > +  if (!E->isTypeDependent() && !E->isValueDependent()) {
>> > +    llvm::APSInt Alignment(32);
>> > +    ExprResult ICE
>> > +      = VerifyIntegerConstantExpression(E, &Alignment,
>> > +          diag::err_align_value_attribute_argument_not_int,
>> > +            /*AllowFold*/ false);
>> > +    if (ICE.isInvalid())
>> > +      return;
>> > +
>> > +    if (!Alignment.isPowerOf2()) {
>> > +      Diag(AttrLoc, diag::err_attribute_aligned_not_power_of_two)
>> > +        << E->getSourceRange();
>> > +      return;
>> > +    }
>> > +
>> > +    D->addAttr(::new (Context)
>> > +              AlignValueAttr(AttrRange, Context, ICE.get(),
>> > +              SpellingListIndex));
>> > +    return;
>> > +  }
>> > +
>> > +  // Save dependent expressions in the AST to be instantiated.
>> > +  D->addAttr(::new (Context) AlignValueAttr(TmpAttr));
>> > +  return;
>> > +}
>> > +
>> >  static void handleAlignedAttr(Sema &S, Decl *D, const
>> >  AttributeList &Attr) {
>> >    // check the attribute arguments.
>> >    if (Attr.getNumArgs() > 1) {
>> > @@ -4115,6 +4170,9 @@
>> >    case AttributeList::AT_Aligned:
>> >      handleAlignedAttr(S, D, Attr);
>> >      break;
>> > +  case AttributeList::AT_AlignValue:
>> > +    handleAlignValueAttr(S, D, Attr);
>> > +    break;
>> >    case AttributeList::AT_AlwaysInline:
>> >      handleAlwaysInlineAttr(S, D, Attr);
>> >      break;
>> > Index: lib/Sema/SemaTemplateInstantiateDecl.cpp
>> > ===================================================================
>> > --- lib/Sema/SemaTemplateInstantiateDecl.cpp
>> > +++ lib/Sema/SemaTemplateInstantiateDecl.cpp
>> > @@ -129,6 +129,17 @@
>> >    }
>> >  }
>> >
>> > +static void instantiateDependentAlignValueAttr(
>> > +    Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
>> > +    const AlignValueAttr *Aligned, Decl *New) {
>> > +  // The alignment expression is a constant expression.
>> > +  EnterExpressionEvaluationContext Unevaluated(S,
>> > Sema::ConstantEvaluated);
>> > +  ExprResult Result = S.SubstExpr(Aligned->getAlignment(),
>> > TemplateArgs);
>> > +  if (!Result.isInvalid())
>> > +    S.AddAlignValueAttr(Aligned->getLocation(), New,
>> > Result.getAs<Expr>(),
>> > +                          Aligned->getSpellingListIndex());
>>
>> Formatting?
>>
>> > +}
>> > +
>> >  static void instantiateDependentEnableIfAttr(
>> >      Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
>> >      const EnableIfAttr *A, const Decl *Tmpl, Decl *New) {
>> > @@ -176,6 +187,12 @@
>> >        continue;
>> >      }
>> >
>> > +    const AlignValueAttr *AlignValue =
>> > dyn_cast<AlignValueAttr>(TmplAttr);
>> > +    if (AlignValue &&
>> > AlignValue->getAlignment()->isValueDependent()) {
>> > +      instantiateDependentAlignValueAttr(*this, TemplateArgs,
>> > AlignValue, New);
>> > +      continue;
>> > +    }
>> > +
>> >      const EnableIfAttr *EnableIf =
>> >      dyn_cast<EnableIfAttr>(TmplAttr);
>> >      if (EnableIf && EnableIf->getCond()->isValueDependent()) {
>> >        instantiateDependentEnableIfAttr(*this, TemplateArgs,
>> >        EnableIf, Tmpl,
>> > Index: test/CodeGen/align_value.cpp
>> > ===================================================================
>> > --- /dev/null
>> > +++ test/CodeGen/align_value.cpp
>> > @@ -0,0 +1,8 @@
>> > +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o -
>> > %s | FileCheck %s
>> > +
>> > +typedef double * __attribute__((align_value(64))) aligned_double;
>> > +
>> > +void foo(aligned_double x, double * y
>> > __attribute__((align_value(32))),
>> > +         double & z __attribute__((align_value(128)))) { };
>> > +// CHECK: define void @_Z3fooPdS_Rd(double* align 64 %x, double*
>> > align 32 %y, double* dereferenceable(8) align 128 %z)
>> > +
>> > Index: test/Sema/align_value.c
>> > ===================================================================
>> > --- /dev/null
>> > +++ test/Sema/align_value.c
>> > @@ -0,0 +1,29 @@
>> > +// RUN: %clang_cc1 -fsyntax-only -verify %s
>> > +
>> > +typedef double * __attribute__((align_value(64))) aligned_double;
>> > +
>> > +void foo(aligned_double x, double * y
>> > __attribute__((align_value(32)))) { };
>> > +
>> > +// expected-error@+1 {{requested alignment is not a power of 2}}
>> > +typedef double * __attribute__((align_value(63))) aligned_double1;
>> > +
>> > +// expected-error@+1 {{requested alignment is not a power of 2}}
>> > +typedef double * __attribute__((align_value(-2))) aligned_double2;
>> > +
>> > +// expected-error@+1 {{attribute takes one argument}}
>> > +typedef double * __attribute__((align_value(63, 4)))
>> > aligned_double3;
>> > +
>> > +// expected-error@+1 {{attribute takes one argument}}
>> > +typedef double * __attribute__((align_value())) aligned_double3a;
>> > +
>> > +// expected-error@+1 {{attribute takes one argument}}
>> > +typedef double * __attribute__((align_value)) aligned_double3b;
>> > +
>> > +// expected-error@+1 {{'align_value' attribute requires integer
>> > constant}}
>> > +typedef double * __attribute__((align_value(4.5)))
>> > aligned_double4;
>> > +
>> > +// expected-warning@+1 {{'align_value' attribute only applies to a
>> > pointer or reference ('int' is invalid)}}
>> > +typedef int __attribute__((align_value(32))) aligned_int;
>> > +
>> > +typedef double * __attribute__((align_value(32*2)))
>> > aligned_double5;
>> > +
>> > Index: test/SemaCXX/align_value.cpp
>> > ===================================================================
>> > --- /dev/null
>> > +++ test/SemaCXX/align_value.cpp
>>
>> If you decide to add the CXX11 spelling, this would be a good place
>> to
>> use the C++11-style syntax.
>>
>> > @@ -0,0 +1,26 @@
>> > +// RUN: %clang_cc1 -fsyntax-only -verify %s
>> > +
>> > +typedef double * __attribute__((align_value(64))) aligned_double;
>> > +
>> > +void foo(aligned_double x, double * y
>> > __attribute__((align_value(32))),
>> > +         double & z __attribute__((align_value(128)))) { };
>> > +
>> > +template <typename T, int Q>
>> > +struct x {
>> > +  typedef T* aligned_int __attribute__((align_value(32+8*Q)));
>> > +  aligned_int V;
>> > +
>> > +  void foo(aligned_int a, T &b
>> > __attribute__((align_value(sizeof(T)*4))));
>> > +};
>> > +
>> > +x<float, 4> y;
>> > +
>> > +template <typename T, int Q>
>> > +struct nope {
>> > +  // expected-error@+1 {{requested alignment is not a power of 2}}
>> > +  void foo(T &b __attribute__((align_value(sizeof(T)+1))));
>> > +};
>> > +
>> > +// expected-note@+1 {{in instantiation of template class
>> > 'nope<long double, 4>' requested here}}
>> > +nope<long double, 4> y2;
>> > +
>> >
>>
>> ~Aaron
>>
>
> --
> Hal Finkel
> Assistant Computational Scientist
> Leadership Computing Facility
> Argonne National Laboratory

~Aaron

_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to