/* * jit-rules-alpha.ins - Instruction selector for alpha. * * Copyright (C) 2006 Southern Storm Software, Pty Ltd. * * This file is part of the libjit library. * * The libjit library is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation, either version 2.1 of * the License, or (at your option) any later version. * * The libjit library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with the libjit library. If not, see * . */ %inst_type alpha_inst %regclass reg alpha_reg %regclass lreg alpha_reg %regclass freg alpha_freg /* * Conversion opcodes. */ JIT_OP_TRUNC_SBYTE: [reg] -> { alpha_slli(inst,$1,56,$1); alpha_srai(inst,$1,56,$1); } JIT_OP_TRUNC_UBYTE: [reg] -> { _alpha_li8(inst,ALPHA_AT,0xff); alpha_and(inst,$1,ALPHA_AT,$1); } JIT_OP_TRUNC_SHORT: [reg] -> { alpha_slli(inst,$1,56,$1); alpha_srai(inst,$1,56,$1); } JIT_OP_TRUNC_USHORT: [reg] -> { alpha_slli(inst,$1,56,$1); alpha_srli(inst,$1,56,$1); } /* * TODO: JIT_OP_NFLOAT_TO_FLOAT32 JIT_OP_NFLOAT_TO_FLOAT64 * TODO: JIT_OP_FLOAT32_TO_NFLOAT JIT_OP_FLOAT64_TO_NFLOAT * * Requires floating-point opcodes */ /* * Arithmetic opcodes. * * These operations take the two parameters [$1, $2] and perform the * operation on them and store the result in $1. The format of most of * the alpha arithmetic operations is alpha_opl(inst,sreg0,sreg1,dreg). * For operations with imediate values we use alpha_liN to load the * value into ALPHA_AT, a register reserved for the assembler, before * doing any operations on it. * * Perform an arithmetic operation on signed 32-bit integers. */ /* return value1 + value2; */ JIT_OP_IADD: [=reg, reg, imm, if("$3 == 0")] -> { alpha_mov(inst,$2,$1); } [=reg, reg, reg] -> { alpha_addl(inst,$3,$2,$1); } /* return value1 - value2; */ JIT_OP_ISUB: [=reg, reg, imm, if("$3 == 0")] -> { alpha_mov(inst,$2,$1); } [=reg, reg, reg] -> { alpha_subl(inst,$3,$2,$1); } /* return value1 * value2; */ /* TODO add more trivial IMUL imm rules */ JIT_OP_IMUL: [=reg, reg, imm, if("$3 == 1")] -> { alpha_mov(inst,$2,$1); } [=reg, reg, imm, if("$3 == 0")] -> { alpha_clr(inst,$1); } [=reg, reg, imm, if("$3 == -1")] -> { alpha_subl(inst,$1,ALPHA_ZERO,$2); } [=reg, reg, reg] -> { alpha_mull(inst,$3,$2,$1); } /* * TODO: JIT_OP_IDIV, JIT_OP_IDIV_UN, JIT_OP_IREM, JIT_OP_IREM_UN * * alpha has no integer division instruction, so you have to convert the * value to a float, do floating-point division, and convert the result * back to an integer. This depends on adding floating-point instructions * to jit-gen-alpha.h */ /* return -value1; */ JIT_OP_INEG: [reg] -> { /* Alpha has no neg operation, do $1 = 0 - $1; instead */ alpha_subl(inst,ALPHA_ZERO,$1,$1); } /* return value1 + value2 */ JIT_OP_LADD: [=lreg, lreg, lreg] -> { alpha_addq(inst,$3,$2,$1); } /* return value1 - value2 */ JIT_OP_LSUB: [=lreg, lreg, lreg] -> { alpha_subq(inst,$3,$2,$1); } /* return value1 * value2 */ /* TODO add more trivial LMUL imm rules */ JIT_OP_LMUL: [=lreg, lreg, imm, if("$3 == 1")] -> { alpha_mov(inst,$2,$1); } [=lreg, lreg, imm, if("$3 == 0")] -> { alpha_clr(inst,$1); } [=lreg, lreg, imm, if("$3 == -1")] -> { alpha_subq(inst,$1,ALPHA_ZERO,$2); } [=lreg, lreg, lreg] -> { alpha_mulq(inst,$3,$2,$1); } JIT_OP_LNEG: [lreg] -> { /* Alpha has no neg operation, do $1 = 0 - $1; instead */ alpha_subq(inst,ALPHA_ZERO,$1,$1); } /* * TODO: JIT_OP_FADD, JIT_OP_DADD, JIT_OP_NFADD, JIT_OP_FSUB * TODO: JIT_OP_DSUB, JIT_OP_NFSUB, JIT_OP_FMUL, JIT_OP_DMUL * TODO: JIT_OP_NFMUL, JIT_OP_FDIV, JIT_OP_DDIV, JIT_OP_NFDIV * TODO: JIT_OP_FREM, JIT_OP_DREM, JIT_OP_NFREM, JIT_OP_FREM, * TODO: JIT_OP_DREM, JIT_OP_NFREM, JIT_OP_FNEG, JIT_OP_DNEG, * TODO: JIT_OP_NFNEG * * This depends on adding floating-point instructions to jit-gen-alpha.h */ /* * Bitwise opcodes. */ JIT_OP_IAND: [=reg, reg, reg] -> { alpha_and(inst,$3,$2,$1); } JIT_OP_IOR: [=reg, reg, reg] -> { alpha_or(inst,$3,$2,$1); } JIT_OP_IXOR: [=reg, reg, reg] -> { alpha_xor(inst,$3,$2,$1); } JIT_OP_INOT: [reg] -> { _alpha_li32(inst,ALPHA_AT,0xffffffff); alpha_xor(inst,ALPHA_AT,$1,$1); } /* * TODO: JIT_OP_ISHL JIT_OP_ISHR JIT_OP_ISHR_UN * * The machine instructions operate on 64-bit values. * Some extra masking and clean up will need to be done to get * these to work properly. */ JIT_OP_LAND: [=reg, reg, reg] -> { alpha_and(inst,$3,$2,$1); } JIT_OP_LOR: [=reg, reg, reg] -> { alpha_or(inst,$3,$2,$1); } JIT_OP_LXOR: [=reg, reg, reg] -> { alpha_xor(inst,$3,$2,$1); } JIT_OP_LNOT: [reg] -> { _alpha_li64(inst,ALPHA_AT,0xffffffff); alpha_xor(inst,ALPHA_AT,$1,$1); } JIT_OP_LSHL: [=reg, reg, reg] -> { alpha_sll(inst,$3,$2,$1); } JIT_OP_LSHR: [=reg, reg, reg] -> { alpha_srl(inst,$3,$2,$1); } JIT_OP_LSHR_UN: [=reg, reg, reg] -> { alpha_sra(inst,$3,$2,$1); } /* * Branch opcodes */ JIT_OP_BR: branch [] -> { /* branch if ALPHA_ZERO is zero (this is always true) */ alpha_output_branch(func, inst, ALPHA_OP_BEQ, insn, ALPHA_ZERO); } JIT_OP_BR_IFALSE: branch [reg] -> { /* banch if $1 == 0 */ alpha_output_branch(func, inst, ALPHA_OP_BEQ, insn, $1); } JIT_OP_BR_ITRUE: branch [reg] -> { /* branch if $1 != 0 */ alpha_output_branch(func, inst, ALPHA_OP_BNE, insn, $1); } JIT_OP_BR_IEQ: branch [reg, reg] -> { /* $1 == $2 -> $at */ alpha_cmpeq(inst, $1, $2, ALPHA_AT); /* branch if $at == 1 */ alpha_output_branch(func, inst, ALPHA_OP_BEQ, insn, ALPHA_AT); } JIT_OP_BR_INE: branch [reg, reg] -> { /* $1 == $2 -> $at */ alpha_cmpeq(inst, $1, $2, ALPHA_AT); /* branch if $at == 0 */ alpha_output_branch(func, inst, ALPHA_OP_BNE, insn, ALPHA_AT); } JIT_OP_BR_ILT: branch [reg, reg] -> { /* $1 < $2 -> $at */ alpha_cmplt(inst, $1, $2, ALPHA_AT); /* branch if $at == 1 */ alpha_output_branch(func, inst, ALPHA_OP_BEQ, insn, ALPHA_AT); } JIT_OP_BR_ILT_UN: branch [reg, reg] -> { /* $1 < $2 -> $at */ alpha_cmpult(inst, $1, $2, ALPHA_AT); /* branch if $at == 1 */ alpha_output_branch(func, inst, ALPHA_OP_BEQ, insn, ALPHA_AT); } JIT_OP_BR_ILE: branch [reg, reg] -> { /* $1 <= $2 -> $at */ alpha_cmple(inst, $1, $2, ALPHA_AT); /* branch if $at == 1 */ alpha_output_branch(func, inst, ALPHA_OP_BEQ, insn, ALPHA_AT); } JIT_OP_BR_ILE_UN: branch [reg, reg] -> { /* $1 <= $2 -> $at */ alpha_cmpule(inst, $1, $2, ALPHA_AT); /* branch if $at == 1 */ alpha_output_branch(func, inst, ALPHA_OP_BEQ, insn, ALPHA_AT); } JIT_OP_BR_IGT: branch [reg, reg] -> { /* $1 <= $2 -> $at */ alpha_cmpgt(inst, $1, $2, ALPHA_AT); /* branch if $at == 1 */ alpha_output_branch(func, inst, ALPHA_OP_BEQ, insn, ALPHA_AT); } JIT_OP_BR_IGT_UN: branch [reg, reg] -> { /* $1 > $2 -> $at */ alpha_cmpugt(inst, $1, $2, ALPHA_AT); /* branch if $at == 1 */ alpha_output_branch(func, inst, ALPHA_OP_BEQ, insn, ALPHA_AT); } JIT_OP_BR_IGE: branch [reg, reg] -> { /* $1 >= $2 -> $at */ alpha_cmpge(inst, $1, $2, ALPHA_AT); /* branch if $at == 1 */ alpha_output_branch(func, inst, ALPHA_OP_BEQ, insn, ALPHA_AT); } JIT_OP_BR_IGE_UN: branch [reg, reg] -> { /* $1 >= $2 -> $at */ alpha_cmpuge(inst, $1, $2, ALPHA_AT); /* branch if $at == 1 */ alpha_output_branch(func, inst, ALPHA_OP_BEQ, insn, ALPHA_AT); } /* * Comparison opcodes. */ JIT_OP_IEQ: [=reg, reg, reg] -> { alpha_cmpeq(inst,$3,$2,$1); } JIT_OP_INE: [=reg, reg, reg] -> { alpha_cmpeq(inst,$3,$2,$1); alpha_cmpeq(inst,$1,ALPHA_ZERO,$1); } JIT_OP_ILT: [=reg, reg, reg] -> { alpha_cmplt(inst,$3,$2,$1); } JIT_OP_ILT_UN: [=reg, reg, reg] -> { alpha_cmpult(inst,$3,$2,$1); } JIT_OP_ILE: [=reg, reg, reg] -> { alpha_cmple(inst,$3,$2,$1); } JIT_OP_ILE_UN: [=reg, reg, reg] -> { alpha_cmpule(inst,$3,$2,$1); } /* TODO: JIT_OP_IGT JIT_OP_IGT_UN JIT_OP_IGE JIT_OP_IGE_UN */ /* * Mathematical opcodes. * * TODO: JIT_OP_FATAN, JIT_OP_DATAN, JIT_OP_NFATAN JIT_OP_FCOS, JIT_OP_DCOS, JIT_OP_NFCOS * TODO: JIT_OP_FSIN, JIT_OP_DSIN, JIT_OP_NFSIN JIT_OP_FSQRT, JIT_OP_DSQRT, JIT_OP_NFSQRT * TODO: JIT_OP_FABS, JIT_OP_DABS, JIT_OP_NFABS * * Requires floating-point opcodes */ /* * Pointer check opcodes. */ /* TODO: JIT_OP_CHECK_NULL: note */ /* * Function calls. */ JIT_OP_CALL: [] -> { jit_function_t func = (jit_function_t)(insn->dest); alpha_call(inst, jit_function_to_closure(func)); } /* TODO: JIT_OP_CALL_TAIL, JIT_OP_CALL_INDIRECT, JIT_OP_CALL_VTABLE_PTR */ JIT_OP_RETURN: [] -> { jump_to_epilog(gen, inst, block); } JIT_OP_RETURN_INT: branch [reg] -> { alpha_mov(inst,$1,ALPHA_V0); jump_to_epilog(gen, inst, block); } JIT_OP_RETURN_LONG: branch [reg] -> { alpha_mov(inst,$1,ALPHA_V0); jump_to_epilog(gen, inst, block); } /* TODO: JIT_OP_RETURN_FLOAT32 JIT_OP_RETURN_FLOAT64 JIT_OP_RETURN_NFLOAT */ JIT_OP_CALL_EXTERNAL: [] -> { alpha_call(inst, (insn->dest)); } /* * Stack pushes and pops. */ JIT_OP_RETURN_REG: manual [] -> { /* Nothing to do here */; } JIT_OP_PUSH_INT: note [imm] -> { alpha_li(inst,ALPHA_AT,$1); alpha_stq(inst,ALPHA_AT,ALPHA_SP,0); alpha_lda(inst,ALPHA_SP,ALPHA_SP,-8); } [reg] -> { alpha_stq(inst,$1,ALPHA_SP,0); alpha_lda(inst,ALPHA_SP,ALPHA_SP,-8); } JIT_OP_PUSH_LONG: note [imm] -> { alpha_li(inst,ALPHA_AT,$1); alpha_stq(inst,ALPHA_AT,ALPHA_SP,0); alpha_lda(inst,ALPHA_SP,ALPHA_SP,-8); } [reg] -> { alpha_stq(inst,$1,ALPHA_SP,0); alpha_lda(inst,ALPHA_SP,ALPHA_SP,-8); } JIT_OP_POP_STACK: [] -> { alpha_lda(inst,ALPHA_SP,ALPHA_SP,insn->value1->address); }