root/trunk/blade/PostfixX86.d

Revision 187, 8.5 kB (checked in by Don Clugston, 3 months ago)

Added prod(). Use .ptr to get raw data, so it works with Bill Baxter's ArrayView?.

  • Property svn:mime-type set to text/x-dsrc
  • Property svn:eol-style set to native
Line 
1 //  Written in the D programming language 1.0
2 /**
3 * BLADE  -- Basic Linear Algebra D Expressions
4 *
5 * Given an expression string of the form "A+(B*C)*D", and a ranklist string
6 * the entries of which correspond to A, B, C, ...,
7 * values being'0'=scalar, '1'=vector, '2'=matrix.
8 * This string is converted to postfix, applying simple X86-specific optimisations.
9 *
10 * The elements of the postfix string may be:
11 *  ABC          a variable or constant, to be pushed onto the stack
12 *  0            the literal zero (used to initialize a dot product, for example)
13 *  *+-/         ST(0)*ST(1), ST(0)+ST(1), ST(0)-ST(1), ST(0)/ST(1) and pop stack
14 *  _            ST(1)-ST(0) and pop stack
15 *  =            store ST(0) and pop stack
16 *  ,            duplicate stack top (so ,* means ST=ST*ST, ,+ means ST*=2)
17 *  a            abs
18 *  n            unary negation
19 *  m            ST(0) = max(ST(0), ST(1))
20 *  u            ST(1) = min(ST(0), ST(1))
21 *  q            sqrt
22 *  1            the literal one (used to initialize a product, for example)
23 *
24 *  NOT YET IMPLEMENTED:
25 *  scel         sin, cos, exp, log
26 *
27 * Unassigned lower case letters: bdfghijkoprtvwxyz
28 */
29
30 module blade.PostfixX86;
31 private import blade.BladeVisitor;
32
33 public:
34 /// Converts an infix string into postfix.
35 /// Apply x87-specific optimisations during the conversion.
36 char [] makePostfixForX87(char [] operations, char [][] typelist, char[] ranklist)
37 {
38     return beginVisit(X87PostfixVisitor(typelist, ranklist), operations);
39 }
40
41 /// Converts an infix string into postfix.
42 /// Apply SSE/SSE2-specific optimisations during the conversion.
43 char [] makePostfixForSSE(char [] operations, char [] ranklist)
44 {
45     return beginVisit(SSEPostfixVisitor(ranklist), operations);
46 }
47
48 private:
49 // ------------------------------------------------
50 //   Convert infix string to postfix
51 // ------------------------------------------------
52
53 struct X87PostfixVisitor {
54     alias typeof(*this) This;
55     alias char [] ReturnType;
56     char [][] typelist;
57     char [] ranklist;
58 static:
59     ReturnType onVisitSymbol(This this_, char [] sym) {
60         return sym;
61     }
62     ReturnType onVisitFunction(This this_, char [] func, char [][] args) {
63         char [] left = doVisit(this_,args[0]);
64         switch(func) {
65         case "dot":
66             char [] right = doVisit(this_, args[1]);
67             if (left==right) return "0" ~ left ~ ",*+";
68             return "0" ~ left ~ right ~ "*+";
69         case "prod":
70             return "1" ~ left ~ "*";
71         case "sum":  return "0" ~ left ~ "+";
72 //        case "max":  return left ~ "m";
73 //        case "min":  return left ~ "u";
74         case "abs":  return left ~ "a";
75         case "sqrt": return left ~ "q";
76         default:     assert(0, "BLADE ICE: Unsupported");
77         }
78     }
79     ReturnType onVisitPrefix(This this_, char [] op, char [] expr) {
80         if (op=="-") return doVisit(this_, expr) ~ "n"; // unary minus
81         assert(0, "BLADE ICE: Unsupported");
82     }
83     ReturnType onVisitPostfix(This this_, char [] op, char [] expr) {
84         assert(0, "BLADE ICE: Unsupported");
85     }
86     ReturnType onVisitIndex(This this_, char [] base, char [][2][] slices) {
87         assert(0, "BLADE ICE: Unsupported");
88     }
89     ReturnType onVisitBinaryOp(This this_, char [] op, char [] left, char [] right) {
90         char [] first = doVisit(this_, left);
91         char [] second;
92         if (op.length==2 && op[1]=='=') { // +=, -=, *=, /=
93             // Convert "A+=B" into "A=A+B"
94             second = beginVisit(this_, left ~ op[0] ~ right);
95             return second ~ first ~ "=";
96         }
97         second = doVisit(this_, right);
98         if (op=="=") {
99             return second ~ first ~ "=";
100         }
101         if (second == first) return first ~ "," ~ op;
102
103         // x87 OPTIMISATION #1
104         // On x87, fmul has a long latency, so we want to delay using the
105         // result of a multiply. Since + is commutative, we can achieve this
106         // by calculating the value with the multiply, before the other one.
107         // We can also do the same thing with -, but we'll need to use fsubr
108         // instead of fsub. We use _ to mean reversed subtraction.
109         if (op=="+" || op=="-") {
110             char [] oprvs = (op=="-")? "_" : op;
111             if (second[second.length-1]=='*'&& first[first.length-1]!='*') {
112                return second ~ first ~ oprvs;
113             }
114             // x87 OPTIMISATION #2
115             // When an operation is performed between a real[] and a non-real[],
116             // we want to have the real[] being the one which is loaded first.
117             if (second.length==1 && this_.typelist[second[0]-'A']=="real" && this_.ranklist[second[0]-'A']=='1') {
118                    return second ~ first ~ oprvs;
119             }
120         }
121         return first ~ second ~ op;
122     }
123 }
124
125
126 unittest {
127 assert(makePostfixForX87("A=B", ["double", "double"],"11")=="BA=");
128 assert(makePostfixForX87("(B*C)+A", ["double", "float", "float"],"111")=="BC*A+");
129 assert(makePostfixForX87("(B*C)+A", ["real", "float", "float"],"111")=="ABC*+");
130 assert(makePostfixForX87("A-(B*C)", ["double", "float", "float"],"100")=="BC*A_");
131 assert(makePostfixForX87("(B*C)-A", ["float", "float", "float"],"100")=="BC*A-");
132 assert(makePostfixForX87("(B*C)-A", ["real", "float", "float"],"100")=="ABC*_");
133 assert(makePostfixForX87("C+=((B*C)-A)", ["real", "float", "float"],"101")=="CABC*_+C=");
134 assert(makePostfixForX87("C-=((B*C)-A)", ["real", "float", "float"],"101")=="CABC*_-C=");
135 assert(makePostfixForX87("C-=(B*A)", ["real", "float", "float"],"101") =="BA*C_C=");
136 assert(makePostfixForX87("C-=(B*A)", ["real", "float", "real"],"101") =="BA*C_C=");
137 assert(makePostfixForX87("((A*B)+(C*D))+(E*F)", ["int", "int", "int"],"000")=="EF*AB*CD*++");
138 }
139
140 /// Converts an infix string into postfix.
141 /// Apply SSE/SSE2-specific optimisations during the conversion.
142 struct SSEPostfixVisitor {
143     alias typeof(*this) This;
144     alias char [] ReturnType;
145     char [] ranklist;
146 static:
147     ReturnType onVisitSymbol(This this_, char [] sym) {
148         return sym;
149     }
150     ReturnType onVisitFunction(This this_, char [] func, char [][] args) {
151         switch(func) {
152         case "dot":
153             char [] left = doVisit(this_,args[0]);
154             char [] right = doVisit(this_, args[1]);
155             if (left==right) return "0" ~ left ~ ",*+";
156             return "0" ~ left ~ right ~ "*+";
157         case "sum":
158             return "0" ~ doVisit(this_, args[0]) ~ "+";
159         case "abs": return doVisit(this_,args[0]) ~ "a";
160         case "sqrt": return doVisit(this_,args[0]) ~ "q";
161         case "prod":
162             return "1" ~ doVisit(this_, args[0]) ~ "*";
163         default:   assert(0, "BLADE ICE: Unsupported");
164         }
165     }
166     ReturnType onVisitPrefix(This this_, char [] op, char [] expr) {
167         if (op=="-") return doVisit(this_, expr) ~ "n"; // unary minus
168         assert(0, "BLADE ICE: Unsupported");
169     }
170     ReturnType onVisitPostfix(This this_, char [] op, char [] expr) {
171         assert(0, "BLADE ICE: Unsupported");
172     }
173     ReturnType onVisitIndex(This this_, char [] base, char [][2][] slices) {
174         assert(0, "BLADE ICE: Unsupported");
175     }
176     ReturnType onVisitBinaryOp(This this_, char [] op, char [] left, char [] right) {
177         char [] first = doVisit(this_, left);
178         char [] second;
179         if (op.length==2 && op[1]=='=') { // +=, -=, *=, /=
180             // Convert "A+=B" into "A=A+B"
181             second = beginVisit(this_, left ~ op[0] ~ right);
182             return second ~ first ~ "=";
183         }
184         second = doVisit(this_, right);
185         if (op=="=") {
186             return second ~ first ~ "=";
187         }
188         if (second == first) return first ~ "," ~ op;
189
190         // SSE OPTIMISATION #1
191         // Multiplies have a long latency, so we want to delay using the
192         // result of a multiply. Since + is commutative, we can achieve this
193         // by calculating the value with the multiply, before the other one.
194         if (op=="+") {
195             if (second[second.length-1]=='*'&& first[first.length-1]!='*') {
196                return second ~ first ~ op;
197             }
198         }
199         if (op=="*") {
200             // SSE OPTIMISATION #2
201             // When an operation is performed between a vector and a scalar
202             // we want to have the vector being the one which is loaded first.
203             if (first.length==1 && this_.ranklist[first[0]-'A']=='0') {
204                    return second ~ first ~ op;
205             }
206         }
207         return first ~ second ~ op;
208     }
209 }
210
211 unittest {
212 assert(makePostfixForSSE("A=B", "11")=="BA=");
213 assert(makePostfixForSSE("(A*B)+C", "101")=="AB*C+");
214 assert(makePostfixForSSE("A=(B*C)", "110")=="BC*A=");
215 assert(makePostfixForSSE("prod((A*B))", "10")=="1AB**");
216 }
Note: See TracBrowser for help on using the browser.