llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clangir

@llvm/pr-subscribers-clang

Author: Erich Keane (erichkeane)

<details>
<summary>Changes</summary>

Classic codegen has a lot of infrastructure to emit the loop-info-stack, we can 
do it as a pretty simple attribute. This handles lowering to CIR for these 
hints, after extracting the stuff that determines the values to a separate type 
in CodeGenUtils.

Flattening the loops/emitting this to LLVM-IR is left to a follow up.

AI Notice: I made claude help me with the tests, so it did much of that to make 
sure we got reasonable test coverage.

---

Patch is 62.67 KiB, truncated to 20.00 KiB below, full version: 
https://github.com/llvm/llvm-project/pull/232975.diff


17 Files Affected:

- (modified) clang/include/clang/CIR/Dialect/IR/CIRAttrs.td (+134) 
- (modified) clang/include/clang/CIR/Dialect/IR/CIROps.td (+11-4) 
- (added) clang/include/clang/CodeGenUtils/LoopAttributes.h (+98) 
- (modified) clang/lib/CIR/CodeGen/CIRGenFunction.h (+11-3) 
- (modified) clang/lib/CIR/CodeGen/CIRGenStmt.cpp (+101-17) 
- (modified) clang/lib/CodeGen/CGLoopInfo.cpp (+2-262) 
- (modified) clang/lib/CodeGen/CGLoopInfo.h (+4-56) 
- (modified) clang/lib/CodeGenUtils/CMakeLists.txt (+1) 
- (added) clang/lib/CodeGenUtils/LoopAttributes.cpp (+285) 
- (added) clang/test/CIR/CodeGen/loop-hints-stds.cpp (+84) 
- (added) clang/test/CIR/CodeGen/loop-hints.c (+52) 
- (added) clang/test/CIR/CodeGen/loop-hints.cpp (+139) 
- (added) clang/test/CIR/CodeGenHLSL/loop-hints.hlsl (+16) 
- (modified) clang/test/CIR/CodeGenOpenACC/loop.cpp (+1-1) 
- (added) clang/test/CIR/CodeGenOpenCL/loop-hints.cl (+18) 
- (added) clang/test/CIR/IR/invalid-loop-hints.cir (+73) 
- (added) clang/test/CIR/IR/loop-hints.cir (+40) 


``````````diff
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td 
b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
index aa9562586d2f5..b3cc021989fde 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
@@ -953,6 +953,140 @@ def CIR_FenvAttr : CIR_Attr<"Fenv", "fenv"> {
   let canHaveIllegalCXXABIType = 0;
 }
 
+//===----------------------------------------------------------------------===//
+// CIR_FlagParam
+//===----------------------------------------------------------------------===//
+
+/// A simple UnitAttr wrapper so that an attributes parameter can print JUST 
its
+/// name and be used with the ($keyword^)? syntax in assemblyFormat.
+class CIR_FlagParam<string keyword> : OptionalParameter<"mlir::UnitAttr"> {
+  let printer = "$_printer << \"" # keyword # "\"";
+  let parser = "[&]() -> ::mlir::FailureOr<::mlir::UnitAttr> {\n"
+               "  if (::mlir::succeeded($_parser.parseOptionalKeyword(\""
+               # keyword # "\")))\n"
+               "    return ::mlir::UnitAttr::get($_ctxt);\n"
+               "  return ::mlir::UnitAttr();\n"
+               "}()";
+}
+
+//===----------------------------------------------------------------------===//
+// LoopUnrollMode
+//===----------------------------------------------------------------------===//
+
+def CIR_LoopUnrollMode : CIR_I32Enum<
+    "LoopUnrollMode", "loop unrolling mode", [
+  I32EnumCase<"Enable", 0, "enable">,
+  I32EnumCase<"Disable", 1, "disable">,
+  I32EnumCase<"Full", 2, "full">
+]> {
+  let description = [{
+    How a loop is unrolled (or unrolled and jammed): `enable` asks for the
+    optimizer to unroll the loop, `disable` forbids it, and `full` asks for it
+    to be unrolled completely.
+  }];
+}
+
+//===----------------------------------------------------------------------===//
+// LoopHintAttr
+//===----------------------------------------------------------------------===//
+
+def CIR_LoopHintAttr : CIR_Attr<"LoopHint", "loop_hint"> {
+  let summary = "Optimizer hints and guarantees attached to a loop";
+  let description = [{
+    The `#cir.loop_hint` attribute carries per-loop information for the
+    optimizer: the forward-progress guarantee and the hints from
+    `#pragma clang loop`, `#pragma unroll`, `[[clang::code_align]]` and their
+    OpenCL and HLSL spellings. It is attached to the loop operations
+    (`cir.for`, `cir.while`, `cir.do`).
+
+    - `must_progress`: the loop must eventually terminate or have an
+      observable side effect (the forward-progress guarantee of C++11 and
+      later, and C11 loops with a non-constant condition).
+    - `vectorize_enable`: force vectorization on.
+    - `vectorize_width`: the vectorization factor. A width of 1 disables
+      vectorization.
+    - `vectorize_scalable`: whether the vectorization factor is
+      scalable, or explicitly fixed.
+    - `vectorize_predicate`: enable or disable predicated vectorization.
+    - `interleave_count`: the interleave count. A count of 1 disables
+      interleaving.
+    - `unroll`: The unrolling mode: enable, disable, or full.
+    - `unroll_count`: the unroll factor.
+    - `unroll_and_jam`: the unroll-and-jam mode: enable, disable, or full.
+    - `distribute`: enable or disable loop distribution.
+    - `pipeline_disabled`: disable software pipelining.
+    - `pipeline_initiation_interval`: the pipelining initiation interval.
+    - `licm_disabled`: disable loop-invariant code motion.
+    - `parallel`: the loop's iterations are independent, so its memory
+      accesses are parallel accesses.
+    - `code_align`: the alignment of the loop, in bytes.
+
+    Example:
+    ```
+    #cir.loop_hint<>
+    #cir.loop_hint< must_progress>
+    #cir.loop_hint< must_progress vectorize_enable interleave_count = 2
+                    unroll_count = 4>
+    ```
+  }];
+
+  let parameters = (ins
+    CIR_FlagParam<"must_progress">:$must_progress,
+    CIR_FlagParam<"vectorize_enable">:$vectorize_enable,
+    OptionalParameter<"uint32_t">:$vectorize_width,
+    OptionalParameter<"mlir::BoolAttr">:$vectorize_scalable,
+    OptionalParameter<"mlir::BoolAttr">:$vectorize_predicate,
+    OptionalParameter<"uint32_t">:$interleave_count,
+    OptionalParameter<"std::optional<cir::LoopUnrollMode>">:$unroll,
+    OptionalParameter<"uint32_t">:$unroll_count,
+    OptionalParameter<"std::optional<cir::LoopUnrollMode>">:$unroll_and_jam,
+    OptionalParameter<"uint32_t">:$unroll_and_jam_count,
+    OptionalParameter<"mlir::BoolAttr">:$distribute,
+    CIR_FlagParam<"pipeline_disabled">:$pipeline_disabled,
+    OptionalParameter<"uint32_t">:$pipeline_initiation_interval,
+    CIR_FlagParam<"licm_disabled">:$licm_disabled,
+    CIR_FlagParam<"parallel">:$parallel,
+    OptionalParameter<"uint32_t">:$code_align);
+
+  let assemblyFormat = [{
+    `<`
+      (` ` $must_progress^)?
+      (` ` $vectorize_enable^)?
+      (` ` `vectorize_width` `=` $vectorize_width^)?
+      (` ` `vectorize_scalable` `=` $vectorize_scalable^)?
+      (` ` `vectorize_predicate` `=` $vectorize_predicate^)?
+      (` ` `interleave_count` `=` $interleave_count^)?
+      (` ` `unroll` `=` $unroll^)?
+      (` ` `unroll_count` `=` $unroll_count^)?
+      (` ` `unroll_and_jam` `=` $unroll_and_jam^)?
+      (` ` `unroll_and_jam_count` `=` $unroll_and_jam_count^)?
+      (` ` `distribute` `=` $distribute^)?
+      (` ` $pipeline_disabled^)?
+      (` ` `pipeline_initiation_interval` `=` $pipeline_initiation_interval^)?
+      (` ` $licm_disabled^)?
+      (` ` $parallel^)?
+      (` ` `code_align` `=` $code_align^)?
+    `>`
+  }];
+
+  let extraClassDeclaration = [{
+    /// Returns true if no hint is set, in which case the attribute has no
+    /// information and there is no reason to use it. Every parameter is
+    /// unset when it is null, empty or 0, so this must name all of them.
+    bool isEmpty() const {
+      return !getMustProgress() && !getVectorizeEnable() &&
+             !getVectorizeWidth() && !getVectorizeScalable() &&
+             !getVectorizePredicate() && !getInterleaveCount() &&
+             !getUnroll() && !getUnrollCount() && !getUnrollAndJam() &&
+             !getUnrollAndJamCount() && !getDistribute() &&
+             !getPipelineDisabled() && !getPipelineInitiationInterval() &&
+             !getLicmDisabled() && !getParallel() && !getCodeAlign();
+    }
+  }];
+
+  let canHaveIllegalCXXABIType = 0;
+}
+
 
