5151#include < algorithm>
5252#include < cstddef>
5353#include < iterator>
54+ #include < memory>
5455#include < numeric>
56+ #include < string>
57+ #include < utility>
58+ #include < vector>
5559
5660#include " clad/Differentiator/CladUtils.h"
5761#include " clad/Differentiator/Compatibility.h"
5862
59- #include " clang/ASTMatchers/ASTMatchFinder.h"
60- #include " clang/ASTMatchers/ASTMatchers.h"
61-
62- using namespace clang ::ast_matchers;
63-
6463namespace clad {
6564
6665Expr* getArraySizeExpr (const ArrayType* AT , ASTContext& context,
@@ -136,51 +135,130 @@ Expr* ReverseModeVisitor::getStdInitListSizeExpr(const Expr* E) {
136135 return CladTapeResult{*this , PushExpr, PopExpr, TapeRef};
137136 }
138137
139- static bool isInjectiveE (const clang::Expr* E, clang::ASTContext& ctx) {
140- StatementMatcher matcher =
141- binaryOperator (
142- hasOperatorName (" +" ),
143- hasLHS (expr (
144- has (callExpr (hasDescendant (memberExpr (
145- hasObjectExpression (opaqueValueExpr (hasSourceExpression (
146- declRefExpr (to (varDecl (hasName (" threadIdx" ))))))))))),
147- unless (binaryOperator ()))),
148- hasRHS (binaryOperator (
149- hasOperatorName (" *" ),
150- has (expr (
151- has (callExpr (hasDescendant (memberExpr (hasObjectExpression (
152- opaqueValueExpr (hasSourceExpression (declRefExpr (
153- to (varDecl (hasName (" blockIdx" ))))))))))),
154- unless (binaryOperator ()))),
155- has (expr (
156- has (callExpr (hasDescendant (memberExpr (hasObjectExpression (
157- opaqueValueExpr (hasSourceExpression (declRefExpr (
158- to (varDecl (hasName (" blockDim" ))))))))))),
159- unless (binaryOperator ()))))))
160- .bind (" targetVar" );
161-
162- class InjectivePatternMatchCallback : public MatchFinder ::MatchCallback {
163- const clang::Expr* targetExpr;
138+ static bool isInjectiveE (const clang::Expr* E) {
139+ class InjectiveCheckerExpr
140+ : public clang::RecursiveASTVisitor<InjectiveCheckerExpr> {
141+ struct IdxNode {
142+ struct ExprOrBinOp {
143+ const clang::DeclRefExpr* m_E = nullptr ;
144+ clang::BinaryOperatorKind m_Opcode;
145+ enum class Kind { Expr, Opcode } m_Kind;
146+
147+ ExprOrBinOp (const clang::DeclRefExpr* E)
148+ : m_E(E), m_Kind(Kind::Expr) {}
149+ ExprOrBinOp (clang::BinaryOperatorKind op)
150+ : m_Opcode(op), m_Kind(Kind::Opcode) {}
151+
152+ [[nodiscard]] bool isExpr () const { return m_Kind == Kind::Expr; }
153+ [[nodiscard]] bool isOpcode () const { return m_Kind == Kind::Opcode; }
154+ };
155+
156+ ExprOrBinOp Node;
157+ std::unique_ptr<IdxNode> left;
158+ std::unique_ptr<IdxNode> right;
159+
160+ IdxNode (ExprOrBinOp N) : Node(N) {}
161+ };
162+ std::unique_ptr<IdxNode> m_Root;
163+ IdxNode* m_ParentNode = nullptr ;
164+
165+ enum class side { left, right } m_Side;
164166
165167 public:
166- InjectivePatternMatchCallback (const clang::Expr* E) : targetExpr(E) {}
167- bool matched = false ;
168- virtual void run (const MatchFinder::MatchResult& Result) override {
169- if (const auto * expr =
170- Result.Nodes .getNodeAs <clang::BinaryOperator>(" targetVar" )) {
171- if (targetExpr == expr)
172- matched = true ;
168+ InjectiveCheckerExpr () = default ;
169+
170+ bool comparePatternToTree (const IdxNode* current,
171+ const std::vector<std::string>& patternIdx,
172+ size_t i = 1 ) {
173+
174+ if (!current && (i >= patternIdx.size () || patternIdx[i].empty ()))
175+ return true ;
176+
177+ if (!current || i >= patternIdx.size () || patternIdx[i].empty ())
178+ return false ;
179+
180+ const std::string& expected = patternIdx[i];
181+
182+ if (current->Node .isOpcode ()) {
183+ std::string actualOp =
184+ clang::BinaryOperator::getOpcodeStr (current->Node .m_Opcode ).str ();
185+ if (actualOp != expected)
186+ return false ;
187+ } else if (current->Node .isExpr ()) {
188+ std::string actualName =
189+ current->Node .m_E ->getNameInfo ().getAsString ();
190+ if (actualName != expected)
191+ return false ;
173192 }
193+
194+ bool sameOrder =
195+ comparePatternToTree (current->left .get (), patternIdx, 2 * i) &&
196+ comparePatternToTree (current->right .get (), patternIdx, 2 * i + 1 );
197+
198+ if (sameOrder)
199+ return true ;
200+
201+ return comparePatternToTree (current->left .get (), patternIdx,
202+ 2 * i + 1 ) &&
203+ comparePatternToTree (current->right .get (), patternIdx, 2 * i);
204+ }
205+
206+ bool isInjectiveIdx (const clang::Expr* E) {
207+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
208+ TraverseStmt (const_cast <clang::Expr*>(E));
209+ std::vector<std::string> pattern = {" " , " +" , " threadIdx" , " *" ,
210+ " " , " " , " blockIdx" , " blockDim" };
211+ return comparePatternToTree (m_Root.get (), pattern);
212+ }
213+
214+ bool TraverseBinaryOperator (clang::BinaryOperator* BinOp) {
215+ const auto opCode = BinOp->getOpcode ();
216+ if (opCode == BO_Add || opCode == BO_Mul) {
217+ std::unique_ptr<IdxNode> curr = std::make_unique<IdxNode>(opCode);
218+ IdxNode* currPtr = nullptr ;
219+
220+ if (!m_Root) {
221+ m_Root = std::move (curr);
222+ currPtr = m_Root.get ();
223+ } else {
224+ currPtr = curr.get ();
225+
226+ if (m_Side == side::left)
227+ m_ParentNode->left = std::move (curr);
228+
229+ if (m_Side == side::right)
230+ m_ParentNode->right = std::move (curr);
231+ }
232+
233+ Expr* L = BinOp->getLHS ();
234+ Expr* R = BinOp->getRHS ();
235+
236+ m_ParentNode = currPtr;
237+ m_Side = side::left;
238+ TraverseStmt (L);
239+ m_ParentNode = currPtr;
240+
241+ m_Side = side::right;
242+ TraverseStmt (R);
243+ }
244+ return true ;
174245 }
175- bool hasMatched () const { return matched; }
176- };
177246
178- MatchFinder Finder;
179- InjectivePatternMatchCallback Callback (E);
180- Finder.addMatcher (matcher, &Callback);
181- Finder.matchAST (ctx);
247+ bool TraverseDeclRefExpr (clang::DeclRefExpr* DRE ) {
248+ std::unique_ptr<IdxNode> curr = std::make_unique<IdxNode>(DRE );
249+
250+ if (m_ParentNode) {
251+ if (m_Side == side::left)
252+ m_ParentNode->left = std::move (curr);
182253
183- return Callback.hasMatched ();
254+ if (m_Side == side::right)
255+ m_ParentNode->right = std::move (curr);
256+ }
257+ return true ;
258+ }
259+
260+ } checker;
261+ return checker.isInjectiveIdx (E);
184262 }
185263
186264 static bool isInjective (const clang::Expr* E, clang::ASTContext& ctx) {
@@ -189,7 +267,7 @@ Expr* ReverseModeVisitor::getStdInitListSizeExpr(const Expr* E) {
189267 clang::ASTContext& m_Context;
190268
191269 public:
192- InjectiveChecker (clang::ASTContext& Context) : m_Context(Context){};
270+ InjectiveChecker (clang::ASTContext& Context) : m_Context(Context) {};
193271
194272 bool isInjectiveIdx (const clang::Expr* E) {
195273 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
@@ -218,15 +296,15 @@ Expr* ReverseModeVisitor::getStdInitListSizeExpr(const Expr* E) {
218296 if (isConstL && !isConstR)
219297 return TraverseStmt (R);
220298
221- return isInjectiveE (BinOp, m_Context );
299+ return isInjectiveE (BinOp);
222300 }
223301 return false ;
224302 }
225303
226304 bool TraverseDeclRefExpr (clang::DeclRefExpr* DRE ) {
227305 if (auto * VD = dyn_cast<VarDecl>(DRE ->getDecl ())) {
228306 if (auto * init = VD ->getInit ())
229- return isInjectiveE (init->IgnoreImpCasts (), m_Context );
307+ return isInjectiveE (init->IgnoreImpCasts ());
230308 }
231309 return false ;
232310 }
@@ -258,8 +336,9 @@ Expr* ReverseModeVisitor::getStdInitListSizeExpr(const Expr* E) {
258336 }
259337 } else if (const auto * ASE = dyn_cast<ArraySubscriptExpr>(E)) {
260338 if (m_DiffReq->hasAttr <clang::CUDAGlobalAttr>()) {
261- auto * idx = ASE ->getIdx ();
262- auto * base = dyn_cast<DeclRefExpr>(ASE ->getBase ()->IgnoreImpCasts ());
339+ const auto * idx = ASE ->getIdx ();
340+ const auto * base =
341+ dyn_cast<DeclRefExpr>(ASE ->getBase ()->IgnoreImpCasts ());
263342 if (const auto * PVD = dyn_cast<ParmVarDecl>(base->getDecl ())) {
264343 if (m_DiffReq->hasAttr <clang::CUDAGlobalAttr>()) {
265344 // Check whether this param is in the global memory of the GPU and
@@ -268,7 +347,6 @@ Expr* ReverseModeVisitor::getStdInitListSizeExpr(const Expr* E) {
268347 !isInjective (idx, m_Context);
269348 }
270349 }
271- return true ;
272350 }
273351 }
274352 return false ;
0 commit comments