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