xref: /aosp_15_r20/art/runtime/arch/riscv64/asm_support_riscv64.S (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1/*
2 * Copyright (C) 2023 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_RISCV64_ASM_SUPPORT_RISCV64_S_
18#define ART_RUNTIME_ARCH_RISCV64_ASM_SUPPORT_RISCV64_S_
19
20#include "asm_support_riscv64.h"
21#include "interpreter/cfi_asm_support.h"
22
23// Define special registers.
24
25// Register holding Thread::Current().
26#define xSELF s1
27
28
29.macro ENTRY name
30    .hidden \name  // Hide this as a global symbol, so we do not incur plt calls.
31    .global \name
32    .balign 16
33\name:
34    .cfi_startproc
35.endm
36
37
38.macro END name
39    .cfi_endproc
40    .size \name, .-\name
41.endm
42
43
44.macro UNDEFINED name
45    ENTRY \name
46        unimp
47    END \name
48.endm
49
50
51.macro CFI_REMEMBER_STATE
52    .cfi_remember_state
53.endm
54
55
56// The spec is not clear whether the CFA is part of the saved state and tools differ in the
57// behaviour, so explicitly set the CFA to avoid any ambiguity.
58// The restored CFA state should match the CFA state during CFI_REMEMBER_STATE.
59.macro CFI_RESTORE_STATE_AND_DEF_CFA reg, offset
60    .cfi_restore_state
61    .cfi_def_cfa \reg, \offset
62.endm
63
64
65.macro CFI_EXPRESSION_BREG n, b, offset
66    .if (-0x40 <= (\offset)) && ((\offset) < 0x40)
67        CFI_EXPRESSION_BREG_1(\n, \b, \offset)
68    .elseif (-0x2000 <= (\offset)) && ((\offset) < 0x2000)
69        CFI_EXPRESSION_BREG_2(\n, \b, \offset)
70    .else
71        .error "Unsupported offset"
72    .endif
73.endm
74
75
76.macro CFI_DEF_CFA_BREG_PLUS_UCONST reg, offset, size
77    .if (((\offset) < -0x40) || ((\offset) >= 0x40))
78        .error "Unsupported offset"
79    .endif
80
81    .if ((\size) < 0)
82        .error "Unsupported size, negative"
83    .elseif ((\size) < 0x80)
84        CFI_DEF_CFA_BREG_PLUS_UCONST_1_1(\reg, \offset, \size)
85    .elseif ((\size) < 0x4000)
86        CFI_DEF_CFA_BREG_PLUS_UCONST_1_2(\reg, \offset, \size)
87    .else
88        .error "Unsupported size, too large"
89    .endif
90.endm
91
92
93// Macro to poison (negate) the reference for heap poisoning.
94.macro POISON_HEAP_REF ref
95#ifdef USE_HEAP_POISONING
96    neg \ref, \ref
97    zext.w \ref, \ref
98#endif  // USE_HEAP_POISONING
99.endm
100
101
102// Macro to unpoison (negate) the reference for heap poisoning.
103.macro UNPOISON_HEAP_REF ref
104#ifdef USE_HEAP_POISONING
105    neg \ref, \ref
106    zext.w \ref, \ref
107#endif  // USE_HEAP_POISONING
108.endm
109
110
111.macro INCREASE_FRAME frame_adjustment
112    addi sp, sp, -(\frame_adjustment)
113    .cfi_adjust_cfa_offset (\frame_adjustment)
114.endm
115
116
117.macro DECREASE_FRAME frame_adjustment
118    addi sp, sp, (\frame_adjustment)
119    .cfi_adjust_cfa_offset -(\frame_adjustment)
120.endm
121
122
123.macro SAVE_GPR_BASE base, reg, offset
124    sd \reg, (\offset)(\base)
125    .cfi_rel_offset \reg, (\offset)
126.endm
127
128
129.macro SAVE_GPR reg, offset
130    SAVE_GPR_BASE sp, \reg, \offset
131.endm
132
133
134.macro RESTORE_GPR_BASE base, reg, offset
135    ld \reg, (\offset)(\base)
136    .cfi_restore \reg
137.endm
138
139
140.macro RESTORE_GPR reg, offset
141    RESTORE_GPR_BASE sp, \reg, \offset
142.endm
143
144
145.macro RESTORE_GPR_NE skip, reg, offset
146    .ifnc \skip, \reg
147    RESTORE_GPR_BASE sp, \reg, \offset
148    .endif
149.endm
150
151
152.macro SAVE_FPR reg, offset
153    fsd \reg, (\offset)(sp)
154    .cfi_rel_offset \reg, (\offset)
155.endm
156
157
158.macro RESTORE_FPR reg, offset
159    fld \reg, (\offset)(sp)
160    .cfi_restore \reg
161.endm
162
163
164// 8 argument GPRS: a0 - a7 and 8 argument FPRs: fa0 - fa7
165#define ALL_ARGS_SIZE (8 * (8 + 8))
166
167
168.macro SAVE_ALL_ARGS_INCREASE_FRAME extra_space
169    // Reserve space for all argument registers, plus the extra space.
170    INCREASE_FRAME (ALL_ARGS_SIZE + \extra_space)
171
172    // Argument GPRs a0 - a7.
173    sd    a0, (8*0)(sp)
174    sd    a1, (8*1)(sp)
175    sd    a2, (8*2)(sp)
176    sd    a3, (8*3)(sp)
177    sd    a4, (8*4)(sp)
178    sd    a5, (8*5)(sp)
179    sd    a6, (8*6)(sp)
180    sd    a7, (8*7)(sp)
181
182    // Argument FPRs fa0 - fa7.
183    fsd   fa0, (8*8)(sp)
184    fsd   fa1, (8*9)(sp)
185    fsd   fa2, (8*10)(sp)
186    fsd   fa3, (8*11)(sp)
187    fsd   fa4, (8*12)(sp)
188    fsd   fa5, (8*13)(sp)
189    fsd   fa6, (8*14)(sp)
190    fsd   fa7, (8*15)(sp)
191.endm
192
193
194.macro RESTORE_ALL_ARGS_DECREASE_FRAME extra_space
195    // Argument GPRs a0 - a7.
196    ld    a0, (8*0)(sp)
197    ld    a1, (8*1)(sp)
198    ld    a2, (8*2)(sp)
199    ld    a3, (8*3)(sp)
200    ld    a4, (8*4)(sp)
201    ld    a5, (8*5)(sp)
202    ld    a6, (8*6)(sp)
203    ld    a7, (8*7)(sp)
204
205    // Argument FPRs fa0 - fa7.
206    fld   fa0, (8*8)(sp)
207    fld   fa1, (8*9)(sp)
208    fld   fa2, (8*10)(sp)
209    fld   fa3, (8*11)(sp)
210    fld   fa4, (8*12)(sp)
211    fld   fa5, (8*13)(sp)
212    fld   fa6, (8*14)(sp)
213    fld   fa7, (8*15)(sp)
214
215    DECREASE_FRAME (ALL_ARGS_SIZE + \extra_space)
216.endm
217
218
219.macro LOAD_RUNTIME_INSTANCE reg
220#if __has_feature(hwaddress_sanitizer)
221#error "ART does not support HWASAN on RISC-V yet"
222#else
223    la \reg, _ZN3art7Runtime9instance_E
224#endif
225    ld \reg, 0(\reg)
226.endm
227
228
229// We need to save callee-save GPRs on the stack as they may contain references, and must be
230// visible to GC (unless the called method holds mutator lock and prevents GC from happening).
231// FP callee-saves shall be preserved by whatever runtime function we call, so they do not need
232// to be saved.
233.macro SETUP_SAVE_REFS_AND_ARGS_FRAME_INTERNAL
234#if (FRAME_SIZE_SAVE_REFS_AND_ARGS != 8*(1 + 8 + 7 + 11 + 1))
235#error "FRAME_SIZE_SAVE_REFS_AND_ARGS(RISCV64) size not as expected."
236#endif
237    // stack slot (0*8)(sp) is for ArtMethod*
238
239    SAVE_FPR fa0, (1*8)
240    SAVE_FPR fa1, (2*8)
241    SAVE_FPR fa2, (3*8)
242    SAVE_FPR fa3, (4*8)
243    SAVE_FPR fa4, (5*8)
244    SAVE_FPR fa5, (6*8)
245    SAVE_FPR fa6, (7*8)
246    SAVE_FPR fa7, (8*8)
247
248    SAVE_GPR fp,  (9*8)  // x8, frame pointer
249    // s1 (x9) is the ART thread register
250
251    // a0 (x10) is the method pointer
252    SAVE_GPR a1,  (10*8)  // x11
253    SAVE_GPR a2,  (11*8)  // x12
254    SAVE_GPR a3,  (12*8)  // x13
255    SAVE_GPR a4,  (13*8)  // x14
256    SAVE_GPR a5,  (14*8)  // x15
257    SAVE_GPR a6,  (15*8)  // x16
258    SAVE_GPR a7,  (16*8)  // x17
259
260    SAVE_GPR s2,  (17*8)  // x18
261    SAVE_GPR s3,  (18*8)  // x19
262    SAVE_GPR s4,  (19*8)  // x20
263    SAVE_GPR s5,  (20*8)  // x21
264    SAVE_GPR s6,  (21*8)  // x22
265    SAVE_GPR s7,  (22*8)  // x23
266    SAVE_GPR s8,  (23*8)  // x24
267    SAVE_GPR s9,  (24*8)  // x25
268    SAVE_GPR s10, (25*8)  // x26
269    SAVE_GPR s11, (26*8)  // x27
270
271    SAVE_GPR ra,  (27*8)  // x1, return address
272.endm
273
274
275.macro RESTORE_SAVE_REFS_AND_ARGS_FRAME_INTERNAL
276    // stack slot (0*8)(sp) is for ArtMethod*
277
278    RESTORE_FPR fa0, (1*8)
279    RESTORE_FPR fa1, (2*8)
280    RESTORE_FPR fa2, (3*8)
281    RESTORE_FPR fa3, (4*8)
282    RESTORE_FPR fa4, (5*8)
283    RESTORE_FPR fa5, (6*8)
284    RESTORE_FPR fa6, (7*8)
285    RESTORE_FPR fa7, (8*8)
286
287    RESTORE_GPR fp,  (9*8)  // x8, frame pointer
288
289    // a0 is the method pointer
290    RESTORE_GPR a1,  (10*8)  // x11
291    RESTORE_GPR a2,  (11*8)  // x12
292    RESTORE_GPR a3,  (12*8)  // x13
293    RESTORE_GPR a4,  (13*8)  // x14
294    RESTORE_GPR a5,  (14*8)  // x15
295    RESTORE_GPR a6,  (15*8)  // x16
296    RESTORE_GPR a7,  (16*8)  // x17
297
298    // s1 is the ART thread register
299    RESTORE_GPR s2,  (17*8)  // x18
300    RESTORE_GPR s3,  (18*8)  // x19
301    RESTORE_GPR s4,  (19*8)  // x20
302    RESTORE_GPR s5,  (20*8)  // x21
303    RESTORE_GPR s6,  (21*8)  // x22
304    RESTORE_GPR s7,  (22*8)  // x23
305    RESTORE_GPR s8,  (23*8)  // x24
306    RESTORE_GPR s9,  (24*8)  // x25
307    RESTORE_GPR s10, (25*8)  // x26
308    RESTORE_GPR s11, (26*8)  // x27
309
310    RESTORE_GPR ra,  (27*8)  // x1, return address
311.endm
312
313
314.macro SETUP_CALLEE_SAVE_FRAME_COMMON_INTERNAL reg
315    // ArtMethod* is in reg, store it at the bottom of the stack.
316    sd \reg, (sp)
317
318    // Place sp in Thread::Current()->top_quick_frame.
319    sd sp, THREAD_TOP_QUICK_FRAME_OFFSET(xSELF)
320.endm
321
322
323.macro SETUP_CALLEE_SAVE_FRAME_COMMON tmpreg, runtime_method_offset
324    // art::Runtime* tmpreg = art::Runtime::instance_;
325    LOAD_RUNTIME_INSTANCE \tmpreg
326
327    // ArtMethod* tmpreg = Runtime::instance_->callee_save_methods_[<callee-save-frame-type>];
328    ld  \tmpreg, \runtime_method_offset(\tmpreg)
329
330    SETUP_CALLEE_SAVE_FRAME_COMMON_INTERNAL \tmpreg
331.endm
332
333
334.macro SETUP_SAVE_REFS_AND_ARGS_FRAME
335    INCREASE_FRAME FRAME_SIZE_SAVE_REFS_AND_ARGS
336    SETUP_SAVE_REFS_AND_ARGS_FRAME_INTERNAL
337    SETUP_CALLEE_SAVE_FRAME_COMMON t0, RUNTIME_SAVE_REFS_AND_ARGS_METHOD_OFFSET
338.endm
339
340
341.macro SETUP_SAVE_REFS_AND_ARGS_FRAME_WITH_METHOD_IN_A0
342    INCREASE_FRAME FRAME_SIZE_SAVE_REFS_AND_ARGS
343    SETUP_SAVE_REFS_AND_ARGS_FRAME_INTERNAL
344    SETUP_CALLEE_SAVE_FRAME_COMMON_INTERNAL a0
345.endm
346
347
348.macro RESTORE_SAVE_REFS_AND_ARGS_FRAME
349    RESTORE_SAVE_REFS_AND_ARGS_FRAME_INTERNAL
350    DECREASE_FRAME FRAME_SIZE_SAVE_REFS_AND_ARGS
351.endm
352
353
354.macro SAVE_ALL_CALLEE_SAVES
355#if (FRAME_SIZE_SAVE_ALL_CALLEE_SAVES != 8*(12 + 11 + 1 + 1 + 1))
356#error "FRAME_SIZE_SAVE_ALL_CALLEE_SAVES(RISCV64) size not as expected."
357#endif
358    // stack slot (0*8)(sp) is for ArtMethod*
359    // stack slot (1*8)(sp) is for padding
360
361    // FP callee-saves.
362    SAVE_FPR fs0,  (8*2)   // f8
363    SAVE_FPR fs1,  (8*3)   // f9
364    SAVE_FPR fs2,  (8*4)   // f18
365    SAVE_FPR fs3,  (8*5)   // f19
366    SAVE_FPR fs4,  (8*6)   // f20
367    SAVE_FPR fs5,  (8*7)   // f21
368    SAVE_FPR fs6,  (8*8)   // f22
369    SAVE_FPR fs7,  (8*9)   // f23
370    SAVE_FPR fs8,  (8*10)  // f24
371    SAVE_FPR fs9,  (8*11)  // f25
372    SAVE_FPR fs10, (8*12)  // f26
373    SAVE_FPR fs11, (8*13)  // f27
374
375    // GP callee-saves
376    SAVE_GPR s0,  (8*14)  // x8/fp, frame pointer
377    // s1 (x9) is the ART thread register
378    SAVE_GPR s2,  (8*15)  // x18
379    SAVE_GPR s3,  (8*16)  // x19
380    SAVE_GPR s4,  (8*17)  // x20
381    SAVE_GPR s5,  (8*18)  // x21
382    SAVE_GPR s6,  (8*19)  // x22
383    SAVE_GPR s7,  (8*20)  // x23
384    SAVE_GPR s8,  (8*21)  // x24
385    SAVE_GPR s9,  (8*22)  // x25
386    SAVE_GPR s10, (8*23)  // x26
387    SAVE_GPR s11, (8*24)  // x27
388
389    SAVE_GPR ra,  (8*25)  // x1, return address
390.endm
391
392
393.macro RESTORE_ALL_CALLEE_SAVES
394#if (FRAME_SIZE_SAVE_ALL_CALLEE_SAVES != 8*(12 + 11 + 1 + 1 + 1))
395#error "FRAME_SIZE_SAVE_ALL_CALLEE_SAVES(RISCV64) size not as expected."
396#endif
397    // stack slot (8*0)(sp) is for ArtMethod*
398    // stack slot (8*1)(sp) is for padding
399
400    // FP callee-saves.
401    RESTORE_FPR fs0,  (8*2)   // f8
402    RESTORE_FPR fs1,  (8*3)   // f9
403    RESTORE_FPR fs2,  (8*4)   // f18
404    RESTORE_FPR fs3,  (8*5)   // f19
405    RESTORE_FPR fs4,  (8*6)   // f20
406    RESTORE_FPR fs5,  (8*7)   // f21
407    RESTORE_FPR fs6,  (8*8)   // f22
408    RESTORE_FPR fs7,  (8*9)   // f23
409    RESTORE_FPR fs8,  (8*10)  // f24
410    RESTORE_FPR fs9,  (8*11)  // f25
411    RESTORE_FPR fs10, (8*12)  // f26
412    RESTORE_FPR fs11, (8*13)  // f27
413
414    // GP callee-saves
415    RESTORE_GPR s0,  (8*14)  // x8/fp, frame pointer
416    // s1 is the ART thread register
417    RESTORE_GPR s2,  (8*15)  // x18
418    RESTORE_GPR s3,  (8*16)  // x19
419    RESTORE_GPR s4,  (8*17)  // x20
420    RESTORE_GPR s5,  (8*18)  // x21
421    RESTORE_GPR s6,  (8*19)  // x22
422    RESTORE_GPR s7,  (8*20)  // x23
423    RESTORE_GPR s8,  (8*21)  // x24
424    RESTORE_GPR s9,  (8*22)  // x25
425    RESTORE_GPR s10, (8*23)  // x26
426    RESTORE_GPR s11, (8*24)  // x27
427
428    RESTORE_GPR ra,  (8*25)  // x1, return address
429.endm
430
431
432.macro SETUP_SAVE_ALL_CALLEE_SAVES_FRAME
433    INCREASE_FRAME FRAME_SIZE_SAVE_ALL_CALLEE_SAVES
434    SAVE_ALL_CALLEE_SAVES
435    SETUP_CALLEE_SAVE_FRAME_COMMON t0, RUNTIME_SAVE_ALL_CALLEE_SAVES_METHOD_OFFSET
436.endm
437
438
439.macro SETUP_SAVE_EVERYTHING_FRAME_DECREMENTED_SP_SKIP_RA \
440        runtime_method_offset = RUNTIME_SAVE_EVERYTHING_METHOD_OFFSET
441#if (FRAME_SIZE_SAVE_EVERYTHING != 8*(1 + 32 + 27))
442#error "FRAME_SIZE_SAVE_EVERYTHING(RISCV64) size not as expected."
443#endif
444    // stack slot (8*0)(sp) is for ArtMethod*
445
446    // 32 slots for FPRs
447    SAVE_FPR ft0,  8*1   // f0
448    SAVE_FPR ft1,  8*2   // f1
449    SAVE_FPR ft2,  8*3   // f2
450    SAVE_FPR ft3,  8*4   // f3
451    SAVE_FPR ft4,  8*5   // f4
452    SAVE_FPR ft5,  8*6   // f5
453    SAVE_FPR ft6,  8*7   // f6
454    SAVE_FPR ft7,  8*8   // f7
455    SAVE_FPR fs0,  8*9   // f8
456    SAVE_FPR fs1,  8*10  // f9
457#define SAVE_EVERYTHING_FRAME_OFFSET_FA0 (8*11)
458    SAVE_FPR fa0,  8*11  // f10, its offset must equal SAVE_EVERYTHING_FRAME_OFFSET_FA0
459    SAVE_FPR fa1,  8*12  // f11
460    SAVE_FPR fa2,  8*13  // f12
461    SAVE_FPR fa3,  8*14  // f13
462    SAVE_FPR fa4,  8*15  // f14
463    SAVE_FPR fa5,  8*16  // f15
464    SAVE_FPR fa6,  8*17  // f16
465    SAVE_FPR fa7,  8*18  // f17
466    SAVE_FPR fs2,  8*19  // f18
467    SAVE_FPR fs3,  8*20  // f19
468    SAVE_FPR fs4,  8*21  // f20
469    SAVE_FPR fs5,  8*22  // f21
470    SAVE_FPR fs6,  8*23  // f22
471    SAVE_FPR fs7,  8*24  // f23
472    SAVE_FPR fs8,  8*25  // f24
473    SAVE_FPR fs9,  8*26  // f25
474    SAVE_FPR fs10, 8*27  // f26
475    SAVE_FPR fs11, 8*28  // f27
476    SAVE_FPR ft8,  8*29  // f28
477    SAVE_FPR ft9,  8*30  // f29
478    SAVE_FPR ft10, 8*31  // f30
479    SAVE_FPR ft11, 8*32  // f31
480
481    // 27 slots for GPRs (excluded: zero/x0, sp/x2, gp/x3, tp/x4, s1/x9 -- the ART thread register)
482    SAVE_GPR t0,  8*33  // x5
483    SAVE_GPR t1,  8*34  // x6
484    SAVE_GPR t2,  8*35  // x7
485    SAVE_GPR s0,  8*36  // x8
486#define SAVE_EVERYTHING_FRAME_OFFSET_A0 (8*37)
487    SAVE_GPR a0,  8*37  // x10, its offset must equal SAVE_EVERYTHING_FRAME_OFFSET_A0
488    SAVE_GPR a1,  8*38  // x11
489    SAVE_GPR a2,  8*39  // x12
490    SAVE_GPR a3,  8*40  // x13
491    SAVE_GPR a4,  8*41  // x14
492    SAVE_GPR a5,  8*42  // x15
493    SAVE_GPR a6,  8*43  // x16
494    SAVE_GPR a7,  8*44  // x17
495    SAVE_GPR s2,  8*45  // x18
496    SAVE_GPR s3,  8*46  // x19
497    SAVE_GPR s4,  8*47  // x20
498    SAVE_GPR s5,  8*48  // x21
499    SAVE_GPR s6,  8*49  // x22
500    SAVE_GPR s7,  8*50  // x23
501    SAVE_GPR s8,  8*51  // x24
502    SAVE_GPR s9,  8*52  // x25
503    SAVE_GPR s10, 8*53  // x26
504    SAVE_GPR s11, 8*54  // x27
505    SAVE_GPR t3,  8*55  // x28
506    SAVE_GPR t4,  8*56  // x29
507    SAVE_GPR t5,  8*57  // x30
508    SAVE_GPR t6,  8*58  // x31
509
510    // RA already saved by the user of this macro.
511
512    SETUP_CALLEE_SAVE_FRAME_COMMON t0, \runtime_method_offset
513.endm
514
515
516.macro SETUP_SAVE_EVERYTHING_FRAME runtime_method_offset = RUNTIME_SAVE_EVERYTHING_METHOD_OFFSET
517#if (FRAME_SIZE_SAVE_EVERYTHING != 8*(1 + 32 + 27))
518#error "FRAME_SIZE_SAVE_EVERYTHING(RISCV64) size not as expected."
519#endif
520    INCREASE_FRAME FRAME_SIZE_SAVE_EVERYTHING
521    SAVE_GPR ra,  8*59  // x1, return address
522    SETUP_SAVE_EVERYTHING_FRAME_DECREMENTED_SP_SKIP_RA \runtime_method_offset
523.endm
524
525
526.macro RESTORE_SAVE_EVERYTHING_FRAME load_a0 = 1
527    // stack slot (8*0)(sp) is for ArtMethod*
528
529    // 32 slots for FPRs
530    RESTORE_FPR ft0,  (8*1)   // f0
531    RESTORE_FPR ft1,  (8*2)   // f1
532    RESTORE_FPR ft2,  (8*3)   // f2
533    RESTORE_FPR ft3,  (8*4)   // f3
534    RESTORE_FPR ft4,  (8*5)   // f4
535    RESTORE_FPR ft5,  (8*6)   // f5
536    RESTORE_FPR ft6,  (8*7)   // f6
537    RESTORE_FPR ft7,  (8*8)   // f7
538    RESTORE_FPR fs0,  (8*9)   // f8
539    RESTORE_FPR fs1,  (8*10)  // f9
540#if SAVE_EVERYTHING_FRAME_OFFSET_FA0 != (8*11)
541#error "unexpected SAVE_EVERYTHING_FRAME_OFFSET_FA0"
542#endif
543    RESTORE_FPR fa0,  (8*11)  // f10, offset must equal SAVE_EVERYTHING_FRAME_OFFSET_FA0
544    RESTORE_FPR fa1,  (8*12)  // f11
545    RESTORE_FPR fa2,  (8*13)  // f12
546    RESTORE_FPR fa3,  (8*14)  // f13
547    RESTORE_FPR fa4,  (8*15)  // f14
548    RESTORE_FPR fa5,  (8*16)  // f15
549    RESTORE_FPR fa6,  (8*17)  // f16
550    RESTORE_FPR fa7,  (8*18)  // f17
551    RESTORE_FPR fs2,  (8*19)  // f18
552    RESTORE_FPR fs3,  (8*20)  // f19
553    RESTORE_FPR fs4,  (8*21)  // f20
554    RESTORE_FPR fs5,  (8*22)  // f21
555    RESTORE_FPR fs6,  (8*23)  // f22
556    RESTORE_FPR fs7,  (8*24)  // f23
557    RESTORE_FPR fs8,  (8*25)  // f24
558    RESTORE_FPR fs9,  (8*26)  // f25
559    RESTORE_FPR fs10, (8*27)  // f26
560    RESTORE_FPR fs11, (8*28)  // f27
561    RESTORE_FPR ft8,  (8*29)  // f28
562    RESTORE_FPR ft9,  (8*30)  // f29
563    RESTORE_FPR ft10, (8*31)  // f30
564    RESTORE_FPR ft11, (8*32)  // f31
565
566    // 26 slots for GPRs (excluded: zero/x0, sp/x2, gp/x3, tp/x4, s1/x9 -- the ART thread register)
567    RESTORE_GPR t0,  (8*33)  // x5
568    RESTORE_GPR t1,  (8*34)  // x6
569    RESTORE_GPR t2,  (8*35)  // x7
570    RESTORE_GPR s0,  (8*36)  // x8
571#if SAVE_EVERYTHING_FRAME_OFFSET_A0 != (8*37)
572#error "unexpected SAVE_EVERYTHING_FRAME_OFFSET_A0"
573#endif
574    .if \load_a0
575    RESTORE_GPR a0,  (8*37)  // x10, offset must equal SAVE_EVERYTHING_FRAME_OFFSET_A0
576    .endif
577    RESTORE_GPR a1,  (8*38)  // x11
578    RESTORE_GPR a2,  (8*39)  // x12
579    RESTORE_GPR a3,  (8*40)  // x13
580    RESTORE_GPR a4,  (8*41)  // x14
581    RESTORE_GPR a5,  (8*42)  // x15
582    RESTORE_GPR a6,  (8*43)  // x16
583    RESTORE_GPR a7,  (8*44)  // x17
584    RESTORE_GPR s2,  (8*45)  // x18
585    RESTORE_GPR s3,  (8*46)  // x19
586    RESTORE_GPR s4,  (8*47)  // x20
587    RESTORE_GPR s5,  (8*48)  // x21
588    RESTORE_GPR s6,  (8*49)  // x22
589    RESTORE_GPR s7,  (8*50)  // x23
590    RESTORE_GPR s8,  (8*51)  // x24
591    RESTORE_GPR s9,  (8*52)  // x25
592    RESTORE_GPR s10, (8*53)  // x26
593    RESTORE_GPR s11, (8*54)  // x27
594    RESTORE_GPR t3,  (8*55)  // x28
595    RESTORE_GPR t4,  (8*56)  // x29
596    RESTORE_GPR t5,  (8*57)  // x30
597    RESTORE_GPR t6,  (8*58)  // x31
598
599    RESTORE_GPR ra,  (8*59)  // x1, return address
600
601    DECREASE_FRAME FRAME_SIZE_SAVE_EVERYTHING
602.endm
603
604
605// For compatibility with Runtime::CreateCalleeSaveMethod(kSaveRefsOnly).
606.macro SETUP_SAVE_REFS_ONLY_FRAME
607    INCREASE_FRAME FRAME_SIZE_SAVE_REFS_ONLY
608
609    // stack slot (8*0)(sp) is for ArtMethod*
610    // stack slot (8*1)(sp) is for padding
611    SAVE_GPR s0,  (8*2)   // x8
612    SAVE_GPR s2,  (8*3)   // x18
613    SAVE_GPR s3,  (8*4)   // x19
614    SAVE_GPR s4,  (8*5)   // x20
615    SAVE_GPR s5,  (8*6)   // x21
616    SAVE_GPR s6,  (8*7)   // x22
617    SAVE_GPR s7,  (8*8)   // x23
618    SAVE_GPR s8,  (8*9)   // x24
619    SAVE_GPR s9,  (8*10)  // x25
620    SAVE_GPR s10, (8*11)  // x26
621    SAVE_GPR s11, (8*12)  // x27
622    SAVE_GPR ra,  (8*13)  // x1
623
624    SETUP_CALLEE_SAVE_FRAME_COMMON t0, RUNTIME_SAVE_REFS_ONLY_METHOD_OFFSET
625.endm
626
627
628.macro RESTORE_SAVE_REFS_ONLY_FRAME
629    // stack slot (8*0)(sp) is for ArtMethod*
630    // stack slot (8*1)(sp) is for padding
631    RESTORE_GPR s0,  (8*2)   // x8
632    RESTORE_GPR s2,  (8*3)   // x18
633    RESTORE_GPR s3,  (8*4)   // x19
634    RESTORE_GPR s4,  (8*5)   // x20
635    RESTORE_GPR s5,  (8*6)   // x21
636    RESTORE_GPR s6,  (8*7)   // x22
637    RESTORE_GPR s7,  (8*8)   // x23
638    RESTORE_GPR s8,  (8*9)   // x24
639    RESTORE_GPR s9,  (8*10)  // x25
640    RESTORE_GPR s10, (8*11)  // x26
641    RESTORE_GPR s11, (8*12)  // x27
642    RESTORE_GPR ra,  (8*13)  // x1
643
644    DECREASE_FRAME FRAME_SIZE_SAVE_REFS_ONLY
645.endm
646
647
648// CFI note. This macro is used where the CFA rule is a dwarf expression, so adjustment of SP does
649// not affect CFA computation. We also elide CFI descriptors for the argument registers, because
650// they can be recovered from the stack in a debugging scenario.
651.macro SPILL_ALL_ARGUMENTS
652#if (FRAME_SIZE_SAVE_ARGS_ONLY != 128)
653#error "FRAME_SIZE_SAVE_ARGS_ONLY(riscv64) not as expected."
654#endif
655    addi sp, sp, -FRAME_SIZE_SAVE_ARGS_ONLY
656    sd a0,   (8*0)(sp)
657    sd a1,   (8*1)(sp)
658    sd a2,   (8*2)(sp)
659    sd a3,   (8*3)(sp)
660    sd a4,   (8*4)(sp)
661    sd a5,   (8*5)(sp)
662    sd a6,   (8*6)(sp)
663    sd a7,   (8*7)(sp)
664    fsd fa0, (8*8)(sp)
665    fsd fa1, (8*9)(sp)
666    fsd fa2, (8*10)(sp)
667    fsd fa3, (8*11)(sp)
668    fsd fa4, (8*12)(sp)
669    fsd fa5, (8*13)(sp)
670    fsd fa6, (8*14)(sp)
671    fsd fa7, (8*15)(sp)
672.endm
673
674
675.macro RESTORE_ALL_ARGUMENTS
676    ld a0,   (8*0)(sp)
677    ld a1,   (8*1)(sp)
678    ld a2,   (8*2)(sp)
679    ld a3,   (8*3)(sp)
680    ld a4,   (8*4)(sp)
681    ld a5,   (8*5)(sp)
682    ld a6,   (8*6)(sp)
683    ld a7,   (8*7)(sp)
684    fld fa0, (8*8)(sp)
685    fld fa1, (8*9)(sp)
686    fld fa2, (8*10)(sp)
687    fld fa3, (8*11)(sp)
688    fld fa4, (8*12)(sp)
689    fld fa5, (8*13)(sp)
690    fld fa6, (8*14)(sp)
691    fld fa7, (8*15)(sp)
692    addi sp, sp, FRAME_SIZE_SAVE_ARGS_ONLY
693.endm
694
695
696.macro SETUP_NTERP_SAVE_CALLEE_SAVES
697#if (NTERP_SIZE_SAVE_CALLEE_SAVES != 8*(12 + 1 + 10 + 1))
698#error "NTERP_SIZE_SAVE_CALLEE_SAVES(RISCV64) size not as expected."
699#endif
700    // FP callee-saves.
701    SAVE_FPR fs0,  (8*0)   // f8
702    SAVE_FPR fs1,  (8*1)   // f9
703    SAVE_FPR fs2,  (8*2)   // f18
704    SAVE_FPR fs3,  (8*3)   // f19
705    SAVE_FPR fs4,  (8*4)   // f20
706    SAVE_FPR fs5,  (8*5)   // f21
707    SAVE_FPR fs6,  (8*6)   // f22
708    SAVE_FPR fs7,  (8*7)   // f23
709    SAVE_FPR fs8,  (8*8)   // f24
710    SAVE_FPR fs9,  (8*9)   // f25
711    SAVE_FPR fs10, (8*10)  // f26
712    SAVE_FPR fs11, (8*11)  // f27
713
714    // GP callee-saves
715    SAVE_GPR s0,  (8*12)  // x8/fp, frame pointer
716    // s1 (x9) is the ART thread register
717    SAVE_GPR s2,  (8*13)  // x18
718    SAVE_GPR s3,  (8*14)  // x19
719    SAVE_GPR s4,  (8*15)  // x20
720    SAVE_GPR s5,  (8*16)  // x21
721    SAVE_GPR s6,  (8*17)  // x22
722    SAVE_GPR s7,  (8*18)  // x23
723    SAVE_GPR s8,  (8*19)  // x24
724    SAVE_GPR s9,  (8*20)  // x25
725    SAVE_GPR s10, (8*21)  // x26
726    SAVE_GPR s11, (8*22)  // x27
727
728    SAVE_GPR ra,  (8*23)  // x1, return address
729.endm
730
731
732.macro RESTORE_NTERP_SAVE_CALLEE_SAVES
733#if (NTERP_SIZE_SAVE_CALLEE_SAVES != 8*(12 + 1 + 10 + 1))
734#error "NTERP_SIZE_SAVE_CALLEE_SAVES(RISCV64) size not as expected."
735#endif
736    // FP callee-saves.
737    RESTORE_FPR fs0,  (8*0)   // f8
738    RESTORE_FPR fs1,  (8*1)   // f9
739    RESTORE_FPR fs2,  (8*2)   // f18
740    RESTORE_FPR fs3,  (8*3)   // f19
741    RESTORE_FPR fs4,  (8*4)   // f20
742    RESTORE_FPR fs5,  (8*5)   // f21
743    RESTORE_FPR fs6,  (8*6)   // f22
744    RESTORE_FPR fs7,  (8*7)   // f23
745    RESTORE_FPR fs8,  (8*8)   // f24
746    RESTORE_FPR fs9,  (8*9)   // f25
747    RESTORE_FPR fs10, (8*10)  // f26
748    RESTORE_FPR fs11, (8*11)  // f27
749
750    // GP callee-saves
751    RESTORE_GPR s0,  (8*12)  // x8/fp, frame pointer
752    // s1 is the ART thread register
753    RESTORE_GPR s2,  (8*13)  // x18
754    RESTORE_GPR s3,  (8*14)  // x19
755    RESTORE_GPR s4,  (8*15)  // x20
756    RESTORE_GPR s5,  (8*16)  // x21
757    RESTORE_GPR s6,  (8*17)  // x22
758    RESTORE_GPR s7,  (8*18)  // x23
759    RESTORE_GPR s8,  (8*19)  // x24
760    RESTORE_GPR s9,  (8*20)  // x25
761    RESTORE_GPR s10, (8*21)  // x26
762    RESTORE_GPR s11, (8*22)  // x27
763
764    RESTORE_GPR ra,  (8*23)  // x1, return address
765.endm
766
767
768// Macro that calls through to artDeliverPendingExceptionFromCode, where the pending exception is
769// Thread::Current()->exception_ when the runtime method frame is ready.
770.macro DELIVER_PENDING_EXCEPTION_FRAME_READY
771    mv a0, xSELF
772    call artDeliverPendingExceptionFromCode
773    call art_quick_do_long_jump   // (Context*)
774    unimp  // Unreached
775.endm
776
777
778// Macro that calls through to artDeliverPendingExceptionFromCode, where the pending exception is
779// Thread::Current()->exception_.
780.macro DELIVER_PENDING_EXCEPTION
781    SETUP_SAVE_ALL_CALLEE_SAVES_FRAME
782    DELIVER_PENDING_EXCEPTION_FRAME_READY
783.endm
784
785
786.macro RETURN_OR_DELIVER_PENDING_EXCEPTION_REG reg
787    ld \reg, THREAD_EXCEPTION_OFFSET(xSELF)
788    bnez \reg, 1f
789    ret
7901:
791    DELIVER_PENDING_EXCEPTION
792.endm
793
794// Macro to emit a single LUI to load the given value while checking that the low 12 bits are zero.
795.macro LUI_VALUE reg, value
796    .if (\value & 0xfff) != 0
797    .error "Cannot use LUI to materialize a value with some of the low 12 bits set."
798    .endif
799    lui \reg, (\value) >> 12
800.endm
801
802
803// Locking is needed for both managed code and JNI stubs.
804.macro LOCK_OBJECT_FAST_PATH obj, slow_lock, can_be_null
805    // Use scratch registers T1-T6 as temporaries.
806    // Note: T0 is used as the argument register for `art_jni_lock_object` and passed as `obj`.
807    lw      t2, THREAD_ID_OFFSET(xSELF)
808    .if \can_be_null
809        beqz    \obj, \slow_lock
810    .endif
811    addi    t1, \obj, MIRROR_OBJECT_LOCK_WORD_OFFSET  // Exclusive load/store has no offset.
8121:
813    // Note: The LR/SC sequence must be at most 16 instructions, so we cannot have the
814    // recursive locking in a slow-path as on other architectures.
815    lr.w.aq t3, (t1)                  // Acquire needed only in most common case.
816    LUI_VALUE t5, LOCK_WORD_GC_STATE_MASK_SHIFTED  // Prepare mask for testing non-gc bits.
817    xor     t4, t3, t2                // Prepare the value to store if unlocked
818                                      //   (thread id, count of 0 and preserved read barrier bits),
819                                      // or prepare to compare thread id for recursive lock check
820                                      //   (lock_word.ThreadId() ^ self->ThreadId()).
821    or      t6, t5, t3                // Test the non-gc bits.
822    beq     t6, t5, 2f                // Check if unlocked.
823                                      // Check lock word state and thread id together,
824    LUI_VALUE \
825        t5, 0xffffffff ^ (LOCK_WORD_STATE_MASK_SHIFTED | LOCK_WORD_THIN_LOCK_OWNER_MASK_SHIFTED)
826    or      t6, t5, t4
827    bne     t6, t5, \slow_lock
828    LUI_VALUE t4, LOCK_WORD_THIN_LOCK_COUNT_ONE  // Increment the recursive lock count.
829    addw    t4, t3, t4
830    LUI_VALUE t5, LOCK_WORD_THIN_LOCK_COUNT_MASK_SHIFTED  // Test the new thin lock count.
831    and     t5, t4, t5
832    beqz    t5, \slow_lock            // Zero as the new count indicates overflow, go slow path.
8332:
834    // Store the prepared value:
835    //   - if unlocked, original lock word plus thread id,
836    //   - if already locked, original lock word plus incremented lock count.
837    sc.w    t3, t4, (t1)
838    bnez    t3, 1b                    // If the store failed, retry.
839    ret
840.endm
841
842// Unlocking is needed for both managed code and JNI stubs.
843.macro UNLOCK_OBJECT_FAST_PATH obj, slow_unlock, can_be_null
844    // Use scratch registers T1-T6 as temporaries.
845    // Note: T0 is used as the argument register for `art_jni_unlock_object` and passed as `obj`.
846    lw      t2, THREAD_ID_OFFSET(xSELF)
847    .if \can_be_null
848        beqz    \obj, \slow_unlock
849    .endif
850    addi    t1, \obj, MIRROR_OBJECT_LOCK_WORD_OFFSET  // Exclusive load/store has no offset.
8511:
852    // Note: Without read barriers, we could do plain LW here but there is no store-release
853    // other than SC on riscv64, so we do this with LR/SC for all cofigurations.
854    // Note: The LR/SC sequence must be at most 16 instructions, so we cannot have the
855    // recursive unlocking in a slow-path as on other architectures.
856    lr.w    t3, (t1)
857    LUI_VALUE t5, LOCK_WORD_GC_STATE_MASK_SHIFTED  // Prepare mask for testing non-gc bits.
858    xor     t4, t3, t2                // Prepare the value to store if simply locked
859                                      //   (mostly 0s, and preserved read barrier bits),
860                                      // or prepare to compare thread id for recursive lock check
861                                      //   (lock_word.ThreadId() ^ self->ThreadId()).
862    or      t6, t5, t4                // Test the non-gc bits.
863    beq     t6, t5, 2f                // Simply locked by this thread?
864                                      // Check lock word state and thread id together.
865    LUI_VALUE \
866        t5, 0xffffffff ^ (LOCK_WORD_STATE_MASK_SHIFTED | LOCK_WORD_THIN_LOCK_OWNER_MASK_SHIFTED)
867    or      t6, t5, t4
868    bne     t6, t5, \slow_unlock
869    LUI_VALUE t4, LOCK_WORD_THIN_LOCK_COUNT_ONE  // Decrement the recursive lock count.
870    subw    t4, t3, t4
8712:
872    // Store the prepared value:
873    //   - if simply locked, original lock word with removed thread id,
874    //   - if recursively locked, original lock word plus decremented lock count.
875    sc.w.rl t3, t4, (t1)              // Need to use atomic instructions for read barrier.
876    bnez    t3, 1b                    // If the store failed, retry.
877    ret
878.endm
879
880
881// Macros to branch based on the value of a specific bit.
882.macro BRANCH_IF_BIT_CLEAR tmp, reg, bit, dest
883    slli    \tmp, \reg, (63 - \bit) // tested bit => sign bit
884    bgez    \tmp, \dest
885.endm
886
887
888.macro BRANCH_IF_BIT_SET tmp, reg, bit, dest
889    slli    \tmp, \reg, (63 - \bit) // tested bit => sign bit
890    bltz    \tmp, \dest
891.endm
892
893
894#endif  // ART_RUNTIME_ARCH_RISCV64_ASM_SUPPORT_RISCV64_S_
895