10#include "clang/AST/ASTContext.h"
11#include "clang/ASTMatchers/ASTMatchFinder.h"
20 const auto ThreadID = expr(hasDescendant(callExpr(callee(functionDecl(
21 anyOf(hasName(
"get_global_id"), hasName(
"get_local_id")))))));
23 const auto RefVarOrField = forEachDescendant(
24 stmt(anyOf(declRefExpr(to(varDecl())).bind(
"assign_ref_var"),
25 memberExpr(member(fieldDecl())).bind(
"assign_ref_field"))));
32 anyOf(declStmt(hasDescendant(varDecl(hasInitializer(ThreadID))
33 .bind(
"tid_dep_var"))),
35 isAssignmentOperator(), hasRHS(ThreadID),
37 declRefExpr(to(varDecl().bind(
"tid_dep_var"))),
39 fieldDecl().bind(
"tid_dep_field"))))))))
40 .bind(
"straight_assignment"))),
46 stmt(forEachDescendant(
47 varDecl(hasInitializer(RefVarOrField)).bind(
"pot_tid_var"))),
53 stmt(forEachDescendant(
55 allOf(isAssignmentOperator(), hasRHS(RefVarOrField),
56 hasLHS(anyOf(declRefExpr(to(varDecl().bind(
"pot_tid_var"))),
58 fieldDecl().bind(
"pot_tid_field")))))))
59 .bind(
"potential_assignment"))),
67 expr(anyOf(hasDescendant(callExpr(callee(functionDecl(
68 anyOf(hasName(
"get_global_id"),
69 hasName(
"get_local_id")))))
71 hasDescendant(stmt(anyOf(declRefExpr(to(varDecl())),
72 memberExpr(member(fieldDecl())))))))
74 Finder->addMatcher(stmt(anyOf(forStmt(hasCondition(CondExpr)),
75 doStmt(hasCondition(CondExpr)),
76 whileStmt(hasCondition(CondExpr))))
77 .bind(
"backward_branch"),
81const IdDependentBackwardBranchCheck::IdDependencyRecord *
82IdDependentBackwardBranchCheck::hasIdDepVar(
const Expr *Expression) {
86 if (
const auto *Declaration = dyn_cast<DeclRefExpr>(Expression)) {
88 const auto *CheckVariable =
89 dyn_cast_if_present<VarDecl>(Declaration->getDecl());
92 auto FoundVariable = IdDepVarsMap.find(CheckVariable);
93 if (FoundVariable == IdDepVarsMap.end())
95 return &(FoundVariable->second);
97 for (
const auto *Child : Expression->children())
98 if (
const auto *ChildExpression = dyn_cast_if_present<Expr>(Child))
99 if (
const IdDependencyRecord *Result = hasIdDepVar(ChildExpression))
104const IdDependentBackwardBranchCheck::IdDependencyRecord *
105IdDependentBackwardBranchCheck::hasIdDepField(
const Expr *Expression) {
109 if (
const auto *MemberExpression = dyn_cast<MemberExpr>(Expression)) {
110 const auto *CheckField =
111 dyn_cast_if_present<FieldDecl>(MemberExpression->getMemberDecl());
114 auto FoundField = IdDepFieldsMap.find(CheckField);
115 if (FoundField == IdDepFieldsMap.end())
117 return &(FoundField->second);
119 for (
const auto *Child : Expression->children())
120 if (
const auto *ChildExpression = dyn_cast_if_present<Expr>(Child))
121 if (
const IdDependencyRecord *Result = hasIdDepField(ChildExpression))
126void IdDependentBackwardBranchCheck::saveIdDepVar(
const Stmt *Statement,
127 const VarDecl *Variable) {
130 IdDependencyRecord(Variable,
Variable->getBeginLoc(),
131 Twine(
"assignment of ID-dependent variable ") +
135void IdDependentBackwardBranchCheck::saveIdDepField(
const Stmt *Statement,
136 const FieldDecl *Field) {
138 IdDepFieldsMap[
Field] = IdDependencyRecord(
139 Field, Statement->getBeginLoc(),
140 Twine(
"assignment of ID-dependent field ") +
Field->getNameAsString());
143void IdDependentBackwardBranchCheck::saveIdDepVarFromPotentialReference(
144 const DeclRefExpr *RefExpr,
const MemberExpr *MemExpr,
145 const VarDecl *PotentialVar) {
147 if (IdDepVarsMap.contains(PotentialVar))
150 llvm::raw_string_ostream StringStream(Message);
151 StringStream <<
"inferred assignment of ID-dependent value from "
154 const auto *RefVar = dyn_cast<VarDecl>(RefExpr->getDecl());
156 if (IdDepVarsMap.contains(RefVar)) {
157 StringStream <<
"variable " << RefVar->getNameAsString();
158 IdDepVarsMap[PotentialVar] = IdDependencyRecord(
159 PotentialVar, PotentialVar->getBeginLoc(), Message);
164 const auto *RefField = dyn_cast<FieldDecl>(MemExpr->getMemberDecl());
166 if (IdDepFieldsMap.contains(RefField)) {
167 StringStream <<
"member " << RefField->getNameAsString();
168 IdDepVarsMap[PotentialVar] = IdDependencyRecord(
169 PotentialVar, PotentialVar->getBeginLoc(), Message);
174void IdDependentBackwardBranchCheck::saveIdDepFieldFromPotentialReference(
175 const Stmt *Statement,
const DeclRefExpr *RefExpr,
176 const MemberExpr *MemExpr,
const FieldDecl *PotentialField) {
178 if (IdDepFieldsMap.contains(PotentialField))
181 llvm::raw_string_ostream StringStream(Message);
182 StringStream <<
"inferred assignment of ID-dependent member from "
185 const auto *RefVar = dyn_cast<VarDecl>(RefExpr->getDecl());
187 if (IdDepVarsMap.contains(RefVar)) {
188 StringStream <<
"variable " << RefVar->getNameAsString();
189 IdDepFieldsMap[PotentialField] =
190 IdDependencyRecord(PotentialField, Statement->getBeginLoc(), Message);
195 const auto *RefField = dyn_cast<FieldDecl>(MemExpr->getMemberDecl());
196 if (IdDepFieldsMap.contains(RefField)) {
197 StringStream <<
"member " << RefField->getNameAsString();
198 IdDepFieldsMap[PotentialField] =
199 IdDependencyRecord(PotentialField, Statement->getBeginLoc(), Message);
204IdDependentBackwardBranchCheck::LoopType
205IdDependentBackwardBranchCheck::getLoopType(
const Stmt *Loop) {
206 switch (Loop->getStmtClass()) {
207 case Stmt::DoStmtClass:
209 case Stmt::WhileStmtClass:
211 case Stmt::ForStmtClass:
219 const MatchFinder::MatchResult &Result) {
222 const auto *Variable = Result.Nodes.getNodeAs<VarDecl>(
"tid_dep_var");
223 const auto *Field = Result.Nodes.getNodeAs<FieldDecl>(
"tid_dep_field");
224 const auto *Statement = Result.Nodes.getNodeAs<Stmt>(
"straight_assignment");
225 const auto *PotentialAssignment =
226 Result.Nodes.getNodeAs<Stmt>(
"potential_assignment");
227 const auto *RefExpr = Result.Nodes.getNodeAs<DeclRefExpr>(
"assign_ref_var");
228 const auto *MemExpr = Result.Nodes.getNodeAs<MemberExpr>(
"assign_ref_field");
229 const auto *PotentialVar = Result.Nodes.getNodeAs<VarDecl>(
"pot_tid_var");
230 const auto *PotentialField =
231 Result.Nodes.getNodeAs<FieldDecl>(
"pot_tid_field");
234 if (Statement && (Variable || Field)) {
236 saveIdDepVar(Statement, Variable);
238 saveIdDepField(Statement, Field);
242 if ((RefExpr || MemExpr) && PotentialVar)
243 saveIdDepVarFromPotentialReference(RefExpr, MemExpr, PotentialVar);
246 if ((RefExpr || MemExpr) && PotentialField)
247 saveIdDepFieldFromPotentialReference(PotentialAssignment, RefExpr, MemExpr,
252 const auto *CondExpr = Result.Nodes.getNodeAs<Expr>(
"cond_expr");
253 const auto *IDCall = Result.Nodes.getNodeAs<CallExpr>(
"id_call");
254 const auto *Loop = Result.Nodes.getNodeAs<Stmt>(
"backward_branch");
257 const LoopType Type = getLoopType(Loop);
260 diag(CondExpr->getBeginLoc(),
261 "backward branch (%select{do|while|for}0 loop) is ID-dependent due "
262 "to ID function call and may cause performance degradation")
267 const IdDependencyRecord *IdDepVar = hasIdDepVar(CondExpr);
268 const IdDependencyRecord *IdDepField = hasIdDepField(CondExpr);
270 diag(CondExpr->getBeginLoc(),
271 "backward branch (%select{do|while|for}0 loop) is ID-dependent due "
272 "to variable reference to %1 and may cause performance degradation")
273 << Type << IdDepVar->VariableDeclaration;
274 diag(IdDepVar->Location, IdDepVar->Message, DiagnosticIDs::Note);
275 }
else if (IdDepField) {
276 diag(CondExpr->getBeginLoc(),
277 "backward branch (%select{do|while|for}0 loop) is ID-dependent due "
278 "to member reference to %1 and may cause performance degradation")
279 << Type << IdDepField->FieldDeclaration;
280 diag(IdDepField->Location, IdDepField->Message, DiagnosticIDs::Note);
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
void registerMatchers(ast_matchers::MatchFinder *Finder) override