xref: /aosp_15_r20/art/runtime/interpreter/mterp/riscv64/floating_point.S (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker// Note: Floating point operations must follow IEEE 754 rules, using round-to-nearest and gradual
2*795d594fSAndroid Build Coastguard Worker// underflow, except where stated otherwise.
3*795d594fSAndroid Build Coastguard Worker
4*795d594fSAndroid Build Coastguard Worker//
5*795d594fSAndroid Build Coastguard Worker// floating-point comparators vAA, vBB, vCC
6*795d594fSAndroid Build Coastguard Worker// Note: Perform the indicated floating point comparison, setting a to 0 if b == c, 1 if b > c, or
7*795d594fSAndroid Build Coastguard Worker// -1 if b < c. The "bias" listed indicates how NaN comparisons are treated: "gt bias" instructions
8*795d594fSAndroid Build Coastguard Worker// return 1 for NaN comparisons, and "lt bias" instructions return -1.
9*795d594fSAndroid Build Coastguard Worker//
10*795d594fSAndroid Build Coastguard Worker
11*795d594fSAndroid Build Coastguard Worker// cmpl-float vAA, vBB, vCC
12*795d594fSAndroid Build Coastguard Worker// Format 23x: AA|2d CC|BB
13*795d594fSAndroid Build Coastguard Worker// LT bias, if NaN then vAA := -1
14*795d594fSAndroid Build Coastguard Worker%def op_cmpl_float(is_double=False):
15*795d594fSAndroid Build Coastguard Worker   FETCH t1, count=1     // t1 := CC|BB
16*795d594fSAndroid Build Coastguard Worker   srliw t0, xINST, 8    // t0 := AA
17*795d594fSAndroid Build Coastguard Worker   srliw t2, t1, 8       // t2 := CC
18*795d594fSAndroid Build Coastguard Worker   andi t1, t1, 0xFF     // t1 := BB
19*795d594fSAndroid Build Coastguard Worker%  get_vreg_float("ft1", "t1", is_double=is_double)  # ft1 := fp[BB]
20*795d594fSAndroid Build Coastguard Worker%  get_vreg_float("ft2", "t2", is_double=is_double)  # ft2 := fp[CC]
21*795d594fSAndroid Build Coastguard Worker   // Note: Formula "((FLE r,l) - 1) + (FLT r,l)" lifted from compiler.
22*795d594fSAndroid Build Coastguard Worker%  precision = "d" if is_double else "s"
23*795d594fSAndroid Build Coastguard Worker   fle.${precision} t1, ft2, ft1
24*795d594fSAndroid Build Coastguard Worker   flt.${precision} t2, ft2, ft1
25*795d594fSAndroid Build Coastguard Worker   addi t1, t1, -1
26*795d594fSAndroid Build Coastguard Worker   add t2, t2, t1
27*795d594fSAndroid Build Coastguard Worker   FETCH_ADVANCE_INST 2
28*795d594fSAndroid Build Coastguard Worker%  set_vreg("t2", "t0", z0="t1")  # fp[AA] := result
29*795d594fSAndroid Build Coastguard Worker   GET_INST_OPCODE t0
30*795d594fSAndroid Build Coastguard Worker   GOTO_OPCODE t0
31*795d594fSAndroid Build Coastguard Worker
32*795d594fSAndroid Build Coastguard Worker// cmpg-float vvAA, vBB, vCC
33*795d594fSAndroid Build Coastguard Worker// Format 23x: AA|2e CC|BB
34*795d594fSAndroid Build Coastguard Worker// GT bias, if NaN then vAA := 1
35*795d594fSAndroid Build Coastguard Worker%def op_cmpg_float(is_double=False):
36*795d594fSAndroid Build Coastguard Worker   FETCH t1, count=1     // t1 := CC|BB
37*795d594fSAndroid Build Coastguard Worker   srliw t0, xINST, 8    // t0 := AA
38*795d594fSAndroid Build Coastguard Worker   srliw t2, t1, 8       // t2 := CC
39*795d594fSAndroid Build Coastguard Worker   andi t1, t1, 0xFF     // t1 := BB
40*795d594fSAndroid Build Coastguard Worker%  get_vreg_float("ft1", "t1", is_double=is_double)  # ft1 := fp[BB]
41*795d594fSAndroid Build Coastguard Worker%  get_vreg_float("ft2", "t2", is_double=is_double)  # ft2 := fp[CC]
42*795d594fSAndroid Build Coastguard Worker   // Note: Formula "((FLE l,r) ^ 1) - (FLT l,r)" lifted from compiler.
43*795d594fSAndroid Build Coastguard Worker%  precision = "d" if is_double else "s"
44*795d594fSAndroid Build Coastguard Worker   fle.${precision} t1, ft1, ft2
45*795d594fSAndroid Build Coastguard Worker   flt.${precision} t2, ft1, ft2
46*795d594fSAndroid Build Coastguard Worker   xori t1, t1, 1
47*795d594fSAndroid Build Coastguard Worker   sub t2, t1, t2
48*795d594fSAndroid Build Coastguard Worker   FETCH_ADVANCE_INST 2
49*795d594fSAndroid Build Coastguard Worker%  set_vreg("t2", "t0", z0="t1")  # fp[AA] := result
50*795d594fSAndroid Build Coastguard Worker   GET_INST_OPCODE t0
51*795d594fSAndroid Build Coastguard Worker   GOTO_OPCODE t0
52*795d594fSAndroid Build Coastguard Worker
53*795d594fSAndroid Build Coastguard Worker// cmpl-double vAA, vBB, vCC
54*795d594fSAndroid Build Coastguard Worker// Format 23x: AA|2f CC|BB
55*795d594fSAndroid Build Coastguard Worker// LT bias, if NaN then vAA := -1
56*795d594fSAndroid Build Coastguard Worker%def op_cmpl_double():
57*795d594fSAndroid Build Coastguard Worker%  op_cmpl_float(is_double=True)
58*795d594fSAndroid Build Coastguard Worker
59*795d594fSAndroid Build Coastguard Worker// cmpg-double vAA, vBB, vCC
60*795d594fSAndroid Build Coastguard Worker// Format 23x: AA|30 CC|BB
61*795d594fSAndroid Build Coastguard Worker// Note: Formula "((FLE l,r) ^ 1) - (FLT l,r)" lifted from compiler.
62*795d594fSAndroid Build Coastguard Worker// GT bias, if NaN then vAA := 1
63*795d594fSAndroid Build Coastguard Worker%def op_cmpg_double():
64*795d594fSAndroid Build Coastguard Worker%  op_cmpg_float(is_double=True)
65*795d594fSAndroid Build Coastguard Worker
66*795d594fSAndroid Build Coastguard Worker//
67*795d594fSAndroid Build Coastguard Worker// funop vA, vB
68*795d594fSAndroid Build Coastguard Worker// Format 12x: B|A|op
69*795d594fSAndroid Build Coastguard Worker//
70*795d594fSAndroid Build Coastguard Worker
71*795d594fSAndroid Build Coastguard Worker// neg-float vA, vB
72*795d594fSAndroid Build Coastguard Worker// Format 12x: B|A|7f
73*795d594fSAndroid Build Coastguard Worker%def op_neg_float():
74*795d594fSAndroid Build Coastguard Worker%  generic_funop(instr="fneg.s ft0, ft0", dst="s", src="s")
75*795d594fSAndroid Build Coastguard Worker
76*795d594fSAndroid Build Coastguard Worker// neg-double vA, vB
77*795d594fSAndroid Build Coastguard Worker// Format 12x: B|A|80
78*795d594fSAndroid Build Coastguard Worker%def op_neg_double():
79*795d594fSAndroid Build Coastguard Worker%  generic_funop(instr="fneg.d ft0, ft0", dst="d", src="d")
80*795d594fSAndroid Build Coastguard Worker
81*795d594fSAndroid Build Coastguard Worker// int-to-float vA, vB
82*795d594fSAndroid Build Coastguard Worker// Format 12x: B|A|82
83*795d594fSAndroid Build Coastguard Worker// Note: Conversion of int32 to float, using round-to-nearest. This loses precision for some values.
84*795d594fSAndroid Build Coastguard Worker// Note: For ties, the IEEE 754-2008 standard defaults to "roundTiesToEven" for binary floats.
85*795d594fSAndroid Build Coastguard Worker%def op_int_to_float():
86*795d594fSAndroid Build Coastguard Worker%  generic_funop(instr="fcvt.s.w ft0, t1, rne", dst="s", src="w")
87*795d594fSAndroid Build Coastguard Worker
88*795d594fSAndroid Build Coastguard Worker// int-to-double vA, vB
89*795d594fSAndroid Build Coastguard Worker// Format 12x: B|A|83
90*795d594fSAndroid Build Coastguard Worker// Note: Conversion of int32 to double.
91*795d594fSAndroid Build Coastguard Worker%def op_int_to_double():
92*795d594fSAndroid Build Coastguard Worker%  generic_funop(instr="fcvt.d.w ft0, t1", dst="d", src="w")
93*795d594fSAndroid Build Coastguard Worker
94*795d594fSAndroid Build Coastguard Worker// long-to-float vA, vB
95*795d594fSAndroid Build Coastguard Worker// Format 12x: B|A|85
96*795d594fSAndroid Build Coastguard Worker// Note: Conversion of int64 to float, using round-to-nearest. This loses precision for some values.
97*795d594fSAndroid Build Coastguard Worker// Note: For ties, the IEEE 754-2008 standard defaults to "roundTiesToEven" for binary floats.
98*795d594fSAndroid Build Coastguard Worker%def op_long_to_float():
99*795d594fSAndroid Build Coastguard Worker%  generic_funop(instr="fcvt.s.l ft0, t1, rne", dst="s", src="l")
100*795d594fSAndroid Build Coastguard Worker
101*795d594fSAndroid Build Coastguard Worker// long-to-double vA, vB
102*795d594fSAndroid Build Coastguard Worker// Format 12x: B|A|86
103*795d594fSAndroid Build Coastguard Worker// Note: Conversion of int64 to double, using round-to-nearest. This loses precision for some values.
104*795d594fSAndroid Build Coastguard Worker// Note: For ties, the IEEE 754-2008 standard defaults to "roundTiesToEven" for binary floats.
105*795d594fSAndroid Build Coastguard Worker%def op_long_to_double():
106*795d594fSAndroid Build Coastguard Worker%  generic_funop(instr="fcvt.d.l ft0, t1, rne", dst="d", src="l")
107*795d594fSAndroid Build Coastguard Worker
108*795d594fSAndroid Build Coastguard Worker// float-to-int vA, vB
109*795d594fSAndroid Build Coastguard Worker// Format 12x: B|A|87
110*795d594fSAndroid Build Coastguard Worker// Note: Conversion of float to int32, using round-toward-zero. NaN and -0.0 (negative zero)
111*795d594fSAndroid Build Coastguard Worker// convert to the integer 0. Infinities and values with too large a magnitude to be represented
112*795d594fSAndroid Build Coastguard Worker// get converted to either 0x7fffffff or -0x80000000 depending on sign.
113*795d594fSAndroid Build Coastguard Worker//
114*795d594fSAndroid Build Coastguard Worker// FCVT.W.S RTZ has the following behavior:
115*795d594fSAndroid Build Coastguard Worker// - NaN rounds to 0x7ffffff - requires check and set to zero.
116*795d594fSAndroid Build Coastguard Worker// - negative zero rounds to zero - matches dex spec.
117*795d594fSAndroid Build Coastguard Worker// - pos inf rounds to 0x7fffffff - matches dex spec.
118*795d594fSAndroid Build Coastguard Worker// - neg inf rounds to 0x80000000 - matches dex spec.
119*795d594fSAndroid Build Coastguard Worker%def op_float_to_int():
120*795d594fSAndroid Build Coastguard Worker%  generic_funop(instr="fcvt.w.s t1, ft0, rtz", dst="w", src="s", nan_zeroed=True)
121*795d594fSAndroid Build Coastguard Worker
122*795d594fSAndroid Build Coastguard Worker// float-to-long vA, vB
123*795d594fSAndroid Build Coastguard Worker// Format 12x: B|A|88
124*795d594fSAndroid Build Coastguard Worker// Note: Conversion of float to int64, using round-toward-zero. The same special case rules as for
125*795d594fSAndroid Build Coastguard Worker// float-to-int apply here, except that out-of-range values get converted to either
126*795d594fSAndroid Build Coastguard Worker// 0x7fffffffffffffff or -0x8000000000000000 depending on sign.
127*795d594fSAndroid Build Coastguard Worker//
128*795d594fSAndroid Build Coastguard Worker// FCVT.L.S RTZ has the following behavior:
129*795d594fSAndroid Build Coastguard Worker// - NaN rounds to 0x7fffffffffffffff - requires check and set to zero.
130*795d594fSAndroid Build Coastguard Worker// - negative zero rounds to zero - matches dex spec.
131*795d594fSAndroid Build Coastguard Worker// - pos inf rounds to 0x7fffffffffffffff - matches dex spec.
132*795d594fSAndroid Build Coastguard Worker// - neg inf rounds to 0x8000000000000000 - matches dex spec.
133*795d594fSAndroid Build Coastguard Worker%def op_float_to_long():
134*795d594fSAndroid Build Coastguard Worker%  generic_funop(instr="fcvt.l.s t1, ft0, rtz", dst="l", src="s", nan_zeroed=True)
135*795d594fSAndroid Build Coastguard Worker
136*795d594fSAndroid Build Coastguard Worker// float-to-double vA, vB
137*795d594fSAndroid Build Coastguard Worker// Format 12x: B|A|89
138*795d594fSAndroid Build Coastguard Worker// Note: Conversion of float to double, preserving the value exactly.
139*795d594fSAndroid Build Coastguard Worker%def op_float_to_double():
140*795d594fSAndroid Build Coastguard Worker%  generic_funop(instr="fcvt.d.s ft0, ft0", dst="d", src="s")
141*795d594fSAndroid Build Coastguard Worker
142*795d594fSAndroid Build Coastguard Worker// double-to-int vA, vB
143*795d594fSAndroid Build Coastguard Worker// Format 12x: B|A|8a
144*795d594fSAndroid Build Coastguard Worker// Note: Conversion of double to int32, using round-toward-zero. The same special case rules as for
145*795d594fSAndroid Build Coastguard Worker// float-to-int apply here.
146*795d594fSAndroid Build Coastguard Worker%def op_double_to_int():
147*795d594fSAndroid Build Coastguard Worker%  generic_funop(instr="fcvt.w.d t1, ft0, rtz", dst="w", src="d", nan_zeroed=True)
148*795d594fSAndroid Build Coastguard Worker
149*795d594fSAndroid Build Coastguard Worker// double-to-long vA, vB
150*795d594fSAndroid Build Coastguard Worker// Format 12x: B|A|8b
151*795d594fSAndroid Build Coastguard Worker// Note: Conversion of double to int64, using round-toward-zero. The same special case rules as for
152*795d594fSAndroid Build Coastguard Worker// float-to-long apply here.
153*795d594fSAndroid Build Coastguard Worker%def op_double_to_long():
154*795d594fSAndroid Build Coastguard Worker%  generic_funop(instr="fcvt.l.d t1, ft0, rtz", dst="l", src="d", nan_zeroed=True)
155*795d594fSAndroid Build Coastguard Worker
156*795d594fSAndroid Build Coastguard Worker// double-to-float vA, vB
157*795d594fSAndroid Build Coastguard Worker// Format 12x: B|A|8c
158*795d594fSAndroid Build Coastguard Worker// Note: Conversion of double to float, using round-to-nearest. This loses precision for some values.
159*795d594fSAndroid Build Coastguard Worker// Note: For ties, the IEEE 754-2008 standard defaults to "roundTiesToEven" for binary floats.
160*795d594fSAndroid Build Coastguard Worker%def op_double_to_float():
161*795d594fSAndroid Build Coastguard Worker%  generic_funop(instr="fcvt.s.d ft0, ft0, rne", dst="s", src="d")
162*795d594fSAndroid Build Coastguard Worker
163*795d594fSAndroid Build Coastguard Worker// unop boilerplate
164*795d594fSAndroid Build Coastguard Worker// instr: operand held in t1 or ft0, result written to t1 or ft0.
165*795d594fSAndroid Build Coastguard Worker// instr must not clobber t2.
166*795d594fSAndroid Build Coastguard Worker// dst: one of w (int32), l (int64), s (float), d (double)
167*795d594fSAndroid Build Coastguard Worker// src: one of w (int32), l (int64), s (float), d (double)
168*795d594fSAndroid Build Coastguard Worker// Clobbers: ft0, t0, t1, t2
169*795d594fSAndroid Build Coastguard Worker%def generic_funop(instr, dst, src, nan_zeroed=False):
170*795d594fSAndroid Build Coastguard Worker    srliw t0, xINST, 12        // t0 := B
171*795d594fSAndroid Build Coastguard Worker    srliw t2, xINST, 8         // t2 := B|A
172*795d594fSAndroid Build Coastguard Worker
173*795d594fSAndroid Build Coastguard Worker%  if src == "w":
174*795d594fSAndroid Build Coastguard Worker%    get_vreg("t1", "t0")     #  t1 := fp[B]
175*795d594fSAndroid Build Coastguard Worker%  elif src == "l":
176*795d594fSAndroid Build Coastguard Worker     GET_VREG_WIDE t1, t0     // t1 := fp[B]
177*795d594fSAndroid Build Coastguard Worker%  elif src == "s":
178*795d594fSAndroid Build Coastguard Worker%    get_vreg_float("ft0", "t0")  #  ft0 := fp[B]
179*795d594fSAndroid Build Coastguard Worker%  elif src == "d":
180*795d594fSAndroid Build Coastguard Worker     GET_VREG_DOUBLE ft0, t0  // ft0 := fp[B]
181*795d594fSAndroid Build Coastguard Worker%  else:
182*795d594fSAndroid Build Coastguard Worker%    assert false, src
183*795d594fSAndroid Build Coastguard Worker%#:
184*795d594fSAndroid Build Coastguard Worker    and t2, t2, 0xF            // t2 := A
185*795d594fSAndroid Build Coastguard Worker    FETCH_ADVANCE_INST 1       // advance xPC, load xINST
186*795d594fSAndroid Build Coastguard Worker%  if nan_zeroed:
187*795d594fSAndroid Build Coastguard Worker     // Okay to clobber T1. It is not read if nan_zeroed=True.
188*795d594fSAndroid Build Coastguard Worker     fclass.${src} t1, ft0  // fclass.s or fclass.d on the source register ft0
189*795d594fSAndroid Build Coastguard Worker     sltiu t1, t1, 0x100    // t1 := 0 if NaN, per dex spec. Skip the conversion.
190*795d594fSAndroid Build Coastguard Worker     beqz t1, 1f
191*795d594fSAndroid Build Coastguard Worker%#:
192*795d594fSAndroid Build Coastguard Worker    $instr                     // read operand (from t1|ft0), write result (to t1|ft0)
193*795d594fSAndroid Build Coastguard Worker                               // do not clobber t2!
194*795d594fSAndroid Build Coastguard Worker1:
195*795d594fSAndroid Build Coastguard Worker
196*795d594fSAndroid Build Coastguard Worker%  if dst == "w":
197*795d594fSAndroid Build Coastguard Worker%    set_vreg("t1", "t2", z0="t0")   #  fp[A] := t1
198*795d594fSAndroid Build Coastguard Worker%  elif dst == "l":
199*795d594fSAndroid Build Coastguard Worker     SET_VREG_WIDE t1, t2, z0=t0     // fp[A] := t1
200*795d594fSAndroid Build Coastguard Worker%  elif dst == "s":
201*795d594fSAndroid Build Coastguard Worker%    set_vreg_float("ft0", "t2", z0="t0")  # fp[A] := ft0
202*795d594fSAndroid Build Coastguard Worker%  elif dst == "d":
203*795d594fSAndroid Build Coastguard Worker     SET_VREG_DOUBLE ft0, t2, z0=t0  // fp[B] := ft0
204*795d594fSAndroid Build Coastguard Worker%  else:
205*795d594fSAndroid Build Coastguard Worker%    assert false, dst
206*795d594fSAndroid Build Coastguard Worker%#:
207*795d594fSAndroid Build Coastguard Worker
208*795d594fSAndroid Build Coastguard Worker   GET_INST_OPCODE t0         // t0 holds next opcode
209*795d594fSAndroid Build Coastguard Worker   GOTO_OPCODE t0             // continue to next
210*795d594fSAndroid Build Coastguard Worker
211*795d594fSAndroid Build Coastguard Worker//
212*795d594fSAndroid Build Coastguard Worker// fbinop vAA, vBB, vCC
213*795d594fSAndroid Build Coastguard Worker// Format 23x: AA|op CC|BB
214*795d594fSAndroid Build Coastguard Worker//
215*795d594fSAndroid Build Coastguard Worker
216*795d594fSAndroid Build Coastguard Worker// add-float vAA, vBB, vCC
217*795d594fSAndroid Build Coastguard Worker// Format 23x: AA|a6 CC|BB
218*795d594fSAndroid Build Coastguard Worker%def op_add_float():
219*795d594fSAndroid Build Coastguard Worker%  generic_fbinop(instr="fadd.s fa0, fa0, fa1, rne")
220*795d594fSAndroid Build Coastguard Worker
221*795d594fSAndroid Build Coastguard Worker// sub-float vAA, vBB, vCC
222*795d594fSAndroid Build Coastguard Worker// Format 23x: AA|a7 CC|BB
223*795d594fSAndroid Build Coastguard Worker%def op_sub_float():
224*795d594fSAndroid Build Coastguard Worker%  generic_fbinop(instr="fsub.s fa0, fa0, fa1, rne")
225*795d594fSAndroid Build Coastguard Worker
226*795d594fSAndroid Build Coastguard Worker// mul-float vAA, vBB, vCC
227*795d594fSAndroid Build Coastguard Worker// Format 23x: AA|a8 CC|BB
228*795d594fSAndroid Build Coastguard Worker%def op_mul_float():
229*795d594fSAndroid Build Coastguard Worker%  generic_fbinop(instr="fmul.s fa0, fa0, fa1, rne")
230*795d594fSAndroid Build Coastguard Worker
231*795d594fSAndroid Build Coastguard Worker// div-float vAA, vBB, vCC
232*795d594fSAndroid Build Coastguard Worker// Format 23x: AA|a9 CC|BB
233*795d594fSAndroid Build Coastguard Worker%def op_div_float():
234*795d594fSAndroid Build Coastguard Worker%  generic_fbinop(instr="fdiv.s fa0, fa0, fa1, rne")
235*795d594fSAndroid Build Coastguard Worker
236*795d594fSAndroid Build Coastguard Worker// rem-float vAA, vBB, vCC
237*795d594fSAndroid Build Coastguard Worker// Format 23x: AA|aa CC|BB
238*795d594fSAndroid Build Coastguard Worker// Note: Floating point remainder after division. This function is different than IEEE 754 remainder
239*795d594fSAndroid Build Coastguard Worker// and is defined as result == a - roundTowardZero(a / b) * b.
240*795d594fSAndroid Build Coastguard Worker// Note: RISC-V does not offer floating point remainder; use fmodf in libm.
241*795d594fSAndroid Build Coastguard Worker%def op_rem_float():
242*795d594fSAndroid Build Coastguard Worker%  generic_fbinop(instr="call fmodf")
243*795d594fSAndroid Build Coastguard Worker
244*795d594fSAndroid Build Coastguard Worker// add-double vAA, vBB, vCC
245*795d594fSAndroid Build Coastguard Worker// Format 23x: AA|ab CC|BB
246*795d594fSAndroid Build Coastguard Worker%def op_add_double():
247*795d594fSAndroid Build Coastguard Worker%  generic_fbinop(instr="fadd.d fa0, fa0, fa1, rne", is_double=True)
248*795d594fSAndroid Build Coastguard Worker
249*795d594fSAndroid Build Coastguard Worker// sub-double vAA, vBB, vCC
250*795d594fSAndroid Build Coastguard Worker// Format 23x: AA|ac CC|BB
251*795d594fSAndroid Build Coastguard Worker%def op_sub_double():
252*795d594fSAndroid Build Coastguard Worker%  generic_fbinop(instr="fsub.d fa0, fa0, fa1, rne", is_double=True)
253*795d594fSAndroid Build Coastguard Worker
254*795d594fSAndroid Build Coastguard Worker// mul-double vAA, vBB, vCC
255*795d594fSAndroid Build Coastguard Worker// Format 23x: AA|ad CC|BB
256*795d594fSAndroid Build Coastguard Worker%def op_mul_double():
257*795d594fSAndroid Build Coastguard Worker%  generic_fbinop(instr="fmul.d fa0, fa0, fa1, rne", is_double=True)
258*795d594fSAndroid Build Coastguard Worker
259*795d594fSAndroid Build Coastguard Worker// div-double vAA, vBB, vCC
260*795d594fSAndroid Build Coastguard Worker// Format 23x: AA|ae CC|BB
261*795d594fSAndroid Build Coastguard Worker%def op_div_double():
262*795d594fSAndroid Build Coastguard Worker%  generic_fbinop(instr="fdiv.d fa0, fa0, fa1, rne", is_double=True)
263*795d594fSAndroid Build Coastguard Worker
264*795d594fSAndroid Build Coastguard Worker// rem-double vAA, vBB, vCC
265*795d594fSAndroid Build Coastguard Worker// Format 23x: AA|af CC|BB
266*795d594fSAndroid Build Coastguard Worker// Note: Floating point remainder after division. This function is different than IEEE 754 remainder
267*795d594fSAndroid Build Coastguard Worker// and is defined as result == a - roundTowardZero(a / b) * b.
268*795d594fSAndroid Build Coastguard Worker// Note: RISC-V does not offer floating point remainder; use fmod in libm.
269*795d594fSAndroid Build Coastguard Worker%def op_rem_double():
270*795d594fSAndroid Build Coastguard Worker%  generic_fbinop(instr="call fmod", is_double=True)
271*795d594fSAndroid Build Coastguard Worker
272*795d594fSAndroid Build Coastguard Worker// fbinop boilerplate
273*795d594fSAndroid Build Coastguard Worker// instr: operands held in fa0 and fa1, result written to fa0
274*795d594fSAndroid Build Coastguard Worker// instr may be a libm call, so:
275*795d594fSAndroid Build Coastguard Worker//  - avoid caller-save state across instr; s11 is used instead.
276*795d594fSAndroid Build Coastguard Worker//  - fa0 and fa1 are used instead of ft0 and ft1.
277*795d594fSAndroid Build Coastguard Worker//
278*795d594fSAndroid Build Coastguard Worker// The is_double flag ensures vregs are read and written in 64-bit widths.
279*795d594fSAndroid Build Coastguard Worker// Clobbers: t0, t1, fa0, fa1, s11
280*795d594fSAndroid Build Coastguard Worker%def generic_fbinop(instr, is_double=False):
281*795d594fSAndroid Build Coastguard Worker   FETCH t0, count=1     // t0 := CC|BB
282*795d594fSAndroid Build Coastguard Worker   srliw s11, xINST, 8   // s11 := AA
283*795d594fSAndroid Build Coastguard Worker   srliw t1, t0, 8       // t1 := CC
284*795d594fSAndroid Build Coastguard Worker   and t0, t0, 0xFF      // t0 := BB
285*795d594fSAndroid Build Coastguard Worker%  get_vreg_float("fa1", "t1", is_double=is_double)
286*795d594fSAndroid Build Coastguard Worker                         // fa1 := fp[CC]
287*795d594fSAndroid Build Coastguard Worker%  get_vreg_float("fa0", "t0", is_double=is_double)
288*795d594fSAndroid Build Coastguard Worker                         // fa0 := fp[BB]
289*795d594fSAndroid Build Coastguard Worker   FETCH_ADVANCE_INST 2  // advance xPC, load xINST
290*795d594fSAndroid Build Coastguard Worker   $instr                // read fa0 and fa1, write result to fa0.
291*795d594fSAndroid Build Coastguard Worker                         // instr may be a function call.
292*795d594fSAndroid Build Coastguard Worker%  set_vreg_float("fa0", "s11", z0="t0", is_double=is_double)
293*795d594fSAndroid Build Coastguard Worker                         // fp[AA] := fa0
294*795d594fSAndroid Build Coastguard Worker   GET_INST_OPCODE t0    // t0 holds next opcode
295*795d594fSAndroid Build Coastguard Worker   GOTO_OPCODE t0        // continue to next
296*795d594fSAndroid Build Coastguard Worker
297*795d594fSAndroid Build Coastguard Worker//
298*795d594fSAndroid Build Coastguard Worker// fbinop/2addr vA, vB
299*795d594fSAndroid Build Coastguard Worker// Format 12x: B|A|op
300*795d594fSAndroid Build Coastguard Worker//
301*795d594fSAndroid Build Coastguard Worker
302*795d594fSAndroid Build Coastguard Worker// add-float/2addr vA, vB
303*795d594fSAndroid Build Coastguard Worker// Format 12x: B|A|c6
304*795d594fSAndroid Build Coastguard Worker%def op_add_float_2addr():
305*795d594fSAndroid Build Coastguard Worker%  generic_fbinop_2addr(instr="fadd.s fa0, fa0, fa1")
306*795d594fSAndroid Build Coastguard Worker
307*795d594fSAndroid Build Coastguard Worker// sub-float/2addr vA, vB
308*795d594fSAndroid Build Coastguard Worker// Format 12x: B|A|c7
309*795d594fSAndroid Build Coastguard Worker%def op_sub_float_2addr():
310*795d594fSAndroid Build Coastguard Worker%  generic_fbinop_2addr(instr="fsub.s fa0, fa0, fa1")
311*795d594fSAndroid Build Coastguard Worker
312*795d594fSAndroid Build Coastguard Worker// mul-float/2addr vA, vB
313*795d594fSAndroid Build Coastguard Worker// Format 12x: B|A|c8
314*795d594fSAndroid Build Coastguard Worker%def op_mul_float_2addr():
315*795d594fSAndroid Build Coastguard Worker%  generic_fbinop_2addr(instr="fmul.s fa0, fa0, fa1")
316*795d594fSAndroid Build Coastguard Worker
317*795d594fSAndroid Build Coastguard Worker// div-float/2addr vA, vB
318*795d594fSAndroid Build Coastguard Worker// Format 12x: B|A|c9
319*795d594fSAndroid Build Coastguard Worker%def op_div_float_2addr():
320*795d594fSAndroid Build Coastguard Worker%  generic_fbinop_2addr(instr="fdiv.s fa0, fa0, fa1")
321*795d594fSAndroid Build Coastguard Worker
322*795d594fSAndroid Build Coastguard Worker// rem-float/2addr vA, vB
323*795d594fSAndroid Build Coastguard Worker// Format 12x: B|A|ca
324*795d594fSAndroid Build Coastguard Worker// Note: Floating point remainder after division. This function is different than IEEE 754 remainder
325*795d594fSAndroid Build Coastguard Worker// and is defined as result == a - roundTowardZero(a / b) * b.
326*795d594fSAndroid Build Coastguard Worker// Note: RISC-V does not offer floating point remainder; use fmodf in libm.
327*795d594fSAndroid Build Coastguard Worker%def op_rem_float_2addr():
328*795d594fSAndroid Build Coastguard Worker%  generic_fbinop_2addr(instr="call fmodf")
329*795d594fSAndroid Build Coastguard Worker
330*795d594fSAndroid Build Coastguard Worker// add-double/2addr vA, vB
331*795d594fSAndroid Build Coastguard Worker// Format 12x: B|A|cb
332*795d594fSAndroid Build Coastguard Worker%def op_add_double_2addr():
333*795d594fSAndroid Build Coastguard Worker%  generic_fbinop_2addr(instr="fadd.d fa0, fa0, fa1", is_double=True)
334*795d594fSAndroid Build Coastguard Worker
335*795d594fSAndroid Build Coastguard Worker// sub-double/2addr vA, vB
336*795d594fSAndroid Build Coastguard Worker// Format 12x: B|A|cc
337*795d594fSAndroid Build Coastguard Worker%def op_sub_double_2addr():
338*795d594fSAndroid Build Coastguard Worker%  generic_fbinop_2addr(instr="fsub.d fa0, fa0, fa1", is_double=True)
339*795d594fSAndroid Build Coastguard Worker
340*795d594fSAndroid Build Coastguard Worker// mul-double/2addr vA, vB
341*795d594fSAndroid Build Coastguard Worker// Format 12x: B|A|cd
342*795d594fSAndroid Build Coastguard Worker%def op_mul_double_2addr():
343*795d594fSAndroid Build Coastguard Worker%  generic_fbinop_2addr(instr="fmul.d fa0, fa0, fa1", is_double=True)
344*795d594fSAndroid Build Coastguard Worker
345*795d594fSAndroid Build Coastguard Worker// div-double/2addr vA, vB
346*795d594fSAndroid Build Coastguard Worker// Format 12x: B|A|ce
347*795d594fSAndroid Build Coastguard Worker%def op_div_double_2addr():
348*795d594fSAndroid Build Coastguard Worker%  generic_fbinop_2addr(instr="fdiv.d fa0, fa0, fa1", is_double=True)
349*795d594fSAndroid Build Coastguard Worker
350*795d594fSAndroid Build Coastguard Worker// rem-double/2addr vA, vB
351*795d594fSAndroid Build Coastguard Worker// Format 12x: B|A|cf
352*795d594fSAndroid Build Coastguard Worker// Note: Floating point remainder after division. This function is different than IEEE 754 remainder
353*795d594fSAndroid Build Coastguard Worker// and is defined as result == a - roundTowardZero(a / b) * b.
354*795d594fSAndroid Build Coastguard Worker// Note: RISC-V does not offer floating point remainder; use fmod in libm.
355*795d594fSAndroid Build Coastguard Worker%def op_rem_double_2addr():
356*795d594fSAndroid Build Coastguard Worker%  generic_fbinop_2addr(instr="call fmod", is_double=True)
357*795d594fSAndroid Build Coastguard Worker
358*795d594fSAndroid Build Coastguard Worker// fbinop/2addr boilerplate
359*795d594fSAndroid Build Coastguard Worker// instr: operands held in fa0 and fa1, result written to fa0
360*795d594fSAndroid Build Coastguard Worker// instr may be a libm call, so:
361*795d594fSAndroid Build Coastguard Worker//  - avoid caller-save state across instr; s11 is used instead.
362*795d594fSAndroid Build Coastguard Worker//  - use fa0 and fa1 instead of ft0 and ft1.
363*795d594fSAndroid Build Coastguard Worker//
364*795d594fSAndroid Build Coastguard Worker// The is_double flag ensures vregs are read and written in 64-bit widths.
365*795d594fSAndroid Build Coastguard Worker// Clobbers: t0, t1, fa0, fa1, s11
366*795d594fSAndroid Build Coastguard Worker%def generic_fbinop_2addr(instr, is_double=False):
367*795d594fSAndroid Build Coastguard Worker   srliw t0, xINST, 8       // t0 := B|A
368*795d594fSAndroid Build Coastguard Worker   srliw t1, xINST, 12      // t1 := B
369*795d594fSAndroid Build Coastguard Worker   and t0, t0, 0xF          // t0 := A
370*795d594fSAndroid Build Coastguard Worker%  get_vreg_float("fa1", "t1", is_double=is_double)
371*795d594fSAndroid Build Coastguard Worker                             // fa1 := fp[B]
372*795d594fSAndroid Build Coastguard Worker   mv s11, t0               // s11 := A
373*795d594fSAndroid Build Coastguard Worker%  get_vreg_float("fa0", "t0", is_double=is_double)
374*795d594fSAndroid Build Coastguard Worker                             // fa0 := fp[A]
375*795d594fSAndroid Build Coastguard Worker   FETCH_ADVANCE_INST 1     // advance xPC, load xINST
376*795d594fSAndroid Build Coastguard Worker   $instr                   // read fa0 and f1, write result to fa0.
377*795d594fSAndroid Build Coastguard Worker                            // instr may be a function call.
378*795d594fSAndroid Build Coastguard Worker   GET_INST_OPCODE t1       // t1 holds next opcode
379*795d594fSAndroid Build Coastguard Worker%  set_vreg_float("fa0", "s11", z0="t0", is_double=is_double)
380*795d594fSAndroid Build Coastguard Worker                            // fp[A] := fa0
381*795d594fSAndroid Build Coastguard Worker   GOTO_OPCODE t1           // continue to next
382