1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/*
18  Art assembly interpreter notes:
19
20  First validate assembly code by implementing ExecuteXXXImpl() style body (doesn't
21  handle invoke, allows higher-level code to create frame & shadow frame.
22
23  Once that's working, support direct entry code & eliminate shadow frame (and
24  excess locals allocation.
25
26  Some (hopefully) temporary ugliness.  We'll treat rFP as pointing to the
27  base of the vreg array within the shadow frame.  Access the other fields,
28  dex_pc_, method_ and number_of_vregs_ via negative offsets.  For now, we'll continue
29  the shadow frame mechanism of double-storing object references - via rFP &
30  number_of_vregs_.
31
32 */
33
34#include "asm_support.h"
35
36#if (__mips==32) && (__mips_isa_rev>=2)
37#define MIPS32REVGE2    /* mips32r2 and greater */
38#if (__mips==32) && (__mips_isa_rev>=5)
39#define FPU64           /* 64 bit FPU */
40#if (__mips==32) && (__mips_isa_rev>=6)
41#define MIPS32REVGE6    /* mips32r6 and greater */
42#endif
43#endif
44#endif
45
46/* MIPS definitions and declarations
47
48   reg  nick      purpose
49   s0   rPC       interpreted program counter, used for fetching instructions
50   s1   rFP       interpreted frame pointer, used for accessing locals and args
51   s2   rSELF     self (Thread) pointer
52   s3   rIBASE    interpreted instruction base pointer, used for computed goto
53   s4   rINST     first 16-bit code unit of current instruction
54   s5   rOBJ      object pointer
55   s6   rREFS     base of object references in shadow frame (ideally, we'll get rid of this later).
56   s7   rTEMP     used as temp storage that can survive a function call
57   s8   rPROFILE  branch profiling countdown
58
59*/
60
61/* single-purpose registers, given names for clarity */
62#define rPC s0
63#define rFP s1
64#define rSELF s2
65#define rIBASE s3
66#define rINST s4
67#define rOBJ s5
68#define rREFS s6
69#define rTEMP s7
70#define rPROFILE s8
71
72#define rARG0 a0
73#define rARG1 a1
74#define rARG2 a2
75#define rARG3 a3
76#define rRESULT0 v0
77#define rRESULT1 v1
78
79/* GP register definitions */
80#define zero    $$0      /* always zero */
81#define AT      $$at     /* assembler temp */
82#define v0      $$2      /* return value */
83#define v1      $$3
84#define a0      $$4      /* argument registers */
85#define a1      $$5
86#define a2      $$6
87#define a3      $$7
88#define t0      $$8      /* temp registers (not saved across subroutine calls) */
89#define t1      $$9
90#define t2      $$10
91#define t3      $$11
92#define t4      $$12
93#define t5      $$13
94#define t6      $$14
95#define t7      $$15
96#define ta0     $$12     /* alias */
97#define ta1     $$13
98#define ta2     $$14
99#define ta3     $$15
100#define s0      $$16     /* saved across subroutine calls (callee saved) */
101#define s1      $$17
102#define s2      $$18
103#define s3      $$19
104#define s4      $$20
105#define s5      $$21
106#define s6      $$22
107#define s7      $$23
108#define t8      $$24     /* two more temp registers */
109#define t9      $$25
110#define k0      $$26     /* kernel temporary */
111#define k1      $$27
112#define gp      $$28     /* global pointer */
113#define sp      $$29     /* stack pointer */
114#define s8      $$30     /* one more callee saved */
115#define ra      $$31     /* return address */
116
117/* FP register definitions */
118#define fv0    $$f0
119#define fv0f   $$f1
120#define fv1    $$f2
121#define fv1f   $$f3
122#define fa0    $$f12
123#define fa0f   $$f13
124#define fa1    $$f14
125#define fa1f   $$f15
126#define ft0    $$f4
127#define ft0f   $$f5
128#define ft1    $$f6
129#define ft1f   $$f7
130#define ft2    $$f8
131#define ft2f   $$f9
132#define ft3    $$f10
133#define ft3f   $$f11
134#define ft4    $$f16
135#define ft4f   $$f17
136#define ft5    $$f18
137#define ft5f   $$f19
138#define fs0    $$f20
139#define fs0f   $$f21
140#define fs1    $$f22
141#define fs1f   $$f23
142#define fs2    $$f24
143#define fs2f   $$f25
144#define fs3    $$f26
145#define fs3f   $$f27
146#define fs4    $$f28
147#define fs4f   $$f29
148#define fs5    $$f30
149#define fs5f   $$f31
150
151#ifndef MIPS32REVGE6
152#define fcc0   $$fcc0
153#define fcc1   $$fcc1
154#endif
155
156#ifdef MIPS32REVGE2
157#define SEB(rd, rt) \
158    seb       rd, rt
159#define SEH(rd, rt) \
160    seh       rd, rt
161#define INSERT_HIGH_HALF(rd_lo, rt_hi) \
162    ins       rd_lo, rt_hi, 16, 16
163#else
164#define SEB(rd, rt) \
165    sll       rd, rt, 24; \
166    sra       rd, rd, 24
167#define SEH(rd, rt) \
168    sll       rd, rt, 16; \
169    sra       rd, rd, 16
170/* Clobbers rt_hi on pre-R2. */
171#define INSERT_HIGH_HALF(rd_lo, rt_hi) \
172    sll       rt_hi, rt_hi, 16; \
173    or        rd_lo, rt_hi
174#endif
175
176#ifdef FPU64
177#define MOVE_TO_FPU_HIGH(r, flo, fhi) \
178    mthc1     r, flo
179#else
180#define MOVE_TO_FPU_HIGH(r, flo, fhi) \
181    mtc1      r, fhi
182#endif
183
184#ifdef MIPS32REVGE6
185#define JR(rt) \
186    jic       rt, 0
187#define LSA(rd, rs, rt, sa) \
188    .if sa; \
189    lsa       rd, rs, rt, sa; \
190    .else; \
191    addu      rd, rs, rt; \
192    .endif
193#else
194#define JR(rt) \
195    jalr      zero, rt
196#define LSA(rd, rs, rt, sa) \
197    .if sa; \
198    .set      push; \
199    .set      noat; \
200    sll       AT, rs, sa; \
201    addu      rd, AT, rt; \
202    .set      pop; \
203    .else; \
204    addu      rd, rs, rt; \
205    .endif
206#endif
207
208/*
209 * Instead of holding a pointer to the shadow frame, we keep rFP at the base of the vregs.  So,
210 * to access other shadow frame fields, we need to use a backwards offset.  Define those here.
211 */
212#define OFF_FP(a) (a - SHADOWFRAME_VREGS_OFFSET)
213#define OFF_FP_NUMBER_OF_VREGS OFF_FP(SHADOWFRAME_NUMBER_OF_VREGS_OFFSET)
214#define OFF_FP_DEX_PC OFF_FP(SHADOWFRAME_DEX_PC_OFFSET)
215#define OFF_FP_LINK OFF_FP(SHADOWFRAME_LINK_OFFSET)
216#define OFF_FP_METHOD OFF_FP(SHADOWFRAME_METHOD_OFFSET)
217#define OFF_FP_RESULT_REGISTER OFF_FP(SHADOWFRAME_RESULT_REGISTER_OFFSET)
218#define OFF_FP_DEX_PC_PTR OFF_FP(SHADOWFRAME_DEX_PC_PTR_OFFSET)
219#define OFF_FP_CODE_ITEM OFF_FP(SHADOWFRAME_CODE_ITEM_OFFSET)
220#define OFF_FP_SHADOWFRAME OFF_FP(0)
221
222#define MTERP_PROFILE_BRANCHES 1
223#define MTERP_LOGGING 0
224
225/*
226 * "export" the PC to dex_pc field in the shadow frame, f/b/o future exception objects.  Must
227 * be done *before* something throws.
228 *
229 * It's okay to do this more than once.
230 *
231 * NOTE: the fast interpreter keeps track of dex pc as a direct pointer to the mapped
232 * dex byte codes.  However, the rest of the runtime expects dex pc to be an instruction
233 * offset into the code_items_[] array.  For effiency, we will "export" the
234 * current dex pc as a direct pointer using the EXPORT_PC macro, and rely on GetDexPC
235 * to convert to a dex pc when needed.
236 */
237#define EXPORT_PC() \
238    sw        rPC, OFF_FP_DEX_PC_PTR(rFP)
239
240#define EXPORT_DEX_PC(tmp) \
241    lw        tmp, OFF_FP_CODE_ITEM(rFP); \
242    sw        rPC, OFF_FP_DEX_PC_PTR(rFP); \
243    addu      tmp, CODEITEM_INSNS_OFFSET; \
244    subu      tmp, rPC, tmp; \
245    sra       tmp, tmp, 1; \
246    sw        tmp, OFF_FP_DEX_PC(rFP)
247
248/*
249 * Fetch the next instruction from rPC into rINST.  Does not advance rPC.
250 */
251#define FETCH_INST() lhu rINST, (rPC)
252
253/*
254 * Fetch the next instruction from the specified offset.  Advances rPC
255 * to point to the next instruction.  "_count" is in 16-bit code units.
256 *
257 * This must come AFTER anything that can throw an exception, or the
258 * exception catch may miss.  (This also implies that it must come after
259 * EXPORT_PC().)
260 */
261#define FETCH_ADVANCE_INST(_count) \
262    lhu       rINST, ((_count)*2)(rPC); \
263    addu      rPC, rPC, ((_count) * 2)
264
265/*
266 * Similar to FETCH_ADVANCE_INST, but does not update rPC.  Used to load
267 * rINST ahead of possible exception point.  Be sure to manually advance rPC
268 * later.
269 */
270#define PREFETCH_INST(_count) lhu rINST, ((_count)*2)(rPC)
271
272/* Advance rPC by some number of code units. */
273#define ADVANCE(_count) addu rPC, rPC, ((_count) * 2)
274
275/*
276 * Fetch the next instruction from an offset specified by rd.  Updates
277 * rPC to point to the next instruction.  "rd" must specify the distance
278 * in bytes, *not* 16-bit code units, and may be a signed value.
279 */
280#define FETCH_ADVANCE_INST_RB(rd) \
281    addu      rPC, rPC, rd; \
282    lhu       rINST, (rPC)
283
284/*
285 * Fetch a half-word code unit from an offset past the current PC.  The
286 * "_count" value is in 16-bit code units.  Does not advance rPC.
287 *
288 * The "_S" variant works the same but treats the value as signed.
289 */
290#define FETCH(rd, _count) lhu rd, ((_count) * 2)(rPC)
291#define FETCH_S(rd, _count) lh rd, ((_count) * 2)(rPC)
292
293/*
294 * Fetch one byte from an offset past the current PC.  Pass in the same
295 * "_count" as you would for FETCH, and an additional 0/1 indicating which
296 * byte of the halfword you want (lo/hi).
297 */
298#define FETCH_B(rd, _count, _byte) lbu rd, ((_count) * 2 + _byte)(rPC)
299
300/*
301 * Put the instruction's opcode field into the specified register.
302 */
303#define GET_INST_OPCODE(rd) and rd, rINST, 0xFF
304
305/*
306 * Transform opcode into branch target address.
307 */
308#define GET_OPCODE_TARGET(rd) \
309    sll       rd, rd, ${handler_size_bits}; \
310    addu      rd, rIBASE, rd
311
312/*
313 * Begin executing the opcode in rd.
314 */
315#define GOTO_OPCODE(rd) \
316    GET_OPCODE_TARGET(rd); \
317    JR(rd)
318
319/*
320 * Get/set the 32-bit value from a Dalvik register.
321 */
322#define GET_VREG(rd, rix) LOAD_eas2(rd, rFP, rix)
323
324#define GET_VREG_F(rd, rix) \
325    .set noat; \
326    EAS2(AT, rFP, rix); \
327    l.s       rd, (AT); \
328    .set at
329
330#ifdef MIPS32REVGE6
331#define SET_VREG(rd, rix) \
332    lsa       t8, rix, rFP, 2; \
333    sw        rd, 0(t8); \
334    lsa       t8, rix, rREFS, 2; \
335    sw        zero, 0(t8)
336#else
337#define SET_VREG(rd, rix) \
338    .set noat; \
339    sll       AT, rix, 2; \
340    addu      t8, rFP, AT; \
341    sw        rd, 0(t8); \
342    addu      t8, rREFS, AT; \
343    .set at; \
344    sw        zero, 0(t8)
345#endif
346
347#ifdef MIPS32REVGE6
348#define SET_VREG_OBJECT(rd, rix) \
349    lsa       t8, rix, rFP, 2; \
350    sw        rd, 0(t8); \
351    lsa       t8, rix, rREFS, 2; \
352    sw        rd, 0(t8)
353#else
354#define SET_VREG_OBJECT(rd, rix) \
355    .set noat; \
356    sll       AT, rix, 2; \
357    addu      t8, rFP, AT; \
358    sw        rd, 0(t8); \
359    addu      t8, rREFS, AT; \
360    .set at; \
361    sw        rd, 0(t8)
362#endif
363
364#ifdef MIPS32REVGE6
365#define SET_VREG64(rlo, rhi, rix) \
366    lsa       t8, rix, rFP, 2; \
367    sw        rlo, 0(t8); \
368    sw        rhi, 4(t8); \
369    lsa       t8, rix, rREFS, 2; \
370    sw        zero, 0(t8); \
371    sw        zero, 4(t8)
372#else
373#define SET_VREG64(rlo, rhi, rix) \
374    .set noat; \
375    sll       AT, rix, 2; \
376    addu      t8, rFP, AT; \
377    sw        rlo, 0(t8); \
378    sw        rhi, 4(t8); \
379    addu      t8, rREFS, AT; \
380    .set at; \
381    sw        zero, 0(t8); \
382    sw        zero, 4(t8)
383#endif
384
385#ifdef MIPS32REVGE6
386#define SET_VREG_F(rd, rix) \
387    lsa       t8, rix, rFP, 2; \
388    s.s       rd, 0(t8); \
389    lsa       t8, rix, rREFS, 2; \
390    sw        zero, 0(t8)
391#else
392#define SET_VREG_F(rd, rix) \
393    .set noat; \
394    sll       AT, rix, 2; \
395    addu      t8, rFP, AT; \
396    s.s       rd, 0(t8); \
397    addu      t8, rREFS, AT; \
398    .set at; \
399    sw        zero, 0(t8)
400#endif
401
402#ifdef MIPS32REVGE6
403#define SET_VREG64_F(rlo, rhi, rix) \
404    lsa       t8, rix, rFP, 2; \
405    .set noat; \
406    mfhc1     AT, rlo; \
407    s.s       rlo, 0(t8); \
408    sw        AT, 4(t8); \
409    .set at; \
410    lsa       t8, rix, rREFS, 2; \
411    sw        zero, 0(t8); \
412    sw        zero, 4(t8)
413#elif defined(FPU64)
414#define SET_VREG64_F(rlo, rhi, rix) \
415    .set noat; \
416    sll       AT, rix, 2; \
417    addu      t8, rREFS, AT; \
418    sw        zero, 0(t8); \
419    sw        zero, 4(t8); \
420    addu      t8, rFP, AT; \
421    mfhc1     AT, rlo; \
422    sw        AT, 4(t8); \
423    .set at; \
424    s.s       rlo, 0(t8)
425#else
426#define SET_VREG64_F(rlo, rhi, rix) \
427    .set noat; \
428    sll       AT, rix, 2; \
429    addu      t8, rFP, AT; \
430    s.s       rlo, 0(t8); \
431    s.s       rhi, 4(t8); \
432    addu      t8, rREFS, AT; \
433    .set at; \
434    sw        zero, 0(t8); \
435    sw        zero, 4(t8)
436#endif
437
438/* Combination of the SET_VREG and GOTO_OPCODE functions to save 1 instruction */
439#ifdef MIPS32REVGE6
440#define SET_VREG_GOTO(rd, rix, dst) \
441    .set noreorder; \
442    GET_OPCODE_TARGET(dst); \
443    lsa       t8, rix, rFP, 2; \
444    sw        rd, 0(t8); \
445    lsa       t8, rix, rREFS, 2; \
446    jalr      zero, dst; \
447    sw        zero, 0(t8); \
448    .set reorder
449#else
450#define SET_VREG_GOTO(rd, rix, dst) \
451    .set noreorder; \
452    GET_OPCODE_TARGET(dst); \
453    .set noat; \
454    sll       AT, rix, 2; \
455    addu      t8, rFP, AT; \
456    sw        rd, 0(t8); \
457    addu      t8, rREFS, AT; \
458    .set at; \
459    jalr      zero, dst; \
460    sw        zero, 0(t8); \
461    .set reorder
462#endif
463
464/* Combination of the SET_VREG_OBJECT and GOTO_OPCODE functions to save 1 instruction */
465#ifdef MIPS32REVGE6
466#define SET_VREG_OBJECT_GOTO(rd, rix, dst) \
467    .set noreorder; \
468    GET_OPCODE_TARGET(dst); \
469    lsa       t8, rix, rFP, 2; \
470    sw        rd, 0(t8); \
471    lsa       t8, rix, rREFS, 2; \
472    jalr      zero, dst; \
473    sw        rd, 0(t8); \
474    .set reorder
475#else
476#define SET_VREG_OBJECT_GOTO(rd, rix, dst) \
477    .set noreorder; \
478    GET_OPCODE_TARGET(dst); \
479    .set noat; \
480    sll       AT, rix, 2; \
481    addu      t8, rFP, AT; \
482    sw        rd, 0(t8); \
483    addu      t8, rREFS, AT; \
484    .set at; \
485    jalr      zero, dst; \
486    sw        rd, 0(t8); \
487    .set reorder
488#endif
489
490/* Combination of the SET_VREG64 and GOTO_OPCODE functions to save 1 instruction */
491#ifdef MIPS32REVGE6
492#define SET_VREG64_GOTO(rlo, rhi, rix, dst) \
493    .set noreorder; \
494    GET_OPCODE_TARGET(dst); \
495    lsa       t8, rix, rFP, 2; \
496    sw        rlo, 0(t8); \
497    sw        rhi, 4(t8); \
498    lsa       t8, rix, rREFS, 2; \
499    sw        zero, 0(t8); \
500    jalr      zero, dst; \
501    sw        zero, 4(t8); \
502    .set reorder
503#else
504#define SET_VREG64_GOTO(rlo, rhi, rix, dst) \
505    .set noreorder; \
506    GET_OPCODE_TARGET(dst); \
507    .set noat; \
508    sll       AT, rix, 2; \
509    addu      t8, rFP, AT; \
510    sw        rlo, 0(t8); \
511    sw        rhi, 4(t8); \
512    addu      t8, rREFS, AT; \
513    .set at; \
514    sw        zero, 0(t8); \
515    jalr      zero, dst; \
516    sw        zero, 4(t8); \
517    .set reorder
518#endif
519
520/* Combination of the SET_VREG_F and GOTO_OPCODE functions to save 1 instruction */
521#ifdef MIPS32REVGE6
522#define SET_VREG_F_GOTO(rd, rix, dst) \
523    .set noreorder; \
524    GET_OPCODE_TARGET(dst); \
525    lsa       t8, rix, rFP, 2; \
526    s.s       rd, 0(t8); \
527    lsa       t8, rix, rREFS, 2; \
528    jalr      zero, dst; \
529    sw        zero, 0(t8); \
530    .set reorder
531#else
532#define SET_VREG_F_GOTO(rd, rix, dst) \
533    .set noreorder; \
534    GET_OPCODE_TARGET(dst); \
535    .set noat; \
536    sll       AT, rix, 2; \
537    addu      t8, rFP, AT; \
538    s.s       rd, 0(t8); \
539    addu      t8, rREFS, AT; \
540    .set at; \
541    jalr      zero, dst; \
542    sw        zero, 0(t8); \
543    .set reorder
544#endif
545
546/* Combination of the SET_VREG64_F and GOTO_OPCODE functions to save 1 instruction */
547#ifdef MIPS32REVGE6
548#define SET_VREG64_F_GOTO(rlo, rhi, rix, dst) \
549    .set noreorder; \
550    GET_OPCODE_TARGET(dst); \
551    lsa       t8, rix, rFP, 2; \
552    .set noat; \
553    mfhc1     AT, rlo; \
554    s.s       rlo, 0(t8); \
555    sw        AT, 4(t8); \
556    .set at; \
557    lsa       t8, rix, rREFS, 2; \
558    sw        zero, 0(t8); \
559    jalr      zero, dst; \
560    sw        zero, 4(t8); \
561    .set reorder
562#elif defined(FPU64)
563#define SET_VREG64_F_GOTO(rlo, rhi, rix, dst) \
564    .set noreorder; \
565    GET_OPCODE_TARGET(dst); \
566    .set noat; \
567    sll       AT, rix, 2; \
568    addu      t8, rREFS, AT; \
569    sw        zero, 0(t8); \
570    sw        zero, 4(t8); \
571    addu      t8, rFP, AT; \
572    mfhc1     AT, rlo; \
573    sw        AT, 4(t8); \
574    .set at; \
575    jalr      zero, dst; \
576    s.s       rlo, 0(t8); \
577    .set reorder
578#else
579#define SET_VREG64_F_GOTO(rlo, rhi, rix, dst) \
580    .set noreorder; \
581    GET_OPCODE_TARGET(dst); \
582    .set noat; \
583    sll       AT, rix, 2; \
584    addu      t8, rFP, AT; \
585    s.s       rlo, 0(t8); \
586    s.s       rhi, 4(t8); \
587    addu      t8, rREFS, AT; \
588    .set at; \
589    sw        zero, 0(t8); \
590    jalr      zero, dst; \
591    sw        zero, 4(t8); \
592    .set reorder
593#endif
594
595#define GET_OPA(rd) srl rd, rINST, 8
596#ifdef MIPS32REVGE2
597#define GET_OPA4(rd) ext rd, rINST, 8, 4
598#else
599#define GET_OPA4(rd) GET_OPA(rd); and rd, 0xf
600#endif
601#define GET_OPB(rd) srl rd, rINST, 12
602
603/*
604 * Form an Effective Address rd = rbase + roff<<shift;
605 * Uses reg AT on pre-R6.
606 */
607#define EASN(rd, rbase, roff, shift) LSA(rd, roff, rbase, shift)
608
609#define EAS1(rd, rbase, roff) EASN(rd, rbase, roff, 1)
610#define EAS2(rd, rbase, roff) EASN(rd, rbase, roff, 2)
611#define EAS3(rd, rbase, roff) EASN(rd, rbase, roff, 3)
612#define EAS4(rd, rbase, roff) EASN(rd, rbase, roff, 4)
613
614#define LOAD_eas2(rd, rbase, roff) \
615    .set noat; \
616    EAS2(AT, rbase, roff); \
617    lw        rd, 0(AT); \
618    .set at
619
620#define STORE_eas2(rd, rbase, roff) \
621    .set noat; \
622    EAS2(AT, rbase, roff); \
623    sw        rd, 0(AT); \
624    .set at
625
626#define LOAD_RB_OFF(rd, rbase, off) lw rd, off(rbase)
627#define STORE_RB_OFF(rd, rbase, off) sw rd, off(rbase)
628
629#define STORE64_off(rlo, rhi, rbase, off) \
630    sw        rlo, off(rbase); \
631    sw        rhi, (off+4)(rbase)
632#define LOAD64_off(rlo, rhi, rbase, off) \
633    lw        rlo, off(rbase); \
634    lw        rhi, (off+4)(rbase)
635
636#define STORE64(rlo, rhi, rbase) STORE64_off(rlo, rhi, rbase, 0)
637#define LOAD64(rlo, rhi, rbase) LOAD64_off(rlo, rhi, rbase, 0)
638
639#ifdef FPU64
640#define STORE64_off_F(rlo, rhi, rbase, off) \
641    s.s       rlo, off(rbase); \
642    .set noat; \
643    mfhc1     AT, rlo; \
644    sw        AT, (off+4)(rbase); \
645    .set at
646#define LOAD64_off_F(rlo, rhi, rbase, off) \
647    l.s       rlo, off(rbase); \
648    .set noat; \
649    lw        AT, (off+4)(rbase); \
650    mthc1     AT, rlo; \
651    .set at
652#else
653#define STORE64_off_F(rlo, rhi, rbase, off) \
654    s.s       rlo, off(rbase); \
655    s.s       rhi, (off+4)(rbase)
656#define LOAD64_off_F(rlo, rhi, rbase, off) \
657    l.s       rlo, off(rbase); \
658    l.s       rhi, (off+4)(rbase)
659#endif
660
661#define STORE64_F(rlo, rhi, rbase) STORE64_off_F(rlo, rhi, rbase, 0)
662#define LOAD64_F(rlo, rhi, rbase) LOAD64_off_F(rlo, rhi, rbase, 0)
663
664
665#define LOAD_base_offMirrorArray_length(rd, rbase) LOAD_RB_OFF(rd, rbase, MIRROR_ARRAY_LENGTH_OFFSET)
666
667#define STACK_STORE(rd, off) sw rd, off(sp)
668#define STACK_LOAD(rd, off) lw rd, off(sp)
669#define CREATE_STACK(n) subu sp, sp, n
670#define DELETE_STACK(n) addu sp, sp, n
671
672#define LOAD_ADDR(dest, addr) la dest, addr
673#define LOAD_IMM(dest, imm) li dest, imm
674#define MOVE_REG(dest, src) move dest, src
675#define STACK_SIZE 128
676
677#define STACK_OFFSET_ARG04 16
678#define STACK_OFFSET_ARG05 20
679#define STACK_OFFSET_ARG06 24
680#define STACK_OFFSET_ARG07 28
681#define STACK_OFFSET_GP    84
682
683#define JAL(n) jal n
684#define BAL(n) bal n
685
686/*
687 * FP register usage restrictions:
688 * 1) We don't use the callee save FP registers so we don't have to save them.
689 * 2) We don't use the odd FP registers so we can share code with mips32r6.
690 */
691#define STACK_STORE_FULL() CREATE_STACK(STACK_SIZE); \
692    STACK_STORE(ra, 124); \
693    STACK_STORE(s8, 120); \
694    STACK_STORE(s0, 116); \
695    STACK_STORE(s1, 112); \
696    STACK_STORE(s2, 108); \
697    STACK_STORE(s3, 104); \
698    STACK_STORE(s4, 100); \
699    STACK_STORE(s5, 96); \
700    STACK_STORE(s6, 92); \
701    STACK_STORE(s7, 88);
702
703#define STACK_LOAD_FULL() STACK_LOAD(gp, STACK_OFFSET_GP); \
704    STACK_LOAD(s7, 88); \
705    STACK_LOAD(s6, 92); \
706    STACK_LOAD(s5, 96); \
707    STACK_LOAD(s4, 100); \
708    STACK_LOAD(s3, 104); \
709    STACK_LOAD(s2, 108); \
710    STACK_LOAD(s1, 112); \
711    STACK_LOAD(s0, 116); \
712    STACK_LOAD(s8, 120); \
713    STACK_LOAD(ra, 124); \
714    DELETE_STACK(STACK_SIZE)
715
716#define REFRESH_IBASE() \
717    lw        rIBASE, THREAD_CURRENT_IBASE_OFFSET(rSELF)
718
719/* Constants for float/double_to_int/long conversions */
720#define INT_MIN                 0x80000000
721#define INT_MIN_AS_FLOAT        0xCF000000
722#define INT_MIN_AS_DOUBLE_HIGH  0xC1E00000
723#define LONG_MIN_HIGH           0x80000000
724#define LONG_MIN_AS_FLOAT       0xDF000000
725#define LONG_MIN_AS_DOUBLE_HIGH 0xC3E00000
726