dvander@195: /* vim: set ts=4 sw=4 tw=99 et: dvander@195: * dvander@195: * Copyright (C) 2012 David Anderson dvander@195: * dvander@195: * This file is part of JITCraft. dvander@195: * dvander@195: * JITCraft is free software: you can redistribute it and/or modify it under dvander@195: * the terms of the GNU General Public License as published by the Free dvander@195: * Software Foundation, either version 3 of the License, or (at your option) dvander@195: * any later version. dvander@195: * dvander@195: * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY dvander@195: * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS dvander@195: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. dvander@195: * dvander@195: * You should have received a copy of the GNU General Public License along with dvander@195: * JITCraft. If not, see http://www.gnu.org/licenses/. dvander@195: */ dvander@195: #include "HIR.h" dvander@195: #include "BytecodeEmitter.h" dvander@196: #include "../Heap-inl.h" dvander@196: #include "../Handles-inl.h" dvander@195: dvander@195: using namespace ke; dvander@195: dvander@195: class HIRTranslator : public HIRVisitor dvander@195: { dvander@195: public: dvander@195: HIRTranslator(Zone *zone, BytecodeEmitter &emitter) dvander@195: : zone_(zone), dvander@195: emitter_(emitter) dvander@195: { dvander@195: } dvander@195: dvander@195: void translate(HIR *hir) { dvander@195: hir->accept(this); dvander@195: } dvander@195: dvander@195: void visitFloat(HFloat *hir); dvander@195: void visitInteger(HInteger *hir); dvander@195: void visitCall(HCall *call); dvander@195: void visitStore(HStore *store); dvander@195: void visitBinary(HBinary *binary); dvander@195: void visitLocal(HLocal *local); dvander@195: void visitGlobal(HGlobal *global); dvander@195: void visitConvert(HConvert *convert); dvander@212: void visitIndex(HIndex *index); dvander@218: void visitPostIncDec(HPostIncDec *hir); dvander@195: dvander@195: private: dvander@195: Zone *zone_; dvander@195: BytecodeEmitter &emitter_; dvander@195: }; dvander@195: dvander@195: #define __ emitter_. dvander@195: dvander@195: void dvander@195: HIRTranslator::visitFloat(HFloat *hir) dvander@195: { dvander@195: __ float_(hir->value()); dvander@195: } dvander@195: dvander@195: void dvander@195: HIRTranslator::visitInteger(HInteger *hir) dvander@195: { dvander@195: __ int_(hir->value()); dvander@195: } dvander@195: dvander@195: void dvander@195: HIRTranslator::visitCall(HCall *call) dvander@195: { dvander@195: Local fun(zone_, FunctionType::cast(call->callee()->type())); dvander@195: dvander@195: assert(call->args()->length() == fun->parameters()->length()); dvander@195: dvander@195: unsigned argc = call->args()->length(); dvander@195: dvander@195: for (size_t i = call->args()->length() - 1; i < call->args()->length(); i--) { dvander@195: HIR *hir = call->args()->at(i); dvander@195: hir->accept(this); dvander@195: } dvander@195: dvander@195: call->callee()->accept(this); dvander@195: __ call(fun, argc); dvander@195: } dvander@195: dvander@195: void dvander@195: HGlobal::bind(HIRVisitor *visitor, BytecodeEmitter &emitter_) dvander@195: { dvander@195: } dvander@195: dvander@195: void dvander@215: HGlobal::hold(BytecodeEmitter &emitter_) dvander@215: { dvander@215: } dvander@215: dvander@215: void dvander@218: HGlobal::swapAndPick(BytecodeEmitter &emitter_) dvander@218: { dvander@218: __ dup(); dvander@218: } dvander@218: dvander@218: void dvander@195: HGlobal::store(BytecodeEmitter &emitter_) dvander@195: { dvander@195: __ setglobal(sym_); dvander@195: } dvander@195: dvander@195: void dvander@195: HGlobal::load(BytecodeEmitter &emitter_) dvander@195: { dvander@195: __ getglobal(sym_); dvander@195: } dvander@195: dvander@195: void dvander@195: HLocal::bind(HIRVisitor *visitor, BytecodeEmitter &emitter_) dvander@195: { dvander@195: if (sym_->type()->isReference()) dvander@195: __ getlocal(sym_); dvander@195: } dvander@195: dvander@195: void dvander@215: HLocal::hold(BytecodeEmitter &emitter_) dvander@215: { dvander@215: if (sym_->type()->isReference()) dvander@215: __ dup(); dvander@215: } dvander@215: dvander@215: void dvander@218: HLocal::swapAndPick(BytecodeEmitter &emitter_) dvander@218: { dvander@218: if (sym_->type()->isReference()) { dvander@218: __ swap(); dvander@218: __ pick2(); dvander@218: } else { dvander@218: __ dup(); dvander@218: } dvander@218: } dvander@218: dvander@218: void dvander@195: HLocal::store(BytecodeEmitter &emitter_) dvander@195: { dvander@195: if (sym_->type()->isReference()) dvander@209: __ setref(sym_->type()->contained_ref()); dvander@195: else dvander@195: __ setlocal(sym_); dvander@195: } dvander@195: dvander@195: void dvander@195: HLocal::load(BytecodeEmitter &emitter_) dvander@195: { dvander@195: if (sym_->type()->isReference()) dvander@195: __ getref(sym_->type()); dvander@195: else dvander@195: __ getlocal(sym_); dvander@195: } dvander@195: dvander@195: void dvander@195: HIndex::bind(HIRVisitor *visitor, BytecodeEmitter &emitter_) dvander@195: { dvander@195: left_->accept(visitor); dvander@195: right_->accept(visitor); dvander@195: } dvander@195: dvander@195: void dvander@215: HIndex::hold(BytecodeEmitter &emitter_) dvander@215: { dvander@215: __ dup2(); dvander@215: } dvander@215: dvander@215: void dvander@218: HIndex::swapAndPick(BytecodeEmitter &emitter_) dvander@218: { dvander@218: // BASE INDEX VALUE dvander@218: __ roll3(); // INDEX VALUE BASE dvander@218: __ roll3(); // VALUE BASE INDEX dvander@218: __ pick3(); // VALUE BASE INDEX VALUE dvander@218: } dvander@218: dvander@218: void dvander@195: HIndex::store(BytecodeEmitter &emitter_) dvander@195: { dvander@195: __ setelem(type()); dvander@195: } dvander@195: dvander@195: void dvander@195: HIndex::load(BytecodeEmitter &emitter_) dvander@195: { dvander@195: __ getelem(type()); dvander@195: } dvander@195: dvander@195: void dvander@195: HIRTranslator::visitLocal(HLocal *local) dvander@195: { dvander@195: local->bind(this, emitter_); dvander@195: local->load(emitter_); dvander@195: } dvander@195: dvander@195: void dvander@212: HIRTranslator::visitIndex(HIndex *index) dvander@212: { dvander@212: index->bind(this, emitter_); dvander@212: index->load(emitter_); dvander@212: } dvander@212: dvander@212: void dvander@195: HIRTranslator::visitGlobal(HGlobal *global) dvander@195: { dvander@195: __ getglobal(global->sym()); dvander@195: } dvander@195: dvander@195: static inline Opcode dvander@195: TokenToOpcode(TokenKind kind) dvander@195: { dvander@195: switch (kind) { dvander@195: case TOK_PLUS: dvander@215: case TOK_ASSIGN_ADD: dvander@217: case TOK_INCREMENT: dvander@195: return OP_ADD; dvander@195: case TOK_MINUS: dvander@215: case TOK_ASSIGN_SUB: dvander@217: case TOK_DECREMENT: dvander@195: return OP_SUB; dvander@195: case TOK_STAR: dvander@215: case TOK_ASSIGN_MUL: dvander@195: return OP_MUL; dvander@195: case TOK_SLASH: dvander@215: case TOK_ASSIGN_DIV: dvander@195: return OP_DIV; dvander@195: case TOK_PERCENT: dvander@215: case TOK_ASSIGN_MOD: dvander@195: return OP_MOD; dvander@195: case TOK_SHR: dvander@215: case TOK_ASSIGN_SHR: dvander@195: return OP_SHR; dvander@195: case TOK_USHR: dvander@215: case TOK_ASSIGN_USHR: dvander@195: return OP_USHR; dvander@195: case TOK_SHL: dvander@215: case TOK_ASSIGN_SHL: dvander@195: return OP_SHL; dvander@195: case TOK_BITAND: dvander@215: case TOK_ASSIGN_BITAND: dvander@195: return OP_BITAND; dvander@195: case TOK_BITOR: dvander@215: case TOK_ASSIGN_BITOR: dvander@195: return OP_BITOR; dvander@195: case TOK_GT: dvander@195: return OP_GT; dvander@195: case TOK_GE: dvander@195: return OP_GE; dvander@195: case TOK_LT: dvander@195: return OP_LT; dvander@195: case TOK_LE: dvander@195: return OP_LE; dvander@195: case TOK_EQUALS: dvander@195: return OP_EQ; dvander@195: case TOK_NOTEQUALS: dvander@195: return OP_NE; dvander@195: default: dvander@195: assert(kind == TOK_BITXOR); dvander@195: return OP_BITXOR; dvander@195: } dvander@195: } dvander@195: dvander@195: void dvander@215: HIRTranslator::visitStore(HStore *store) dvander@215: { dvander@215: store->lval()->bind(this, emitter_); dvander@215: if (store->kind() == TOK_ASSIGN) { dvander@215: store->rval()->accept(this); dvander@215: } else { dvander@215: // Advanced case: dup the ref, load, op, store. dvander@215: store->lval()->hold(emitter_); dvander@215: store->lval()->load(emitter_); dvander@215: store->rval()->accept(this); dvander@215: __ binary(TokenToOpcode(store->kind())); dvander@215: } dvander@215: store->lval()->store(emitter_); dvander@215: } dvander@215: dvander@215: void dvander@218: HIRTranslator::visitPostIncDec(HPostIncDec *hir) dvander@218: { dvander@218: hir->lval()->bind(this, emitter_); dvander@218: hir->lval()->hold(emitter_); dvander@218: hir->lval()->load(emitter_); dvander@218: hir->lval()->swapAndPick(emitter_); dvander@218: hir->rval()->accept(this); dvander@218: __ binary(TokenToOpcode(hir->kind())); dvander@218: hir->lval()->store(emitter_); dvander@218: __ pop(); dvander@218: } dvander@218: dvander@218: void dvander@195: HIRTranslator::visitBinary(HBinary *binary) dvander@195: { dvander@195: binary->left()->accept(this); dvander@195: binary->right()->accept(this); dvander@195: dvander@195: // We define three sets of math operators: dvander@195: // dvander@195: // (1) ADD, SUB, MUL, DIV, MOD, which take two equal types and produce dvander@195: // the same type. dvander@195: // (2) LT, LE, GE, GT, EQ, NE, which take two equal types and produce dvander@195: // a boolean. dvander@195: // (3) SHL, SR, USHR, BITAND, BITOR, BITXOR, BITNOT, which take two dvander@195: // equal integer types and return that integer type. dvander@195: // dvander@195: Opcode op = TokenToOpcode(binary->token()); dvander@195: dvander@195: if (op >= OP_ADD && op <= OP_NE) { dvander@195: if (binary->type()->isFloat()) dvander@195: op = Opcode(int(op) + int(OP_ADD_F - OP_ADD)); dvander@195: } else { dvander@195: assert(binary->type()->isInt32()); dvander@195: } dvander@195: dvander@195: __ binary(op); dvander@195: } dvander@195: dvander@195: void dvander@195: HIRTranslator::visitConvert(HConvert *convert) dvander@195: { dvander@195: convert->in()->accept(this); dvander@195: __ unary(convert->opcode()); dvander@195: } dvander@195: dvander@195: void dvander@195: ke::EmitHIR(Zone *zone, BytecodeEmitter &emitter, HIR *hir) dvander@195: { dvander@195: HIRTranslator translator(zone, emitter); dvander@195: translator.translate(hir); dvander@195: }