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