1/*
2 * Copyright (C) 2013 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#ifndef ART_RUNTIME_ARCH_MIPS_ASM_SUPPORT_MIPS_S_
18#define ART_RUNTIME_ARCH_MIPS_ASM_SUPPORT_MIPS_S_
19
20#include "asm_support_mips.h"
21
22// Define special registers.
23
24// Register holding suspend check count down.
25#define rSUSPEND $s0
26// Register holding Thread::Current().
27#define rSELF $s1
28
29     // Declare a function called name, doesn't set up $gp.
30.macro ENTRY_NO_GP_CUSTOM_CFA name, cfa_offset
31    .type \name, %function
32    .global \name
33    // Cache alignment for function entry.
34    .balign 16
35\name:
36    .cfi_startproc
37     // Ensure we get a sane starting CFA.
38    .cfi_def_cfa $sp, \cfa_offset
39.endm
40
41     // Declare a function called name, doesn't set up $gp.
42.macro ENTRY_NO_GP name
43    ENTRY_NO_GP_CUSTOM_CFA \name, 0
44.endm
45
46     // Declare a function called name, sets up $gp.
47.macro ENTRY name
48    ENTRY_NO_GP \name
49    // Load $gp. We expect that ".set noreorder" is in effect.
50    .cpload $t9
51    // Declare a local convenience label to be branched to when $gp is already set up.
52.L\name\()_gp_set:
53.endm
54
55.macro END name
56    .cfi_endproc
57    .size \name, .-\name
58.endm
59
60.macro UNIMPLEMENTED name
61    ENTRY \name
62    break
63    break
64    END \name
65.endm
66
67#if defined(__mips_isa_rev) && __mips_isa_rev > 2
68  /* mips32r5 & mips32r6 have mthc1 op, and have 64-bit fp regs,
69     and in FPXX abi we avoid referring to odd-numbered fp regs */
70
71/* LDu: Load 64-bit floating-point value to float reg feven,
72   from unaligned (mod-4-aligned) mem location disp(base) */
73.macro LDu feven,fodd,disp,base,temp
74  l.s   \feven, \disp(\base)
75  lw    \temp, \disp+4(\base)
76  mthc1 \temp, \feven
77.endm
78
79/* SDu: Store 64-bit floating-point value from float reg feven,
80   to unaligned (mod-4-aligned) mem location disp(base) */
81.macro SDu feven,fodd,disp,base,temp
82  mfhc1 \temp, \feven
83  s.s   \feven, \disp(\base)
84  sw    \temp, \disp+4(\base)
85.endm
86
87/* MTD: Move double, from general regpair (reven,rodd)
88        to float regpair (feven,fodd) */
89.macro MTD reven,rodd,feven,fodd
90  mtc1  \reven, \feven
91  mthc1 \rodd, \feven
92.endm
93
94#else
95  /* mips32r1 has no mthc1 op;
96     mips32r1 and mips32r2 use 32-bit floating point register mode (FR=0),
97     and always hold doubles as (feven, fodd) fp reg pair */
98
99.macro LDu feven,fodd,disp,base,temp
100  l.s   \feven, \disp(\base)
101  l.s   \fodd,  \disp+4(\base)
102.endm
103
104.macro SDu feven,fodd,disp,base,temp
105  s.s   \feven, \disp(\base)
106  s.s   \fodd,  \disp+4(\base)
107.endm
108
109.macro MTD reven,rodd,feven,fodd
110  mtc1  \reven, \feven
111  mtc1  \rodd, \fodd
112.endm
113
114#endif  /* mips_isa_rev */
115
116// Macros to poison (negate) the reference for heap poisoning.
117.macro POISON_HEAP_REF rRef
118#ifdef USE_HEAP_POISONING
119    subu \rRef, $zero, \rRef
120#endif  // USE_HEAP_POISONING
121.endm
122
123// Macros to unpoison (negate) the reference for heap poisoning.
124.macro UNPOISON_HEAP_REF rRef
125#ifdef USE_HEAP_POISONING
126    subu \rRef, $zero, \rRef
127#endif  // USE_HEAP_POISONING
128.endm
129
130// Byte size of the instructions (un)poisoning heap references.
131#ifdef USE_HEAP_POISONING
132#define HEAP_POISON_INSTR_SIZE 4
133#else
134#define HEAP_POISON_INSTR_SIZE 0
135#endif  // USE_HEAP_POISONING
136
137// Based on contents of creg select the minimum integer
138// At the end of the macro the original value of creg is lost
139.macro MINint dreg,rreg,sreg,creg
140  .set push
141  .set noat
142#if defined(_MIPS_ARCH_MIPS32R6) || defined(_MIPS_ARCH_MIPS64R6)
143  .ifc \dreg, \rreg
144  selnez \dreg, \rreg, \creg
145  seleqz \creg, \sreg, \creg
146  .else
147  seleqz \dreg, \sreg, \creg
148  selnez \creg, \rreg, \creg
149  .endif
150  or     \dreg, \dreg, \creg
151#else
152  movn   \dreg, \rreg, \creg
153  movz   \dreg, \sreg, \creg
154#endif
155  .set pop
156.endm
157
158// Find minimum of two signed registers
159.macro MINs dreg,rreg,sreg
160  .set push
161  .set noat
162  slt    $at, \rreg, \sreg
163  MINint \dreg, \rreg, \sreg, $at
164  .set pop
165.endm
166
167// Find minimum of two unsigned registers
168.macro MINu dreg,rreg,sreg
169  .set push
170  .set noat
171  sltu   $at, \rreg, \sreg
172  MINint \dreg, \rreg, \sreg, $at
173  .set pop
174.endm
175
176// This utility macro is used to check whether the address contained in
177// a register is suitably aligned. Default usage is confirm that the
178// address stored in $sp is a multiple of 16. It can be used for other
179// alignments, and for other base address registers, if needed.
180//
181// Enable this macro by running the shell command:
182//
183//    export ART_MIPS32_CHECK_ALIGNMENT=true
184//
185// NOTE: The value of alignment must be a power of 2, and must fit in an
186// unsigned 15-bit integer. The macro won't behave as expected if these
187// conditions aren't met.
188//
189.macro CHECK_ALIGNMENT ba=$sp, tmp=$at, alignment=16
190#ifdef ART_MIPS32_CHECK_ALIGNMENT
191    .set push
192    .set noat
193    .set noreorder
194    andi  \tmp, \ba, \alignment-1
195    beqz  \tmp, .+12    # Skip break instruction if base address register (ba) is aligned
196    nop
197    break
198    .set pop
199#endif
200.endm
201
202#endif  // ART_RUNTIME_ARCH_MIPS_ASM_SUPPORT_MIPS_S_
203