Clang教程之实现源源变化(4)

在这一节中,对loop-convert的例子进行了修改,以展示对ForStmt的处理。

这里主要是通过AST树结构的判断,增加对类似for(int i=0;i<5;i++)这种循环的循环界判断,在实际程序优化中,意义不是特别大,但是作为示例和练习还是不错的。

主要使用的test case是:

 1 int foo(int a, int b, int *c) {
 2     int ret = 0;
 3     if (a > b) {
 4         ret = a;
 5     } else {
 6         ret = b;
 7     }
 8     for (int temp = 0; temp < 100; ++temp) {
 9         *c = (*c + temp);
10     }
11     return ret;
12 }
13 
14 
15 int main() {
16     int a = 1, b = 2;
17     int c = 0;
18     int d = foo(a, b, &c);
19     return 0;
20 }

对ForStmt的处理在Visitor的VisitForStmt中进行(前排提示,不要尝试在RecursiveASTVisitor中对节点进行修改,大的节点修改会破坏整个AST树的Context,这里的Visitor仅建议作为遍历读取使用)

  1 //------------------------------------------------------------------------------
  2 // Tooling sample. Demonstrates:
  3 //
  4 // ForStmt Demo to show how to use ForStmt
  5 //
  6 // jourluohua (jourluohua@sina.com)
  7 // This code is in the public domain
  8 //------------------------------------------------------------------------------
  9 #include <sstream>
 10 #include <string>
 11 #include <map>
 12 
 13 #include "clang/AST/AST.h"
 14 #include "clang/AST/ASTConsumer.h"
 15 #include "clang/AST/RecursiveASTVisitor.h"
 16 #include "clang/Frontend/ASTConsumers.h"
 17 #include "clang/Frontend/CompilerInstance.h"
 18 #include "clang/Frontend/FrontendActions.h"
 19 #include "clang/Rewrite/Core/Rewriter.h"
 20 #include "clang/Tooling/CommonOptionsParser.h"
 21 #include "clang/Tooling/Tooling.h"
 22 #include "llvm/Support/raw_ostream.h"
 23 
 24 using namespace clang;
 25 using namespace clang::driver;
 26 using namespace clang::tooling;
 27 
 28 static llvm::cl::OptionCategory ToolingSampleCategory("Tooling Sample");
 29 
 30 // By implementing RecursiveASTVisitor, we can specify which AST nodes
 31 // we're interested in by overriding relevant methods.
 32 class LoopBound {
 33 public:
 34   int initVal;
 35   int maxVal;
 36   int incVal;
 37   LoopBound(){
 38     initVal = 0;
 39     maxVal  = 0;
 40     incVal  = 0;
 41   }
 42 };
 43 class MyASTVisitor : public RecursiveASTVisitor<MyASTVisitor> {
 44 public:
 45   MyASTVisitor(Rewriter &R) : TheRewriter(R) {}
 46 
 47   bool VisitForStmt(ForStmt *forStmt) {
 48     // Only care about ForStmt statements.
 49     // now we just judge for(int i=0;i<100;i++) case
 50     VarDecl* initVar = nullptr;
 51     Expr* initExpr = nullptr;
 52     LoopBound* lpBound = new LoopBound();
 53         DeclStmt* DS = nullptr;
 54 
 55     if ((DS = dyn_cast_or_null<DeclStmt>(dyn_cast<ForStmt>(forStmt)->getInit())) != 0 && DS->isSingleDecl() && 
 56                (initVar = dyn_cast<VarDecl>(DS->getSingleDecl())) != 0){
 57             initExpr = initVar->getInit();
 58     }
 59     else {
 60       return true;
 61     }
 62     IntegerLiteral* initInteg = dyn_cast_or_null<IntegerLiteral>(initExpr);
 63     lpBound->initVal = initInteg->getValue().getSExtValue();
 64 
 65     Expr *expCond = dyn_cast<ForStmt>(forStmt)->getCond();
 66     if(isa<BinaryOperator>(expCond))
 67     {
 68       BinaryOperator *binaryOpCond = dyn_cast<BinaryOperator>(expCond);
 69       if(binaryOpCond->getOpcode() ==BO_LT)
 70       {
 71         Expr * condExpr  = binaryOpCond ->getRHS();
 72         assert(condExpr && "condExpr  ");
 73         if(isa<IntegerLiteral>(condExpr))
 74         {
 75           lpBound->maxVal=(dyn_cast<IntegerLiteral>(condExpr)->getValue()).getSExtValue();
 76         }
 77         else
 78         {
 79           return true;
 80         }
 81       }
 82       else
 83       {
 84         return true;
 85       }
 86     }
 87     else
 88     {
 89       return true;
 90     }
 91 
 92     Expr *incExpr = dyn_cast<ForStmt>(forStmt)->getInc();
 93     assert(incExpr && "forStmt->getInc() cannot be NULL");
 94     if(isa<UnaryOperator>(incExpr)){    
 95       UnaryOperator *unaryInc = dyn_cast<UnaryOperator>(incExpr);
 96       if(unaryInc->isIncrementOp () )        //just like '++i' or 'i++', we think that they work same  
 97       {
 98         lpBound->incVal = 1;
 99       }
100       else
101       {
102         return true;
103       }
104       
105     }
106     conditionMap[initVar] = lpBound;
107     return true;
108   }
109 
110   std::map<VarDecl*, LoopBound*>& getCondMap(){
111     return conditionMap;
112   }
113 
114 
115 private:
116   Rewriter &TheRewriter;
117   std::map<VarDecl*, LoopBound*> conditionMap;
118 };
119 
120 // Implementation of the ASTConsumer interface for reading an AST produced
121 // by the Clang parser.
122 class MyASTConsumer : public ASTConsumer {
123 public:
124   MyASTConsumer(Rewriter &R) : Visitor(R) {}
125 
126   // Override the method that gets called for each parsed top-level
127   // declaration.
128   bool HandleTopLevelDecl(DeclGroupRef DR) override {
129     for (DeclGroupRef::iterator b = DR.begin(), e = DR.end(); b != e; ++b) {
130       // Traverse the declaration using our AST visitor.
131       Visitor.TraverseDecl(*b);
132       (*b)->dump();
133     }
134     std::map<VarDecl*, LoopBound*> conditionMap = Visitor.getCondMap();
135     if(conditionMap.size()>0){
136       auto iter = conditionMap.begin();
137       LoopBound *lpFirst = iter->second;
138       VarDecl* varFirst = iter->first;
139       llvm::errs()<<varFirst->getDeclName().getAsString()<<" ["<<lpFirst->initVal<<" "
140                   <<lpFirst->maxVal <<" "<<lpFirst->incVal<<"]\n";
141     }
142     else{
143       llvm::errs()<<"conditionMap.size()==0\n";
144     }
145     return true;
146   }
147 
148 private:
149   MyASTVisitor Visitor;
150 };
151 
152 // For each source file provided to the tool, a new FrontendAction is created.
153 class MyFrontendAction : public ASTFrontendAction {
154 public:
155   MyFrontendAction() {}
156   void EndSourceFileAction() override {
157     SourceManager &SM = TheRewriter.getSourceMgr();
158     llvm::errs() << "** EndSourceFileAction for: "
159                  << SM.getFileEntryForID(SM.getMainFileID())->getName() << "\n";
160 
161     // Now emit the rewritten buffer.
162     TheRewriter.getEditBuffer(SM.getMainFileID()).write(llvm::outs());
163   }
164 
165   std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
166                                                  StringRef file) override {
167     llvm::errs() << "** Creating AST consumer for: " << file << "\n";
168     TheRewriter.setSourceMgr(CI.getSourceManager(), CI.getLangOpts());
169     return std::make_unique<MyASTConsumer>(TheRewriter);
170   }
171 
172 private:
173   Rewriter TheRewriter;
174 };
175 
176 int main(int argc, const char **argv) {
177   llvm::Expected<CommonOptionsParser> op=CommonOptionsParser::create(argc, argv, ToolingSampleCategory);
178   
179   ClangTool Tool(op.get().getCompilations(), op.get().getSourcePathList());
180 
181   // ClangTool::run accepts a FrontendActionFactory, which is then used to
182   // create new objects implementing the FrontendAction interface. Here we use
183   // the helper newFrontendActionFactory to create a default factory that will
184   // return a new MyFrontendAction object every time.
185   // To further customize this, we could create our own factory class.
186   return Tool.run(newFrontendActionFactory<MyFrontendAction>().get());
187 }

结果展示如下:

 

posted @ 2021-03-12 17:55  转换无极限  阅读(671)  评论(0编辑  收藏  举报