@@ -136,51 +136,148 @@ Expr* ReverseModeVisitor::getStdInitListSizeExpr(const Expr* E) {
136136 return CladTapeResult{*this , PushExpr, PopExpr, TapeRef};
137137 }
138138
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;
139+ static bool isInjectiveE (const clang::Expr* E) {
140+ class InjectiveCheckerExpr
141+ : public clang::RecursiveASTVisitor<InjectiveCheckerExpr> {
142+ struct IdxNode {
143+ struct ExprOrBinOp {
144+ const clang::DeclRefExpr* m_E = nullptr ;
145+ clang::BinaryOperatorKind m_Opcode;
146+ enum class Kind { Expr, Opcode } m_Kind;
147+
148+ ExprOrBinOp (const clang::DeclRefExpr* E)
149+ : m_E(E), m_Kind(Kind::Expr) {}
150+ ExprOrBinOp (clang::BinaryOperatorKind op)
151+ : m_Opcode(op), m_Kind(Kind::Opcode) {}
152+
153+ bool isExpr () const { return m_Kind == Kind::Expr; }
154+ bool isOpcode () const { return m_Kind == Kind::Opcode; }
155+ };
156+
157+ ExprOrBinOp Node;
158+ std::unique_ptr<IdxNode> left;
159+ std::unique_ptr<IdxNode> right;
160+
161+ IdxNode (ExprOrBinOp N) : Node(N) {}
162+ };
163+ std::unique_ptr<IdxNode> m_Root;
164+ IdxNode* m_ParentNode;
165+
166+ enum class side { left, right } m_Side;
164167
165168 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 ;
169+ InjectiveCheckerExpr () = default ;
170+
171+ bool comparePatternToTree (const IdxNode* current,
172+ const std::vector<std::string>& patternIdx,
173+ size_t i = 1 , bool * shouldInvert = nullptr ) {
174+ if (!shouldInvert)
175+ shouldInvert = new bool (false );
176+
177+ if (!current && (i >= patternIdx.size () || patternIdx[i].empty ()))
178+ return true ;
179+
180+ if (!current || i >= patternIdx.size () || patternIdx[i].empty ())
181+ return false ;
182+
183+ std::string expected;
184+ if (*shouldInvert)
185+ if (i % 2 == 0 )
186+ expected = patternIdx[i + 1 ];
187+ else
188+ expected = patternIdx[i - 1 ];
189+ else
190+ expected = patternIdx[i];
191+
192+ if (current->Node .isOpcode ()) {
193+ std::string actualOp =
194+ clang::BinaryOperator::getOpcodeStr (current->Node .m_Opcode ).str ();
195+ if (actualOp != expected) {
196+ if (i % 2 == 0 && actualOp == patternIdx[i + 1 ])
197+ *shouldInvert = true ;
198+ else if (i % 2 == 1 && actualOp == patternIdx[i - 1 ])
199+ *shouldInvert = true ;
200+ else
201+ return false ;
202+ }
203+ } else if (current->Node .isExpr ()) {
204+ if (!current->Node .m_E )
205+ return false ;
206+ std::string actualName =
207+ current->Node .m_E ->getNameInfo ().getAsString ();
208+ if (actualName != expected) {
209+ if (i % 2 == 0 && actualName == patternIdx[i + 1 ])
210+ *shouldInvert = true ;
211+ else if (i % 2 == 1 && actualName == patternIdx[i - 1 ])
212+ *shouldInvert = true ;
213+ else
214+ return false ;
215+ }
173216 }
217+
218+ bool * invert = new bool (false );
219+ return comparePatternToTree (current->left .get (), patternIdx, 2 * i,
220+ invert) &&
221+ comparePatternToTree (current->right .get (), patternIdx, 2 * i + 1 ,
222+ invert);
174223 }
175- bool hasMatched () const { return matched; }
176- };
177224
178- MatchFinder Finder;
179- InjectivePatternMatchCallback Callback (E);
180- Finder.addMatcher (matcher, &Callback);
181- Finder.matchAST (ctx);
225+ bool isInjectiveIdx (const clang::Expr* E) {
226+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
227+ TraverseStmt (const_cast <clang::Expr*>(E));
228+ std::vector<std::string> pattern = {" " , " +" , " threadIdx" , " *" ,
229+ " " , " " , " blockIdx" , " blockDim" };
230+ return comparePatternToTree (m_Root.get (), pattern);
231+ }
182232
183- return Callback.hasMatched ();
233+ bool TraverseBinaryOperator (clang::BinaryOperator* BinOp) {
234+ const auto opCode = BinOp->getOpcode ();
235+ if (opCode == BO_Add || opCode == BO_Mul) {
236+ std::unique_ptr<IdxNode> curr = std::make_unique<IdxNode>(opCode);
237+ IdxNode* currPtr;
238+
239+ if (!m_Root) {
240+ m_Root = std::move (curr);
241+ currPtr = m_Root.get ();
242+ } else {
243+ currPtr = curr.get ();
244+
245+ if (m_Side == side::left)
246+ m_ParentNode->left = std::move (curr);
247+
248+ if (m_Side == side::right)
249+ m_ParentNode->right = std::move (curr);
250+ }
251+
252+ Expr* L = BinOp->getLHS ();
253+ Expr* R = BinOp->getRHS ();
254+
255+ m_ParentNode = currPtr;
256+ m_Side = side::left;
257+ TraverseStmt (L);
258+ m_ParentNode = currPtr;
259+
260+ m_Side = side::right;
261+ TraverseStmt (R);
262+ }
263+ return true ;
264+ }
265+
266+ bool TraverseDeclRefExpr (clang::DeclRefExpr* DRE ) {
267+ std::unique_ptr<IdxNode> curr = std::make_unique<IdxNode>(DRE );
268+
269+ if (m_ParentNode) {
270+ if (m_Side == side::left)
271+ m_ParentNode->left = std::move (curr);
272+
273+ if (m_Side == side::right)
274+ m_ParentNode->right = std::move (curr);
275+ }
276+ return true ;
277+ }
278+
279+ } checker;
280+ return checker.isInjectiveIdx (E);
184281 }
185282
186283 static bool isInjective (const clang::Expr* E, clang::ASTContext& ctx) {
@@ -189,7 +286,7 @@ Expr* ReverseModeVisitor::getStdInitListSizeExpr(const Expr* E) {
189286 clang::ASTContext& m_Context;
190287
191288 public:
192- InjectiveChecker (clang::ASTContext& Context) : m_Context(Context){};
289+ InjectiveChecker (clang::ASTContext& Context) : m_Context(Context) {};
193290
194291 bool isInjectiveIdx (const clang::Expr* E) {
195292 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
@@ -218,15 +315,15 @@ Expr* ReverseModeVisitor::getStdInitListSizeExpr(const Expr* E) {
218315 if (isConstL && !isConstR)
219316 return TraverseStmt (R);
220317
221- return isInjectiveE (BinOp, m_Context );
318+ return isInjectiveE (BinOp);
222319 }
223320 return false ;
224321 }
225322
226323 bool TraverseDeclRefExpr (clang::DeclRefExpr* DRE ) {
227324 if (auto * VD = dyn_cast<VarDecl>(DRE ->getDecl ())) {
228325 if (auto * init = VD ->getInit ())
229- return isInjectiveE (init->IgnoreImpCasts (), m_Context );
326+ return isInjectiveE (init->IgnoreImpCasts ());
230327 }
231328 return false ;
232329 }
@@ -258,7 +355,7 @@ Expr* ReverseModeVisitor::getStdInitListSizeExpr(const Expr* E) {
258355 }
259356 } else if (const auto * ASE = dyn_cast<ArraySubscriptExpr>(E)) {
260357 if (m_DiffReq->hasAttr <clang::CUDAGlobalAttr>()) {
261- auto * idx = ASE ->getIdx ();
358+ const auto * idx = ASE ->getIdx ();
262359 auto * base = dyn_cast<DeclRefExpr>(ASE ->getBase ()->IgnoreImpCasts ());
263360 if (const auto * PVD = dyn_cast<ParmVarDecl>(base->getDecl ())) {
264361 if (m_DiffReq->hasAttr <clang::CUDAGlobalAttr>()) {
0 commit comments