Changeset 167
- Timestamp:
- 01/03/08 09:23:43 (8 months ago)
- Files:
-
- trunk/blade/Blade.d (modified) (15 diffs)
- trunk/blade/BladeDemo.d (modified) (2 diffs)
- trunk/blade/BladeRank.d (modified) (2 diffs)
- trunk/blade/BladeSimplify.d (modified) (11 diffs)
- trunk/blade/BladeVisitor.d (modified) (1 diff)
- trunk/blade/CodegenX86.d (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/blade/Blade.d
r165 r167 13 13 * 14 14 * FEATURES: 15 * - Supports any mix of vector addition, subtraction, dot product, and multiplication16 * by a scalar.15 * - Supports any mix of vector addition, subtraction, dot product, slicing, and 16 * multiplication by a scalar. 17 17 * - Generates either x87 asm code, SSE or SSE2 asm code or pure D, depending on 18 18 * the complexity of the expression, and the availability of inline asm. … … 25 25 * FUTURE DIRECTIONS (in order of expected implementation): 26 26 * - Dot product (which was present in BLADE 0.2). 27 * - The x87 code generation targets early Pentiums, which are now irrelevant. 28 * - Support for strided vectors. 29 * - Matrix support. 27 * - Dense matrix support. 28 * - Triangular, banded, symmetric, and sparse matrix support 30 29 * 31 30 * THEORY: … … 40 39 * 0.2 - Support for a wider variety of expressions. Dot product, imaginary numbers, etc. 41 40 * 0.3 - Based on string mixins. Most of the new features of 0.2 are gone, but SSE2 is added. 42 * 0.4 - Added D code generator. Nice error messages. Optimal parameter passing. 41 * 0.4 - Added D code generator. Nice error messages. Optimal parameter passing 42 * (passes pointers, not arrays). 43 * 0.5 - Expression simplification step. 43 44 */ 44 45 … … 47 48 public import blade.SyntaxTree : AbstractSyntaxTree, syntaxtreeof, AST, Symbol; 48 49 private import blade.BladeUtil : enquote, itoa; 49 private import blade.BladeRank : isStrided ;50 private import blade.BladeSimplify : simplifySyntaxTree, RevisedExpression ;50 private import blade.BladeRank : isStrided, exprRank; 51 private import blade.BladeSimplify : simplifySyntaxTree, RevisedExpression, remapCompounds; 51 52 private import blade.CodegenX86 : generateCodeForAsmX87, MAX_X87_VECTORS, 52 53 MAX_87_REALSCALARSPLUSTEMPORARIES, 53 54 generateCodeForSSE, MAX_SSE_VECTORS; 55 private import blade.BladeVisitor: expressionContainsAssignment; 54 56 55 57 private import blade.PostfixX86 : makePostfixForX87; 56 58 57 struct BladeStrided(T)58 {59 T * data; // Pointer to the first element60 }61 59 public: 62 60 … … 79 77 if (revised.errorMessage.length>0) return `static assert(0, "BLADE: ` ~ enquote(revised.errorMessage) ~ `");`; 80 78 VecExpressionType exprType = categorizeExpression(revised); 79 char [] result = generateAsserts(revised, (exprType == VecExpressionType.SSE2Expression || exprType == VecExpressionType.SSE1Expression)); 80 debug(BladeFrontEnd) { 81 result ~= "// Simplified: " ~ revised.expression ~ \n; 82 } 81 83 if (exprType == VecExpressionType.SSE2Expression || exprType == VecExpressionType.SSE1Expression) { 82 return invokeSSE((exprType == VecExpressionType.SSE2Expression), revised);84 return result ~ invokeSSE((exprType == VecExpressionType.SSE2Expression), revised)~ ";"; 83 85 } else if (exprType == VecExpressionType.X87Expression) { 84 return invokeX87(revised);86 return result ~ invokeX87(revised) ~ ";"; 85 87 } else { 86 return DCodeGenerator(revised);88 return result ~ DCodeGenerator(revised); 87 89 } 88 90 } 89 91 92 // For a compound of a different dimensionality (eg a dot product), we may need 93 // to calculate the result seperately. 94 char [] makeVectorCodeForDimensionalCompound(char [] expression, AbstractSyntaxTree tree) 95 { 96 // TODO: 97 return expression; 98 } 90 99 91 100 // These functions have the complete expression encoded in the template type. … … 139 148 SSE1 = false; 140 149 X87 = false; 150 } 151 int wholerank = exprRank(tree.expression, tree.rank); 152 153 if (wholerank==0 && expressionContainsAssignment(tree.expression)) { 154 return VecExpressionType.DExpression; // Scalar assignments always use inline D. 141 155 } 142 156 int numvectors = 0; … … 192 206 } 193 207 208 209 // This is mainly a workaround for compiler bug #1125. Ideally both 210 // pointer and stride would be stored together. 211 struct BladeStrided(T) 212 { 213 T * data; // Pointer to the first element 214 } 215 194 216 //------------------------------------------------------- 195 217 // Invoker functions … … 203 225 char [] invokeX87(RevisedExpression tree) 204 226 { 205 char [] result = assertAllVectorLengthsEqual(tree);227 char [] result = ""; 206 228 char [] stridelist=""; 207 229 char [] alltypes=""; … … 272 294 int firstVector = findVectorForLength(tree); 273 295 return result ~ getValueForSymbol(tree.mapping[firstVector], tree) ~ ".length" 274 ~ vals ~ stridelist ~ ");"; 296 ~ vals ~ stridelist ~ ")"; 297 } 298 299 char [] generateAsserts(RevisedExpression tree, bool checkAlignment) 300 { 301 char [] result = assertAllVectorLengthsEqual(tree); 302 if (checkAlignment) result ~= assertAllVectorsAlign128(tree); 303 return result; 275 304 } 276 305 277 306 /// Generate code which will call the SSE/SSE2 code generation function 278 307 char [] invokeSSE(bool SSE2, RevisedExpression tree) 279 { 280 char [] result = assertAllVectorLengthsEqual(tree); 281 result ~= assertAllVectorsAlign128(tree); 282 283 284 result ~= "SSEVECGEN!(" ~ (SSE2?"2":"1") ~ `,"` ~ enquote(tree.expression) ~ `"`; 308 { 309 char [] result = "SSEVECGEN!(" ~ (SSE2?"2":"1") ~ `,"` ~ enquote(tree.expression) ~ `"`; 285 310 // For SSE2, everything must be implicitly convertible to double. 286 311 char [] vals; … … 303 328 result ~= vals; 304 329 305 return result ~ ") ;";330 return result ~ ")"; 306 331 } 307 332 … … 399 424 if (comp[$-1]!=']') { // simple compound expression 400 425 foreach(d; comp) { 426 if (d=='{') assert(0, "BLADE ICE"); 401 427 if (d>='A' && d<='Z') v ~= tree.symbolTable[d-'A'].value; 402 428 else v ~= d; … … 468 494 } 469 495 496 497 char [] invokeNestedExpression(char [] expr, Symbol[] symbolTable) 498 { 499 char [] ranks; 500 for (int i=0; i<symbolTable.length; ++i) { 501 ranks ~= symbolTable[i].rank; 502 } 503 RevisedExpression revised = remapCompounds(expr, ranks, symbolTable); 504 505 VecExpressionType exprType = categorizeExpression(revised); 506 if (exprType == VecExpressionType.SSE2Expression || exprType == VecExpressionType.SSE1Expression) { 507 return invokeSSE((exprType == VecExpressionType.SSE2Expression), revised); 508 } else if (exprType == VecExpressionType.X87Expression) { 509 return invokeX87(revised); 510 } else { 511 assert(0, "BLADE ICE: Nested D expressions are not yet supported"); 512 return DCodeGenerator(revised); 513 } 514 } 515 470 516 char [] getValueForSymbol(char c, RevisedExpression tree, char [] firstIndexExpr="") 471 517 { … … 476 522 if (c-'A'<tree.symbolTable.length) { 477 523 v = tree.symbolTable[c-'A'].value; 478 } else { // else it's a compound or an indexed array 524 } else { // else it's a compound or an indexed array 479 525 char [] comp = tree.compounds[c-'A'-tree.symbolTable.length]; 480 526 481 if (comp[$-1]!=']') { // simple compound expression 482 foreach(d; comp) { 483 if (d>='A' && d<='Z') v ~= tree.symbolTable[d-'A'].value; 484 else v ~= d; 527 if (comp[$-1]!=']') { // compound expression (not an indexed array) 528 if (comp[0]=='d') { 529 // dot product is a nested expression 530 return invokeNestedExpression(comp, tree.symbolTable); 531 } 532 for (int k=0; k<comp.length; ++k) { 533 char d = comp[k]; 534 if (d=='{') { 535 int braceStart = k+1; 536 for (; comp[k]!='}'; ++k) {} 537 v ~= invokeNestedExpression(comp[braceStart..k], tree.symbolTable); 538 } else if (d>='A' && d<='Z') { 539 v ~= tree.symbolTable[d-'A'].value; 540 } else v ~= d; 485 541 } 486 542 } else { … … 542 598 } 543 599 544 // Convert the compound expression str back into its values.545 char [] reconstituteCompoundExpression(char [] str, Symbol[] table)546 {547 char [] v = "";548 foreach(d; str) {549 if (d>='A' && d<='Z') v ~= table[d-'A'].value;550 else v ~= d;551 }552 return v;553 }554 600 555 601 // Generate inline D code for the expression 556 602 char [] DCodeGenerator(RevisedExpression tree) 557 603 { 558 int lenvec = findVectorForLength(tree); 559 char [] result = assertAllVectorLengthsEqual(tree); 560 result ~= "// " ~ tree.expression ~ \n; 561 result ~= "for (int blade_index=0; blade_index<" 562 ~ getDimensionLengthForSymbol(tree.mapping[lenvec], tree, 1) ~ 563 "; ++blade_index) {"\n; 604 char [] result = "// D generate:" ~ tree.braceExpression ~ \n; 605 int wholerank = exprRank(tree.expression, tree.rank); 606 if (wholerank ==1) { 607 int lenvec = findVectorForLength(tree); 608 result = "for (int blade_index=0; blade_index<" 609 ~ getDimensionLengthForSymbol(tree.mapping[lenvec], tree, 1) 610 ~ "; ++blade_index) {"\n; 611 } 564 612 foreach (c; tree.expression) { 565 if (c>='A' && c<'Z') { 613 if (c>='A' && c<'Z') { 566 614 // restore all symbols into the expression 567 615 // If it's a vector, index it … … 571 619 } else result ~= c; 572 620 } 621 if (wholerank==0) return result ~ ";"; 573 622 return result ~ "; }"; 574 623 } trunk/blade/BladeDemo.d
r166 r167 15 15 // cdouble[] always remains aligned, even when sliced. 16 16 17 float dot_product(float[] a, float[] b) 18 { 19 return 0; 20 } 17 21 18 22 void main() 19 { 23 { 20 24 static z = [3.4, 565, 31.3, 0]; 21 25 double [] a = new double[4]; … … 53 57 mixin(vectorize("another[0..$,1]=6*a[0..2]")); 54 58 55 // Parses, and simplifies to A*A, where A = dot(q,q). No codegen yet. 56 // mixin(vectorize("dot(q,q*dot(q,q))")); 59 // Parses, and simplifies to A*A, where A = dot(q,q). No asm codegen yet. 60 double u; 61 // mixin(vectorize("u = dot(q,q*dot(q,q))")); 62 // mixin(vectorize("q *=dot(q,q*dot(q+q,q))")); 57 63 58 64 writefln("a=", a); 59 65 } 60 trunk/blade/BladeRank.d
r161 r167 64 64 /** Returns the (tensor) rank of the expression expr. 65 65 * A negative number will be returned if an error is detected. 66 * TODO: Should warn of expressions with no effect (ie, with no =). 66 67 * 67 68 * Params: … … 226 227 // bug fixes: 227 228 assert(exprRank("(A[B..$,C])+=D", "2001")==1); 228 229 //NO LONGER SUPPORTED 230 // assert(exprRank("A[B,([B,C]),B]", "600")==4); 231 // assert(exprRank("A[B,(([B,C])[B]),B]", "600")==3); 232 233 } 234 235 236 // Return true if the entire expression contains a multiplication by a scalar 237 bool hasScalarMultiply(char [] expr, char [] rank) 238 { 239 if (expr.length>2 && (expr[0..2]=="++" || expr[0..2]=="--" || expr[$-2..$]=="++" || expr[$-2..$]=="--")) { 240 return false; 241 } 242 if (expr[0]=='+' || expr[0]=='-') return hasScalarMultiply(expr[1..$], rank); 243 244 int x = exprLength(expr); 245 int y = x+1; 246 assert(y < expr.length, "BLADE BUG:" ~ expr); 247 // Deal with shifts, op=, and NCEG operators 248 while (expr[y+1]=='<' || expr[y+1]=='>' || expr[y+1]=='=') ++y; 249 250 char [] op = expr[x+1..y+1]; 251 char [] left = expr[0..x+1]; 252 char [] right = expr[y+1..$]; 253 if (op=="[") { 254 // (A)[C] can still have a multiply by scalar, if A contains a 255 // multiply. 256 if (left.length==1) return false; 257 return hasScalarMultiply(left[1..$], rank); 258 } 259 if (op=="/") return true; 260 if (op!="*" && op!="/") { 261 if (left.length==1 || right.length==1) return false; 262 // (A+B) could contain a multiply by scalar, if both A and B 263 // contain multiplies. 264 return hasScalarMultiply(left[1..$-1], rank) && hasScalarMultiply(right[1..$-1], rank); 265 } 266 // it's not true for matrix*matrix multiplies. 267 if (subexprRank(left, rank)==0) return true; 268 return subexprRank(right, rank) == 0; 269 } 270 271 unittest { 272 assert(hasScalarMultiply("(A*B)+(B*C)","101")); 273 assert(!hasScalarMultiply("(A*B)-(C*C)","101")); 274 assert(!hasScalarMultiply("A+(B*C)","101")); 275 assert(hasScalarMultiply("(A/B)-((A*B)+(C*B))","101")); 276 assert(!hasScalarMultiply("A[B]","20")); 277 assert(!hasScalarMultiply("(C[B])[B..A]","002") ); 278 } 229 } trunk/blade/BladeSimplify.d
r166 r167 13 13 * where B and C are both rank 0, and A is rank 1 or more, the slice can 14 14 * be moved to every vector inside A. 15 * - Use associativity of *: A*(B*C[]) == (A*B)*C[] 15 * - Use associativity of *: A*(B*C[]) == (A*B)*C[] (Not strictly true for 16 * floating point; results may differ by 1ulp, 17 eg (1.3L*3.1L)*4.7L < 1.3L*(3.1L*4.7L) 18 * Note that floating point addition is not associative at all). 16 19 * (D) Expression standardisation 17 20 * - Move multiplies to left: Convert A[]*B into B*A[] (assumes * is commutative, 18 21 * not valid for quaternions). 19 22 * - Convert C-A*B into C+(-A)*B whenever possible. 23 * - Remove unary minus where possible, eg convert A-(-B) into A+B. 20 24 * 21 25 * Author: … … 29 33 public import blade.SyntaxTree : AbstractSyntaxTree, Symbol; 30 34 private import blade.BladeVisitor; 31 private import blade.BladeRank : exprLength, exprRank, subexprRank, 32 hasScalarMultiply, getRankErrorText, isStrided; 35 private import blade.BladeRank : exprRank, subexprRank, getRankErrorText; 33 36 34 37 35 38 /// A simplified vector expression 36 39 struct RevisedExpression { 40 char [] braceExpression; // the expression with compounds in braces 37 41 char [] expression; // the revised expression using new variable names 38 42 // (so, for example, B+=(D-F) becomes A+=(B-C) ). … … 60 64 // Check for undefined symbols 61 65 if (err.length > 0) 62 return RevisedExpression(tree.expression, tree.symbolTable, [""], "","", "Undefined symbols:" ~ err);66 return RevisedExpression(tree.expression, "", tree.symbolTable, [""], "","", "Undefined symbols:" ~ err); 63 67 else { 68 // Remove duplicate symbols, convert intrinsics 64 69 char [] expr2 = removeDuplicates(tree); 65 70 // Check for rank errors 66 71 int wholerank = exprRank(expr2, ranks); 67 72 if (wholerank<0) 68 return RevisedExpression(expr2, tree.symbolTable, [""], "","", getRankErrorText(wholerank)); 69 return simplifyVectorExpression(expr2, ranks, tree.symbolTable); 73 return RevisedExpression(expr2, "", tree.symbolTable, [""], "","", getRankErrorText(wholerank)); 74 // Perform scalar foldings and dimension reduction 75 char [] expr3 = foldScalars(foldIndices(expr2, ranks), ranks); 76 return remapCompounds(expr3, ranks, tree.symbolTable); 70 77 } 71 78 } … … 136 143 } 137 144 138 RevisedExpression simplifyVectorExpression(char [] expr, char [] rank, Symbol[] symTable=[]) 139 { 140 char [] s = foldScalars(foldIndices(expr, rank), rank); 145 public: 146 // Remove everything inside {} from expr, and create new variables for it. 147 RevisedExpression remapCompounds(char [] expr, char [] rank, Symbol[] symTable) 148 { 141 149 char [][] comp; 142 150 char [] used = ""; // which of the old variables are used; gives the new mapping … … 146 154 char next = cast(char)('A' + rank.length); 147 155 char [] e = ""; 148 for (int i=0; i< s.length; ++i) {149 if ( s[i]=='{') {156 for (int i=0; i<expr.length; ++i) { 157 if (expr[i]=='{') { 150 158 int k; 151 159 int bracecount=1; 152 160 for (k=i+1; bracecount>0; ++k) { 153 if ( s[k]=='{') ++bracecount;154 if ( s[k]=='}') --bracecount;161 if (expr[k]=='{') ++bracecount; 162 if (expr[k]=='}') --bracecount; 155 163 } 156 164 --k; 157 char [] newexpr = s[i+1..k]; // strip off the {}165 char [] newexpr = expr[i+1..k]; // strip off the {} 158 166 int newi = k; 159 if (i>0 && k< s.length-1 && s[i-1]=='(' && s[k+1]==')') {167 if (i>0 && k<expr.length-1 && expr[i-1]=='(' && expr[k+1]==')') { 160 168 e = e[0..$-1]; // remove the last '(' 161 169 newi=k+1; // don't add ')' … … 167 175 e ~= next; 168 176 ++next; 169 comp ~= s[i+1..k]; // strip off the {}170 if ( s[k-1]==']') {177 comp ~= expr[i+1..k]; // strip off the {} 178 if (expr[k-1]==']') { 171 179 // it's a vector/matrix of some kind, with rank reduced 172 180 // by indices. Can't just use exprRank, because the [] 173 181 // aren't wrapped by (). 174 r ~= (rank[ s[i+1]-'A'] - indexRank(s[i+1..k]));182 r ~= (rank[expr[i+1]-'A'] - indexRank(expr[i+1..k])); 175 183 } else { 176 184 // it's a scalar expression. Note that it could involve … … 181 189 i = newi; 182 190 } else { 183 e ~= s[i];184 if ( s[i]>='A' && s[i]<='Z') used[s[i]-'A']=s[i];191 e ~= expr[i]; 192 if (expr[i]>='A' && expr[i]<='Z') used[expr[i]-'A']=expr[i]; 185 193 } 186 194 } … … 210 218 } else f ~= c; 211 219 } 212 return RevisedExpression(f, symTable, comp, old_ranks~r, mapping); 220 return RevisedExpression(expr, f, symTable, comp, old_ranks~r, mapping); 221 } 222 223 private: 224 RevisedExpression simplifyVectorExpression(char [] expr, char [] rank, Symbol[] symTable) 225 { 226 return remapCompounds(foldScalars(foldIndices(expr, rank), rank), rank, symTable); 213 227 } 214 228 215 229 unittest { 216 RevisedExpression e = simplifyVectorExpression("A+=(((D[B])*C)[B])", "2004" );230 RevisedExpression e = simplifyVectorExpression("A+=(((D[B])*C)[B])", "2004",[]); 217 231 assert(e.rank=="202"); 218 232 assert(e.compounds[0]=="D[B,B]"); … … 441 455 ScalarFold left = doVisit(this_,args[0]); 442 456 ScalarFold right = doVisit(this_, args[1]); 443 return ScalarFold("", combineMul(combineMul(left.multiplier, right.multiplier), func ~ "(" ~ left.expr ~ "," ~ right.expr ~ ")"));457 return ScalarFold("", combineMul(combineMul(left.multiplier, right.multiplier), "{" ~ func ~ "(" ~ left.expr ~ "," ~ right.expr ~ ")}")); 444 458 } else { 445 459 assert(0, "BLADE: Unsupported function"); … … 554 568 ScalarFold f = beginVisit(ScalarFoldingVisitor(ranks), expr); 555 569 if (f.multiplier=="") return f.expr; 556 else if (f.expr=="") return "{" ~ f.multiplier ~ "}";570 else if (f.expr=="") return f.multiplier; 557 571 else return combineMulWithCompound(f.expr, f.multiplier); 558 572 } … … 560 574 unittest { 561 575 assert(foldScalars("A*=(B*C)", "100")=="A*={(B*C)}"); 562 assert(foldScalars("d(A,(A*d(A,A)))", "1")==" {(d(A,A))*(d(A,A))}");576 assert(foldScalars("d(A,(A*d(A,A)))", "1")=="({d(A,A)})*({d(A,A)})"); 563 577 assert(foldScalars("A-(B*C)", "101")=="A+(C*{(-B)})"); 564 578 assert(foldScalars("A-(B*(-C))", "101")=="A+(C*{(-(-B))})"); trunk/blade/BladeVisitor.d
r161 r167 132 132 return (a.length==1)? a : "(" ~ a ~ ")"; 133 133 } 134 135 // Return true if this expression contains an assignment. 136 bool expressionContainsAssignment(char [] expr) 137 { 138 // BUG: also need to deal with comma, ?:, &&, ||, is, !is, in, 139 // unary &, unary ! 140 if (expr.length>1 && expr[0]=='(') expr = expr[1..$-1]; 141 else if (expr.length==1 && ((expr[0]>='A' && expr[0]<='Z') || expr[0]=='$')){ 142 return false; 143 } 144 if (expr.length>3 && (expr[0]>='a' && expr[1]<='z') && expr[1]=='(') { // function 145 return false; 146 } 147 if (expr.length>2 && (expr[0..2]=="++" || expr[0..2]=="--")) { 148 return false; 149 } 150 if (expr.length>1 && (expr[0]=='+' || expr[0]=='-')) { 151 return false; 152 } 153 if (expr.length>2 && (expr[$-2..$]=="++" || expr[$-2..$]=="--")) { 154 return false; // BUG: actually this is an assignment 155 } 156 int x = exprLength(expr); 157 int y = x+1; 158 assert(y < expr.length, "BLADE ICE:" ~ expr); 159 // Deal with shifts, op=, and NCEG operators 160 if (expr[y+1]=='<' || expr[y+1]=='>') return false; 161 if (expr[y]=='=' && expr[y+1]=='=') return false; 162 if (expr[y]=='=') return true; 163 if (expr[y+1]!='=') return false; 164 if (expr[y]=='<' || expr[y]=='<' || expr[y]=='!') return false; 165 return true; 166 } trunk/blade/CodegenX86.d
r166 r167 289 289 char [] generateCodeForAsmX87(int numStrides, Values...)(char [] postfixOperations) 290 290 { 291 // Because of compiler bug #1125, no structs can be stored in the 'values' tuple. 292 // Thus, lengths and strides must be stored seperately from vector pointers. 291 293 char [] ranklist; 292 294 char [][] typelist;
