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