Last active
June 11, 2020 08:55
-
-
Save mmaxs/6f6ffd3864d57a9bc8512db9f824a948 to your computer and use it in GitHub Desktop.
the Visitor pattern
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// g++ -std=c++1z -Wall -Wpedantic -pedantic-errors -O2 -D__USE_MINGW_ANSI_STDIO vis-ha.cpp -o vis-ha | |
#include <cstdio> | |
#include <typeinfo> | |
#include <vector> | |
#include <utility> | |
class Pass; | |
// the base class for units | |
class Unit | |
{ | |
public: | |
virtual ~Unit() = default; | |
virtual void accept(const Pass&) = 0; | |
}; | |
class ModuleUnit; | |
class FunctionUnit; | |
class LoopUnit; | |
// the base class for passes | |
class Pass | |
{ | |
public: | |
virtual ~Pass() = default; | |
void visit(Unit &u) const { u.accept(*this); }; | |
// by default a pass does nothing with a unit | |
virtual void visit(ModuleUnit&) const {}; | |
virtual void visit(FunctionUnit&) const {}; | |
virtual void visit(LoopUnit&) const {}; | |
}; | |
// concrete unit classes: | |
class ModuleUnit : public Unit | |
{ | |
void accept(const Pass &p) override { p.visit(*this); } | |
}; | |
class FunctionUnit : public Unit | |
{ | |
void accept(const Pass &p) override { p.visit(*this); } | |
}; | |
class LoopUnit : public Unit | |
{ | |
void accept(const Pass &p) override { p.visit(*this); } | |
}; | |
// concrete pass classes: | |
// (a concrete pass overrides only those functions that relevant to its possible targets) | |
#define DUMMY_PROCESSING(_u_) printf("\t%s, %p\n", __PRETTY_FUNCTION__, (void*)&_u_) | |
class ConstPropagationPass : public Pass | |
{ | |
void visit(ModuleUnit &u) const override { DUMMY_PROCESSING(u); }; | |
void visit(FunctionUnit &u) const override { DUMMY_PROCESSING(u); }; | |
}; | |
class FunctionInliningPass : public Pass | |
{ | |
void visit(ModuleUnit &u) const override { DUMMY_PROCESSING(u); }; | |
void visit(FunctionUnit &u) const override { DUMMY_PROCESSING(u); }; | |
}; | |
class LoopFusionPass : public Pass | |
{ | |
void visit(LoopUnit &u) const override { DUMMY_PROCESSING(u); }; | |
}; | |
class LoopUnrollingPass : public Pass | |
{ | |
void visit(LoopUnit &u) const override { DUMMY_PROCESSING(u); }; | |
}; | |
class SanityCheckPass : public Pass | |
{ | |
void visit(ModuleUnit &u) const override { DUMMY_PROCESSING(u); }; | |
void visit(FunctionUnit &u) const override { DUMMY_PROCESSING(u); }; | |
void visit(LoopUnit &u) const override { DUMMY_PROCESSING(u); }; | |
}; | |
int main() | |
{ | |
// example: Cartesian product of two independently arranged vectors | |
std::vector< Unit* > unit_sequence = { | |
new ModuleUnit(), | |
new FunctionUnit(), | |
new LoopUnit(), | |
new LoopUnit(), | |
new FunctionUnit(), | |
new ModuleUnit() | |
}; | |
std::vector< Pass* > pass_stages = { | |
new SanityCheckPass(), | |
new ConstPropagationPass(), | |
new FunctionInliningPass(), | |
new LoopFusionPass(), | |
new LoopUnrollingPass(), | |
new SanityCheckPass() | |
}; | |
for (Unit *u : unit_sequence) | |
{ | |
printf("\n%s: %p\n", typeid(*u).name(), (void*)u); | |
for (Pass *p : pass_stages) | |
{ | |
printf("| %s\n", typeid(*p).name()); | |
p->visit(*u); | |
}; | |
}; | |
// example: more precisely arranged pipeline | |
using stage_t = std::pair< Unit*, Pass* >; | |
std::vector< stage_t > stages = { | |
stage_t{ new ModuleUnit(), new SanityCheckPass() }, | |
stage_t{ new ModuleUnit(), new ConstPropagationPass() }, | |
stage_t{ new FunctionUnit(), new FunctionInliningPass() }, | |
stage_t{ new FunctionUnit(), new SanityCheckPass() }, | |
stage_t{ new LoopUnit(), new LoopFusionPass() }, | |
stage_t{ new LoopUnit(), new LoopUnrollingPass() }, | |
stage_t{ new ModuleUnit(), new SanityCheckPass() }, | |
}; | |
printf("\nStage pipeline:\n"); | |
for (auto [u, p] : stages) | |
p->visit(*u); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Output: