[clang] [clang] Support `#pragma clang loop pipeline(enable)` (PR #112501)
Ryotaro Kasuga via cfe-commits
cfe-commits at lists.llvm.org
Wed Oct 16 01:51:38 PDT 2024
https://github.com/kasuga-fj created https://github.com/llvm/llvm-project/pull/112501
Previously `#pragma clang loop pipeline` only accepted `disable`. This patch adds `enable` as a valid argument for this pragma. This allows Software Pipelining optimization to be applied to some loops instead of all loops.
This is clang part of the fix.
>From 04f0f22178272dbf2ebe8a74569245f97a2f644b Mon Sep 17 00:00:00 2001
From: Ryotaro Kasuga <kasuga.ryotaro at fujitsu.com>
Date: Thu, 10 Oct 2024 09:08:00 +0000
Subject: [PATCH] [clang] Support `#pragma clang loop pipeline(enable)`
Previously `#pragma clang loop pipeline` only accepted `disable`. This
patch adds `enable` as a valid argument for this pragma. This allows
Software Pipelining optimization to be applied to some loops instead of
all loops.
This is clang part of the fix.
---
clang/include/clang/Basic/Attr.td | 6 ++--
clang/include/clang/Basic/AttrDocs.td | 12 ++++++-
.../clang/Basic/DiagnosticParseKinds.td | 2 --
clang/lib/CodeGen/CGLoopInfo.cpp | 36 ++++++++++++-------
clang/lib/CodeGen/CGLoopInfo.h | 11 +++---
clang/lib/Parse/ParsePragma.cpp | 34 ++++++++----------
clang/lib/Sema/SemaStmtAttr.cpp | 8 ++---
clang/test/CodeGenCXX/pragma-pipeline.cpp | 12 +++++++
clang/test/Parser/pragma-loop.cpp | 2 +-
clang/test/Parser/pragma-pipeline.cpp | 8 +++--
10 files changed, 82 insertions(+), 49 deletions(-)
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index ec3d6e0079f630..3d5d5f6ca99f1e 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -4190,7 +4190,7 @@ def LoopHint : Attr {
/// unroll_and_jam: attempt to unroll and jam loop if State == Enable.
/// unroll_and_jam_count: unroll and jams loop 'Value' times.
/// distribute: attempt to distribute loop if State == Enable.
- /// pipeline: disable pipelining loop if State == Disable.
+ /// pipeline: enable pipelining loop if State == Enable.
/// pipeline_initiation_interval: create loop schedule with initiation interval equal to 'Value'.
/// #pragma unroll <argument> directive
@@ -4210,7 +4210,7 @@ def LoopHint : Attr {
"vectorize_predicate"],
["Vectorize", "VectorizeWidth", "Interleave", "InterleaveCount",
"Unroll", "UnrollCount", "UnrollAndJam", "UnrollAndJamCount",
- "PipelineDisabled", "PipelineInitiationInterval", "Distribute",
+ "Pipeline", "PipelineInitiationInterval", "Distribute",
"VectorizePredicate"]>,
EnumArgument<"State", "LoopHintState", /*is_string=*/false,
["enable", "disable", "numeric", "fixed_width",
@@ -4230,7 +4230,7 @@ def LoopHint : Attr {
case UnrollCount: return "unroll_count";
case UnrollAndJam: return "unroll_and_jam";
case UnrollAndJamCount: return "unroll_and_jam_count";
- case PipelineDisabled: return "pipeline";
+ case Pipeline: return "pipeline";
case PipelineInitiationInterval: return "pipeline_initiation_interval";
case Distribute: return "distribute";
case VectorizePredicate: return "vectorize_predicate";
diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td
index b1512e22ee2dd4..e2591c7be7905a 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -3968,8 +3968,18 @@ def PipelineHintDocs : Documentation {
placed immediately before a for, while, do-while, or a C++11 range-based for
loop.
+ Using ``#pragma clang loop pipeline(enable)`` applies the software pipelining
+ optimization if possible:
+
+ .. code-block:: c++
+
+ #pragma clang loop pipeline(enable)
+ for (...) {
+ ...
+ }
+
Using ``#pragma clang loop pipeline(disable)`` avoids the software pipelining
- optimization. The disable state can only be specified:
+ optimization:
.. code-block:: c++
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index 78510e61a639fa..1bf82923aa26bd 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1676,8 +1676,6 @@ def err_pragma_fp_invalid_argument : Error<
def err_pragma_invalid_keyword : Error<
"invalid argument; expected 'enable'%select{|, 'full'}0%select{|, 'assume_safety'}1 or 'disable'">;
-def err_pragma_pipeline_invalid_keyword : Error<
- "invalid argument; expected 'disable'">;
// API notes.
def err_type_unparsed : Error<"unparsed tokens following type">;
diff --git a/clang/lib/CodeGen/CGLoopInfo.cpp b/clang/lib/CodeGen/CGLoopInfo.cpp
index 6b886bd6b6d2cf..04b229da2013e3 100644
--- a/clang/lib/CodeGen/CGLoopInfo.cpp
+++ b/clang/lib/CodeGen/CGLoopInfo.cpp
@@ -39,9 +39,10 @@ MDNode *LoopInfo::createPipeliningMetadata(const LoopAttributes &Attrs,
LLVMContext &Ctx = Header->getContext();
std::optional<bool> Enabled;
- if (Attrs.PipelineDisabled)
+ if (Attrs.Pipeline == LoopAttributes::Disable)
Enabled = false;
- else if (Attrs.PipelineInitiationInterval != 0)
+ else if (Attrs.Pipeline == LoopAttributes::Enable ||
+ Attrs.PipelineInitiationInterval != 0)
Enabled = true;
if (Enabled != true) {
@@ -69,6 +70,11 @@ MDNode *LoopInfo::createPipeliningMetadata(const LoopAttributes &Attrs,
Args.push_back(MDNode::get(Ctx, Vals));
}
+ if (Attrs.Pipeline == LoopAttributes::Enable) {
+ Metadata *Vals[] = {MDString::get(Ctx, "llvm.loop.pipeline.enable")};
+ Args.push_back(MDNode::get(Ctx, Vals));
+ }
+
// No follow-up: This is the last transformation.
MDNode *LoopID = MDNode::getDistinct(Ctx, Args);
@@ -460,8 +466,9 @@ LoopAttributes::LoopAttributes(bool IsParallel)
VectorizePredicateEnable(LoopAttributes::Unspecified), VectorizeWidth(0),
VectorizeScalable(LoopAttributes::Unspecified), InterleaveCount(0),
UnrollCount(0), UnrollAndJamCount(0),
- DistributeEnable(LoopAttributes::Unspecified), PipelineDisabled(false),
- PipelineInitiationInterval(0), CodeAlign(0), MustProgress(false) {}
+ DistributeEnable(LoopAttributes::Unspecified),
+ Pipeline(LoopAttributes::Unspecified), PipelineInitiationInterval(0),
+ CodeAlign(0), MustProgress(false) {}
void LoopAttributes::clear() {
IsParallel = false;
@@ -475,7 +482,7 @@ void LoopAttributes::clear() {
UnrollAndJamEnable = LoopAttributes::Unspecified;
VectorizePredicateEnable = LoopAttributes::Unspecified;
DistributeEnable = LoopAttributes::Unspecified;
- PipelineDisabled = false;
+ Pipeline = LoopAttributes::Unspecified;
PipelineInitiationInterval = 0;
CodeAlign = 0;
MustProgress = false;
@@ -496,7 +503,8 @@ LoopInfo::LoopInfo(BasicBlock *Header, const LoopAttributes &Attrs,
if (!Attrs.IsParallel && Attrs.VectorizeWidth == 0 &&
Attrs.VectorizeScalable == LoopAttributes::Unspecified &&
Attrs.InterleaveCount == 0 && Attrs.UnrollCount == 0 &&
- Attrs.UnrollAndJamCount == 0 && !Attrs.PipelineDisabled &&
+ Attrs.UnrollAndJamCount == 0 &&
+ Attrs.Pipeline == LoopAttributes::Unspecified &&
Attrs.PipelineInitiationInterval == 0 &&
Attrs.VectorizePredicateEnable == LoopAttributes::Unspecified &&
Attrs.VectorizeEnable == LoopAttributes::Unspecified &&
@@ -552,7 +560,7 @@ void LoopInfo::finish() {
AfterJam.VectorizePredicateEnable = Attrs.VectorizePredicateEnable;
AfterJam.UnrollCount = Attrs.UnrollCount;
- AfterJam.PipelineDisabled = Attrs.PipelineDisabled;
+ AfterJam.Pipeline = Attrs.Pipeline;
AfterJam.PipelineInitiationInterval = Attrs.PipelineInitiationInterval;
// If this loop is subject of an unroll-and-jam by the parent loop, and has
@@ -680,8 +688,8 @@ void LoopInfoStack::push(BasicBlock *Header, clang::ASTContext &Ctx,
case LoopHintAttr::Distribute:
setDistributeState(false);
break;
- case LoopHintAttr::PipelineDisabled:
- setPipelineDisabled(true);
+ case LoopHintAttr::Pipeline:
+ setPipelineEnable(false);
break;
case LoopHintAttr::UnrollCount:
case LoopHintAttr::UnrollAndJamCount:
@@ -710,11 +718,13 @@ void LoopInfoStack::push(BasicBlock *Header, clang::ASTContext &Ctx,
case LoopHintAttr::Distribute:
setDistributeState(true);
break;
+ case LoopHintAttr::Pipeline:
+ setPipelineEnable(true);
+ break;
case LoopHintAttr::UnrollCount:
case LoopHintAttr::UnrollAndJamCount:
case LoopHintAttr::VectorizeWidth:
case LoopHintAttr::InterleaveCount:
- case LoopHintAttr::PipelineDisabled:
case LoopHintAttr::PipelineInitiationInterval:
llvm_unreachable("Options cannot enabled.");
break;
@@ -736,7 +746,7 @@ void LoopInfoStack::push(BasicBlock *Header, clang::ASTContext &Ctx,
case LoopHintAttr::VectorizeWidth:
case LoopHintAttr::InterleaveCount:
case LoopHintAttr::Distribute:
- case LoopHintAttr::PipelineDisabled:
+ case LoopHintAttr::Pipeline:
case LoopHintAttr::PipelineInitiationInterval:
llvm_unreachable("Options cannot be used to assume mem safety.");
break;
@@ -757,7 +767,7 @@ void LoopInfoStack::push(BasicBlock *Header, clang::ASTContext &Ctx,
case LoopHintAttr::VectorizeWidth:
case LoopHintAttr::InterleaveCount:
case LoopHintAttr::Distribute:
- case LoopHintAttr::PipelineDisabled:
+ case LoopHintAttr::Pipeline:
case LoopHintAttr::PipelineInitiationInterval:
case LoopHintAttr::VectorizePredicate:
llvm_unreachable("Options cannot be used with 'full' hint.");
@@ -800,7 +810,7 @@ void LoopInfoStack::push(BasicBlock *Header, clang::ASTContext &Ctx,
case LoopHintAttr::VectorizeWidth:
case LoopHintAttr::Interleave:
case LoopHintAttr::Distribute:
- case LoopHintAttr::PipelineDisabled:
+ case LoopHintAttr::Pipeline:
llvm_unreachable("Options cannot be assigned a value.");
break;
}
diff --git a/clang/lib/CodeGen/CGLoopInfo.h b/clang/lib/CodeGen/CGLoopInfo.h
index 0fe33b28913063..58d4ea6c45d2cb 100644
--- a/clang/lib/CodeGen/CGLoopInfo.h
+++ b/clang/lib/CodeGen/CGLoopInfo.h
@@ -73,8 +73,8 @@ struct LoopAttributes {
/// Value for llvm.loop.distribute.enable metadata.
LVEnableState DistributeEnable;
- /// Value for llvm.loop.pipeline.disable metadata.
- bool PipelineDisabled;
+ /// Value for llvm.loop.pipeline metadata.
+ LVEnableState Pipeline;
/// Value for llvm.loop.pipeline.iicount metadata.
unsigned PipelineInitiationInterval;
@@ -281,8 +281,11 @@ class LoopInfoStack {
/// \brief Set the unroll count for the next loop pushed.
void setUnrollAndJamCount(unsigned C) { StagedAttrs.UnrollAndJamCount = C; }
- /// Set the pipeline disabled state.
- void setPipelineDisabled(bool S) { StagedAttrs.PipelineDisabled = S; }
+ /// Set the next pushed loop as a pipeline candidate.
+ void setPipelineEnable(bool Enable = true) {
+ StagedAttrs.Pipeline =
+ Enable ? LoopAttributes::Enable : LoopAttributes::Disable;
+ }
/// Set the pipeline initiation interval.
void setPipelineInitiationInterval(unsigned C) {
diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp
index 12fed448d477c0..7e9b80cd0b0a04 100644
--- a/clang/lib/Parse/ParsePragma.cpp
+++ b/clang/lib/Parse/ParsePragma.cpp
@@ -1454,24 +1454,24 @@ bool Parser::HandlePragmaLoopHint(LoopHint &Hint) {
bool OptionUnroll = false;
bool OptionUnrollAndJam = false;
bool OptionDistribute = false;
- bool OptionPipelineDisabled = false;
+ bool OptionPipeline = false;
bool StateOption = false;
if (OptionInfo) { // Pragma Unroll does not specify an option.
OptionUnroll = OptionInfo->isStr("unroll");
OptionUnrollAndJam = OptionInfo->isStr("unroll_and_jam");
OptionDistribute = OptionInfo->isStr("distribute");
- OptionPipelineDisabled = OptionInfo->isStr("pipeline");
+ OptionPipeline = OptionInfo->isStr("pipeline");
StateOption = llvm::StringSwitch<bool>(OptionInfo->getName())
.Case("vectorize", true)
.Case("interleave", true)
.Case("vectorize_predicate", true)
.Default(false) ||
OptionUnroll || OptionUnrollAndJam || OptionDistribute ||
- OptionPipelineDisabled;
+ OptionPipeline;
}
bool AssumeSafetyArg = !OptionUnroll && !OptionUnrollAndJam &&
- !OptionDistribute && !OptionPipelineDisabled;
+ !OptionDistribute && !OptionPipeline;
// Verify loop hint has an argument.
if (Toks[0].is(tok::eof)) {
ConsumeAnnotationToken();
@@ -1488,21 +1488,17 @@ bool Parser::HandlePragmaLoopHint(LoopHint &Hint) {
SourceLocation StateLoc = Toks[0].getLocation();
IdentifierInfo *StateInfo = Toks[0].getIdentifierInfo();
- bool Valid = StateInfo &&
- llvm::StringSwitch<bool>(StateInfo->getName())
- .Case("disable", true)
- .Case("enable", !OptionPipelineDisabled)
- .Case("full", OptionUnroll || OptionUnrollAndJam)
- .Case("assume_safety", AssumeSafetyArg)
- .Default(false);
+ bool Valid =
+ StateInfo && llvm::StringSwitch<bool>(StateInfo->getName())
+ .Case("disable", true)
+ .Case("enable", true)
+ .Case("full", OptionUnroll || OptionUnrollAndJam)
+ .Case("assume_safety", AssumeSafetyArg)
+ .Default(false);
if (!Valid) {
- if (OptionPipelineDisabled) {
- Diag(Toks[0].getLocation(), diag::err_pragma_pipeline_invalid_keyword);
- } else {
- Diag(Toks[0].getLocation(), diag::err_pragma_invalid_keyword)
- << /*FullKeyword=*/(OptionUnroll || OptionUnrollAndJam)
- << /*AssumeSafetyKeyword=*/AssumeSafetyArg;
- }
+ Diag(Toks[0].getLocation(), diag::err_pragma_invalid_keyword)
+ << /*FullKeyword=*/(OptionUnroll || OptionUnrollAndJam)
+ << /*AssumeSafetyKeyword=*/AssumeSafetyArg;
return false;
}
if (Toks.size() > 2)
@@ -3591,7 +3587,7 @@ static bool ParseLoopHintValue(Preprocessor &PP, Token &Tok, Token PragmaName,
/// 'vectorize_width' '(' loop-hint-value ')'
/// 'interleave_count' '(' loop-hint-value ')'
/// 'unroll_count' '(' loop-hint-value ')'
-/// 'pipeline' '(' disable ')'
+/// 'pipeline' '(' loop-hint-keyword ')'
/// 'pipeline_initiation_interval' '(' loop-hint-value ')'
///
/// loop-hint-keyword:
diff --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp
index f801455596fe6f..9d2989cd12e021 100644
--- a/clang/lib/Sema/SemaStmtAttr.cpp
+++ b/clang/lib/Sema/SemaStmtAttr.cpp
@@ -142,7 +142,7 @@ static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const ParsedAttr &A,
.Case("interleave_count", LoopHintAttr::InterleaveCount)
.Case("unroll", LoopHintAttr::Unroll)
.Case("unroll_count", LoopHintAttr::UnrollCount)
- .Case("pipeline", LoopHintAttr::PipelineDisabled)
+ .Case("pipeline", LoopHintAttr::Pipeline)
.Case("pipeline_initiation_interval",
LoopHintAttr::PipelineInitiationInterval)
.Case("distribute", LoopHintAttr::Distribute)
@@ -170,7 +170,7 @@ static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const ParsedAttr &A,
Option == LoopHintAttr::VectorizePredicate ||
Option == LoopHintAttr::Unroll ||
Option == LoopHintAttr::Distribute ||
- Option == LoopHintAttr::PipelineDisabled) {
+ Option == LoopHintAttr::Pipeline) {
assert(StateLoc && StateLoc->Ident && "Loop hint must have an argument");
if (StateLoc->Ident->isStr("disable"))
State = LoopHintAttr::Disable;
@@ -516,7 +516,7 @@ CheckForIncompatibleAttributes(Sema &S,
// Perform the check for duplicated 'distribute' hints.
Category = Distribute;
break;
- case LoopHintAttr::PipelineDisabled:
+ case LoopHintAttr::Pipeline:
case LoopHintAttr::PipelineInitiationInterval:
Category = Pipeline;
break;
@@ -532,7 +532,7 @@ CheckForIncompatibleAttributes(Sema &S,
Option == LoopHintAttr::Interleave || Option == LoopHintAttr::Unroll ||
Option == LoopHintAttr::UnrollAndJam ||
Option == LoopHintAttr::VectorizePredicate ||
- Option == LoopHintAttr::PipelineDisabled ||
+ Option == LoopHintAttr::Pipeline ||
Option == LoopHintAttr::Distribute) {
// Enable|Disable|AssumeSafety hint. For example, vectorize(enable).
PrevAttr = CategoryState.StateAttr;
diff --git a/clang/test/CodeGenCXX/pragma-pipeline.cpp b/clang/test/CodeGenCXX/pragma-pipeline.cpp
index b7d2136745c7d9..f8948adf1a9d8a 100644
--- a/clang/test/CodeGenCXX/pragma-pipeline.cpp
+++ b/clang/test/CodeGenCXX/pragma-pipeline.cpp
@@ -36,6 +36,15 @@ void pipeline_disabled_on_nested_loop(int *List, int Length, int Value) {
}
}
+void pipeline_enabled(int *List, int Length, int Value) {
+// CHECK-LABEL: define {{.*}} @_Z16pipeline_enabled
+#pragma clang loop pipeline(enable)
+ for (int i = 0; i < Length; i++) {
+ // CHECK: br label {{.*}}, !llvm.loop ![[LOOP_5:.*]]
+ List[i] = Value;
+ }
+}
+
// CHECK: ![[LOOP_1]] = distinct !{![[LOOP_1]], [[MP:![0-9]+]], ![[PIPELINE_DISABLE:.*]]}
// CHECK: ![[PIPELINE_DISABLE]] = !{!"llvm.loop.pipeline.disable", i1 true}
@@ -45,3 +54,6 @@ void pipeline_disabled_on_nested_loop(int *List, int Length, int Value) {
// CHECK: ![[PIPELINE_II_10]] = !{!"llvm.loop.pipeline.initiationinterval", i32 10}
// CHECK: ![[LOOP_4]] = distinct !{![[LOOP_4]], [[MP]], ![[PIPELINE_DISABLE]]}
+
+// CHECK: ![[LOOP_5]] = distinct !{![[LOOP_5]], [[MP]], ![[PIPELINE_ENABLE:.*]]}
+// CHECK: ![[PIPELINE_ENABLE]] = !{!"llvm.loop.pipeline.enable"}
diff --git a/clang/test/Parser/pragma-loop.cpp b/clang/test/Parser/pragma-loop.cpp
index 4078210f96e1b9..bb068b1d6c22b9 100644
--- a/clang/test/Parser/pragma-loop.cpp
+++ b/clang/test/Parser/pragma-loop.cpp
@@ -325,7 +325,7 @@ void foo(int *List, int Length) {
List[i] = i;
}
-#pragma clang loop pipeline(disable, extra)
+#pragma clang loop pipeline(enable, extra)
/* expected-warning {{extra tokens at end of '#pragma clang loop pipeline' - ignored}}*/ while (i-6 < Length) {
List[i] = i;
}
diff --git a/clang/test/Parser/pragma-pipeline.cpp b/clang/test/Parser/pragma-pipeline.cpp
index e500d4d2d5fb25..7d7a8ebab12f07 100644
--- a/clang/test/Parser/pragma-pipeline.cpp
+++ b/clang/test/Parser/pragma-pipeline.cpp
@@ -6,6 +6,11 @@
void test(int *List, int Length, int Value) {
int i = 0;
+#pragma clang loop pipeline(enable)
+ for (int i = 0; i < Length; i++) {
+ List[i] = Value;
+ }
+
#pragma clang loop pipeline(disable)
for (int i = 0; i < Length; i++) {
List[i] = Value;
@@ -17,8 +22,7 @@ void test(int *List, int Length, int Value) {
}
/* expected-error {{expected ')'}} */ #pragma clang loop pipeline(disable
-/* expected-error {{invalid argument; expected 'disable'}} */ #pragma clang loop pipeline(enable)
-/* expected-error {{invalid argument; expected 'disable'}} */ #pragma clang loop pipeline(error)
+/* expected-error {{invalid argument; expected 'enable' or 'disable'}} */ #pragma clang loop pipeline(error)
/* expected-error {{expected '('}} */ #pragma clang loop pipeline disable
/* expected-error {{missing argument; expected an integer value}} */ #pragma clang loop pipeline_initiation_interval()
/* expected-error {{use of undeclared identifier 'error'}} */ #pragma clang loop pipeline_initiation_interval(error)
More information about the cfe-commits
mailing list