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