|
51 | 51 | #include <algorithm> |
52 | 52 | #include <cstddef> |
53 | 53 | #include <iterator> |
| 54 | +#include <memory> |
54 | 55 | #include <numeric> |
| 56 | +#include <string> |
| 57 | +#include <vector> |
55 | 58 |
|
56 | 59 | #include "clad/Differentiator/CladUtils.h" |
57 | 60 | #include "clad/Differentiator/Compatibility.h" |
58 | 61 |
|
59 | | -#include "clang/ASTMatchers/ASTMatchFinder.h" |
60 | | -#include "clang/ASTMatchers/ASTMatchers.h" |
61 | | - |
62 | | -using namespace clang::ast_matchers; |
63 | | - |
64 | 62 | namespace clad { |
65 | 63 |
|
66 | 64 | Expr* getArraySizeExpr(const ArrayType* AT, ASTContext& context, |
@@ -136,51 +134,130 @@ Expr* ReverseModeVisitor::getStdInitListSizeExpr(const Expr* E) { |
136 | 134 | return CladTapeResult{*this, PushExpr, PopExpr, TapeRef}; |
137 | 135 | } |
138 | 136 |
|
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; |
| 137 | + static bool isInjectiveE(const clang::Expr* E) { |
| 138 | + class InjectiveCheckerExpr |
| 139 | + : public clang::RecursiveASTVisitor<InjectiveCheckerExpr> { |
| 140 | + struct IdxNode { |
| 141 | + struct ExprOrBinOp { |
| 142 | + const clang::DeclRefExpr* m_E = nullptr; |
| 143 | + clang::BinaryOperatorKind m_Opcode; |
| 144 | + enum class Kind { Expr, Opcode } m_Kind; |
| 145 | + |
| 146 | + ExprOrBinOp(const clang::DeclRefExpr* E) |
| 147 | + : m_E(E), m_Kind(Kind::Expr) {} |
| 148 | + ExprOrBinOp(clang::BinaryOperatorKind op) |
| 149 | + : m_Opcode(op), m_Kind(Kind::Opcode) {} |
| 150 | + |
| 151 | + [[nodiscard]] bool isExpr() const { return m_Kind == Kind::Expr; } |
| 152 | + [[nodiscard]] bool isOpcode() const { return m_Kind == Kind::Opcode; } |
| 153 | + }; |
| 154 | + |
| 155 | + ExprOrBinOp Node; |
| 156 | + std::unique_ptr<IdxNode> left; |
| 157 | + std::unique_ptr<IdxNode> right; |
| 158 | + |
| 159 | + IdxNode(ExprOrBinOp N) : Node(N) {} |
| 160 | + }; |
| 161 | + std::unique_ptr<IdxNode> m_Root; |
| 162 | + IdxNode* m_ParentNode{}; |
| 163 | + |
| 164 | + enum class side { left, right } m_Side; |
164 | 165 |
|
165 | 166 | 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; |
| 167 | + InjectiveCheckerExpr() = default; |
| 168 | + |
| 169 | + bool comparePatternToTree(const IdxNode* current, |
| 170 | + const std::vector<std::string>& patternIdx, |
| 171 | + size_t i = 1) { |
| 172 | + |
| 173 | + if (!current && (i >= patternIdx.size() || patternIdx[i].empty())) |
| 174 | + return true; |
| 175 | + |
| 176 | + if (!current || i >= patternIdx.size() || patternIdx[i].empty()) |
| 177 | + return false; |
| 178 | + |
| 179 | + std::string expected = patternIdx[i]; |
| 180 | + |
| 181 | + if (current->Node.isOpcode()) { |
| 182 | + std::string actualOp = |
| 183 | + clang::BinaryOperator::getOpcodeStr(current->Node.m_Opcode).str(); |
| 184 | + if (actualOp != expected) |
| 185 | + return false; |
| 186 | + } else if (current->Node.isExpr()) { |
| 187 | + std::string actualName = |
| 188 | + current->Node.m_E->getNameInfo().getAsString(); |
| 189 | + if (actualName != expected) |
| 190 | + return false; |
173 | 191 | } |
| 192 | + |
| 193 | + bool sameOrder = |
| 194 | + comparePatternToTree(current->left.get(), patternIdx, 2 * i) && |
| 195 | + comparePatternToTree(current->right.get(), patternIdx, 2 * i + 1); |
| 196 | + |
| 197 | + if (sameOrder) |
| 198 | + return true; |
| 199 | + |
| 200 | + return comparePatternToTree(current->left.get(), patternIdx, |
| 201 | + 2 * i + 1) && |
| 202 | + comparePatternToTree(current->right.get(), patternIdx, 2 * i); |
174 | 203 | } |
175 | | - bool hasMatched() const { return matched; } |
176 | | - }; |
177 | 204 |
|
178 | | - MatchFinder Finder; |
179 | | - InjectivePatternMatchCallback Callback(E); |
180 | | - Finder.addMatcher(matcher, &Callback); |
181 | | - Finder.matchAST(ctx); |
| 205 | + bool isInjectiveIdx(const clang::Expr* E) { |
| 206 | + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast) |
| 207 | + TraverseStmt(const_cast<clang::Expr*>(E)); |
| 208 | + std::vector<std::string> pattern = {"", "+", "threadIdx", "*", |
| 209 | + "", "", "blockIdx", "blockDim"}; |
| 210 | + return comparePatternToTree(m_Root.get(), pattern); |
| 211 | + } |
182 | 212 |
|
183 | | - return Callback.hasMatched(); |
| 213 | + bool TraverseBinaryOperator(clang::BinaryOperator* BinOp) { |
| 214 | + const auto opCode = BinOp->getOpcode(); |
| 215 | + if (opCode == BO_Add || opCode == BO_Mul) { |
| 216 | + std::unique_ptr<IdxNode> curr = std::make_unique<IdxNode>(opCode); |
| 217 | + IdxNode* currPtr; |
| 218 | + |
| 219 | + if (!m_Root) { |
| 220 | + m_Root = std::move(curr); |
| 221 | + currPtr = m_Root.get(); |
| 222 | + } else { |
| 223 | + currPtr = curr.get(); |
| 224 | + |
| 225 | + if (m_Side == side::left) |
| 226 | + m_ParentNode->left = std::move(curr); |
| 227 | + |
| 228 | + if (m_Side == side::right) |
| 229 | + m_ParentNode->right = std::move(curr); |
| 230 | + } |
| 231 | + |
| 232 | + Expr* L = BinOp->getLHS(); |
| 233 | + Expr* R = BinOp->getRHS(); |
| 234 | + |
| 235 | + m_ParentNode = currPtr; |
| 236 | + m_Side = side::left; |
| 237 | + TraverseStmt(L); |
| 238 | + m_ParentNode = currPtr; |
| 239 | + |
| 240 | + m_Side = side::right; |
| 241 | + TraverseStmt(R); |
| 242 | + } |
| 243 | + return true; |
| 244 | + } |
| 245 | + |
| 246 | + bool TraverseDeclRefExpr(clang::DeclRefExpr* DRE) { |
| 247 | + std::unique_ptr<IdxNode> curr = std::make_unique<IdxNode>(DRE); |
| 248 | + |
| 249 | + if (m_ParentNode) { |
| 250 | + if (m_Side == side::left) |
| 251 | + m_ParentNode->left = std::move(curr); |
| 252 | + |
| 253 | + if (m_Side == side::right) |
| 254 | + m_ParentNode->right = std::move(curr); |
| 255 | + } |
| 256 | + return true; |
| 257 | + } |
| 258 | + |
| 259 | + } checker; |
| 260 | + return checker.isInjectiveIdx(E); |
184 | 261 | } |
185 | 262 |
|
186 | 263 | static bool isInjective(const clang::Expr* E, clang::ASTContext& ctx) { |
@@ -218,15 +295,15 @@ Expr* ReverseModeVisitor::getStdInitListSizeExpr(const Expr* E) { |
218 | 295 | if (isConstL && !isConstR) |
219 | 296 | return TraverseStmt(R); |
220 | 297 |
|
221 | | - return isInjectiveE(BinOp, m_Context); |
| 298 | + return isInjectiveE(BinOp); |
222 | 299 | } |
223 | 300 | return false; |
224 | 301 | } |
225 | 302 |
|
226 | 303 | bool TraverseDeclRefExpr(clang::DeclRefExpr* DRE) { |
227 | 304 | if (auto* VD = dyn_cast<VarDecl>(DRE->getDecl())) { |
228 | 305 | if (auto* init = VD->getInit()) |
229 | | - return isInjectiveE(init->IgnoreImpCasts(), m_Context); |
| 306 | + return isInjectiveE(init->IgnoreImpCasts()); |
230 | 307 | } |
231 | 308 | return false; |
232 | 309 | } |
@@ -258,7 +335,7 @@ Expr* ReverseModeVisitor::getStdInitListSizeExpr(const Expr* E) { |
258 | 335 | } |
259 | 336 | } else if (const auto* ASE = dyn_cast<ArraySubscriptExpr>(E)) { |
260 | 337 | if (m_DiffReq->hasAttr<clang::CUDAGlobalAttr>()) { |
261 | | - auto* idx = ASE->getIdx(); |
| 338 | + const auto* idx = ASE->getIdx(); |
262 | 339 | auto* base = dyn_cast<DeclRefExpr>(ASE->getBase()->IgnoreImpCasts()); |
263 | 340 | if (const auto* PVD = dyn_cast<ParmVarDecl>(base->getDecl())) { |
264 | 341 | if (m_DiffReq->hasAttr<clang::CUDAGlobalAttr>()) { |
|
0 commit comments