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