Added support for fused math-assign ops (+=, etc).
Added support for fused math-assign ops (+=, etc).
1.1 --- a/jitcraft/AST.h Sun Jul 01 14:52:57 2012 -0700
1.2 +++ b/jitcraft/AST.h Sun Jul 01 16:36:39 2012 -0700
1.3 @@ -381,16 +381,16 @@
1.4 class ForStatement : public Statement
1.5 {
1.6 Scope *scope_;
1.7 - VariableDeclaration *declaration_;
1.8 + Statement *initialization_;
1.9 Expression *condition_;
1.10 Statement *update_;
1.11 Statement *body_;
1.12
1.13 public:
1.14 - ForStatement(Scope *scope, VariableDeclaration *declaration,
1.15 + ForStatement(Scope *scope, Statement *initialization,
1.16 Expression *condition, Statement *update, Statement *body)
1.17 : scope_(scope),
1.18 - declaration_(declaration),
1.19 + initialization_(initialization),
1.20 condition_(condition),
1.21 update_(update),
1.22 body_(body)
1.23 @@ -400,8 +400,8 @@
1.24 Kind kind() const {
1.25 return kForStatement;
1.26 }
1.27 - VariableDeclaration *declaration() const {
1.28 - return declaration_;
1.29 + Statement *initialization() const {
1.30 + return initialization_;
1.31 }
1.32 Scope *scope() const {
1.33 return scope_;
1.34 @@ -504,12 +504,14 @@
1.35
1.36 class Assignment : public Expression
1.37 {
1.38 + TokenKind token_;
1.39 Expression *lvalue_;
1.40 Expression *expression_;
1.41
1.42 public:
1.43 - Assignment(Expression *left, Expression *right)
1.44 - : lvalue_(left),
1.45 + Assignment(TokenKind token, Expression *left, Expression *right)
1.46 + : token_(token),
1.47 + lvalue_(left),
1.48 expression_(right)
1.49 {
1.50 }
1.51 @@ -517,6 +519,9 @@
1.52 Kind kind() const {
1.53 return kAssignment;
1.54 }
1.55 + TokenKind token() const {
1.56 + return token_;
1.57 + }
1.58 Expression *lvalue() const {
1.59 return lvalue_;
1.60 }
2.1 --- a/jitcraft/BytecodeCompiler.cpp Sun Jul 01 14:52:57 2012 -0700
2.2 +++ b/jitcraft/BytecodeCompiler.cpp Sun Jul 01 16:36:39 2012 -0700
2.3 @@ -140,14 +140,8 @@
2.4 __ getarg(var->slot());
2.5
2.6 // If this argument is actually a reference, dereference it now.
2.7 - if (var->type()->isReference()) {
2.8 - if (var->type()->contained()->isFloat()) {
2.9 - __ getref_f();
2.10 - } else {
2.11 - assert(var->type()->contained()->isInt32());
2.12 - __ getref_i();
2.13 - }
2.14 - }
2.15 + if (var->type()->isReference())
2.16 + __ getref(var->type()->contained()->primitive());
2.17 }
2.18 break;
2.19 }
2.20 @@ -173,16 +167,33 @@
2.21 void
2.22 BytecodeCompiler::visit(Assignment *node)
2.23 {
2.24 - // First compute the left-hand side.
2.25 + // The first step is three sub-steps:
2.26 + //
2.27 + // (1) Bind the left-hand side.
2.28 + // -- If a cumulative operation (+=, etc):
2.29 + // (2) Save a copy of the binding on the stack.
2.30 + // (3) Dereference the binding to get a value.
2.31 + //
2.32 if (node->lvalue()->isNameProxy()) {
2.33 NameProxy *proxy = node->lvalue()->toNameProxy();
2.34 Variable *var = proxy->binding()->toVariable();
2.35
2.36 - // Make sure to bind the left-hand side first.
2.37 + // Bind.
2.38 if (var->type()->isReference() || var->type()->isArray())
2.39 __ get(var);
2.40
2.41 - node->expression()->accept(this);
2.42 + // Get the value if needed.
2.43 + if (node->token() != TOK_ASSIGN) {
2.44 + // += etc is not allowed on arrays.
2.45 + assert(!var->type()->isArray());
2.46 +
2.47 + if (var->type()->isReference()) {
2.48 + __ dup();
2.49 + __ getref(var->type()->contained()->primitive());
2.50 + } else {
2.51 + __ get(var);
2.52 + }
2.53 + }
2.54 } else if (node->lvalue()->isIndexExpression()) {
2.55 IndexExpression *index = node->lvalue()->toIndexExpression();
2.56
2.57 @@ -195,7 +206,24 @@
2.58 // decision.
2.59 index->left()->accept(this);
2.60 index->right()->accept(this);
2.61 +
2.62 + if (node->token() != TOK_ASSIGN) {
2.63 + __ dup2();
2.64 + __ bounds();
2.65 + if (node->type()->isArray())
2.66 + __ getarray_o();
2.67 + else
2.68 + __ getarray(node->type()->primitive());
2.69 + }
2.70 + }
2.71 +
2.72 + if (node->token() == TOK_ASSIGN) {
2.73 node->expression()->accept(this);
2.74 + } else {
2.75 + visitForALU(node->type(), node->expression());
2.76 +
2.77 + TokenKind alu = TokenKind(int(node->token()) - (TOK_ASSIGN_ADD - TOK_PLUS));
2.78 + __ binary(TokenToOpcode(alu));
2.79 }
2.80
2.81 // Emit the store.
2.82 @@ -207,19 +235,15 @@
2.83 NameProxy *proxy = node->lvalue()->toNameProxy();
2.84 Variable *var = proxy->binding()->toVariable();
2.85
2.86 - if (var->type()->isReference()) {
2.87 - if (var->type()->contained()->isFloat()) {
2.88 - __ setref_f();
2.89 - } else {
2.90 - assert(var->type()->contained()->isInt32());
2.91 - __ setref_i();
2.92 - }
2.93 - } else {
2.94 + if (var->type()->isReference())
2.95 + __ setref(var->type()->contained()->primitive());
2.96 + else
2.97 __ set(var);
2.98 - }
2.99 } else {
2.100 IndexExpression *index = node->lvalue()->toIndexExpression();
2.101 - __ bounds();
2.102 + // :TODO: get rid of the BOUNDS instruction, embed it in setarray*?
2.103 + // We can't emit it here because the stack is slightly out of position.
2.104 + // __ bounds();
2.105 __ setarray(index->left()->type()->contained()->primitive());
2.106 }
2.107 }
2.108 @@ -230,6 +254,8 @@
2.109 node->accept(this);
2.110 if (needed->isFloat() && !node->type()->isFloat())
2.111 __ cvt_i2f();
2.112 + else
2.113 + assert(needed->primitive() == node->type()->primitive());
2.114 }
2.115
2.116 void
2.117 @@ -302,8 +328,8 @@
2.118 Label join, update;
2.119 LoopScope loop(scope_, &join, &update, &loop_);
2.120
2.121 - if (node->declaration())
2.122 - node->declaration()->accept(this);
2.123 + if (node->initialization())
2.124 + node->initialization()->accept(this);
2.125
2.126 Label header, test;
2.127 if (node->condition())
3.1 --- a/jitcraft/BytecodeEmitter.h Sun Jul 01 14:52:57 2012 -0700
3.2 +++ b/jitcraft/BytecodeEmitter.h Sun Jul 01 16:36:39 2012 -0700
3.3 @@ -359,17 +359,21 @@
3.4 void arrayref_lifo() {
3.5 singleByteOp(OP_ARRAYREF_LIFO);
3.6 }
3.7 - void getref_i() {
3.8 - singleByteOp(OP_GETREF_I);
3.9 - }
3.10 - void setref_i() {
3.11 - singleByteOp(OP_SETREF_I);
3.12 + void getref(PrimitiveType type) {
3.13 + if (type == PrimitiveType_Int32) {
3.14 + singleByteOp(OP_GETREF_I);
3.15 + } else {
3.16 + assert(type == PrimitiveType_Float);
3.17 + singleByteOp(OP_GETREF_F);
3.18 + }
3.19 }
3.20 - void getref_f() {
3.21 - singleByteOp(OP_GETREF_F);
3.22 - }
3.23 - void setref_f() {
3.24 - singleByteOp(OP_SETREF_F);
3.25 + void setref(PrimitiveType type) {
3.26 + if (type == PrimitiveType_Int32) {
3.27 + singleByteOp(OP_SETREF_I);
3.28 + } else {
3.29 + assert(type == PrimitiveType_Float);
3.30 + singleByteOp(OP_SETREF_F);
3.31 + }
3.32 }
3.33 void object(Object *obj) {
3.34 ensure(OP_OBJECT_LENGTH);
3.35 @@ -379,6 +383,12 @@
3.36 void arraycopy() {
3.37 singleByteOp(OP_ARRAYCOPY);
3.38 }
3.39 + void dup() {
3.40 + singleByteOp(OP_DUP);
3.41 + }
3.42 + void dup2() {
3.43 + singleByteOp(OP_DUP2);
3.44 + }
3.45 };
3.46
3.47 }
4.1 --- a/jitcraft/Interpreter.cpp Sun Jul 01 14:52:57 2012 -0700
4.2 +++ b/jitcraft/Interpreter.cpp Sun Jul 01 16:36:39 2012 -0700
4.3 @@ -245,7 +245,7 @@
4.4 int right = POP_I32(top);
4.5 int left = POP_I32(top);
4.6 int result = left * right;
4.7 - PUSH_I32(top, result);
4.8 + PUSH_I32(top, result);
4.9 break;
4.10 }
4.11
4.12 @@ -586,6 +586,19 @@
4.13 break;
4.14 }
4.15
4.16 +case OP_DUP:
4.17 +{
4.18 + *top.sp++ = *top.sp;
4.19 + break;
4.20 +}
4.21 +
4.22 +case OP_DUP2:
4.23 +{
4.24 + *top.sp++ = top.sp[-2];
4.25 + *top.sp++ = top.sp[-2];
4.26 + break;
4.27 +}
4.28 +
4.29 default:
4.30 assert(false);
4.31 return false;
5.1 --- a/jitcraft/Opcodes.cpp Sun Jul 01 14:52:57 2012 -0700
5.2 +++ b/jitcraft/Opcodes.cpp Sun Jul 01 16:36:39 2012 -0700
5.3 @@ -104,6 +104,8 @@
5.4 case OP_ARRAYREF_LIFO:
5.5 case OP_OBJECT:
5.6 case OP_ARRAYCOPY:
5.7 + case OP_DUP:
5.8 + case OP_DUP2:
5.9 break;
5.10
5.11 case OP_STOP:
6.1 --- a/jitcraft/Opcodes.tbl Sun Jul 01 14:52:57 2012 -0700
6.2 +++ b/jitcraft/Opcodes.tbl Sun Jul 01 16:36:39 2012 -0700
6.3 @@ -157,3 +157,9 @@
6.4 // copy(Left, Right)
6.5 // push(Left)
6.6 OPDEF(OP_ARRAYCOPY, 55, "arraycopy", 1, 2, 1)
6.7 +
6.8 +// Duplicates the top item on the stack.
6.9 +OPDEF(OP_DUP, 56, "dup", 1, 1, 2)
6.10 +
6.11 +// Duplicates the top two items on the stack.
6.12 +OPDEF(OP_DUP2, 57, "dup2", 1, 2, 4)
7.1 --- a/jitcraft/Parser.cpp Sun Jul 01 14:52:57 2012 -0700
7.2 +++ b/jitcraft/Parser.cpp Sun Jul 01 16:36:39 2012 -0700
7.3 @@ -356,9 +356,27 @@
7.4 }
7.5
7.6 Expression *
7.7 +Parser::assignment()
7.8 +{
7.9 + Expression *left = equals();
7.10 + while (left) {
7.11 + TokenKind token = scanner_.peek();
7.12 + if (token != TOK_ASSIGN && (token < TOK_ASSIGN_ADD || token > TOK_ASSIGN_SHL))
7.13 + break;
7.14 + scanner_.scan();
7.15 + Expression *expr = equals();
7.16 + if (!expr)
7.17 + return NULL;
7.18 +
7.19 + left = new (pool_) Assignment(token, left, expr);
7.20 + }
7.21 + return left;
7.22 +}
7.23 +
7.24 +Expression *
7.25 Parser::expression()
7.26 {
7.27 - return equals();
7.28 + return assignment();
7.29 }
7.30
7.31 Statement *
7.32 @@ -411,12 +429,17 @@
7.33 if (!expect(TOK_LPAREN))
7.34 return NULL;
7.35
7.36 - VariableDeclaration *decl = NULL;
7.37 + Statement *decl = NULL;
7.38 if (!match(TOK_SEMICOLON)) {
7.39 - if (!enterScope(Scope::BLOCK))
7.40 - return NULL;
7.41 - if ((decl = variableDeclaration()) == NULL)
7.42 - return NULL;
7.43 + if (scanner_.peek() == TOK_NEW) {
7.44 + if (!enterScope(Scope::BLOCK))
7.45 + return NULL;
7.46 + if ((decl = variableDeclaration()) == NULL)
7.47 + return NULL;
7.48 + } else {
7.49 + if ((decl = expressionStatement()) == NULL)
7.50 + return NULL;
7.51 + }
7.52 if (!expect(TOK_SEMICOLON))
7.53 return NULL;
7.54 }
7.55 @@ -442,7 +465,7 @@
7.56 return NULL;
7.57
7.58 Scope *blockScope = NULL;
7.59 - if (decl) {
7.60 + if (decl && decl->isVariableDeclaration()) {
7.61 blockScope = scope_->unlinkIfEmpty();
7.62 scope_ = scope_->enclosing();
7.63 }
7.64 @@ -511,18 +534,10 @@
7.65 Statement *
7.66 Parser::expressionStatement()
7.67 {
7.68 - Expression *left = primary();
7.69 + Expression *left = assignment();
7.70 if (!left)
7.71 return NULL;
7.72
7.73 - if (match(TOK_ASSIGN)) {
7.74 - Expression *expr = expression();
7.75 - if (!expr)
7.76 - return NULL;
7.77 -
7.78 - left = new (pool_) Assignment(left, expr);
7.79 - }
7.80 -
7.81 return new (pool_) ExpressionStatement(left);
7.82 }
7.83
7.84 @@ -908,8 +923,8 @@
7.85 prefix();
7.86 fprintf(fp_, "[ ForStatement\n");
7.87 indent();
7.88 - if (node->declaration())
7.89 - node->declaration()->accept(this);
7.90 + if (node->initialization())
7.91 + node->initialization()->accept(this);
7.92 if (node->condition())
7.93 node->condition()->accept(this);
7.94 if (node->update())
8.1 --- a/jitcraft/Parser.h Sun Jul 01 14:52:57 2012 -0700
8.2 +++ b/jitcraft/Parser.h Sun Jul 01 16:36:39 2012 -0700
8.3 @@ -62,6 +62,7 @@
8.4 Expression *bitor();
8.5 Expression *relational();
8.6 Expression *equals();
8.7 + Expression *assignment();
8.8 Expression *expression();
8.9
8.10 Statement *enum_();
9.1 --- a/jitcraft/Scanner.cpp Sun Jul 01 14:52:57 2012 -0700
9.2 +++ b/jitcraft/Scanner.cpp Sun Jul 01 16:36:39 2012 -0700
9.3 @@ -391,15 +391,33 @@
9.4 return TOK_PLUS;
9.5
9.6 case '&':
9.7 + c = getChar();
9.8 + if (c == '=')
9.9 + return TOK_ASSIGN_BITAND;
9.10 + putChar(c);
9.11 return TOK_BITAND;
9.12
9.13 case '|':
9.14 + c = getChar();
9.15 + if (c == '=')
9.16 + return TOK_ASSIGN_BITOR;
9.17 + putChar(c);
9.18 return TOK_BITOR;
9.19
9.20 case '^':
9.21 + c = getChar();
9.22 + if (c == '=')
9.23 + return TOK_ASSIGN_BITXOR;
9.24 + putChar(c);
9.25 return TOK_BITXOR;
9.26
9.27 - case '-': return TOK_MINUS;
9.28 + case '-':
9.29 + c = getChar();
9.30 + if (c == '=')
9.31 + return TOK_ASSIGN_SUB;
9.32 + putChar(c);
9.33 + return TOK_MINUS;
9.34 +
9.35 case ',': return TOK_COMMA;
9.36 case '\0': return TOK_EOF;
9.37
9.38 @@ -429,8 +447,13 @@
9.39 return TOK_GE;
9.40 if (c == '>') {
9.41 c = getChar();
9.42 - if (c == '>')
9.43 + if (c == '>') {
9.44 + c = getChar();
9.45 + if (c == '=')
9.46 + return TOK_ASSIGN_USHR;
9.47 + putChar(c);
9.48 return TOK_USHR;
9.49 + }
9.50 return TOK_SHR;
9.51 }
9.52 putChar(c);
10.1 --- a/jitcraft/SemanticAnalysis.cpp Sun Jul 01 14:52:57 2012 -0700
10.2 +++ b/jitcraft/SemanticAnalysis.cpp Sun Jul 01 16:36:39 2012 -0700
10.3 @@ -189,6 +189,28 @@
10.4 return false;
10.5 }
10.6
10.7 +static inline Type *
10.8 +TypeCheckBinary(TokenKind token, Type *left, Type *right)
10.9 +{
10.10 + if (!left || !right)
10.11 + return NULL;
10.12 +
10.13 + if ((token >= TOK_PLUS && token <= TOK_SLASH) ||
10.14 + (token >= TOK_ASSIGN_ADD && token <= TOK_ASSIGN_DIV))
10.15 + {
10.16 + // If either side is a float, the other side must be a float or int.
10.17 + if (left->isFloat() || right->isFloat()) {
10.18 + assert(left->isFloat() || left->isInt32());
10.19 + assert(right->isFloat() || right->isInt32());
10.20 + return left->isFloat() ? left : right;
10.21 + }
10.22 + }
10.23 +
10.24 + assert(left->isInt32() && right->isInt32());
10.25 + assert(!left->tag() && !right->tag());
10.26 + return left;
10.27 +}
10.28 +
10.29 void
10.30 SemanticAnalysis::visit(Assignment *node)
10.31 {
10.32 @@ -214,34 +236,21 @@
10.33 node->setType(var->type());
10.34 }
10.35
10.36 + if (node->token() != TOK_ASSIGN)
10.37 + assert(TypeCheckBinary(node->token(), node->type(), node->expression()->type()));
10.38 +
10.39 assert(TypeCheckAssignment(node->type(), node->expression()->type()));
10.40 }
10.41
10.42 -
10.43 void
10.44 SemanticAnalysis::visit(BinaryExpression *node)
10.45 {
10.46 + // :TODO: use Local
10.47 Type *left = visitForLoad(node->left());
10.48 Type *right = visitForLoad(node->right());
10.49
10.50 - if (node->token() >= TOK_PLUS && node->token() <= TOK_SLASH) {
10.51 - // Both sides must be primitive.
10.52 - if (!left || !right)
10.53 - return;
10.54 -
10.55 - // If either side is a float, the other side must be a float or int.
10.56 - if (left->isFloat() || right->isFloat()) {
10.57 - assert(left->isFloat() || left->isInt32());
10.58 - assert(right->isFloat() || right->isInt32());
10.59 - node->setType(left->isFloat() ? left : right);
10.60 - return;
10.61 - }
10.62 - }
10.63 -
10.64 - // For now, assert everything else is integer and untagged.
10.65 - assert(left->isInt32() && right->isInt32());
10.66 - assert(!left->tag() && !right->tag());
10.67 - node->setType(left);
10.68 + Type *result = TypeCheckBinary(node->token(), left, right);
10.69 + node->setType(result);
10.70 }
10.71
10.72 void
10.73 @@ -258,8 +267,8 @@
10.74 loopDepth_++;
10.75 if (node->scope())
10.76 scope_ = node->scope();
10.77 - if (node->declaration())
10.78 - node->declaration()->accept(this);
10.79 + if (node->initialization())
10.80 + node->initialization()->accept(this);
10.81 if (node->condition())
10.82 visitForLoad(node->condition());
10.83 if (node->update())
11.1 --- a/jitcraft/Token.h Sun Jul 01 14:52:57 2012 -0700
11.2 +++ b/jitcraft/Token.h Sun Jul 01 16:36:39 2012 -0700
11.3 @@ -20,6 +20,11 @@
11.4
11.5 namespace jc {
11.6
11.7 +// List of tokens the scanner can recognize.
11.8 +//
11.9 +// Some restrictions:
11.10 +// * (ASSIGN_ADD - TOK_PLUS) must be the delta between an operator and its
11.11 +// op-and-assign equivalent.
11.12 #define TOKENMAP(_) \
11.13 _(ERROR, "<error>") \
11.14 _(NEW, "'new'") \
11.15 @@ -56,7 +61,14 @@
11.16 _(LBRACKET, "[") \
11.17 _(RBRACKET, "]") \
11.18 _(ASSIGN_ADD, "+=") \
11.19 + _(ASSIGN_SUB, "-=") \
11.20 _(ASSIGN_MUL, "*=") \
11.21 + _(ASSIGN_DIV, "/=") \
11.22 + _(ASSIGN_BITAND, "&=") \
11.23 + _(ASSIGN_BITOR, "|=") \
11.24 + _(ASSIGN_BITXOR, "^=") \
11.25 + _(ASSIGN_SHR, ">>=") \
11.26 + _(ASSIGN_USHR, ">>>=") \
11.27 _(ASSIGN_SHL, "<<=") \
11.28 _(EQUALS, "==") \
11.29 _(NOTEQUALS, "!=") \
12.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
12.2 +++ b/tests/prototype/assignadd.sp Sun Jul 01 16:36:39 2012 -0700
12.3 @@ -0,0 +1,8 @@
12.4 +main()
12.5 +{
12.6 + new x[3];
12.7 + for (new i = 0; i < 100; i += 3) {
12.8 + x[2] += i;
12.9 + }
12.10 + return x[2];
12.11 +}