Implemented ! operator.
Implemented ! operator.
1.1 --- a/jitcraft/AST.h Tue Jul 17 03:59:52 2012 -0700
1.2 +++ b/jitcraft/AST.h Tue Jul 17 21:40:44 2012 -0700
1.3 @@ -340,7 +340,7 @@
1.4 }
1.5
1.6 Kind kind() const {
1.7 - return kBinaryExpression;
1.8 + return kUnaryExpression;
1.9 }
1.10 Expression *expression() const {
1.11 return expression_;
2.1 --- a/jitcraft/BytecodeCompiler.cpp Tue Jul 17 03:59:52 2012 -0700
2.2 +++ b/jitcraft/BytecodeCompiler.cpp Tue Jul 17 21:40:44 2012 -0700
2.3 @@ -49,6 +49,10 @@
2.4 BinaryExpression *b = expr->toBinaryExpression();
2.5 if (b->token() >= TOK_EQUALS && b->token() <= TOK_OR)
2.6 return b->token();
2.7 + } else if (expr->isUnaryExpression()) {
2.8 + UnaryExpression *u = expr->toUnaryExpression();
2.9 + if (u->token() == TOK_NOT)
2.10 + return TOK_NOT;
2.11 }
2.12 return TOK_EOF;
2.13 }
2.14 @@ -404,6 +408,18 @@
2.15 BytecodeCompiler::visit(UnaryExpression *node)
2.16 {
2.17 switch (node->token()) {
2.18 + case TOK_NOT:
2.19 + {
2.20 + Local<Type> type(zone_, node->expression()->type());
2.21 + node->expression()->accept(this);
2.22 +
2.23 + if (node->type()->isFloat())
2.24 + __ not_f();
2.25 + else
2.26 + __ not_();
2.27 + break;
2.28 + }
2.29 +
2.30 default:
2.31 assert(node->token() == TOK_TILDE);
2.32 node->expression()->accept(this);
2.33 @@ -475,17 +491,22 @@
2.34 Label *fallthrough)
2.35 {
2.36 TokenKind token = ToCompare(expression);
2.37 - if (token == TOK_EOF) {
2.38 - expression->accept(this);
2.39 + if (token == TOK_EOF || token == TOK_NOT) {
2.40 + if (token == TOK_EOF)
2.41 + expression->accept(this);
2.42 + else
2.43 + expression->toUnaryExpression()->expression()->accept(this);
2.44 +
2.45 + bool jumpOnTrue = (fallthrough == falseBranch) ^ (token == TOK_NOT);
2.46
2.47 - Opcode op = (fallthrough == trueBranch) ? OP_JF : OP_JT;
2.48 + Opcode op = jumpOnTrue ? OP_JT : OP_JF;
2.49 if (expression->type()->isFloat())
2.50 op = (Opcode)(int(op) + (OP_JL_F - OP_JL));
2.51
2.52 - if (fallthrough == trueBranch)
2.53 - __ j(op, falseBranch);
2.54 + if (fallthrough == falseBranch)
2.55 + __ j(op, trueBranch);
2.56 else
2.57 - __ j(op, trueBranch);
2.58 + __ j(op, falseBranch);
2.59 return;
2.60 }
2.61
3.1 --- a/jitcraft/BytecodeEmitter.h Tue Jul 17 03:59:52 2012 -0700
3.2 +++ b/jitcraft/BytecodeEmitter.h Tue Jul 17 21:40:44 2012 -0700
3.3 @@ -549,6 +549,12 @@
3.4 void bitnot() {
3.5 singleByteOp(OP_BITNOT);
3.6 }
3.7 + void not_() {
3.8 + singleByteOp(OP_NOT);
3.9 + }
3.10 + void not_f() {
3.11 + singleByteOp(OP_NOT_F);
3.12 + }
3.13
3.14 // Helpers.
3.15 void get(Variable *var) {
4.1 --- a/jitcraft/Interpreter.cpp Tue Jul 17 03:59:52 2012 -0700
4.2 +++ b/jitcraft/Interpreter.cpp Tue Jul 17 21:40:44 2012 -0700
4.3 @@ -533,9 +533,23 @@
4.4 break;
4.5 }
4.6
4.7 +case OP_NOT:
4.8 +{
4.9 + top.sp[-1].i32 = top.sp[-1].i32 ? 0 : 1;
4.10 + break;
4.11 +}
4.12 +
4.13 +case OP_NOT_F:
4.14 +{
4.15 + top.sp[-1].i32 = top.sp[-1].f ? 0 : 1;
4.16 + break;
4.17 +}
4.18 +
4.19 case OP_POP:
4.20 +{
4.21 top.sp--;
4.22 break;
4.23 +}
4.24
4.25 case OP_CALL:
4.26 {
5.1 --- a/jitcraft/Opcodes.cpp Tue Jul 17 03:59:52 2012 -0700
5.2 +++ b/jitcraft/Opcodes.cpp Tue Jul 17 21:40:44 2012 -0700
5.3 @@ -199,6 +199,8 @@
5.4 case OP_EQ_F:
5.5 case OP_NE_F:
5.6 case OP_BITNOT:
5.7 + case OP_NOT:
5.8 + case OP_NOT_F:
5.9 break;
5.10
5.11 case OP_STOP:
6.1 --- a/jitcraft/Opcodes.tbl Tue Jul 17 03:59:52 2012 -0700
6.2 +++ b/jitcraft/Opcodes.tbl Tue Jul 17 21:40:44 2012 -0700
6.3 @@ -85,39 +85,41 @@
6.4 OPDEF(OP_EQ, 30, "eq", 1, 2, 1)
6.5 OPDEF(OP_NE, 31, "ne", 1, 2, 1)
6.6
6.7 -OPDEF(OP_POP, 32, "pop", 1, 1, 0)
6.8 +OPDEF(OP_NOT, 32, "not", 1, 1, 1)
6.9 +
6.10 +OPDEF(OP_POP, 33, "pop", 1, 1, 0)
6.11
6.12 // Unconditional terminator placed at the end of code. If a function returns
6.13 // void, this acts as a RETURNVOID. Otherwise, it must be unreachable.
6.14 -OPDEF(OP_STOP, 33, "stop", 1, 0, 0)
6.15 +OPDEF(OP_STOP, 34, "stop", 1, 0, 0)
6.16
6.17 // Call a function with N arguments. The target function must be the last item
6.18 // on the stack.
6.19 -OPDEF(OP_CALL, 34, "call", 1, -1, 1)
6.20 +OPDEF(OP_CALL, 35, "call", 1, -1, 1)
6.21
6.22 // Similar to GET/LOCAL, except for arguments.
6.23 -OPDEF(OP_GETARG, 35, "getarg", 5, 0, 1)
6.24 -OPDEF(OP_SETARG, 36, "setarg", 5, 1, 1)
6.25 +OPDEF(OP_GETARG, 36, "getarg", 5, 0, 1)
6.26 +OPDEF(OP_SETARG, 37, "setarg", 5, 1, 1)
6.27
6.28 // Reads or writes an integer element to an unsafe array.
6.29 // index = pop()
6.30 // ref = pop()
6.31 // ref[index]
6.32 //
6.33 -OPDEF(OP_GETARRAY_I, 37, "getarray.i", 1, 2, 1)
6.34 -OPDEF(OP_SETARRAY_I, 38, "setarray.i", 1, 3, 1)
6.35 -OPDEF(OP_GETARRAY_F, 39, "getarray.f", 1, 2, 1)
6.36 -OPDEF(OP_SETARRAY_F, 40, "setarray.f", 1, 3, 1)
6.37 -OPDEF(OP_GETARRAY_C, 41, "getarray.c", 1, 2, 1)
6.38 -OPDEF(OP_SETARRAY_C, 42, "setarray.c", 1, 3, 1)
6.39 -OPDEF(OP_GETARRAY_O, 43, "getarray.o", 1, 2, 1)
6.40 +OPDEF(OP_GETARRAY_I, 38, "getarray.i", 1, 2, 1)
6.41 +OPDEF(OP_SETARRAY_I, 39, "setarray.i", 1, 3, 1)
6.42 +OPDEF(OP_GETARRAY_F, 40, "getarray.f", 1, 2, 1)
6.43 +OPDEF(OP_SETARRAY_F, 41, "setarray.f", 1, 3, 1)
6.44 +OPDEF(OP_GETARRAY_C, 42, "getarray.c", 1, 2, 1)
6.45 +OPDEF(OP_SETARRAY_C, 43, "setarray.c", 1, 3, 1)
6.46 +OPDEF(OP_GETARRAY_O, 44, "getarray.o", 1, 2, 1)
6.47
6.48 // Allocate an array, info LIFO space if possible. The ArrayMap to use is
6.49 // specified as an index into the script's Map table.
6.50 //
6.51 // Format:
6.52 // [u8 op] [u32 index]
6.53 -OPDEF(OP_NEWARRAY_LIFO, 44, "newarray.lifo", 5, 0, 1)
6.54 +OPDEF(OP_NEWARRAY_LIFO, 45, "newarray.lifo", 5, 0, 1)
6.55
6.56 // Performs a bounds check on an unsafe array.
6.57 //
6.58 @@ -125,71 +127,73 @@
6.59 // array = pop()
6.60 // push(array)
6.61 // push(index)
6.62 -OPDEF(OP_BOUNDS, 45, "bounds", 1, 2, 2)
6.63 +OPDEF(OP_BOUNDS, 46, "bounds", 1, 2, 2)
6.64
6.65 // Pushes a 32-bit IEEE-754 floating point immediate onto the stack.
6.66 -OPDEF(OP_FLOAT, 46, "float", 5, 0, 1)
6.67 +OPDEF(OP_FLOAT, 47, "float", 5, 0, 1)
6.68
6.69 // Converts an integer to a 32-bit IEEE-754 floating point immediate.
6.70 -OPDEF(OP_CVT_I2F, 47, "cvt.i2f", 1, 1, 1)
6.71 +OPDEF(OP_CVT_I2F, 48, "cvt.i2f", 1, 1, 1)
6.72
6.73 // Stack transitions for these binary operators:
6.74 // rhs = pop()
6.75 // lhs = pop()
6.76 // push(lhs OP rhs)
6.77 -OPDEF(OP_ADD_F, 48, "add.f", 1, 2, 1)
6.78 -OPDEF(OP_SUB_F, 49, "sub.f", 1, 2, 1)
6.79 -OPDEF(OP_MUL_F, 50, "mul.f", 1, 2, 1)
6.80 -OPDEF(OP_DIV_F, 51, "div.f", 1, 2, 1)
6.81 +OPDEF(OP_ADD_F, 49, "add.f", 1, 2, 1)
6.82 +OPDEF(OP_SUB_F, 50, "sub.f", 1, 2, 1)
6.83 +OPDEF(OP_MUL_F, 51, "mul.f", 1, 2, 1)
6.84 +OPDEF(OP_DIV_F, 52, "div.f", 1, 2, 1)
6.85
6.86 -OPDEF(OP_LT_F, 52, "lt.f", 1, 2, 1)
6.87 -OPDEF(OP_LE_F, 53, "le.f", 1, 2, 1)
6.88 -OPDEF(OP_GE_F, 54, "ge.f", 1, 2, 1)
6.89 -OPDEF(OP_GT_F, 55, "gt.f", 1, 2, 1)
6.90 -OPDEF(OP_EQ_F, 56, "eq.f", 1, 2, 1)
6.91 -OPDEF(OP_NE_F, 57, "ne.f", 1, 2, 1)
6.92 +OPDEF(OP_LT_F, 53, "lt.f", 1, 2, 1)
6.93 +OPDEF(OP_LE_F, 54, "le.f", 1, 2, 1)
6.94 +OPDEF(OP_GE_F, 55, "ge.f", 1, 2, 1)
6.95 +OPDEF(OP_GT_F, 56, "gt.f", 1, 2, 1)
6.96 +OPDEF(OP_EQ_F, 57, "eq.f", 1, 2, 1)
6.97 +OPDEF(OP_NE_F, 58, "ne.f", 1, 2, 1)
6.98 +
6.99 +OPDEF(OP_NOT_F, 59, "not.f", 1, 1, 1)
6.100
6.101 // Bitwise operators.
6.102 -OPDEF(OP_SHL, 58, "shl", 1, 2, 1)
6.103 -OPDEF(OP_SHR, 59, "shr", 1, 2, 1)
6.104 -OPDEF(OP_USHR, 60, "ushr", 1, 2, 1)
6.105 -OPDEF(OP_BITAND, 61, "bitand", 1, 2, 1)
6.106 -OPDEF(OP_BITOR, 62, "bitor", 1, 2, 1)
6.107 -OPDEF(OP_BITXOR, 63, "bitxor", 1, 2, 1)
6.108 -OPDEF(OP_BITNOT, 64, "bitnot", 1, 1, 1)
6.109 +OPDEF(OP_SHL, 60, "shl", 1, 2, 1)
6.110 +OPDEF(OP_SHR, 61, "shr", 1, 2, 1)
6.111 +OPDEF(OP_USHR, 62, "ushr", 1, 2, 1)
6.112 +OPDEF(OP_BITAND, 63, "bitand", 1, 2, 1)
6.113 +OPDEF(OP_BITOR, 64, "bitor", 1, 2, 1)
6.114 +OPDEF(OP_BITXOR, 65, "bitxor", 1, 2, 1)
6.115 +OPDEF(OP_BITNOT, 66, "bitnot", 1, 1, 1)
6.116
6.117 // Saves or restores the position of the LIFO heap to/from a local slot.
6.118 -OPDEF(OP_SAVELIFO, 65, "savelifo", 5, 0, 0)
6.119 -OPDEF(OP_UNWINDLIFO, 66, "unwindlifo", 5, 0, 0)
6.120 +OPDEF(OP_SAVELIFO, 67, "savelifo", 5, 0, 0)
6.121 +OPDEF(OP_UNWINDLIFO, 68, "unwindlifo", 5, 0, 0)
6.122
6.123 // Composes a variable reference to a stack slot or argument.
6.124 -OPDEF(OP_VARREF_LIFO, 67, "varref.lifo", 5, 0, 1)
6.125 -OPDEF(OP_ARGREF_LIFO, 68, "argref.lifo", 5, 0, 1)
6.126 -OPDEF(OP_SLOTREF_LIFO, 69, "slotref.lifo", 1, 1, 1)
6.127 -OPDEF(OP_ARRAYREF_LIFO, 70, "arrayref.lifo",1, 2, 1)
6.128 -OPDEF(OP_GETREF_I, 71, "getref.i", 1, 1, 1)
6.129 -OPDEF(OP_SETREF_I, 72, "setref.i", 1, 2, 1)
6.130 -OPDEF(OP_GETREF_F, 73, "getref.f", 1, 1, 1)
6.131 -OPDEF(OP_SETREF_F, 74, "setref.f", 1, 2, 1)
6.132 +OPDEF(OP_VARREF_LIFO, 69, "varref.lifo", 5, 0, 1)
6.133 +OPDEF(OP_ARGREF_LIFO, 70, "argref.lifo", 5, 0, 1)
6.134 +OPDEF(OP_SLOTREF_LIFO, 71, "slotref.lifo", 1, 1, 1)
6.135 +OPDEF(OP_ARRAYREF_LIFO, 72, "arrayref.lifo",1, 2, 1)
6.136 +OPDEF(OP_GETREF_I, 73, "getref.i", 1, 1, 1)
6.137 +OPDEF(OP_SETREF_I, 74, "setref.i", 1, 2, 1)
6.138 +OPDEF(OP_GETREF_F, 75, "getref.f", 1, 1, 1)
6.139 +OPDEF(OP_SETREF_F, 76, "setref.f", 1, 2, 1)
6.140
6.141 // Pushes an object reference onto the stack.
6.142 -OPDEF(OP_OBJECT, 75, "object", 5, 0, 1)
6.143 +OPDEF(OP_OBJECT, 77, "object", 5, 0, 1)
6.144
6.145 // Performs an array-to-array assignment.
6.146 // Left = pop()
6.147 // Right = pop()
6.148 // copy(Left, Right)
6.149 // push(Left)
6.150 -OPDEF(OP_ARRAYCOPY, 76, "arraycopy", 1, 2, 1)
6.151 +OPDEF(OP_ARRAYCOPY, 78, "arraycopy", 1, 2, 1)
6.152
6.153 // Duplicates the top item on the stack.
6.154 -OPDEF(OP_DUP, 77, "dup", 1, 1, 2)
6.155 +OPDEF(OP_DUP, 79, "dup", 1, 1, 2)
6.156
6.157 // Duplicates the top two items on the stack.
6.158 -OPDEF(OP_DUP2, 78, "dup2", 1, 2, 4)
6.159 +OPDEF(OP_DUP2, 80, "dup2", 1, 2, 4)
6.160
6.161 // Swaps the two items at the top of the stack.
6.162 -OPDEF(OP_SWAP, 79, "swap", 1, 2, 2)
6.163 +OPDEF(OP_SWAP, 81, "swap", 1, 2, 2)
6.164
6.165 // Roll operation is the same as Forth. It steals a value on the stack,
6.166 // shifting all stack values down, and then places the stolen value back at
6.167 @@ -199,14 +203,14 @@
6.168 // sp[-3] = sp[-2]
6.169 // sp[-2] = sp[-1]
6.170 // sp[-1] = p
6.171 -OPDEF(OP_ROLL3, 80, "roll3", 1, 3, 3)
6.172 +OPDEF(OP_ROLL3, 82, "roll3", 1, 3, 3)
6.173
6.174 // Pick operation is the same as Forth. It pushes a copy of a slot at a
6.175 // specific depth.
6.176 //
6.177 // push(sp[-n])
6.178 -OPDEF(OP_PICK2, 82, "pick2", 1, 2, 3)
6.179 -OPDEF(OP_PICK3, 83, "pick3", 1, 3, 4)
6.180 +OPDEF(OP_PICK2, 83, "pick2", 1, 2, 3)
6.181 +OPDEF(OP_PICK3, 84, "pick3", 1, 3, 4)
6.182
6.183 // Calls a native function. During the course of calling a native, arguments
6.184 // on the stack are re-pushed to match the cell-based native calling
6.185 @@ -217,14 +221,14 @@
6.186 //
6.187 // [u8 Opcode] [u32 Index] [u32 ArgCount]
6.188 //
6.189 -OPDEF(OP_CALLNATIVE, 84, "callnative", 9, -1, 1)
6.190 +OPDEF(OP_CALLNATIVE, 85, "callnative", 9, -1, 1)
6.191
6.192 // Returns from a function that does return a value.
6.193 -OPDEF(OP_RETURNVOID, 85, "returnvoid", 1, 0, 0)
6.194 +OPDEF(OP_RETURNVOID, 86, "returnvoid", 1, 0, 0)
6.195
6.196 // Loads the module of the running function.
6.197 -OPDEF(OP_MODULE, 86, "module", 1, 0, 1)
6.198 +OPDEF(OP_MODULE, 87, "module", 1, 0, 1)
6.199
6.200 // Loads a function from a module object. The operand is the slot number
6.201 // in the module.
6.202 -OPDEF(OP_GETMODULE_FN, 87, "getmodule.fn", 5, 1, 1)
6.203 +OPDEF(OP_GETMODULE_FN, 88, "getmodule.fn", 5, 1, 1)
7.1 --- a/jitcraft/Parser.cpp Tue Jul 17 03:59:52 2012 -0700
7.2 +++ b/jitcraft/Parser.cpp Tue Jul 17 21:40:44 2012 -0700
7.3 @@ -260,6 +260,7 @@
7.4 return new (pool_) IncDecExpression(pos, token, expr, false);
7.5 }
7.6
7.7 + case TOK_NOT:
7.8 case TOK_TILDE:
7.9 {
7.10 scanner_.scan();
8.1 --- a/jitcraft/SemanticAnalysis.cpp Tue Jul 17 03:59:52 2012 -0700
8.2 +++ b/jitcraft/SemanticAnalysis.cpp Tue Jul 17 21:40:44 2012 -0700
8.3 @@ -207,7 +207,13 @@
8.4 }
8.5 }
8.6
8.7 - if (token >= TOK_EQUALS && token <= TOK_OR) {
8.8 + if (token == TOK_OR || token == TOK_AND) {
8.9 + if (!canTest(node, left) || !canTest(node, right))
8.10 + return NULL;
8.11 + return zone_->types()->getPrimitive(PrimitiveType_Int32);
8.12 + }
8.13 +
8.14 + if (token >= TOK_EQUALS && token <= TOK_GE) {
8.15 if ((left->isFloat() || (left->isInt32() && !left->tag())) &&
8.16 (right->isFloat() || (right->isInt32() && !right->tag())))
8.17 {
8.18 @@ -230,7 +236,7 @@
8.19 bool
8.20 SemanticAnalysis::canTest(AstNode *node, Handle<Type> type)
8.21 {
8.22 - if (type->isArray()) {
8.23 + if (type->isArray() || (type->isInt32() && type->tag())) {
8.24 cc_.reportError(node->pos(), Message_ArrayIsNotBoolean);
8.25 return false;
8.26 }
8.27 @@ -340,13 +346,21 @@
8.28
8.29 switch (node->token())
8.30 {
8.31 + case TOK_NOT:
8.32 + if (!canTest(node->expression(), type))
8.33 + return;
8.34 + type = zone_->types()->getPrimitive(PrimitiveType_Int32);
8.35 + if (!type)
8.36 + return;
8.37 + node->setType(type);
8.38 + break;
8.39 +
8.40 default:
8.41 assert(node->token() == TOK_TILDE);
8.42 if (!type->isInt32() || type->tag()) {
8.43 unaryTypeError(node, node->token(), type);
8.44 return;
8.45 }
8.46 -
8.47 node->setType(type);
8.48 break;
8.49 }