src/compiler/HIR.cpp
author David Anderson <dvander@alliedmods.net>
Sun Jan 06 13:52:21 2013 -0800 (2013-01-06)
changeset 256 3c184218462d
parent 247 7721042bdb67
child 263 ba85a47ee414
permissions -rw-r--r--
Initial implementation of module imports.
     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 visitField(HField *field);
    54     void visitPostIncDec(HPostIncDec *hir);
    55     void visitToRef(HToRef *hir);
    56     void visitNewDependentArray(HNewDependentArray *hir);
    57     void visitImport(HImport *import);
    58 
    59   private:
    60     Zone *zone_;
    61     BytecodeEmitter &emitter_;
    62 };
    63 
    64 #define __ emitter_.
    65 
    66 void
    67 HIRTranslator::visitBoolean(HBoolean *hir)
    68 {
    69     if (hir->value())
    70         __ true_();
    71     else
    72         __ false_();
    73 }
    74 
    75 void
    76 HIRTranslator::visitFloat(HFloat *hir)
    77 {
    78     __ float_(hir->value());
    79 }
    80 
    81 void
    82 HIRTranslator::visitInteger(HInteger *hir)
    83 {
    84     __ int_(hir->value());
    85 }
    86 
    87 void
    88 HIRTranslator::visitArray(HArray *hir)
    89 {
    90     __ object(hir->array());
    91 
    92     if (hir->duplicate())
    93         __ duparray(); 
    94 }
    95 
    96 void
    97 HIRTranslator::visitCall(HCall *call)
    98 {
    99     Local<FunctionType> fun(zone_, FunctionType::cast(call->callee()->type()));
   100     
   101     assert(call->args()->length() == fun->parameters()->length());
   102 
   103     __ note_position(call->node()->pos());
   104 
   105     unsigned argc = call->args()->length();
   106     for (size_t i = call->args()->length() - 1; i < call->args()->length(); i--) {
   107         HIR *hir = call->args()->at(i);
   108         hir->accept(this);
   109     }
   110 
   111     call->callee()->accept(this);
   112     __ call(fun, argc);
   113 }
   114 
   115 void
   116 HGlobal::bind(HIRVisitor *visitor, BytecodeEmitter &emitter_)
   117 {
   118 }
   119 
   120 void
   121 HGlobal::hold(BytecodeEmitter &emitter_)
   122 {
   123 }
   124 
   125 void
   126 HGlobal::swapAndPick(BytecodeEmitter &emitter_)
   127 {
   128     __ dup();
   129 }
   130 
   131 void
   132 HGlobal::store(BytecodeEmitter &emitter_)
   133 {
   134     __ setglobal(sym_);
   135 }
   136 
   137 void
   138 HGlobal::load(BytecodeEmitter &emitter_)
   139 {
   140     __ getglobal(sym_);
   141 }
   142 
   143 bool
   144 HGlobal::ref(BytecodeEmitter &emitter_)
   145 {
   146     return false;
   147 }
   148 
   149 static inline Type *
   150 MaybeDereference(Type *type)
   151 {
   152     if (type->isReference())
   153         return ReferenceType::cast(type)->contained();
   154     return type;
   155 }
   156 
   157 HLocal::HLocal(AstNode *node, VariableSymbol *sym)
   158   : HLValue(node, MaybeDereference(sym->type())),
   159     sym_(sym)
   160 {
   161 }
   162 
   163 void
   164 HLocal::bind(HIRVisitor *visitor, BytecodeEmitter &emitter_)
   165 {
   166     if (sym_->type()->isReference()) {
   167         if (sym_->storage() == VariableSymbol::Local)
   168             __ getlocal(sym_);
   169         else if (sym_->storage() == VariableSymbol::Arg)
   170             __ getarg(sym_);
   171         else
   172             assert(false);
   173     }
   174 }
   175 
   176 void
   177 HLocal::hold(BytecodeEmitter &emitter_)
   178 {
   179     if (sym_->type()->isReference())
   180         __ dup();
   181 }
   182 
   183 void
   184 HLocal::swapAndPick(BytecodeEmitter &emitter_)
   185 {
   186     if (sym_->type()->isReference()) {
   187         __ swap();
   188         __ pick2();
   189     } else {
   190         __ dup();
   191     }
   192 }
   193 
   194 void
   195 HLocal::store(BytecodeEmitter &emitter_)
   196 {
   197     if (sym_->type()->isReference()) {
   198         __ setref(ReferenceType::cast(sym_->type())->contained());
   199     } else {
   200         if (sym_->storage() == VariableSymbol::Local)
   201             __ setlocal(sym_);
   202         else if (sym_->storage() == VariableSymbol::Arg)
   203             __ setarg(sym_);
   204         else
   205             assert(false);
   206     }
   207 }
   208 
   209 void
   210 HLocal::load(BytecodeEmitter &emitter_)
   211 {
   212     if (sym_->type()->isReference())
   213         __ getref(ReferenceType::cast(sym_->type())->contained());
   214     else if (sym_->storage() == VariableSymbol::Local)
   215         __ getlocal(sym_);
   216     else if (sym_->storage() == VariableSymbol::Arg)
   217         __ getarg(sym_);
   218     else
   219         assert(false);
   220 }
   221 
   222 bool
   223 HLocal::ref(BytecodeEmitter &emitter_)
   224 {
   225     if (sym_->storage() == VariableSymbol::Heap) {
   226         // Closing over a reference should never pass SemA.
   227         assert(!sym_->type()->isReference());
   228 
   229         // We don't support direct references to heap-allocated locals. This
   230         // should probably be banned in SemA? But for now, just assert. :TODO:
   231         assert(false);
   232         return false;
   233     }
   234         
   235     if (sym_->type()->isReference()) {
   236         if (sym_->storage() == VariableSymbol::Local)
   237             __ getlocal(sym_);
   238         else if (sym_->storage() == VariableSymbol::Arg)
   239             __ getarg(sym_);
   240         else
   241             assert(false);
   242     } else {
   243         __ newref(sym_);
   244     }
   245 
   246     return true;
   247 }
   248 
   249 void
   250 HIndex::bind(HIRVisitor *visitor, BytecodeEmitter &emitter_)
   251 {
   252     __ note_position(node()->pos());
   253     left_->accept(visitor);
   254     right_->accept(visitor);
   255 }
   256 
   257 void
   258 HIndex::hold(BytecodeEmitter &emitter_)
   259 {
   260     __ dup2();
   261 }
   262 
   263 void
   264 HIndex::swapAndPick(BytecodeEmitter &emitter_)
   265 {
   266     // BASE INDEX VALUE
   267     __ roll3();         // INDEX VALUE BASE
   268     __ roll3();         // VALUE BASE INDEX
   269     __ pick3();         // VALUE BASE INDEX VALUE
   270 }
   271 
   272 void
   273 HIndex::store(BytecodeEmitter &emitter_)
   274 {
   275     __ setelem(type());
   276 }
   277 
   278 void
   279 HIndex::load(BytecodeEmitter &emitter_)
   280 {
   281     __ getelem(type());
   282 }
   283 
   284 bool
   285 HIndex::ref(BytecodeEmitter &emitter_)
   286 {
   287     return false;
   288 }
   289 
   290 void
   291 HField::bind(HIRVisitor *visitor, BytecodeEmitter &emitter_)
   292 {
   293     __ note_position(node()->pos());
   294     base_->accept(visitor);
   295 }
   296 
   297 void
   298 HField::hold(BytecodeEmitter &emitter_)
   299 {
   300     __ dup();
   301 }
   302 
   303 void
   304 HField::swapAndPick(BytecodeEmitter &emitter_)
   305 {
   306     // BASE VALUE
   307     __ swap();      // VALUE BASE
   308     __ pick2();     // VALUE BASE VALUE
   309 }
   310 
   311 void
   312 HField::store(BytecodeEmitter &emitter_)
   313 {
   314     __ setfield(index_, type());
   315 }
   316 
   317 void
   318 HField::load(BytecodeEmitter &emitter_)
   319 {
   320     __ getfield(index_, type());
   321 }
   322 
   323 bool
   324 HField::ref(BytecodeEmitter &emitter_)
   325 {
   326     return false;
   327 }
   328 
   329 void
   330 HIRTranslator::visitLocal(HLocal *local)
   331 {
   332     local->bind(this, emitter_);
   333     local->load(emitter_);
   334 }
   335 
   336 void
   337 HIRTranslator::visitIndex(HIndex *index)
   338 {
   339     index->bind(this, emitter_);
   340     index->load(emitter_);
   341 }
   342 
   343 void
   344 HIRTranslator::visitField(HField *field)
   345 {
   346     field->bind(this, emitter_);
   347     field->load(emitter_);
   348 }
   349 
   350 void
   351 HIRTranslator::visitGlobal(HGlobal *global)
   352 {
   353     global->bind(this, emitter_);
   354     global->load(emitter_);
   355 }
   356 
   357 static inline Opcode
   358 TokenToOpcode(TokenKind kind)
   359 {
   360     switch (kind) {
   361       case TOK_PLUS:
   362       case TOK_ASSIGN_ADD:
   363       case TOK_INCREMENT:
   364         return OP_ADD;
   365       case TOK_MINUS:
   366       case TOK_ASSIGN_SUB:
   367       case TOK_DECREMENT:
   368         return OP_SUB;
   369       case TOK_STAR:
   370       case TOK_ASSIGN_MUL:
   371         return OP_MUL;
   372       case TOK_SLASH:
   373       case TOK_ASSIGN_DIV:
   374         return OP_DIV;
   375       case TOK_PERCENT:
   376       case TOK_ASSIGN_MOD:
   377         return OP_MOD;
   378       case TOK_SHR:
   379       case TOK_ASSIGN_SHR:
   380         return OP_SHR;
   381       case TOK_USHR:
   382       case TOK_ASSIGN_USHR:
   383         return OP_USHR;
   384       case TOK_SHL:
   385       case TOK_ASSIGN_SHL:
   386         return OP_SHL;
   387       case TOK_BITAND:
   388       case TOK_ASSIGN_BITAND:
   389         return OP_BITAND;
   390       case TOK_BITOR:
   391       case TOK_ASSIGN_BITOR:
   392         return OP_BITOR;
   393       case TOK_GT:
   394           return OP_GT;
   395       case TOK_GE:
   396           return OP_GE;
   397       case TOK_LT:
   398           return OP_LT;
   399       case TOK_LE:
   400           return OP_LE;
   401       case TOK_EQUALS:
   402           return OP_EQ;
   403       case TOK_NOTEQUALS:
   404           return OP_NE;
   405       default:
   406         assert(kind == TOK_BITXOR);
   407         return OP_BITXOR;
   408     }
   409 }
   410 
   411 void
   412 HIRTranslator::visitStore(HStore *store)
   413 {
   414     store->lval()->bind(this, emitter_);
   415 
   416     if (store->kind() == TOK_ASSIGN) {
   417         // Fixed-length arrays and structs have copy semantics.
   418         Local<Type> type(zone_, store->lval()->type());
   419         if (type->isArray() && ArrayType::cast(type)->isFixedLength()) {
   420             store->lval()->load(emitter_);
   421             store->rval()->accept(this);
   422             __ copyarray();
   423         } else if (type->isStruct()) {
   424             store->lval()->load(emitter_);
   425             store->rval()->accept(this);
   426             __ copystruct();
   427         } else {
   428             store->rval()->accept(this);
   429             store->lval()->store(emitter_);
   430         }
   431     } else {
   432         // Advanced case: dup the ref, load, op, store.
   433         store->lval()->hold(emitter_);
   434         store->lval()->load(emitter_);
   435         store->rval()->accept(this);
   436         __ binary(TokenToOpcode(store->kind()));
   437         store->lval()->store(emitter_);
   438     }
   439 }
   440 
   441 void
   442 HIRTranslator::visitPostIncDec(HPostIncDec *hir)
   443 {
   444     hir->lval()->bind(this, emitter_);
   445     hir->lval()->hold(emitter_);
   446     hir->lval()->load(emitter_);
   447     hir->lval()->swapAndPick(emitter_);
   448     hir->rval()->accept(this);
   449     __ binary(TokenToOpcode(hir->kind()));
   450     hir->lval()->store(emitter_);
   451     __ pop();
   452 }
   453 
   454 void
   455 HIRTranslator::visitBinary(HBinary *binary)
   456 {
   457     binary->left()->accept(this);
   458     binary->right()->accept(this);
   459 
   460     // We define three sets of math operators:
   461     //
   462     //  (1) ADD, SUB, MUL, DIV, MOD, which take two equal types and produce
   463     //      the same type.
   464     //  (2) LT, LE, GE, GT, EQ, NE, which take two equal types and produce
   465     //      a boolean.
   466     //  (3) SHL, SR, USHR, BITAND, BITOR, BITXOR, BITNOT, which take two
   467     //      equal integer types and return that integer type.
   468     //
   469     Opcode op = TokenToOpcode(binary->token());
   470 
   471     if (op == OP_DIV)
   472         __ note_position(binary->node()->pos());
   473 
   474     if (op >= OP_ADD && op <= OP_NE) {
   475         if (binary->type()->isFloat())
   476             op = Opcode(int(op) + int(OP_ADD_F - OP_ADD));
   477     } else {
   478         assert(binary->type()->isInt32());
   479     }
   480 
   481     __ binary(op);
   482 }
   483 
   484 void
   485 HIRTranslator::visitUnary(HUnary *unary)
   486 {
   487     unary->in()->accept(this);
   488 
   489     switch (unary->token()) {
   490       case TOK_TILDE:
   491         __ bitnot();
   492         break;
   493 
   494       case TOK_MINUS:
   495         if (unary->type()->isFloat())
   496             __ neg_f();
   497         else
   498             __ neg();
   499         break;
   500 
   501       default:
   502         assert(unary->token() == TOK_LABEL);
   503         __ bitcast(unary->type());
   504         break;
   505     }
   506 }
   507 
   508 void
   509 HIRTranslator::visitConvert(HConvert *convert)
   510 {
   511     convert->in()->accept(this);
   512     __ unary(convert->opcode());
   513 }
   514 
   515 void
   516 HIRTranslator::visitToRef(HToRef *hir)
   517 {
   518     HIR *in = hir->in();
   519 
   520     // See if we can bind a direct reference.
   521     if (in->isLValue() && in->toLValue()->ref(emitter_))
   522         return;
   523 
   524     // No, we can't. So instead we create an on-stack reference.
   525     in->accept(this);
   526     __ slotref_lifo();
   527 }
   528 
   529 void
   530 HIRTranslator::visitNewDependentArray(HNewDependentArray *hir)
   531 {
   532     hir->base()->accept(this);
   533     hir->index()->accept(this);
   534 
   535     Local<ArrayType> type(zone_, ArrayType::cast(hir->type()));
   536 
   537     // The dependent map is used for the opcode, but is not attached.
   538     Local<ArrayMap> map(zone_, ArrayMap::NewDependent(zone_, type));
   539     if (!map)
   540         return;
   541 
   542     __ deparray(map);
   543 }
   544 
   545 void
   546 HIRTranslator::visitImport(HImport *import)
   547 {
   548     __ import(import->index());
   549 }
   550 
   551 void
   552 ke::EmitHIR(Zone *zone, BytecodeEmitter &emitter, HIR *hir)
   553 {
   554     HIRTranslator translator(zone, emitter);
   555     translator.translate(hir);
   556 }