blob: 1132a09e7c925b05c0e83ba28d9e8540137f98ba [file] [log] [blame]
%def fbinop(instr=""):
/*:
* Generic 32-bit floating-point operation.
*
* For: add-float, sub-float, mul-float, div-float.
* form: <op> f0, f0, f1
*/
/* binop vAA, vBB, vCC */
srl a4, rINST, 8 # a4 <- AA
lbu a2, 2(rPC) # a2 <- BB
lbu a3, 3(rPC) # a3 <- CC
GET_VREG_FLOAT f0, a2 # f0 <- vBB
GET_VREG_FLOAT f1, a3 # f1 <- vCC
$instr # f0 <- f0 op f1
FETCH_ADVANCE_INST 2 # advance rPC, load rINST
GET_INST_OPCODE v0 # extract opcode from rINST
SET_VREG_FLOAT f0, a4 # vAA <- f0
GOTO_OPCODE v0 # jump to next instruction
%def fbinop2addr(instr=""):
/*:
* Generic 32-bit "/2addr" floating-point operation.
*
* For: add-float/2addr, sub-float/2addr, mul-float/2addr, div-float/2addr.
* form: <op> f0, f0, f1
*/
/* binop/2addr vA, vB */
ext a2, rINST, 8, 4 # a2 <- A
ext a3, rINST, 12, 4 # a3 <- B
GET_VREG_FLOAT f0, a2 # f0 <- vA
GET_VREG_FLOAT f1, a3 # f1 <- vB
$instr # f0 <- f0 op f1
FETCH_ADVANCE_INST 1 # advance rPC, load rINST
GET_INST_OPCODE v0 # extract opcode from rINST
SET_VREG_FLOAT f0, a2 # vA <- f0
GOTO_OPCODE v0 # jump to next instruction
%def fbinopWide(instr=""):
/*:
* Generic 64-bit floating-point operation.
*
* For: add-double, sub-double, mul-double, div-double.
* form: <op> f0, f0, f1
*/
/* binop vAA, vBB, vCC */
srl a4, rINST, 8 # a4 <- AA
lbu a2, 2(rPC) # a2 <- BB
lbu a3, 3(rPC) # a3 <- CC
GET_VREG_DOUBLE f0, a2 # f0 <- vBB
GET_VREG_DOUBLE f1, a3 # f1 <- vCC
$instr # f0 <- f0 op f1
FETCH_ADVANCE_INST 2 # advance rPC, load rINST
GET_INST_OPCODE v0 # extract opcode from rINST
SET_VREG_DOUBLE f0, a4 # vAA <- f0
GOTO_OPCODE v0 # jump to next instruction
%def fbinopWide2addr(instr=""):
/*:
* Generic 64-bit "/2addr" floating-point operation.
*
* For: add-double/2addr, sub-double/2addr, mul-double/2addr, div-double/2addr.
* form: <op> f0, f0, f1
*/
/* binop/2addr vA, vB */
ext a2, rINST, 8, 4 # a2 <- A
ext a3, rINST, 12, 4 # a3 <- B
GET_VREG_DOUBLE f0, a2 # f0 <- vA
GET_VREG_DOUBLE f1, a3 # f1 <- vB
$instr # f0 <- f0 op f1
FETCH_ADVANCE_INST 1 # advance rPC, load rINST
GET_INST_OPCODE v0 # extract opcode from rINST
SET_VREG_DOUBLE f0, a2 # vA <- f0
GOTO_OPCODE v0 # jump to next instruction
%def fcmp(gt_bias=""):
/*
* Compare two floating-point values. Puts 0, 1, or -1 into the
* destination register based on the results of the comparison.
*
* For: cmpl-float, cmpg-float
*/
/* op vAA, vBB, vCC */
srl a4, rINST, 8 # a4 <- AA
lbu a2, 2(rPC) # a2 <- BB
lbu a3, 3(rPC) # a3 <- CC
GET_VREG_FLOAT f0, a2 # f0 <- vBB
GET_VREG_FLOAT f1, a3 # f1 <- vCC
cmp.eq.s f2, f0, f1
li a0, 0
bc1nez f2, 1f # done if vBB == vCC (ordered)
.if $gt_bias
cmp.lt.s f2, f0, f1
li a0, -1
bc1nez f2, 1f # done if vBB < vCC (ordered)
li a0, 1 # vBB > vCC or unordered
.else
cmp.lt.s f2, f1, f0
li a0, 1
bc1nez f2, 1f # done if vBB > vCC (ordered)
li a0, -1 # vBB < vCC or unordered
.endif
1:
FETCH_ADVANCE_INST 2 # advance rPC, load rINST
GET_INST_OPCODE v0 # extract opcode from rINST
SET_VREG a0, a4 # vAA <- a0
GOTO_OPCODE v0 # jump to next instruction
%def fcmpWide(gt_bias=""):
/*
* Compare two floating-point values. Puts 0, 1, or -1 into the
* destination register based on the results of the comparison.
*
* For: cmpl-double, cmpg-double
*/
/* op vAA, vBB, vCC */
srl a4, rINST, 8 # a4 <- AA
lbu a2, 2(rPC) # a2 <- BB
lbu a3, 3(rPC) # a3 <- CC
GET_VREG_DOUBLE f0, a2 # f0 <- vBB
GET_VREG_DOUBLE f1, a3 # f1 <- vCC
cmp.eq.d f2, f0, f1
li a0, 0
bc1nez f2, 1f # done if vBB == vCC (ordered)
.if $gt_bias
cmp.lt.d f2, f0, f1
li a0, -1
bc1nez f2, 1f # done if vBB < vCC (ordered)
li a0, 1 # vBB > vCC or unordered
.else
cmp.lt.d f2, f1, f0
li a0, 1
bc1nez f2, 1f # done if vBB > vCC (ordered)
li a0, -1 # vBB < vCC or unordered
.endif
1:
FETCH_ADVANCE_INST 2 # advance rPC, load rINST
GET_INST_OPCODE v0 # extract opcode from rINST
SET_VREG a0, a4 # vAA <- a0
GOTO_OPCODE v0 # jump to next instruction
%def fcvtFooter(suffix="", valreg=""):
/*
* Stores a specified register containing the result of conversion
* from or to a floating-point type and jumps to the next instruction.
*
* Expects a1 to contain the destination Dalvik register number.
* a1 is set up by fcvtHeader.S.
*
* For: int-to-float, int-to-double, long-to-float, long-to-double,
* float-to-int, float-to-long, float-to-double, double-to-int,
* double-to-long, double-to-float, neg-float, neg-double.
*
* Note that this file can't be included after a break in other files
* and in those files its contents appear as a copy.
* See: float-to-int, float-to-long, double-to-int, double-to-long.
*/
GET_INST_OPCODE v0 # extract opcode from rINST
SET_VREG$suffix $valreg, a1
GOTO_OPCODE v0 # jump to next instruction
%def fcvtHeader(suffix="", valreg=""):
/*
* Loads a specified register from vB. Used primarily for conversions
* from or to a floating-point type.
*
* Sets up a1 = A and a2 = B. a2 is later used by fcvtFooter.S to
* store the result in vA and jump to the next instruction.
*
* For: int-to-float, int-to-double, long-to-float, long-to-double,
* float-to-int, float-to-long, float-to-double, double-to-int,
* double-to-long, double-to-float, neg-float, neg-double.
*/
ext a1, rINST, 8, 4 # a1 <- A
srl a2, rINST, 12 # a2 <- B
GET_VREG$suffix $valreg, a2
FETCH_ADVANCE_INST 1 # advance rPC, load rINST
%def op_add_double():
% fbinopWide(instr="add.d f0, f0, f1")
%def op_add_double_2addr():
% fbinopWide2addr(instr="add.d f0, f0, f1")
%def op_add_float():
% fbinop(instr="add.s f0, f0, f1")
%def op_add_float_2addr():
% fbinop2addr(instr="add.s f0, f0, f1")
%def op_cmpg_double():
% fcmpWide(gt_bias="1")
%def op_cmpg_float():
% fcmp(gt_bias="1")
%def op_cmpl_double():
% fcmpWide(gt_bias="0")
%def op_cmpl_float():
% fcmp(gt_bias="0")
%def op_div_double():
% fbinopWide(instr="div.d f0, f0, f1")
%def op_div_double_2addr():
% fbinopWide2addr(instr="div.d f0, f0, f1")
%def op_div_float():
% fbinop(instr="div.s f0, f0, f1")
%def op_div_float_2addr():
% fbinop2addr(instr="div.s f0, f0, f1")
%def op_double_to_float():
/*
* Conversion from or to floating-point happens in a floating-point register.
* Therefore we load the input and store the output into or from a
* floating-point register irrespective of the type.
*/
% fcvtHeader(suffix="_DOUBLE", valreg="f0")
cvt.s.d f0, f0
% fcvtFooter(suffix="_FLOAT", valreg="f0")
%def op_double_to_int():
% fcvtHeader(suffix="_DOUBLE", valreg="f0")
trunc.w.d f0, f0
% fcvtFooter(suffix="_FLOAT", valreg="f0")
%def op_double_to_long():
% fcvtHeader(suffix="_DOUBLE", valreg="f0")
trunc.l.d f0, f0
% fcvtFooter(suffix="_DOUBLE", valreg="f0")
%def op_float_to_double():
/*
* Conversion from or to floating-point happens in a floating-point register.
* Therefore we load the input and store the output into or from a
* floating-point register irrespective of the type.
*/
% fcvtHeader(suffix="_FLOAT", valreg="f0")
cvt.d.s f0, f0
% fcvtFooter(suffix="_DOUBLE", valreg="f0")
%def op_float_to_int():
% fcvtHeader(suffix="_FLOAT", valreg="f0")
trunc.w.s f0, f0
% fcvtFooter(suffix="_FLOAT", valreg="f0")
%def op_float_to_long():
% fcvtHeader(suffix="_FLOAT", valreg="f0")
trunc.l.s f0, f0
% fcvtFooter(suffix="_DOUBLE", valreg="f0")
%def op_int_to_double():
/*
* Conversion from or to floating-point happens in a floating-point register.
* Therefore we load the input and store the output into or from a
* floating-point register irrespective of the type.
*/
% fcvtHeader(suffix="_FLOAT", valreg="f0")
cvt.d.w f0, f0
% fcvtFooter(suffix="_DOUBLE", valreg="f0")
%def op_int_to_float():
/*
* Conversion from or to floating-point happens in a floating-point register.
* Therefore we load the input and store the output into or from a
* floating-point register irrespective of the type.
*/
% fcvtHeader(suffix="_FLOAT", valreg="f0")
cvt.s.w f0, f0
% fcvtFooter(suffix="_FLOAT", valreg="f0")
%def op_long_to_double():
/*
* Conversion from or to floating-point happens in a floating-point register.
* Therefore we load the input and store the output into or from a
* floating-point register irrespective of the type.
*/
% fcvtHeader(suffix="_DOUBLE", valreg="f0")
cvt.d.l f0, f0
% fcvtFooter(suffix="_DOUBLE", valreg="f0")
%def op_long_to_float():
/*
* Conversion from or to floating-point happens in a floating-point register.
* Therefore we load the input and store the output into or from a
* floating-point register irrespective of the type.
*/
% fcvtHeader(suffix="_DOUBLE", valreg="f0")
cvt.s.l f0, f0
% fcvtFooter(suffix="_FLOAT", valreg="f0")
%def op_mul_double():
% fbinopWide(instr="mul.d f0, f0, f1")
%def op_mul_double_2addr():
% fbinopWide2addr(instr="mul.d f0, f0, f1")
%def op_mul_float():
% fbinop(instr="mul.s f0, f0, f1")
%def op_mul_float_2addr():
% fbinop2addr(instr="mul.s f0, f0, f1")
%def op_neg_double():
% fcvtHeader(suffix="_DOUBLE", valreg="f0")
neg.d f0, f0
% fcvtFooter(suffix="_DOUBLE", valreg="f0")
%def op_neg_float():
% fcvtHeader(suffix="_FLOAT", valreg="f0")
neg.s f0, f0
% fcvtFooter(suffix="_FLOAT", valreg="f0")
%def op_rem_double():
/* rem-double vAA, vBB, vCC */
.extern fmod
lbu a2, 2(rPC) # a2 <- BB
lbu a3, 3(rPC) # a3 <- CC
GET_VREG_DOUBLE f12, a2 # f12 <- vBB
GET_VREG_DOUBLE f13, a3 # f13 <- vCC
jal fmod # f0 <- f12 op f13
srl a4, rINST, 8 # a4 <- AA
FETCH_ADVANCE_INST 2 # advance rPC, load rINST
GET_INST_OPCODE v0 # extract opcode from rINST
SET_VREG_DOUBLE f0, a4 # vAA <- f0
GOTO_OPCODE v0 # jump to next instruction
%def op_rem_double_2addr():
/* rem-double/2addr vA, vB */
.extern fmod
ext a2, rINST, 8, 4 # a2 <- A
ext a3, rINST, 12, 4 # a3 <- B
GET_VREG_DOUBLE f12, a2 # f12 <- vA
GET_VREG_DOUBLE f13, a3 # f13 <- vB
jal fmod # f0 <- f12 op f13
ext a2, rINST, 8, 4 # a2 <- A
FETCH_ADVANCE_INST 1 # advance rPC, load rINST
GET_INST_OPCODE v0 # extract opcode from rINST
SET_VREG_DOUBLE f0, a2 # vA <- f0
GOTO_OPCODE v0 # jump to next instruction
%def op_rem_float():
/* rem-float vAA, vBB, vCC */
.extern fmodf
lbu a2, 2(rPC) # a2 <- BB
lbu a3, 3(rPC) # a3 <- CC
GET_VREG_FLOAT f12, a2 # f12 <- vBB
GET_VREG_FLOAT f13, a3 # f13 <- vCC
jal fmodf # f0 <- f12 op f13
srl a4, rINST, 8 # a4 <- AA
FETCH_ADVANCE_INST 2 # advance rPC, load rINST
GET_INST_OPCODE v0 # extract opcode from rINST
SET_VREG_FLOAT f0, a4 # vAA <- f0
GOTO_OPCODE v0 # jump to next instruction
%def op_rem_float_2addr():
/* rem-float/2addr vA, vB */
.extern fmodf
ext a2, rINST, 8, 4 # a2 <- A
ext a3, rINST, 12, 4 # a3 <- B
GET_VREG_FLOAT f12, a2 # f12 <- vA
GET_VREG_FLOAT f13, a3 # f13 <- vB
jal fmodf # f0 <- f12 op f13
ext a2, rINST, 8, 4 # a2 <- A
FETCH_ADVANCE_INST 1 # advance rPC, load rINST
GET_INST_OPCODE v0 # extract opcode from rINST
SET_VREG_FLOAT f0, a2 # vA <- f0
GOTO_OPCODE v0 # jump to next instruction
%def op_sub_double():
% fbinopWide(instr="sub.d f0, f0, f1")
%def op_sub_double_2addr():
% fbinopWide2addr(instr="sub.d f0, f0, f1")
%def op_sub_float():
% fbinop(instr="sub.s f0, f0, f1")
%def op_sub_float_2addr():
% fbinop2addr(instr="sub.s f0, f0, f1")