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

/*
* 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);
}