src/compiler/HIR.cpp
author David Anderson <dvander@alliedmods.net>
Thu Dec 20 00:59:38 2012 -0800 (2012-12-20)
changeset 222 0cde1379b29f
parent 221 0c588a96837c
child 234 26e3035cdffc
permissions -rw-r--r--
Re-added support for reference arguments.
     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 "../Heap-inl.h"
    23 #include "../Handles-inl.h"
    24 
    25 using namespace ke;
    26 
    27 class HIRTranslator : public HIRVisitor
    28 {
    29   public:
    30     HIRTranslator(Zone *zone, BytecodeEmitter &emitter)
    31       : zone_(zone),
    32         emitter_(emitter)
    33     {
    34     }
    35 
    36     void translate(HIR *hir) {
    37         hir->accept(this);
    38     }
    39 
    40     void visitFloat(HFloat *hir);
    41     void visitInteger(HInteger *hir);
    42     void visitCall(HCall *call);
    43     void visitStore(HStore *store);
    44     void visitBinary(HBinary *binary);
    45     void visitLocal(HLocal *local);
    46     void visitGlobal(HGlobal *global);
    47     void visitConvert(HConvert *convert);
    48     void visitIndex(HIndex *index);
    49     void visitPostIncDec(HPostIncDec *hir);
    50     void visitToRef(HToRef *hir);
    51 
    52   private:
    53     Zone *zone_;
    54     BytecodeEmitter &emitter_;
    55 };
    56 
    57 #define __ emitter_.
    58 
    59 void
    60 HIRTranslator::visitFloat(HFloat *hir)
    61 {
    62     __ float_(hir->value());
    63 }
    64 
    65 void
    66 HIRTranslator::visitInteger(HInteger *hir)
    67 {
    68     __ int_(hir->value());
    69 }
    70 
    71 void
    72 HIRTranslator::visitCall(HCall *call)
    73 {
    74     Local<FunctionType> fun(zone_, FunctionType::cast(call->callee()->type()));
    75     
    76     assert(call->args()->length() == fun->parameters()->length());
    77 
    78     __ note_position(call->node()->pos());
    79 
    80     unsigned argc = call->args()->length();
    81     for (size_t i = call->args()->length() - 1; i < call->args()->length(); i--) {
    82         HIR *hir = call->args()->at(i);
    83         hir->accept(this);
    84     }
    85 
    86     call->callee()->accept(this);
    87     __ call(fun, argc);
    88 }
    89 
    90 void
    91 HGlobal::bind(HIRVisitor *visitor, BytecodeEmitter &emitter_)
    92 {
    93 }
    94 
    95 void
    96 HGlobal::hold(BytecodeEmitter &emitter_)
    97 {
    98 }
    99 
   100 void
   101 HGlobal::swapAndPick(BytecodeEmitter &emitter_)
   102 {
   103     __ dup();
   104 }
   105 
   106 void
   107 HGlobal::store(BytecodeEmitter &emitter_)
   108 {
   109     __ setglobal(sym_);
   110 }
   111 
   112 void
   113 HGlobal::load(BytecodeEmitter &emitter_)
   114 {
   115     __ getglobal(sym_);
   116 }
   117 
   118 bool
   119 HGlobal::ref(BytecodeEmitter &emitter_)
   120 {
   121     return false;
   122 }
   123 
   124 static inline Type *
   125 MaybeDereference(Type *type)
   126 {
   127     if (type->isReference())
   128         return ReferenceType::cast(type)->contained();
   129     return type;
   130 }
   131 
   132 HLocal::HLocal(AstNode *node, VariableSymbol *sym)
   133   : HLValue(node, MaybeDereference(sym->type())),
   134     sym_(sym)
   135 {
   136 }
   137 
   138 void
   139 HLocal::bind(HIRVisitor *visitor, BytecodeEmitter &emitter_)
   140 {
   141     if (sym_->type()->isReference()) {
   142         if (sym_->storage() == VariableSymbol::Local)
   143             __ getlocal(sym_);
   144         else if (sym_->storage() == VariableSymbol::Arg)
   145             __ getarg(sym_);
   146         else
   147             assert(false);
   148     }
   149 }
   150 
   151 void
   152 HLocal::hold(BytecodeEmitter &emitter_)
   153 {
   154     if (sym_->type()->isReference())
   155         __ dup();
   156 }
   157 
   158 void
   159 HLocal::swapAndPick(BytecodeEmitter &emitter_)
   160 {
   161     if (sym_->type()->isReference()) {
   162         __ swap();
   163         __ pick2();
   164     } else {
   165         __ dup();
   166     }
   167 }
   168 
   169 void
   170 HLocal::store(BytecodeEmitter &emitter_)
   171 {
   172     if (sym_->type()->isReference()) {
   173         __ setref(ReferenceType::cast(sym_->type())->contained());
   174     } else {
   175         if (sym_->storage() == VariableSymbol::Local)
   176             __ setlocal(sym_);
   177         else if (sym_->storage() == VariableSymbol::Arg)
   178             __ setarg(sym_);
   179         else
   180             assert(false);
   181     }
   182 }
   183 
   184 void
   185 HLocal::load(BytecodeEmitter &emitter_)
   186 {
   187     if (sym_->type()->isReference())
   188         __ getref(ReferenceType::cast(sym_->type())->contained());
   189     else if (sym_->storage() == VariableSymbol::Local)
   190         __ getlocal(sym_);
   191     else if (sym_->storage() == VariableSymbol::Arg)
   192         __ getarg(sym_);
   193     else
   194         assert(false);
   195 }
   196 
   197 bool
   198 HLocal::ref(BytecodeEmitter &emitter_)
   199 {
   200     if (sym_->storage() == VariableSymbol::Heap) {
   201         // Closing over a reference should never pass SemA.
   202         assert(!sym_->type()->isReference());
   203 
   204         // We don't support direct references to heap-allocated locals. This
   205         // should probably be banned in SemA? But for now, just assert. :TODO:
   206         assert(false);
   207         return false;
   208     }
   209         
   210     if (sym_->type()->isReference()) {
   211         if (sym_->storage() == VariableSymbol::Local)
   212             __ getlocal(sym_);
   213         else if (sym_->storage() == VariableSymbol::Arg)
   214             __ getarg(sym_);
   215         else
   216             assert(false);
   217     } else {
   218         __ newref(sym_);
   219     }
   220 
   221     return true;
   222 }
   223 
   224 void
   225 HIndex::bind(HIRVisitor *visitor, BytecodeEmitter &emitter_)
   226 {
   227     __ note_position(node()->pos());
   228     left_->accept(visitor);
   229     right_->accept(visitor);
   230 }
   231 
   232 void
   233 HIndex::hold(BytecodeEmitter &emitter_)
   234 {
   235     __ dup2();
   236 }
   237 
   238 void
   239 HIndex::swapAndPick(BytecodeEmitter &emitter_)
   240 {
   241     // BASE INDEX VALUE
   242     __ roll3();         // INDEX VALUE BASE
   243     __ roll3();         // VALUE BASE INDEX
   244     __ pick3();         // VALUE BASE INDEX VALUE
   245 }
   246 
   247 void
   248 HIndex::store(BytecodeEmitter &emitter_)
   249 {
   250     __ setelem(type());
   251 }
   252 
   253 void
   254 HIndex::load(BytecodeEmitter &emitter_)
   255 {
   256     __ getelem(type());
   257 }
   258 
   259 bool
   260 HIndex::ref(BytecodeEmitter &emitter_)
   261 {
   262     return false;
   263 }
   264 
   265 void
   266 HIRTranslator::visitLocal(HLocal *local)
   267 {
   268     local->bind(this, emitter_);
   269     local->load(emitter_);
   270 }
   271 
   272 void
   273 HIRTranslator::visitIndex(HIndex *index)
   274 {
   275     index->bind(this, emitter_);
   276     index->load(emitter_);
   277 }
   278 
   279 void
   280 HIRTranslator::visitGlobal(HGlobal *global)
   281 {
   282     global->bind(this, emitter_);
   283     global->load(emitter_);
   284 }
   285 
   286 static inline Opcode
   287 TokenToOpcode(TokenKind kind)
   288 {
   289     switch (kind) {
   290       case TOK_PLUS:
   291       case TOK_ASSIGN_ADD:
   292       case TOK_INCREMENT:
   293         return OP_ADD;
   294       case TOK_MINUS:
   295       case TOK_ASSIGN_SUB:
   296       case TOK_DECREMENT:
   297         return OP_SUB;
   298       case TOK_STAR:
   299       case TOK_ASSIGN_MUL:
   300         return OP_MUL;
   301       case TOK_SLASH:
   302       case TOK_ASSIGN_DIV:
   303         return OP_DIV;
   304       case TOK_PERCENT:
   305       case TOK_ASSIGN_MOD:
   306         return OP_MOD;
   307       case TOK_SHR:
   308       case TOK_ASSIGN_SHR:
   309         return OP_SHR;
   310       case TOK_USHR:
   311       case TOK_ASSIGN_USHR:
   312         return OP_USHR;
   313       case TOK_SHL:
   314       case TOK_ASSIGN_SHL:
   315         return OP_SHL;
   316       case TOK_BITAND:
   317       case TOK_ASSIGN_BITAND:
   318         return OP_BITAND;
   319       case TOK_BITOR:
   320       case TOK_ASSIGN_BITOR:
   321         return OP_BITOR;
   322       case TOK_GT:
   323           return OP_GT;
   324       case TOK_GE:
   325           return OP_GE;
   326       case TOK_LT:
   327           return OP_LT;
   328       case TOK_LE:
   329           return OP_LE;
   330       case TOK_EQUALS:
   331           return OP_EQ;
   332       case TOK_NOTEQUALS:
   333           return OP_NE;
   334       default:
   335         assert(kind == TOK_BITXOR);
   336         return OP_BITXOR;
   337     }
   338 }
   339 
   340 void
   341 HIRTranslator::visitStore(HStore *store)
   342 {
   343     store->lval()->bind(this, emitter_);
   344     if (store->kind() == TOK_ASSIGN) {
   345         store->rval()->accept(this);
   346     } else {
   347         // Advanced case: dup the ref, load, op, store.
   348         store->lval()->hold(emitter_);
   349         store->lval()->load(emitter_);
   350         store->rval()->accept(this);
   351         __ binary(TokenToOpcode(store->kind()));
   352     }
   353     store->lval()->store(emitter_);
   354 }
   355 
   356 void
   357 HIRTranslator::visitPostIncDec(HPostIncDec *hir)
   358 {
   359     hir->lval()->bind(this, emitter_);
   360     hir->lval()->hold(emitter_);
   361     hir->lval()->load(emitter_);
   362     hir->lval()->swapAndPick(emitter_);
   363     hir->rval()->accept(this);
   364     __ binary(TokenToOpcode(hir->kind()));
   365     hir->lval()->store(emitter_);
   366     __ pop();
   367 }
   368 
   369 void
   370 HIRTranslator::visitBinary(HBinary *binary)
   371 {
   372     binary->left()->accept(this);
   373     binary->right()->accept(this);
   374 
   375     // We define three sets of math operators:
   376     //
   377     //  (1) ADD, SUB, MUL, DIV, MOD, which take two equal types and produce
   378     //      the same type.
   379     //  (2) LT, LE, GE, GT, EQ, NE, which take two equal types and produce
   380     //      a boolean.
   381     //  (3) SHL, SR, USHR, BITAND, BITOR, BITXOR, BITNOT, which take two
   382     //      equal integer types and return that integer type.
   383     //
   384     Opcode op = TokenToOpcode(binary->token());
   385 
   386     if (op == OP_DIV)
   387         __ note_position(binary->node()->pos());
   388 
   389     if (op >= OP_ADD && op <= OP_NE) {
   390         if (binary->type()->isFloat())
   391             op = Opcode(int(op) + int(OP_ADD_F - OP_ADD));
   392     } else {
   393         assert(binary->type()->isInt32());
   394     }
   395 
   396     __ binary(op);
   397 }
   398 
   399 void
   400 HIRTranslator::visitConvert(HConvert *convert)
   401 {
   402     convert->in()->accept(this);
   403     __ unary(convert->opcode());
   404 }
   405 
   406 void
   407 HIRTranslator::visitToRef(HToRef *hir)
   408 {
   409     HIR *in = hir->in();
   410 
   411     // See if we can bind a direct reference.
   412     if (in->isLValue() && in->toLValue()->ref(emitter_))
   413         return;
   414 
   415     // No, we can't. So instead we create an on-stack reference.
   416     in->accept(this);
   417     __ slotref_lifo();
   418 }
   419 
   420 void
   421 ke::EmitHIR(Zone *zone, BytecodeEmitter &emitter, HIR *hir)
   422 {
   423     HIRTranslator translator(zone, emitter);
   424     translator.translate(hir);
   425 }