[clang] [CIR] Implement 'loop hint' lowering (PR #232975)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Oct 16 16:01:12 PDT 2026
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
More information about the cfe-commits
mailing list