src/compiler/HIR.cpp
author David Anderson <dvander@alliedmods.net>
Thu Dec 27 21:07:03 2012 -0800 (2012-12-27)
changeset 246 f9c4371d59d4
parent 245 9371f058625a
child 247 7721042bdb67
permissions -rw-r--r--
Add support for unary - and bitcast operator.
     1 /* vim: set ts=4 sw=4 tw=99 et:
     2  *
     3  * Copyright (C) 2012 David Anderson
     4  *
     5  * This file is part of JITCraft.
     6  *
     7  * JITCraft is free software: you can redistribute it and/or modify it under
     8  * the terms of the GNU General Public License as published by the Free
     9  * Software Foundation, either version 3 of the License, or (at your option)
    10  * any later version.
    11  * 
    12  * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
    13  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    14  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
    15  *
    16  * You should have received a copy of the GNU General Public License along with
    17  * JITCraft. If not, see http://www.gnu.org/licenses/.
    18  */
    19 #include "AST.h"
    20 #include "HIR.h"
    21 #include "BytecodeEmitter.h"
    22 #include "../Strings.h"
    23 #include "../Heap-inl.h"
    24 #include "../Handles-inl.h"
    25 
    26 using namespace ke;
    27 
    28 class HIRTranslator : public HIRVisitor
    29 {
    30   public:
    31     HIRTranslator(Zone *zone, BytecodeEmitter &emitter)
    32       : zone_(zone),
    33         emitter_(emitter)
    34     {
    35     }
    36 
    37     void translate(HIR *hir) {
    38         hir->accept(this);
    39     }
    40 
    41     void visitBoolean(HBoolean *hir);
    42     void visitFloat(HFloat *hir);
    43     void visitInteger(HInteger *hir);
    44     void visitArray(HArray *hir);
    45     void visitCall(HCall *call);
    46     void visitStore(HStore *store);
    47     void visitUnary(HUnary *unary);
    48     void visitBinary(HBinary *binary);
    49     void visitLocal(HLocal *local);
    50     void visitGlobal(HGlobal *global);
    51     void visitConvert(HConvert *convert);
    52     void visitIndex(HIndex *index);
    53     void visitPostIncDec(HPostIncDec *hir);
    54     void visitToRef(HToRef *hir);
    55 
    56   private:
    57     Zone *zone_;
    58     BytecodeEmitter &emitter_;
    59 };
    60 
    61 #define __ emitter_.
    62 
    63 void
    64 HIRTranslator::visitBoolean(HBoolean *hir)
    65 {
    66     if (hir->value())
    67         __ true_();
    68     else
    69         __ false_();
    70 }
    71 
    72 void
    73 HIRTranslator::visitFloat(HFloat *hir)
    74 {
    75     __ float_(hir->value());
    76 }
    77 
    78 void
    79 HIRTranslator::visitInteger(HInteger *hir)
    80 {
    81     __ int_(hir->value());
    82 }
    83 
    84 void
    85 HIRTranslator::visitArray(HArray *hir)
    86 {
    87     __ object(hir->array());
    88 
    89     if (hir->duplicate())
    90         __ duparray(); 
    91 }
    92 
    93 void
    94 HIRTranslator::visitCall(HCall *call)
    95 {
    96     Local<FunctionType> fun(zone_, FunctionType::cast(call->callee()->type()));
    97     
    98     assert(call->args()->length() == fun->parameters()->length());
    99 
   100     __ note_position(call->node()->pos());
   101 
   102     unsigned argc = call->args()->length();
   103     for (size_t i = call->args()->length() - 1; i < call->args()->length(); i--) {
   104         HIR *hir = call->args()->at(i);
   105         hir->accept(this);
   106     }
   107 
   108     call->callee()->accept(this);
   109     __ call(fun, argc);
   110 }
   111 
   112 void
   113 HGlobal::bind(HIRVisitor *visitor, BytecodeEmitter &emitter_)
   114 {
   115 }
   116 
   117 void
   118 HGlobal::hold(BytecodeEmitter &emitter_)
   119 {
   120 }
   121 
   122 void
   123 HGlobal::swapAndPick(BytecodeEmitter &emitter_)
   124 {
   125     __ dup();
   126 }
   127 
   128 void
   129 HGlobal::store(BytecodeEmitter &emitter_)
   130 {
   131     __ setglobal(sym_);
   132 }
   133 
   134 void
   135 HGlobal::load(BytecodeEmitter &emitter_)
   136 {
   137     __ getglobal(sym_);
   138 }
   139 
   140 bool
   141 HGlobal::ref(BytecodeEmitter &emitter_)
   142 {
   143     return false;
   144 }
   145 
   146 static inline Type *
   147 MaybeDereference(Type *type)
   148 {
   149     if (type->isReference())
   150         return ReferenceType::cast(type)->contained();
   151     return type;
   152 }
   153 
   154 HLocal::HLocal(AstNode *node, VariableSymbol *sym)
   155   : HLValue(node, MaybeDereference(sym->type())),
   156     sym_(sym)
   157 {
   158 }
   159 
   160 void
   161 HLocal::bind(HIRVisitor *visitor, BytecodeEmitter &emitter_)
   162 {
   163     if (sym_->type()->isReference()) {
   164         if (sym_->storage() == VariableSymbol::Local)
   165             __ getlocal(sym_);
   166         else if (sym_->storage() == VariableSymbol::Arg)
   167             __ getarg(sym_);
   168         else
   169             assert(false);
   170     }
   171 }
   172 
   173 void
   174 HLocal::hold(BytecodeEmitter &emitter_)
   175 {
   176     if (sym_->type()->isReference())
   177         __ dup();
   178 }
   179 
   180 void
   181 HLocal::swapAndPick(BytecodeEmitter &emitter_)
   182 {
   183     if (sym_->type()->isReference()) {
   184         __ swap();
   185         __ pick2();
   186     } else {
   187         __ dup();
   188     }
   189 }
   190 
   191 void
   192 HLocal::store(BytecodeEmitter &emitter_)
   193 {
   194     if (sym_->type()->isReference()) {
   195         __ setref(ReferenceType::cast(sym_->type())->contained());
   196     } else {
   197         if (sym_->storage() == VariableSymbol::Local)
   198             __ setlocal(sym_);
   199         else if (sym_->storage() == VariableSymbol::Arg)
   200             __ setarg(sym_);
   201         else
   202             assert(false);
   203     }
   204 }
   205 
   206 void
   207 HLocal::load(BytecodeEmitter &emitter_)
   208 {
   209     if (sym_->type()->isReference())
   210         __ getref(ReferenceType::cast(sym_->type())->contained());
   211     else if (sym_->storage() == VariableSymbol::Local)
   212         __ getlocal(sym_);
   213     else if (sym_->storage() == VariableSymbol::Arg)
   214         __ getarg(sym_);
   215     else
   216         assert(false);
   217 }
   218 
   219 bool
   220 HLocal::ref(BytecodeEmitter &emitter_)
   221 {
   222     if (sym_->storage() == VariableSymbol::Heap) {
   223         // Closing over a reference should never pass SemA.
   224         assert(!sym_->type()->isReference());
   225 
   226         // We don't support direct references to heap-allocated locals. This
   227         // should probably be banned in SemA? But for now, just assert. :TODO:
   228         assert(false);
   229         return false;
   230     }
   231         
   232     if (sym_->type()->isReference()) {
   233         if (sym_->storage() == VariableSymbol::Local)
   234             __ getlocal(sym_);
   235         else if (sym_->storage() == VariableSymbol::Arg)
   236             __ getarg(sym_);
   237         else
   238             assert(false);
   239     } else {
   240         __ newref(sym_);
   241     }
   242 
   243     return true;
   244 }
   245 
   246 void
   247 HIndex::bind(HIRVisitor *visitor, BytecodeEmitter &emitter_)
   248 {
   249     __ note_position(node()->pos());
   250     left_->accept(visitor);
   251     right_->accept(visitor);
   252 }
   253 
   254 void
   255 HIndex::hold(BytecodeEmitter &emitter_)
   256 {
   257     __ dup2();
   258 }
   259 
   260 void
   261 HIndex::swapAndPick(BytecodeEmitter &emitter_)
   262 {
   263     // BASE INDEX VALUE
   264     __ roll3();         // INDEX VALUE BASE
   265     __ roll3();         // VALUE BASE INDEX
   266     __ pick3();         // VALUE BASE INDEX VALUE
   267 }
   268 
   269 void
   270 HIndex::store(BytecodeEmitter &emitter_)
   271 {
   272     __ setelem(type());
   273 }
   274 
   275 void
   276 HIndex::load(BytecodeEmitter &emitter_)
   277 {
   278     __ getelem(type());
   279 }
   280 
   281 bool
   282 HIndex::ref(BytecodeEmitter &emitter_)
   283 {
   284     return false;
   285 }
   286 
   287 void
   288 HIRTranslator::visitLocal(HLocal *local)
   289 {
   290     local->bind(this, emitter_);
   291     local->load(emitter_);
   292 }
   293 
   294 void
   295 HIRTranslator::visitIndex(HIndex *index)
   296 {
   297     index->bind(this, emitter_);
   298     index->load(emitter_);
   299 }
   300 
   301 void
   302 HIRTranslator::visitGlobal(HGlobal *global)
   303 {
   304     global->bind(this, emitter_);
   305     global->load(emitter_);
   306 }
   307 
   308 static inline Opcode
   309 TokenToOpcode(TokenKind kind)
   310 {
   311     switch (kind) {
   312       case TOK_PLUS:
   313       case TOK_ASSIGN_ADD:
   314       case TOK_INCREMENT:
   315         return OP_ADD;
   316       case TOK_MINUS:
   317       case TOK_ASSIGN_SUB:
   318       case TOK_DECREMENT:
   319         return OP_SUB;
   320       case TOK_STAR:
   321       case TOK_ASSIGN_MUL:
   322         return OP_MUL;
   323       case TOK_SLASH:
   324       case TOK_ASSIGN_DIV:
   325         return OP_DIV;
   326       case TOK_PERCENT:
   327       case TOK_ASSIGN_MOD:
   328         return OP_MOD;
   329       case TOK_SHR:
   330       case TOK_ASSIGN_SHR:
   331         return OP_SHR;
   332       case TOK_USHR:
   333       case TOK_ASSIGN_USHR:
   334         return OP_USHR;
   335       case TOK_SHL:
   336       case TOK_ASSIGN_SHL:
   337         return OP_SHL;
   338       case TOK_BITAND:
   339       case TOK_ASSIGN_BITAND:
   340         return OP_BITAND;
   341       case TOK_BITOR:
   342       case TOK_ASSIGN_BITOR:
   343         return OP_BITOR;
   344       case TOK_GT:
   345           return OP_GT;
   346       case TOK_GE:
   347           return OP_GE;
   348       case TOK_LT:
   349           return OP_LT;
   350       case TOK_LE:
   351           return OP_LE;
   352       case TOK_EQUALS:
   353           return OP_EQ;
   354       case TOK_NOTEQUALS:
   355           return OP_NE;
   356       default:
   357         assert(kind == TOK_BITXOR);
   358         return OP_BITXOR;
   359     }
   360 }
   361 
   362 void
   363 HIRTranslator::visitStore(HStore *store)
   364 {
   365     store->lval()->bind(this, emitter_);
   366 
   367     if (store->kind() == TOK_ASSIGN) {
   368         // Fixed-length arrays and structs have copy semantics.
   369         Local<Type> type(zone_, store->lval()->type());
   370         if (type->isArray() && ArrayType::cast(type)->isFixedLength()) {
   371             store->lval()->load(emitter_);
   372             store->rval()->accept(this);
   373             __ copyarray();
   374         } else if (type->isStruct()) {
   375             store->lval()->load(emitter_);
   376             store->rval()->accept(this);
   377             __ copystruct();
   378         } else {
   379             store->rval()->accept(this);
   380             store->lval()->store(emitter_);
   381         }
   382     } else {
   383         // Advanced case: dup the ref, load, op, store.
   384         store->lval()->hold(emitter_);
   385         store->lval()->load(emitter_);
   386         store->rval()->accept(this);
   387         __ binary(TokenToOpcode(store->kind()));
   388         store->lval()->store(emitter_);
   389     }
   390 }
   391 
   392 void
   393 HIRTranslator::visitPostIncDec(HPostIncDec *hir)
   394 {
   395     hir->lval()->bind(this, emitter_);
   396     hir->lval()->hold(emitter_);
   397     hir->lval()->load(emitter_);
   398     hir->lval()->swapAndPick(emitter_);
   399     hir->rval()->accept(this);
   400     __ binary(TokenToOpcode(hir->kind()));
   401     hir->lval()->store(emitter_);
   402     __ pop();
   403 }
   404 
   405 void
   406 HIRTranslator::visitBinary(HBinary *binary)
   407 {
   408     binary->left()->accept(this);
   409     binary->right()->accept(this);
   410 
   411     // We define three sets of math operators:
   412     //
   413     //  (1) ADD, SUB, MUL, DIV, MOD, which take two equal types and produce
   414     //      the same type.
   415     //  (2) LT, LE, GE, GT, EQ, NE, which take two equal types and produce
   416     //      a boolean.
   417     //  (3) SHL, SR, USHR, BITAND, BITOR, BITXOR, BITNOT, which take two
   418     //      equal integer types and return that integer type.
   419     //
   420     Opcode op = TokenToOpcode(binary->token());
   421 
   422     if (op == OP_DIV)
   423         __ note_position(binary->node()->pos());
   424 
   425     if (op >= OP_ADD && op <= OP_NE) {
   426         if (binary->type()->isFloat())
   427             op = Opcode(int(op) + int(OP_ADD_F - OP_ADD));
   428     } else {
   429         assert(binary->type()->isInt32());
   430     }
   431 
   432     __ binary(op);
   433 }
   434 
   435 void
   436 HIRTranslator::visitUnary(HUnary *unary)
   437 {
   438     unary->in()->accept(this);
   439 
   440     switch (unary->token()) {
   441       case TOK_MINUS:
   442         if (unary->type()->isFloat())
   443             __ neg_f();
   444         else
   445             __ neg();
   446         break;
   447 
   448       default:
   449         assert(unary->token() == TOK_LABEL);
   450         __ bitcast(unary->type());
   451         break;
   452     }
   453 }
   454 
   455 void
   456 HIRTranslator::visitConvert(HConvert *convert)
   457 {
   458     convert->in()->accept(this);
   459     __ unary(convert->opcode());
   460 }
   461 
   462 void
   463 HIRTranslator::visitToRef(HToRef *hir)
   464 {
   465     HIR *in = hir->in();
   466 
   467     // See if we can bind a direct reference.
   468     if (in->isLValue() && in->toLValue()->ref(emitter_))
   469         return;
   470 
   471     // No, we can't. So instead we create an on-stack reference.
   472     in->accept(this);
   473     __ slotref_lifo();
   474 }
   475 
   476 void
   477 ke::EmitHIR(Zone *zone, BytecodeEmitter &emitter, HIR *hir)
   478 {
   479     HIRTranslator translator(zone, emitter);
   480     translator.translate(hir);
   481 }