-
Notifications
You must be signed in to change notification settings - Fork 744
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'sycl' into private/dvodopya/improve-allowlist
- Loading branch information
Showing
6,327 changed files
with
1,309,820 additions
and
179,386 deletions.
The diff you're trying to view is too large. We only load the first 3000 changed files.
There are no files selected for viewing
Validating CODEOWNERS rules …
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# Reporting LLVM Security Issues | ||
|
||
To report security issues in LLVM, please follow the steps outlined on the | ||
[LLVM Security Group](https://llvm.org/docs/Security.html#how-to-report-a-security-issue) | ||
page. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
264 changes: 264 additions & 0 deletions
264
clang-tools-extra/clang-tidy/altera/IdDependentBackwardBranchCheck.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,264 @@ | ||
//===--- IdDependentBackwardBranchCheck.cpp - clang-tidy ------------------===// | ||
// | ||
// 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 | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#include "IdDependentBackwardBranchCheck.h" | ||
#include "clang/AST/ASTContext.h" | ||
#include "clang/ASTMatchers/ASTMatchFinder.h" | ||
|
||
using namespace clang::ast_matchers; | ||
|
||
namespace clang { | ||
namespace tidy { | ||
namespace altera { | ||
|
||
void IdDependentBackwardBranchCheck::registerMatchers(MatchFinder *Finder) { | ||
// Prototype to identify all variables which hold a thread-variant ID. | ||
// First Matcher just finds all the direct assignments of either ID call. | ||
const auto ThreadID = expr(hasDescendant(callExpr(callee(functionDecl( | ||
anyOf(hasName("get_global_id"), hasName("get_local_id"))))))); | ||
|
||
const auto RefVarOrField = forEachDescendant( | ||
stmt(anyOf(declRefExpr(to(varDecl())).bind("assign_ref_var"), | ||
memberExpr(member(fieldDecl())).bind("assign_ref_field")))); | ||
|
||
Finder->addMatcher( | ||
compoundStmt( | ||
// Bind on actual get_local/global_id calls. | ||
forEachDescendant( | ||
stmt( | ||
anyOf(declStmt(hasDescendant(varDecl(hasInitializer(ThreadID)) | ||
.bind("tid_dep_var"))), | ||
binaryOperator(allOf( | ||
isAssignmentOperator(), hasRHS(ThreadID), | ||
hasLHS(anyOf( | ||
declRefExpr(to(varDecl().bind("tid_dep_var"))), | ||
memberExpr(member( | ||
fieldDecl().bind("tid_dep_field"))))))))) | ||
.bind("straight_assignment"))), | ||
this); | ||
|
||
// Bind all VarDecls that include an initializer with a variable DeclRefExpr | ||
// (in case it is ID-dependent). | ||
Finder->addMatcher( | ||
stmt(forEachDescendant( | ||
varDecl(hasInitializer(RefVarOrField)).bind("pot_tid_var"))), | ||
this); | ||
|
||
// Bind all VarDecls that are assigned a value with a variable DeclRefExpr (in | ||
// case it is ID-dependent). | ||
Finder->addMatcher( | ||
stmt(forEachDescendant(binaryOperator( | ||
allOf(isAssignmentOperator(), hasRHS(RefVarOrField), | ||
hasLHS(anyOf( | ||
declRefExpr(to(varDecl().bind("pot_tid_var"))), | ||
memberExpr(member(fieldDecl().bind("pot_tid_field"))))))))), | ||
this); | ||
|
||
// Second Matcher looks for branch statements inside of loops and bind on the | ||
// condition expression IF it either calls an ID function or has a variable | ||
// DeclRefExpr. DeclRefExprs are checked later to confirm whether the variable | ||
// is ID-dependent. | ||
const auto CondExpr = | ||
expr(anyOf(hasDescendant(callExpr(callee(functionDecl( | ||
anyOf(hasName("get_global_id"), | ||
hasName("get_local_id"))))) | ||
.bind("id_call")), | ||
hasDescendant(stmt(anyOf(declRefExpr(to(varDecl())), | ||
memberExpr(member(fieldDecl()))))))) | ||
.bind("cond_expr"); | ||
Finder->addMatcher(stmt(anyOf(forStmt(hasCondition(CondExpr)), | ||
doStmt(hasCondition(CondExpr)), | ||
whileStmt(hasCondition(CondExpr)))) | ||
.bind("backward_branch"), | ||
this); | ||
} | ||
|
||
IdDependentBackwardBranchCheck::IdDependencyRecord * | ||
IdDependentBackwardBranchCheck::hasIdDepVar(const Expr *Expression) { | ||
if (const auto *Declaration = dyn_cast<DeclRefExpr>(Expression)) { | ||
// It is a DeclRefExpr, so check if it's an ID-dependent variable. | ||
const auto *CheckVariable = dyn_cast<VarDecl>(Declaration->getDecl()); | ||
auto FoundVariable = IdDepVarsMap.find(CheckVariable); | ||
if (FoundVariable == IdDepVarsMap.end()) | ||
return nullptr; | ||
return &(FoundVariable->second); | ||
} | ||
for (const auto *Child : Expression->children()) | ||
if (const auto *ChildExpression = dyn_cast<Expr>(Child)) | ||
if (IdDependencyRecord *Result = hasIdDepVar(ChildExpression)) | ||
return Result; | ||
return nullptr; | ||
} | ||
|
||
IdDependentBackwardBranchCheck::IdDependencyRecord * | ||
IdDependentBackwardBranchCheck::hasIdDepField(const Expr *Expression) { | ||
if (const auto *MemberExpression = dyn_cast<MemberExpr>(Expression)) { | ||
const auto *CheckField = | ||
dyn_cast<FieldDecl>(MemberExpression->getMemberDecl()); | ||
auto FoundField = IdDepFieldsMap.find(CheckField); | ||
if (FoundField == IdDepFieldsMap.end()) | ||
return nullptr; | ||
return &(FoundField->second); | ||
} | ||
for (const auto *Child : Expression->children()) | ||
if (const auto *ChildExpression = dyn_cast<Expr>(Child)) | ||
if (IdDependencyRecord *Result = hasIdDepField(ChildExpression)) | ||
return Result; | ||
return nullptr; | ||
} | ||
|
||
void IdDependentBackwardBranchCheck::saveIdDepVar(const Stmt *Statement, | ||
const VarDecl *Variable) { | ||
// Record that this variable is thread-dependent. | ||
IdDepVarsMap[Variable] = | ||
IdDependencyRecord(Variable, Variable->getBeginLoc(), | ||
Twine("assignment of ID-dependent variable ") + | ||
Variable->getNameAsString()); | ||
} | ||
|
||
void IdDependentBackwardBranchCheck::saveIdDepField(const Stmt *Statement, | ||
const FieldDecl *Field) { | ||
// Record that this field is thread-dependent. | ||
IdDepFieldsMap[Field] = IdDependencyRecord( | ||
Field, Statement->getBeginLoc(), | ||
Twine("assignment of ID-dependent field ") + Field->getNameAsString()); | ||
} | ||
|
||
void IdDependentBackwardBranchCheck::saveIdDepVarFromReference( | ||
const DeclRefExpr *RefExpr, const MemberExpr *MemExpr, | ||
const VarDecl *PotentialVar) { | ||
// If the variable is already in IdDepVarsMap, ignore it. | ||
if (IdDepVarsMap.find(PotentialVar) != IdDepVarsMap.end()) | ||
return; | ||
std::string Message; | ||
llvm::raw_string_ostream StringStream(Message); | ||
StringStream << "inferred assignment of ID-dependent value from " | ||
"ID-dependent "; | ||
if (RefExpr) { | ||
const auto *RefVar = dyn_cast<VarDecl>(RefExpr->getDecl()); | ||
// If variable isn't ID-dependent, but RefVar is. | ||
if (IdDepVarsMap.find(RefVar) != IdDepVarsMap.end()) | ||
StringStream << "variable " << RefVar->getNameAsString(); | ||
} | ||
if (MemExpr) { | ||
const auto *RefField = dyn_cast<FieldDecl>(MemExpr->getMemberDecl()); | ||
// If variable isn't ID-dependent, but RefField is. | ||
if (IdDepFieldsMap.find(RefField) != IdDepFieldsMap.end()) | ||
StringStream << "member " << RefField->getNameAsString(); | ||
} | ||
IdDepVarsMap[PotentialVar] = | ||
IdDependencyRecord(PotentialVar, PotentialVar->getBeginLoc(), Message); | ||
} | ||
|
||
void IdDependentBackwardBranchCheck::saveIdDepFieldFromReference( | ||
const DeclRefExpr *RefExpr, const MemberExpr *MemExpr, | ||
const FieldDecl *PotentialField) { | ||
// If the field is already in IdDepFieldsMap, ignore it. | ||
if (IdDepFieldsMap.find(PotentialField) != IdDepFieldsMap.end()) | ||
return; | ||
std::string Message; | ||
llvm::raw_string_ostream StringStream(Message); | ||
StringStream << "inferred assignment of ID-dependent member from " | ||
"ID-dependent "; | ||
if (RefExpr) { | ||
const auto *RefVar = dyn_cast<VarDecl>(RefExpr->getDecl()); | ||
// If field isn't ID-dependent, but RefVar is. | ||
if (IdDepVarsMap.find(RefVar) != IdDepVarsMap.end()) | ||
StringStream << "variable " << RefVar->getNameAsString(); | ||
} | ||
if (MemExpr) { | ||
const auto *RefField = dyn_cast<FieldDecl>(MemExpr->getMemberDecl()); | ||
if (IdDepFieldsMap.find(RefField) != IdDepFieldsMap.end()) | ||
StringStream << "member " << RefField->getNameAsString(); | ||
} | ||
IdDepFieldsMap[PotentialField] = IdDependencyRecord( | ||
PotentialField, PotentialField->getBeginLoc(), Message); | ||
} | ||
|
||
IdDependentBackwardBranchCheck::LoopType | ||
IdDependentBackwardBranchCheck::getLoopType(const Stmt *Loop) { | ||
switch (Loop->getStmtClass()) { | ||
case Stmt::DoStmtClass: | ||
return DoLoop; | ||
case Stmt::WhileStmtClass: | ||
return WhileLoop; | ||
case Stmt::ForStmtClass: | ||
return ForLoop; | ||
default: | ||
return UnknownLoop; | ||
} | ||
} | ||
|
||
void IdDependentBackwardBranchCheck::check( | ||
const MatchFinder::MatchResult &Result) { | ||
// The first half of the callback only deals with identifying and storing | ||
// ID-dependency information into the IdDepVars and IdDepFields maps. | ||
const auto *Variable = Result.Nodes.getNodeAs<VarDecl>("tid_dep_var"); | ||
const auto *Field = Result.Nodes.getNodeAs<FieldDecl>("tid_dep_field"); | ||
const auto *Statement = Result.Nodes.getNodeAs<Stmt>("straight_assignment"); | ||
const auto *RefExpr = Result.Nodes.getNodeAs<DeclRefExpr>("assign_ref_var"); | ||
const auto *MemExpr = Result.Nodes.getNodeAs<MemberExpr>("assign_ref_field"); | ||
const auto *PotentialVar = Result.Nodes.getNodeAs<VarDecl>("pot_tid_var"); | ||
const auto *PotentialField = | ||
Result.Nodes.getNodeAs<FieldDecl>("pot_tid_field"); | ||
|
||
// Save variables and fields assigned directly through ID function calls. | ||
if (Statement && (Variable || Field)) { | ||
if (Variable) | ||
saveIdDepVar(Statement, Variable); | ||
else if (Field) | ||
saveIdDepField(Statement, Field); | ||
} | ||
|
||
// Save variables assigned to values of Id-dependent variables and fields. | ||
if ((RefExpr || MemExpr) && PotentialVar) | ||
saveIdDepVarFromReference(RefExpr, MemExpr, PotentialVar); | ||
|
||
// Save fields assigned to values of ID-dependent variables and fields. | ||
if ((RefExpr || MemExpr) && PotentialField) | ||
saveIdDepFieldFromReference(RefExpr, MemExpr, PotentialField); | ||
|
||
// The second part of the callback deals with checking if a branch inside a | ||
// loop is thread dependent. | ||
const auto *CondExpr = Result.Nodes.getNodeAs<Expr>("cond_expr"); | ||
const auto *IDCall = Result.Nodes.getNodeAs<CallExpr>("id_call"); | ||
const auto *Loop = Result.Nodes.getNodeAs<Stmt>("backward_branch"); | ||
if (!Loop) | ||
return; | ||
LoopType Type = getLoopType(Loop); | ||
if (CondExpr) { | ||
if (IDCall) { // Conditional expression calls an ID function directly. | ||
diag(CondExpr->getBeginLoc(), | ||
"backward branch (%select{do|while|for}0 loop) is ID-dependent due " | ||
"to ID function call and may cause performance degradation") | ||
<< Type; | ||
return; | ||
} | ||
// Conditional expression has DeclRefExpr(s), check ID-dependency. | ||
IdDependencyRecord *IdDepVar = hasIdDepVar(CondExpr); | ||
IdDependencyRecord *IdDepField = hasIdDepField(CondExpr); | ||
if (IdDepVar) { | ||
// Change one of these to a Note | ||
diag(IdDepVar->Location, IdDepVar->Message, DiagnosticIDs::Note); | ||
diag(CondExpr->getBeginLoc(), | ||
"backward branch (%select{do|while|for}0 loop) is ID-dependent due " | ||
"to variable reference to %1 and may cause performance degradation") | ||
<< Type << IdDepVar->VariableDeclaration; | ||
} else if (IdDepField) { | ||
diag(IdDepField->Location, IdDepField->Message, DiagnosticIDs::Note); | ||
diag(CondExpr->getBeginLoc(), | ||
"backward branch (%select{do|while|for}0 loop) is ID-dependent due " | ||
"to member reference to %1 and may cause performance degradation") | ||
<< Type << IdDepField->FieldDeclaration; | ||
} | ||
} | ||
} | ||
|
||
} // namespace altera | ||
} // namespace tidy | ||
} // namespace clang |
Oops, something went wrong.