mirror of https://github.com/ademakov/libjit
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
478 lines
9.8 KiB
478 lines
9.8 KiB
/*
|
|
* 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
|
|
* <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
%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);
|
|
}
|
|
|