Skip to content

Commit c820f94

Browse files
authored
Merge pull request #45 from sx-aurora-dev/feature/merge-upstream-20210401
Feature/merge upstream 20210401
2 parents 20e75bf + 63cef7f commit c820f94

File tree

6,156 files changed

+452181
-132688
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

6,156 files changed

+452181
-132688
lines changed

clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ void ExpandModularHeadersPPCallbacks::HasInclude(SourceLocation Loc, StringRef,
230230
void ExpandModularHeadersPPCallbacks::PragmaOpenCLExtension(
231231
SourceLocation NameLoc, const IdentifierInfo *, SourceLocation StateLoc,
232232
unsigned) {
233-
// FIME: Figure out whether it's the right location to parse to.
233+
// FIXME: Figure out whether it's the right location to parse to.
234234
parseToLocation(NameLoc);
235235
}
236236
void ExpandModularHeadersPPCallbacks::PragmaWarning(SourceLocation Loc,
@@ -256,7 +256,7 @@ void ExpandModularHeadersPPCallbacks::MacroExpands(const Token &MacroNameTok,
256256
const MacroDefinition &,
257257
SourceRange Range,
258258
const MacroArgs *) {
259-
// FIME: Figure out whether it's the right location to parse to.
259+
// FIXME: Figure out whether it's the right location to parse to.
260260
parseToLocation(Range.getBegin());
261261
}
262262
void ExpandModularHeadersPPCallbacks::MacroDefined(const Token &MacroNameTok,
@@ -271,12 +271,12 @@ void ExpandModularHeadersPPCallbacks::MacroUndefined(
271271
void ExpandModularHeadersPPCallbacks::Defined(const Token &MacroNameTok,
272272
const MacroDefinition &,
273273
SourceRange Range) {
274-
// FIME: Figure out whether it's the right location to parse to.
274+
// FIXME: Figure out whether it's the right location to parse to.
275275
parseToLocation(Range.getBegin());
276276
}
277277
void ExpandModularHeadersPPCallbacks::SourceRangeSkipped(
278278
SourceRange Range, SourceLocation EndifLoc) {
279-
// FIME: Figure out whether it's the right location to parse to.
279+
// FIXME: Figure out whether it's the right location to parse to.
280280
parseToLocation(EndifLoc);
281281
}
282282
void ExpandModularHeadersPPCallbacks::If(SourceLocation Loc, SourceRange,

clang-tools-extra/clang-tidy/GlobList.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ using namespace tidy;
1515
// Returns true if GlobList starts with the negative indicator ('-'), removes it
1616
// from the GlobList.
1717
static bool consumeNegativeIndicator(StringRef &GlobList) {
18-
GlobList = GlobList.trim(" \r\n");
18+
GlobList = GlobList.trim();
1919
if (GlobList.startswith("-")) {
2020
GlobList = GlobList.substr(1);
2121
return true;
@@ -27,7 +27,7 @@ static bool consumeNegativeIndicator(StringRef &GlobList) {
2727
// removes it and the trailing comma from the GlobList.
2828
static llvm::Regex consumeGlob(StringRef &GlobList) {
2929
StringRef UntrimmedGlob = GlobList.substr(0, GlobList.find(','));
30-
StringRef Glob = UntrimmedGlob.trim(' ');
30+
StringRef Glob = UntrimmedGlob.trim();
3131
GlobList = GlobList.substr(UntrimmedGlob.size() + 1);
3232
SmallString<128> RegexText("^");
3333
StringRef MetaChars("()^$|*+?.[]\\{}");

clang-tools-extra/clang-tidy/altera/AlteraTidyModule.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "KernelNameRestrictionCheck.h"
1313
#include "SingleWorkItemBarrierCheck.h"
1414
#include "StructPackAlignCheck.h"
15+
#include "UnrollLoopsCheck.h"
1516

1617
using namespace clang::ast_matchers;
1718

@@ -28,6 +29,7 @@ class AlteraModule : public ClangTidyModule {
2829
"altera-single-work-item-barrier");
2930
CheckFactories.registerCheck<StructPackAlignCheck>(
3031
"altera-struct-pack-align");
32+
CheckFactories.registerCheck<UnrollLoopsCheck>("altera-unroll-loops");
3133
}
3234
};
3335

clang-tools-extra/clang-tidy/altera/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ add_clang_library(clangTidyAlteraModule
88
KernelNameRestrictionCheck.cpp
99
SingleWorkItemBarrierCheck.cpp
1010
StructPackAlignCheck.cpp
11+
UnrollLoopsCheck.cpp
1112

1213
LINK_LIBS
1314
clangTidy
Lines changed: 277 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,277 @@
1+
//===--- UnrollLoopsCheck.cpp - clang-tidy --------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "UnrollLoopsCheck.h"
10+
#include "clang/AST/APValue.h"
11+
#include "clang/AST/ASTContext.h"
12+
#include "clang/AST/ASTTypeTraits.h"
13+
#include "clang/AST/OperationKinds.h"
14+
#include "clang/AST/ParentMapContext.h"
15+
#include "clang/ASTMatchers/ASTMatchFinder.h"
16+
#include <math.h>
17+
18+
using namespace clang::ast_matchers;
19+
20+
namespace clang {
21+
namespace tidy {
22+
namespace altera {
23+
24+
UnrollLoopsCheck::UnrollLoopsCheck(StringRef Name, ClangTidyContext *Context)
25+
: ClangTidyCheck(Name, Context),
26+
MaxLoopIterations(Options.get("MaxLoopIterations", 100U)) {}
27+
28+
void UnrollLoopsCheck::registerMatchers(MatchFinder *Finder) {
29+
const auto HasLoopBound = hasDescendant(
30+
varDecl(allOf(matchesName("__end*"),
31+
hasDescendant(integerLiteral().bind("cxx_loop_bound")))));
32+
const auto CXXForRangeLoop =
33+
cxxForRangeStmt(anyOf(HasLoopBound, unless(HasLoopBound)));
34+
const auto AnyLoop = anyOf(forStmt(), whileStmt(), doStmt(), CXXForRangeLoop);
35+
Finder->addMatcher(
36+
stmt(allOf(AnyLoop, unless(hasDescendant(stmt(AnyLoop))))).bind("loop"),
37+
this);
38+
}
39+
40+
void UnrollLoopsCheck::check(const MatchFinder::MatchResult &Result) {
41+
const auto *Loop = Result.Nodes.getNodeAs<Stmt>("loop");
42+
const auto *CXXLoopBound =
43+
Result.Nodes.getNodeAs<IntegerLiteral>("cxx_loop_bound");
44+
const ASTContext *Context = Result.Context;
45+
switch (unrollType(Loop, Result.Context)) {
46+
case NotUnrolled:
47+
diag(Loop->getBeginLoc(),
48+
"kernel performance could be improved by unrolling this loop with a "
49+
"'#pragma unroll' directive");
50+
break;
51+
case PartiallyUnrolled:
52+
// Loop already partially unrolled, do nothing.
53+
break;
54+
case FullyUnrolled:
55+
if (hasKnownBounds(Loop, CXXLoopBound, Context)) {
56+
if (hasLargeNumIterations(Loop, CXXLoopBound, Context)) {
57+
diag(Loop->getBeginLoc(),
58+
"loop likely has a large number of iterations and thus "
59+
"cannot be fully unrolled; to partially unroll this loop, use "
60+
"the '#pragma unroll <num>' directive");
61+
return;
62+
}
63+
return;
64+
}
65+
if (isa<WhileStmt, DoStmt>(Loop)) {
66+
diag(Loop->getBeginLoc(),
67+
"full unrolling requested, but loop bounds may not be known; to "
68+
"partially unroll this loop, use the '#pragma unroll <num>' "
69+
"directive",
70+
DiagnosticIDs::Note);
71+
break;
72+
}
73+
diag(Loop->getBeginLoc(),
74+
"full unrolling requested, but loop bounds are not known; to "
75+
"partially unroll this loop, use the '#pragma unroll <num>' "
76+
"directive");
77+
break;
78+
}
79+
}
80+
81+
enum UnrollLoopsCheck::UnrollType
82+
UnrollLoopsCheck::unrollType(const Stmt *Statement, ASTContext *Context) {
83+
const DynTypedNodeList Parents = Context->getParents<Stmt>(*Statement);
84+
for (const DynTypedNode &Parent : Parents) {
85+
const auto *ParentStmt = Parent.get<AttributedStmt>();
86+
if (!ParentStmt)
87+
continue;
88+
for (const Attr *Attribute : ParentStmt->getAttrs()) {
89+
const auto *LoopHint = dyn_cast<LoopHintAttr>(Attribute);
90+
if (!LoopHint)
91+
continue;
92+
switch (LoopHint->getState()) {
93+
case LoopHintAttr::Numeric:
94+
return PartiallyUnrolled;
95+
case LoopHintAttr::Disable:
96+
return NotUnrolled;
97+
case LoopHintAttr::Full:
98+
return FullyUnrolled;
99+
case LoopHintAttr::Enable:
100+
return FullyUnrolled;
101+
case LoopHintAttr::AssumeSafety:
102+
return NotUnrolled;
103+
case LoopHintAttr::FixedWidth:
104+
return NotUnrolled;
105+
case LoopHintAttr::ScalableWidth:
106+
return NotUnrolled;
107+
}
108+
}
109+
}
110+
return NotUnrolled;
111+
}
112+
113+
bool UnrollLoopsCheck::hasKnownBounds(const Stmt *Statement,
114+
const IntegerLiteral *CXXLoopBound,
115+
const ASTContext *Context) {
116+
if (isa<CXXForRangeStmt>(Statement))
117+
return CXXLoopBound != nullptr;
118+
// Too many possibilities in a while statement, so always recommend partial
119+
// unrolling for these.
120+
if (isa<WhileStmt, DoStmt>(Statement))
121+
return false;
122+
// The last loop type is a for loop.
123+
const auto *ForLoop = dyn_cast<ForStmt>(Statement);
124+
if (!ForLoop)
125+
llvm_unreachable("Unknown loop");
126+
const Stmt *Initializer = ForLoop->getInit();
127+
const Expr *Conditional = ForLoop->getCond();
128+
const Expr *Increment = ForLoop->getInc();
129+
if (!Initializer || !Conditional || !Increment)
130+
return false;
131+
// If the loop variable value isn't known, loop bounds are unknown.
132+
if (const auto *InitDeclStatement = dyn_cast<DeclStmt>(Initializer)) {
133+
if (const auto *VariableDecl =
134+
dyn_cast<VarDecl>(InitDeclStatement->getSingleDecl())) {
135+
APValue *Evaluation = VariableDecl->evaluateValue();
136+
if (!Evaluation || !Evaluation->hasValue())
137+
return false;
138+
}
139+
}
140+
// If increment is unary and not one of ++ and --, loop bounds are unknown.
141+
if (const auto *Op = dyn_cast<UnaryOperator>(Increment))
142+
if (!Op->isIncrementDecrementOp())
143+
return false;
144+
145+
if (isa<BinaryOperator>(Conditional)) {
146+
const auto *BinaryOp = dyn_cast<BinaryOperator>(Conditional);
147+
const Expr *LHS = BinaryOp->getLHS();
148+
const Expr *RHS = BinaryOp->getRHS();
149+
// If both sides are value dependent or constant, loop bounds are unknown.
150+
return LHS->isEvaluatable(*Context) != RHS->isEvaluatable(*Context);
151+
}
152+
return false; // If it's not a binary operator, loop bounds are unknown.
153+
}
154+
155+
const Expr *UnrollLoopsCheck::getCondExpr(const Stmt *Statement) {
156+
if (const auto *ForLoop = dyn_cast<ForStmt>(Statement))
157+
return ForLoop->getCond();
158+
if (const auto *WhileLoop = dyn_cast<WhileStmt>(Statement))
159+
return WhileLoop->getCond();
160+
if (const auto *DoWhileLoop = dyn_cast<DoStmt>(Statement))
161+
return DoWhileLoop->getCond();
162+
if (const auto *CXXRangeLoop = dyn_cast<CXXForRangeStmt>(Statement))
163+
return CXXRangeLoop->getCond();
164+
llvm_unreachable("Unknown loop");
165+
}
166+
167+
bool UnrollLoopsCheck::hasLargeNumIterations(const Stmt *Statement,
168+
const IntegerLiteral *CXXLoopBound,
169+
const ASTContext *Context) {
170+
// Because hasKnownBounds is called before this, if this is true, then
171+
// CXXLoopBound is also matched.
172+
if (isa<CXXForRangeStmt>(Statement)) {
173+
assert(CXXLoopBound && "CXX ranged for loop has no loop bound");
174+
return exprHasLargeNumIterations(CXXLoopBound, Context);
175+
}
176+
const auto *ForLoop = dyn_cast<ForStmt>(Statement);
177+
assert(ForLoop && "Unknown loop");
178+
const Stmt *Initializer = ForLoop->getInit();
179+
const Expr *Conditional = ForLoop->getCond();
180+
const Expr *Increment = ForLoop->getInc();
181+
int InitValue;
182+
// If the loop variable value isn't known, we can't know the loop bounds.
183+
if (const auto *InitDeclStatement = dyn_cast<DeclStmt>(Initializer)) {
184+
if (const auto *VariableDecl =
185+
dyn_cast<VarDecl>(InitDeclStatement->getSingleDecl())) {
186+
APValue *Evaluation = VariableDecl->evaluateValue();
187+
if (!Evaluation || !Evaluation->isInt())
188+
return true;
189+
InitValue = Evaluation->getInt().getExtValue();
190+
}
191+
}
192+
assert(isa<BinaryOperator>(Conditional) &&
193+
"Conditional is not a binary operator");
194+
int EndValue;
195+
const auto *BinaryOp = dyn_cast<BinaryOperator>(Conditional);
196+
if (!extractValue(EndValue, BinaryOp, Context))
197+
return true;
198+
199+
double Iterations;
200+
201+
// If increment is unary and not one of ++, --, we can't know the loop bounds.
202+
if (const auto *Op = dyn_cast<UnaryOperator>(Increment)) {
203+
if (Op->isIncrementOp())
204+
Iterations = EndValue - InitValue;
205+
else if (Op->isDecrementOp())
206+
Iterations = InitValue - EndValue;
207+
else
208+
llvm_unreachable("Unary operator neither increment nor decrement");
209+
}
210+
211+
// If increment is binary and not one of +, -, *, /, we can't know the loop
212+
// bounds.
213+
if (const auto *Op = dyn_cast<BinaryOperator>(Increment)) {
214+
int ConstantValue;
215+
if (!extractValue(ConstantValue, Op, Context))
216+
return true;
217+
switch (Op->getOpcode()) {
218+
case (BO_AddAssign):
219+
Iterations = ceil(float(EndValue - InitValue) / ConstantValue);
220+
break;
221+
case (BO_SubAssign):
222+
Iterations = ceil(float(InitValue - EndValue) / ConstantValue);
223+
break;
224+
case (BO_MulAssign):
225+
Iterations = 1 + (log(EndValue) - log(InitValue)) / log(ConstantValue);
226+
break;
227+
case (BO_DivAssign):
228+
Iterations = 1 + (log(InitValue) - log(EndValue)) / log(ConstantValue);
229+
break;
230+
default:
231+
// All other operators are not handled; assume large bounds.
232+
return true;
233+
}
234+
}
235+
return Iterations > MaxLoopIterations;
236+
}
237+
238+
bool UnrollLoopsCheck::extractValue(int &Value, const BinaryOperator *Op,
239+
const ASTContext *Context) {
240+
const Expr *LHS = Op->getLHS();
241+
const Expr *RHS = Op->getRHS();
242+
Expr::EvalResult Result;
243+
if (LHS->isEvaluatable(*Context))
244+
LHS->EvaluateAsRValue(Result, *Context);
245+
else if (RHS->isEvaluatable(*Context))
246+
RHS->EvaluateAsRValue(Result, *Context);
247+
else
248+
return false; // Cannot evalue either side.
249+
if (!Result.Val.isInt())
250+
return false; // Cannot check number of iterations, return false to be
251+
// safe.
252+
Value = Result.Val.getInt().getExtValue();
253+
return true;
254+
}
255+
256+
bool UnrollLoopsCheck::exprHasLargeNumIterations(const Expr *Expression,
257+
const ASTContext *Context) {
258+
Expr::EvalResult Result;
259+
if (Expression->EvaluateAsRValue(Result, *Context)) {
260+
if (!Result.Val.isInt())
261+
return false; // Cannot check number of iterations, return false to be
262+
// safe.
263+
// The following assumes values go from 0 to Val in increments of 1.
264+
return Result.Val.getInt() > MaxLoopIterations;
265+
}
266+
// Cannot evaluate Expression as an r-value, so cannot check number of
267+
// iterations.
268+
return false;
269+
}
270+
271+
void UnrollLoopsCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
272+
Options.store(Opts, "MaxLoopIterations", MaxLoopIterations);
273+
}
274+
275+
} // namespace altera
276+
} // namespace tidy
277+
} // namespace clang

0 commit comments

Comments
 (0)