xref: /aosp_15_r20/art/runtime/interpreter/mterp/riscv64/control_flow.S (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker// return-void
2*795d594fSAndroid Build Coastguard Worker// Format 10x: 00|0e
3*795d594fSAndroid Build Coastguard Worker%def op_return_void():
4*795d594fSAndroid Build Coastguard Worker%  op_return(is_void=True)
5*795d594fSAndroid Build Coastguard Worker
6*795d594fSAndroid Build Coastguard Worker
7*795d594fSAndroid Build Coastguard Worker// return vAA
8*795d594fSAndroid Build Coastguard Worker// Format 11x: AA|0f
9*795d594fSAndroid Build Coastguard Worker// Clobbers: t0
10*795d594fSAndroid Build Coastguard Worker%def op_return(is_object=False, is_void=False, is_wide=False):
11*795d594fSAndroid Build Coastguard Worker%  if is_void:
12*795d594fSAndroid Build Coastguard Worker     // Thread fence for constructor
13*795d594fSAndroid Build Coastguard Worker     fence w, w
14*795d594fSAndroid Build Coastguard Worker%  else:
15*795d594fSAndroid Build Coastguard Worker     srliw t0, xINST, 8  // t0 := AA
16*795d594fSAndroid Build Coastguard Worker%    if is_wide:
17*795d594fSAndroid Build Coastguard Worker       GET_VREG_WIDE a0, t0  // a0 := fp[AA:AA+1]
18*795d594fSAndroid Build Coastguard Worker       // The method may return to compiled code, so also place result in fa0.
19*795d594fSAndroid Build Coastguard Worker       fmv.d.x fa0, a0
20*795d594fSAndroid Build Coastguard Worker%    elif is_object:
21*795d594fSAndroid Build Coastguard Worker       GET_VREG_OBJECT a0, t0  // a0 := refs[AA]
22*795d594fSAndroid Build Coastguard Worker%    else:
23*795d594fSAndroid Build Coastguard Worker%      get_vreg("a0", "t0")    #  a0 := fp[AA]
24*795d594fSAndroid Build Coastguard Worker       // The method may return to compiled code, so also place result in fa0.
25*795d594fSAndroid Build Coastguard Worker       fmv.w.x fa0, a0
26*795d594fSAndroid Build Coastguard Worker%#:
27*795d594fSAndroid Build Coastguard Worker
28*795d594fSAndroid Build Coastguard Worker   CFI_REMEMBER_STATE
29*795d594fSAndroid Build Coastguard Worker   ld sp, -8(xREFS)  // caller's interpreted frame pointer
30*795d594fSAndroid Build Coastguard Worker   .cfi_def_cfa sp, NTERP_SIZE_SAVE_CALLEE_SAVES
31*795d594fSAndroid Build Coastguard Worker   RESTORE_NTERP_SAVE_CALLEE_SAVES
32*795d594fSAndroid Build Coastguard Worker   DECREASE_FRAME NTERP_SIZE_SAVE_CALLEE_SAVES
33*795d594fSAndroid Build Coastguard Worker   ret
34*795d594fSAndroid Build Coastguard Worker   // Since opcode handlers are merely labeled asm chunks within ExecuteNterpImpl's FDE, we must
35*795d594fSAndroid Build Coastguard Worker   // restate the correct CFA rule for subsequent handlers. It is initially stated when setting up
36*795d594fSAndroid Build Coastguard Worker   // the nterp frame (setup_nterp_frame).
37*795d594fSAndroid Build Coastguard Worker   .cfi_restore_state
38*795d594fSAndroid Build Coastguard Worker   CFI_DEF_CFA_BREG_PLUS_UCONST CFI_REFS, -8, NTERP_SIZE_SAVE_CALLEE_SAVES
39*795d594fSAndroid Build Coastguard Worker
40*795d594fSAndroid Build Coastguard Worker// return-wide vAA
41*795d594fSAndroid Build Coastguard Worker// Format 11x: AA|10
42*795d594fSAndroid Build Coastguard Worker%def op_return_wide():
43*795d594fSAndroid Build Coastguard Worker%  op_return(is_wide=True)
44*795d594fSAndroid Build Coastguard Worker
45*795d594fSAndroid Build Coastguard Worker// return-object vAA
46*795d594fSAndroid Build Coastguard Worker// Format 11x: AA|11
47*795d594fSAndroid Build Coastguard Worker%def op_return_object():
48*795d594fSAndroid Build Coastguard Worker%  op_return(is_object=True)
49*795d594fSAndroid Build Coastguard Worker
50*795d594fSAndroid Build Coastguard Worker// throw vAA
51*795d594fSAndroid Build Coastguard Worker// Format 11x: AA|27
52*795d594fSAndroid Build Coastguard Worker// Throw the indicated exception.
53*795d594fSAndroid Build Coastguard Worker%def op_throw():
54*795d594fSAndroid Build Coastguard Worker   EXPORT_PC
55*795d594fSAndroid Build Coastguard Worker   srliw t0, xINST, 8      // t0 := AA
56*795d594fSAndroid Build Coastguard Worker   GET_VREG_OBJECT a0, t0  // a0 := exception object
57*795d594fSAndroid Build Coastguard Worker   mv a1, xSELF
58*795d594fSAndroid Build Coastguard Worker   call art_quick_deliver_exception  // args a0, a1
59*795d594fSAndroid Build Coastguard Worker   unimp
60*795d594fSAndroid Build Coastguard Worker
61*795d594fSAndroid Build Coastguard Worker// goto +AA
62*795d594fSAndroid Build Coastguard Worker// Format 10t: AA|28
63*795d594fSAndroid Build Coastguard Worker// Unconditionally jump to the indicated instruction.
64*795d594fSAndroid Build Coastguard Worker// Note: The branch offset must not be 0.
65*795d594fSAndroid Build Coastguard Worker%def op_goto():
66*795d594fSAndroid Build Coastguard Worker   srliw t0, xINST, 8  // t0 := AA (zext)
67*795d594fSAndroid Build Coastguard Worker   sext.b t0, t0       // t0 := +AA (sext)
68*795d594fSAndroid Build Coastguard Worker   BRANCH units=t0
69*795d594fSAndroid Build Coastguard Worker
70*795d594fSAndroid Build Coastguard Worker// goto/16 +AAAA
71*795d594fSAndroid Build Coastguard Worker// Format 20t: 00|29 AAAA
72*795d594fSAndroid Build Coastguard Worker// Unconditionally jump to the indicated instruction.
73*795d594fSAndroid Build Coastguard Worker// Note: The branch offset must not be 0.
74*795d594fSAndroid Build Coastguard Worker%def op_goto_16():
75*795d594fSAndroid Build Coastguard Worker   FETCH t0, 1, signed=1  // t0 := +AAAA (sext)
76*795d594fSAndroid Build Coastguard Worker   BRANCH units=t0
77*795d594fSAndroid Build Coastguard Worker
78*795d594fSAndroid Build Coastguard Worker// goto/32 +AAAAAAAA
79*795d594fSAndroid Build Coastguard Worker// Format 30t: 00|2a AAAA(lo) AAAA(hi)
80*795d594fSAndroid Build Coastguard Worker// Unconditionally jump to the indicated instruction.
81*795d594fSAndroid Build Coastguard Worker%def op_goto_32():
82*795d594fSAndroid Build Coastguard Worker   FETCH t0, 1, signed=1, width=32  // t0 := +AAAAAAAA (sext)
83*795d594fSAndroid Build Coastguard Worker   BRANCH units=t0
84*795d594fSAndroid Build Coastguard Worker
85*795d594fSAndroid Build Coastguard Worker// packed-switch vAA, +BBBBBBBB
86*795d594fSAndroid Build Coastguard Worker// Format 31t: AA|2b BBBB(lo) BBBB(hi)
87*795d594fSAndroid Build Coastguard Worker// Jump to a new instruction based on the value in the given register, using a table of offsets
88*795d594fSAndroid Build Coastguard Worker// corresponding to each value in a particular integral range, or fall through to the next
89*795d594fSAndroid Build Coastguard Worker// instruction if there is no match.
90*795d594fSAndroid Build Coastguard Worker%def op_packed_switch(is_packed=True):
91*795d594fSAndroid Build Coastguard Worker   srliw t0, xINST, 8          // t0 := AA
92*795d594fSAndroid Build Coastguard Worker   FETCH t1, count=1, signed=1, width=32  // t1 := +BBBBBBBB (sext)
93*795d594fSAndroid Build Coastguard Worker%  get_vreg("a1", "t0")        #  a1 := vAA
94*795d594fSAndroid Build Coastguard Worker   sh1add a0, t1, xPC          // a0 := +BBBBBBBB * 2 + xPC
95*795d594fSAndroid Build Coastguard Worker%  if is_packed:
96*795d594fSAndroid Build Coastguard Worker     call NterpDoPackedSwitch  // args a0 (switchData), a1 (value)
97*795d594fSAndroid Build Coastguard Worker%  else:
98*795d594fSAndroid Build Coastguard Worker     call NterpDoSparseSwitch  // args a0 (switchData), a1 (value)
99*795d594fSAndroid Build Coastguard Worker%#:
100*795d594fSAndroid Build Coastguard Worker   BRANCH units=a0
101*795d594fSAndroid Build Coastguard Worker
102*795d594fSAndroid Build Coastguard Worker// sparse-switch vAA, +BBBBBBBB
103*795d594fSAndroid Build Coastguard Worker// Format 31t: AA|2c BBBB(lo) BBBB(hi)
104*795d594fSAndroid Build Coastguard Worker// Jump to a new instruction based on the value in the given register, using an ordered table of
105*795d594fSAndroid Build Coastguard Worker// value-offset pairs, or fall through to the next instruction if there is no match.
106*795d594fSAndroid Build Coastguard Worker%def op_sparse_switch():
107*795d594fSAndroid Build Coastguard Worker%  op_packed_switch(is_packed=False)
108*795d594fSAndroid Build Coastguard Worker
109*795d594fSAndroid Build Coastguard Worker// cmp-long vAA, vBB, vCC
110*795d594fSAndroid Build Coastguard Worker// Format 23x: AA|31 CC|BB
111*795d594fSAndroid Build Coastguard Worker%def op_cmp_long():
112*795d594fSAndroid Build Coastguard Worker   FETCH t1, count=1     // t1 := CC|BB
113*795d594fSAndroid Build Coastguard Worker   srliw t0, xINST, 8    // t0 := AA
114*795d594fSAndroid Build Coastguard Worker   srliw t2, t1, 8       // t2 := CC
115*795d594fSAndroid Build Coastguard Worker   andi t1, t1, 0xFF     // t1 := BB
116*795d594fSAndroid Build Coastguard Worker   GET_VREG_WIDE t1, t1  // t1 := fp[BB]
117*795d594fSAndroid Build Coastguard Worker   GET_VREG_WIDE t2, t2  // t2 := fp[CC]
118*795d594fSAndroid Build Coastguard Worker   // Note: Formula "(SLT r,l) - (SLT l,r)" lifted from compiler.
119*795d594fSAndroid Build Coastguard Worker   slt t3, t1, t2
120*795d594fSAndroid Build Coastguard Worker   slt t4, t2, t1
121*795d594fSAndroid Build Coastguard Worker   sub t4, t4, t3
122*795d594fSAndroid Build Coastguard Worker   FETCH_ADVANCE_INST 2
123*795d594fSAndroid Build Coastguard Worker%  set_vreg("t4", "t0", z0="t1")  # fp[AA] := t4
124*795d594fSAndroid Build Coastguard Worker   GET_INST_OPCODE t0
125*795d594fSAndroid Build Coastguard Worker   GOTO_OPCODE t0
126*795d594fSAndroid Build Coastguard Worker
127*795d594fSAndroid Build Coastguard Worker// Common helper for if-test.
128*795d594fSAndroid Build Coastguard Worker// Format 22t: B|A|op CCCC
129*795d594fSAndroid Build Coastguard Worker%def bincmp(op):
130*795d594fSAndroid Build Coastguard Worker   srliw t0, xINST, 8   // t0 := B|A
131*795d594fSAndroid Build Coastguard Worker   srliw t1, xINST, 12  // t1 := B
132*795d594fSAndroid Build Coastguard Worker   andi t0, t0, 0xF     // t0 := A
133*795d594fSAndroid Build Coastguard Worker%  get_vreg("t0", "t0")  # t0 := vA
134*795d594fSAndroid Build Coastguard Worker%  get_vreg("t1", "t1")  # t1 := vB
135*795d594fSAndroid Build Coastguard Worker   b${op} t0, t1, .L${opcode}_branch
136*795d594fSAndroid Build Coastguard Worker
137*795d594fSAndroid Build Coastguard Worker   FETCH_ADVANCE_INST 2
138*795d594fSAndroid Build Coastguard Worker   GET_INST_OPCODE t2
139*795d594fSAndroid Build Coastguard Worker   GOTO_OPCODE t2
140*795d594fSAndroid Build Coastguard Worker
141*795d594fSAndroid Build Coastguard Worker.L${opcode}_branch:
142*795d594fSAndroid Build Coastguard Worker   FETCH t2, count=1, signed=1  // t2 := +CCCC (sext)
143*795d594fSAndroid Build Coastguard Worker   BRANCH units=t2
144*795d594fSAndroid Build Coastguard Worker
145*795d594fSAndroid Build Coastguard Worker// if-eq vA, vB, +CCCC
146*795d594fSAndroid Build Coastguard Worker// Format 22t: B|A|32 CCCC
147*795d594fSAndroid Build Coastguard Worker// Branch to the given destination if the given two registers' values compare as specified.
148*795d594fSAndroid Build Coastguard Worker// Note: The branch offset must not be 0.
149*795d594fSAndroid Build Coastguard Worker%def op_if_eq():
150*795d594fSAndroid Build Coastguard Worker%  bincmp(op="eq")
151*795d594fSAndroid Build Coastguard Worker
152*795d594fSAndroid Build Coastguard Worker// if-ne vA, vB, +CCCC
153*795d594fSAndroid Build Coastguard Worker// Format 22t: B|A|33 CCCC
154*795d594fSAndroid Build Coastguard Worker// Branch to the given destination if the given two registers' values compare as specified.
155*795d594fSAndroid Build Coastguard Worker// Note: The branch offset must not be 0.
156*795d594fSAndroid Build Coastguard Worker%def op_if_ne():
157*795d594fSAndroid Build Coastguard Worker%  bincmp(op="ne")
158*795d594fSAndroid Build Coastguard Worker
159*795d594fSAndroid Build Coastguard Worker// if-lt vA, vB, +CCCC
160*795d594fSAndroid Build Coastguard Worker// Format 22t: B|A|34 CCCC
161*795d594fSAndroid Build Coastguard Worker// Branch to the given destination if the given two registers' values compare as specified.
162*795d594fSAndroid Build Coastguard Worker// Note: The branch offset must not be 0.
163*795d594fSAndroid Build Coastguard Worker%def op_if_lt():
164*795d594fSAndroid Build Coastguard Worker%  bincmp(op="lt")
165*795d594fSAndroid Build Coastguard Worker
166*795d594fSAndroid Build Coastguard Worker// if-ge vA, vB, +CCCC
167*795d594fSAndroid Build Coastguard Worker// Format 22t: B|A|35 CCCC
168*795d594fSAndroid Build Coastguard Worker// Branch to the given destination if the given two registers' values compare as specified.
169*795d594fSAndroid Build Coastguard Worker// Note: The branch offset must not be 0.
170*795d594fSAndroid Build Coastguard Worker%def op_if_ge():
171*795d594fSAndroid Build Coastguard Worker%  bincmp(op="ge")
172*795d594fSAndroid Build Coastguard Worker
173*795d594fSAndroid Build Coastguard Worker// if-gt vA, vB, +CCCC
174*795d594fSAndroid Build Coastguard Worker// Format 22t: B|A|36 CCCC
175*795d594fSAndroid Build Coastguard Worker// Branch to the given destination if the given two registers' values compare as specified.
176*795d594fSAndroid Build Coastguard Worker// Note: The branch offset must not be 0.
177*795d594fSAndroid Build Coastguard Worker%def op_if_gt():
178*795d594fSAndroid Build Coastguard Worker%  bincmp(op="gt")
179*795d594fSAndroid Build Coastguard Worker
180*795d594fSAndroid Build Coastguard Worker// if-le vA, vB, +CCCC
181*795d594fSAndroid Build Coastguard Worker// Format 22t: B|A|37 CCCC
182*795d594fSAndroid Build Coastguard Worker// Branch to the given destination if the given two registers' values compare as specified.
183*795d594fSAndroid Build Coastguard Worker// Note: The branch offset must not be 0.
184*795d594fSAndroid Build Coastguard Worker%def op_if_le():
185*795d594fSAndroid Build Coastguard Worker%  bincmp(op="le")
186*795d594fSAndroid Build Coastguard Worker
187*795d594fSAndroid Build Coastguard Worker// Common helper for if-testz.
188*795d594fSAndroid Build Coastguard Worker// Format 21t: AA|op BBBB
189*795d594fSAndroid Build Coastguard Worker%def zcmp(op):
190*795d594fSAndroid Build Coastguard Worker   srliw t0, xINST, 8   // t0 := AA
191*795d594fSAndroid Build Coastguard Worker%  get_vreg("t0", "t0")  # t0 := vAA
192*795d594fSAndroid Build Coastguard Worker   b${op} t0, .L${opcode}_branch
193*795d594fSAndroid Build Coastguard Worker
194*795d594fSAndroid Build Coastguard Worker   FETCH_ADVANCE_INST 2
195*795d594fSAndroid Build Coastguard Worker   GET_INST_OPCODE t1
196*795d594fSAndroid Build Coastguard Worker   GOTO_OPCODE t1
197*795d594fSAndroid Build Coastguard Worker
198*795d594fSAndroid Build Coastguard Worker.L${opcode}_branch:
199*795d594fSAndroid Build Coastguard Worker   FETCH t1, count=1, signed=1  // t1 := +BBBB (sext)
200*795d594fSAndroid Build Coastguard Worker   BRANCH units=t1
201*795d594fSAndroid Build Coastguard Worker
202*795d594fSAndroid Build Coastguard Worker// if-eqz vAA, +BBBB
203*795d594fSAndroid Build Coastguard Worker// Format 21t: AA|38 BBBB
204*795d594fSAndroid Build Coastguard Worker// Branch to the given destination if the given register's value compares with 0 as specified.
205*795d594fSAndroid Build Coastguard Worker// Note: The branch offset must not be 0.
206*795d594fSAndroid Build Coastguard Worker%def op_if_eqz():
207*795d594fSAndroid Build Coastguard Worker%  zcmp(op="eqz")
208*795d594fSAndroid Build Coastguard Worker
209*795d594fSAndroid Build Coastguard Worker// if-nez vAA, +BBBB
210*795d594fSAndroid Build Coastguard Worker// Format 21t: AA|39 BBBB
211*795d594fSAndroid Build Coastguard Worker// Branch to the given destination if the given register's value compares with 0 as specified.
212*795d594fSAndroid Build Coastguard Worker// Note: The branch offset must not be 0.
213*795d594fSAndroid Build Coastguard Worker%def op_if_nez():
214*795d594fSAndroid Build Coastguard Worker%  zcmp(op="nez")
215*795d594fSAndroid Build Coastguard Worker
216*795d594fSAndroid Build Coastguard Worker// if-ltz vAA, +BBBB
217*795d594fSAndroid Build Coastguard Worker// Format 21t: AA|3a BBBB
218*795d594fSAndroid Build Coastguard Worker// Branch to the given destination if the given register's value compares with 0 as specified.
219*795d594fSAndroid Build Coastguard Worker// Note: The branch offset must not be 0.
220*795d594fSAndroid Build Coastguard Worker%def op_if_ltz():
221*795d594fSAndroid Build Coastguard Worker%  zcmp(op="ltz")
222*795d594fSAndroid Build Coastguard Worker
223*795d594fSAndroid Build Coastguard Worker// if-gez vAA, +BBBB
224*795d594fSAndroid Build Coastguard Worker// Format 21t: AA|3b BBBB
225*795d594fSAndroid Build Coastguard Worker// Branch to the given destination if the given register's value compares with 0 as specified.
226*795d594fSAndroid Build Coastguard Worker// Note: The branch offset must not be 0.
227*795d594fSAndroid Build Coastguard Worker%def op_if_gez():
228*795d594fSAndroid Build Coastguard Worker%  zcmp(op="gez")
229*795d594fSAndroid Build Coastguard Worker
230*795d594fSAndroid Build Coastguard Worker// if-gtz vAA, +BBBB
231*795d594fSAndroid Build Coastguard Worker// Format 21t: AA|3c BBBB
232*795d594fSAndroid Build Coastguard Worker// Branch to the given destination if the given register's value compares with 0 as specified.
233*795d594fSAndroid Build Coastguard Worker// Note: The branch offset must not be 0.
234*795d594fSAndroid Build Coastguard Worker%def op_if_gtz():
235*795d594fSAndroid Build Coastguard Worker%  zcmp(op="gtz")
236*795d594fSAndroid Build Coastguard Worker
237*795d594fSAndroid Build Coastguard Worker// if-lez vAA, +BBBB
238*795d594fSAndroid Build Coastguard Worker// Format 21t: AA|3d BBBB
239*795d594fSAndroid Build Coastguard Worker// Branch to the given destination if the given register's value compares with 0 as specified.
240*795d594fSAndroid Build Coastguard Worker// Note: The branch offset must not be 0.
241*795d594fSAndroid Build Coastguard Worker%def op_if_lez():
242*795d594fSAndroid Build Coastguard Worker%  zcmp(op="lez")
243*795d594fSAndroid Build Coastguard Worker
244