[flang-commits] [compiler-rt] [llvm] [flang] [clang-tools-extra] [clang] [clang] Add support for new loop attribute [[clang::code_align()]] (PR #70762)

via flang-commits flang-commits at lists.llvm.org
Mon Nov 13 19:49:29 PST 2023


https://github.com/smanna12 updated https://github.com/llvm/llvm-project/pull/70762

>From 93d46d40f46663cfa30fc01da965887508684e25 Mon Sep 17 00:00:00 2001
From: "Manna, Soumi" <soumi.manna at intel.com>
Date: Mon, 30 Oct 2023 21:41:00 -0700
Subject: [PATCH 01/15] [clang] Add support for new loop attribute
 [[clang::code_align()]]

---
 clang/include/clang/Basic/Attr.td             |   9 ++
 clang/include/clang/Basic/AttrDocs.td         |  43 ++++++
 .../clang/Basic/DiagnosticSemaKinds.td        |   4 +
 clang/include/clang/Sema/Sema.h               |   2 +
 clang/lib/CodeGen/CGLoopInfo.cpp              |  29 +++-
 clang/lib/CodeGen/CGLoopInfo.h                |   6 +
 clang/lib/Sema/SemaStmtAttr.cpp               |  53 ++++++++
 clang/lib/Sema/SemaTemplateInstantiate.cpp    |   8 +-
 clang/test/CodeGen/code_align.c               |  61 +++++++++
 clang/test/Sema/code_align.c                  | 124 ++++++++++++++++++
 clang/test/Sema/code_align_ast.c              |  91 +++++++++++++
 11 files changed, 426 insertions(+), 4 deletions(-)
 create mode 100644 clang/test/CodeGen/code_align.c
 create mode 100644 clang/test/Sema/code_align.c
 create mode 100644 clang/test/Sema/code_align_ast.c

diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index 25231c5b82b907c..e25bea67bf9e86e 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -4280,3 +4280,12 @@ def PreferredType: InheritableAttr {
   let Args = [TypeArgument<"Type", 1>];
   let Documentation = [PreferredTypeDocumentation];
 }
+
+def CodeAlign: StmtAttr {
+  let Spellings = [CXX11<"clang", "code_align">,
+                   C23<"clang", "code_align">];
+  let Subjects = SubjectList<[ForStmt, CXXForRangeStmt, WhileStmt, DoStmt],
+                              ErrorDiag, "'for', 'while', and 'do' statements">;
+  let Args = [ExprArgument<"NExpr">];
+  let Documentation = [CodeAlignAttrDocs];
+}
diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td
index 05703df2129f612..5ee224e117d049c 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -7416,3 +7416,46 @@ that ``p->array`` must have at least ``p->count`` number of elements available:
 
   }];
 }
+
+def CodeAlignAttrDocs : Documentation {
+  let Category = DocCatVariable;
+  let Heading = "clang::code_align";
+  let Content = [{
+The ``clang::code_align(N)`` attribute applies to a loop and it specifies the
+byte alignment for a loop. The attribute accepts a positive integer constant
+initialization expression indicating the number of bytes for the minimum
+alignment boundary. Its value must be a power of 2, between 1 and 4096, such as
+1, 2, 4, 8, and so on. This attribute sets ``llvm.loop.align`` loop metadata
+when it applies on a loop statement.
+
+.. code-block:: c++
+
+  void foo() {
+    int var = 0;
+    [[clang::code_align(16)]] for (int i = 0; i < 10; ++i) var++;
+  }
+
+  void Array(int *array, size_t n) {
+    [[clang::code_align(64)]] for (int i = 0; i < n; ++i) array[i] = 0;
+  }
+
+  void count () {
+  int a1[10], int i = 0;
+  [[clang::code_align(32)]] while (i < 10) {
+    a1[i] += 3;
+  }
+
+  void check() {
+    int a = 10;
+    [[clang::code_align(8)]] do {
+      a = a + 1;
+    } while (a < 20);
+  }
+
+  template<int A>
+  void func() {
+    [[clang::code_align(A)]] for(;;) { }
+  }
+
+  }];
+}
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 224c0df7f1fb71f..4b0f24d25e3e902 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -10026,6 +10026,10 @@ def err_duplicate_case_differing_expr : Error<
 def warn_case_empty_range : Warning<"empty case range specified">;
 def warn_missing_case_for_condition :
   Warning<"no case matching constant switch condition '%0'">;
+def err_loop_attr_duplication : Error<
+  "duplicate loop attribute %0">;
+def err_attribute_argument_not_power_of_two : Error<
+  "%0 attribute argument must be a constant power of two greater than zero">;
 
 def warn_def_missing_case : Warning<"%plural{"
   "1:enumeration value %1 not explicitly handled in switch|"
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 1e9752345ffd173..376335e9bbe70ca 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -2096,6 +2096,8 @@ class Sema final {
   QualType BuildAddressSpaceAttr(QualType &T, Expr *AddrSpace,
                                  SourceLocation AttrLoc);
 
+  CodeAlignAttr *BuildCodeAlignAttr(const AttributeCommonInfo &CI, Expr *E);
+
   bool CheckQualifiedFunctionForTypeId(QualType T, SourceLocation Loc);
 
   bool CheckFunctionReturnType(QualType T, SourceLocation Loc);
diff --git a/clang/lib/CodeGen/CGLoopInfo.cpp b/clang/lib/CodeGen/CGLoopInfo.cpp
index e5d9db273c2d336..a7cae301ba7bfda 100644
--- a/clang/lib/CodeGen/CGLoopInfo.cpp
+++ b/clang/lib/CodeGen/CGLoopInfo.cpp
@@ -440,6 +440,14 @@ MDNode *LoopInfo::createMetadata(
         Ctx, {MDString::get(Ctx, "llvm.loop.parallel_accesses"), AccGroup}));
   }
 
+  // Setting clang::code_align attribute.
+  if (Attrs.CodeAlign > 0) {
+    Metadata *Vals[] = {MDString::get(Ctx, "llvm.loop.align"),
+                        ConstantAsMetadata::get(ConstantInt::get(
+                            llvm::Type::getInt32Ty(Ctx), Attrs.CodeAlign))};
+    LoopProperties.push_back(MDNode::get(Ctx, Vals));
+  }
+
   LoopProperties.insert(LoopProperties.end(), AdditionalLoopProperties.begin(),
                         AdditionalLoopProperties.end());
   return createFullUnrollMetadata(Attrs, LoopProperties, HasUserTransforms);
@@ -453,7 +461,7 @@ LoopAttributes::LoopAttributes(bool IsParallel)
       VectorizeScalable(LoopAttributes::Unspecified), InterleaveCount(0),
       UnrollCount(0), UnrollAndJamCount(0),
       DistributeEnable(LoopAttributes::Unspecified), PipelineDisabled(false),
-      PipelineInitiationInterval(0), MustProgress(false) {}
+      PipelineInitiationInterval(0), CodeAlign(0), MustProgress(false) {}
 
 void LoopAttributes::clear() {
   IsParallel = false;
@@ -469,6 +477,7 @@ void LoopAttributes::clear() {
   DistributeEnable = LoopAttributes::Unspecified;
   PipelineDisabled = false;
   PipelineInitiationInterval = 0;
+  CodeAlign = 0;
   MustProgress = false;
 }
 
@@ -493,8 +502,8 @@ LoopInfo::LoopInfo(BasicBlock *Header, const LoopAttributes &Attrs,
       Attrs.VectorizeEnable == LoopAttributes::Unspecified &&
       Attrs.UnrollEnable == LoopAttributes::Unspecified &&
       Attrs.UnrollAndJamEnable == LoopAttributes::Unspecified &&
-      Attrs.DistributeEnable == LoopAttributes::Unspecified && !StartLoc &&
-      !EndLoc && !Attrs.MustProgress)
+      Attrs.DistributeEnable == LoopAttributes::Unspecified &&
+      Attrs.CodeAlign == 0 && !StartLoc && !EndLoc && !Attrs.MustProgress)
     return;
 
   TempLoopID = MDNode::getTemporary(Header->getContext(), std::nullopt);
@@ -788,6 +797,20 @@ void LoopInfoStack::push(BasicBlock *Header, clang::ASTContext &Ctx,
     }
   }
 
+  // Translate 'loop attributes' arguments to equivalent Attr enums.
+  // It's being handled separately from LoopHintAttrs not to support
+  // legacy GNU attributes and pragma styles.
+  //
+  // For attribute code_align:
+  // n - 'llvm.loop.align i32 n' metadata will be emitted.
+  for (const auto *A : Attrs) {
+    if (const auto *CodeAlign = dyn_cast<CodeAlignAttr>(A)) {
+      const auto *CE = cast<ConstantExpr>(CodeAlign->getNExpr());
+      llvm::APSInt ArgVal = CE->getResultAsAPSInt();
+      setCodeAlign(ArgVal.getSExtValue());
+    }
+  }
+
   setMustProgress(MustProgress);
 
   if (CGOpts.OptimizationLevel > 0)
diff --git a/clang/lib/CodeGen/CGLoopInfo.h b/clang/lib/CodeGen/CGLoopInfo.h
index 856e892f712e31f..f5438d7865946ab 100644
--- a/clang/lib/CodeGen/CGLoopInfo.h
+++ b/clang/lib/CodeGen/CGLoopInfo.h
@@ -79,6 +79,9 @@ struct LoopAttributes {
   /// Value for llvm.loop.pipeline.iicount metadata.
   unsigned PipelineInitiationInterval;
 
+  /// Value for 'llvm.loop.align' loop metadata.
+  unsigned CodeAlign;
+
   /// Value for whether the loop is required to make progress.
   bool MustProgress;
 };
@@ -282,6 +285,9 @@ class LoopInfoStack {
     StagedAttrs.PipelineInitiationInterval = C;
   }
 
+  /// Set the CodeAlign for the next loop pushed.
+  void setCodeAlign(unsigned C) { StagedAttrs.CodeAlign = C; }
+
   /// Set no progress for the next loop pushed.
   void setMustProgress(bool P) { StagedAttrs.MustProgress = P; }
 
diff --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp
index ad20bc8871f103a..7b9dd0c97e61c1e 100644
--- a/clang/lib/Sema/SemaStmtAttr.cpp
+++ b/clang/lib/Sema/SemaStmtAttr.cpp
@@ -322,6 +322,56 @@ static Attr *handleUnlikely(Sema &S, Stmt *St, const ParsedAttr &A,
   return ::new (S.Context) UnlikelyAttr(S.Context, A);
 }
 
+CodeAlignAttr *Sema::BuildCodeAlignAttr(const AttributeCommonInfo &CI,
+                                        Expr *E) {
+  if (!E->isValueDependent()) {
+    llvm::APSInt ArgVal;
+    ExprResult Res = VerifyIntegerConstantExpression(E, &ArgVal);
+    if (Res.isInvalid())
+      return nullptr;
+    E = Res.get();
+
+    // This attribute requires a strictly positive value.
+    if (ArgVal <= 0) {
+      Diag(E->getExprLoc(), diag::err_attribute_requires_positive_integer)
+          << CI << /*positive*/ 0;
+      return nullptr;
+    }
+
+    // This attribute requires a single constant power of two greater than zero.
+    if (!ArgVal.isPowerOf2()) {
+      Diag(E->getExprLoc(), diag::err_attribute_argument_not_power_of_two)
+          << CI;
+      return nullptr;
+    }
+  }
+
+  return new (Context) CodeAlignAttr(Context, CI, E);
+}
+
+static Attr *handleCodeAlignAttr(Sema &S, Stmt *St, const ParsedAttr &A) {
+
+  Expr *E = A.getArgAsExpr(0);
+  return S.BuildCodeAlignAttr(A, E);
+}
+
+// Emit duplicate error for [[clang::code_align()]] attribute.
+template <typename LoopAttrT>
+static void
+CheckForDuplicateLoopAttribute(Sema &S,
+                               const SmallVectorImpl<const Attr *> &Attrs) {
+  const LoopAttrT *LoopAttr = nullptr;
+
+  for (const auto *I : Attrs) {
+    if (LoopAttr && isa<LoopAttrT>(I)) {
+      // Cannot specify same type of attribute twice.
+      S.Diag(I->getLocation(), diag::err_loop_attr_duplication) << LoopAttr;
+    }
+    if (isa<LoopAttrT>(I))
+      LoopAttr = cast<LoopAttrT>(I);
+  }
+}
+
 #define WANT_STMT_MERGE_LOGIC
 #include "clang/Sema/AttrParsedAttrImpl.inc"
 #undef WANT_STMT_MERGE_LOGIC
@@ -523,6 +573,8 @@ static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const ParsedAttr &A,
     return handleLikely(S, St, A, Range);
   case ParsedAttr::AT_Unlikely:
     return handleUnlikely(S, St, A, Range);
+  case ParsedAttr::AT_CodeAlign:
+    return handleCodeAlignAttr(S, St, A);
   default:
     // N.B., ClangAttrEmitter.cpp emits a diagnostic helper that ensures a
     // declaration attribute is not written on a statement, but this code is
@@ -541,4 +593,5 @@ void Sema::ProcessStmtAttributes(Stmt *S, const ParsedAttributes &InAttrs,
   }
 
   CheckForIncompatibleAttributes(*this, OutAttrs);
+  CheckForDuplicateLoopAttribute<CodeAlignAttr>(*this, OutAttrs);
 }
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index e09897318ba9883..436364cfc0a4dce 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1374,7 +1374,7 @@ namespace {
     const AlwaysInlineAttr *
     TransformStmtAlwaysInlineAttr(const Stmt *OrigS, const Stmt *InstS,
                                   const AlwaysInlineAttr *A);
-
+    const CodeAlignAttr *TransformCodeAlignAttr(const CodeAlignAttr *CA);
     ExprResult TransformPredefinedExpr(PredefinedExpr *E);
     ExprResult TransformDeclRefExpr(DeclRefExpr *E);
     ExprResult TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E);
@@ -1905,6 +1905,12 @@ const AlwaysInlineAttr *TemplateInstantiator::TransformStmtAlwaysInlineAttr(
   return A;
 }
 
