performing source to source t ransformations with clang
play

Performing Source-to-Source T ransformations with Clang European - PowerPoint PPT Presentation

Center for Information Services and High Performance Computing (ZIH) Performing Source-to-Source T ransformations with Clang European LLVM Conference Paris, 2013 Zellescher Weg 12 Willers-Bau A 105 T el. +49 351 - 463 - 32442 Olaf Krzikalla


  1. Center for Information Services and High Performance Computing (ZIH) Performing Source-to-Source T ransformations with Clang European LLVM Conference Paris, 2013 Zellescher Weg 12 Willers-Bau A 105 T el. +49 351 - 463 - 32442 Olaf Krzikalla (olaf.krzikalla@tu-dresden.de)

  2. Agenda today 1. Some disclaimers (sort of) and some background: source-to-source vectorization – 2. Our current solution (working with clang 3.2) traversing the AST – editing the AST – 3. Best (or worth discussing) practices merging ASTs – using TreeTransform – cloning – 4. Future Directions Olaf Krzikalla 2

  3. Disclaimers ● no strategical elaboration of the source-to-source approach ● instead a lot of code ● we transfom clang's AST! ● actually not allowed ● source-to-source transformation  source-to-source compilation ● all blue highlighted code works ● open source and downloadable at http://scout.zih.tu-dresden.de/ ● project started in 2009  meanwhile better approaches for some tasks Olaf Krzikalla 3

  4. The big picture: Scout vectorized loop residual loop Olaf Krzikalla 4

  5. The medium picture: Components clang Scout Lexer ASTProcessing AST editing LLVM Parser AST cloning AST traversal AST pragma parsing Rewrite Static Vectorizing Analyzer Olaf Krzikalla 5

  6. The Detailed Picture: Code 2. Our current solution (working with clang 3.2) AST creation and AST editing Olaf Krzikalla 6

  7. AST Creation ● central class StmtEditor ● interface for the creation of variables, expressions and statements class StmtEditor { class StmtEditor { public: public: ASTContext& Ctx(); ASTContext& Ctx(); BinaryOperator* Assign_(Expr* lhs, Expr* rhs); BinaryOperator* Assign_(Expr* lhs, Expr* rhs); BinaryOperator* Add_(Expr* lhs, Expr* rhs); BinaryOperator* Add_(Expr* lhs, Expr* rhs); DeclRefExpr* DeclRef_(ValueDecl* VD); DeclRefExpr* DeclRef_(ValueDecl* VD); Expr* Int_(int value); // simple 32 bit integer Expr* Int_(int value); // simple 32 bit integer Expr* Float_(const llvm::APFloat& value, QualType t); Expr* Float_(const llvm::APFloat& value, QualType t); VarDecl* VarDecl_(QualType tmpType, Expr* init = 0, VarDecl* VarDecl_(QualType tmpType, Expr* init = 0, const tOriginalNameInfo& originalVar = tOriginalNameInfo()); const tOriginalNameInfo& originalVar = tOriginalNameInfo()); // aso. // aso. }; }; clangAddons/include/clang/ASTProcessing/StmtEditor.h Olaf Krzikalla 7

  8. AST Creation ● best way: access the member functions of StmtEditor by derivation: class LoopBlocker : StmtEditor { class LoopBlocker : StmtEditor { void block(ForStmt* Node) { void block(ForStmt* Node) { DeclStmt *temp = TmpVar_(Ctx().IntTy), *temp_bound = TmpVar_(Ctx().IntTy), DeclStmt *temp = TmpVar_(Ctx().IntTy), *temp_bound = TmpVar_(Ctx().IntTy), *i_bound = TmpVar_(Ctx().IntTy); *i_bound = TmpVar_(Ctx().IntTy); Stmt* innerBody[3] = { Stmt* innerBody[3] = { // temp_bound = i_bound - loopVar; // temp_bound = i_bound - loopVar; Assign_(DeclRef_(temp_bound), Sub_(DeclRef_(i_bound), DeclRef_(loopVar))), Assign_(DeclRef_(temp_bound), Sub_(DeclRef_(i_bound), DeclRef_(loopVar))), // temp_bound = temp_bound < tileSize ? temp_bound : tileSize; // temp_bound = temp_bound < tileSize ? temp_bound : tileSize; Assign_(DeclRef_(temp_bound), Conditional_(LT_(DeclRef_(temp_bound), Assign_(DeclRef_(temp_bound), Conditional_(LT_(DeclRef_(temp_bound), Int_(tileSize)), DeclRef_(temp_bound), Int_(tileSize))), Int_(tileSize)), DeclRef_(temp_bound), Int_(tileSize))), // for (temp=0; temp < temp_bound; ++temp) ... // for (temp=0; temp < temp_bound; ++temp) ... For_(Assign_(DeclRef_(temp),Int_(0)), LT_(DeclRef_(temp),DeclRef_(temp_bound)), For_(Assign_(DeclRef_(temp),Int_(0)), LT_(DeclRef_(temp),DeclRef_(temp_bound)), PreInc_(DeclRef_(temp)), Node->getBody()) PreInc_(DeclRef_(temp)), Node->getBody()) }; }; Node->setBody(Compound_(innerBody)); Node->setBody(Compound_(innerBody)); } } }; }; clangAddons/include/clang/ASTProcessing/LoopBlocking.cpp Olaf Krzikalla 8

  9. AST Creation ● transformation performed: for (...; i < z; ++i) for (...; i < z; ++i) for-body for-body for (...; i < z; ++i) { for (...; i < z; ++i) { temp_bound = i_bound - i; temp_bound = i_bound - i; temp_bound = temp_bound < tileSize ? temp_bound : tileSize; temp_bound = temp_bound < tileSize ? temp_bound : tileSize; for ( temp = 0; temp < temp_bound; ++temp) for ( temp = 0; temp < temp_bound; ++temp) for-Body; for-Body; } } ● things missing: ● implementation of StmtEditor ● replace loop index i with temp  mutating an AST enters the true minefield Olaf Krzikalla 9

  10. AST Creation ● creating AST nodes: ● no problem at statement level class StmtEditor { class StmtEditor { static const SourceLocation nopos; // helper static const SourceLocation nopos; // helper IfStmt* If_(Expr* cond, Stmt* then, Stmt* else) { IfStmt* If_(Expr* cond, Stmt* then, Stmt* else) { return new (Ctx()) IfStmt(Ctx(), nopos, 0, cond, then, nopos, else)); return new (Ctx()) IfStmt(Ctx(), nopos, 0, cond, then, nopos, else)); } } }; }; Olaf Krzikalla 10

  11. AST Creation ● creating AST nodes: ● implementation of the most possible naive approach at expression level: BinaryOperator* BinOp_(Expr* lhs, Expr* rhs, BinaryOperator::Opcode opc) { BinaryOperator* BinOp_(Expr* lhs, Expr* rhs, BinaryOperator::Opcode opc) { if (opc >= BO_MulAssign && opc <= BO_OrAssign) if (opc >= BO_MulAssign && opc <= BO_OrAssign) { { return new(Ctx())CompoundAssignOperator(lhs, rhs, opc, lhs->getType(), return new(Ctx())CompoundAssignOperator(lhs, rhs, opc, lhs->getType(), VK_RValue, OK_Ordinary, lhs->getType(), lhs->getType(), VK_RValue, OK_Ordinary, lhs->getType(), lhs->getType(), nopos, false)); nopos, false)); } } QualType resultType = (BinaryOperator::isComparisonOp(opc) || QualType resultType = (BinaryOperator::isComparisonOp(opc) || BinaryOperator::isLogicalOp(opc)) ? Ctx().BoolTy : lhs->getType(); BinaryOperator::isLogicalOp(opc)) ? Ctx().BoolTy : lhs->getType(); return new(Ctx())BinaryOperator(lhs, rhs, opc, resultType, return new(Ctx())BinaryOperator(lhs, rhs, opc, resultType, VK_RValue, OK_Ordinary, nopos, false)); VK_RValue, OK_Ordinary, nopos, false)); } } ● fails for various reasons  don't try this at home ● requires redirection to Sema Olaf Krzikalla 11

  12. AST Editing ● editing AST nodes ● replacing statements in compound statements is no problem ● general purpose replacement ● requires parent map internally maintained by StmtEditor ● and once again: works smoothly at statement level only, but replacing sub-expressions is dangerous class StmtEditor { class StmtEditor { // all staments of S are replaced by Stmts // all staments of S are replaced by Stmts void replaceStmts(CompoundStmt* S, Stmt **Stmts, unsigned NumStmts); void replaceStmts(CompoundStmt* S, Stmt **Stmts, unsigned NumStmts); // replaces from in the parent with newStmt, returns newStmt // replaces from in the parent with newStmt, returns newStmt Stmt* replaceStatement(Stmt* from, Stmt* newStmt); Stmt* replaceStatement(Stmt* from, Stmt* newStmt); }; }; However: all this code shown here is in production  clang can do this kind of transformations! Olaf Krzikalla 12

  13. AST T raversing ● template<typename Derived> class RecursiveASTVisitor; ● processing of different AST classes in one traversal ● uses CRTP  requires sub-classing Olaf Krzikalla 13

  14. AST T raversing ● template<class StmtTy> class stmt_iterator ● forward iterator for a particular AST class given by StmtTy ● implementation based on llvm::df_iterator<Stmt*> ● usable in floating code: //... //... for (stmt_iterator<ForStmt> i = stmt_ibegin(root), for (stmt_iterator<ForStmt> i = stmt_ibegin(root), e = stmt_iend(root); i != e; ++i) e = stmt_iend(root); i != e; ++i) { { ForStmt* node = *i; ForStmt* node = *i; //... //... } } //... //... clangAddons/include/clang/ASTProcessing/StmtTraversal.h Olaf Krzikalla 14

  15. AST T raversing ● template<class StmtTy> class stmt_iterator ● processes only one AST class per traversal ● doesn't handle type decls Olaf Krzikalla 15

  16. The Detailed Picture: More Code 3. Best (or worth discussing) practices questions raised on cfe-dev and our solutions Olaf Krzikalla 16

  17. Cloning ● cloning parts of an AST is important for many transformation tasks ● e.g. function inlining, loop unrolling aso. ● just search for "clone" on cfe-dev class StmtClone : public StmtVisitor<StmtClone, Stmt*> class StmtClone : public StmtVisitor<StmtClone, Stmt*> { { public: public: template<class StmtTy> template<class StmtTy> StmtTy* Clone(StmtTy* S) { StmtTy* Clone(StmtTy* S) { return static_cast<StmtTy*>(Visit(S)); return static_cast<StmtTy*>(Visit(S)); } } Stmt* StmtClone::VisitStmt(Stmt*) { Stmt* StmtClone::VisitStmt(Stmt*) { assert(0 && "clone incomplete"); assert(0 && "clone incomplete"); return NULL; return NULL; } } // visitor functions // visitor functions }; }; clangAddons/include/clang/ASTProcessing/StmtClone.h Olaf Krzikalla 17

Download Presentation
Download Policy: The content available on the website is offered to you 'AS IS' for your personal information and use only. It cannot be commercialized, licensed, or distributed on other websites without prior consent from the author. To download a presentation, simply click this link. If you encounter any difficulties during the download process, it's possible that the publisher has removed the file from their server.

Recommend


More recommend