220 likes | 236 Views
A detailed review of PETE code exploring Expression Templates, Syntax Trees, and Encoding with examples. Future work and conclusions discussed.
E N D
PETE code Review Xingmin Luo 6/12/2003
Outline • Overview • Motivation • Expression Templates • Syntax tree • Encoding syntax tree with Expression Templates • Trace results of 3 kinds of expressions • b = 1; c = 2; d = 3; • b = c; • a = b + c + d; • Future Work and Conclusions
Motivation • Discover how and why PETE works? • How to modify PETE code to support Psi calculus; for example, where (which files) we should change to support reverse operation in Convolution.
Expression Templates • const Expression <BinaryNode<OpAdd, Reference<Array>, Reference<Array> > > &expr1 = b + c; • const Expression <BinaryNode<OpAdd, Reference<Array>, BinaryNode<OpMultiply, Scalar<int>, Reference<Array> > > > &expr2 = b + 3 * c; • const Expression<BinaryNode<OpAdd, Reference<Array>, BinaryNode<OpMultiply, Reference<Array>, Reference<Array> > > > &expr3 = b + c * d;
Syntax trees + + + b c b * b * 3 c c d (1) (2) (3) b + c b + 3 * c b + c * d
Encoding syntax trees with expression Templates (ET) - 1 + b c (1) • const Expression <BinaryNode<OpAdd, Reference<Array>, Reference<Array> > > &expr1 = b + c;
Encoding syntax trees with expression Templates (ET) - 2 + b * 3 C (2) b + 3 * c const Expression <BinaryNode<OpAdd, Reference<Array>, BinaryNode<OpMultiply, Scalar<int>, Reference<Array> > > > &expr2 = b + 3 * c;
Encoding syntax trees with expression Templates (ET) - 3 + b * c d (3) b + c * d • const Expression<BinaryNode<OpAdd, Reference<Array>, BinaryNode<OpMultiply, Reference<Array>, Reference<Array> > > > &expr3 = b + c * d;
Files • PETE ( pete.h ) includes the following files • #include "PETE/Scalar.h" • #include "PETE/TypeComputations.h" • #include "PETE/TreeNodes.h" • #include "PETE/OperatorTags.h" • #include "PETE/Functors.h" • #include "PETE/Combiners.h" • #include "PETE/ForEach.h" • #include "PETE/CreateLeaf.h“ • Our implementations • Array.cpp • Array.h
Variables declaration and definition • Array.cpp vector <int> shape; Array <int> a(shape), b(shape), c(shape), d(shape); • Array.h Array(const vector <int> shape) { long i, sum; sum=1; for (i=0; i<shape.size(); i++) { sum = sum * shape[i]; (this->shape).push_back(shape[i]); } this->size = sum; this->d = my_malloc(sum*sizeof(T)); } private: T * d; vector <int> shape; long size;
Trace result of b=1;c=2;d=3; • Array.cpp b=1;c=2;d=3; • Array.h Array &operator=(T value) { for(long i=0; i<this->size; i++) d[i] = value; return *this; } private: T * d; vector <int> shape; long size;
Trace result of b=c; • Array.cpp b=c; • Array.h Array &operator=(const Array &v) { for(long i=0; i<this->size; i++) d[i] = v.d[i]; return *this; } private: T * d; vector <int> shape; long size;
Trace result of a = b + c + d; (1) • Array.cpp a = b + c + d; • Array.h template<class RHS> Array &operator=(const Expression<RHS> &rhs) { for(long i=0; i<this->size; i++) d[i] = forEach(rhs, EvalLeaf1(i), OpCombine()); return *this; } private: T * d; vector <int> shape; long size;
Trace result of a = b + c + d; (2) • ForEach.h CLASS NAME ForEach<Expr, FTag, CTag> forEach(Expr& e, FTag& f, CTag& c) //call this function //same as ForEach::apply // Expr is the type of the expression tree. // FTag is the type of the leaf tag.(specifies the operation being applied) // CTag is the type of the combiner tag. // ForEach<Expr,FTag,CTag>::apply(Expr &e,FTag& f,CTag& c) is a function // that traverses the expression tree defined by e, applies the functor f // to each leaf and combines the results together using the combiner c. // The type of object returned is given by: // typename ForEach<Expr,FTag,CTag>::Type_t // the function forEach(Expr& e,FTag& f,CTag& c) duplicates the action // of ForEach::apply
Trace result of a = b + c + d; (3) • ForEach.h template<class Expr, class FTag, class CTag> inline typename ForEach<Expr,FTag,CTag>::Type_t forEach(const Expr &e, const FTag &f, const CTag &c) { return ForEach<Expr, FTag, CTag>::apply(e, f, c); } template<class Expr, class FTag, class CTag> struct ForEach { typedef typename LeafFunctor<Expr, FTag>::Type_t Type_t; inline static Type_t apply(const Expr &expr, const FTag &f, const CTag &) { return LeafFunctor<Expr, FTag>::apply(expr, f); } };
Trace result of a = b + c + d; (4) • CreateLeaf.h (defines expression tree) template<class T> class Expression { public: // Type of the expression. typedef T Expression_t; // Construct from an expression. Expression(const T& expr) : expr_m(expr) { } // Accessor that returns the expression. const Expression_t& expression() const { return expr_m; } private: // Store the expression by value since it is a temporary produced // by operator functions. T expr_m; };
Trace result of a = b + c + d; (5) • Functors.h (functors define here, however....) // LeafFunctors are used by ForEach to apply operations to the leaves of the // expression tree. Typical functors are evaluators, counters, etc. struct EvalLeaf1 { int i1_m; inline EvalLeaf1(int i1) : i1_m(i1) { } inline int val1() const { return i1_m; } }; • Array.h specializes EvalLeaf1 function template<class T> struct LeafFunctor<Array <T>, EvalLeaf1> { typedef T Type_t; static Type_t apply(const Array <T> &a, const EvalLeaf1 &f) { return a[f.val1()]; } };
Trace result of a = b + c + d; (6) • Combiners.h (defines combiner tag) struct OpCombine { PETE_EMPTY_CONSTRUCTORS(OpCombine) }; template<class A,class Op> struct Combine1<A, Op, OpCombine> { typedef typename UnaryReturn<A, Op>::Type_t Type_t; inline static Type_t combine(A a, Op op, OpCombine) { return op(a); } }; template<class A,class B,class Op> struct Combine2<A, B, Op, OpCombine> { typedef typename BinaryReturn<A, B, Op>::Type_t Type_t; inline static Type_t combine(A a, B b, Op op, OpCombine) { return op(a, b); } }; template<class A,class B,class C,class Op> struct Combine3<A, B, C, Op, OpCombine> { typedef typename TrinaryReturn<A, B, C, Op>::Type_t Type_t; inline static Type_t combine(A a, B b, C c, Op op, OpCombine) { return op(a, b, c); } };
user defined Expression <> tree examples • Array.cpp Array <int> d; const Expression<BinaryNode<OpAdd, Reference<Array>, Reference<Array> > > &expr1 = b + c; d = expr1; cout << d << endl; int num = forEach(expr1, CountLeaf(), SumCombine()); cout << num << endl; const Expression<BinaryNode<OpAdd, Reference<Array>, BinaryNode<OpMultiply, Scalar<int>, Reference<Array> > > > &expr2 = b + 3 * c; num = forEach(expr2, CountLeaf(), SumCombine()); cout << num << endl; const Expression<BinaryNode<OpAdd, Reference<Array>, BinaryNode<OpMultiply, Reference<Array>, Reference<Array> > > > &expr3 = b + c * d; num = forEach(expr3, CountLeaf(), SumCombine()); cout << num << endl;
Future Work • Modify PETE code to support Psi operations. • Extend our current implementation of the Psi calculus • Build high-level Psi calculus tools
Conclusions • PETE’s Expression templates provide the ability to perform compiler preprocessor-style optimizations (expression tree manipulation) • The C++ template mechanism can be applied to a wide variety of problems (e.g. tree traversal ala PETE, graph traversal, list traversal) to gain run-time speedup at the expense of compile time/space
Acknowlegements • Prof. Lenore Mullin • Prof. Dan Rosenkrantz • Prof. Harry Hunt