//===----------------------------------------------------------------------===//
 // FastMathFlagsAttr
 
//===----------------------------------------------------------------------===//
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td 
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 63d50761806a6..533039f44c3f2 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -2369,11 +2369,13 @@ class CIR_WhileOpBase<string mnemonic> : 
CIR_LoopOpBase<mnemonic> {
 }
 
 def CIR_WhileOp : CIR_WhileOpBase<"while"> {
-  let arguments = (ins OptionalAttr<CIR_CleanupKindAttr>:$cleanupKind);
+  let arguments = (ins OptionalAttr<CIR_CleanupKindAttr>:$cleanupKind,
+                       OptionalAttr<CIR_LoopHintAttr>:$loop_hints);
   let regions = (region MinSizedRegion<1>:$cond, MinSizedRegion<1>:$body,
                         MaxSizedRegion<1>:$cleanup);
   let assemblyFormat = [{
-    $cond `do` $body (`cleanup` enum($cleanupKind) $cleanup^)? attr-dict
+    $cond `do` $body (`cleanup` enum($cleanupKind) $cleanup^)?
+    (`loop_hints` $loop_hints^)? attr-dict
   }];
 
   let description = [{
@@ -2449,8 +2451,11 @@ def CIR_WhileOp : CIR_WhileOpBase<"while"> {
 }
 
 def CIR_DoWhileOp : CIR_WhileOpBase<"do"> {
+  let arguments = (ins OptionalAttr<CIR_LoopHintAttr>:$loop_hints);
   let regions = (region MinSizedRegion<1>:$body, MinSizedRegion<1>:$cond);
-  let assemblyFormat = " $body `while` $cond attr-dict";
+  let assemblyFormat = [{
+    $body `while` $cond (`loop_hints` $loop_hints^)? attr-dict
+  }];
 
   let extraClassDeclaration = [{
     mlir::Region &getEntry() { return getBody(); }
@@ -2524,7 +2529,8 @@ def CIR_ForOp : CIR_LoopOpBase<"for"> {
     ```
   }];
 
-  let arguments = (ins OptionalAttr<CIR_CleanupKindAttr>:$cleanupKind);
+  let arguments = (ins OptionalAttr<CIR_CleanupKindAttr>:$cleanupKind,
+                       OptionalAttr<CIR_LoopHintAttr>:$loop_hints);
   let regions = (region MinSizedRegion<1>:$cond,
                         MinSizedRegion<1>:$body,
                         MinSizedRegion<1>:$step,
@@ -2534,6 +2540,7 @@ def CIR_ForOp : CIR_LoopOpBase<"for"> {
     `body` $body
     `step` $step
     (`cleanup` enum($cleanupKind) $cleanup^)?
+    (`loop_hints` $loop_hints^)?
     attr-dict
   }];
 
diff --git a/clang/include/clang/CodeGenUtils/LoopAttributes.h 
b/clang/include/clang/CodeGenUtils/LoopAttributes.h
new file mode 100644
index 0000000000000..49c1bbfcacfba
--- /dev/null
+++ b/clang/include/clang/CodeGenUtils/LoopAttributes.h
@@ -0,0 +1,98 @@
+//===--- LoopAttributes.h - Shared loop hint state ---------------*- C++
+//-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file holds the state of the attributes and hints that may be specified
+// on a loop, and the logic to determine it from the loop's statement
+// attributes and the command line options. Both classic CodeGen and CIR
+// CodeGen use it, and each translates the state into its own representation.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_CODEGENUTILS_LOOPATTRIBUTES_H
+#define LLVM_CLANG_CODEGENUTILS_LOOPATTRIBUTES_H
+
+#include "llvm/ADT/ArrayRef.h"
+
+namespace clang {
+class ASTContext;
+class Attr;
+class CodeGenOptions;
+} // namespace clang
+
+namespace clang::CodeGenUtils {
+
+/// Attributes that may be specified on loops.
+struct LoopAttributes {
+  explicit LoopAttributes(bool IsParallel = false);
+  void clear();
+
+  /// Generate llvm.loop.parallel metadata for loads and stores.
+  bool IsParallel;
+
+  /// State of loop vectorization or unrolling.
+  enum LVEnableState { Unspecified, Enable, Disable, Full };
+
+  /// Value for llvm.loop.vectorize.enable metadata.
+  LVEnableState VectorizeEnable;
+
+  /// Value for llvm.loop.unroll.* metadata (enable, disable, or full).
+  LVEnableState UnrollEnable;
+
+  /// Value for llvm.loop.unroll_and_jam.* metadata (enable, disable, or full).
+  LVEnableState UnrollAndJamEnable;
+
+  /// Value for llvm.loop.vectorize.predicate metadata
+  LVEnableState VectorizePredicateEnable;
+
+  /// Value for llvm.loop.vectorize.width metadata.
+  unsigned VectorizeWidth;
+
+  // Value for llvm.loop.vectorize.scalable.enable
+  LVEnableState VectorizeScalable;
+
+  /// Value for llvm.loop.interleave.count metadata.
+  unsigned InterleaveCount;
+
+  /// llvm.unroll.
+  unsigned UnrollCount;
+
+  /// llvm.unroll.
+  unsigned UnrollAndJamCount;
+
+  /// Value for llvm.loop.distribute.enable metadata.
+  LVEnableState DistributeEnable;
+
+  /// Value for llvm.loop.pipeline.disable metadata.
+  bool PipelineDisabled;
+
+  /// Value for llvm.licm.disable metadata.
+  bool LICMDisabled;
+
+  /// Value for llvm.loop.pipeline.iicount metadata.
+  unsigned PipelineInitiationInterval;
+
+  /// Value for 'llvm.loop.align' metadata.
+  unsigned CodeAlign;
+
+  /// Value for whether the loop is required to make progress.
+  bool MustProgress;
+};
+
+/// Update \p Attrs with the loop hints in \p StmtAttrs (`#pragma clang loop`,
+/// `#pragma unroll`, `[[clang::code_align]]`, the OpenCL and HLSL spellings),
+/// the command line options that adjust every loop (-falign-loops and
+/// -fno-unroll-loops), and whether the loop must make progress.
+void updateLoopAttributes(LoopAttributes &Attrs, ASTContext &Ctx,
+                          const CodeGenOptions &CGOpts,
+                          llvm::ArrayRef<const Attr *> StmtAttrs,
+                          bool MustProgress);
+
+} // namespace clang::CodeGenUtils
+
+#endif // LLVM_CLANG_CODEGENUTILS_LOOPATTRIBUTES_H
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h 
b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index 90da139c0f19c..ee7a1e38f0017 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -2240,7 +2240,8 @@ class CIRGenFunction : public CIRGenTypeCache {
   void emitDeleteCall(const FunctionDecl *deleteFD, mlir::Value ptr,
                       QualType deleteTy);
 
-  mlir::LogicalResult emitDoStmt(const clang::DoStmt &s);
+  mlir::LogicalResult emitDoStmt(const clang::DoStmt &s,
+                                 llvm::ArrayRef<const Attr *> attrs = {});
 
   mlir::Value emitCXXTypeidExpr(const CXXTypeidExpr *e);
   mlir::Value emitDynamicCast(Address thisAddr, const CXXDynamicCastExpr *dce);
@@ -2302,7 +2303,8 @@ class CIRGenFunction : public CIRGenTypeCache {
   mlir::LogicalResult emitSimpleStmt(const clang::Stmt *s,
                                      bool useCurrentScope);
 
-  mlir::LogicalResult emitForStmt(const clang::ForStmt &s);
+  mlir::LogicalResult emitForStmt(const clang::ForStmt &s,
+                                  llvm::ArrayRef<const Attr *> attrs = {});
 
   void emitForwardingCallToLambda(const CXXMethodDecl *lambdaCallOperator,
                                   CallArgList &callArgs);
@@ -2585,7 +2587,13 @@ class CIRGenFunction : public CIRGenTypeCache {
 
   void emitVariablyModifiedType(QualType ty);
 
-  mlir::LogicalResult emitWhileStmt(const clang::WhileStmt &s);
+  mlir::LogicalResult emitWhileStmt(const clang::WhileStmt &s,
+                                    llvm::ArrayRef<const Attr *> attrs = {});
+
+  /// Build the hints that get attached to a loop, or a null attribute
+  /// if there is nothing to say about it.
+  cir::LoopHintAttr getLoopHints(llvm::ArrayRef<const Attr *> attrs,
+                                 bool mustProgress);
 
   std::optional<mlir::Value> emitRISCVBuiltinExpr(unsigned builtinID,
                                                   const CallExpr *expr);
diff --git a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp 
b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
index 9e14ac420aa9f..5f308751f6f54 100644
--- a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
@@ -22,6 +22,7 @@
 #include "clang/AST/StmtOpenMP.h"
 #include "clang/AST/StmtSYCL.h"
 #include "clang/CIR/MissingFeatures.h"
+#include "clang/CodeGenUtils/LoopAttributes.h"
 #include "clang/CodeGenUtils/StmtUtils.h"
 #include "llvm/Support/SaveAndRestore.h"
 
@@ -256,11 +257,11 @@ mlir::LogicalResult CIRGenFunction::emitStmt(const Stmt 
*s,
   case Stmt::SwitchStmtClass:
     return emitSwitchStmt(cast<SwitchStmt>(*s));
   case Stmt::ForStmtClass:
-    return emitForStmt(cast<ForStmt>(*s));
+    return emitForStmt(cast<ForStmt>(*s), attr);
   case Stmt::WhileStmtClass:
-    return emitWhileStmt(cast<WhileStmt>(*s));
+    return emitWhileStmt(cast<WhileStmt>(*s), attr);
   case Stmt::DoStmtClass:
-    return emitDoStmt(cast<DoStmt>(*s));
+    return emitDoStmt(cast<DoStmt>(*s), attr);
   case Stmt::CXXTryStmtClass:
     return emitCXXTryStmt(cast<CXXTryStmt>(*s));
   case Stmt::CXXForRangeStmtClass:
@@ -991,12 +992,83 @@ mlir::LogicalResult CIRGenFunction::emitSwitchCase(const 
SwitchCase &s,
   llvm_unreachable("expect case or default stmt");
 }
 
+cir::LoopHintAttr CIRGenFunction::getLoopHints(ArrayRef<const Attr *> attrs,
+                                               bool mustProgress) {
+  // Determine the state of the hints, the same way classic codegen does.
+  CodeGenUtils::LoopAttributes loopAttrs;
+  CodeGenUtils::updateLoopAttributes(loopAttrs, getContext(),
+                                     cgm.getCodeGenOpts(), attrs, 
mustProgress);
+
+  // Memory accesses in a `parallel` loop are tagged as parallel accesses when
+  // CIR is lowered.
+  assert(!cir::MissingFeatures::loopInfoStack());
+  mlir::MLIRContext *ctx = &getMLIRContext();
+
+  auto convertFlag = [&](bool set) {
+    return set ? mlir::UnitAttr::get(ctx) : mlir::UnitAttr();
+  };
+  auto convertStateToBool =
+      [&](CodeGenUtils::LoopAttributes::LVEnableState state) {
+        switch (state) {
+        case CodeGenUtils::LoopAttributes::LVEnableState::Unspecified:
+          return mlir::BoolAttr();
+        case CodeGenUtils::LoopAttributes::LVEnableState::Enable:
+          return mlir::BoolAttr::get(ctx, true);
+        case CodeGenUtils::LoopAttributes::LVEnableState::Disable:
+          return mlir::BoolAttr::get(ctx, false);
+        case CodeGenUtils::LoopAttributes::LVEnableState::Full:
+          llvm_unreachable("'full' only applies to unrolling");
+        }
+        llvm_unreachable("unknown bool state");
+      };
+
+  auto convertUnrollMode = [](CodeGenUtils::LoopAttributes::LVEnableState 
state)
+      -> std::optional<cir::LoopUnrollMode> {
+    switch (state) {
+    case CodeGenUtils::LoopAttributes::LVEnableState::Unspecified:
+      return std::nullopt;
+    case CodeGenUtils::LoopAttributes::LVEnableState::Enable:
+      return cir::LoopUnrollMode::Enable;
+    case CodeGenUtils::LoopAttributes::LVEnableState::Disable:
+      return cir::LoopUnrollMode::Disable;
+    case CodeGenUtils::LoopAttributes::LVEnableState::Full:
+      return cir::LoopUnrollMode::Full;
+    }
+
+    llvm_unreachable("unknown unroll state");
+  };
+
+  // Only OMP seems to generate this, so leave as an NYI for now.
+  if (loopAttrs.VectorizeEnable ==
+          CodeGenUtils::LoopAttributes::LVEnableState::Disable ||
+      loopAttrs.VectorizeEnable ==
+          CodeGenUtils::LoopAttributes::LVEnableState::Full)
+    cgm.errorNYI(SourceLocation{}, "unsupported vector-enable loop state");
+
+  bool vectorizeEnable = loopAttrs.VectorizeEnable ==
+                         CodeGenUtils::LoopAttributes::LVEnableState::Enable;
+  auto hints = cir::LoopHintAttr::get(
+      ctx, convertFlag(loopAttrs.MustProgress), convertFlag(vectorizeEnable),
+      loopAttrs.VectorizeWidth, 
convertStateToBool(loopAttrs.VectorizeScalable),
+      convertStateToBool(loopAttrs.VectorizePredicateEnable),
+      loopAttrs.InterleaveCount, convertUnrollMode(loopAttrs.UnrollEnable),
+      loopAttrs.UnrollCount, convertUnrollMode(loopAttrs.UnrollAndJamEnable),
+      loopAttrs.UnrollAndJamCount,
+      convertStateToBool(loopAttrs.DistributeEnable),
+      convertFlag(loopAttrs.PipelineDisabled),
+      loopAttrs.PipelineInitiationInterval, 
convertFlag(loopAttrs.LICMDisabled),
+      convertFlag(loopAttrs.IsParallel), loopAttrs.CodeAlign);
+
+  if (hints.isEmpty())
+    return {};
+  return hints;
+}
+
 mlir::LogicalResult
 CIRGenFunction::emitCXXForRangeStmt(const CXXForRangeStmt &s,
                                     ArrayRef<const Attr *> forAttrs) {
   cir::ForOp forOp;
 
-  // TODO(cir): pass in array of attributes.
   auto forStmtBuilder = [&]() -> mlir::LogicalResult {
     mlir::LogicalResult loopRes = mlir::success();
     // Evaluate the first pieces before the loop.
@@ -1010,7 +1082,10 @@ CIRGenFunction::emitCXXForRangeStmt(const 
CXXForRangeStmt &s,
     if (emitStmt(s.getEndStmt(), /*useCurrentScope=*/true).failed())
       return mlir::failure();
 
-    assert(!cir::MissingFeatures::loopInfoStack());
+    // FIXME: Classic codegen never sets 'must progress' on these loops, but
+    // probably could?
+    cir::LoopHintAttr loopHints =
+        getLoopHints(forAttrs, /*mustProgress=*/false);
 
     forOp = builder.createFor(
         getLoc(s.getSourceRange()),
@@ -1041,6 +1116,7 @@ CIRGenFunction::emitCXXForRangeStmt(const CXXForRangeStmt 
&s,
               loopRes = mlir::failure();
           builder.createYield(loc);
         });
+    forOp.setLoopHintsAttr(loopHints);
     return loopRes;
   };
 
@@ -1064,18 +1140,19 @@ CIRGenFunction::emitCXXForRangeStmt(const 
CXXForRangeStmt &s,
   return mlir::success();
 }
 
-mlir::LogicalResult CIRGenFunction::emitForStmt(const ForStmt &s) {
+mlir::LogicalResult CIRGenFunction::emitForStmt(const ForStmt &s,
+                                                ArrayRef<const Attr *> attrs) {
   cir::ForOp forOp;
 
-  // TODO: pass in an array of attributes.
   auto forStmtBuilder = [&]() -> mlir::LogicalResult {
     mlir::LogicalResult loopRes = mlir:...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/232975
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to