xref: /openbmc/qemu/target/loongarch/tcg/insn_trans/trans_arith.c.inc (revision 8188c3cda586dc445cac875b7d21c0c960dbe97e)
1*5c23704eSSong Gao/* SPDX-License-Identifier: GPL-2.0-or-later */
2*5c23704eSSong Gao/*
3*5c23704eSSong Gao * Copyright (c) 2021 Loongson Technology Corporation Limited
4*5c23704eSSong Gao */
5*5c23704eSSong Gao
6*5c23704eSSong Gaostatic bool gen_rrr(DisasContext *ctx, arg_rrr *a,
7*5c23704eSSong Gao                    DisasExtend src1_ext, DisasExtend src2_ext,
8*5c23704eSSong Gao                    DisasExtend dst_ext, void (*func)(TCGv, TCGv, TCGv))
9*5c23704eSSong Gao{
10*5c23704eSSong Gao    TCGv dest = gpr_dst(ctx, a->rd, dst_ext);
11*5c23704eSSong Gao    TCGv src1 = gpr_src(ctx, a->rj, src1_ext);
12*5c23704eSSong Gao    TCGv src2 = gpr_src(ctx, a->rk, src2_ext);
13*5c23704eSSong Gao
14*5c23704eSSong Gao    func(dest, src1, src2);
15*5c23704eSSong Gao    gen_set_gpr(a->rd, dest, dst_ext);
16*5c23704eSSong Gao
17*5c23704eSSong Gao    return true;
18*5c23704eSSong Gao}
19*5c23704eSSong Gao
20*5c23704eSSong Gaostatic bool gen_rri_v(DisasContext *ctx, arg_rr_i *a,
21*5c23704eSSong Gao                      DisasExtend src_ext, DisasExtend dst_ext,
22*5c23704eSSong Gao                      void (*func)(TCGv, TCGv, TCGv))
23*5c23704eSSong Gao{
24*5c23704eSSong Gao    TCGv dest = gpr_dst(ctx, a->rd, dst_ext);
25*5c23704eSSong Gao    TCGv src1 = gpr_src(ctx, a->rj, src_ext);
26*5c23704eSSong Gao    TCGv src2 = tcg_constant_tl(a->imm);
27*5c23704eSSong Gao
28*5c23704eSSong Gao    func(dest, src1, src2);
29*5c23704eSSong Gao    gen_set_gpr(a->rd, dest, dst_ext);
30*5c23704eSSong Gao
31*5c23704eSSong Gao    return true;
32*5c23704eSSong Gao}
33*5c23704eSSong Gao
34*5c23704eSSong Gaostatic bool gen_rri_c(DisasContext *ctx, arg_rr_i *a,
35*5c23704eSSong Gao                      DisasExtend src_ext, DisasExtend dst_ext,
36*5c23704eSSong Gao                      void (*func)(TCGv, TCGv, target_long))
37*5c23704eSSong Gao{
38*5c23704eSSong Gao    TCGv dest = gpr_dst(ctx, a->rd, dst_ext);
39*5c23704eSSong Gao    TCGv src1 = gpr_src(ctx, a->rj, src_ext);
40*5c23704eSSong Gao
41*5c23704eSSong Gao    func(dest, src1, a->imm);
42*5c23704eSSong Gao    gen_set_gpr(a->rd, dest, dst_ext);
43*5c23704eSSong Gao
44*5c23704eSSong Gao    return true;
45*5c23704eSSong Gao}
46*5c23704eSSong Gao
47*5c23704eSSong Gaostatic bool gen_rrr_sa(DisasContext *ctx, arg_rrr_sa *a,
48*5c23704eSSong Gao                       DisasExtend src_ext, DisasExtend dst_ext,
49*5c23704eSSong Gao                       void (*func)(TCGv, TCGv, TCGv, target_long))
50*5c23704eSSong Gao{
51*5c23704eSSong Gao    TCGv dest = gpr_dst(ctx, a->rd, dst_ext);
52*5c23704eSSong Gao    TCGv src1 = gpr_src(ctx, a->rj, src_ext);
53*5c23704eSSong Gao    TCGv src2 = gpr_src(ctx, a->rk, src_ext);
54*5c23704eSSong Gao
55*5c23704eSSong Gao    func(dest, src1, src2, a->sa);
56*5c23704eSSong Gao    gen_set_gpr(a->rd, dest, dst_ext);
57*5c23704eSSong Gao
58*5c23704eSSong Gao    return true;
59*5c23704eSSong Gao}
60*5c23704eSSong Gao
61*5c23704eSSong Gaostatic bool trans_lu12i_w(DisasContext *ctx, arg_lu12i_w *a)
62*5c23704eSSong Gao{
63*5c23704eSSong Gao    TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE);
64*5c23704eSSong Gao
65*5c23704eSSong Gao    tcg_gen_movi_tl(dest, a->imm << 12);
66*5c23704eSSong Gao    gen_set_gpr(a->rd, dest, EXT_NONE);
67*5c23704eSSong Gao
68*5c23704eSSong Gao    return true;
69*5c23704eSSong Gao}
70*5c23704eSSong Gao
71*5c23704eSSong Gaostatic bool gen_pc(DisasContext *ctx, arg_r_i *a,
72*5c23704eSSong Gao                   target_ulong (*func)(target_ulong, int))
73*5c23704eSSong Gao{
74*5c23704eSSong Gao    TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE);
75*5c23704eSSong Gao    target_ulong addr = make_address_pc(ctx, func(ctx->base.pc_next, a->imm));
76*5c23704eSSong Gao
77*5c23704eSSong Gao    tcg_gen_movi_tl(dest, addr);
78*5c23704eSSong Gao    gen_set_gpr(a->rd, dest, EXT_NONE);
79*5c23704eSSong Gao
80*5c23704eSSong Gao    return true;
81*5c23704eSSong Gao}
82*5c23704eSSong Gao
83*5c23704eSSong Gaostatic void gen_slt(TCGv dest, TCGv src1, TCGv src2)
84*5c23704eSSong Gao{
85*5c23704eSSong Gao    tcg_gen_setcond_tl(TCG_COND_LT, dest, src1, src2);
86*5c23704eSSong Gao}
87*5c23704eSSong Gao
88*5c23704eSSong Gaostatic void gen_sltu(TCGv dest, TCGv src1, TCGv src2)
89*5c23704eSSong Gao{
90*5c23704eSSong Gao    tcg_gen_setcond_tl(TCG_COND_LTU, dest, src1, src2);
91*5c23704eSSong Gao}
92*5c23704eSSong Gao
93*5c23704eSSong Gaostatic void gen_mulh_w(TCGv dest, TCGv src1, TCGv src2)
94*5c23704eSSong Gao{
95*5c23704eSSong Gao    tcg_gen_mul_i64(dest, src1, src2);
96*5c23704eSSong Gao    tcg_gen_sari_i64(dest, dest, 32);
97*5c23704eSSong Gao}
98*5c23704eSSong Gao
99*5c23704eSSong Gaostatic void gen_mulh_d(TCGv dest, TCGv src1, TCGv src2)
100*5c23704eSSong Gao{
101*5c23704eSSong Gao    TCGv discard = tcg_temp_new();
102*5c23704eSSong Gao    tcg_gen_muls2_tl(discard, dest, src1, src2);
103*5c23704eSSong Gao}
104*5c23704eSSong Gao
105*5c23704eSSong Gaostatic void gen_mulh_du(TCGv dest, TCGv src1, TCGv src2)
106*5c23704eSSong Gao{
107*5c23704eSSong Gao    TCGv discard = tcg_temp_new();
108*5c23704eSSong Gao    tcg_gen_mulu2_tl(discard, dest, src1, src2);
109*5c23704eSSong Gao}
110*5c23704eSSong Gao
111*5c23704eSSong Gaostatic void prep_divisor_d(TCGv ret, TCGv src1, TCGv src2)
112*5c23704eSSong Gao{
113*5c23704eSSong Gao    TCGv t0 = tcg_temp_new();
114*5c23704eSSong Gao    TCGv t1 = tcg_temp_new();
115*5c23704eSSong Gao    TCGv zero = tcg_constant_tl(0);
116*5c23704eSSong Gao
117*5c23704eSSong Gao    /*
118*5c23704eSSong Gao     * If min / -1, set the divisor to 1.
119*5c23704eSSong Gao     * This avoids potential host overflow trap and produces min.
120*5c23704eSSong Gao     * If x / 0, set the divisor to 1.
121*5c23704eSSong Gao     * This avoids potential host overflow trap;
122*5c23704eSSong Gao     * the required result is undefined.
123*5c23704eSSong Gao     */
124*5c23704eSSong Gao    tcg_gen_setcondi_tl(TCG_COND_EQ, ret, src1, INT64_MIN);
125*5c23704eSSong Gao    tcg_gen_setcondi_tl(TCG_COND_EQ, t0, src2, -1);
126*5c23704eSSong Gao    tcg_gen_setcondi_tl(TCG_COND_EQ, t1, src2, 0);
127*5c23704eSSong Gao    tcg_gen_and_tl(ret, ret, t0);
128*5c23704eSSong Gao    tcg_gen_or_tl(ret, ret, t1);
129*5c23704eSSong Gao    tcg_gen_movcond_tl(TCG_COND_NE, ret, ret, zero, ret, src2);
130*5c23704eSSong Gao}
131*5c23704eSSong Gao
132*5c23704eSSong Gaostatic void prep_divisor_du(TCGv ret, TCGv src2)
133*5c23704eSSong Gao{
134*5c23704eSSong Gao    TCGv zero = tcg_constant_tl(0);
135*5c23704eSSong Gao    TCGv one = tcg_constant_tl(1);
136*5c23704eSSong Gao
137*5c23704eSSong Gao    /*
138*5c23704eSSong Gao     * If x / 0, set the divisor to 1.
139*5c23704eSSong Gao     * This avoids potential host overflow trap;
140*5c23704eSSong Gao     * the required result is undefined.
141*5c23704eSSong Gao     */
142*5c23704eSSong Gao    tcg_gen_movcond_tl(TCG_COND_EQ, ret, src2, zero, one, src2);
143*5c23704eSSong Gao}
144*5c23704eSSong Gao
145*5c23704eSSong Gaostatic void gen_div_d(TCGv dest, TCGv src1, TCGv src2)
146*5c23704eSSong Gao{
147*5c23704eSSong Gao    TCGv t0 = tcg_temp_new();
148*5c23704eSSong Gao    prep_divisor_d(t0, src1, src2);
149*5c23704eSSong Gao    tcg_gen_div_tl(dest, src1, t0);
150*5c23704eSSong Gao}
151*5c23704eSSong Gao
152*5c23704eSSong Gaostatic void gen_rem_d(TCGv dest, TCGv src1, TCGv src2)
153*5c23704eSSong Gao{
154*5c23704eSSong Gao    TCGv t0 = tcg_temp_new();
155*5c23704eSSong Gao    prep_divisor_d(t0, src1, src2);
156*5c23704eSSong Gao    tcg_gen_rem_tl(dest, src1, t0);
157*5c23704eSSong Gao}
158*5c23704eSSong Gao
159*5c23704eSSong Gaostatic void gen_div_du(TCGv dest, TCGv src1, TCGv src2)
160*5c23704eSSong Gao{
161*5c23704eSSong Gao    TCGv t0 = tcg_temp_new();
162*5c23704eSSong Gao    prep_divisor_du(t0, src2);
163*5c23704eSSong Gao    tcg_gen_divu_tl(dest, src1, t0);
164*5c23704eSSong Gao}
165*5c23704eSSong Gao
166*5c23704eSSong Gaostatic void gen_rem_du(TCGv dest, TCGv src1, TCGv src2)
167*5c23704eSSong Gao{
168*5c23704eSSong Gao    TCGv t0 = tcg_temp_new();
169*5c23704eSSong Gao    prep_divisor_du(t0, src2);
170*5c23704eSSong Gao    tcg_gen_remu_tl(dest, src1, t0);
171*5c23704eSSong Gao}
172*5c23704eSSong Gao
173*5c23704eSSong Gaostatic void gen_div_w(TCGv dest, TCGv src1, TCGv src2)
174*5c23704eSSong Gao{
175*5c23704eSSong Gao    TCGv t0 = tcg_temp_new();
176*5c23704eSSong Gao    /* We need not check for integer overflow for div_w. */
177*5c23704eSSong Gao    prep_divisor_du(t0, src2);
178*5c23704eSSong Gao    tcg_gen_div_tl(dest, src1, t0);
179*5c23704eSSong Gao}
180*5c23704eSSong Gao
181*5c23704eSSong Gaostatic void gen_rem_w(TCGv dest, TCGv src1, TCGv src2)
182*5c23704eSSong Gao{
183*5c23704eSSong Gao    TCGv t0 = tcg_temp_new();
184*5c23704eSSong Gao    /* We need not check for integer overflow for rem_w. */
185*5c23704eSSong Gao    prep_divisor_du(t0, src2);
186*5c23704eSSong Gao    tcg_gen_rem_tl(dest, src1, t0);
187*5c23704eSSong Gao}
188*5c23704eSSong Gao
189*5c23704eSSong Gaostatic void gen_alsl(TCGv dest, TCGv src1, TCGv src2, target_long sa)
190*5c23704eSSong Gao{
191*5c23704eSSong Gao    TCGv t0 = tcg_temp_new();
192*5c23704eSSong Gao    tcg_gen_shli_tl(t0, src1, sa);
193*5c23704eSSong Gao    tcg_gen_add_tl(dest, t0, src2);
194*5c23704eSSong Gao}
195*5c23704eSSong Gao
196*5c23704eSSong Gaostatic bool trans_lu32i_d(DisasContext *ctx, arg_lu32i_d *a)
197*5c23704eSSong Gao{
198*5c23704eSSong Gao    TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE);
199*5c23704eSSong Gao    TCGv src1 = gpr_src(ctx, a->rd, EXT_NONE);
200*5c23704eSSong Gao    TCGv src2 = tcg_constant_tl(a->imm);
201*5c23704eSSong Gao
202*5c23704eSSong Gao    if (!avail_64(ctx)) {
203*5c23704eSSong Gao        return false;
204*5c23704eSSong Gao    }
205*5c23704eSSong Gao
206*5c23704eSSong Gao    tcg_gen_deposit_tl(dest, src1, src2, 32, 32);
207*5c23704eSSong Gao    gen_set_gpr(a->rd, dest, EXT_NONE);
208*5c23704eSSong Gao
209*5c23704eSSong Gao    return true;
210*5c23704eSSong Gao}
211*5c23704eSSong Gao
212*5c23704eSSong Gaostatic bool trans_lu52i_d(DisasContext *ctx, arg_lu52i_d *a)
213*5c23704eSSong Gao{
214*5c23704eSSong Gao    TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE);
215*5c23704eSSong Gao    TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
216*5c23704eSSong Gao    TCGv src2 = tcg_constant_tl(a->imm);
217*5c23704eSSong Gao
218*5c23704eSSong Gao    if (!avail_64(ctx)) {
219*5c23704eSSong Gao        return false;
220*5c23704eSSong Gao    }
221*5c23704eSSong Gao
222*5c23704eSSong Gao    tcg_gen_deposit_tl(dest, src1, src2, 52, 12);
223*5c23704eSSong Gao    gen_set_gpr(a->rd, dest, EXT_NONE);
224*5c23704eSSong Gao
225*5c23704eSSong Gao    return true;
226*5c23704eSSong Gao}
227*5c23704eSSong Gao
228*5c23704eSSong Gaostatic target_ulong gen_pcaddi(target_ulong pc, int imm)
229*5c23704eSSong Gao{
230*5c23704eSSong Gao    return pc + (imm << 2);
231*5c23704eSSong Gao}
232*5c23704eSSong Gao
233*5c23704eSSong Gaostatic target_ulong gen_pcalau12i(target_ulong pc, int imm)
234*5c23704eSSong Gao{
235*5c23704eSSong Gao    return (pc + (imm << 12)) & ~0xfff;
236*5c23704eSSong Gao}
237*5c23704eSSong Gao
238*5c23704eSSong Gaostatic target_ulong gen_pcaddu12i(target_ulong pc, int imm)
239*5c23704eSSong Gao{
240*5c23704eSSong Gao    return pc + (imm << 12);
241*5c23704eSSong Gao}
242*5c23704eSSong Gao
243*5c23704eSSong Gaostatic target_ulong gen_pcaddu18i(target_ulong pc, int imm)
244*5c23704eSSong Gao{
245*5c23704eSSong Gao    return pc + ((target_ulong)(imm) << 18);
246*5c23704eSSong Gao}
247*5c23704eSSong Gao
248*5c23704eSSong Gaostatic bool trans_addu16i_d(DisasContext *ctx, arg_addu16i_d *a)
249*5c23704eSSong Gao{
250*5c23704eSSong Gao    TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE);
251*5c23704eSSong Gao    TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
252*5c23704eSSong Gao
253*5c23704eSSong Gao    if (!avail_64(ctx)) {
254*5c23704eSSong Gao        return false;
255*5c23704eSSong Gao    }
256*5c23704eSSong Gao
257*5c23704eSSong Gao    tcg_gen_addi_tl(dest, src1, a->imm << 16);
258*5c23704eSSong Gao    gen_set_gpr(a->rd, dest, EXT_NONE);
259*5c23704eSSong Gao
260*5c23704eSSong Gao    return true;
261*5c23704eSSong Gao}
262*5c23704eSSong Gao
263*5c23704eSSong GaoTRANS(add_w, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_SIGN, tcg_gen_add_tl)
264*5c23704eSSong GaoTRANS(add_d, 64, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_add_tl)
265*5c23704eSSong GaoTRANS(sub_w, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_SIGN, tcg_gen_sub_tl)
266*5c23704eSSong GaoTRANS(sub_d, 64, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_sub_tl)
267*5c23704eSSong GaoTRANS(and, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_and_tl)
268*5c23704eSSong GaoTRANS(or, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_or_tl)
269*5c23704eSSong GaoTRANS(xor, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_xor_tl)
270*5c23704eSSong GaoTRANS(nor, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_nor_tl)
271*5c23704eSSong GaoTRANS(andn, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_andc_tl)
272*5c23704eSSong GaoTRANS(orn, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_orc_tl)
273*5c23704eSSong GaoTRANS(slt, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_slt)
274*5c23704eSSong GaoTRANS(sltu, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_sltu)
275*5c23704eSSong GaoTRANS(mul_w, ALL, gen_rrr, EXT_SIGN, EXT_SIGN, EXT_SIGN, tcg_gen_mul_tl)
276*5c23704eSSong GaoTRANS(mul_d, 64, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_mul_tl)
277*5c23704eSSong GaoTRANS(mulh_w, ALL, gen_rrr, EXT_SIGN, EXT_SIGN, EXT_NONE, gen_mulh_w)
278*5c23704eSSong GaoTRANS(mulh_wu, ALL, gen_rrr, EXT_ZERO, EXT_ZERO, EXT_NONE, gen_mulh_w)
279*5c23704eSSong GaoTRANS(mulh_d, 64, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_mulh_d)
280*5c23704eSSong GaoTRANS(mulh_du, 64, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_mulh_du)
281*5c23704eSSong GaoTRANS(mulw_d_w, 64, gen_rrr, EXT_SIGN, EXT_SIGN, EXT_NONE, tcg_gen_mul_tl)
282*5c23704eSSong GaoTRANS(mulw_d_wu, 64, gen_rrr, EXT_ZERO, EXT_ZERO, EXT_NONE, tcg_gen_mul_tl)
283*5c23704eSSong GaoTRANS(div_w, ALL, gen_rrr, EXT_SIGN, EXT_SIGN, EXT_SIGN, gen_div_w)
284*5c23704eSSong GaoTRANS(mod_w, ALL, gen_rrr, EXT_SIGN, EXT_SIGN, EXT_SIGN, gen_rem_w)
285*5c23704eSSong GaoTRANS(div_wu, ALL, gen_rrr, EXT_ZERO, EXT_ZERO, EXT_SIGN, gen_div_du)
286*5c23704eSSong GaoTRANS(mod_wu, ALL, gen_rrr, EXT_ZERO, EXT_ZERO, EXT_SIGN, gen_rem_du)
287*5c23704eSSong GaoTRANS(div_d, 64, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_div_d)
288*5c23704eSSong GaoTRANS(mod_d, 64, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_rem_d)
289*5c23704eSSong GaoTRANS(div_du, 64, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_div_du)
290*5c23704eSSong GaoTRANS(mod_du, 64, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_rem_du)
291*5c23704eSSong GaoTRANS(slti, ALL, gen_rri_v, EXT_NONE, EXT_NONE, gen_slt)
292*5c23704eSSong GaoTRANS(sltui, ALL, gen_rri_v, EXT_NONE, EXT_NONE, gen_sltu)
293*5c23704eSSong GaoTRANS(addi_w, ALL, gen_rri_c, EXT_NONE, EXT_SIGN, tcg_gen_addi_tl)
294*5c23704eSSong GaoTRANS(addi_d, 64, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_addi_tl)
295*5c23704eSSong GaoTRANS(alsl_w, ALL, gen_rrr_sa, EXT_NONE, EXT_SIGN, gen_alsl)
296*5c23704eSSong GaoTRANS(alsl_wu, 64, gen_rrr_sa, EXT_NONE, EXT_ZERO, gen_alsl)
297*5c23704eSSong GaoTRANS(alsl_d, 64, gen_rrr_sa, EXT_NONE, EXT_NONE, gen_alsl)
298*5c23704eSSong GaoTRANS(pcaddi, ALL, gen_pc, gen_pcaddi)
299*5c23704eSSong GaoTRANS(pcalau12i, ALL, gen_pc, gen_pcalau12i)
300*5c23704eSSong GaoTRANS(pcaddu12i, ALL, gen_pc, gen_pcaddu12i)
301*5c23704eSSong GaoTRANS(pcaddu18i, 64, gen_pc, gen_pcaddu18i)
302*5c23704eSSong GaoTRANS(andi, ALL, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_andi_tl)
303*5c23704eSSong GaoTRANS(ori, ALL, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_ori_tl)
304*5c23704eSSong GaoTRANS(xori, ALL, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_xori_tl)
305