1*22dc650dSSadaf Ebrahimi /*
2*22dc650dSSadaf Ebrahimi * Stack-less Just-In-Time compiler
3*22dc650dSSadaf Ebrahimi *
4*22dc650dSSadaf Ebrahimi * Copyright Zoltan Herczeg ([email protected]). All rights reserved.
5*22dc650dSSadaf Ebrahimi *
6*22dc650dSSadaf Ebrahimi * Redistribution and use in source and binary forms, with or without modification, are
7*22dc650dSSadaf Ebrahimi * permitted provided that the following conditions are met:
8*22dc650dSSadaf Ebrahimi *
9*22dc650dSSadaf Ebrahimi * 1. Redistributions of source code must retain the above copyright notice, this list of
10*22dc650dSSadaf Ebrahimi * conditions and the following disclaimer.
11*22dc650dSSadaf Ebrahimi *
12*22dc650dSSadaf Ebrahimi * 2. Redistributions in binary form must reproduce the above copyright notice, this list
13*22dc650dSSadaf Ebrahimi * of conditions and the following disclaimer in the documentation and/or other materials
14*22dc650dSSadaf Ebrahimi * provided with the distribution.
15*22dc650dSSadaf Ebrahimi *
16*22dc650dSSadaf Ebrahimi * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
17*22dc650dSSadaf Ebrahimi * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18*22dc650dSSadaf Ebrahimi * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
19*22dc650dSSadaf Ebrahimi * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20*22dc650dSSadaf Ebrahimi * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
21*22dc650dSSadaf Ebrahimi * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
22*22dc650dSSadaf Ebrahimi * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23*22dc650dSSadaf Ebrahimi * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
24*22dc650dSSadaf Ebrahimi * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25*22dc650dSSadaf Ebrahimi */
26*22dc650dSSadaf Ebrahimi
load_immediate(struct sljit_compiler * compiler,sljit_s32 dst_r,sljit_sw imm,sljit_s32 tmp_r)27*22dc650dSSadaf Ebrahimi static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst_r, sljit_sw imm, sljit_s32 tmp_r)
28*22dc650dSSadaf Ebrahimi {
29*22dc650dSSadaf Ebrahimi sljit_sw high;
30*22dc650dSSadaf Ebrahimi
31*22dc650dSSadaf Ebrahimi if (imm <= SIMM_MAX && imm >= SIMM_MIN)
32*22dc650dSSadaf Ebrahimi return push_inst(compiler, ADDI | RD(dst_r) | RS1(TMP_ZERO) | IMM_I(imm));
33*22dc650dSSadaf Ebrahimi
34*22dc650dSSadaf Ebrahimi if (imm <= 0x7fffffffl && imm >= S32_MIN) {
35*22dc650dSSadaf Ebrahimi if (imm > S32_MAX) {
36*22dc650dSSadaf Ebrahimi SLJIT_ASSERT((imm & 0x800) != 0);
37*22dc650dSSadaf Ebrahimi FAIL_IF(push_inst(compiler, LUI | RD(dst_r) | (sljit_ins)0x80000000u));
38*22dc650dSSadaf Ebrahimi return push_inst(compiler, XORI | RD(dst_r) | RS1(dst_r) | IMM_I(imm));
39*22dc650dSSadaf Ebrahimi }
40*22dc650dSSadaf Ebrahimi
41*22dc650dSSadaf Ebrahimi if ((imm & 0x800) != 0)
42*22dc650dSSadaf Ebrahimi imm += 0x1000;
43*22dc650dSSadaf Ebrahimi
44*22dc650dSSadaf Ebrahimi FAIL_IF(push_inst(compiler, LUI | RD(dst_r) | (sljit_ins)(imm & ~0xfff)));
45*22dc650dSSadaf Ebrahimi
46*22dc650dSSadaf Ebrahimi if ((imm & 0xfff) == 0)
47*22dc650dSSadaf Ebrahimi return SLJIT_SUCCESS;
48*22dc650dSSadaf Ebrahimi
49*22dc650dSSadaf Ebrahimi return push_inst(compiler, ADDI | RD(dst_r) | RS1(dst_r) | IMM_I(imm));
50*22dc650dSSadaf Ebrahimi }
51*22dc650dSSadaf Ebrahimi
52*22dc650dSSadaf Ebrahimi /* Trailing zeroes could be used to produce shifted immediates. */
53*22dc650dSSadaf Ebrahimi
54*22dc650dSSadaf Ebrahimi if (imm <= 0x7ffffffffffl && imm >= -0x80000000000l) {
55*22dc650dSSadaf Ebrahimi high = imm >> 12;
56*22dc650dSSadaf Ebrahimi
57*22dc650dSSadaf Ebrahimi if (imm & 0x800)
58*22dc650dSSadaf Ebrahimi high = ~high;
59*22dc650dSSadaf Ebrahimi
60*22dc650dSSadaf Ebrahimi if (high > S32_MAX) {
61*22dc650dSSadaf Ebrahimi SLJIT_ASSERT((high & 0x800) != 0);
62*22dc650dSSadaf Ebrahimi FAIL_IF(push_inst(compiler, LUI | RD(dst_r) | (sljit_ins)0x80000000u));
63*22dc650dSSadaf Ebrahimi FAIL_IF(push_inst(compiler, XORI | RD(dst_r) | RS1(dst_r) | IMM_I(high)));
64*22dc650dSSadaf Ebrahimi } else {
65*22dc650dSSadaf Ebrahimi if ((high & 0x800) != 0)
66*22dc650dSSadaf Ebrahimi high += 0x1000;
67*22dc650dSSadaf Ebrahimi
68*22dc650dSSadaf Ebrahimi FAIL_IF(push_inst(compiler, LUI | RD(dst_r) | (sljit_ins)(high & ~0xfff)));
69*22dc650dSSadaf Ebrahimi
70*22dc650dSSadaf Ebrahimi if ((high & 0xfff) != 0)
71*22dc650dSSadaf Ebrahimi FAIL_IF(push_inst(compiler, ADDI | RD(dst_r) | RS1(dst_r) | IMM_I(high)));
72*22dc650dSSadaf Ebrahimi }
73*22dc650dSSadaf Ebrahimi
74*22dc650dSSadaf Ebrahimi FAIL_IF(push_inst(compiler, SLLI | RD(dst_r) | RS1(dst_r) | IMM_I(12)));
75*22dc650dSSadaf Ebrahimi
76*22dc650dSSadaf Ebrahimi if ((imm & 0xfff) != 0)
77*22dc650dSSadaf Ebrahimi return push_inst(compiler, XORI | RD(dst_r) | RS1(dst_r) | IMM_I(imm));
78*22dc650dSSadaf Ebrahimi
79*22dc650dSSadaf Ebrahimi return SLJIT_SUCCESS;
80*22dc650dSSadaf Ebrahimi }
81*22dc650dSSadaf Ebrahimi
82*22dc650dSSadaf Ebrahimi SLJIT_ASSERT(dst_r != tmp_r);
83*22dc650dSSadaf Ebrahimi
84*22dc650dSSadaf Ebrahimi high = imm >> 32;
85*22dc650dSSadaf Ebrahimi imm = (sljit_s32)imm;
86*22dc650dSSadaf Ebrahimi
87*22dc650dSSadaf Ebrahimi if ((imm & 0x80000000l) != 0)
88*22dc650dSSadaf Ebrahimi high = ~high;
89*22dc650dSSadaf Ebrahimi
90*22dc650dSSadaf Ebrahimi if (high <= 0x7ffff && high >= -0x80000) {
91*22dc650dSSadaf Ebrahimi FAIL_IF(push_inst(compiler, LUI | RD(tmp_r) | (sljit_ins)(high << 12)));
92*22dc650dSSadaf Ebrahimi high = 0x1000;
93*22dc650dSSadaf Ebrahimi } else {
94*22dc650dSSadaf Ebrahimi if ((high & 0x800) != 0)
95*22dc650dSSadaf Ebrahimi high += 0x1000;
96*22dc650dSSadaf Ebrahimi
97*22dc650dSSadaf Ebrahimi FAIL_IF(push_inst(compiler, LUI | RD(tmp_r) | (sljit_ins)(high & ~0xfff)));
98*22dc650dSSadaf Ebrahimi high &= 0xfff;
99*22dc650dSSadaf Ebrahimi }
100*22dc650dSSadaf Ebrahimi
101*22dc650dSSadaf Ebrahimi if (imm <= SIMM_MAX && imm >= SIMM_MIN) {
102*22dc650dSSadaf Ebrahimi FAIL_IF(push_inst(compiler, ADDI | RD(dst_r) | RS1(TMP_ZERO) | IMM_I(imm)));
103*22dc650dSSadaf Ebrahimi imm = 0;
104*22dc650dSSadaf Ebrahimi } else if (imm > S32_MAX) {
105*22dc650dSSadaf Ebrahimi SLJIT_ASSERT((imm & 0x800) != 0);
106*22dc650dSSadaf Ebrahimi
107*22dc650dSSadaf Ebrahimi FAIL_IF(push_inst(compiler, LUI | RD(dst_r) | (sljit_ins)0x80000000u));
108*22dc650dSSadaf Ebrahimi imm = 0x1000 | (imm & 0xfff);
109*22dc650dSSadaf Ebrahimi } else {
110*22dc650dSSadaf Ebrahimi if ((imm & 0x800) != 0)
111*22dc650dSSadaf Ebrahimi imm += 0x1000;
112*22dc650dSSadaf Ebrahimi
113*22dc650dSSadaf Ebrahimi FAIL_IF(push_inst(compiler, LUI | RD(dst_r) | (sljit_ins)(imm & ~0xfff)));
114*22dc650dSSadaf Ebrahimi imm &= 0xfff;
115*22dc650dSSadaf Ebrahimi }
116*22dc650dSSadaf Ebrahimi
117*22dc650dSSadaf Ebrahimi if ((high & 0xfff) != 0)
118*22dc650dSSadaf Ebrahimi FAIL_IF(push_inst(compiler, ADDI | RD(tmp_r) | RS1(tmp_r) | IMM_I(high)));
119*22dc650dSSadaf Ebrahimi
120*22dc650dSSadaf Ebrahimi if (imm & 0x1000)
121*22dc650dSSadaf Ebrahimi FAIL_IF(push_inst(compiler, XORI | RD(dst_r) | RS1(dst_r) | IMM_I(imm)));
122*22dc650dSSadaf Ebrahimi else if (imm != 0)
123*22dc650dSSadaf Ebrahimi FAIL_IF(push_inst(compiler, ADDI | RD(dst_r) | RS1(dst_r) | IMM_I(imm)));
124*22dc650dSSadaf Ebrahimi
125*22dc650dSSadaf Ebrahimi FAIL_IF(push_inst(compiler, SLLI | RD(tmp_r) | RS1(tmp_r) | IMM_I((high & 0x1000) ? 20 : 32)));
126*22dc650dSSadaf Ebrahimi return push_inst(compiler, XOR | RD(dst_r) | RS1(dst_r) | RS2(tmp_r));
127*22dc650dSSadaf Ebrahimi }
128*22dc650dSSadaf Ebrahimi
sljit_emit_fset64(struct sljit_compiler * compiler,sljit_s32 freg,sljit_f64 value)129*22dc650dSSadaf Ebrahimi SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fset64(struct sljit_compiler *compiler,
130*22dc650dSSadaf Ebrahimi sljit_s32 freg, sljit_f64 value)
131*22dc650dSSadaf Ebrahimi {
132*22dc650dSSadaf Ebrahimi union {
133*22dc650dSSadaf Ebrahimi sljit_sw imm;
134*22dc650dSSadaf Ebrahimi sljit_f64 value;
135*22dc650dSSadaf Ebrahimi } u;
136*22dc650dSSadaf Ebrahimi
137*22dc650dSSadaf Ebrahimi CHECK_ERROR();
138*22dc650dSSadaf Ebrahimi CHECK(check_sljit_emit_fset64(compiler, freg, value));
139*22dc650dSSadaf Ebrahimi
140*22dc650dSSadaf Ebrahimi u.value = value;
141*22dc650dSSadaf Ebrahimi
142*22dc650dSSadaf Ebrahimi if (u.imm == 0)
143*22dc650dSSadaf Ebrahimi return push_inst(compiler, FMV_W_X | (1 << 25) | RS1(TMP_ZERO) | FRD(freg));
144*22dc650dSSadaf Ebrahimi
145*22dc650dSSadaf Ebrahimi FAIL_IF(load_immediate(compiler, TMP_REG1, u.imm, TMP_REG3));
146*22dc650dSSadaf Ebrahimi return push_inst(compiler, FMV_W_X | (1 << 25) | RS1(TMP_REG1) | FRD(freg));
147*22dc650dSSadaf Ebrahimi }
148*22dc650dSSadaf Ebrahimi
sljit_emit_fcopy(struct sljit_compiler * compiler,sljit_s32 op,sljit_s32 freg,sljit_s32 reg)149*22dc650dSSadaf Ebrahimi SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fcopy(struct sljit_compiler *compiler, sljit_s32 op,
150*22dc650dSSadaf Ebrahimi sljit_s32 freg, sljit_s32 reg)
151*22dc650dSSadaf Ebrahimi {
152*22dc650dSSadaf Ebrahimi sljit_ins inst;
153*22dc650dSSadaf Ebrahimi
154*22dc650dSSadaf Ebrahimi CHECK_ERROR();
155*22dc650dSSadaf Ebrahimi CHECK(check_sljit_emit_fcopy(compiler, op, freg, reg));
156*22dc650dSSadaf Ebrahimi
157*22dc650dSSadaf Ebrahimi if (GET_OPCODE(op) == SLJIT_COPY_TO_F64)
158*22dc650dSSadaf Ebrahimi inst = FMV_W_X | RS1(reg) | FRD(freg);
159*22dc650dSSadaf Ebrahimi else
160*22dc650dSSadaf Ebrahimi inst = FMV_X_W | FRS1(freg) | RD(reg);
161*22dc650dSSadaf Ebrahimi
162*22dc650dSSadaf Ebrahimi if (!(op & SLJIT_32))
163*22dc650dSSadaf Ebrahimi inst |= (sljit_ins)1 << 25;
164*22dc650dSSadaf Ebrahimi
165*22dc650dSSadaf Ebrahimi return push_inst(compiler, inst);
166*22dc650dSSadaf Ebrahimi }
167*22dc650dSSadaf Ebrahimi
emit_const(struct sljit_compiler * compiler,sljit_s32 dst,sljit_sw init_value,sljit_ins last_ins)168*22dc650dSSadaf Ebrahimi static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw init_value, sljit_ins last_ins)
169*22dc650dSSadaf Ebrahimi {
170*22dc650dSSadaf Ebrahimi sljit_sw high;
171*22dc650dSSadaf Ebrahimi
172*22dc650dSSadaf Ebrahimi if ((init_value & 0x800) != 0)
173*22dc650dSSadaf Ebrahimi init_value += 0x1000;
174*22dc650dSSadaf Ebrahimi
175*22dc650dSSadaf Ebrahimi high = init_value >> 32;
176*22dc650dSSadaf Ebrahimi
177*22dc650dSSadaf Ebrahimi if ((init_value & 0x80000000l) != 0)
178*22dc650dSSadaf Ebrahimi high = ~high;
179*22dc650dSSadaf Ebrahimi
180*22dc650dSSadaf Ebrahimi if ((high & 0x800) != 0)
181*22dc650dSSadaf Ebrahimi high += 0x1000;
182*22dc650dSSadaf Ebrahimi
183*22dc650dSSadaf Ebrahimi FAIL_IF(push_inst(compiler, LUI | RD(TMP_REG3) | (sljit_ins)(high & ~0xfff)));
184*22dc650dSSadaf Ebrahimi FAIL_IF(push_inst(compiler, ADDI | RD(TMP_REG3) | RS1(TMP_REG3) | IMM_I(high)));
185*22dc650dSSadaf Ebrahimi FAIL_IF(push_inst(compiler, LUI | RD(dst) | (sljit_ins)(init_value & ~0xfff)));
186*22dc650dSSadaf Ebrahimi FAIL_IF(push_inst(compiler, SLLI | RD(TMP_REG3) | RS1(TMP_REG3) | IMM_I(32)));
187*22dc650dSSadaf Ebrahimi FAIL_IF(push_inst(compiler, XOR | RD(dst) | RS1(dst) | RS2(TMP_REG3)));
188*22dc650dSSadaf Ebrahimi return push_inst(compiler, last_ins | RS1(dst) | IMM_I(init_value));
189*22dc650dSSadaf Ebrahimi }
190*22dc650dSSadaf Ebrahimi
sljit_set_jump_addr(sljit_uw addr,sljit_uw new_target,sljit_sw executable_offset)191*22dc650dSSadaf Ebrahimi SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset)
192*22dc650dSSadaf Ebrahimi {
193*22dc650dSSadaf Ebrahimi sljit_ins *inst = (sljit_ins*)addr;
194*22dc650dSSadaf Ebrahimi sljit_sw high;
195*22dc650dSSadaf Ebrahimi SLJIT_UNUSED_ARG(executable_offset);
196*22dc650dSSadaf Ebrahimi
197*22dc650dSSadaf Ebrahimi if ((new_target & 0x800) != 0)
198*22dc650dSSadaf Ebrahimi new_target += 0x1000;
199*22dc650dSSadaf Ebrahimi
200*22dc650dSSadaf Ebrahimi high = (sljit_sw)new_target >> 32;
201*22dc650dSSadaf Ebrahimi
202*22dc650dSSadaf Ebrahimi if ((new_target & 0x80000000l) != 0)
203*22dc650dSSadaf Ebrahimi high = ~high;
204*22dc650dSSadaf Ebrahimi
205*22dc650dSSadaf Ebrahimi if ((high & 0x800) != 0)
206*22dc650dSSadaf Ebrahimi high += 0x1000;
207*22dc650dSSadaf Ebrahimi
208*22dc650dSSadaf Ebrahimi SLJIT_UPDATE_WX_FLAGS(inst, inst + 5, 0);
209*22dc650dSSadaf Ebrahimi
210*22dc650dSSadaf Ebrahimi SLJIT_ASSERT((inst[0] & 0x7f) == LUI);
211*22dc650dSSadaf Ebrahimi inst[0] = (inst[0] & 0xfff) | (sljit_ins)(high & ~0xfff);
212*22dc650dSSadaf Ebrahimi SLJIT_ASSERT((inst[1] & 0x707f) == ADDI);
213*22dc650dSSadaf Ebrahimi inst[1] = (inst[1] & 0xfffff) | IMM_I(high);
214*22dc650dSSadaf Ebrahimi SLJIT_ASSERT((inst[2] & 0x7f) == LUI);
215*22dc650dSSadaf Ebrahimi inst[2] = (inst[2] & 0xfff) | (sljit_ins)((sljit_sw)new_target & ~0xfff);
216*22dc650dSSadaf Ebrahimi SLJIT_ASSERT((inst[5] & 0x707f) == ADDI || (inst[5] & 0x707f) == JALR);
217*22dc650dSSadaf Ebrahimi inst[5] = (inst[5] & 0xfffff) | IMM_I(new_target);
218*22dc650dSSadaf Ebrahimi SLJIT_UPDATE_WX_FLAGS(inst, inst + 5, 1);
219*22dc650dSSadaf Ebrahimi
220*22dc650dSSadaf Ebrahimi inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
221*22dc650dSSadaf Ebrahimi SLJIT_CACHE_FLUSH(inst, inst + 5);
222*22dc650dSSadaf Ebrahimi }
223