Implemented ! operator.
authorDavid Anderson <dvander@alliedmods.net>
Tue Jul 17 21:40:44 2012 -0700 (2012-07-17)
changeset 790206df35882c
parent 78 93e0a19c805a
child 80 c58dff4e560c
Implemented ! operator.
jitcraft/AST.h
jitcraft/BytecodeCompiler.cpp
jitcraft/BytecodeEmitter.h
jitcraft/Interpreter.cpp
jitcraft/Opcodes.cpp
jitcraft/Opcodes.tbl
jitcraft/Parser.cpp
jitcraft/SemanticAnalysis.cpp
     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      }