+const CodeAlignAttr *
+TemplateInstantiator::TransformCodeAlignAttr(const CodeAlignAttr *CA) {
+  Expr *TransformedExpr = getDerived().TransformExpr(CA->getNExpr()).get();
+  return getSema().BuildCodeAlignAttr(*CA, TransformedExpr);
+}
+
 ExprResult TemplateInstantiator::transformNonTypeTemplateParmRef(
     Decl *AssociatedDecl, const NonTypeTemplateParmDecl *parm,
     SourceLocation loc, TemplateArgument arg,
diff --git a/clang/test/CodeGen/code_align.c b/clang/test/CodeGen/code_align.c
new file mode 100644
index 000000000000000..f1ee06ff70eef27
--- /dev/null
+++ b/clang/test/CodeGen/code_align.c
@@ -0,0 +1,61 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-C %s
+// RUN: %clang_cc1 -x c++ -std=c++11 -fsyntax-only -emit-llvm %s -o - | FileCheck %s --check-prefixes CHECK-C,CHECK-CPP
+
+// Add CodeGen tests for Loop attribute: [[clang::code_align)]].
+
+// CHECK-C: br label %for.cond, !llvm.loop ![[MD_FP:[0-9]+]]
+// CHECK-C: br label %while.cond, !llvm.loop ![[MD_FP_1:[0-9]+]]
+// CHECK-C: br i1 %cmp3, label %do.body, label %do.end, !llvm.loop ![[MD_FP_2:[0-9]+]]
+// CHECK-C: br label %for.cond5, !llvm.loop ![[MD_FP_3:[0-9]+]]
+
+// CHECK-CPP: br label %for.cond, !llvm.loop ![[MD_FP_4:[0-9]+]]
+// CHECK-CPP: br label %for.cond2, !llvm.loop ![[MD_FP_5:[0-9]+]]
+
+void bar(int);
+void code_align() {
+  int a[10];
+  // CHECK-C: ![[MD_FP]] = distinct !{![[MD_FP]], ![[MP:[0-9]+]], ![[MD_code_align:[0-9]+]]}
+  // CHECK-C-NEXT: ![[MP]] = !{!"llvm.loop.mustprogress"}
+  // CHECK-C-NEXT: ![[MD_code_align]] = !{!"llvm.loop.align", i32 4}
+  [[clang::code_align(4)]]
+  for(int I=0; I<128; ++I) { bar(I); }
+
+  // CHECK-C: ![[MD_FP_1]] = distinct !{![[MD_FP_1]], ![[MP]], ![[MD_code_align_1:[0-9]+]]}
+  // CHECK-C-NEXT: ![[MD_code_align_1]] = !{!"llvm.loop.align", i32 16}
+  int i = 0;
+  [[clang::code_align(16)]] while (i < 60) {
+    a[i] += 3;
+  }
+
+  // CHECK-C: ![[MD_FP_2]] = distinct !{![[MD_FP_2]], ![[MP]], ![[MD_code_align_2:[0-9]+]]}
+  // CHECK-C-NEXT: ![[MD_code_align_2]] = !{!"llvm.loop.align", i32 8}
+  int b = 10;
+  [[clang::code_align(8)]] do {
+    b = b + 1;
+  } while (b < 20);
+
+  // CHECK-C: ![[MD_FP_3]] = distinct !{![[MD_FP_3]], ![[MP]], ![[MD_code_align_3:[0-9]+]]}
+  // CHECK-C-NEXT: ![[MD_code_align_3]] = !{!"llvm.loop.align", i32 64}
+  [[clang::code_align(64)]]
+  for(int I=0; I<128; ++I) { bar(I); }
+}
+
+#if __cplusplus >= 201103L
+template <int A, int B>
+void code_align_cpp() {
+  int a[10];	
+  // CHECK-CPP: ![[MD_FP_4]] = distinct !{![[MD_FP_4]], ![[MP]], ![[MD_code_align_4:[0-9]+]]}
+  // CHECK-CPP-NEXT: ![[MD_code_align_4]] = !{!"llvm.loop.align", i32 32}
+  [[clang::code_align(A)]] for (int i = 0; i != 10; ++i)
+    a[i] = 0;
+
+  // CHECK-CPP: ![[MD_FP_5]] = distinct !{![[MD_FP_5]], ![[MD_code_align]]}
+  int c[] = {0, 1, 2, 3, 4, 5};
+  [[clang::code_align(B)]] for (int n : c) { n *= 2; }
+}
+
+int main() {
+  code_align_cpp<32, 4>();
+  return 0;
+}
+#endif
diff --git a/clang/test/Sema/code_align.c b/clang/test/Sema/code_align.c
new file mode 100644
index 000000000000000..74f39ffe23300d0
--- /dev/null
+++ b/clang/test/Sema/code_align.c
@@ -0,0 +1,124 @@
+// RUN: %clang_cc1 -fsyntax-only -verify=expected,c-local %s
+// RUN: %clang_cc1 -fsyntax-only -verify=expected,cpp-local -pedantic -x c++ -std=c++11 %s 
+
+// Add diagnostics tests for Loop attribute: [[clang::code_align()]].
+
+void foo() {
+  int i;
+  int a[10], b[10];
+
+  [[clang::code_align(8)]]
+  for (i = 0; i < 10; ++i) {  // this is OK
+    a[i] = b[i] = 0;
+  }
+  // expected-error at +1 {{'code_align' attribute only applies to 'for', 'while', and 'do' statements}}
+  [[clang::code_align(4)]]
+  i = 7;
+  for (i = 0; i < 10; ++i) {
+    a[i] = b[i] = 0;
+  }
+
+  // expected-error at +1{{'code_align' attribute cannot be applied to a declaration}}
+  [[clang::code_align(12)]] int n[10];
+}
+
+void bar(int);
+#if __cplusplus >= 201103L
+// cpp-local-note at +2 {{declared here}}
+#endif
+void foo1(int A)
+{
+  // expected-error at +1 {{'code_align' attribute requires a positive integral compile time constant expression}}
+  [[clang::code_align(0)]]
+  for(int I=0; I<128; ++I) { bar(I); }
+
+  // expected-error at +1{{'code_align' attribute requires a positive integral compile time constant expression}}
+  [[clang::code_align(-4)]]
+  for(int I=0; I<128; ++I) { bar(I); }
+
+#if __cplusplus >= 201103L
+    // cpp-local-error at +4 {{integral constant expression must have integral or unscoped enumeration type, not 'double'}}
+#else
+    // c-local-error at +2 {{integer constant expression must have integer type, not 'double'}}
+#endif
+  [[clang::code_align(64.0)]]
+  for(int I=0; I<128; ++I) { bar(I); }
+
+  // expected-error at +1 {{'code_align' attribute takes one argument}}
+  [[clang::code_align()]]
+  for(int I=0; I<128; ++I) { bar(I); }
+
+  // expected-error at +1 {{'code_align' attribute takes one argument}}
+  [[clang::code_align(4,8)]]
+  for(int I=0; I<128; ++I) { bar(I); }
+
+  // no diagnostic is expected
+  [[clang::code_align(32)]]
+  for(int I=0; I<128; ++I) { bar(I); }
+
+#if __cplusplus >= 201103L
+  // cpp-local-error at +4 {{integral constant expression must have integral or unscoped enumeration type, not 'const char[4]'}}
+#else  
+  // c-local-error at +2 {{integer constant expression must have integer type, not 'char[4]'}}
+#endif
+  [[clang::code_align("abc")]]
+  for(int I=0; I<128; ++I) { bar(I); }
+
+  [[clang::code_align(64)]]
+  // expected-error at +1 {{duplicate loop attribute 'code_align'}}
+  [[clang::code_align(64)]]
+  for(int I=0; I<128; ++I) { bar(I); }
+
+  // expected-error at +1 {{'code_align' attribute argument must be a constant power of two greater than zero}}
+  [[clang::code_align(7)]]
+  for(int I=0; I<128; ++I) { bar(I); }
+
+#if __cplusplus >= 201103L
+  // cpp-local-error at +5 {{expression is not an integral constant expression}}
+  // cpp-local-note at +4 {{function parameter 'A' with unknown value cannot be used in a constant expression}}
+#else
+  // c-local-error at +2 {{expression is not an integer constant expression}}
+#endif  
+  [[clang::code_align(A)]]
+  for(int I=0; I<128; ++I) { bar(I); }
+}
+
+#if __cplusplus >= 201103L
+void check_code_align_expression() {
+  int a[10];
+
+  // Test that checks expression is not a constant expression.
+  int foo2; // cpp-local-note {{declared here}}
+  // cpp-local-error at +2{{expression is not an integral constant expression}}
+  // cpp-local-note at +1{{read of non-const variable 'foo2' is not allowed in a constant expression}}
+  [[clang::code_align(foo2 + 1)]]
+  for (int i = 0; i != 10; ++i)
+    a[i] = 0;
+
+  // Test that checks expression is a constant expression.
+  constexpr int bars = 0;
+  [[clang::code_align(bars + 1)]]
+  for (int i = 0; i != 10; ++i)
+    a[i] = 0;
+}
+
+template <int A, int B, int C, int D>
+void code_align_dependent() {
+  [[clang::code_align(C)]]
+  for(int I=0; I<128; ++I) { bar(I); }
+
+  [[clang::code_align(A)]]
+  // cpp-local-error at +1 {{duplicate loop attribute 'code_align'}}
+  [[clang::code_align(B)]]
+  for(int I=0; I<128; ++I) { bar(I); }
+
+  // cpp-local-error at +1{{'code_align' attribute requires a positive integral compile time constant expression}}
+  [[clang::code_align(D)]]
+  for(int I=0; I<128; ++I) { bar(I); }
+}
+
+int main() {
+  code_align_dependent<8, 16, 32, -10>(); // cpp-local-note{{in instantiation of function template specialization 'code_align_dependent<8, 16, 32, -10>' requested here}}
+  return 0;
+}
+#endif
diff --git a/clang/test/Sema/code_align_ast.c b/clang/test/Sema/code_align_ast.c
new file mode 100644
index 000000000000000..300e55d696fd402
--- /dev/null
+++ b/clang/test/Sema/code_align_ast.c
@@ -0,0 +1,91 @@
+// RUN: %clang_cc1 -fsyntax-only -ast-dump -verify %s | FileCheck -check-prefix=CHECK-C %s
+// RUN: %clang_cc1 -x c++ -std=c++11 -fsyntax-only -ast-dump %s | FileCheck %s --check-prefixes CHECK-C,CHECK-CPP
+
+// expected-no-diagnostics
+
+// Add AST tests for Loop attribute: [[clang::code_align()]].
+
+void bar(int);
+// CHECK-C: FunctionDecl{{.*}}code_align 'void ()'
+void code_align() {
+  int a1[10], a2[10];
+  // CHECK-C: AttributedStmt
+  // CHECK-C-NEXT: CodeAlignAttr
+  // CHECK-C-NEXT:  ConstantExpr{{.*}}'int'
+  // CHECK-C-NEXT:  value: Int 16
+  // CHECK-C-NEXT:  IntegerLiteral{{.*}}16{{$}}
+  [[clang::code_align(16)]] for (int p = 0; p < 128; ++p) {
+    a1[p] = a2[p] = 0;
+  }
+
+  // CHECK-C: AttributedStmt
+  // CHECK-C-NEXT:  CodeAlignAttr
+  // CHECK-C-NEXT:  ConstantExpr{{.*}}'int'
+  // CHECK-C-NEXT:  value: Int 4
+  // CHECK-C-NEXT:  IntegerLiteral{{.*}}4{{$}}
+  int i = 0;
+  [[clang::code_align(4)]] while (i < 30) {
+    a1[i] += 3;
+  }
+
+  // CHECK-C: AttributedStmt
+  // CHECK-C-NEXT:  CodeAlignAttr
+  // CHECK-C-NEXT:  ConstantExpr{{.*}}'int'
+  // CHECK-C-NEXT:  value: Int 32
+  // CHECK-C-NEXT:  IntegerLiteral{{.*}}32{{$}}
+  for (int i = 0; i < 128; ++i) {
+    [[clang::code_align(32)]]  for (int j = 0; j < 128; ++j) {
+      a1[i] += a1[j];
+    }
+  }
+
+  // CHECK-C: AttributedStmt
+  // CHECK-C-NEXT:  CodeAlignAttr
+  // CHECK-C-NEXT:  ConstantExpr{{.*}}'int'
+  // CHECK-C-NEXT:  value: Int 64
+  // CHECK-C-NEXT:  IntegerLiteral{{.*}}64{{$}}
+  [[clang::code_align(64)]]
+  for(int I=0; I<128; ++I) { bar(I); }
+
+  // CHECK-C: AttributedStmt
+  // CHECK-C-NEXT: CodeAlignAttr
+  // CHECK-C-NEXT:  ConstantExpr{{.*}}'int'
+  // CHECK-C-NEXT:  value: Int 4
+  // CHECK-C-NEXT:  IntegerLiteral{{.*}}4{{$}}
+  int b = 10;
+  [[clang::code_align(4)]] do {
+    b = b + 1;
+  } while (b < 20);
+}
+
+#if __cplusplus >= 201103L
+//CHECK-CPP: FunctionDecl{{.*}}used code_align_cpp 'void ()' implicit_instantiation
+template <int A, int B>
+void code_align_cpp() {
+  int a[10];
+  // CHECK-CPP: AttributedStmt
+  // CHECK-CPP-NEXT:  CodeAlignAttr
+  // CHECK-CPP-NEXT:  ConstantExpr{{.*}}'int'
+  // CHECK-CPP-NEXT:  value: Int 32
+  // CHECK-CPP-NEXT:  SubstNonTypeTemplateParmExpr{{.*}}'int'
+  // CHECK-CPP-NEXT:  NonTypeTemplateParmDecl{{.*}}referenced 'int' depth 0 index 0 A
+  // CHECK-CPP-NEXT:  IntegerLiteral{{.*}}32{{$}}
+  [[clang::code_align(A)]] for (int i = 0; i != 10; ++i)
+    a[i] = 0;
+
+  // CHECK-CPP: AttributedStmt
+  // CHECK-CPP-NEXT:  CodeAlignAttr
+  // CHECK-CPP-NEXT:  ConstantExpr{{.*}}'int'
+  // CHECK-CPP-NEXT:  value: Int 4
+  // CHECK-CPP-NEXT:  SubstNonTypeTemplateParmExpr{{.*}}'int'
+  // CHECK-CPP-NEXT:  NonTypeTemplateParmDecl{{.*}}referenced 'int' depth 0 index 1 B
+  // CHECK-CPP-NEXT:  IntegerLiteral{{.*}}4{{$}}
+  int c[] = {0, 1, 2, 3, 4, 5};
+  [[clang::code_align(B)]] for (int n : c) { n *= 2; }
+}
+
+int main() {
+  code_align_cpp<32, 4>();
+  return 0;
+}
+#endif

>From d049dc9997bdb78ff7e7cbf9b04aa42b9274cfd9 Mon Sep 17 00:00:00 2001
From: "Manna, Soumi" <soumi.manna at intel.com>
Date: Wed, 1 Nov 2023 20:24:51 -0700
Subject: [PATCH 02/15] Address review comments

---
 clang/include/clang/Basic/Attr.td             | 13 ++++++--
 clang/include/clang/Basic/AttrDocs.td         |  9 +++---
 .../clang/Basic/DiagnosticSemaKinds.td        |  4 +--
 clang/lib/CodeGen/CGLoopInfo.cpp              |  7 ++--
 clang/lib/CodeGen/CGLoopInfo.h                |  4 +--
 clang/lib/Sema/SemaStmtAttr.cpp               | 32 ++++++++-----------
 clang/lib/Sema/SemaTemplateInstantiate.cpp    |  2 +-
 clang/test/CodeGen/code_align.c               |  6 ++--
 clang/test/Sema/code_align.c                  | 21 ++++++------
 clang/test/Sema/code_align_ast.c              |  8 ++---
 10 files changed, 51 insertions(+), 55 deletions(-)

diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index e25bea67bf9e86e..88d232f4aba0163 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -4282,10 +4282,17 @@ def PreferredType: InheritableAttr {
 }
 
 def CodeAlign: StmtAttr {
-  let Spellings = [CXX11<"clang", "code_align">,
-                   C23<"clang", "code_align">];
+  let Spellings = [Clang<"code_align">];
   let Subjects = SubjectList<[ForStmt, CXXForRangeStmt, WhileStmt, DoStmt],
                               ErrorDiag, "'for', 'while', and 'do' statements">;
-  let Args = [ExprArgument<"NExpr">];
+  let Args = [ExprArgument<"Alignment">];
   let Documentation = [CodeAlignAttrDocs];
+  let AdditionalMembers = [{
+    static int getMinValue() {
+      return 1;
+    }
+    static int getMaxValue() {
+      return 4096;
+    }
+  }];
 }
diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td
index 5ee224e117d049c..099c7dc547cfa81 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -7421,12 +7421,11 @@ def CodeAlignAttrDocs : Documentation {
   let Category = DocCatVariable;
   let Heading = "clang::code_align";
   let Content = [{
-The ``clang::code_align(N)`` attribute applies to a loop and it specifies the
-byte alignment for a loop. The attribute accepts a positive integer constant
+The ``clang::code_align(N)`` attribute applies to a loop and specifies the byte
+alignment for a loop. The attribute accepts a positive integer constant
 initialization expression indicating the number of bytes for the minimum
-alignment boundary. Its value must be a power of 2, between 1 and 4096, such as
-1, 2, 4, 8, and so on. This attribute sets ``llvm.loop.align`` loop metadata
-when it applies on a loop statement.
+alignment boundary. Its value must be a power of 2, between 1 and 4096
+(inclusive).
 
 .. code-block:: c++
 
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 4b0f24d25e3e902..5d9aaba57131445 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -10028,8 +10028,8 @@ def warn_missing_case_for_condition :
   Warning<"no case matching constant switch condition '%0'">;
 def err_loop_attr_duplication : Error<
   "duplicate loop attribute %0">;
-def err_attribute_argument_not_power_of_two : Error<
-  "%0 attribute argument must be a constant power of two greater than zero">;
+def err_attribute_power_of_two_in_range : Error<
+  "%0 attribute must be a constant power of two between %1 and %2 inclusive">;
 
 def warn_def_missing_case : Warning<"%plural{"
   "1:enumeration value %1 not explicitly handled in switch|"
diff --git a/clang/lib/CodeGen/CGLoopInfo.cpp b/clang/lib/CodeGen/CGLoopInfo.cpp
index a7cae301ba7bfda..a951198b925a513 100644
--- a/clang/lib/CodeGen/CGLoopInfo.cpp
+++ b/clang/lib/CodeGen/CGLoopInfo.cpp
@@ -797,15 +797,12 @@ void LoopInfoStack::push(BasicBlock *Header, clang::ASTContext &Ctx,
     }
   }
 
-  // Translate 'loop attributes' arguments to equivalent Attr enums.
-  // It's being handled separately from LoopHintAttrs not to support
-  // legacy GNU attributes and pragma styles.
-  //
+  // Identify loop attribute 'code_align' from Attrs.
   // For attribute code_align:
   // n - 'llvm.loop.align i32 n' metadata will be emitted.
   for (const auto *A : Attrs) {
     if (const auto *CodeAlign = dyn_cast<CodeAlignAttr>(A)) {
-      const auto *CE = cast<ConstantExpr>(CodeAlign->getNExpr());
+      const auto *CE = cast<ConstantExpr>(CodeAlign->getAlignment());
       llvm::APSInt ArgVal = CE->getResultAsAPSInt();
       setCodeAlign(ArgVal.getSExtValue());
     }
diff --git a/clang/lib/CodeGen/CGLoopInfo.h b/clang/lib/CodeGen/CGLoopInfo.h
index f5438d7865946ab..a1c8c7e5307fd9c 100644
--- a/clang/lib/CodeGen/CGLoopInfo.h
+++ b/clang/lib/CodeGen/CGLoopInfo.h
@@ -79,7 +79,7 @@ struct LoopAttributes {
   /// Value for llvm.loop.pipeline.iicount metadata.
   unsigned PipelineInitiationInterval;
 
-  /// Value for 'llvm.loop.align' loop metadata.
+  /// Value for 'llvm.loop.align' metadata.
   unsigned CodeAlign;
 
   /// Value for whether the loop is required to make progress.
@@ -285,7 +285,7 @@ class LoopInfoStack {
     StagedAttrs.PipelineInitiationInterval = C;
   }
 
-  /// Set the CodeAlign for the next loop pushed.
+  /// Set value of code align for the next loop pushed.
   void setCodeAlign(unsigned C) { StagedAttrs.CodeAlign = C; }
 
   /// Set no progress for the next loop pushed.
diff --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp
index 7b9dd0c97e61c1e..c34fc4de5b0c670 100644
--- a/clang/lib/Sema/SemaStmtAttr.cpp
+++ b/clang/lib/Sema/SemaStmtAttr.cpp
@@ -331,17 +331,13 @@ CodeAlignAttr *Sema::BuildCodeAlignAttr(const AttributeCommonInfo &CI,
       return nullptr;
     E = Res.get();
 
-    // This attribute requires a strictly positive value.
-    if (ArgVal <= 0) {
-      Diag(E->getExprLoc(), diag::err_attribute_requires_positive_integer)
-          << CI << /*positive*/ 0;
-      return nullptr;
-    }
-
-    // This attribute requires a single constant power of two greater than zero.
-    if (!ArgVal.isPowerOf2()) {
-      Diag(E->getExprLoc(), diag::err_attribute_argument_not_power_of_two)
-          << CI;
+    int align_value = ArgVal.getSExtValue();
+    if (align_value < CodeAlignAttr::getMinValue() ||
+        align_value > CodeAlignAttr::getMaxValue() ||
+        !ArgVal.isPowerOf2()) {
+      Diag(CI.getLoc(), diag:: err_attribute_power_of_two_in_range)
+          << CI << CodeAlignAttr::getMinValue()
+	  << CodeAlignAttr::getMaxValue();
       return nullptr;
     }
   }
@@ -360,15 +356,15 @@ template <typename LoopAttrT>
 static void
 CheckForDuplicateLoopAttribute(Sema &S,
                                const SmallVectorImpl<const Attr *> &Attrs) {
-  const LoopAttrT *LoopAttr = nullptr;
-
+  const Attr *A = nullptr;
   for (const auto *I : Attrs) {
-    if (LoopAttr && isa<LoopAttrT>(I)) {
-      // Cannot specify same type of attribute twice.
-      S.Diag(I->getLocation(), diag::err_loop_attr_duplication) << LoopAttr;
+    if (isa<LoopAttrT>(I)) {
+      if (A) {
+        // Cannot specify same type of attribute twice.
+        S.Diag(I->getLocation(), diag::err_loop_attr_duplication) << A;
+       }
+       A = I;
     }
-    if (isa<LoopAttrT>(I))
-      LoopAttr = cast<LoopAttrT>(I);
   }
 }
 
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 436364cfc0a4dce..cd679d9a1f83529 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1907,7 +1907,7 @@ const AlwaysInlineAttr *TemplateInstantiator::TransformStmtAlwaysInlineAttr(
 
 const CodeAlignAttr *
 TemplateInstantiator::TransformCodeAlignAttr(const CodeAlignAttr *CA) {
-  Expr *TransformedExpr = getDerived().TransformExpr(CA->getNExpr()).get();
+  Expr *TransformedExpr = getDerived().TransformExpr(CA->getAlignment()).get();
   return getSema().BuildCodeAlignAttr(*CA, TransformedExpr);
 }
 
diff --git a/clang/test/CodeGen/code_align.c b/clang/test/CodeGen/code_align.c
index f1ee06ff70eef27..f6d86ec969ae5f6 100644
--- a/clang/test/CodeGen/code_align.c
+++ b/clang/test/CodeGen/code_align.c
@@ -1,7 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-C %s
-// RUN: %clang_cc1 -x c++ -std=c++11 -fsyntax-only -emit-llvm %s -o - | FileCheck %s --check-prefixes CHECK-C,CHECK-CPP
-
-// Add CodeGen tests for Loop attribute: [[clang::code_align)]].
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -x c %s %s -o - | FileCheck -check-prefix=CHECK-C %s
+// RUN: %clang_cc1 -fsyntax-only -emit-llvm -x c++ -std=c++11 %s -o - | FileCheck %s --check-prefixes CHECK-C,CHECK-CPP
 
 // CHECK-C: br label %for.cond, !llvm.loop ![[MD_FP:[0-9]+]]
 // CHECK-C: br label %while.cond, !llvm.loop ![[MD_FP_1:[0-9]+]]
diff --git a/clang/test/Sema/code_align.c b/clang/test/Sema/code_align.c
index 74f39ffe23300d0..f4f977dbf65767d 100644
--- a/clang/test/Sema/code_align.c
+++ b/clang/test/Sema/code_align.c
@@ -1,7 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -verify=expected,c-local %s
-// RUN: %clang_cc1 -fsyntax-only -verify=expected,cpp-local -pedantic -x c++ -std=c++11 %s 
-
-// Add diagnostics tests for Loop attribute: [[clang::code_align()]].
+// RUN: %clang_cc1 -fsyntax-only -verify=expected,c-local -x c %s
+// RUN: %clang_cc1 -fsyntax-only -verify=expected,cpp-local -pedantic -x c++ -std=c++11 %s
 
 void foo() {
   int i;
@@ -28,11 +26,11 @@ void bar(int);
 #endif
 void foo1(int A)
 {
-  // expected-error at +1 {{'code_align' attribute requires a positive integral compile time constant expression}}
+  // expected-error at +1 {{'code_align' attribute must be a constant power of two between 1 and 4096 inclusive}}
   [[clang::code_align(0)]]
   for(int I=0; I<128; ++I) { bar(I); }
 
-  // expected-error at +1{{'code_align' attribute requires a positive integral compile time constant expression}}
+  // expected-error at +1{{'code_align' attribute must be a constant power of two between 1 and 4096 inclusive}}
   [[clang::code_align(-4)]]
   for(int I=0; I<128; ++I) { bar(I); }
 
@@ -69,10 +67,14 @@ void foo1(int A)
   [[clang::code_align(64)]]
   for(int I=0; I<128; ++I) { bar(I); }
 
-  // expected-error at +1 {{'code_align' attribute argument must be a constant power of two greater than zero}}
+  // expected-error at +1 {{'code_align' attribute must be a constant power of two between 1 and 4096 inclusive}}
   [[clang::code_align(7)]]
   for(int I=0; I<128; ++I) { bar(I); }
 
+  // expected-error at +1 {{'code_align' attribute must be a constant power of two between 1 and 4096 inclusive}}
+  [[clang::code_align(5000)]]
+  for(int I=0; I<128; ++I) { bar(I); }
+
 #if __cplusplus >= 201103L
   // cpp-local-error at +5 {{expression is not an integral constant expression}}
   // cpp-local-note at +4 {{function parameter 'A' with unknown value cannot be used in a constant expression}}
@@ -112,13 +114,14 @@ void code_align_dependent() {
   [[clang::code_align(B)]]
   for(int I=0; I<128; ++I) { bar(I); }
 
-  // cpp-local-error at +1{{'code_align' attribute requires a positive integral compile time constant expression}}
+  // cpp-local-error at +2{{'code_align' attribute must be a constant power of two between 1 and 4096 inclusive}}
+  // cpp-local-note@#neg-instantiation {{in instantiation of function template specialization}}
   [[clang::code_align(D)]]
   for(int I=0; I<128; ++I) { bar(I); }
 }
 
 int main() {
-  code_align_dependent<8, 16, 32, -10>(); // cpp-local-note{{in instantiation of function template specialization 'code_align_dependent<8, 16, 32, -10>' requested here}}
+  code_align_dependent<8, 16, 32, -10>(); // #neg-instantiation
   return 0;
 }
 #endif
diff --git a/clang/test/Sema/code_align_ast.c b/clang/test/Sema/code_align_ast.c
index 300e55d696fd402..962cfa09c539216 100644
--- a/clang/test/Sema/code_align_ast.c
+++ b/clang/test/Sema/code_align_ast.c
@@ -1,9 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -ast-dump -verify %s | FileCheck -check-prefix=CHECK-C %s
-// RUN: %clang_cc1 -x c++ -std=c++11 -fsyntax-only -ast-dump %s | FileCheck %s --check-prefixes CHECK-C,CHECK-CPP
-
-// expected-no-diagnostics
-
-// Add AST tests for Loop attribute: [[clang::code_align()]].
+// RUN: %clang_cc1 -fsyntax-only -ast-dump -verify -x c %s | FileCheck -check-prefix=CHECK-C %s
+// RUN: %clang_cc1 -fsyntax-only -ast-dump -x c++ -std=c++11 %s | FileCheck %s --check-prefixes CHECK-C,CHECK-CPP
 
 void bar(int);
 // CHECK-C: FunctionDecl{{.*}}code_align 'void ()'

>From 6c44cc15df0b98967b6a76c73a16a77539c47ccc Mon Sep 17 00:00:00 2001
From: "Manna, Soumi" <soumi.manna at intel.com>
Date: Wed, 1 Nov 2023 20:41:41 -0700
Subject: [PATCH 03/15] Fix clang format errors

---
 clang/lib/Sema/SemaStmtAttr.cpp | 12 +++++-------
 1 file changed, 5 insertions(+), 7 deletions(-)

diff --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp
index c34fc4de5b0c670..8a75b3021223083 100644
--- a/clang/lib/Sema/SemaStmtAttr.cpp
+++ b/clang/lib/Sema/SemaStmtAttr.cpp
@@ -333,11 +333,9 @@ CodeAlignAttr *Sema::BuildCodeAlignAttr(const AttributeCommonInfo &CI,
 
     int align_value = ArgVal.getSExtValue();
     if (align_value < CodeAlignAttr::getMinValue() ||
-        align_value > CodeAlignAttr::getMaxValue() ||
-        !ArgVal.isPowerOf2()) {
-      Diag(CI.getLoc(), diag:: err_attribute_power_of_two_in_range)
-          << CI << CodeAlignAttr::getMinValue()
-	  << CodeAlignAttr::getMaxValue();
+        align_value > CodeAlignAttr::getMaxValue() || !ArgVal.isPowerOf2()) {
+      Diag(CI.getLoc(), diag::err_attribute_power_of_two_in_range)
+          << CI << CodeAlignAttr::getMinValue() << CodeAlignAttr::getMaxValue();
       return nullptr;
     }
   }
@@ -362,8 +360,8 @@ CheckForDuplicateLoopAttribute(Sema &S,
       if (A) {
         // Cannot specify same type of attribute twice.
         S.Diag(I->getLocation(), diag::err_loop_attr_duplication) << A;
-       }
-       A = I;
+      }
+      A = I;
     }
   }
 }

>From f35c4be758851246b8d11fe7cf64d760e6531a11 Mon Sep 17 00:00:00 2001
From: "Manna, Soumi" <soumi.manna at intel.com>
Date: Thu, 2 Nov 2023 06:14:58 -0700
Subject: [PATCH 04/15] Fix Lit test failure

---
 clang/test/Sema/code_align_ast.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/clang/test/Sema/code_align_ast.c b/clang/test/Sema/code_align_ast.c
index 962cfa09c539216..2cfbf11f1fd0eab 100644
--- a/clang/test/Sema/code_align_ast.c
+++ b/clang/test/Sema/code_align_ast.c
@@ -1,6 +1,8 @@
 // RUN: %clang_cc1 -fsyntax-only -ast-dump -verify -x c %s | FileCheck -check-prefix=CHECK-C %s
 // RUN: %clang_cc1 -fsyntax-only -ast-dump -x c++ -std=c++11 %s | FileCheck %s --check-prefixes CHECK-C,CHECK-CPP
 
+// expected-no-diagnostics
+
 void bar(int);
 // CHECK-C: FunctionDecl{{.*}}code_align 'void ()'
 void code_align() {

>From 4c40ce27e81ae40f05aeabb513881032c04feb92 Mon Sep 17 00:00:00 2001
From: "Manna, Soumi" <soumi.manna at intel.com>
Date: Mon, 6 Nov 2023 09:30:22 -0800
Subject: [PATCH 05/15] Address review comments

---
 clang/docs/ReleaseNotes.rst                   | 17 +++++++
 .../clang/Basic/DiagnosticSemaKinds.td        |  3 +-
 clang/lib/Sema/SemaStmtAttr.cpp               | 28 ++++++----
 clang/test/Sema/code_align.c                  | 51 ++++++++-----------
 4 files changed, 57 insertions(+), 42 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index bc28bb567f6932a..37e985cb13d5072 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -288,6 +288,23 @@ Attribute Changes in Clang
   When viewing ``S::FruitKind`` in a debugger, it will behave as if the member
   was declared as type ``E`` rather than ``unsigned``.
 
+- Clang now supports ``[[clang::code_align(N)]]`` as an attribute which can be
+  applied to a loop and specifies the byte alignment for a loop. This attribute
+  accepts a positive integer constant initialization expression indicating the
+  number of bytes for the minimum alignment boundary. Its value must be a power
+  of 2, between 1 and 4096(inclusive).
+
+  .. code-block:: c++
+
+      void Array(int *array, size_t n) {
+        [[clang::code_align(64)]] for (int i = 0; i < n; ++i) array[i] = 0;
+      }
+
+      template<int A>
+      void func() {
+        [[clang::code_align(A)]] for(;;) { }
+      }
+
 Improvements to Clang's diagnostics
 -----------------------------------
 - Clang constexpr evaluator now prints template arguments when displaying
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 5d9aaba57131445..8dab0bb996d0e9d 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -10029,7 +10029,8 @@ def warn_missing_case_for_condition :
 def err_loop_attr_duplication : Error<
   "duplicate loop attribute %0">;
 def err_attribute_power_of_two_in_range : Error<
-  "%0 attribute must be a constant power of two between %1 and %2 inclusive">;
+  "%0 attribute requires an integer argument which is a constant power of two "
+  "between %1 and %2 inclusive - got %3">;
 
 def warn_def_missing_case : Warning<"%plural{"
   "1:enumeration value %1 not explicitly handled in switch|"
diff --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp
index 8a75b3021223083..a75b1d0b085bb34 100644
--- a/clang/lib/Sema/SemaStmtAttr.cpp
+++ b/clang/lib/Sema/SemaStmtAttr.cpp
@@ -331,15 +331,23 @@ CodeAlignAttr *Sema::BuildCodeAlignAttr(const AttributeCommonInfo &CI,
       return nullptr;
     E = Res.get();
 
-    int align_value = ArgVal.getSExtValue();
-    if (align_value < CodeAlignAttr::getMinValue() ||
-        align_value > CodeAlignAttr::getMaxValue() || !ArgVal.isPowerOf2()) {
+    // This attribute requires a strictly positive value.
+    if (ArgVal <= 0) {
+      Diag(E->getExprLoc(), diag::err_attribute_requires_positive_integer)
+          << CI << /*positive*/ 0;
+      return nullptr;
+    }
+
+    // This attribute requires an integer argument which is a constant power of
+    // two between 1 and 4096 inclusive.
+    int AlignValue = ArgVal.getSExtValue();
+    if (AlignValue > CodeAlignAttr::getMaxValue() || !ArgVal.isPowerOf2()) {
       Diag(CI.getLoc(), diag::err_attribute_power_of_two_in_range)
-          << CI << CodeAlignAttr::getMinValue() << CodeAlignAttr::getMaxValue();
+          << CI << CodeAlignAttr::getMinValue() << CodeAlignAttr::getMaxValue()
+	  << AlignValue;
       return nullptr;
     }
   }
-
   return new (Context) CodeAlignAttr(Context, CI, E);
 }
 
@@ -350,16 +358,16 @@ static Attr *handleCodeAlignAttr(Sema &S, Stmt *St, const ParsedAttr &A) {
 }
 
 // Emit duplicate error for [[clang::code_align()]] attribute.
-template <typename LoopAttrT>
 static void
-CheckForDuplicateLoopAttribute(Sema &S,
-                               const SmallVectorImpl<const Attr *> &Attrs) {
+CheckForDuplicateCodeAlignAttribute(Sema &S,
+                                    const SmallVectorImpl<const Attr *> &Attrs) {
   const Attr *A = nullptr;
   for (const auto *I : Attrs) {
-    if (isa<LoopAttrT>(I)) {
+    if (isa<CodeAlignAttr>(I)) {
       if (A) {
         // Cannot specify same type of attribute twice.
         S.Diag(I->getLocation(), diag::err_loop_attr_duplication) << A;
+	S.Diag(A->getLocation(),diag::note_previous_attribute);
       }
       A = I;
     }
@@ -587,5 +595,5 @@ void Sema::ProcessStmtAttributes(Stmt *S, const ParsedAttributes &InAttrs,
   }
 
   CheckForIncompatibleAttributes(*this, OutAttrs);
-  CheckForDuplicateLoopAttribute<CodeAlignAttr>(*this, OutAttrs);
+  CheckForDuplicateCodeAlignAttribute(*this, OutAttrs);
 }
diff --git a/clang/test/Sema/code_align.c b/clang/test/Sema/code_align.c
index f4f977dbf65767d..715d2896969464b 100644
--- a/clang/test/Sema/code_align.c
+++ b/clang/test/Sema/code_align.c
@@ -21,24 +21,19 @@ void foo() {
 }
 
 void bar(int);
-#if __cplusplus >= 201103L
-// cpp-local-note at +2 {{declared here}}
-#endif
+// cpp-local-note at +1 {{declared here}}
 void foo1(int A)
 {
-  // expected-error at +1 {{'code_align' attribute must be a constant power of two between 1 and 4096 inclusive}}
+  // expected-error at +1 {{'code_align' attribute requires a positive integral compile time constant expression}}
   [[clang::code_align(0)]]
   for(int I=0; I<128; ++I) { bar(I); }
 
-  // expected-error at +1{{'code_align' attribute must be a constant power of two between 1 and 4096 inclusive}}
+  // expected-error at +1 {{'code_align' attribute requires a positive integral compile time constant expression}}
   [[clang::code_align(-4)]]
   for(int I=0; I<128; ++I) { bar(I); }
 
-#if __cplusplus >= 201103L
-    // cpp-local-error at +4 {{integral constant expression must have integral or unscoped enumeration type, not 'double'}}
-#else
-    // c-local-error at +2 {{integer constant expression must have integer type, not 'double'}}
-#endif
+    // cpp-local-error at +2 {{integral constant expression must have integral or unscoped enumeration type, not 'double'}}
+    // c-local-error at +1 {{integer constant expression must have integer type, not 'double'}}
   [[clang::code_align(64.0)]]
   for(int I=0; I<128; ++I) { bar(I); }
 
@@ -54,38 +49,30 @@ void foo1(int A)
   [[clang::code_align(32)]]
   for(int I=0; I<128; ++I) { bar(I); }
 
-#if __cplusplus >= 201103L
-  // cpp-local-error at +4 {{integral constant expression must have integral or unscoped enumeration type, not 'const char[4]'}}
-#else  
-  // c-local-error at +2 {{integer constant expression must have integer type, not 'char[4]'}}
-#endif
+  // cpp-local-error at +2 {{integral constant expression must have integral or unscoped enumeration type, not 'const char[4]'}}
+  // c-local-error at +1 {{integer constant expression must have integer type, not 'char[4]'}}
   [[clang::code_align("abc")]]
   for(int I=0; I<128; ++I) { bar(I); }
 
-  [[clang::code_align(64)]]
-  // expected-error at +1 {{duplicate loop attribute 'code_align'}}
-  [[clang::code_align(64)]]
+  [[clang::code_align(64)]] // expected-note {{previous attribute is here}}
+  [[clang::code_align(64)]] // expected-error {{duplicate loop attribute 'code_align'}}
   for(int I=0; I<128; ++I) { bar(I); }
 
-  // expected-error at +1 {{'code_align' attribute must be a constant power of two between 1 and 4096 inclusive}}
+  // expected-error at +1 {{'code_align' attribute requires an integer argument which is a constant power of two between 1 and 4096 inclusive - got 7}}
   [[clang::code_align(7)]]
   for(int I=0; I<128; ++I) { bar(I); }
 
-  // expected-error at +1 {{'code_align' attribute must be a constant power of two between 1 and 4096 inclusive}}
+  // expected-error at +1 {{'code_align' attribute requires an integer argument which is a constant power of two between 1 and 4096 inclusive - got 5000}}
   [[clang::code_align(5000)]]
   for(int I=0; I<128; ++I) { bar(I); }
 
-#if __cplusplus >= 201103L
-  // cpp-local-error at +5 {{expression is not an integral constant expression}}
-  // cpp-local-note at +4 {{function parameter 'A' with unknown value cannot be used in a constant expression}}
-#else
-  // c-local-error at +2 {{expression is not an integer constant expression}}
-#endif  
+  // cpp-local-error at +3 {{expression is not an integral constant expression}}
+  // cpp-local-note at +2 {{function parameter 'A' with unknown value cannot be used in a constant expression}}
+  // c-local-error at +1 {{expression is not an integer constant expression}}
   [[clang::code_align(A)]]
   for(int I=0; I<128; ++I) { bar(I); }
 }
 
-#if __cplusplus >= 201103L
 void check_code_align_expression() {
   int a[10];
 
@@ -97,24 +84,26 @@ void check_code_align_expression() {
   for (int i = 0; i != 10; ++i)
     a[i] = 0;
 
+#if __cplusplus >= 201103L
   // Test that checks expression is a constant expression.
   constexpr int bars = 0;
   [[clang::code_align(bars + 1)]]
   for (int i = 0; i != 10; ++i)
     a[i] = 0;
+#endif
 }
 
+#if __cplusplus >= 201103L
 template <int A, int B, int C, int D>
 void code_align_dependent() {
   [[clang::code_align(C)]]
   for(int I=0; I<128; ++I) { bar(I); }
 
-  [[clang::code_align(A)]]
-  // cpp-local-error at +1 {{duplicate loop attribute 'code_align'}}
-  [[clang::code_align(B)]]
+  [[clang::code_align(A)]] // expected-note {{previous attribute is here}}
+  [[clang::code_align(B)]] // cpp-local-error  {{duplicate loop attribute 'code_align'}}
   for(int I=0; I<128; ++I) { bar(I); }
 
-  // cpp-local-error at +2{{'code_align' attribute must be a constant power of two between 1 and 4096 inclusive}}
+  // cpp-local-error at +2{{'code_align' attribute requires a positive integral compile time constant expression}}
   // cpp-local-note@#neg-instantiation {{in instantiation of function template specialization}}
   [[clang::code_align(D)]]
   for(int I=0; I<128; ++I) { bar(I); }

>From 9144e440b3898a24bad042158312643a29266cb6 Mon Sep 17 00:00:00 2001
From: "Manna, Soumi" <soumi.manna at intel.com>
Date: Mon, 6 Nov 2023 10:07:30 -0800
Subject: [PATCH 06/15] Fix clang format errors

---
 clang/lib/Sema/SemaStmtAttr.cpp | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp
index a75b1d0b085bb34..e3671cee99422b0 100644
--- a/clang/lib/Sema/SemaStmtAttr.cpp
+++ b/clang/lib/Sema/SemaStmtAttr.cpp
@@ -344,7 +344,7 @@ CodeAlignAttr *Sema::BuildCodeAlignAttr(const AttributeCommonInfo &CI,
     if (AlignValue > CodeAlignAttr::getMaxValue() || !ArgVal.isPowerOf2()) {
       Diag(CI.getLoc(), diag::err_attribute_power_of_two_in_range)
           << CI << CodeAlignAttr::getMinValue() << CodeAlignAttr::getMaxValue()
-	  << AlignValue;
+          << AlignValue;
       return nullptr;
     }
   }
@@ -358,16 +358,15 @@ static Attr *handleCodeAlignAttr(Sema &S, Stmt *St, const ParsedAttr &A) {
 }
 
 // Emit duplicate error for [[clang::code_align()]] attribute.
-static void
-CheckForDuplicateCodeAlignAttribute(Sema &S,
-                                    const SmallVectorImpl<const Attr *> &Attrs) {
+static void CheckForDuplicateCodeAlignAttribute(
+    Sema &S, const SmallVectorImpl<const Attr *> &Attrs) {
   const Attr *A = nullptr;
   for (const auto *I : Attrs) {
     if (isa<CodeAlignAttr>(I)) {
       if (A) {
         // Cannot specify same type of attribute twice.
         S.Diag(I->getLocation(), diag::err_loop_attr_duplication) << A;
-	S.Diag(A->getLocation(),diag::note_previous_attribute);
+        S.Diag(A->getLocation(), diag::note_previous_attribute);
       }
       A = I;
     }

>From 22f66bd0199300a92ea2aefc66a2640e79b734a4 Mon Sep 17 00:00:00 2001
From: "Manna, Soumi" <soumi.manna at intel.com>
Date: Mon, 6 Nov 2023 11:56:08 -0800
Subject: [PATCH 07/15] Address review comments

---
 clang/include/clang/Basic/DiagnosticSemaKinds.td |  2 +-
 clang/lib/CodeGen/CGLoopInfo.cpp                 | 10 ++++------
 clang/lib/Sema/SemaStmtAttr.cpp                  | 10 ++--------
 clang/test/Sema/code_align.c                     | 10 +++++-----
 4 files changed, 12 insertions(+), 20 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 8dab0bb996d0e9d..886458f5e946e6d 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -10030,7 +10030,7 @@ def err_loop_attr_duplication : Error<
   "duplicate loop attribute %0">;
 def err_attribute_power_of_two_in_range : Error<
   "%0 attribute requires an integer argument which is a constant power of two "
-  "between %1 and %2 inclusive - got %3">;
+  "between %1 and %2 inclusive; got %3">;
 
 def warn_def_missing_case : Warning<"%plural{"
   "1:enumeration value %1 not explicitly handled in switch|"
diff --git a/clang/lib/CodeGen/CGLoopInfo.cpp b/clang/lib/CodeGen/CGLoopInfo.cpp
index a951198b925a513..0d4800b90a2f26c 100644
--- a/clang/lib/CodeGen/CGLoopInfo.cpp
+++ b/clang/lib/CodeGen/CGLoopInfo.cpp
@@ -800,12 +800,10 @@ void LoopInfoStack::push(BasicBlock *Header, clang::ASTContext &Ctx,
   // Identify loop attribute 'code_align' from Attrs.
   // For attribute code_align:
   // n - 'llvm.loop.align i32 n' metadata will be emitted.
-  for (const auto *A : Attrs) {
-    if (const auto *CodeAlign = dyn_cast<CodeAlignAttr>(A)) {
-      const auto *CE = cast<ConstantExpr>(CodeAlign->getAlignment());
-      llvm::APSInt ArgVal = CE->getResultAsAPSInt();
-      setCodeAlign(ArgVal.getSExtValue());
-    }
+  if (const auto *CodeAlign = getSpecificAttr<const CodeAlignAttr>(Attrs)) {
+    const auto *CE = cast<ConstantExpr>(CodeAlign->getAlignment());
+    llvm::APSInt ArgVal = CE->getResultAsAPSInt();
+    setCodeAlign(ArgVal.getSExtValue());
   }
 
   setMustProgress(MustProgress);
diff --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp
index e3671cee99422b0..96fa74427ee7852 100644
--- a/clang/lib/Sema/SemaStmtAttr.cpp
+++ b/clang/lib/Sema/SemaStmtAttr.cpp
@@ -331,17 +331,11 @@ CodeAlignAttr *Sema::BuildCodeAlignAttr(const AttributeCommonInfo &CI,
       return nullptr;
     E = Res.get();
 
-    // This attribute requires a strictly positive value.
-    if (ArgVal <= 0) {
-      Diag(E->getExprLoc(), diag::err_attribute_requires_positive_integer)
-          << CI << /*positive*/ 0;
-      return nullptr;
-    }
-
     // This attribute requires an integer argument which is a constant power of
     // two between 1 and 4096 inclusive.
     int AlignValue = ArgVal.getSExtValue();
-    if (AlignValue > CodeAlignAttr::getMaxValue() || !ArgVal.isPowerOf2()) {
+    if (AlignValue < CodeAlignAttr::getMinValue() ||
+        AlignValue > CodeAlignAttr::getMaxValue() || !ArgVal.isPowerOf2()) {
       Diag(CI.getLoc(), diag::err_attribute_power_of_two_in_range)
           << CI << CodeAlignAttr::getMinValue() << CodeAlignAttr::getMaxValue()
           << AlignValue;
diff --git a/clang/test/Sema/code_align.c b/clang/test/Sema/code_align.c
index 715d2896969464b..51ecc070c672ed5 100644
--- a/clang/test/Sema/code_align.c
+++ b/clang/test/Sema/code_align.c
@@ -24,11 +24,11 @@ void bar(int);
 // cpp-local-note at +1 {{declared here}}
 void foo1(int A)
 {
-  // expected-error at +1 {{'code_align' attribute requires a positive integral compile time constant expression}}
+  // expected-error at +1 {{'code_align' attribute requires an integer argument which is a constant power of two between 1 and 4096 inclusive; got 0}}
   [[clang::code_align(0)]]
   for(int I=0; I<128; ++I) { bar(I); }
 
-  // expected-error at +1 {{'code_align' attribute requires a positive integral compile time constant expression}}
+  // expected-error at +1 {{'code_align' attribute requires an integer argument which is a constant power of two between 1 and 4096 inclusive; got -4}}
   [[clang::code_align(-4)]]
   for(int I=0; I<128; ++I) { bar(I); }
 
@@ -58,11 +58,11 @@ void foo1(int A)
   [[clang::code_align(64)]] // expected-error {{duplicate loop attribute 'code_align'}}
   for(int I=0; I<128; ++I) { bar(I); }
 
-  // expected-error at +1 {{'code_align' attribute requires an integer argument which is a constant power of two between 1 and 4096 inclusive - got 7}}
+  // expected-error at +1 {{'code_align' attribute requires an integer argument which is a constant power of two between 1 and 4096 inclusive; got 7}}
   [[clang::code_align(7)]]
   for(int I=0; I<128; ++I) { bar(I); }
 
-  // expected-error at +1 {{'code_align' attribute requires an integer argument which is a constant power of two between 1 and 4096 inclusive - got 5000}}
+  // expected-error at +1 {{'code_align' attribute requires an integer argument which is a constant power of two between 1 and 4096 inclusive; got 5000}}
   [[clang::code_align(5000)]]
   for(int I=0; I<128; ++I) { bar(I); }
 
@@ -103,7 +103,7 @@ void code_align_dependent() {
   [[clang::code_align(B)]] // cpp-local-error  {{duplicate loop attribute 'code_align'}}
   for(int I=0; I<128; ++I) { bar(I); }
 
-  // cpp-local-error at +2{{'code_align' attribute requires a positive integral compile time constant expression}}
+  // cpp-local-error at +2{{'code_align' attribute requires an integer argument which is a constant power of two between 1 and 4096 inclusive; got -10}}
   // cpp-local-note@#neg-instantiation {{in instantiation of function template specialization}}
   [[clang::code_align(D)]]
   for(int I=0; I<128; ++I) { bar(I); }

>From 66f6269c4c00825e6f839fd9b6c1c204600e06b7 Mon Sep 17 00:00:00 2001
From: "Manna, Soumi" <soumi.manna at intel.com>
Date: Mon, 6 Nov 2023 19:28:02 -0800
Subject: [PATCH 08/15] Fix lit test failure

---
 clang/test/Sema/code_align.c | 41 ++++++++++++++++++------------------
 1 file changed, 21 insertions(+), 20 deletions(-)

diff --git a/clang/test/Sema/code_align.c b/clang/test/Sema/code_align.c
index 51ecc070c672ed5..ad8ec603a4d19e1 100644
--- a/clang/test/Sema/code_align.c
+++ b/clang/test/Sema/code_align.c
@@ -9,7 +9,7 @@ void foo() {
   for (i = 0; i < 10; ++i) {  // this is OK
     a[i] = b[i] = 0;
   }
-  // expected-error at +1 {{'code_align' attribute only applies to 'for', 'while', and 'do' statements}}
+  // expected-error at +1{{'code_align' attribute only applies to 'for', 'while', and 'do' statements}}
   [[clang::code_align(4)]]
   i = 7;
   for (i = 0; i < 10; ++i) {
@@ -21,27 +21,27 @@ void foo() {
 }
 
 void bar(int);
-// cpp-local-note at +1 {{declared here}}
+// cpp-local-note at +1{{declared here}}
 void foo1(int A)
 {
-  // expected-error at +1 {{'code_align' attribute requires an integer argument which is a constant power of two between 1 and 4096 inclusive; got 0}}
+  // expected-error at +1{{'code_align' attribute requires an integer argument which is a constant power of two between 1 and 4096 inclusive; got 0}}
   [[clang::code_align(0)]]
   for(int I=0; I<128; ++I) { bar(I); }
 
-  // expected-error at +1 {{'code_align' attribute requires an integer argument which is a constant power of two between 1 and 4096 inclusive; got -4}}
+  // expected-error at +1{{'code_align' attribute requires an integer argument which is a constant power of two between 1 and 4096 inclusive; got -4}}
   [[clang::code_align(-4)]]
   for(int I=0; I<128; ++I) { bar(I); }
 
-    // cpp-local-error at +2 {{integral constant expression must have integral or unscoped enumeration type, not 'double'}}
-    // c-local-error at +1 {{integer constant expression must have integer type, not 'double'}}
+    // cpp-local-error at +2{{integral constant expression must have integral or unscoped enumeration type, not 'double'}}
+    // c-local-error at +1{{integer constant expression must have integer type, not 'double'}}
   [[clang::code_align(64.0)]]
   for(int I=0; I<128; ++I) { bar(I); }
 
-  // expected-error at +1 {{'code_align' attribute takes one argument}}
+  // expected-error at +1{{'code_align' attribute takes one argument}}
   [[clang::code_align()]]
   for(int I=0; I<128; ++I) { bar(I); }
 
-  // expected-error at +1 {{'code_align' attribute takes one argument}}
+  // expected-error at +1{{'code_align' attribute takes one argument}}
   [[clang::code_align(4,8)]]
   for(int I=0; I<128; ++I) { bar(I); }
 
@@ -49,26 +49,26 @@ void foo1(int A)
   [[clang::code_align(32)]]
   for(int I=0; I<128; ++I) { bar(I); }
 
-  // cpp-local-error at +2 {{integral constant expression must have integral or unscoped enumeration type, not 'const char[4]'}}
-  // c-local-error at +1 {{integer constant expression must have integer type, not 'char[4]'}}
+  // cpp-local-error at +2{{integral constant expression must have integral or unscoped enumeration type, not 'const char[4]'}}
+  // c-local-error at +1{{integer constant expression must have integer type, not 'char[4]'}}
   [[clang::code_align("abc")]]
   for(int I=0; I<128; ++I) { bar(I); }
 
-  [[clang::code_align(64)]] // expected-note {{previous attribute is here}}
-  [[clang::code_align(64)]] // expected-error {{duplicate loop attribute 'code_align'}}
+  [[clang::code_align(64)]] // expected-note{{previous attribute is here}}
+  [[clang::code_align(64)]] // expected-error{{duplicate loop attribute 'code_align'}}
   for(int I=0; I<128; ++I) { bar(I); }
 
-  // expected-error at +1 {{'code_align' attribute requires an integer argument which is a constant power of two between 1 and 4096 inclusive; got 7}}
+  // expected-error at +1{{'code_align' attribute requires an integer argument which is a constant power of two between 1 and 4096 inclusive; got 7}}
   [[clang::code_align(7)]]
   for(int I=0; I<128; ++I) { bar(I); }
 
-  // expected-error at +1 {{'code_align' attribute requires an integer argument which is a constant power of two between 1 and 4096 inclusive; got 5000}}
+  // expected-error at +1{{'code_align' attribute requires an integer argument which is a constant power of two between 1 and 4096 inclusive; got 5000}}
   [[clang::code_align(5000)]]
   for(int I=0; I<128; ++I) { bar(I); }
 
-  // cpp-local-error at +3 {{expression is not an integral constant expression}}
-  // cpp-local-note at +2 {{function parameter 'A' with unknown value cannot be used in a constant expression}}
-  // c-local-error at +1 {{expression is not an integer constant expression}}
+  // cpp-local-error at +3{{expression is not an integral constant expression}}
+  // cpp-local-note at +2{{function parameter 'A' with unknown value cannot be used in a constant expression}}
+  // c-local-error at +1{{expression is not an integer constant expression}}
   [[clang::code_align(A)]]
   for(int I=0; I<128; ++I) { bar(I); }
 }
@@ -78,6 +78,7 @@ void check_code_align_expression() {
 
   // Test that checks expression is not a constant expression.
   int foo2; // cpp-local-note {{declared here}}
+  // c-local-error at +3{{expression is not an integer constant expression}}
   // cpp-local-error at +2{{expression is not an integral constant expression}}
   // cpp-local-note at +1{{read of non-const variable 'foo2' is not allowed in a constant expression}}
   [[clang::code_align(foo2 + 1)]]
@@ -99,12 +100,12 @@ void code_align_dependent() {
   [[clang::code_align(C)]]
   for(int I=0; I<128; ++I) { bar(I); }
 
-  [[clang::code_align(A)]] // expected-note {{previous attribute is here}}
-  [[clang::code_align(B)]] // cpp-local-error  {{duplicate loop attribute 'code_align'}}
+  [[clang::code_align(A)]] // expected-note{{previous attribute is here}}
+  [[clang::code_align(B)]] // cpp-local-error{{duplicate loop attribute 'code_align'}}
   for(int I=0; I<128; ++I) { bar(I); }
 
   // cpp-local-error at +2{{'code_align' attribute requires an integer argument which is a constant power of two between 1 and 4096 inclusive; got -10}}
-  // cpp-local-note@#neg-instantiation {{in instantiation of function template specialization}}
+  // cpp-local-note@#neg-instantiation{{in instantiation of function template specialization}}
   [[clang::code_align(D)]]
   for(int I=0; I<128; ++I) { bar(I); }
 }

>From 3ac064bc26a516a81b2ff36ec0dc9c55350c3e3f Mon Sep 17 00:00:00 2001
From: "Manna, Soumi" <soumi.manna at intel.com>
Date: Mon, 6 Nov 2023 20:23:07 -0800
Subject: [PATCH 09/15] Fix DuplicateCodeAlignAttrs check

---
 clang/lib/Sema/SemaStmtAttr.cpp | 38 +++++++++++++++++++++++----------
 1 file changed, 27 insertions(+), 11 deletions(-)

diff --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp
index 96fa74427ee7852..253b6378953b485 100644
--- a/clang/lib/Sema/SemaStmtAttr.cpp
+++ b/clang/lib/Sema/SemaStmtAttr.cpp
@@ -352,17 +352,33 @@ static Attr *handleCodeAlignAttr(Sema &S, Stmt *St, const ParsedAttr &A) {
 }
 
 // Emit duplicate error for [[clang::code_align()]] attribute.
-static void CheckForDuplicateCodeAlignAttribute(
-    Sema &S, const SmallVectorImpl<const Attr *> &Attrs) {
-  const Attr *A = nullptr;
-  for (const auto *I : Attrs) {
-    if (isa<CodeAlignAttr>(I)) {
-      if (A) {
-        // Cannot specify same type of attribute twice.
-        S.Diag(I->getLocation(), diag::err_loop_attr_duplication) << A;
-        S.Diag(A->getLocation(), diag::note_previous_attribute);
-      }
-      A = I;
+static void
+CheckForDuplicateCodeAlignAttrs(Sema &S,
+                                ArrayRef<const Attr *> Attrs) {
+  // Create a list of CodeAlign attributes only.
+  SmallVector<const CodeAlignAttr *, 8> OnlyCodeAlignAttrs;
+  llvm::transform(
+      Attrs, std::back_inserter(OnlyCodeAlignAttrs), [](const Attr *A) {
+        return dyn_cast_or_null<const CodeAlignAttr>(A);
+      });
+  OnlyCodeAlignAttrs.erase(
+      std::remove(OnlyCodeAlignAttrs.begin(), OnlyCodeAlignAttrs.end(),
+                  static_cast<CodeAlignAttr *>(nullptr)),
+      OnlyCodeAlignAttrs.end());
+  if (OnlyCodeAlignAttrs.empty())
+    return;
+
+  for (const auto *I : OnlyCodeAlignAttrs) {
+    const auto *OtherAttrItr =
+    llvm::find_if(OnlyCodeAlignAttrs, [](const CodeAlignAttr *A) {
+      return isa<CodeAlignAttr>(A);
+    });
+
+    const CodeAlignAttr *OtherAttr =
+        OtherAttrItr == OnlyCodeAlignAttrs.end() ? nullptr : *OtherAttrItr;
+    if (OtherAttr != I) {
+      S.Diag(I->getLocation(), diag::err_loop_attr_duplication) << OtherAttr;
+      S.Diag(OtherAttr->getLocation(), diag::note_previous_attribute);
     }
   }
 }

>From 172e2385edfb3f87b8c80c5d96a8fbb7c52e805d Mon Sep 17 00:00:00 2001
From: "Manna, Soumi" <soumi.manna at intel.com>
Date: Mon, 6 Nov 2023 20:42:01 -0800
Subject: [PATCH 10/15] Fix Clang format errors

---
 clang/lib/Sema/SemaStmtAttr.cpp | 25 ++++++++++++-------------
 1 file changed, 12 insertions(+), 13 deletions(-)

diff --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp
index 253b6378953b485..a3042a380913329 100644
--- a/clang/lib/Sema/SemaStmtAttr.cpp
+++ b/clang/lib/Sema/SemaStmtAttr.cpp
@@ -352,27 +352,26 @@ static Attr *handleCodeAlignAttr(Sema &S, Stmt *St, const ParsedAttr &A) {
 }
 
 // Emit duplicate error for [[clang::code_align()]] attribute.
-static void
-CheckForDuplicateCodeAlignAttrs(Sema &S,
-                                ArrayRef<const Attr *> Attrs) {
+static void CheckForDuplicateCodeAlignAttrs(Sema &S,
+                                            ArrayRef<const Attr *> Attrs) {
   // Create a list of CodeAlign attributes only.
   SmallVector<const CodeAlignAttr *, 8> OnlyCodeAlignAttrs;
   llvm::transform(
-      Attrs, std::back_inserter(OnlyCodeAlignAttrs), [](const Attr *A) {
-        return dyn_cast_or_null<const CodeAlignAttr>(A);
-      });
-  OnlyCodeAlignAttrs.erase(
-      std::remove(OnlyCodeAlignAttrs.begin(), OnlyCodeAlignAttrs.end(),
-                  static_cast<CodeAlignAttr *>(nullptr)),
-      OnlyCodeAlignAttrs.end());
+      Attrs, std::back_inserter(OnlyCodeAlignAttrs),
+      [](const Attr *A) { return dyn_cast_or_null<const CodeAlignAttr>(A); });
+  OnlyCodeAlignAttrs.erase(std::remove(OnlyCodeAlignAttrs.begin(),
+                                       OnlyCodeAlignAttrs.end(),
+                                       static_cast<CodeAlignAttr *>(nullptr)),
+                           OnlyCodeAlignAttrs.end());
+
   if (OnlyCodeAlignAttrs.empty())
     return;
 
   for (const auto *I : OnlyCodeAlignAttrs) {
     const auto *OtherAttrItr =
-    llvm::find_if(OnlyCodeAlignAttrs, [](const CodeAlignAttr *A) {
-      return isa<CodeAlignAttr>(A);
-    });
+        llvm::find_if(OnlyCodeAlignAttrs, [](const CodeAlignAttr *A) {
+          return isa<CodeAlignAttr>(A);
+        });
 
     const CodeAlignAttr *OtherAttr =
         OtherAttrItr == OnlyCodeAlignAttrs.end() ? nullptr : *OtherAttrItr;

>From c8d5270bc4eca6a6b9c6beedbf00c92fa502f487 Mon Sep 17 00:00:00 2001
From: "Manna, Soumi" <soumi.manna at intel.com>
Date: Mon, 6 Nov 2023 20:52:56 -0800
Subject: [PATCH 11/15] Remove wrong function

---
 clang/lib/Sema/SemaStmtAttr.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp
index a3042a380913329..81b25fd1bbe20d4 100644
--- a/clang/lib/Sema/SemaStmtAttr.cpp
+++ b/clang/lib/Sema/SemaStmtAttr.cpp
@@ -603,5 +603,5 @@ void Sema::ProcessStmtAttributes(Stmt *S, const ParsedAttributes &InAttrs,
   }
 
   CheckForIncompatibleAttributes(*this, OutAttrs);
-  CheckForDuplicateCodeAlignAttribute(*this, OutAttrs);
+  CheckForDuplicateCodeAlignAttrs(*this, OutAttrs);
 }

>From 2e6ee337a76ace24d22351475da366d193393312 Mon Sep 17 00:00:00 2001
From: "Manna, Soumi" <soumi.manna at intel.com>
Date: Mon, 13 Nov 2023 09:53:12 -0800
Subject: [PATCH 12/15] Update diagnostic message and test

---
 clang/include/clang/Basic/DiagnosticSemaKinds.td |  2 +-
 clang/test/Sema/code_align.c                     | 10 +++++-----
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 83993def97c350d..27d322e1d46e622 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -10029,7 +10029,7 @@ def err_loop_attr_duplication : Error<
   "duplicate loop attribute %0">;
 def err_attribute_power_of_two_in_range : Error<
   "%0 attribute requires an integer argument which is a constant power of two "
-  "between %1 and %2 inclusive; got %3">;
+  "between %1 and %2 inclusive; provided argument was %3">;
 
 def warn_def_missing_case : Warning<"%plural{"
   "1:enumeration value %1 not explicitly handled in switch|"
diff --git a/clang/test/Sema/code_align.c b/clang/test/Sema/code_align.c
index ad8ec603a4d19e1..07bb50f7574c825 100644
--- a/clang/test/Sema/code_align.c
+++ b/clang/test/Sema/code_align.c
@@ -24,11 +24,11 @@ void bar(int);
 // cpp-local-note at +1{{declared here}}
 void foo1(int A)
 {
-  // expected-error at +1{{'code_align' attribute requires an integer argument which is a constant power of two between 1 and 4096 inclusive; got 0}}
+  // expected-error at +1{{'code_align' attribute requires an integer argument which is a constant power of two between 1 and 4096 inclusive; provided argument was 0}}
   [[clang::code_align(0)]]
   for(int I=0; I<128; ++I) { bar(I); }
 
-  // expected-error at +1{{'code_align' attribute requires an integer argument which is a constant power of two between 1 and 4096 inclusive; got -4}}
+  // expected-error at +1{{'code_align' attribute requires an integer argument which is a constant power of two between 1 and 4096 inclusive; provided argument was -4}}
   [[clang::code_align(-4)]]
   for(int I=0; I<128; ++I) { bar(I); }
 
@@ -58,11 +58,11 @@ void foo1(int A)
   [[clang::code_align(64)]] // expected-error{{duplicate loop attribute 'code_align'}}
   for(int I=0; I<128; ++I) { bar(I); }
 
-  // expected-error at +1{{'code_align' attribute requires an integer argument which is a constant power of two between 1 and 4096 inclusive; got 7}}
+  // expected-error at +1{{'code_align' attribute requires an integer argument which is a constant power of two between 1 and 4096 inclusive; provided argument was 7}}
   [[clang::code_align(7)]]
   for(int I=0; I<128; ++I) { bar(I); }
 
-  // expected-error at +1{{'code_align' attribute requires an integer argument which is a constant power of two between 1 and 4096 inclusive; got 5000}}
+  // expected-error at +1{{'code_align' attribute requires an integer argument which is a constant power of two between 1 and 4096 inclusive; provided argument was 5000}}
   [[clang::code_align(5000)]]
   for(int I=0; I<128; ++I) { bar(I); }
 
@@ -104,7 +104,7 @@ void code_align_dependent() {
   [[clang::code_align(B)]] // cpp-local-error{{duplicate loop attribute 'code_align'}}
   for(int I=0; I<128; ++I) { bar(I); }
 
-  // cpp-local-error at +2{{'code_align' attribute requires an integer argument which is a constant power of two between 1 and 4096 inclusive; got -10}}
+  // cpp-local-error at +2{{'code_align' attribute requires an integer argument which is a constant power of two between 1 and 4096 inclusive; provided argument was -10}}
   // cpp-local-note@#neg-instantiation{{in instantiation of function template specialization}}
   [[clang::code_align(D)]]
   for(int I=0; I<128; ++I) { bar(I); }

>From 84748604e3a392d6d3a4f2559992d63b485bb647 Mon Sep 17 00:00:00 2001
From: "Manna, Soumi" <soumi.manna at intel.com>
Date: Mon, 13 Nov 2023 10:59:49 -0800
Subject: [PATCH 13/15] Update min and max aligment check

---
 clang/include/clang/Basic/Attr.td | 8 --------
 clang/lib/Sema/SemaStmtAttr.cpp   | 9 +++++----
 2 files changed, 5 insertions(+), 12 deletions(-)

diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index 51d92c662743885..6ab206039d91812 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -4304,12 +4304,4 @@ def CodeAlign: StmtAttr {
                               ErrorDiag, "'for', 'while', and 'do' statements">;
   let Args = [ExprArgument<"Alignment">];
   let Documentation = [CodeAlignAttrDocs];
-  let AdditionalMembers = [{
-    static int getMinValue() {
-      return 1;
-    }
-    static int getMaxValue() {
-      return 4096;
-    }
-  }];
 }
diff --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp
index 81b25fd1bbe20d4..9dafc90557a86c4 100644
--- a/clang/lib/Sema/SemaStmtAttr.cpp
+++ b/clang/lib/Sema/SemaStmtAttr.cpp
@@ -334,11 +334,12 @@ CodeAlignAttr *Sema::BuildCodeAlignAttr(const AttributeCommonInfo &CI,
     // This attribute requires an integer argument which is a constant power of
     // two between 1 and 4096 inclusive.
     int AlignValue = ArgVal.getSExtValue();
-    if (AlignValue < CodeAlignAttr::getMinValue() ||
-        AlignValue > CodeAlignAttr::getMaxValue() || !ArgVal.isPowerOf2()) {
+    static int MaximumAlignment = 4096;
+    static int MinimumAlignment = 1;
+    if (AlignValue < MinimumAlignment ||
+        AlignValue > MaximumAlignment || !ArgVal.isPowerOf2()) {
       Diag(CI.getLoc(), diag::err_attribute_power_of_two_in_range)
-          << CI << CodeAlignAttr::getMinValue() << CodeAlignAttr::getMaxValue()
-          << AlignValue;
+          << CI << MinimumAlignment << MaximumAlignment << AlignValue;
       return nullptr;
     }
   }

>From aa85ed1ede892c7da3d5c2dee5886dd0e2ad0cb7 Mon Sep 17 00:00:00 2001
From: "Manna, Soumi" <soumi.manna at intel.com>
Date: Mon, 13 Nov 2023 11:42:01 -0800
Subject: [PATCH 14/15] Add additional members as static-constexpr

---
 clang/include/clang/Basic/Attr.td | 4 ++++
 clang/lib/Sema/SemaStmtAttr.cpp   | 9 ++++-----
 2 files changed, 8 insertions(+), 5 deletions(-)

diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index 6ab206039d91812..fddd425356d3283 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -4304,4 +4304,8 @@ def CodeAlign: StmtAttr {
                               ErrorDiag, "'for', 'while', and 'do' statements">;
   let Args = [ExprArgument<"Alignment">];
   let Documentation = [CodeAlignAttrDocs];
+  let AdditionalMembers = [{
+    static constexpr int MinimumAlignment = 1;
+    static constexpr int MaximumAlignment = 4096;
+  }];
 }
diff --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp
index 9dafc90557a86c4..df3d37327c2e0a0 100644
--- a/clang/lib/Sema/SemaStmtAttr.cpp
+++ b/clang/lib/Sema/SemaStmtAttr.cpp
@@ -334,12 +334,11 @@ CodeAlignAttr *Sema::BuildCodeAlignAttr(const AttributeCommonInfo &CI,
     // This attribute requires an integer argument which is a constant power of
     // two between 1 and 4096 inclusive.
     int AlignValue = ArgVal.getSExtValue();
-    static int MaximumAlignment = 4096;
-    static int MinimumAlignment = 1;
-    if (AlignValue < MinimumAlignment ||
-        AlignValue > MaximumAlignment || !ArgVal.isPowerOf2()) {
+    if (AlignValue < CodeAlignAttr::MinimumAlignment ||
+        AlignValue > CodeAlignAttr::MaximumAlignment || !ArgVal.isPowerOf2()) {
       Diag(CI.getLoc(), diag::err_attribute_power_of_two_in_range)
-          << CI << MinimumAlignment << MaximumAlignment << AlignValue;
+          << CI << CodeAlignAttr::MinimumAlignment
+          << CodeAlignAttr::MaximumAlignment << AlignValue;
       return nullptr;
     }
   }

>From 088767463be990eb8af4e62a6c66cf4ba06613c3 Mon Sep 17 00:00:00 2001
From: "Manna, Soumi" <soumi.manna at intel.com>
Date: Mon, 13 Nov 2023 19:48:36 -0800
Subject: [PATCH 15/15] Address review comments

---
 clang/lib/Sema/SemaStmtAttr.cpp | 13 +++++++++----
 clang/test/Sema/code_align.c    | 17 +++++++++++++++++
 2 files changed, 26 insertions(+), 4 deletions(-)

diff --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp
index df3d37327c2e0a0..58c676e83036228 100644
--- a/clang/lib/Sema/SemaStmtAttr.cpp
+++ b/clang/lib/Sema/SemaStmtAttr.cpp
@@ -333,12 +333,17 @@ CodeAlignAttr *Sema::BuildCodeAlignAttr(const AttributeCommonInfo &CI,
 
     // This attribute requires an integer argument which is a constant power of
     // two between 1 and 4096 inclusive.
-    int AlignValue = ArgVal.getSExtValue();
-    if (AlignValue < CodeAlignAttr::MinimumAlignment ||
-        AlignValue > CodeAlignAttr::MaximumAlignment || !ArgVal.isPowerOf2()) {
+    if (ArgVal < CodeAlignAttr::MinimumAlignment) {
       Diag(CI.getLoc(), diag::err_attribute_power_of_two_in_range)
           << CI << CodeAlignAttr::MinimumAlignment
-          << CodeAlignAttr::MaximumAlignment << AlignValue;
+          << CodeAlignAttr::MaximumAlignment << ArgVal.getSExtValue();
+      return nullptr;
+    }
+
+    if (ArgVal > CodeAlignAttr::MaximumAlignment || !ArgVal.isPowerOf2()) {
+      Diag(CI.getLoc(), diag::err_attribute_power_of_two_in_range)
+          << CI << CodeAlignAttr::MinimumAlignment
+          << CodeAlignAttr::MaximumAlignment << ArgVal.getZExtValue();
       return nullptr;
     }
   }
diff --git a/clang/test/Sema/code_align.c b/clang/test/Sema/code_align.c
index 07bb50f7574c825..0ef606e7ffec36a 100644
--- a/clang/test/Sema/code_align.c
+++ b/clang/test/Sema/code_align.c
@@ -66,6 +66,23 @@ void foo1(int A)
   [[clang::code_align(5000)]]
   for(int I=0; I<128; ++I) { bar(I); }
 
+  // expected-warning at +2 {{integer literal is too large to be represented in a signed integer type, interpreting as unsigned}}
+  // expected-error at +1 {{'code_align' attribute requires an integer argument which is a constant power of two between 1 and 4096 inclusive; provided argument was 9223372036854775808}}
+  [[clang::code_align(9223372036854775808)]]
+  for(int I=0; I<256; ++I) { bar(I); }
+
+  // expected-error at +1 {{'code_align' attribute requires an integer argument which is a constant power of two between 1 and 4096 inclusive; provided argument was 0}}
+  [[clang::code_align((__int128_t)0x1234567890abcde0ULL << 64)]]
+  for(int I=0; I<256; ++I) { bar(I); }
+
+  // expected-error at +1 {{'code_align' attribute requires an integer argument which is a constant power of two between 1 and 4096 inclusive; provided argument was 1311768467294899680}}
+  [[clang::code_align((__int128_t)0x1234567890abcde0ULL)]]
+  for(int I=0; I<256; ++I) { bar(I); }
+
+  // expected-error at +1 {{'code_align' attribute requires an integer argument which is a constant power of two between 1 and 4096 inclusive; provided argument was 32768}}
+  [[clang::code_align(32768)]]
+  for(int I=0; I<256; ++I) { bar(I); }
+
   // cpp-local-error at +3{{expression is not an integral constant expression}}
   // cpp-local-note at +2{{function parameter 'A' with unknown value cannot be used in a constant expression}}
   // c-local-error at +1{{expression is not an integer constant expression}}



More information about the flang-commits mailing list