xref: /aosp_15_r20/art/runtime/interpreter/mterp/riscv64/invoke.S (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker// Theory of operation. These invoke-X opcodes bounce to code labels in main.S which attempt a
2*795d594fSAndroid Build Coastguard Worker// variety of fast paths; the full asm doesn't fit in the per-opcode handler's size limit.
3*795d594fSAndroid Build Coastguard Worker//
4*795d594fSAndroid Build Coastguard Worker// Calling convention. There are three argument transfer types.
5*795d594fSAndroid Build Coastguard Worker// (A) Managed ABI -> Nterp. The ExecuteNterpImpl handles this case. We set up a fresh nterp frame
6*795d594fSAndroid Build Coastguard Worker//     and move arguments from machine arg registers (and sometimes stack) into the frame.
7*795d594fSAndroid Build Coastguard Worker// (B) Nterp -> Nterp. An invoke op's fast path handles this case. If we can stay in nterp, then
8*795d594fSAndroid Build Coastguard Worker//     we set up a fresh nterp frame, and copy the register slots from caller to callee.
9*795d594fSAndroid Build Coastguard Worker// (C) Nterp -> Managed ABI. Invoke op's remaining cases. To leave nterp, we read out arguments from
10*795d594fSAndroid Build Coastguard Worker//     the caller's nterp frame and place them into machine arg registers (and sometimes stack).
11*795d594fSAndroid Build Coastguard Worker//     Doing so requires obtaining and deciphering the method's shorty for arg type, width, and
12*795d594fSAndroid Build Coastguard Worker//     order info.
13*795d594fSAndroid Build Coastguard Worker//
14*795d594fSAndroid Build Coastguard Worker// Fast path structure.
15*795d594fSAndroid Build Coastguard Worker// (0) If the next method's "quick code" is nterp, then set up a fresh nterp frame and perform a
16*795d594fSAndroid Build Coastguard Worker//     vreg->vreg transfer. Jump to handler for the next method's first opcode.
17*795d594fSAndroid Build Coastguard Worker// - The following paths leave nterp. -
18*795d594fSAndroid Build Coastguard Worker// (1) If the next method is guaranteed to be only object refs, then the managed ABI is very simple:
19*795d594fSAndroid Build Coastguard Worker//     just place all arguments in the native arg registers using LWU. Call the quick code.
20*795d594fSAndroid Build Coastguard Worker// (2) The next method might have an arg/return shape that can avoid the shorty, or at least avoid
21*795d594fSAndroid Build Coastguard Worker//     most complications of the managed ABI arg setup.
22*795d594fSAndroid Build Coastguard Worker// (2.1) If the next method has 0 args, then peek ahead in dex: if no scalar return, then call the
23*795d594fSAndroid Build Coastguard Worker//       quick code. (Even when the next opcode is move-result-object, nterp will expect the
24*795d594fSAndroid Build Coastguard Worker//       reference at a0, matching where the managed ABI leaves it after the call.)
25*795d594fSAndroid Build Coastguard Worker// (2.2) If the next method has 0 args and scalar return, or has 1 arg, then obtain the shorty.
26*795d594fSAndroid Build Coastguard Worker// (2.2.1) Post-shorty: if 0 args, call the quick code. (After the call, a returned float must be
27*795d594fSAndroid Build Coastguard Worker//         copied from fa0 into a0.)
28*795d594fSAndroid Build Coastguard Worker// (2.2.2) Post-shorty: check the arg's shorty type. If 'L', we must load it with LWU. Otherwise, we
29*795d594fSAndroid Build Coastguard Worker//         load it with LW and store a copy into FA0 (to avoid another branch). Call the quick code.
30*795d594fSAndroid Build Coastguard Worker// - The fully pessimistic case. -
31*795d594fSAndroid Build Coastguard Worker// (3) The next method has 2+ arguments with a mix of float/double/long, OR it is polymorphic OR
32*795d594fSAndroid Build Coastguard Worker//     custom. Obtain the shorty and perform the full setup for managed ABI. Polymorphic and
33*795d594fSAndroid Build Coastguard Worker//     custom invokes are specially shunted to the runtime. Otherwise we call the quick code.
34*795d594fSAndroid Build Coastguard Worker//
35*795d594fSAndroid Build Coastguard Worker// Code organization. These functions are organized in a three tier structure to aid readability.
36*795d594fSAndroid Build Coastguard Worker// (P) The "front end" is an opcode handler, such as op_invoke_virtual(). They are defined in
37*795d594fSAndroid Build Coastguard Worker//     invoke.S. Since all the invoke code cannot fit in the allotted handler region, every invoke
38*795d594fSAndroid Build Coastguard Worker//     handler has code extending into a "back end".
39*795d594fSAndroid Build Coastguard Worker// (Q) The opcode handler calls a "back end" label that is located in main.S. The code for that
40*795d594fSAndroid Build Coastguard Worker//     label is defined in invoke.S. As a convention, the label in main.S is NterpInvokeVirtual. The
41*795d594fSAndroid Build Coastguard Worker//     code in invoke.S is nterp_invoke_virtual().
42*795d594fSAndroid Build Coastguard Worker// (R) For the Nterp to Nterp fast path case, the back end calls a label located in main.S, the code
43*795d594fSAndroid Build Coastguard Worker//     for which is defined in invoke.S. As a convention, the label in main.S is
44*795d594fSAndroid Build Coastguard Worker//     NterpToNterpInstance, and the code in invoke.S is nterp_to_nterp_instance().
45*795d594fSAndroid Build Coastguard Worker// Helpers for each tier are placed just after the functions of each tier.
46*795d594fSAndroid Build Coastguard Worker
47*795d594fSAndroid Build Coastguard Worker//
48*795d594fSAndroid Build Coastguard Worker// invoke-kind {vC, vD, vE, vF, vG}, meth@BBBB
49*795d594fSAndroid Build Coastguard Worker// Format 35c: A|G|op BBBB F|E|D|C
50*795d594fSAndroid Build Coastguard Worker//
51*795d594fSAndroid Build Coastguard Worker
52*795d594fSAndroid Build Coastguard Worker// invoke-virtual {vC, vD, vE, vF, vG}, meth@BBBB
53*795d594fSAndroid Build Coastguard Worker// Format 35c: A|G|6e BBBB F|E|D|C
54*795d594fSAndroid Build Coastguard Worker//
55*795d594fSAndroid Build Coastguard Worker// Note: invoke-virtual is used to invoke a normal virtual method (a method that is not private,
56*795d594fSAndroid Build Coastguard Worker// static, or final, and is also not a constructor).
57*795d594fSAndroid Build Coastguard Worker%def op_invoke_virtual(range=""):
58*795d594fSAndroid Build Coastguard Worker   EXPORT_PC
59*795d594fSAndroid Build Coastguard Worker   FETCH s7, count=2                // s7 := F|E|D|C or CCCC (range)
60*795d594fSAndroid Build Coastguard Worker   FETCH_FROM_THREAD_CACHE a0, /*slow path*/2f, t0, t1
61*795d594fSAndroid Build Coastguard Worker                                    // a0 := method idx of resolved virtual method
62*795d594fSAndroid Build Coastguard Worker1:
63*795d594fSAndroid Build Coastguard Worker%  fetch_receiver(reg="a1", vreg="s7", range=range)
64*795d594fSAndroid Build Coastguard Worker                                    // a1 := fp[C] (this)
65*795d594fSAndroid Build Coastguard Worker   // Note: null case handled by SEGV handler.
66*795d594fSAndroid Build Coastguard Worker   lwu t0, MIRROR_OBJECT_CLASS_OFFSET(a1)
67*795d594fSAndroid Build Coastguard Worker                                    // t0 := klass object (32-bit addr)
68*795d594fSAndroid Build Coastguard Worker   UNPOISON_HEAP_REF t0
69*795d594fSAndroid Build Coastguard Worker   // Entry address = entry's byte offset in vtable + vtable's byte offset in klass object.
70*795d594fSAndroid Build Coastguard Worker   sh3add a0, a0, t0                // a0 := entry's byte offset
71*795d594fSAndroid Build Coastguard Worker   ld a0, MIRROR_CLASS_VTABLE_OFFSET_64(a0)
72*795d594fSAndroid Build Coastguard Worker                                    // a0 := ArtMethod*
73*795d594fSAndroid Build Coastguard Worker   tail NterpInvokeVirtual${range}  // args a0, a1, s7
74*795d594fSAndroid Build Coastguard Worker2:
75*795d594fSAndroid Build Coastguard Worker%  resolve_method_into_a0()
76*795d594fSAndroid Build Coastguard Worker   j 1b
77*795d594fSAndroid Build Coastguard Worker
78*795d594fSAndroid Build Coastguard Worker
79*795d594fSAndroid Build Coastguard Worker// invoke-super {vC, vD, vE, vF, vG}, meth@BBBB
80*795d594fSAndroid Build Coastguard Worker// Format 35c: A|G|6f BBBB F|E|D|C
81*795d594fSAndroid Build Coastguard Worker//
82*795d594fSAndroid Build Coastguard Worker// Note: When the method_id references a method of a non-interface class, invoke-super is used to
83*795d594fSAndroid Build Coastguard Worker// invoke the closest superclass's virtual method (as opposed to the one with the same method_id in
84*795d594fSAndroid Build Coastguard Worker// the calling class).
85*795d594fSAndroid Build Coastguard Worker// Note: In Dex files version 037 or later, if the method_id refers to an interface method,
86*795d594fSAndroid Build Coastguard Worker// invoke-super is used to invoke the most specific, non-overridden version of that method defined
87*795d594fSAndroid Build Coastguard Worker// on that interface. The same method restrictions hold as for invoke-virtual. In Dex files prior to
88*795d594fSAndroid Build Coastguard Worker// version 037, having an interface method_id is illegal and undefined.
89*795d594fSAndroid Build Coastguard Worker%def op_invoke_super(range=""):
90*795d594fSAndroid Build Coastguard Worker   EXPORT_PC
91*795d594fSAndroid Build Coastguard Worker   FETCH s7, count=2              // s7 := F|E|D|C or CCCC (range)
92*795d594fSAndroid Build Coastguard Worker   FETCH_FROM_THREAD_CACHE a0, /*slow path*/2f, t0, t1
93*795d594fSAndroid Build Coastguard Worker                                  // a0 := ArtMethod*
94*795d594fSAndroid Build Coastguard Worker1:
95*795d594fSAndroid Build Coastguard Worker%  fetch_receiver(reg="a1", vreg="s7", range=range)
96*795d594fSAndroid Build Coastguard Worker                                  // a1 := fp[C] (this)
97*795d594fSAndroid Build Coastguard Worker   beqz a1, 3f                    // throw if null
98*795d594fSAndroid Build Coastguard Worker   tail NterpInvokeSuper${range}  // args a0, a1, s7
99*795d594fSAndroid Build Coastguard Worker2:
100*795d594fSAndroid Build Coastguard Worker%  resolve_method_into_a0()
101*795d594fSAndroid Build Coastguard Worker   j 1b
102*795d594fSAndroid Build Coastguard Worker3:
103*795d594fSAndroid Build Coastguard Worker   tail common_errNullObject
104*795d594fSAndroid Build Coastguard Worker
105*795d594fSAndroid Build Coastguard Worker
106*795d594fSAndroid Build Coastguard Worker// invoke-direct {vC, vD, vE, vF, vG}, meth@BBBB
107*795d594fSAndroid Build Coastguard Worker// Format 35c: A|G|70 BBBB F|E|D|C
108*795d594fSAndroid Build Coastguard Worker//
109*795d594fSAndroid Build Coastguard Worker// Note: invoke-direct is used to invoke a non-static direct method (that is, an instance method
110*795d594fSAndroid Build Coastguard Worker// that is by its nature non-overridable, namely either a private instance method or a constructor).
111*795d594fSAndroid Build Coastguard Worker//
112*795d594fSAndroid Build Coastguard Worker// For additional context on string init, see b/28555675. The object reference is replaced after
113*795d594fSAndroid Build Coastguard Worker// the string factory call, so we disable thread-caching the resolution of string init, and skip
114*795d594fSAndroid Build Coastguard Worker// fast paths out to managed ABI calls.
115*795d594fSAndroid Build Coastguard Worker%def op_invoke_direct(range=""):
116*795d594fSAndroid Build Coastguard Worker   EXPORT_PC
117*795d594fSAndroid Build Coastguard Worker   FETCH s7, count=2               // s7 := F|E|D|C or CCCC (range)
118*795d594fSAndroid Build Coastguard Worker   FETCH_FROM_THREAD_CACHE a0, /*slow path*/2f, t0, t1
119*795d594fSAndroid Build Coastguard Worker                                   // a0 := ArtMethod*, never String.<init>
120*795d594fSAndroid Build Coastguard Worker1:
121*795d594fSAndroid Build Coastguard Worker%  fetch_receiver(reg="a1", vreg="s7", range=range)
122*795d594fSAndroid Build Coastguard Worker                                   // a1 := fp[C] (this)
123*795d594fSAndroid Build Coastguard Worker   beqz a1, 3f                     // throw if null
124*795d594fSAndroid Build Coastguard Worker   tail NterpInvokeDirect${range}  // args a0, a1, s7
125*795d594fSAndroid Build Coastguard Worker2:
126*795d594fSAndroid Build Coastguard Worker%  resolve_method_into_a0()        #  a0 := ArtMethod* or String.<init>
127*795d594fSAndroid Build Coastguard Worker   and t0, a0, 0x1                 // t0 := string-init bit
128*795d594fSAndroid Build Coastguard Worker   beqz t0, 1b                     // not string init
129*795d594fSAndroid Build Coastguard Worker   and a0, a0, ~0x1                // clear string-init bit
130*795d594fSAndroid Build Coastguard Worker   tail NterpInvokeStringInit${range}  // args a0, s7
131*795d594fSAndroid Build Coastguard Worker3:
132*795d594fSAndroid Build Coastguard Worker   tail common_errNullObject
133*795d594fSAndroid Build Coastguard Worker
134*795d594fSAndroid Build Coastguard Worker
135*795d594fSAndroid Build Coastguard Worker// invoke-static {vC, vD, vE, vF, vG}, meth@BBBB
136*795d594fSAndroid Build Coastguard Worker// Format 35c: A|G|71 BBBB F|E|D|C
137*795d594fSAndroid Build Coastguard Worker//
138*795d594fSAndroid Build Coastguard Worker// Note: invoke-static is used to invoke a static method (which is always considered a direct
139*795d594fSAndroid Build Coastguard Worker// method).
140*795d594fSAndroid Build Coastguard Worker%def op_invoke_static(range=""):
141*795d594fSAndroid Build Coastguard Worker   EXPORT_PC
142*795d594fSAndroid Build Coastguard Worker   // TODO: Unnecessary if A=0, and unnecessary if nterp-to-nterp.
143*795d594fSAndroid Build Coastguard Worker   FETCH s7, count=2               // s7 := F|E|D|C or CCCC (range)
144*795d594fSAndroid Build Coastguard Worker   FETCH_FROM_THREAD_CACHE a0, /*slow path*/1f, t0, t1
145*795d594fSAndroid Build Coastguard Worker                                   // a0 := ArtMethod*
146*795d594fSAndroid Build Coastguard Worker   tail NterpInvokeStatic${range}  // arg a0, s7
147*795d594fSAndroid Build Coastguard Worker1:
148*795d594fSAndroid Build Coastguard Worker%  resolve_method_into_a0()
149*795d594fSAndroid Build Coastguard Worker   tail NterpInvokeStatic${range}  // arg a0, s7
150*795d594fSAndroid Build Coastguard Worker
151*795d594fSAndroid Build Coastguard Worker
152*795d594fSAndroid Build Coastguard Worker// invoke-interface {vC, vD, vE, vF, vG}, meth@BBBB
153*795d594fSAndroid Build Coastguard Worker// Format 35c: A|G|72 BBBB F|E|D|C
154*795d594fSAndroid Build Coastguard Worker//
155*795d594fSAndroid Build Coastguard Worker// Note: invoke-interface is used to invoke an interface method, that is, on an object whose
156*795d594fSAndroid Build Coastguard Worker// concrete class isn't known, using a method_id that refers to an interface.
157*795d594fSAndroid Build Coastguard Worker%def op_invoke_interface(range=""):
158*795d594fSAndroid Build Coastguard Worker   EXPORT_PC
159*795d594fSAndroid Build Coastguard Worker   FETCH s7, count=2               // s7 := F|E|D|C or CCCC (range)
160*795d594fSAndroid Build Coastguard Worker   // T0 is eventually used to carry the "hidden argument" in the managed ABI.
161*795d594fSAndroid Build Coastguard Worker   // This handler is tight on space, so we cache this arg in A0 and move it to T0 later.
162*795d594fSAndroid Build Coastguard Worker   // Here, A0 is one of
163*795d594fSAndroid Build Coastguard Worker   // (1) ArtMethod*
164*795d594fSAndroid Build Coastguard Worker   // (2) ArtMethod* with LSB #1 set (default method)
165*795d594fSAndroid Build Coastguard Worker   // (3) method index << 16 with LSB #0 set (j.l.Object method)
166*795d594fSAndroid Build Coastguard Worker   FETCH_FROM_THREAD_CACHE a0, /*slow path*/5f, t0, t1
167*795d594fSAndroid Build Coastguard Worker1:
168*795d594fSAndroid Build Coastguard Worker%  fetch_receiver(reg="a1", vreg="s7", range=range)
169*795d594fSAndroid Build Coastguard Worker                          // a1 := fp[C] (this)
170*795d594fSAndroid Build Coastguard Worker   // Note: null case handled by SEGV handler.
171*795d594fSAndroid Build Coastguard Worker   lwu t0, MIRROR_OBJECT_CLASS_OFFSET(a1)
172*795d594fSAndroid Build Coastguard Worker                          // t0 := klass object (32-bit addr)
173*795d594fSAndroid Build Coastguard Worker   UNPOISON_HEAP_REF t0
174*795d594fSAndroid Build Coastguard Worker   slliw t1, a0, 30       // test LSB #0 and #1
175*795d594fSAndroid Build Coastguard Worker   bltz t1, 3f            // LSB #1 is set; handle default method
176*795d594fSAndroid Build Coastguard Worker   bgtz t1, 4f            // LSB #0 is set; handle object method
177*795d594fSAndroid Build Coastguard Worker   // no signal bits; it is a clean ArtMethod*
178*795d594fSAndroid Build Coastguard Worker   lhu t1, ART_METHOD_IMT_INDEX_OFFSET(a0)
179*795d594fSAndroid Build Coastguard Worker                          // t1 := idx into interface method table (16-bit value)
180*795d594fSAndroid Build Coastguard Worker2:
181*795d594fSAndroid Build Coastguard Worker   ld t0, MIRROR_CLASS_IMT_PTR_OFFSET_64(t0)
182*795d594fSAndroid Build Coastguard Worker                          // t0 := base address of imt
183*795d594fSAndroid Build Coastguard Worker   sh3add t0, t1, t0      // t0 := entry's address in imt
184*795d594fSAndroid Build Coastguard Worker   ld a2, (t0)            // a2 := ArtMethod*
185*795d594fSAndroid Build Coastguard Worker   tail NterpInvokeInterface${range}  // a0 (hidden arg), a1 (this), a2 (ArtMethod*), s7 (vregs)
186*795d594fSAndroid Build Coastguard Worker3:
187*795d594fSAndroid Build Coastguard Worker   andi a0, a0, ~2        // a0 := default ArtMethod*, LSB #1 cleared
188*795d594fSAndroid Build Coastguard Worker   lhu t1, ART_METHOD_METHOD_INDEX_OFFSET(a0)
189*795d594fSAndroid Build Coastguard Worker                          // t1 := method_index_ (16-bit value)
190*795d594fSAndroid Build Coastguard Worker   // Default methods have a contract with art::IMTable.
191*795d594fSAndroid Build Coastguard Worker   andi t1, t1, ART_METHOD_IMT_MASK
192*795d594fSAndroid Build Coastguard Worker                          // t1 := idx into interface method table
193*795d594fSAndroid Build Coastguard Worker   j 2b
194*795d594fSAndroid Build Coastguard Worker4:
195*795d594fSAndroid Build Coastguard Worker   // Interface methods on j.l.Object have a contract with NterpGetMethod.
196*795d594fSAndroid Build Coastguard Worker   srliw t1, a0, 16       // t3 := method index
197*795d594fSAndroid Build Coastguard Worker   sh3add t0, t1, t0      // t0 := entry's byte offset, before vtable offset adjustment
198*795d594fSAndroid Build Coastguard Worker   ld a0, MIRROR_CLASS_VTABLE_OFFSET_64(t0)
199*795d594fSAndroid Build Coastguard Worker   tail NterpInvokeDirect${range}  // args a0, a1, s7
200*795d594fSAndroid Build Coastguard Worker5:
201*795d594fSAndroid Build Coastguard Worker%  resolve_method_into_a0()
202*795d594fSAndroid Build Coastguard Worker   j 1b
203*795d594fSAndroid Build Coastguard Worker
204*795d594fSAndroid Build Coastguard Worker
205*795d594fSAndroid Build Coastguard Worker//
206*795d594fSAndroid Build Coastguard Worker// invoke-kind/range {vCCCC .. vNNNN}, meth@BBBB
207*795d594fSAndroid Build Coastguard Worker// Format 3rc: AA|op BBBB CCCC
208*795d594fSAndroid Build Coastguard Worker// where NNNN = CCCC + AA - 1, that is A determines the count 0..255, and C determines the first
209*795d594fSAndroid Build Coastguard Worker// register.
210*795d594fSAndroid Build Coastguard Worker//
211*795d594fSAndroid Build Coastguard Worker
212*795d594fSAndroid Build Coastguard Worker// invoke-virtual/range {vCCCC .. vNNNN}, meth@BBBB
213*795d594fSAndroid Build Coastguard Worker// Format 3rc: AA|74 BBBB CCCC
214*795d594fSAndroid Build Coastguard Worker//
215*795d594fSAndroid Build Coastguard Worker// Note: invoke-virtual/range is used to invoke a normal virtual method (a method that is not
216*795d594fSAndroid Build Coastguard Worker// private, static, or final, and is also not a constructor).
217*795d594fSAndroid Build Coastguard Worker%def op_invoke_virtual_range():
218*795d594fSAndroid Build Coastguard Worker%   op_invoke_virtual(range="Range")
219*795d594fSAndroid Build Coastguard Worker
220*795d594fSAndroid Build Coastguard Worker
221*795d594fSAndroid Build Coastguard Worker// invoke-super/range {vCCCC .. vNNNN}, meth@BBBB
222*795d594fSAndroid Build Coastguard Worker// Format 3rc: AA|75 BBBB CCCC
223*795d594fSAndroid Build Coastguard Worker//
224*795d594fSAndroid Build Coastguard Worker// Note: When the method_id references a method of a non-interface class, invoke-super/range is used
225*795d594fSAndroid Build Coastguard Worker// to invoke the closest superclass's virtual method (as opposed to the one with the same method_id
226*795d594fSAndroid Build Coastguard Worker// in the calling class).
227*795d594fSAndroid Build Coastguard Worker// Note: In Dex files version 037 or later, if the method_id refers to an interface method,
228*795d594fSAndroid Build Coastguard Worker// invoke-super/range is used to invoke the most specific, non-overridden version of that method
229*795d594fSAndroid Build Coastguard Worker// defined on that interface. In Dex files prior to version 037, having an interface method_id is
230*795d594fSAndroid Build Coastguard Worker// illegal and undefined.
231*795d594fSAndroid Build Coastguard Worker%def op_invoke_super_range():
232*795d594fSAndroid Build Coastguard Worker%   op_invoke_super(range="Range")
233*795d594fSAndroid Build Coastguard Worker
234*795d594fSAndroid Build Coastguard Worker
235*795d594fSAndroid Build Coastguard Worker// invoke-direct/range {vCCCC .. vNNNN}, meth@BBBB
236*795d594fSAndroid Build Coastguard Worker// Format 3rc: AA|76 BBBB CCCC
237*795d594fSAndroid Build Coastguard Worker//
238*795d594fSAndroid Build Coastguard Worker// Note: invoke-direct/range is used to invoke a non-static direct method (that is, an instance
239*795d594fSAndroid Build Coastguard Worker// method that is by its nature non-overridable, namely either a private instance method or a
240*795d594fSAndroid Build Coastguard Worker// constructor).
241*795d594fSAndroid Build Coastguard Worker%def op_invoke_direct_range():
242*795d594fSAndroid Build Coastguard Worker%   op_invoke_direct(range="Range")
243*795d594fSAndroid Build Coastguard Worker
244*795d594fSAndroid Build Coastguard Worker
245*795d594fSAndroid Build Coastguard Worker// invoke-static/range {vCCCC .. vNNNN}, meth@BBBB
246*795d594fSAndroid Build Coastguard Worker// Format 3rc: AA|77 BBBB CCCC
247*795d594fSAndroid Build Coastguard Worker//
248*795d594fSAndroid Build Coastguard Worker// Note: invoke-static/range is used to invoke a static method (which is always considered a direct
249*795d594fSAndroid Build Coastguard Worker// method).
250*795d594fSAndroid Build Coastguard Worker%def op_invoke_static_range():
251*795d594fSAndroid Build Coastguard Worker%   op_invoke_static(range="Range")
252*795d594fSAndroid Build Coastguard Worker
253*795d594fSAndroid Build Coastguard Worker
254*795d594fSAndroid Build Coastguard Worker// invoke-interface/range {vCCCC .. vNNNN}, meth@BBBB
255*795d594fSAndroid Build Coastguard Worker// Format 3rc: AA|78 BBBB CCCC
256*795d594fSAndroid Build Coastguard Worker//
257*795d594fSAndroid Build Coastguard Worker// Note: invoke-interface/range is used to invoke an interface method, that is, on an object whose
258*795d594fSAndroid Build Coastguard Worker// concrete class isn't known, using a method_id that refers to an interface.
259*795d594fSAndroid Build Coastguard Worker%def op_invoke_interface_range():
260*795d594fSAndroid Build Coastguard Worker%   op_invoke_interface(range="Range")
261*795d594fSAndroid Build Coastguard Worker
262*795d594fSAndroid Build Coastguard Worker
263*795d594fSAndroid Build Coastguard Worker// invoke-polymorphic {vC, vD, vE, vF, vG}, meth@BBBB, proto@HHHH
264*795d594fSAndroid Build Coastguard Worker// Format 45cc: A|G|fa BBBB F|E|D|C HHHH
265*795d594fSAndroid Build Coastguard Worker//
266*795d594fSAndroid Build Coastguard Worker// Note: Invoke the indicated signature polymorphic method. The result (if any) may be stored with
267*795d594fSAndroid Build Coastguard Worker// an appropriate move-result* variant as the immediately subsequent instruction.
268*795d594fSAndroid Build Coastguard Worker//
269*795d594fSAndroid Build Coastguard Worker// The method reference must be to a signature polymorphic method, such as
270*795d594fSAndroid Build Coastguard Worker// java.lang.invoke.MethodHandle.invoke or java.lang.invoke.MethodHandle.invokeExact.
271*795d594fSAndroid Build Coastguard Worker//
272*795d594fSAndroid Build Coastguard Worker// The receiver must be an object supporting the signature polymorphic method being invoked.
273*795d594fSAndroid Build Coastguard Worker//
274*795d594fSAndroid Build Coastguard Worker// The prototype reference describes the argument types provided and the expected return type.
275*795d594fSAndroid Build Coastguard Worker//
276*795d594fSAndroid Build Coastguard Worker// The invoke-polymorphic bytecode may raise exceptions when it executes. The exceptions are
277*795d594fSAndroid Build Coastguard Worker// described in the API documentation for the signature polymorphic method being invoked.
278*795d594fSAndroid Build Coastguard Worker//
279*795d594fSAndroid Build Coastguard Worker// Present in Dex files from version 038 onwards.
280*795d594fSAndroid Build Coastguard Worker%def op_invoke_polymorphic(range=""):
281*795d594fSAndroid Build Coastguard Worker   EXPORT_PC
282*795d594fSAndroid Build Coastguard Worker   FETCH s7, count=2  // s7 := F|E|D|C or CCCC (range)
283*795d594fSAndroid Build Coastguard Worker   // No need to fetch the target method; the runtime handles it.
284*795d594fSAndroid Build Coastguard Worker%  fetch_receiver(reg="s8", vreg="s7", range=range)
285*795d594fSAndroid Build Coastguard Worker   beqz s8, 1f        // throw if null
286*795d594fSAndroid Build Coastguard Worker
287*795d594fSAndroid Build Coastguard Worker   ld a0, (sp)        // a0 := caller ArtMethod*
288*795d594fSAndroid Build Coastguard Worker   mv a1, xPC
289*795d594fSAndroid Build Coastguard Worker   call NterpGetShortyFromInvokePolymorphic  // args a0, a1
290*795d594fSAndroid Build Coastguard Worker   mv a1, s8
291*795d594fSAndroid Build Coastguard Worker   tail NterpInvokePolymorphic${range}  // args a0 (shorty), a1 (this), s7 (vregs)
292*795d594fSAndroid Build Coastguard Worker1:
293*795d594fSAndroid Build Coastguard Worker   tail common_errNullObject
294*795d594fSAndroid Build Coastguard Worker
295*795d594fSAndroid Build Coastguard Worker
296*795d594fSAndroid Build Coastguard Worker// invoke-polymorphic/range {vCCCC .. vNNNN}, meth@BBBB, proto@HHHH
297*795d594fSAndroid Build Coastguard Worker// Format 4rcc: AA|fb BBBB CCCC HHHH
298*795d594fSAndroid Build Coastguard Worker// where NNNN = CCCC + AA - 1, that is A determines the count 0..255, and C determines the first
299*795d594fSAndroid Build Coastguard Worker// register.
300*795d594fSAndroid Build Coastguard Worker//
301*795d594fSAndroid Build Coastguard Worker// Note: Invoke the indicated method handle. See the invoke-polymorphic description above for
302*795d594fSAndroid Build Coastguard Worker// details.
303*795d594fSAndroid Build Coastguard Worker//
304*795d594fSAndroid Build Coastguard Worker// Present in Dex files from version 038 onwards.
305*795d594fSAndroid Build Coastguard Worker%def op_invoke_polymorphic_range():
306*795d594fSAndroid Build Coastguard Worker%   op_invoke_polymorphic(range="Range")
307*795d594fSAndroid Build Coastguard Worker
308*795d594fSAndroid Build Coastguard Worker
309*795d594fSAndroid Build Coastguard Worker// invoke-custom {vC, vD, vE, vF, vG}, call_site@BBBB
310*795d594fSAndroid Build Coastguard Worker// Format 35c: A|G|fc BBBB F|E|D|C
311*795d594fSAndroid Build Coastguard Worker//
312*795d594fSAndroid Build Coastguard Worker// Note: Resolves and invokes the indicated call site. The result from the invocation (if any) may
313*795d594fSAndroid Build Coastguard Worker// be stored with an appropriate move-result* variant as the immediately subsequent instruction.
314*795d594fSAndroid Build Coastguard Worker//
315*795d594fSAndroid Build Coastguard Worker// This instruction executes in two phases: call site resolution and call site invocation.
316*795d594fSAndroid Build Coastguard Worker//
317*795d594fSAndroid Build Coastguard Worker// Call site resolution checks whether the indicated call site has an associated
318*795d594fSAndroid Build Coastguard Worker// java.lang.invoke.CallSite instance. If not, the bootstrap linker method for the indicated call
319*795d594fSAndroid Build Coastguard Worker// site is invoked using arguments present in the DEX file (see call_site_item). The bootstrap
320*795d594fSAndroid Build Coastguard Worker// linker method returns a java.lang.invoke.CallSite instance that will then be associated with the
321*795d594fSAndroid Build Coastguard Worker// indicated call site if no association exists. Another thread may have already made the
322*795d594fSAndroid Build Coastguard Worker// association first, and if so execution of the instruction continues with the first associated
323*795d594fSAndroid Build Coastguard Worker// java.lang.invoke.CallSite instance.
324*795d594fSAndroid Build Coastguard Worker//
325*795d594fSAndroid Build Coastguard Worker// Call site invocation is made on the java.lang.invoke.MethodHandle target of the resolved
326*795d594fSAndroid Build Coastguard Worker// java.lang.invoke.CallSite instance. The target is invoked as if executing invoke-polymorphic
327*795d594fSAndroid Build Coastguard Worker// (described above) using the method handle and arguments to the invoke-custom instruction as the
328*795d594fSAndroid Build Coastguard Worker// arguments to an exact method handle invocation.
329*795d594fSAndroid Build Coastguard Worker//
330*795d594fSAndroid Build Coastguard Worker// Exceptions raised by the bootstrap linker method are wrapped in a java.lang.BootstrapMethodError.
331*795d594fSAndroid Build Coastguard Worker// A BootstrapMethodError is also raised if:
332*795d594fSAndroid Build Coastguard Worker// - the bootstrap linker method fails to return a java.lang.invoke.CallSite instance.
333*795d594fSAndroid Build Coastguard Worker// - the returned java.lang.invoke.CallSite has a null method handle target.
334*795d594fSAndroid Build Coastguard Worker// - the method handle target is not of the requested type.
335*795d594fSAndroid Build Coastguard Worker//
336*795d594fSAndroid Build Coastguard Worker// Present in Dex files from version 038 onwards.
337*795d594fSAndroid Build Coastguard Worker%def op_invoke_custom(range=""):
338*795d594fSAndroid Build Coastguard Worker   EXPORT_PC
339*795d594fSAndroid Build Coastguard Worker   ld a0, (sp)  // a0 := caller ArtMethod*
340*795d594fSAndroid Build Coastguard Worker   mv a1, xPC
341*795d594fSAndroid Build Coastguard Worker   call NterpGetShortyFromInvokeCustom  // args a0, a1
342*795d594fSAndroid Build Coastguard Worker   mv s7, a0    // s7 := shorty
343*795d594fSAndroid Build Coastguard Worker   FETCH a0, 1  // a0 := BBBB
344*795d594fSAndroid Build Coastguard Worker   FETCH s8, 2  // s8 := F|E|D|C or CCCC (range)
345*795d594fSAndroid Build Coastguard Worker   tail NterpInvokeCustom${range}  // args a0 (BBBB), s7 (shorty), s8 (vregs)
346*795d594fSAndroid Build Coastguard Worker
347*795d594fSAndroid Build Coastguard Worker
348*795d594fSAndroid Build Coastguard Worker// invoke-custom/range {vCCCC .. vNNNN}, call_site@BBBB
349*795d594fSAndroid Build Coastguard Worker// Format 3rc: AA|fd BBBB CCCC
350*795d594fSAndroid Build Coastguard Worker// where NNNN = CCCC + AA - 1, that is A determines the count 0..255, and C determines the first
351*795d594fSAndroid Build Coastguard Worker// register.
352*795d594fSAndroid Build Coastguard Worker//
353*795d594fSAndroid Build Coastguard Worker// Note: Resolve and invoke a call site. See the invoke-custom description above for details.
354*795d594fSAndroid Build Coastguard Worker//
355*795d594fSAndroid Build Coastguard Worker// Present in Dex files from version 038 onwards.
356*795d594fSAndroid Build Coastguard Worker%def op_invoke_custom_range():
357*795d594fSAndroid Build Coastguard Worker%  op_invoke_custom(range="Range")
358*795d594fSAndroid Build Coastguard Worker
359*795d594fSAndroid Build Coastguard Worker
360*795d594fSAndroid Build Coastguard Worker// handler helpers
361*795d594fSAndroid Build Coastguard Worker
362*795d594fSAndroid Build Coastguard Worker%def resolve_method_into_a0():
363*795d594fSAndroid Build Coastguard Worker   mv a0, xSELF
364*795d594fSAndroid Build Coastguard Worker   ld a1, (sp)  // We can't always rely on a0 = ArtMethod*.
365*795d594fSAndroid Build Coastguard Worker   mv a2, xPC
366*795d594fSAndroid Build Coastguard Worker   call nterp_get_method
367*795d594fSAndroid Build Coastguard Worker
368*795d594fSAndroid Build Coastguard Worker
369*795d594fSAndroid Build Coastguard Worker%def fetch_receiver(reg="", vreg="", range=""):
370*795d594fSAndroid Build Coastguard Worker%  if range == 'Range':
371*795d594fSAndroid Build Coastguard Worker     GET_VREG_OBJECT $reg, $vreg           // reg := refs[CCCC]
372*795d594fSAndroid Build Coastguard Worker%  else:
373*795d594fSAndroid Build Coastguard Worker     andi $reg, $vreg, 0xF                 // reg := C
374*795d594fSAndroid Build Coastguard Worker     GET_VREG_OBJECT $reg, $reg            // reg := refs[C]
375*795d594fSAndroid Build Coastguard Worker
376*795d594fSAndroid Build Coastguard Worker
377*795d594fSAndroid Build Coastguard Worker//
378*795d594fSAndroid Build Coastguard Worker// These asm blocks are positioned in main.S for visibility to stack walking.
379*795d594fSAndroid Build Coastguard Worker//
380*795d594fSAndroid Build Coastguard Worker
381*795d594fSAndroid Build Coastguard Worker
382*795d594fSAndroid Build Coastguard Worker// NterpInvokeVirtual
383*795d594fSAndroid Build Coastguard Worker// a0: ArtMethod*
384*795d594fSAndroid Build Coastguard Worker// a1: this
385*795d594fSAndroid Build Coastguard Worker// s7: vreg ids F|E|D|C
386*795d594fSAndroid Build Coastguard Worker%def nterp_invoke_virtual():
387*795d594fSAndroid Build Coastguard Worker%  nterp_invoke_direct(uniq="invoke_virtual")
388*795d594fSAndroid Build Coastguard Worker
389*795d594fSAndroid Build Coastguard Worker
390*795d594fSAndroid Build Coastguard Worker// NterpInvokeSuper
391*795d594fSAndroid Build Coastguard Worker// a0: ArtMethod*
392*795d594fSAndroid Build Coastguard Worker// a1: this
393*795d594fSAndroid Build Coastguard Worker// s7: vreg ids F|E|D|C
394*795d594fSAndroid Build Coastguard Worker%def nterp_invoke_super():
395*795d594fSAndroid Build Coastguard Worker%  nterp_invoke_direct(uniq="invoke_super")
396*795d594fSAndroid Build Coastguard Worker
397*795d594fSAndroid Build Coastguard Worker
398*795d594fSAndroid Build Coastguard Worker// NterpInvokeDirect
399*795d594fSAndroid Build Coastguard Worker// a0: ArtMethod*
400*795d594fSAndroid Build Coastguard Worker// a1: this
401*795d594fSAndroid Build Coastguard Worker// s7: (regular) vreg ids F|E|D|C, (range) vreg id CCCC
402*795d594fSAndroid Build Coastguard Worker%def nterp_invoke_direct(uniq="invoke_direct", range=""):
403*795d594fSAndroid Build Coastguard Worker   ld s8, ART_METHOD_QUICK_CODE_OFFSET_64(a0)
404*795d594fSAndroid Build Coastguard Worker                                 // s8 := quick code
405*795d594fSAndroid Build Coastguard Worker%  try_nterp(quick="s8", z0="t0", skip=f".L{uniq}_simple")
406*795d594fSAndroid Build Coastguard Worker   call NterpToNterpInstance${range}  // args a0, a1
407*795d594fSAndroid Build Coastguard Worker   j .L${uniq}_next_op
408*795d594fSAndroid Build Coastguard Worker
409*795d594fSAndroid Build Coastguard Worker.L${uniq}_simple:
410*795d594fSAndroid Build Coastguard Worker%  if range == 'Range':
411*795d594fSAndroid Build Coastguard Worker%    try_simple_args_range(vC="s7", z0="t0", z1="t1", z2="t2", z3="t3", z4="t4", skip=f".L{uniq}_01", uniq=uniq)
412*795d594fSAndroid Build Coastguard Worker%  else:
413*795d594fSAndroid Build Coastguard Worker%    try_simple_args(v_fedc="s7", z0="t0", z1="t1", skip=f".L{uniq}_01", uniq=uniq)
414*795d594fSAndroid Build Coastguard Worker%#:
415*795d594fSAndroid Build Coastguard Worker   jalr s8                       // (regular) args a0 - a5, (range) args a0 - a7 and stack
416*795d594fSAndroid Build Coastguard Worker   j .L${uniq}_next_op
417*795d594fSAndroid Build Coastguard Worker
418*795d594fSAndroid Build Coastguard Worker.L${uniq}_01:
419*795d594fSAndroid Build Coastguard Worker   mv s9, zero                   // initialize shorty reg
420*795d594fSAndroid Build Coastguard Worker%  try_01_args(vreg="s7", shorty="s9", z0="t0", z1="t1", z2="t2", y0="s10", y1="s11", y2="s0", skip=f".L{uniq}_slow", call=f".L{uniq}_01_call", uniq=uniq, range=range)
421*795d594fSAndroid Build Coastguard Worker                                 // if s9 := shorty, then maybe (a2, fa0) := fp[D] or fp[CCCC + 1]
422*795d594fSAndroid Build Coastguard Worker.L${uniq}_01_call:
423*795d594fSAndroid Build Coastguard Worker   jalr s8                       // args a0, a1, and maybe a2, fa0
424*795d594fSAndroid Build Coastguard Worker   beqz s9, .L${uniq}_next_op    // no shorty, no scalar return
425*795d594fSAndroid Build Coastguard Worker%  maybe_float_returned(shorty="s9", z0="t0", z1="t1", uniq=f"{uniq}_0")
426*795d594fSAndroid Build Coastguard Worker                                 // a0 := fa0 if float return
427*795d594fSAndroid Build Coastguard Worker   j .L${uniq}_next_op
428*795d594fSAndroid Build Coastguard Worker
429*795d594fSAndroid Build Coastguard Worker.L${uniq}_slow:
430*795d594fSAndroid Build Coastguard Worker%  get_shorty_save_a0_a1(shorty="s9", y0="s10", y1="s11")
431*795d594fSAndroid Build Coastguard Worker%  if range == 'Range':
432*795d594fSAndroid Build Coastguard Worker%    slow_setup_args_range(shorty="s9", vC="s7", z0="t0", z1="t1", z2="t2", z3="t3", z4="t4", z5="t5", z6="t6", z7="s10", uniq=uniq)
433*795d594fSAndroid Build Coastguard Worker%  else:
434*795d594fSAndroid Build Coastguard Worker%    slow_setup_args(shorty="s9", vregs="s7", z0="t0", z1="t1", z2="t2", z3="t3", z4="t4", z5="t5", z6="t6", uniq=uniq)
435*795d594fSAndroid Build Coastguard Worker%#:
436*795d594fSAndroid Build Coastguard Worker   jalr s8                       // args in a0-a5, fa0-fa4
437*795d594fSAndroid Build Coastguard Worker%  maybe_float_returned(shorty="s9", z0="t0", z1="t1", uniq=f"{uniq}_1")
438*795d594fSAndroid Build Coastguard Worker                                 // a0 := fa0 if float return
439*795d594fSAndroid Build Coastguard Worker.L${uniq}_next_op:
440*795d594fSAndroid Build Coastguard Worker   FETCH_ADVANCE_INST 3
441*795d594fSAndroid Build Coastguard Worker   GET_INST_OPCODE t0
442*795d594fSAndroid Build Coastguard Worker   GOTO_OPCODE t0
443*795d594fSAndroid Build Coastguard Worker
444*795d594fSAndroid Build Coastguard Worker
445*795d594fSAndroid Build Coastguard Worker// NterpInvokeStringInit
446*795d594fSAndroid Build Coastguard Worker// a0: ArtMethod*
447*795d594fSAndroid Build Coastguard Worker// s7: (regular) vreg ids F|E|D|C, (range) vreg id CCCC
448*795d594fSAndroid Build Coastguard Worker%def nterp_invoke_string_init(uniq="invoke_string_init", range=""):
449*795d594fSAndroid Build Coastguard Worker   ld s8, ART_METHOD_QUICK_CODE_OFFSET_64(a0)
450*795d594fSAndroid Build Coastguard Worker                        // s8 := quick code
451*795d594fSAndroid Build Coastguard Worker%  try_nterp(quick="s8", z0="t0", skip=f".L{uniq}_slow")
452*795d594fSAndroid Build Coastguard Worker   call NterpToNterpStringInit${range}  // arg a0
453*795d594fSAndroid Build Coastguard Worker   j .L${uniq}_next_op
454*795d594fSAndroid Build Coastguard Worker
455*795d594fSAndroid Build Coastguard Worker.L${uniq}_slow:
456*795d594fSAndroid Build Coastguard Worker%  get_shorty_save_a0_a1(shorty="s9", y0="s10", y1="s11")
457*795d594fSAndroid Build Coastguard Worker%  if range == 'Range':
458*795d594fSAndroid Build Coastguard Worker%    slow_setup_args_string_init_range(shorty="s9", vC="s7", z0="t0", z1="t1", z2="t2", z3="t3", uniq=uniq)
459*795d594fSAndroid Build Coastguard Worker%  else:
460*795d594fSAndroid Build Coastguard Worker%    slow_setup_args_string_init(shorty="s9", v_fedc="s7", z0="t0", z1="t1", z2="t2", uniq=uniq)
461*795d594fSAndroid Build Coastguard Worker%#:
462*795d594fSAndroid Build Coastguard Worker   jalr s8              // args (regular) a0 - a5, (range) a0 - a5
463*795d594fSAndroid Build Coastguard Worker
464*795d594fSAndroid Build Coastguard Worker.L${uniq}_next_op:
465*795d594fSAndroid Build Coastguard Worker%  fetch_receiver(reg="t0", vreg="s7", range=range)
466*795d594fSAndroid Build Coastguard Worker                        // t0 := fp[C] (this)
467*795d594fSAndroid Build Coastguard Worker%  subst_vreg_references(old="t0", new="a0", z0="t1", z1="t2", z2="t3", uniq=uniq)
468*795d594fSAndroid Build Coastguard Worker   FETCH_ADVANCE_INST 3
469*795d594fSAndroid Build Coastguard Worker   GET_INST_OPCODE t0
470*795d594fSAndroid Build Coastguard Worker   GOTO_OPCODE t0
471*795d594fSAndroid Build Coastguard Worker
472*795d594fSAndroid Build Coastguard Worker
473*795d594fSAndroid Build Coastguard Worker// NterpInvokeStatic
474*795d594fSAndroid Build Coastguard Worker// a0: ArtMethod*
475*795d594fSAndroid Build Coastguard Worker// s7: (regular) vreg ids F|E|D|C, (range) vreg id CCCC
476*795d594fSAndroid Build Coastguard Worker%def nterp_invoke_static(uniq="invoke_static", range=""):
477*795d594fSAndroid Build Coastguard Worker   ld s8, ART_METHOD_QUICK_CODE_OFFSET_64(a0)
478*795d594fSAndroid Build Coastguard Worker                               // s8 := quick code
479*795d594fSAndroid Build Coastguard Worker%  try_nterp(quick="s8", z0="t0", skip=f".L{uniq}_simple")
480*795d594fSAndroid Build Coastguard Worker   call NterpToNterpStatic${range}  // arg a0
481*795d594fSAndroid Build Coastguard Worker   j .L${uniq}_next_op
482*795d594fSAndroid Build Coastguard Worker
483*795d594fSAndroid Build Coastguard Worker.L${uniq}_simple:
484*795d594fSAndroid Build Coastguard Worker%  if range == 'Range':
485*795d594fSAndroid Build Coastguard Worker%    try_simple_args_range(vC="s7", z0="t0", z1="t1", z2="t2", z3="t3", z4="t4", arg_start="0", skip=f".L{uniq}_01", uniq=uniq)
486*795d594fSAndroid Build Coastguard Worker%  else:
487*795d594fSAndroid Build Coastguard Worker%    try_simple_args(v_fedc="s7", z0="t0", z1="t1", arg_start="0", skip=f".L{uniq}_01", uniq=uniq)
488*795d594fSAndroid Build Coastguard Worker%#:
489*795d594fSAndroid Build Coastguard Worker   jalr s8                     // args (regular) a0 - a5, (range) a0 - a7 and maybe stack
490*795d594fSAndroid Build Coastguard Worker   j .L${uniq}_next_op
491*795d594fSAndroid Build Coastguard Worker
492*795d594fSAndroid Build Coastguard Worker.L${uniq}_01:
493*795d594fSAndroid Build Coastguard Worker   mv s9, zero                 // initialize shorty reg
494*795d594fSAndroid Build Coastguard Worker%  try_01_args_static(vreg="s7", shorty="s9", z0="t0", z1="t1", z2="t2", y0="s10", y1="s11", skip=f".L{uniq}_slow", call=f".L{uniq}_01_call", uniq=uniq, range=range)
495*795d594fSAndroid Build Coastguard Worker                               // if s9 := shorty, then maybe (a2, fa0) := fp[C] or fp[CCCC]
496*795d594fSAndroid Build Coastguard Worker.L${uniq}_01_call:
497*795d594fSAndroid Build Coastguard Worker   jalr s8                     // args a0, and maybe a1, fa0
498*795d594fSAndroid Build Coastguard Worker   beqz s9, .L${uniq}_next_op  // no shorty, no scalar return
499*795d594fSAndroid Build Coastguard Worker%  maybe_float_returned(shorty="s9", z0="t0", z1="t1", uniq=f"{uniq}_0")
500*795d594fSAndroid Build Coastguard Worker                               // a0 := fa0 if float return
501*795d594fSAndroid Build Coastguard Worker   j .L${uniq}_next_op
502*795d594fSAndroid Build Coastguard Worker
503*795d594fSAndroid Build Coastguard Worker.L${uniq}_slow:
504*795d594fSAndroid Build Coastguard Worker%  get_shorty_save_a0(shorty="s9", y0="s10")
505*795d594fSAndroid Build Coastguard Worker%  if range == 'Range':
506*795d594fSAndroid Build Coastguard Worker%    slow_setup_args_range(shorty="s9", vC="s7", z0="t0", z1="t1", z2="t2", z3="t3", z4="t4", z5="t5", z6="t6", z7="s10", arg_start="0", uniq=uniq)
507*795d594fSAndroid Build Coastguard Worker%  else:
508*795d594fSAndroid Build Coastguard Worker%    slow_setup_args(shorty="s9", vregs="s7", z0="t0", z1="t1", z2="t2", z3="t3", z4="t4", z5="t5", z6="t6", arg_start="0", uniq=uniq)
509*795d594fSAndroid Build Coastguard Worker%#:
510*795d594fSAndroid Build Coastguard Worker   jalr s8                     // args (regular) a0 - a5 and fa0 - fa4, (range) a0 - a7 and fa0 - fa7 and maybe stack
511*795d594fSAndroid Build Coastguard Worker%  maybe_float_returned(shorty="s9", z0="t0", z1="t1", uniq=f"{uniq}_1")
512*795d594fSAndroid Build Coastguard Worker                               // a0 := fa0 if float return
513*795d594fSAndroid Build Coastguard Worker.L${uniq}_next_op:
514*795d594fSAndroid Build Coastguard Worker   FETCH_ADVANCE_INST 3
515*795d594fSAndroid Build Coastguard Worker   GET_INST_OPCODE t0
516*795d594fSAndroid Build Coastguard Worker   GOTO_OPCODE t0
517*795d594fSAndroid Build Coastguard Worker
518*795d594fSAndroid Build Coastguard Worker
519*795d594fSAndroid Build Coastguard Worker// NterpInvokeInterface
520*795d594fSAndroid Build Coastguard Worker// a0: the target interface method
521*795d594fSAndroid Build Coastguard Worker//     - ignored in nterp-to-nterp transfer
522*795d594fSAndroid Build Coastguard Worker//     - preserved through shorty calls
523*795d594fSAndroid Build Coastguard Worker//     - side-loaded in T0 as a "hidden argument" in managed ABI transfer
524*795d594fSAndroid Build Coastguard Worker// a1: this
525*795d594fSAndroid Build Coastguard Worker// a2: ArtMethod*
526*795d594fSAndroid Build Coastguard Worker// s7: vreg ids F|E|D|C
527*795d594fSAndroid Build Coastguard Worker%def nterp_invoke_interface(uniq="invoke_interface", range=""):
528*795d594fSAndroid Build Coastguard Worker   // We immediately adjust the incoming arguments to suit the rest of the invoke.
529*795d594fSAndroid Build Coastguard Worker   mv t0, a0                   // t0 := hidden arg, preserve until quick call
530*795d594fSAndroid Build Coastguard Worker   mv a0, a2                   // a0 := ArtMethod*
531*795d594fSAndroid Build Coastguard Worker
532*795d594fSAndroid Build Coastguard Worker   ld s8, ART_METHOD_QUICK_CODE_OFFSET_64(a0)
533*795d594fSAndroid Build Coastguard Worker                               // s8 := quick code
534*795d594fSAndroid Build Coastguard Worker%  try_nterp(quick="s8", z0="t1", skip=f".L{uniq}_simple")
535*795d594fSAndroid Build Coastguard Worker   call NterpToNterpInstance${range}  // args a0, a1
536*795d594fSAndroid Build Coastguard Worker   j .L${uniq}_next_op
537*795d594fSAndroid Build Coastguard Worker
538*795d594fSAndroid Build Coastguard Worker.L${uniq}_simple:
539*795d594fSAndroid Build Coastguard Worker%  if range == 'Range':
540*795d594fSAndroid Build Coastguard Worker%    try_simple_args_range(vC="s7", z0="t1", z1="t2", z2="t3", z3="t4", z4="t5", skip=f".L{uniq}_01", uniq=uniq)
541*795d594fSAndroid Build Coastguard Worker%  else:
542*795d594fSAndroid Build Coastguard Worker%    try_simple_args(v_fedc="s7", z0="t1", z1="t2", skip=f".L{uniq}_01", uniq=uniq)
543*795d594fSAndroid Build Coastguard Worker%#:
544*795d594fSAndroid Build Coastguard Worker   jalr s8                     // args (regular) a0 - a5 and t0, (range) a0 - a7 and t0 and maybe stack
545*795d594fSAndroid Build Coastguard Worker   j .L${uniq}_next_op
546*795d594fSAndroid Build Coastguard Worker
547*795d594fSAndroid Build Coastguard Worker.L${uniq}_01:
548*795d594fSAndroid Build Coastguard Worker   mv s9, zero                 // initialize shorty reg
549*795d594fSAndroid Build Coastguard Worker%  try_01_args(vreg="s7", shorty="s9", z0="t1", z1="t2", z2="t3", y0="s10", y1="s11", y2="s0", interface=True, skip=f".L{uniq}_slow", call=f".L{uniq}_01_call", uniq=uniq, range=range)
550*795d594fSAndroid Build Coastguard Worker                               // if s9 := shorty, then maybe (a2, fa0) := fp[D] or fp[CCCC + 1]
551*795d594fSAndroid Build Coastguard Worker                               // (xINST clobbered, if taking this fast path)
552*795d594fSAndroid Build Coastguard Worker.L${uniq}_01_call:
553*795d594fSAndroid Build Coastguard Worker   jalr s8                     // args a0, a1, and t0, and maybe a2, fa0
554*795d594fSAndroid Build Coastguard Worker   beqz s9, .L${uniq}_next_op  // no shorty, no scalar return
555*795d594fSAndroid Build Coastguard Worker%  maybe_float_returned(shorty="s9", z0="t0", z1="t1", uniq=f"{uniq}_0")
556*795d594fSAndroid Build Coastguard Worker                               // a0 := fa0 if float return
557*795d594fSAndroid Build Coastguard Worker   j .L${uniq}_next_op
558*795d594fSAndroid Build Coastguard Worker
559*795d594fSAndroid Build Coastguard Worker.L${uniq}_slow:
560*795d594fSAndroid Build Coastguard Worker%  get_shorty_for_interface_save_a0_a1_t0(shorty="s9", y0="s10", y1="s11", y2="s0")
561*795d594fSAndroid Build Coastguard Worker%  if range == 'Range':
562*795d594fSAndroid Build Coastguard Worker%    slow_setup_args_range(shorty="s9", vC="s7", z0="s10", z1="t1", z2="t2", z3="t3", z4="t4", z5="t5", z6="t6", z7="s11", uniq=uniq)
563*795d594fSAndroid Build Coastguard Worker%  else:
564*795d594fSAndroid Build Coastguard Worker%    slow_setup_args(shorty="s9", vregs="s7", z0="s10", z1="t1", z2="t2", z3="t3", z4="t4", z5="t5", z6="t6", uniq=uniq)
565*795d594fSAndroid Build Coastguard Worker%#:
566*795d594fSAndroid Build Coastguard Worker   jalr s8                     // args (regular) a0 - a5, fa0 - fa4, t0, (range) a0 - a7, fa0 - fa7, t0
567*795d594fSAndroid Build Coastguard Worker%  maybe_float_returned(shorty="s9", z0="t0", z1="t1", uniq=f"{uniq}_1")
568*795d594fSAndroid Build Coastguard Worker                               // a0 := fa0 if float return
569*795d594fSAndroid Build Coastguard Worker.L${uniq}_next_op:
570*795d594fSAndroid Build Coastguard Worker   FETCH_ADVANCE_INST 3
571*795d594fSAndroid Build Coastguard Worker   GET_INST_OPCODE t0
572*795d594fSAndroid Build Coastguard Worker   GOTO_OPCODE t0
573*795d594fSAndroid Build Coastguard Worker
574*795d594fSAndroid Build Coastguard Worker
575*795d594fSAndroid Build Coastguard Worker// NterpInvokePolymorphic
576*795d594fSAndroid Build Coastguard Worker// a0: shorty
577*795d594fSAndroid Build Coastguard Worker// a1: receiver this
578*795d594fSAndroid Build Coastguard Worker// s7: (regular) vreg ids F|E|D|C, (range) vreg id CCCC
579*795d594fSAndroid Build Coastguard Worker%def nterp_invoke_polymorphic(uniq="invoke_polymorphic", range=""):
580*795d594fSAndroid Build Coastguard Worker%  if range == "Range":
581*795d594fSAndroid Build Coastguard Worker%    slow_setup_args_range(shorty="a0", vC="s7", z0="t0", z1="t1", z2="t2", z3="t3", z4="t4", z5="t5", z6="t6", z7="s8", uniq=uniq)
582*795d594fSAndroid Build Coastguard Worker%  else:
583*795d594fSAndroid Build Coastguard Worker%    slow_setup_args(shorty="a0", vregs="s7", z0="t0", z1="t1", z2="t2", z3="t3", z4="t4", z5="t5", z6="t6", uniq=uniq)
584*795d594fSAndroid Build Coastguard Worker%#:
585*795d594fSAndroid Build Coastguard Worker   // Managed ABI argument regs get spilled to stack and consumed by artInvokePolymorphic.
586*795d594fSAndroid Build Coastguard Worker   call art_quick_invoke_polymorphic  // args a1 - a7, fa0 - fa7, and maybe stack
587*795d594fSAndroid Build Coastguard Worker   // Note: If float return, artInvokePolymorphic will place the value in A0, as Nterp expects.
588*795d594fSAndroid Build Coastguard Worker   FETCH_ADVANCE_INST 4
589*795d594fSAndroid Build Coastguard Worker   GET_INST_OPCODE t0
590*795d594fSAndroid Build Coastguard Worker   GOTO_OPCODE t0
591*795d594fSAndroid Build Coastguard Worker
592*795d594fSAndroid Build Coastguard Worker
593*795d594fSAndroid Build Coastguard Worker// NterpInvokeCustom
594*795d594fSAndroid Build Coastguard Worker// a0: BBBB
595*795d594fSAndroid Build Coastguard Worker// s7: shorty
596*795d594fSAndroid Build Coastguard Worker// s8: (regular) vreg ids F|E|D|C, (range) vreg id CCCC
597*795d594fSAndroid Build Coastguard Worker%def nterp_invoke_custom(uniq="invoke_custom", range=""):
598*795d594fSAndroid Build Coastguard Worker%  if range == "Range":
599*795d594fSAndroid Build Coastguard Worker%    slow_setup_args_range(shorty="s7", vC="s8", z0="t0", z1="t1", z2="t2", z3="t3", z4="t4", z5="t5", z6="t6", z7="s9", arg_start="0", uniq=uniq)
600*795d594fSAndroid Build Coastguard Worker%  else:
601*795d594fSAndroid Build Coastguard Worker%    slow_setup_args(shorty="s7", vregs="s8", z0="t0", z1="t1", z2="t2", z3="t3", z4="t4", z5="t5", z6="t6", arg_start="0", uniq=uniq)
602*795d594fSAndroid Build Coastguard Worker%#:
603*795d594fSAndroid Build Coastguard Worker   // Managed ABI argument regs get spilled to stack and consumed by artInvokeCustom.
604*795d594fSAndroid Build Coastguard Worker   call art_quick_invoke_custom  // args a0 - a7, fa0 - fa7, and maybe stack
605*795d594fSAndroid Build Coastguard Worker   // Note: If float return, artInvokeCustom will place the value in A0, as Nterp expects.
606*795d594fSAndroid Build Coastguard Worker   FETCH_ADVANCE_INST 3
607*795d594fSAndroid Build Coastguard Worker   GET_INST_OPCODE t0
608*795d594fSAndroid Build Coastguard Worker   GOTO_OPCODE t0
609*795d594fSAndroid Build Coastguard Worker
610*795d594fSAndroid Build Coastguard Worker
611*795d594fSAndroid Build Coastguard Worker// NterpInvokeVirtualRange
612*795d594fSAndroid Build Coastguard Worker// a0: ArtMethod*
613*795d594fSAndroid Build Coastguard Worker// a1: this
614*795d594fSAndroid Build Coastguard Worker// s7: vreg id CCCC
615*795d594fSAndroid Build Coastguard Worker%def nterp_invoke_virtual_range():
616*795d594fSAndroid Build Coastguard Worker%  nterp_invoke_direct(uniq="invoke_virtual_range", range="Range")
617*795d594fSAndroid Build Coastguard Worker
618*795d594fSAndroid Build Coastguard Worker
619*795d594fSAndroid Build Coastguard Worker// NterpInvokeSuperRange
620*795d594fSAndroid Build Coastguard Worker// a0: ArtMethod*
621*795d594fSAndroid Build Coastguard Worker// a1: this
622*795d594fSAndroid Build Coastguard Worker// s7: vreg id CCCC
623*795d594fSAndroid Build Coastguard Worker%def nterp_invoke_super_range():
624*795d594fSAndroid Build Coastguard Worker%  nterp_invoke_direct(uniq="invoke_super_range", range="Range")
625*795d594fSAndroid Build Coastguard Worker
626*795d594fSAndroid Build Coastguard Worker
627*795d594fSAndroid Build Coastguard Worker// NterpInvokeDirectRange
628*795d594fSAndroid Build Coastguard Worker// Hardcoded:
629*795d594fSAndroid Build Coastguard Worker// a0: ArtMethod*
630*795d594fSAndroid Build Coastguard Worker// a1: this
631*795d594fSAndroid Build Coastguard Worker// s7: vreg id CCCC
632*795d594fSAndroid Build Coastguard Worker%def nterp_invoke_direct_range():
633*795d594fSAndroid Build Coastguard Worker%  nterp_invoke_direct(uniq="invoke_direct_range", range="Range")
634*795d594fSAndroid Build Coastguard Worker
635*795d594fSAndroid Build Coastguard Worker
636*795d594fSAndroid Build Coastguard Worker// NterpInvokeStringInitRange
637*795d594fSAndroid Build Coastguard Worker// a0: ArtMethod*
638*795d594fSAndroid Build Coastguard Worker// s7: vreg id CCCC
639*795d594fSAndroid Build Coastguard Worker%def nterp_invoke_string_init_range():
640*795d594fSAndroid Build Coastguard Worker%  nterp_invoke_string_init(uniq="invoke_string_init_range", range="Range")
641*795d594fSAndroid Build Coastguard Worker
642*795d594fSAndroid Build Coastguard Worker
643*795d594fSAndroid Build Coastguard Worker// NterpInvokeStaticRange
644*795d594fSAndroid Build Coastguard Worker// a0: ArtMethod*
645*795d594fSAndroid Build Coastguard Worker// s7: vreg id CCCC
646*795d594fSAndroid Build Coastguard Worker%def nterp_invoke_static_range():
647*795d594fSAndroid Build Coastguard Worker%  nterp_invoke_static(uniq="invoke_static_range", range="Range")
648*795d594fSAndroid Build Coastguard Worker
649*795d594fSAndroid Build Coastguard Worker
650*795d594fSAndroid Build Coastguard Worker// NterpInvokeInterfaceRange
651*795d594fSAndroid Build Coastguard Worker// a0: the target interface method
652*795d594fSAndroid Build Coastguard Worker//     - ignored in nterp-to-nterp transfer
653*795d594fSAndroid Build Coastguard Worker//     - preserved through shorty calls
654*795d594fSAndroid Build Coastguard Worker//     - side-loaded in T0 as a "hidden argument" in managed ABI transfer
655*795d594fSAndroid Build Coastguard Worker// a1: this
656*795d594fSAndroid Build Coastguard Worker// a2: ArtMethod*
657*795d594fSAndroid Build Coastguard Worker// s7: vreg id CCCC
658*795d594fSAndroid Build Coastguard Worker%def nterp_invoke_interface_range():
659*795d594fSAndroid Build Coastguard Worker%  nterp_invoke_interface(uniq="invoke_interface_range", range="Range")
660*795d594fSAndroid Build Coastguard Worker
661*795d594fSAndroid Build Coastguard Worker
662*795d594fSAndroid Build Coastguard Worker// NterpInvokePolymorphicRange
663*795d594fSAndroid Build Coastguard Worker%def nterp_invoke_polymorphic_range():
664*795d594fSAndroid Build Coastguard Worker%  nterp_invoke_polymorphic(uniq="invoke_polymorphic_range", range="Range")
665*795d594fSAndroid Build Coastguard Worker
666*795d594fSAndroid Build Coastguard Worker
667*795d594fSAndroid Build Coastguard Worker// NterpInvokeCustomRange
668*795d594fSAndroid Build Coastguard Worker%def nterp_invoke_custom_range():
669*795d594fSAndroid Build Coastguard Worker%  nterp_invoke_custom(uniq="invoke_custom_range", range="Range")
670*795d594fSAndroid Build Coastguard Worker
671*795d594fSAndroid Build Coastguard Worker
672*795d594fSAndroid Build Coastguard Worker// fast path and slow path helpers
673*795d594fSAndroid Build Coastguard Worker
674*795d594fSAndroid Build Coastguard Worker
675*795d594fSAndroid Build Coastguard Worker// Input
676*795d594fSAndroid Build Coastguard Worker// - quick: quick code ptr
677*795d594fSAndroid Build Coastguard Worker// Temporaries: z0
678*795d594fSAndroid Build Coastguard Worker%def try_nterp(quick="", z0="", skip=""):
679*795d594fSAndroid Build Coastguard Worker   lla $z0, ExecuteNterpImpl
680*795d594fSAndroid Build Coastguard Worker   bne $z0, $quick, $skip
681*795d594fSAndroid Build Coastguard Worker
682*795d594fSAndroid Build Coastguard Worker
683*795d594fSAndroid Build Coastguard Worker// Hardcoded
684*795d594fSAndroid Build Coastguard Worker// - a0: ArtMethod*
685*795d594fSAndroid Build Coastguard Worker// - xINST
686*795d594fSAndroid Build Coastguard Worker// Input
687*795d594fSAndroid Build Coastguard Worker// - v_fedc: vreg ids F|E|D|C
688*795d594fSAndroid Build Coastguard Worker// Temporaries: z0, z1
689*795d594fSAndroid Build Coastguard Worker%def try_simple_args(v_fedc="", z0="", z1="", arg_start="1", skip="", uniq=""):
690*795d594fSAndroid Build Coastguard Worker   lwu $z0, ART_METHOD_ACCESS_FLAGS_OFFSET(a0)
691*795d594fSAndroid Build Coastguard Worker   // The meaning of nterp-invoke-fast-path-flag for RISC-V diverges from other ISAs.
692*795d594fSAndroid Build Coastguard Worker   BRANCH_IF_BIT_CLEAR $z0, $z0, ART_METHOD_NTERP_INVOKE_FAST_PATH_FLAG_BIT, $skip
693*795d594fSAndroid Build Coastguard Worker
694*795d594fSAndroid Build Coastguard Worker   srliw $z0, xINST, 12              // z0 := A
695*795d594fSAndroid Build Coastguard Worker%  if arg_start == "0":
696*795d594fSAndroid Build Coastguard Worker     beqz $z0, .L${uniq}_simple_done  // A = 0: no further args.
697*795d594fSAndroid Build Coastguard Worker%#:
698*795d594fSAndroid Build Coastguard Worker   li $z1, 2
699*795d594fSAndroid Build Coastguard Worker   blt $z0, $z1, .L${uniq}_simple_1  // A = 1
700*795d594fSAndroid Build Coastguard Worker   beq $z0, $z1, .L${uniq}_simple_2  // A = 2
701*795d594fSAndroid Build Coastguard Worker   li $z1, 4
702*795d594fSAndroid Build Coastguard Worker   blt $z0, $z1, .L${uniq}_simple_3  // A = 3
703*795d594fSAndroid Build Coastguard Worker   beq $z0, $z1, .L${uniq}_simple_4  // A = 4
704*795d594fSAndroid Build Coastguard Worker   // A = 5
705*795d594fSAndroid Build Coastguard Worker   srliw $z1, xINST, 8               // z1 := A|G
706*795d594fSAndroid Build Coastguard Worker   andi $z1, $z1, 0xF                // z1 := G
707*795d594fSAndroid Build Coastguard Worker   GET_VREG_OBJECT a5, $z1
708*795d594fSAndroid Build Coastguard Worker.L${uniq}_simple_4:
709*795d594fSAndroid Build Coastguard Worker   srliw $z1, $v_fedc, 12            // z1 := F
710*795d594fSAndroid Build Coastguard Worker   GET_VREG_OBJECT a4, $z1
711*795d594fSAndroid Build Coastguard Worker.L${uniq}_simple_3:
712*795d594fSAndroid Build Coastguard Worker   srliw $z1, $v_fedc, 8             // z1 := F|E
713*795d594fSAndroid Build Coastguard Worker   andi $z1, $z1, 0xF                // z1 := E
714*795d594fSAndroid Build Coastguard Worker   GET_VREG_OBJECT a3, $z1
715*795d594fSAndroid Build Coastguard Worker.L${uniq}_simple_2:
716*795d594fSAndroid Build Coastguard Worker   srliw $z1, $v_fedc, 4             // z1 := F|E|D
717*795d594fSAndroid Build Coastguard Worker   andi $z1, $z1, 0xF                // z1 := D
718*795d594fSAndroid Build Coastguard Worker   GET_VREG_OBJECT a2, $z1
719*795d594fSAndroid Build Coastguard Worker.L${uniq}_simple_1:
720*795d594fSAndroid Build Coastguard Worker%  if arg_start == "0":
721*795d594fSAndroid Build Coastguard Worker     andi $z1, $v_fedc, 0xF          // z1 := C
722*795d594fSAndroid Build Coastguard Worker     GET_VREG_OBJECT a1, $z1
723*795d594fSAndroid Build Coastguard Worker   // instance: a1 already set to "this"
724*795d594fSAndroid Build Coastguard Worker.L${uniq}_simple_done:
725*795d594fSAndroid Build Coastguard Worker
726*795d594fSAndroid Build Coastguard Worker
727*795d594fSAndroid Build Coastguard Worker// Range variant.
728*795d594fSAndroid Build Coastguard Worker%def try_simple_args_range(vC="", z0="", z1="", z2="", z3="", z4="", skip="", arg_start="1", uniq=""):
729*795d594fSAndroid Build Coastguard Worker   lwu $z0, ART_METHOD_ACCESS_FLAGS_OFFSET(a0)
730*795d594fSAndroid Build Coastguard Worker   // The meaning of nterp-invoke-fast-path-flag for RISC-V diverges from other ISAs.
731*795d594fSAndroid Build Coastguard Worker   BRANCH_IF_BIT_CLEAR $z0, $z0, ART_METHOD_NTERP_INVOKE_FAST_PATH_FLAG_BIT, $skip
732*795d594fSAndroid Build Coastguard Worker
733*795d594fSAndroid Build Coastguard Worker   srliw $z0, xINST, 8                 // z0 := AA
734*795d594fSAndroid Build Coastguard Worker%  if arg_start == "0":  # static:
735*795d594fSAndroid Build Coastguard Worker     beqz $z0, .L${uniq}_simple_done   // AA = 0: no further args.
736*795d594fSAndroid Build Coastguard Worker     sh2add $z1, $vC, xFP              // z1 := &FP[CCCC]
737*795d594fSAndroid Build Coastguard Worker     li $z2, 2
738*795d594fSAndroid Build Coastguard Worker     blt $z0, $z2, .L${uniq}_simple_1  // AA = 1
739*795d594fSAndroid Build Coastguard Worker%  else:  # instance:
740*795d594fSAndroid Build Coastguard Worker     li $z2, 2
741*795d594fSAndroid Build Coastguard Worker     blt $z0, $z2, .L${uniq}_simple_done  // AA = 1, and a1 already loaded.
742*795d594fSAndroid Build Coastguard Worker     sh2add $z1, $vC, xFP               // z1 := &FP[CCCC]
743*795d594fSAndroid Build Coastguard Worker%#:
744*795d594fSAndroid Build Coastguard Worker   // Here: z0, z1, z2 same values for static vs instance.
745*795d594fSAndroid Build Coastguard Worker   beq $z0, $z2, .L${uniq}_simple_2  // AA = 2
746*795d594fSAndroid Build Coastguard Worker   li $z2, 4
747*795d594fSAndroid Build Coastguard Worker   blt $z0, $z2, .L${uniq}_simple_3  // AA = 3
748*795d594fSAndroid Build Coastguard Worker   beq $z0, $z2, .L${uniq}_simple_4  // AA = 4
749*795d594fSAndroid Build Coastguard Worker   li $z2, 6
750*795d594fSAndroid Build Coastguard Worker   blt $z0, $z2, .L${uniq}_simple_5  // AA = 5
751*795d594fSAndroid Build Coastguard Worker   beq $z0, $z2, .L${uniq}_simple_6  // AA = 6
752*795d594fSAndroid Build Coastguard Worker   li $z2, 7
753*795d594fSAndroid Build Coastguard Worker   beq $z0, $z2, .L${uniq}_simple_7  // AA = 7
754*795d594fSAndroid Build Coastguard Worker
755*795d594fSAndroid Build Coastguard Worker   // AA >= 8: store in stack. Load/store from FP[CCCC + 7] upwards.
756*795d594fSAndroid Build Coastguard Worker   slli $z2, $z0, 63                 // z2 := negative if z0 bit #0 is set (odd)
757*795d594fSAndroid Build Coastguard Worker   sh2add $z0, $z0, $z1              // z0 := loop guard at top of stack
758*795d594fSAndroid Build Coastguard Worker   addi $z3, $z1, 7*4                // z3 := &FP[CCCC + 7]
759*795d594fSAndroid Build Coastguard Worker   addi $z4, sp, __SIZEOF_POINTER__ + 7*4
760*795d594fSAndroid Build Coastguard Worker                                     // z4 := &OUT[CCCC + 7]
761*795d594fSAndroid Build Coastguard Worker   bltz $z2, .L${uniq}_simple_loop_wide
762*795d594fSAndroid Build Coastguard Worker                                     // if AA odd, branch to wide-copy
763*795d594fSAndroid Build Coastguard Worker   lwu $z2, ($z3)
764*795d594fSAndroid Build Coastguard Worker   sw $z2, ($z4)
765*795d594fSAndroid Build Coastguard Worker   addi $z3, $z3, 4
766*795d594fSAndroid Build Coastguard Worker   addi $z4, $z4, 4
767*795d594fSAndroid Build Coastguard Worker
768*795d594fSAndroid Build Coastguard Worker.L${uniq}_simple_loop_wide:
769*795d594fSAndroid Build Coastguard Worker   // TODO: Consider ensuring 64-bit stores are aligned.
770*795d594fSAndroid Build Coastguard Worker   beq $z3, $z0, .L${uniq}_simple_7
771*795d594fSAndroid Build Coastguard Worker   ld $z2, ($z3)
772*795d594fSAndroid Build Coastguard Worker   sd $z2, ($z4)
773*795d594fSAndroid Build Coastguard Worker   addi $z3, $z3, 8
774*795d594fSAndroid Build Coastguard Worker   addi $z4, $z4, 8
775*795d594fSAndroid Build Coastguard Worker   j .L${uniq}_simple_loop_wide
776*795d594fSAndroid Build Coastguard Worker
777*795d594fSAndroid Build Coastguard Worker   // Bottom 7 slots of OUT array never written; first args are passed with a1-a7.
778*795d594fSAndroid Build Coastguard Worker.L${uniq}_simple_7:
779*795d594fSAndroid Build Coastguard Worker   lwu a7, 6*4($z1)
780*795d594fSAndroid Build Coastguard Worker.L${uniq}_simple_6:
781*795d594fSAndroid Build Coastguard Worker   lwu a6, 5*4($z1)
782*795d594fSAndroid Build Coastguard Worker.L${uniq}_simple_5:
783*795d594fSAndroid Build Coastguard Worker   lwu a5, 4*4($z1)
784*795d594fSAndroid Build Coastguard Worker.L${uniq}_simple_4:
785*795d594fSAndroid Build Coastguard Worker   lwu a4, 3*4($z1)
786*795d594fSAndroid Build Coastguard Worker.L${uniq}_simple_3:
787*795d594fSAndroid Build Coastguard Worker   lwu a3, 2*4($z1)
788*795d594fSAndroid Build Coastguard Worker.L${uniq}_simple_2:
789*795d594fSAndroid Build Coastguard Worker   lwu a2, 1*4($z1)
790*795d594fSAndroid Build Coastguard Worker.L${uniq}_simple_1:
791*795d594fSAndroid Build Coastguard Worker%  if arg_start == "0":  # static:
792*795d594fSAndroid Build Coastguard Worker     lwu a1, 0*4($z1)
793*795d594fSAndroid Build Coastguard Worker%#:
794*795d594fSAndroid Build Coastguard Worker.L${uniq}_simple_done:
795*795d594fSAndroid Build Coastguard Worker
796*795d594fSAndroid Build Coastguard Worker
797*795d594fSAndroid Build Coastguard Worker// Check if a 0/1 arg invoke form is possible, set up a2 and fa0 if needed.
798*795d594fSAndroid Build Coastguard Worker// If a return value expected, move possible float return to a0.
799*795d594fSAndroid Build Coastguard Worker// Hardcoded: xINST, xPC, xFP, a0, a1, t0, fa0
800*795d594fSAndroid Build Coastguard Worker// NOTE xINST clobbered if interface=True and we're taking the fast path.
801*795d594fSAndroid Build Coastguard Worker// zN are temporaries, yN are callee-save
802*795d594fSAndroid Build Coastguard Worker%def try_01_args(vreg="", shorty="", z0="", z1="", z2="", y0="", y1="", y2="", interface=False, skip="", call="", uniq="", range=""):
803*795d594fSAndroid Build Coastguard Worker%  if range == 'Range':
804*795d594fSAndroid Build Coastguard Worker     srliw $y0, xINST, 8   // y0 := AA
805*795d594fSAndroid Build Coastguard Worker%  else:
806*795d594fSAndroid Build Coastguard Worker     srliw $y0, xINST, 12  // y0 := A
807*795d594fSAndroid Build Coastguard Worker%#:
808*795d594fSAndroid Build Coastguard Worker   addi $y0, $y0, -2       // y0 := A - 2 or (range) AA - 2
809*795d594fSAndroid Build Coastguard Worker   bgtz $y0, $skip         // 2+ args: slow path
810*795d594fSAndroid Build Coastguard Worker   beqz $y0, .L${uniq}_01_shorty  // this and 1 arg: determine arg type with shorty
811*795d594fSAndroid Build Coastguard Worker   // 0 args
812*795d594fSAndroid Build Coastguard Worker%  try_01_args_peek_next(z0=z0)  # z0 is zero if invoke has scalar return
813*795d594fSAndroid Build Coastguard Worker   bnez $z0, $call         // Non-scalar return, 0 args: make the call.
814*795d594fSAndroid Build Coastguard Worker   // Scalar return, 0 args: determine return type with shorty
815*795d594fSAndroid Build Coastguard Worker
816*795d594fSAndroid Build Coastguard Worker.L${uniq}_01_shorty:
817*795d594fSAndroid Build Coastguard Worker   // Get shorty, stash in callee-save to be available on return.
818*795d594fSAndroid Build Coastguard Worker   // When getting shorty, stash this fast path's A0 and A1, then restore.
819*795d594fSAndroid Build Coastguard Worker%  if interface:
820*795d594fSAndroid Build Coastguard Worker     // xINST is a regular callee save. Safe: orig xINST value unused before FETCH_ADVANCE_INST.
821*795d594fSAndroid Build Coastguard Worker%    get_shorty_for_interface_save_a0_a1_t0(shorty=shorty, y0=y1, y1=y2, y2="xINST")
822*795d594fSAndroid Build Coastguard Worker%  else:
823*795d594fSAndroid Build Coastguard Worker%    get_shorty_save_a0_a1(shorty=shorty, y0=y1, y1=y2)
824*795d594fSAndroid Build Coastguard Worker%#:
825*795d594fSAndroid Build Coastguard Worker   // shorty assigned
826*795d594fSAndroid Build Coastguard Worker   bltz $y0, $call         // Scalar return, 0 args: make the call.
827*795d594fSAndroid Build Coastguard Worker   // ins = 2: this and 1 arg. Load arg type.
828*795d594fSAndroid Build Coastguard Worker   lb $z0, 1($shorty)      // z0 := first arg
829*795d594fSAndroid Build Coastguard Worker   li $z1, 'L'             // ref type
830*795d594fSAndroid Build Coastguard Worker%  if range == 'Range':
831*795d594fSAndroid Build Coastguard Worker     sh2add $z2, $vreg, xFP  // z2 := &fp[CCCC]
832*795d594fSAndroid Build Coastguard Worker     lwu a2, 4($z2)        // a2 := fp[CCCC + 1], zext
833*795d594fSAndroid Build Coastguard Worker%  else:
834*795d594fSAndroid Build Coastguard Worker     srliw $z2, $vreg, 4   // z2 := F|E|D
835*795d594fSAndroid Build Coastguard Worker     andi $z2, $z2, 0xF    // z2 := D
836*795d594fSAndroid Build Coastguard Worker     sh2add $z2, $z2, xFP  // z2 := &fp[D]
837*795d594fSAndroid Build Coastguard Worker     lwu a2, ($z2)         // a2 := fp[D], zext
838*795d594fSAndroid Build Coastguard Worker%#:
839*795d594fSAndroid Build Coastguard Worker   beq $z0, $z1, $call     // ref type: LWU into a2
840*795d594fSAndroid Build Coastguard Worker   // non-'L' type
841*795d594fSAndroid Build Coastguard Worker   fmv.w.x fa0, a2         // overload of managed ABI, for one arg
842*795d594fSAndroid Build Coastguard Worker   sext.w a2, a2           // scalar type: LW into a2
843*795d594fSAndroid Build Coastguard Worker   // immediately followed by call
844*795d594fSAndroid Build Coastguard Worker
845*795d594fSAndroid Build Coastguard Worker
846*795d594fSAndroid Build Coastguard Worker// Static variant.
847*795d594fSAndroid Build Coastguard Worker%def try_01_args_static(vreg="", shorty="", z0="", z1="", z2="", y0="", y1="", skip="", call="", uniq="", range=""):
848*795d594fSAndroid Build Coastguard Worker%  if range == 'Range':
849*795d594fSAndroid Build Coastguard Worker     srliw $y0, xINST, 8     // y0 := AA
850*795d594fSAndroid Build Coastguard Worker%  else:
851*795d594fSAndroid Build Coastguard Worker     srliw $y0, xINST, 12    // y0 := A
852*795d594fSAndroid Build Coastguard Worker%#:
853*795d594fSAndroid Build Coastguard Worker   addi $y0, $y0, -1         // y0 := A - 1 or (range) AA - 1
854*795d594fSAndroid Build Coastguard Worker   bgtz $y0, $skip           // 2+ args: slow path
855*795d594fSAndroid Build Coastguard Worker   beqz $y0, .L${uniq}_01_shorty  // 1 arg: determine arg type with shorty
856*795d594fSAndroid Build Coastguard Worker   // 0 args
857*795d594fSAndroid Build Coastguard Worker%  try_01_args_peek_next(z0=z0)  # z0 is zero if invoke has scalar return
858*795d594fSAndroid Build Coastguard Worker   bnez $z0, $call           // Non-scalar return, 0 args: make the call.
859*795d594fSAndroid Build Coastguard Worker   // Scalar return, 0 args: determine return type with shorty.
860*795d594fSAndroid Build Coastguard Worker
861*795d594fSAndroid Build Coastguard Worker.L${uniq}_01_shorty:
862*795d594fSAndroid Build Coastguard Worker   // Get shorty, stash in callee-save to be available on return.
863*795d594fSAndroid Build Coastguard Worker   // When getting shorty, stash this fast path's A0 then restore.
864*795d594fSAndroid Build Coastguard Worker%  get_shorty_save_a0(shorty=shorty, y0=y1)
865*795d594fSAndroid Build Coastguard Worker   // shorty assigned
866*795d594fSAndroid Build Coastguard Worker   bltz $y0, $call           // Scalar return, 0 args: make the call.
867*795d594fSAndroid Build Coastguard Worker   // ins = 1: load arg type
868*795d594fSAndroid Build Coastguard Worker   lb $z0, 1($shorty)        // z0 := first arg
869*795d594fSAndroid Build Coastguard Worker   li $z1, 'L'               // ref type
870*795d594fSAndroid Build Coastguard Worker%  if range == 'Range':
871*795d594fSAndroid Build Coastguard Worker     sh2add $z2, $vreg, xFP  // z2 := &fp[CCCC]
872*795d594fSAndroid Build Coastguard Worker%  else:
873*795d594fSAndroid Build Coastguard Worker     andi $z2, $vreg, 0xF    // z2 := C
874*795d594fSAndroid Build Coastguard Worker     sh2add $z2, $z2, xFP    // z2 := &fp[C]
875*795d594fSAndroid Build Coastguard Worker%#:
876*795d594fSAndroid Build Coastguard Worker   lwu a1, ($z2)             // a1 := fp[C] or (range) fp[CCCC], zext
877*795d594fSAndroid Build Coastguard Worker   beq $z0, $z1, $call       // ref type: LWU into a1
878*795d594fSAndroid Build Coastguard Worker   // non-'L' type
879*795d594fSAndroid Build Coastguard Worker   fmv.w.x fa0, a1           // overload of managed ABI, for one arg
880*795d594fSAndroid Build Coastguard Worker   sext.w a1, a1             // scalar type: LW into a1
881*795d594fSAndroid Build Coastguard Worker   // immediately followed by call
882*795d594fSAndroid Build Coastguard Worker
883*795d594fSAndroid Build Coastguard Worker
884*795d594fSAndroid Build Coastguard Worker%def try_01_args_peek_next(z0=""):
885*795d594fSAndroid Build Coastguard Worker   FETCH $z0, count=3, width=8, byte=0
886*795d594fSAndroid Build Coastguard Worker                                // z0 := next op
887*795d594fSAndroid Build Coastguard Worker   andi $z0, $z0, ~1            // clear bit #0
888*795d594fSAndroid Build Coastguard Worker   addi $z0, $z0, -0x0A         // z0 := zero if op is 0x0A or 0x0B
889*795d594fSAndroid Build Coastguard Worker
890*795d594fSAndroid Build Coastguard Worker
891*795d594fSAndroid Build Coastguard Worker// The invoked method might return in FA0, via managed ABI.
892*795d594fSAndroid Build Coastguard Worker// The next opcode, MOVE-RESULT{-WIDE}, expects the value in A0.
893*795d594fSAndroid Build Coastguard Worker%def maybe_float_returned(shorty="", z0="", z1="", uniq=""):
894*795d594fSAndroid Build Coastguard Worker   lb $z0, ($shorty)  // z0 := first byte of shorty; type of return
895*795d594fSAndroid Build Coastguard Worker   li $z1, 'F'        //
896*795d594fSAndroid Build Coastguard Worker   beq $z0, $z1, .L${uniq}_float_return_move
897*795d594fSAndroid Build Coastguard Worker   li $z1, 'D'        //
898*795d594fSAndroid Build Coastguard Worker   bne $z0, $z1, .L${uniq}_float_return_done
899*795d594fSAndroid Build Coastguard Worker.L${uniq}_float_return_move:
900*795d594fSAndroid Build Coastguard Worker   // If fa0 carries a 32-bit float, the hi bits of fa0 will contain all 1's (NaN boxing).
901*795d594fSAndroid Build Coastguard Worker   // The use of fmv.x.d will transfer those hi bits into a0, and that's okay, because the next
902*795d594fSAndroid Build Coastguard Worker   // opcode, move-result, will only read the lo 32-bits of a0 - the box bits are correctly ignored.
903*795d594fSAndroid Build Coastguard Worker   // If fa0 carries a 64-bit float, then fmv.x.d works as expected.
904*795d594fSAndroid Build Coastguard Worker   fmv.x.d a0, fa0
905*795d594fSAndroid Build Coastguard Worker.L${uniq}_float_return_done:
906*795d594fSAndroid Build Coastguard Worker
907*795d594fSAndroid Build Coastguard Worker
908*795d594fSAndroid Build Coastguard Worker// Hardcoded:
909*795d594fSAndroid Build Coastguard Worker// - a0: ArtMethod*
910*795d594fSAndroid Build Coastguard Worker// - a1: this
911*795d594fSAndroid Build Coastguard Worker// Callee-saves: y0, y1
912*795d594fSAndroid Build Coastguard Worker%def get_shorty_save_a0_a1(shorty="", y0="", y1=""):
913*795d594fSAndroid Build Coastguard Worker   mv $y1, a1
914*795d594fSAndroid Build Coastguard Worker   mv $y0, a0
915*795d594fSAndroid Build Coastguard Worker   call NterpGetShorty  // arg a0
916*795d594fSAndroid Build Coastguard Worker   mv $shorty, a0
917*795d594fSAndroid Build Coastguard Worker   mv a0, $y0
918*795d594fSAndroid Build Coastguard Worker   mv a1, $y1
919*795d594fSAndroid Build Coastguard Worker
920*795d594fSAndroid Build Coastguard Worker
921*795d594fSAndroid Build Coastguard Worker// Static variant.
922*795d594fSAndroid Build Coastguard Worker// Hardcoded:
923*795d594fSAndroid Build Coastguard Worker// - a0: ArtMethod*
924*795d594fSAndroid Build Coastguard Worker// Callee-saves: y0
925*795d594fSAndroid Build Coastguard Worker%def get_shorty_save_a0(shorty="", y0=""):
926*795d594fSAndroid Build Coastguard Worker   mv $y0, a0
927*795d594fSAndroid Build Coastguard Worker   call NterpGetShorty  // arg a0
928*795d594fSAndroid Build Coastguard Worker   mv $shorty, a0
929*795d594fSAndroid Build Coastguard Worker   mv a0, $y0
930*795d594fSAndroid Build Coastguard Worker
931*795d594fSAndroid Build Coastguard Worker
932*795d594fSAndroid Build Coastguard Worker// Interface variant.
933*795d594fSAndroid Build Coastguard Worker// Hardcoded:
934*795d594fSAndroid Build Coastguard Worker// - a0: ArtMethod*
935*795d594fSAndroid Build Coastguard Worker// - a1: this
936*795d594fSAndroid Build Coastguard Worker// - t0: "hidden argument"
937*795d594fSAndroid Build Coastguard Worker// Callee-saves: y0, y1, y2
938*795d594fSAndroid Build Coastguard Worker%def get_shorty_for_interface_save_a0_a1_t0(shorty="", y0="", y1="", y2=""):
939*795d594fSAndroid Build Coastguard Worker   mv $y2, t0
940*795d594fSAndroid Build Coastguard Worker   mv $y1, a1
941*795d594fSAndroid Build Coastguard Worker   mv $y0, a0
942*795d594fSAndroid Build Coastguard Worker   ld a0, (sp)            // a0 := caller ArtMethod*
943*795d594fSAndroid Build Coastguard Worker   FETCH reg=a1, count=1  // a1 := BBBB method idx
944*795d594fSAndroid Build Coastguard Worker   call NterpGetShortyFromMethodId
945*795d594fSAndroid Build Coastguard Worker   mv $shorty, a0
946*795d594fSAndroid Build Coastguard Worker   mv a0, $y0
947*795d594fSAndroid Build Coastguard Worker   mv a1, $y1
948*795d594fSAndroid Build Coastguard Worker   mv t0, $y2
949*795d594fSAndroid Build Coastguard Worker
950*795d594fSAndroid Build Coastguard Worker
951*795d594fSAndroid Build Coastguard Worker// Hardcoded: xFP, xREFS
952*795d594fSAndroid Build Coastguard Worker// Starting with vreg index 0, replace any old reference with new reference.
953*795d594fSAndroid Build Coastguard Worker%def subst_vreg_references(old="", new="", z0="", z1="", z2="", uniq=""):
954*795d594fSAndroid Build Coastguard Worker   mv $z0, xFP               // z0 := &fp[0]
955*795d594fSAndroid Build Coastguard Worker   mv $z1, xREFS             // z1 := &refs[0]
956*795d594fSAndroid Build Coastguard Worker.L${uniq}_subst_try:
957*795d594fSAndroid Build Coastguard Worker   lwu $z2, ($z1)
958*795d594fSAndroid Build Coastguard Worker   bne $z2, $old, .L${uniq}_subst_next
959*795d594fSAndroid Build Coastguard Worker   sw $new, ($z0)
960*795d594fSAndroid Build Coastguard Worker   sw $new, ($z1)
961*795d594fSAndroid Build Coastguard Worker.L${uniq}_subst_next:
962*795d594fSAndroid Build Coastguard Worker   addi $z0, $z0, 4
963*795d594fSAndroid Build Coastguard Worker   addi $z1, $z1, 4
964*795d594fSAndroid Build Coastguard Worker   bne $z1, xFP, .L${uniq}_subst_try
965*795d594fSAndroid Build Coastguard Worker
966*795d594fSAndroid Build Coastguard Worker
967*795d594fSAndroid Build Coastguard Worker// Hardcoded
968*795d594fSAndroid Build Coastguard Worker// - a0: ArtMethod*
969*795d594fSAndroid Build Coastguard Worker// - a1: this
970*795d594fSAndroid Build Coastguard Worker// Input
971*795d594fSAndroid Build Coastguard Worker// - vregs: F|E|D|C from dex
972*795d594fSAndroid Build Coastguard Worker%def slow_setup_args(shorty="", vregs="", z0="", z1="", z2="", z3="", z4="", z5="", z6="", arg_start="1", uniq=""):
973*795d594fSAndroid Build Coastguard Worker   srliw $z0, xINST, 12     // z0 := A
974*795d594fSAndroid Build Coastguard Worker   li $z1, 5
975*795d594fSAndroid Build Coastguard Worker   blt $z0, $z1, .L${uniq}_slow_gpr
976*795d594fSAndroid Build Coastguard Worker   // A = 5: need vreg G
977*795d594fSAndroid Build Coastguard Worker   srliw $z1, xINST, 8      // z1 := A|G
978*795d594fSAndroid Build Coastguard Worker   andi $z1, $z1, 0xF       // z1 := G
979*795d594fSAndroid Build Coastguard Worker   slliw $z1, $z1, 16       // z1 := G0000
980*795d594fSAndroid Build Coastguard Worker   add $vregs, $z1, $vregs  // vregs := G|F|E|D|C
981*795d594fSAndroid Build Coastguard Worker
982*795d594fSAndroid Build Coastguard Worker.L${uniq}_slow_gpr:
983*795d594fSAndroid Build Coastguard Worker   addi $z0, $shorty, 1     // z0 := first arg of shorty
984*795d594fSAndroid Build Coastguard Worker   srliw $z1, $vregs, 4*$arg_start
985*795d594fSAndroid Build Coastguard Worker                            // z1 := (instance) F|E|D or G|F|E|D, (static) F|E|D|C or G|F|E|D|C
986*795d594fSAndroid Build Coastguard Worker   li $z2, 'D'              // double
987*795d594fSAndroid Build Coastguard Worker   li $z3, 'F'              // float
988*795d594fSAndroid Build Coastguard Worker   li $z4, 'J'              // long
989*795d594fSAndroid Build Coastguard Worker   li $z5, 'L'              // ref
990*795d594fSAndroid Build Coastguard Worker   // linear scan through shorty: extract non-float vregs
991*795d594fSAndroid Build Coastguard Worker%  if arg_start == "0":  # static can place vC into a1; instance already loaded "this" into a1.
992*795d594fSAndroid Build Coastguard Worker%    load_vreg_in_gpr(gpr="a1", shorty=z0, vregs=z1, D=z2, F=z3, J=z4, L=z5, z0=z6, done=f".L{uniq}_slow_fpr", uniq=f"{uniq}_0")
993*795d594fSAndroid Build Coastguard Worker%  load_vreg_in_gpr(gpr="a2", shorty=z0, vregs=z1, D=z2, F=z3, J=z4, L=z5, z0=z6, done=f".L{uniq}_slow_fpr", uniq=f"{uniq}_1")
994*795d594fSAndroid Build Coastguard Worker%  load_vreg_in_gpr(gpr="a3", shorty=z0, vregs=z1, D=z2, F=z3, J=z4, L=z5, z0=z6, done=f".L{uniq}_slow_fpr", uniq=f"{uniq}_2")
995*795d594fSAndroid Build Coastguard Worker%  load_vreg_in_gpr(gpr="a4", shorty=z0, vregs=z1, D=z2, F=z3, J=z4, L=z5, z0=z6, done=f".L{uniq}_slow_fpr", uniq=f"{uniq}_3")
996*795d594fSAndroid Build Coastguard Worker%  load_vreg_in_gpr(gpr="a5", shorty=z0, vregs=z1, D=z2, F=z3, J=z4, L=z5, z0=z6, done=f".L{uniq}_slow_fpr", uniq=f"{uniq}_4")
997*795d594fSAndroid Build Coastguard Worker
998*795d594fSAndroid Build Coastguard Worker.L${uniq}_slow_fpr:
999*795d594fSAndroid Build Coastguard Worker   addi $z0, $shorty, 1     // z0 := first arg of shorty
1000*795d594fSAndroid Build Coastguard Worker   srliw $z1, $vregs, 4*$arg_start
1001*795d594fSAndroid Build Coastguard Worker                            // z1 := (instance) F|E|D or G|F|E|D, (static) F|E|D|C or G|F|E|D|C
1002*795d594fSAndroid Build Coastguard Worker   // linear scan through shorty: extract float/double vregs
1003*795d594fSAndroid Build Coastguard Worker%  load_vreg_in_fpr(fpr="fa0", shorty=z0, vregs=z1, D=z2, F=z3, J=z4, z0=z5, done=f".L{uniq}_slow_done", uniq=f"{uniq}_0")
1004*795d594fSAndroid Build Coastguard Worker%  load_vreg_in_fpr(fpr="fa1", shorty=z0, vregs=z1, D=z2, F=z3, J=z4, z0=z5, done=f".L{uniq}_slow_done", uniq=f"{uniq}_1")
1005*795d594fSAndroid Build Coastguard Worker%  load_vreg_in_fpr(fpr="fa2", shorty=z0, vregs=z1, D=z2, F=z3, J=z4, z0=z5, done=f".L{uniq}_slow_done", uniq=f"{uniq}_2")
1006*795d594fSAndroid Build Coastguard Worker%  load_vreg_in_fpr(fpr="fa3", shorty=z0, vregs=z1, D=z2, F=z3, J=z4, z0=z5, done=f".L{uniq}_slow_done", uniq=f"{uniq}_3")
1007*795d594fSAndroid Build Coastguard Worker%  if arg_start == "0":  # static can place G into fa4; instance has only 4 args.
1008*795d594fSAndroid Build Coastguard Worker%    load_vreg_in_fpr(fpr="fa4", shorty=z0, vregs=z1, D=z2, F=z3, J=z4, z0=z5, done=f".L{uniq}_slow_done", uniq=f"{uniq}_4")
1009*795d594fSAndroid Build Coastguard Worker%#:
1010*795d594fSAndroid Build Coastguard Worker.L${uniq}_slow_done:
1011*795d594fSAndroid Build Coastguard Worker
1012*795d594fSAndroid Build Coastguard Worker
1013*795d594fSAndroid Build Coastguard Worker// String-init variant: up to 4 args, no long/double/float args.
1014*795d594fSAndroid Build Coastguard Worker// Ref args ('L') loaded with LW *must* apply ZEXT.W to avoid subtle address bugs.
1015*795d594fSAndroid Build Coastguard Worker%def slow_setup_args_string_init(shorty="", v_fedc="", z0="", z1="", z2="", uniq=""):
1016*795d594fSAndroid Build Coastguard Worker   srliw $z0, xINST, 12            // z0 := A; possible values 1-5
1017*795d594fSAndroid Build Coastguard Worker   li $z1, 2
1018*795d594fSAndroid Build Coastguard Worker   blt $z0, $z1, .L${uniq}_slow_1  // A = 1
1019*795d594fSAndroid Build Coastguard Worker   li $z2, 'L'                     // z2 := ref type
1020*795d594fSAndroid Build Coastguard Worker   beq $z0, $z1, .L${uniq}_slow_2  // A = 2
1021*795d594fSAndroid Build Coastguard Worker   li $z1, 4
1022*795d594fSAndroid Build Coastguard Worker   blt $z0, $z1, .L${uniq}_slow_3  // A = 3
1023*795d594fSAndroid Build Coastguard Worker   beq $z0, $z1, .L${uniq}_slow_4  // A = 4
1024*795d594fSAndroid Build Coastguard Worker
1025*795d594fSAndroid Build Coastguard Worker   // A = 5
1026*795d594fSAndroid Build Coastguard Worker   srliw $z0, xINST, 8             // z0 := A|G
1027*795d594fSAndroid Build Coastguard Worker   andi $z0, $z0, 0xF              // z0 := G
1028*795d594fSAndroid Build Coastguard Worker%  get_vreg("a4", z0)
1029*795d594fSAndroid Build Coastguard Worker   lb $z1, 4($shorty)              // shorty RDEFG
1030*795d594fSAndroid Build Coastguard Worker   bne $z1, $z2, .L${uniq}_slow_4
1031*795d594fSAndroid Build Coastguard Worker   zext.w a4, a4
1032*795d594fSAndroid Build Coastguard Worker.L${uniq}_slow_4:
1033*795d594fSAndroid Build Coastguard Worker   srliw $z1, $v_fedc, 12          // z1 := F
1034*795d594fSAndroid Build Coastguard Worker%  get_vreg("a3", z1)
1035*795d594fSAndroid Build Coastguard Worker   lb $z1, 3($shorty)              // shorty RDEF
1036*795d594fSAndroid Build Coastguard Worker   bne $z1, $z2, .L${uniq}_slow_3
1037*795d594fSAndroid Build Coastguard Worker   zext.w a3, a3
1038*795d594fSAndroid Build Coastguard Worker.L${uniq}_slow_3:
1039*795d594fSAndroid Build Coastguard Worker   srliw $z1, $v_fedc, 8           // z1 := F|E
1040*795d594fSAndroid Build Coastguard Worker   andi $z1, $z1, 0xF              // z1 := E
1041*795d594fSAndroid Build Coastguard Worker%  get_vreg("a2", z1)
1042*795d594fSAndroid Build Coastguard Worker   lb $z1, 2($shorty)              // shorty RDE
1043*795d594fSAndroid Build Coastguard Worker   bne $z1, $z2, .L${uniq}_slow_2
1044*795d594fSAndroid Build Coastguard Worker   zext.w a2, a2
1045*795d594fSAndroid Build Coastguard Worker.L${uniq}_slow_2:
1046*795d594fSAndroid Build Coastguard Worker   srliw $z1, $v_fedc, 4           // z1 := F|E|D
1047*795d594fSAndroid Build Coastguard Worker   andi $z1, $z1, 0xF              // z1 := D
1048*795d594fSAndroid Build Coastguard Worker%  get_vreg("a1", z1)
1049*795d594fSAndroid Build Coastguard Worker   lb $z1, 1($shorty)              // shorty RD
1050*795d594fSAndroid Build Coastguard Worker   bne $z1, $z2, .L${uniq}_slow_1
1051*795d594fSAndroid Build Coastguard Worker   zext.w a1, a1
1052*795d594fSAndroid Build Coastguard Worker.L${uniq}_slow_1:
1053*795d594fSAndroid Build Coastguard Worker   // "this" never read in string-init
1054*795d594fSAndroid Build Coastguard Worker
1055*795d594fSAndroid Build Coastguard Worker
1056*795d594fSAndroid Build Coastguard Worker// Range and static-range variant.
1057*795d594fSAndroid Build Coastguard Worker// Hardcoded
1058*795d594fSAndroid Build Coastguard Worker// - (caller) xPC, xINST, xFP
1059*795d594fSAndroid Build Coastguard Worker// - (callee) sp
1060*795d594fSAndroid Build Coastguard Worker// Input
1061*795d594fSAndroid Build Coastguard Worker// - vC: CCCC from dex
1062*795d594fSAndroid Build Coastguard Worker%def slow_setup_args_range(shorty="", vC="", z0="", z1="", z2="", z3="", z4="", z5="", z6="", z7="", arg_start="1", uniq=""):
1063*795d594fSAndroid Build Coastguard Worker   addi $z0, $shorty, 1       // z0 := first arg of shorty
1064*795d594fSAndroid Build Coastguard Worker   addi $z1, $vC, $arg_start  // z1 := (instance) CCCC+1, (static) CCCC
1065*795d594fSAndroid Build Coastguard Worker   mv $z2, zero               // z2 := is_out_stack_needed false
1066*795d594fSAndroid Build Coastguard Worker   li $z3, 'D'                // double
1067*795d594fSAndroid Build Coastguard Worker   li $z4, 'F'                // float
1068*795d594fSAndroid Build Coastguard Worker   li $z5, 'J'                // long
1069*795d594fSAndroid Build Coastguard Worker   li $z6, 'L'                // ref
1070*795d594fSAndroid Build Coastguard Worker
1071*795d594fSAndroid Build Coastguard Worker   // linear scan through shorty: extract non-float vregs
1072*795d594fSAndroid Build Coastguard Worker%  if arg_start == "0":  # static can place vCCCC into a1; instance already loaded "this" into a1.
1073*795d594fSAndroid Build Coastguard Worker%    load_vreg_in_gpr_range(gpr="a1", shorty=z0, idx=z1, D=z3, F=z4, J=z5, L=z6, z0=z7, done=f".L{uniq}_slow_fpr", uniq=f"{uniq}_1")
1074*795d594fSAndroid Build Coastguard Worker%  load_vreg_in_gpr_range(gpr="a2", shorty=z0, idx=z1, D=z3, F=z4, J=z5, L=z6, z0=z7, done=f".L{uniq}_slow_fpr", uniq=f"{uniq}_2")
1075*795d594fSAndroid Build Coastguard Worker%  load_vreg_in_gpr_range(gpr="a3", shorty=z0, idx=z1, D=z3, F=z4, J=z5, L=z6, z0=z7, done=f".L{uniq}_slow_fpr", uniq=f"{uniq}_3")
1076*795d594fSAndroid Build Coastguard Worker%  load_vreg_in_gpr_range(gpr="a4", shorty=z0, idx=z1, D=z3, F=z4, J=z5, L=z6, z0=z7, done=f".L{uniq}_slow_fpr", uniq=f"{uniq}_4")
1077*795d594fSAndroid Build Coastguard Worker%  load_vreg_in_gpr_range(gpr="a5", shorty=z0, idx=z1, D=z3, F=z4, J=z5, L=z6, z0=z7, done=f".L{uniq}_slow_fpr", uniq=f"{uniq}_5")
1078*795d594fSAndroid Build Coastguard Worker%  load_vreg_in_gpr_range(gpr="a6", shorty=z0, idx=z1, D=z3, F=z4, J=z5, L=z6, z0=z7, done=f".L{uniq}_slow_fpr", uniq=f"{uniq}_6")
1079*795d594fSAndroid Build Coastguard Worker%  load_vreg_in_gpr_range(gpr="a7", shorty=z0, idx=z1, D=z3, F=z4, J=z5, L=z6, z0=z7, done=f".L{uniq}_slow_fpr", uniq=f"{uniq}_7")
1080*795d594fSAndroid Build Coastguard Worker%  is_out_stack_needed(needed=z2, shorty=z0, D=z3, F=z4, z0=z1, uniq=uniq)
1081*795d594fSAndroid Build Coastguard Worker
1082*795d594fSAndroid Build Coastguard Worker.L${uniq}_slow_fpr:
1083*795d594fSAndroid Build Coastguard Worker   addi $z0, $shorty, 1       // z0 := first arg of shorty
1084*795d594fSAndroid Build Coastguard Worker   addi $z1, $vC, $arg_start  // z1 := (instance) CCCC+1, (static) CCCC
1085*795d594fSAndroid Build Coastguard Worker   // linear scan through shorty: extract float/double vregs
1086*795d594fSAndroid Build Coastguard Worker%  load_vreg_in_fpr_range(fpr="fa0", shorty=z0, idx=z1, D=z3, F=z4, J=z5, z0=z6, done=f".L{uniq}_slow_stack", uniq=f"{uniq}_0")
1087*795d594fSAndroid Build Coastguard Worker%  load_vreg_in_fpr_range(fpr="fa1", shorty=z0, idx=z1, D=z3, F=z4, J=z5, z0=z6, done=f".L{uniq}_slow_stack", uniq=f"{uniq}_1")
1088*795d594fSAndroid Build Coastguard Worker%  load_vreg_in_fpr_range(fpr="fa2", shorty=z0, idx=z1, D=z3, F=z4, J=z5, z0=z6, done=f".L{uniq}_slow_stack", uniq=f"{uniq}_2")
1089*795d594fSAndroid Build Coastguard Worker%  load_vreg_in_fpr_range(fpr="fa3", shorty=z0, idx=z1, D=z3, F=z4, J=z5, z0=z6, done=f".L{uniq}_slow_stack", uniq=f"{uniq}_3")
1090*795d594fSAndroid Build Coastguard Worker%  load_vreg_in_fpr_range(fpr="fa4", shorty=z0, idx=z1, D=z3, F=z4, J=z5, z0=z6, done=f".L{uniq}_slow_stack", uniq=f"{uniq}_4")
1091*795d594fSAndroid Build Coastguard Worker%  load_vreg_in_fpr_range(fpr="fa5", shorty=z0, idx=z1, D=z3, F=z4, J=z5, z0=z6, done=f".L{uniq}_slow_stack", uniq=f"{uniq}_5")
1092*795d594fSAndroid Build Coastguard Worker%  load_vreg_in_fpr_range(fpr="fa6", shorty=z0, idx=z1, D=z3, F=z4, J=z5, z0=z6, done=f".L{uniq}_slow_stack", uniq=f"{uniq}_6")
1093*795d594fSAndroid Build Coastguard Worker%  load_vreg_in_fpr_range(fpr="fa7", shorty=z0, idx=z1, D=z3, F=z4, J=z5, z0=z6, done=f".L{uniq}_slow_stack", uniq=f"{uniq}_7")
1094*795d594fSAndroid Build Coastguard Worker%  is_out_stack_needed_float(needed=z2, shorty=z0, D=z3, F=z4, z0=z1, uniq=uniq)
1095*795d594fSAndroid Build Coastguard Worker
1096*795d594fSAndroid Build Coastguard Worker.L${uniq}_slow_stack:
1097*795d594fSAndroid Build Coastguard Worker   beqz $z2, .L${uniq}_slow_done  // No stack needed, skip it. Otherwise copy-paste it all with LD/SD.
1098*795d594fSAndroid Build Coastguard Worker   addi $z0, sp, 8            // z0 := base addr of out array
1099*795d594fSAndroid Build Coastguard Worker   sh2add $z1, $vC, xFP       // z1 := base addr of FP[CCCC]
1100*795d594fSAndroid Build Coastguard Worker   srliw $z2, xINST, 8        // z2 := AA, vreg count
1101*795d594fSAndroid Build Coastguard Worker   sh2add $z2, $z2, $z1       // z2 := loop guard, addr of one slot past top of xFP array
1102*795d594fSAndroid Build Coastguard Worker%  copy_vregs_to_out(out=z0, fp=z1, fp_top=z2, z0=z3, uniq=uniq)
1103*795d594fSAndroid Build Coastguard Worker.L${uniq}_slow_done:
1104*795d594fSAndroid Build Coastguard Worker
1105*795d594fSAndroid Build Coastguard Worker
1106*795d594fSAndroid Build Coastguard Worker// String-init variant: up to 4 args, no long/float/double args.
1107*795d594fSAndroid Build Coastguard Worker// Ref args ('L') loaded with LW *must* apply ZEXT.W to avoid subtle address bugs.
1108*795d594fSAndroid Build Coastguard Worker%def slow_setup_args_string_init_range(shorty="", vC="", z0="", z1="", z2="", z3="", uniq=""):
1109*795d594fSAndroid Build Coastguard Worker   srliw $z0, xINST, 8             // z0 := AA; possible values 1-5
1110*795d594fSAndroid Build Coastguard Worker   li $z1, 2
1111*795d594fSAndroid Build Coastguard Worker   blt $z0, $z1, .L${uniq}_slow_1  // A = 1
1112*795d594fSAndroid Build Coastguard Worker   sh2add $z2, $vC, xFP            // z2 := &fp[CCCC]
1113*795d594fSAndroid Build Coastguard Worker   li $z3, 'L'                     // z3 := ref type
1114*795d594fSAndroid Build Coastguard Worker   beq $z0, $z1, .L${uniq}_slow_2  // A = 2
1115*795d594fSAndroid Build Coastguard Worker   li $z1, 4
1116*795d594fSAndroid Build Coastguard Worker   blt $z0, $z1, .L${uniq}_slow_3  // A = 3
1117*795d594fSAndroid Build Coastguard Worker   beq $z0, $z1, .L${uniq}_slow_4  // A = 4
1118*795d594fSAndroid Build Coastguard Worker   // A = 5
1119*795d594fSAndroid Build Coastguard Worker   lw a4, 4*4($z2)
1120*795d594fSAndroid Build Coastguard Worker   lb $z1, 4($shorty)
1121*795d594fSAndroid Build Coastguard Worker   bne $z1, $z3, .L${uniq}_slow_4
1122*795d594fSAndroid Build Coastguard Worker   zext.w a4, a4
1123*795d594fSAndroid Build Coastguard Worker.L${uniq}_slow_4:
1124*795d594fSAndroid Build Coastguard Worker   lw a3, 3*4($z2)
1125*795d594fSAndroid Build Coastguard Worker   lb $z1, 3($shorty)
1126*795d594fSAndroid Build Coastguard Worker   bne $z1, $z3, .L${uniq}_slow_3
1127*795d594fSAndroid Build Coastguard Worker   zext.w a3, a3
1128*795d594fSAndroid Build Coastguard Worker.L${uniq}_slow_3:
1129*795d594fSAndroid Build Coastguard Worker   lw a2, 2*4($z2)
1130*795d594fSAndroid Build Coastguard Worker   lb $z1, 2($shorty)
1131*795d594fSAndroid Build Coastguard Worker   bne $z1, $z3, .L${uniq}_slow_2
1132*795d594fSAndroid Build Coastguard Worker   zext.w a2, a2
1133*795d594fSAndroid Build Coastguard Worker.L${uniq}_slow_2:
1134*795d594fSAndroid Build Coastguard Worker   lw a1, 1*4($z2)
1135*795d594fSAndroid Build Coastguard Worker   lb $z1, 1($shorty)
1136*795d594fSAndroid Build Coastguard Worker   bne $z1, $z3, .L${uniq}_slow_1
1137*795d594fSAndroid Build Coastguard Worker   zext.w a1, a1
1138*795d594fSAndroid Build Coastguard Worker.L${uniq}_slow_1:
1139*795d594fSAndroid Build Coastguard Worker   // "this" never read in string-init
1140*795d594fSAndroid Build Coastguard Worker
1141*795d594fSAndroid Build Coastguard Worker
1142*795d594fSAndroid Build Coastguard Worker// Iterate through 4-bit vreg ids in the "vregs" register, load a non-FP value
1143*795d594fSAndroid Build Coastguard Worker// into one argument register.
1144*795d594fSAndroid Build Coastguard Worker%def load_vreg_in_gpr(gpr="", shorty="", vregs="", D="", F="", J="", L="", z0="", done="", uniq=""):
1145*795d594fSAndroid Build Coastguard Worker.L${uniq}_gpr_find:
1146*795d594fSAndroid Build Coastguard Worker   lb $z0, ($shorty)         // z0 := next shorty arg spec
1147*795d594fSAndroid Build Coastguard Worker   addi $shorty, $shorty, 1  // increment char ptr
1148*795d594fSAndroid Build Coastguard Worker   beqz $z0, $done           // z0 == \0
1149*795d594fSAndroid Build Coastguard Worker   beq $z0, $F, .L${uniq}_gpr_skip_4_bytes
1150*795d594fSAndroid Build Coastguard Worker   beq $z0, $D, .L${uniq}_gpr_skip_8_bytes
1151*795d594fSAndroid Build Coastguard Worker
1152*795d594fSAndroid Build Coastguard Worker   andi $gpr, $vregs, 0xF    // gpr := vreg id
1153*795d594fSAndroid Build Coastguard Worker   beq $z0, $J, .L${uniq}_gpr_load_8_bytes
1154*795d594fSAndroid Build Coastguard Worker%  get_vreg(gpr, gpr)        #  gpr := 32-bit load
1155*795d594fSAndroid Build Coastguard Worker   bne $z0, $L, .L${uniq}_gpr_load_common
1156*795d594fSAndroid Build Coastguard Worker   zext.w $gpr, $gpr
1157*795d594fSAndroid Build Coastguard Worker.L${uniq}_gpr_load_common:
1158*795d594fSAndroid Build Coastguard Worker   srliw $vregs, $vregs, 4   // shift out the processed arg, one vreg
1159*795d594fSAndroid Build Coastguard Worker   j .L${uniq}_gpr_set       // and exit
1160*795d594fSAndroid Build Coastguard Worker.L${uniq}_gpr_load_8_bytes:
1161*795d594fSAndroid Build Coastguard Worker   GET_VREG_WIDE $gpr, $gpr  // gpr := 64-bit load
1162*795d594fSAndroid Build Coastguard Worker   srliw $vregs, $vregs, 8   // shift out the processed arg, a vreg pair
1163*795d594fSAndroid Build Coastguard Worker   j .L${uniq}_gpr_set       // and exit
1164*795d594fSAndroid Build Coastguard Worker
1165*795d594fSAndroid Build Coastguard Worker.L${uniq}_gpr_skip_8_bytes:
1166*795d594fSAndroid Build Coastguard Worker   srliw $vregs, $vregs, 4   // shift out a skipped arg
1167*795d594fSAndroid Build Coastguard Worker.L${uniq}_gpr_skip_4_bytes:
1168*795d594fSAndroid Build Coastguard Worker   srliw $vregs, $vregs, 4   // shift out a skipped arg
1169*795d594fSAndroid Build Coastguard Worker   j .L${uniq}_gpr_find
1170*795d594fSAndroid Build Coastguard Worker.L${uniq}_gpr_set:
1171*795d594fSAndroid Build Coastguard Worker
1172*795d594fSAndroid Build Coastguard Worker
1173*795d594fSAndroid Build Coastguard Worker// Iterate through 4-bit vreg ids in the "vregs" register, load a float or double
1174*795d594fSAndroid Build Coastguard Worker// value into one floating point argument register.
1175*795d594fSAndroid Build Coastguard Worker%def load_vreg_in_fpr(fpr="", shorty="", vregs="", D="", F="", J="", z0="", done="", uniq=""):
1176*795d594fSAndroid Build Coastguard Worker.L${uniq}_fpr_find:
1177*795d594fSAndroid Build Coastguard Worker   lb $z0, ($shorty)         // z0 := next shorty arg spec
1178*795d594fSAndroid Build Coastguard Worker   addi $shorty, $shorty, 1  // increment char ptr
1179*795d594fSAndroid Build Coastguard Worker   beqz $z0, $done           // z0 == \0
1180*795d594fSAndroid Build Coastguard Worker   beq $z0, $F, .L${uniq}_fpr_load_4_bytes
1181*795d594fSAndroid Build Coastguard Worker   beq $z0, $D, .L${uniq}_fpr_load_8_bytes
1182*795d594fSAndroid Build Coastguard Worker
1183*795d594fSAndroid Build Coastguard Worker   srliw $vregs, $vregs, 4   // shift out a skipped arg, one vreg
1184*795d594fSAndroid Build Coastguard Worker   bne $z0, $J, .L${uniq}_fpr_find
1185*795d594fSAndroid Build Coastguard Worker   srliw $vregs, $vregs, 4   // shift out one more skipped arg, for J
1186*795d594fSAndroid Build Coastguard Worker   j .L${uniq}_fpr_find
1187*795d594fSAndroid Build Coastguard Worker
1188*795d594fSAndroid Build Coastguard Worker.L${uniq}_fpr_load_4_bytes:
1189*795d594fSAndroid Build Coastguard Worker   andi $z0, $vregs, 0xF
1190*795d594fSAndroid Build Coastguard Worker%  get_vreg_float(fpr, z0)
1191*795d594fSAndroid Build Coastguard Worker   srliw $vregs, $vregs, 4   // shift out the processed arg, one vreg
1192*795d594fSAndroid Build Coastguard Worker   j .L${uniq}_fpr_set
1193*795d594fSAndroid Build Coastguard Worker.L${uniq}_fpr_load_8_bytes:
1194*795d594fSAndroid Build Coastguard Worker   andi $z0, $vregs, 0xF
1195*795d594fSAndroid Build Coastguard Worker   GET_VREG_DOUBLE $fpr, $z0
1196*795d594fSAndroid Build Coastguard Worker   srliw $vregs, $vregs, 8   // shift out the processed arg, a vreg pair
1197*795d594fSAndroid Build Coastguard Worker.L${uniq}_fpr_set:
1198*795d594fSAndroid Build Coastguard Worker
1199*795d594fSAndroid Build Coastguard Worker
1200*795d594fSAndroid Build Coastguard Worker// Range variant
1201*795d594fSAndroid Build Coastguard Worker%def load_vreg_in_gpr_range(gpr="", shorty="", idx="", D="", F="", J="", L="", z0="", done="", uniq=""):
1202*795d594fSAndroid Build Coastguard Worker.L${uniq}_gpr_range_find:
1203*795d594fSAndroid Build Coastguard Worker   lb $z0, ($shorty)           // z0 := next shorty arg
1204*795d594fSAndroid Build Coastguard Worker   addi $shorty, $shorty, 1    // increment char ptr
1205*795d594fSAndroid Build Coastguard Worker   beqz $z0, $done             // z0 == \0
1206*795d594fSAndroid Build Coastguard Worker   beq $z0, $F, .L${uniq}_gpr_range_skip_1_vreg
1207*795d594fSAndroid Build Coastguard Worker   beq $z0, $D, .L${uniq}_gpr_range_skip_2_vreg
1208*795d594fSAndroid Build Coastguard Worker
1209*795d594fSAndroid Build Coastguard Worker   beq $z0, $J, .L${uniq}_gpr_range_load_2_vreg
1210*795d594fSAndroid Build Coastguard Worker%  get_vreg(gpr, idx)
1211*795d594fSAndroid Build Coastguard Worker   bne $z0, $L, .L${uniq}_gpr_range_load_common
1212*795d594fSAndroid Build Coastguard Worker   zext.w $gpr, $gpr
1213*795d594fSAndroid Build Coastguard Worker.L${uniq}_gpr_range_load_common:
1214*795d594fSAndroid Build Coastguard Worker   addi $idx, $idx, 1
1215*795d594fSAndroid Build Coastguard Worker   j .L${uniq}_gpr_range_done
1216*795d594fSAndroid Build Coastguard Worker.L${uniq}_gpr_range_load_2_vreg:
1217*795d594fSAndroid Build Coastguard Worker   GET_VREG_WIDE $gpr, $idx
1218*795d594fSAndroid Build Coastguard Worker   addi $idx, $idx, 2
1219*795d594fSAndroid Build Coastguard Worker   j .L${uniq}_gpr_range_done
1220*795d594fSAndroid Build Coastguard Worker
1221*795d594fSAndroid Build Coastguard Worker.L${uniq}_gpr_range_skip_2_vreg:
1222*795d594fSAndroid Build Coastguard Worker   addi $idx, $idx, 1
1223*795d594fSAndroid Build Coastguard Worker.L${uniq}_gpr_range_skip_1_vreg:
1224*795d594fSAndroid Build Coastguard Worker   addi $idx, $idx, 1
1225*795d594fSAndroid Build Coastguard Worker   j .L${uniq}_gpr_range_find
1226*795d594fSAndroid Build Coastguard Worker.L${uniq}_gpr_range_done:
1227*795d594fSAndroid Build Coastguard Worker
1228*795d594fSAndroid Build Coastguard Worker
1229*795d594fSAndroid Build Coastguard Worker// Range variant.
1230*795d594fSAndroid Build Coastguard Worker%def load_vreg_in_fpr_range(fpr="", shorty="", idx="", D="", F="", J="", z0="", done="", uniq=""):
1231*795d594fSAndroid Build Coastguard Worker.L${uniq}_fpr_range_find:
1232*795d594fSAndroid Build Coastguard Worker   lb $z0, ($shorty)         // z0 := next shorty arg
1233*795d594fSAndroid Build Coastguard Worker   addi $shorty, $shorty, 1  // increment char ptr
1234*795d594fSAndroid Build Coastguard Worker   beqz $z0, $done           // z0 == \0
1235*795d594fSAndroid Build Coastguard Worker   beq $z0, $F, .L${uniq}_fpr_range_load_4_bytes
1236*795d594fSAndroid Build Coastguard Worker   beq $z0, $D, .L${uniq}_fpr_range_load_8_bytes
1237*795d594fSAndroid Build Coastguard Worker
1238*795d594fSAndroid Build Coastguard Worker   addi $idx, $idx, 1        // increment idx
1239*795d594fSAndroid Build Coastguard Worker   bne $z0, $J, .L${uniq}_fpr_range_find
1240*795d594fSAndroid Build Coastguard Worker   addi $idx, $idx, 1        // increment once more for J
1241*795d594fSAndroid Build Coastguard Worker   j .L${uniq}_fpr_range_find
1242*795d594fSAndroid Build Coastguard Worker
1243*795d594fSAndroid Build Coastguard Worker.L${uniq}_fpr_range_load_4_bytes:
1244*795d594fSAndroid Build Coastguard Worker   mv $z0, $idx
1245*795d594fSAndroid Build Coastguard Worker%  get_vreg_float(fpr, z0)
1246*795d594fSAndroid Build Coastguard Worker   addi $idx, $idx, 1
1247*795d594fSAndroid Build Coastguard Worker   j .L${uniq}_fpr_range_set
1248*795d594fSAndroid Build Coastguard Worker.L${uniq}_fpr_range_load_8_bytes:
1249*795d594fSAndroid Build Coastguard Worker   mv $z0, $idx
1250*795d594fSAndroid Build Coastguard Worker   GET_VREG_DOUBLE $fpr, $z0
1251*795d594fSAndroid Build Coastguard Worker   addi $idx, $idx, 2
1252*795d594fSAndroid Build Coastguard Worker.L${uniq}_fpr_range_set:
1253*795d594fSAndroid Build Coastguard Worker
1254*795d594fSAndroid Build Coastguard Worker
1255*795d594fSAndroid Build Coastguard Worker%def is_out_stack_needed(needed="", shorty="", D="", F="", z0="", uniq=""):
1256*795d594fSAndroid Build Coastguard Worker.L${uniq}_scan_arg:
1257*795d594fSAndroid Build Coastguard Worker   lb $z0, ($shorty)
1258*795d594fSAndroid Build Coastguard Worker   addi $shorty, $shorty, 1
1259*795d594fSAndroid Build Coastguard Worker   beqz $z0, .L${uniq}_scan_done
1260*795d594fSAndroid Build Coastguard Worker   beq $z0, $F, .L${uniq}_scan_arg
1261*795d594fSAndroid Build Coastguard Worker   beq $z0, $D, .L${uniq}_scan_arg
1262*795d594fSAndroid Build Coastguard Worker   li $needed, 1
1263*795d594fSAndroid Build Coastguard Worker.L${uniq}_scan_done:
1264*795d594fSAndroid Build Coastguard Worker
1265*795d594fSAndroid Build Coastguard Worker
1266*795d594fSAndroid Build Coastguard Worker%def is_out_stack_needed_float(needed="", shorty="", D="", F="", z0="", uniq=""):
1267*795d594fSAndroid Build Coastguard Worker   bnez $needed, .L${uniq}_scan_float_done
1268*795d594fSAndroid Build Coastguard Worker.L${uniq}_scan_float_arg:
1269*795d594fSAndroid Build Coastguard Worker   lb $z0, ($shorty)
1270*795d594fSAndroid Build Coastguard Worker   addi $shorty, $shorty, 1
1271*795d594fSAndroid Build Coastguard Worker   beqz $z0, .L${uniq}_scan_float_done
1272*795d594fSAndroid Build Coastguard Worker   beq $z0, $F, .L${uniq}_scan_float_found
1273*795d594fSAndroid Build Coastguard Worker   beq $z0, $D, .L${uniq}_scan_float_found
1274*795d594fSAndroid Build Coastguard Worker   j .L${uniq}_scan_float_arg
1275*795d594fSAndroid Build Coastguard Worker.L${uniq}_scan_float_found:
1276*795d594fSAndroid Build Coastguard Worker   li $needed, 1
1277*795d594fSAndroid Build Coastguard Worker.L${uniq}_scan_float_done:
1278*795d594fSAndroid Build Coastguard Worker
1279*795d594fSAndroid Build Coastguard Worker
1280*795d594fSAndroid Build Coastguard Worker%def copy_vregs_to_out(out="", fp="", fp_top="", z0="", uniq=""):
1281*795d594fSAndroid Build Coastguard Worker   sub $z0, $fp_top, $fp  // z0 := byte range
1282*795d594fSAndroid Build Coastguard Worker   BRANCH_IF_BIT_CLEAR $z0, $z0, 2, .L${uniq}_copy_wide
1283*795d594fSAndroid Build Coastguard Worker                          // branch if odd count of slots
1284*795d594fSAndroid Build Coastguard Worker   lwu $z0, ($fp)
1285*795d594fSAndroid Build Coastguard Worker   sw $z0, ($out)
1286*795d594fSAndroid Build Coastguard Worker   addi $fp, $fp, 4
1287*795d594fSAndroid Build Coastguard Worker   addi $out, $out, 4
1288*795d594fSAndroid Build Coastguard Worker.L${uniq}_copy_wide:
1289*795d594fSAndroid Build Coastguard Worker   beq $fp, $fp_top, .L${uniq}_copy_done
1290*795d594fSAndroid Build Coastguard Worker   ld $z0, ($fp)
1291*795d594fSAndroid Build Coastguard Worker   sd $z0, ($out)
1292*795d594fSAndroid Build Coastguard Worker   addi $fp, $fp, 8
1293*795d594fSAndroid Build Coastguard Worker   addi $out, $out, 8
1294*795d594fSAndroid Build Coastguard Worker   j .L${uniq}_copy_wide
1295*795d594fSAndroid Build Coastguard Worker.L${uniq}_copy_done:
1296*795d594fSAndroid Build Coastguard Worker
1297*795d594fSAndroid Build Coastguard Worker
1298*795d594fSAndroid Build Coastguard Worker// NterpToNterpInstance
1299*795d594fSAndroid Build Coastguard Worker// a0: ArtMethod*
1300*795d594fSAndroid Build Coastguard Worker// a1: this
1301*795d594fSAndroid Build Coastguard Worker%def nterp_to_nterp_instance():
1302*795d594fSAndroid Build Coastguard Worker%  nterp_to_nterp(how_vC="in_a1", uniq="n2n_instance")
1303*795d594fSAndroid Build Coastguard Worker
1304*795d594fSAndroid Build Coastguard Worker
1305*795d594fSAndroid Build Coastguard Worker// NterpToNterpStringInit
1306*795d594fSAndroid Build Coastguard Worker// a0: ArtMethod*
1307*795d594fSAndroid Build Coastguard Worker%def nterp_to_nterp_string_init():
1308*795d594fSAndroid Build Coastguard Worker%  nterp_to_nterp(how_vC="skip", uniq="n2n_string_init")
1309*795d594fSAndroid Build Coastguard Worker
1310*795d594fSAndroid Build Coastguard Worker
1311*795d594fSAndroid Build Coastguard Worker// NterpToNterpStatic
1312*795d594fSAndroid Build Coastguard Worker// a0: ArtMethod*
1313*795d594fSAndroid Build Coastguard Worker%def nterp_to_nterp_static():
1314*795d594fSAndroid Build Coastguard Worker%  nterp_to_nterp(a1_instance=False, how_vC="load", uniq="n2n_static")
1315*795d594fSAndroid Build Coastguard Worker
1316*795d594fSAndroid Build Coastguard Worker
1317*795d594fSAndroid Build Coastguard Worker// NterpToNterpInstanceRange
1318*795d594fSAndroid Build Coastguard Worker%def nterp_to_nterp_instance_range():
1319*795d594fSAndroid Build Coastguard Worker%  nterp_to_nterp(how_vC="in_a1", uniq="n2n_instance_range", range="Range")
1320*795d594fSAndroid Build Coastguard Worker
1321*795d594fSAndroid Build Coastguard Worker
1322*795d594fSAndroid Build Coastguard Worker// NterpToNterpStringInitRange
1323*795d594fSAndroid Build Coastguard Worker%def nterp_to_nterp_string_init_range():
1324*795d594fSAndroid Build Coastguard Worker%  nterp_to_nterp(how_vC="skip", uniq="n2n_string_init_range", range="Range")
1325*795d594fSAndroid Build Coastguard Worker
1326*795d594fSAndroid Build Coastguard Worker
1327*795d594fSAndroid Build Coastguard Worker// NterpToNterpStaticRange
1328*795d594fSAndroid Build Coastguard Worker%def nterp_to_nterp_static_range():
1329*795d594fSAndroid Build Coastguard Worker%  nterp_to_nterp(a1_instance=False, how_vC="load", uniq="n2n_static_range", range="Range")
1330*795d594fSAndroid Build Coastguard Worker
1331*795d594fSAndroid Build Coastguard Worker
1332*795d594fSAndroid Build Coastguard Worker// helpers
1333*795d594fSAndroid Build Coastguard Worker
1334*795d594fSAndroid Build Coastguard Worker
1335*795d594fSAndroid Build Coastguard Worker%def nterp_to_nterp(a1_instance=True, how_vC="", uniq="", range=""):
1336*795d594fSAndroid Build Coastguard Worker   .cfi_startproc
1337*795d594fSAndroid Build Coastguard Worker%  setup_nterp_frame(cfi_refs="23", refs="s8", fp="s9", pc="s10", regs="s11", spills_sp="t0", z0="t1", z1="t2", z2="t3", z3="t4", uniq=uniq)
1338*795d594fSAndroid Build Coastguard Worker       // s8  := callee xREFS
1339*795d594fSAndroid Build Coastguard Worker       // s9  := callee xFP
1340*795d594fSAndroid Build Coastguard Worker       // s10 := callee xPC
1341*795d594fSAndroid Build Coastguard Worker       // s11 := fp/refs vreg count
1342*795d594fSAndroid Build Coastguard Worker       // t0  := post-spills pre-frame sp (unused here)
1343*795d594fSAndroid Build Coastguard Worker       // sp  := post-frame callee sp
1344*795d594fSAndroid Build Coastguard Worker%  if range == 'Range':
1345*795d594fSAndroid Build Coastguard Worker%    n2n_arg_move_range(refs="s8", fp="s9", regs="s11", vC="s7", z0="t0", z1="t1", z2="t2", z3="t3", z4="t4", z5="t5", a1_instance=a1_instance, how_vC=how_vC, uniq=uniq)
1346*795d594fSAndroid Build Coastguard Worker%  else:
1347*795d594fSAndroid Build Coastguard Worker%    n2n_arg_move(refs="s8", fp="s9", pc="s10", regs="s11", v_fedc="s7", z0="t0", z1="t1", z2="t2", z3="t3", a1_instance=a1_instance, how_vC=how_vC, uniq=uniq)
1348*795d594fSAndroid Build Coastguard Worker%#:
1349*795d594fSAndroid Build Coastguard Worker   mv xREFS, s8
1350*795d594fSAndroid Build Coastguard Worker   mv xFP, s9
1351*795d594fSAndroid Build Coastguard Worker   mv xPC, s10
1352*795d594fSAndroid Build Coastguard Worker   CFI_DEFINE_DEX_PC_WITH_OFFSET(/*tmpReg*/CFI_TMP, /*dexReg*/CFI_DEX, /*dexOffset*/0)
1353*795d594fSAndroid Build Coastguard Worker
1354*795d594fSAndroid Build Coastguard Worker   START_EXECUTING_INSTRUCTIONS
1355*795d594fSAndroid Build Coastguard Worker   .cfi_endproc
1356*795d594fSAndroid Build Coastguard Worker
1357*795d594fSAndroid Build Coastguard Worker
1358*795d594fSAndroid Build Coastguard Worker// See runtime/nterp_helpers.cc for a diagram of the setup.
1359*795d594fSAndroid Build Coastguard Worker// Hardcoded
1360*795d594fSAndroid Build Coastguard Worker// - a0 - ArtMethod*
1361*795d594fSAndroid Build Coastguard Worker// Input
1362*795d594fSAndroid Build Coastguard Worker// - \cfi_refs: dwarf register number of \refs, for CFI
1363*795d594fSAndroid Build Coastguard Worker// - \uniq: string to ensure unique symbolic labels between instantiations
1364*795d594fSAndroid Build Coastguard Worker// Output
1365*795d594fSAndroid Build Coastguard Worker// - sp: adjusted downward for callee-saves and nterp frame
1366*795d594fSAndroid Build Coastguard Worker// - \refs: callee xREFS
1367*795d594fSAndroid Build Coastguard Worker// - \fp: callee xFP
1368*795d594fSAndroid Build Coastguard Worker// - \pc: callee xPC
1369*795d594fSAndroid Build Coastguard Worker// - \regs: register count in \refs
1370*795d594fSAndroid Build Coastguard Worker// - \ins: in count
1371*795d594fSAndroid Build Coastguard Worker// - \spills_sp: stack pointer after reg spills
1372*795d594fSAndroid Build Coastguard Worker%def setup_nterp_frame(cfi_refs="", refs="", fp="", pc="", regs="", ins="zero", spills_sp="", z0="", z1="", z2="", z3="", uniq=""):
1373*795d594fSAndroid Build Coastguard Worker   // Check guard page for stack overflow.
1374*795d594fSAndroid Build Coastguard Worker   li $z0, -STACK_OVERFLOW_RESERVED_BYTES
1375*795d594fSAndroid Build Coastguard Worker   add $z0, $z0, sp
1376*795d594fSAndroid Build Coastguard Worker   ld zero, ($z0)
1377*795d594fSAndroid Build Coastguard Worker
1378*795d594fSAndroid Build Coastguard Worker   INCREASE_FRAME NTERP_SIZE_SAVE_CALLEE_SAVES
1379*795d594fSAndroid Build Coastguard Worker                        // sp := sp + callee-saves
1380*795d594fSAndroid Build Coastguard Worker   SETUP_NTERP_SAVE_CALLEE_SAVES
1381*795d594fSAndroid Build Coastguard Worker
1382*795d594fSAndroid Build Coastguard Worker   ld $pc, ART_METHOD_DATA_OFFSET_64(a0)
1383*795d594fSAndroid Build Coastguard Worker   FETCH_CODE_ITEM_INFO code_item=$pc, regs=$regs, outs=$z0, ins=$ins
1384*795d594fSAndroid Build Coastguard Worker                        // pc   := callee dex array
1385*795d594fSAndroid Build Coastguard Worker                        // regs := vreg count for fp array and refs array
1386*795d594fSAndroid Build Coastguard Worker                        // z0   := vreg count for outs array
1387*795d594fSAndroid Build Coastguard Worker                        // ins  := vreg count for ins array
1388*795d594fSAndroid Build Coastguard Worker
1389*795d594fSAndroid Build Coastguard Worker   // Compute required frame size: ((2 * \regs) + \z0) * 4 + 24
1390*795d594fSAndroid Build Coastguard Worker   // - The register array and reference array each have \regs number of slots.
1391*795d594fSAndroid Build Coastguard Worker   // - The out array has \z0 slots.
1392*795d594fSAndroid Build Coastguard Worker   // - Each register slot is 4 bytes.
1393*795d594fSAndroid Build Coastguard Worker   // - Additional 24 bytes for 3 fields: saved frame pointer, dex pc, and ArtMethod*.
1394*795d594fSAndroid Build Coastguard Worker   sh1add $z1, $regs, $z0
1395*795d594fSAndroid Build Coastguard Worker   slli $z1, $z1, 2
1396*795d594fSAndroid Build Coastguard Worker   addi $z1, $z1, 24    // z1 := frame size, without alignment padding
1397*795d594fSAndroid Build Coastguard Worker
1398*795d594fSAndroid Build Coastguard Worker   // compute new stack pointer
1399*795d594fSAndroid Build Coastguard Worker   sub $z1, sp, $z1
1400*795d594fSAndroid Build Coastguard Worker   // 16-byte alignment.
1401*795d594fSAndroid Build Coastguard Worker   andi $z1, $z1, ~0xF  // z1 := new sp
1402*795d594fSAndroid Build Coastguard Worker
1403*795d594fSAndroid Build Coastguard Worker   // Set \refs to base of reference array. Align to pointer size for the frame pointer and dex pc
1404*795d594fSAndroid Build Coastguard Worker   // pointer, below the reference array.
1405*795d594fSAndroid Build Coastguard Worker   sh2add $z0, $z0, $z1  // z0 := out array size in bytes
1406*795d594fSAndroid Build Coastguard Worker   addi $z0, $z0, 28     //     + 24 bytes for 3 fields, plus 4 for alignment slack.
1407*795d594fSAndroid Build Coastguard Worker   andi $refs, $z0, -__SIZEOF_POINTER__
1408*795d594fSAndroid Build Coastguard Worker                         // refs := refs array base
1409*795d594fSAndroid Build Coastguard Worker
1410*795d594fSAndroid Build Coastguard Worker   // Set \fp to base of register array, above the reference array. This region is already aligned.
1411*795d594fSAndroid Build Coastguard Worker   sh2add $fp, $regs, $refs
1412*795d594fSAndroid Build Coastguard Worker                         // fp := fp array base
1413*795d594fSAndroid Build Coastguard Worker
1414*795d594fSAndroid Build Coastguard Worker   // Set up the stack pointer.
1415*795d594fSAndroid Build Coastguard Worker   mv $spills_sp, sp     // spills_sp := old sp
1416*795d594fSAndroid Build Coastguard Worker   .cfi_def_cfa_register $spills_sp
1417*795d594fSAndroid Build Coastguard Worker   mv sp, $z1            // sp := new sp
1418*795d594fSAndroid Build Coastguard Worker   sd $spills_sp, -8($refs)
1419*795d594fSAndroid Build Coastguard Worker   // The CFA rule is now a dwarf expression, because the nterp frame offset for SP is a dynamic
1420*795d594fSAndroid Build Coastguard Worker   // value, and thus SP cannot help compute CFA. For the duration of the nterp frame, CFI
1421*795d594fSAndroid Build Coastguard Worker   // directives cannot adjust this CFA rule, but may still capture CFI for register spills as
1422*795d594fSAndroid Build Coastguard Worker   // "register + offset" with a dwarf expression.
1423*795d594fSAndroid Build Coastguard Worker   CFI_DEF_CFA_BREG_PLUS_UCONST $cfi_refs, -8, NTERP_SIZE_SAVE_CALLEE_SAVES
1424*795d594fSAndroid Build Coastguard Worker
1425*795d594fSAndroid Build Coastguard Worker   // Put nulls in reference array.
1426*795d594fSAndroid Build Coastguard Worker   beqz $regs, .L${uniq}_ref_zero_done
1427*795d594fSAndroid Build Coastguard Worker   mv $z0, $refs         // z0 := address iterator
1428*795d594fSAndroid Build Coastguard Worker.L${uniq}_ref_zero:
1429*795d594fSAndroid Build Coastguard Worker   // Write in 8-byte increments, so fp[0] gets zero'ed too, if \regs is odd.
1430*795d594fSAndroid Build Coastguard Worker   sd zero, ($z0)
1431*795d594fSAndroid Build Coastguard Worker   addi $z0, $z0, 8
1432*795d594fSAndroid Build Coastguard Worker   bltu $z0, $fp, .L${uniq}_ref_zero
1433*795d594fSAndroid Build Coastguard Worker.L${uniq}_ref_zero_done:
1434*795d594fSAndroid Build Coastguard Worker   // Save the ArtMethod*.
1435*795d594fSAndroid Build Coastguard Worker   sd a0, (sp)
1436*795d594fSAndroid Build Coastguard Worker
1437*795d594fSAndroid Build Coastguard Worker
1438*795d594fSAndroid Build Coastguard Worker// Hardcoded
1439*795d594fSAndroid Build Coastguard Worker// - (caller) xINST, xFP, xREFS, xPC
1440*795d594fSAndroid Build Coastguard Worker// - a0: ArtMethod*
1441*795d594fSAndroid Build Coastguard Worker// - a1: this, for instance invoke
1442*795d594fSAndroid Build Coastguard Worker%def n2n_arg_move(refs="", fp="", regs="", pc="", v_fedc="", z0="", z1="", z2="", z3="", a1_instance=True, how_vC="", uniq=""):
1443*795d594fSAndroid Build Coastguard Worker   srliw $z0, xINST, 12       // z0 := A (arg count)
1444*795d594fSAndroid Build Coastguard Worker
1445*795d594fSAndroid Build Coastguard Worker%  if not a1_instance:
1446*795d594fSAndroid Build Coastguard Worker     beqz $z0, .L${uniq}_arg_done
1447*795d594fSAndroid Build Coastguard Worker%#:
1448*795d594fSAndroid Build Coastguard Worker   // A >= 1, decide and branch
1449*795d594fSAndroid Build Coastguard Worker   li $z1, 2
1450*795d594fSAndroid Build Coastguard Worker   sub $z2, $regs, $z0        // z2 := regs - A; vC's index in fp
1451*795d594fSAndroid Build Coastguard Worker   sh2add $z3, $z2, $fp       // z3 := addr of fp[C]
1452*795d594fSAndroid Build Coastguard Worker   sh2add $z2, $z2, $refs     // z2 := addr of refs[C]
1453*795d594fSAndroid Build Coastguard Worker   blt $z0, $z1, .L${uniq}_arg_1
1454*795d594fSAndroid Build Coastguard Worker   beq $z0, $z1, .L${uniq}_arg_2
1455*795d594fSAndroid Build Coastguard Worker   li $z1, 4
1456*795d594fSAndroid Build Coastguard Worker   blt $z0, $z1, .L${uniq}_arg_3
1457*795d594fSAndroid Build Coastguard Worker   beq $z0, $z1, .L${uniq}_arg_4
1458*795d594fSAndroid Build Coastguard Worker
1459*795d594fSAndroid Build Coastguard Worker   // A = 5
1460*795d594fSAndroid Build Coastguard Worker   srliw $z0, xINST, 8
1461*795d594fSAndroid Build Coastguard Worker   andi $z0, $z0, 0xF         // z0 := G
1462*795d594fSAndroid Build Coastguard Worker%  get_vreg(z1, z0)           #  z1 := xFP[G]
1463*795d594fSAndroid Build Coastguard Worker   sw $z1, (4*4)($z3)         // fp[G] := z1
1464*795d594fSAndroid Build Coastguard Worker   GET_VREG_OBJECT $z0, $z0   // z0 := xREFS[G]
1465*795d594fSAndroid Build Coastguard Worker   sw $z0, (4*4)($z2)         // refs[G] := z0
1466*795d594fSAndroid Build Coastguard Worker.L${uniq}_arg_4:
1467*795d594fSAndroid Build Coastguard Worker   srliw $z0, $v_fedc, 12     // z0 := F
1468*795d594fSAndroid Build Coastguard Worker%  get_vreg(z1, z0)           #  z1 := xFP[F]
1469*795d594fSAndroid Build Coastguard Worker   sw $z1, (3*4)($z3)         // fp[F] := z1
1470*795d594fSAndroid Build Coastguard Worker   GET_VREG_OBJECT $z0, $z0   // z0 := xREFS[F]
1471*795d594fSAndroid Build Coastguard Worker   sw $z0, (3*4)($z2)         // refs[F] := z0
1472*795d594fSAndroid Build Coastguard Worker.L${uniq}_arg_3:
1473*795d594fSAndroid Build Coastguard Worker   srliw $z0, $v_fedc, 8      // z0 := F|E
1474*795d594fSAndroid Build Coastguard Worker   andi $z0, $z0, 0xF         // z0 := E
1475*795d594fSAndroid Build Coastguard Worker%  get_vreg(z1, z0)           #  z1 := xFP[E]
1476*795d594fSAndroid Build Coastguard Worker   sw $z1, (2*4)($z3)         // fp[E] := z1
1477*795d594fSAndroid Build Coastguard Worker   GET_VREG_OBJECT $z0, $z0   // z0 := xREFS[E]
1478*795d594fSAndroid Build Coastguard Worker   sw $z0, (2*4)($z2)         // refs[E] := z0
1479*795d594fSAndroid Build Coastguard Worker.L${uniq}_arg_2:
1480*795d594fSAndroid Build Coastguard Worker   srliw $z0, $v_fedc, 4      // z0 := F|E|D
1481*795d594fSAndroid Build Coastguard Worker   andi $z0, $z0, 0xF         // z0 := D
1482*795d594fSAndroid Build Coastguard Worker%  get_vreg(z1, z0)           #  z1 := xFP[D]
1483*795d594fSAndroid Build Coastguard Worker   sw $z1, (1*4)($z3)         // fp[D] := z1
1484*795d594fSAndroid Build Coastguard Worker   GET_VREG_OBJECT $z0, $z0   // z0 := xREFS[D]
1485*795d594fSAndroid Build Coastguard Worker   sw $z0, (1*4)($z2)         // refs[D] := z0
1486*795d594fSAndroid Build Coastguard Worker.L${uniq}_arg_1:
1487*795d594fSAndroid Build Coastguard Worker%  if how_vC == "in_a1":
1488*795d594fSAndroid Build Coastguard Worker     // a1 = xFP[C] from earlier stage of instance invoke
1489*795d594fSAndroid Build Coastguard Worker     sw a1, (0*4)($z3)        // fp[C] := a1
1490*795d594fSAndroid Build Coastguard Worker     sw a1, (0*4)($z2)        // refs[C] := a1
1491*795d594fSAndroid Build Coastguard Worker%  elif how_vC == "skip":
1492*795d594fSAndroid Build Coastguard Worker     // string init doesn't read "this"
1493*795d594fSAndroid Build Coastguard Worker%  elif how_vC == "load":
1494*795d594fSAndroid Build Coastguard Worker     // static method loads vC just like other vregs
1495*795d594fSAndroid Build Coastguard Worker     andi $z0, $v_fedc, 0xF   // z0 := C
1496*795d594fSAndroid Build Coastguard Worker%    get_vreg(z1, z0)         #  z1 := xFP[C]
1497*795d594fSAndroid Build Coastguard Worker     sw $z1, (0*4)($z3)       // fp[C] := z1
1498*795d594fSAndroid Build Coastguard Worker     GET_VREG_OBJECT $z0, $z0  // z0 := xREFS[C]
1499*795d594fSAndroid Build Coastguard Worker     sw $z0, (0*4)($z2)       // refs[C] := z0
1500*795d594fSAndroid Build Coastguard Worker%#:
1501*795d594fSAndroid Build Coastguard Worker.L${uniq}_arg_done:
1502*795d594fSAndroid Build Coastguard Worker
1503*795d594fSAndroid Build Coastguard Worker
1504*795d594fSAndroid Build Coastguard Worker%def n2n_arg_move_range(refs="", fp="", regs="", vC="", z0="", z1="", z2="", z3="", z4="", z5="", a1_instance=True, how_vC="", uniq=""):
1505*795d594fSAndroid Build Coastguard Worker   srliw $z0, xINST, 8     // z0 := AA (arg count)
1506*795d594fSAndroid Build Coastguard Worker
1507*795d594fSAndroid Build Coastguard Worker%  if not a1_instance:
1508*795d594fSAndroid Build Coastguard Worker     beqz $z0, .L${uniq}_arg_range_done
1509*795d594fSAndroid Build Coastguard Worker%#:
1510*795d594fSAndroid Build Coastguard Worker   // AA >= 1, iterator setup
1511*795d594fSAndroid Build Coastguard Worker   sub $z4, $regs, $z0     // z4 := regs - AA; starting idx in fp and refs
1512*795d594fSAndroid Build Coastguard Worker   sh2add $z1, $vC, xREFS  // z1 := addr of xREFS[CCCC]
1513*795d594fSAndroid Build Coastguard Worker   sh2add $z2, $vC, xFP    // z2 := addr of xFP[CCCC]
1514*795d594fSAndroid Build Coastguard Worker   sh2add $z3, $z4, $refs  // z3 := addr of refs[z4]
1515*795d594fSAndroid Build Coastguard Worker   sh2add $z4, $z4, $fp    // z4 := addr of fp[z4]
1516*795d594fSAndroid Build Coastguard Worker
1517*795d594fSAndroid Build Coastguard Worker   BRANCH_IF_BIT_CLEAR $z0, $z0, 0, .L${uniq}_arg_range_copy_wide
1518*795d594fSAndroid Build Coastguard Worker                           // branch if AA is even
1519*795d594fSAndroid Build Coastguard Worker   // AA is odd, transfer one slot. Apply some optimizations.
1520*795d594fSAndroid Build Coastguard Worker%  if how_vC == "in_a1":
1521*795d594fSAndroid Build Coastguard Worker     sw a1, ($z3)
1522*795d594fSAndroid Build Coastguard Worker     sw a1, ($z4)
1523*795d594fSAndroid Build Coastguard Worker%  elif how_vC == "skip":
1524*795d594fSAndroid Build Coastguard Worker     // string init doesn't read "this"
1525*795d594fSAndroid Build Coastguard Worker%  elif how_vC == "load":
1526*795d594fSAndroid Build Coastguard Worker     lw $z0, ($z1)
1527*795d594fSAndroid Build Coastguard Worker     lw $z5, ($z2)
1528*795d594fSAndroid Build Coastguard Worker     sw $z0, ($z3)
1529*795d594fSAndroid Build Coastguard Worker     sw $z5, ($z4)
1530*795d594fSAndroid Build Coastguard Worker%#:
1531*795d594fSAndroid Build Coastguard Worker   addi $z1, $z1, 4
1532*795d594fSAndroid Build Coastguard Worker   addi $z2, $z2, 4
1533*795d594fSAndroid Build Coastguard Worker   addi $z3, $z3, 4
1534*795d594fSAndroid Build Coastguard Worker   addi $z4, $z4, 4
1535*795d594fSAndroid Build Coastguard Worker.L${uniq}_arg_range_copy_wide:
1536*795d594fSAndroid Build Coastguard Worker   // Even count of vreg slots, apply LD/SD.
1537*795d594fSAndroid Build Coastguard Worker   beq $z3, $fp, .L${uniq}_arg_range_done  // terminate loop if refs[regs] == fp[0]
1538*795d594fSAndroid Build Coastguard Worker   ld $z0, ($z1)
1539*795d594fSAndroid Build Coastguard Worker   ld $z5, ($z2)
1540*795d594fSAndroid Build Coastguard Worker   sd $z0, ($z3)
1541*795d594fSAndroid Build Coastguard Worker   sd $z5, ($z4)
1542*795d594fSAndroid Build Coastguard Worker   addi $z1, $z1, 8
1543*795d594fSAndroid Build Coastguard Worker   addi $z2, $z2, 8
1544*795d594fSAndroid Build Coastguard Worker   addi $z3, $z3, 8
1545*795d594fSAndroid Build Coastguard Worker   addi $z4, $z4, 8
1546*795d594fSAndroid Build Coastguard Worker   j .L${uniq}_arg_range_copy_wide
1547*795d594fSAndroid Build Coastguard Worker.L${uniq}_arg_range_done:
1548*795d594fSAndroid Build Coastguard Worker
1549*795d594fSAndroid Build Coastguard Worker
1550*795d594fSAndroid Build Coastguard Worker//
1551*795d594fSAndroid Build Coastguard Worker// Nterp entry point helpers
1552*795d594fSAndroid Build Coastguard Worker//
1553*795d594fSAndroid Build Coastguard Worker
1554*795d594fSAndroid Build Coastguard Worker
1555*795d594fSAndroid Build Coastguard Worker// Hardcoded:
1556*795d594fSAndroid Build Coastguard Worker// - a0: ArtMethod*
1557*795d594fSAndroid Build Coastguard Worker%def setup_ref_args_and_go(fp="", refs="", refs_end="", spills_sp="", z0="", z1="", done=""):
1558*795d594fSAndroid Build Coastguard Worker   // Store managed-ABI register args into fp/refs arrays.
1559*795d594fSAndroid Build Coastguard Worker%  store_ref_to_vreg(gpr="a1", fp=fp, refs=refs, refs_end=refs_end, done=done)
1560*795d594fSAndroid Build Coastguard Worker%  store_ref_to_vreg(gpr="a2", fp=fp, refs=refs, refs_end=refs_end, done=done)
1561*795d594fSAndroid Build Coastguard Worker%  store_ref_to_vreg(gpr="a3", fp=fp, refs=refs, refs_end=refs_end, done=done)
1562*795d594fSAndroid Build Coastguard Worker%  store_ref_to_vreg(gpr="a4", fp=fp, refs=refs, refs_end=refs_end, done=done)
1563*795d594fSAndroid Build Coastguard Worker%  store_ref_to_vreg(gpr="a5", fp=fp, refs=refs, refs_end=refs_end, done=done)
1564*795d594fSAndroid Build Coastguard Worker%  store_ref_to_vreg(gpr="a6", fp=fp, refs=refs, refs_end=refs_end, done=done)
1565*795d594fSAndroid Build Coastguard Worker%  store_ref_to_vreg(gpr="a7", fp=fp, refs=refs, refs_end=refs_end, done=done)
1566*795d594fSAndroid Build Coastguard Worker   // We drained arg registers, so continue from caller's stack.
1567*795d594fSAndroid Build Coastguard Worker   // A ref arg is 4 bytes, so the continuation offset is well known.
1568*795d594fSAndroid Build Coastguard Worker   addi $z0, $spills_sp, (NTERP_SIZE_SAVE_CALLEE_SAVES + 8 + 7*4)
1569*795d594fSAndroid Build Coastguard Worker       // z0 := out array base addr + 7 vreg slots
1570*795d594fSAndroid Build Coastguard Worker.Lentry_ref_stack:
1571*795d594fSAndroid Build Coastguard Worker   lwu $z1, ($z0)
1572*795d594fSAndroid Build Coastguard Worker   sw $z1, ($fp)
1573*795d594fSAndroid Build Coastguard Worker   sw $z1, ($refs)
1574*795d594fSAndroid Build Coastguard Worker   addi $z0, $z0, 4
1575*795d594fSAndroid Build Coastguard Worker   addi $fp, $fp, 4
1576*795d594fSAndroid Build Coastguard Worker   addi $refs, $refs, 4
1577*795d594fSAndroid Build Coastguard Worker   bne $refs, $refs_end, .Lentry_ref_stack
1578*795d594fSAndroid Build Coastguard Worker
1579*795d594fSAndroid Build Coastguard Worker   j $done
1580*795d594fSAndroid Build Coastguard Worker
1581*795d594fSAndroid Build Coastguard Worker
1582*795d594fSAndroid Build Coastguard Worker%def store_ref_to_vreg(gpr="", fp="", refs="", refs_end="", done=""):
1583*795d594fSAndroid Build Coastguard Worker   sw $gpr, ($fp)
1584*795d594fSAndroid Build Coastguard Worker   sw $gpr, ($refs)
1585*795d594fSAndroid Build Coastguard Worker   addi $fp, $fp, 4
1586*795d594fSAndroid Build Coastguard Worker   addi $refs, $refs, 4
1587*795d594fSAndroid Build Coastguard Worker   beq $refs, $refs_end, $done
1588*795d594fSAndroid Build Coastguard Worker
1589*795d594fSAndroid Build Coastguard Worker
1590*795d594fSAndroid Build Coastguard Worker// \fp and \refs are used as array base addrs, unmodified.
1591*795d594fSAndroid Build Coastguard Worker%def store_gpr_to_vreg(gpr="", offset="", shorty="", fp="", refs="", z0="", z1="", D="", F="", J="", L="", next=""):
1592*795d594fSAndroid Build Coastguard Worker.Lentry_arg_${gpr}:
1593*795d594fSAndroid Build Coastguard Worker   lb $z0, ($shorty)         // z0 := shorty type
1594*795d594fSAndroid Build Coastguard Worker   addi $shorty, $shorty, 1  // Increment char ptr.
1595*795d594fSAndroid Build Coastguard Worker   beqz $z0, $next           // z0 = \0: finished shorty pass
1596*795d594fSAndroid Build Coastguard Worker   beq $z0, $D, .Lentry_arg_skip_double_${gpr}
1597*795d594fSAndroid Build Coastguard Worker   beq $z0, $F, .Lentry_arg_skip_float_${gpr}
1598*795d594fSAndroid Build Coastguard Worker
1599*795d594fSAndroid Build Coastguard Worker   add $z1, $offset, $fp
1600*795d594fSAndroid Build Coastguard Worker   beq $z0, $J, .Lentry_arg_long_${gpr}
1601*795d594fSAndroid Build Coastguard Worker   sw $gpr, ($z1)
1602*795d594fSAndroid Build Coastguard Worker   bne $z0, $L, .Lentry_arg_finish_${gpr}
1603*795d594fSAndroid Build Coastguard Worker   add $z1, $offset, $refs
1604*795d594fSAndroid Build Coastguard Worker   sw $gpr, ($z1)
1605*795d594fSAndroid Build Coastguard Worker   j .Lentry_arg_finish_${gpr}
1606*795d594fSAndroid Build Coastguard Worker.Lentry_arg_skip_double_${gpr}:
1607*795d594fSAndroid Build Coastguard Worker   addi $offset, $offset, 4
1608*795d594fSAndroid Build Coastguard Worker.Lentry_arg_skip_float_${gpr}:
1609*795d594fSAndroid Build Coastguard Worker   addi $offset, $offset, 4
1610*795d594fSAndroid Build Coastguard Worker   j .Lentry_arg_${gpr}
1611*795d594fSAndroid Build Coastguard Worker.Lentry_arg_long_${gpr}:
1612*795d594fSAndroid Build Coastguard Worker   sd $gpr, ($z1)
1613*795d594fSAndroid Build Coastguard Worker   addi $offset, $offset, 4
1614*795d594fSAndroid Build Coastguard Worker.Lentry_arg_finish_${gpr}:
1615*795d594fSAndroid Build Coastguard Worker   addi $offset, $offset, 4
1616*795d594fSAndroid Build Coastguard Worker
1617*795d594fSAndroid Build Coastguard Worker
1618*795d594fSAndroid Build Coastguard Worker// \fp is used as array base addr, unmodified.
1619*795d594fSAndroid Build Coastguard Worker%def store_fpr_to_vreg(fpr="", offset="", shorty="", fp="", z0="", z1="", D="", F="", J="", next=""):
1620*795d594fSAndroid Build Coastguard Worker.Lentry_farg_${fpr}:
1621*795d594fSAndroid Build Coastguard Worker   lb $z0, ($shorty)         // z0 := shorty type
1622*795d594fSAndroid Build Coastguard Worker   addi $shorty, $shorty, 1  // Increment char ptr.
1623*795d594fSAndroid Build Coastguard Worker   beqz $z0, $next           // z0 = \0: finished shorty pass
1624*795d594fSAndroid Build Coastguard Worker   beq $z0, $D, .Lentry_farg_double_${fpr}
1625*795d594fSAndroid Build Coastguard Worker   beq $z0, $F, .Lentry_farg_float_${fpr}
1626*795d594fSAndroid Build Coastguard Worker   addi $offset, $offset, 4
1627*795d594fSAndroid Build Coastguard Worker   bne $z0, $J, .Lentry_farg_${fpr}
1628*795d594fSAndroid Build Coastguard Worker   addi $offset, $offset, 4
1629*795d594fSAndroid Build Coastguard Worker   j .Lentry_farg_${fpr}
1630*795d594fSAndroid Build Coastguard Worker
1631*795d594fSAndroid Build Coastguard Worker.Lentry_farg_float_${fpr}:
1632*795d594fSAndroid Build Coastguard Worker   add $z1, $offset, $fp
1633*795d594fSAndroid Build Coastguard Worker   fsw $fpr, ($z1)
1634*795d594fSAndroid Build Coastguard Worker   j .Lentry_farg_finish_${fpr}
1635*795d594fSAndroid Build Coastguard Worker.Lentry_farg_double_${fpr}:
1636*795d594fSAndroid Build Coastguard Worker   add $z1, $offset, $fp
1637*795d594fSAndroid Build Coastguard Worker   fsd $fpr, ($z1)
1638*795d594fSAndroid Build Coastguard Worker   addi $offset, $offset, 4
1639*795d594fSAndroid Build Coastguard Worker.Lentry_farg_finish_${fpr}:
1640*795d594fSAndroid Build Coastguard Worker   addi $offset, $offset, 4
1641*795d594fSAndroid Build Coastguard Worker
1642*795d594fSAndroid Build Coastguard Worker
1643*795d594fSAndroid Build Coastguard Worker// \outs, \fp, \refs are used as iterators, modified.
1644*795d594fSAndroid Build Coastguard Worker%def store_outs_to_vregs(outs="", shorty="", fp="", refs="", z0="", z1="", D="", F="", J="", L="", next=""):
1645*795d594fSAndroid Build Coastguard Worker.Lentry_stack:
1646*795d594fSAndroid Build Coastguard Worker   lb $z0, ($shorty)         // z0 := next shorty arg spec
1647*795d594fSAndroid Build Coastguard Worker   addi $shorty, $shorty, 1  // Increment char ptr.
1648*795d594fSAndroid Build Coastguard Worker   beqz $z0, $next           // z0 == \0
1649*795d594fSAndroid Build Coastguard Worker   beq $z0, $F, .Lentry_stack_next_4
1650*795d594fSAndroid Build Coastguard Worker   beq $z0, $D, .Lentry_stack_next_8
1651*795d594fSAndroid Build Coastguard Worker   beq $z0, $J, .Lentry_stack_long
1652*795d594fSAndroid Build Coastguard Worker   // 32-bit arg
1653*795d594fSAndroid Build Coastguard Worker   lwu $z1, ($outs)
1654*795d594fSAndroid Build Coastguard Worker   sw $z1, ($fp)
1655*795d594fSAndroid Build Coastguard Worker   bne $z0, $L, .Lentry_stack_next_4
1656*795d594fSAndroid Build Coastguard Worker   // and also a ref
1657*795d594fSAndroid Build Coastguard Worker   sw $z1, ($refs)
1658*795d594fSAndroid Build Coastguard Worker.Lentry_stack_next_4:
1659*795d594fSAndroid Build Coastguard Worker   addi $outs, $outs, 4
1660*795d594fSAndroid Build Coastguard Worker   addi $fp, $fp, 4
1661*795d594fSAndroid Build Coastguard Worker   addi $refs, $refs, 4
1662*795d594fSAndroid Build Coastguard Worker   j .Lentry_stack
1663*795d594fSAndroid Build Coastguard Worker.Lentry_stack_long:
1664*795d594fSAndroid Build Coastguard Worker   ld $z1, ($outs)
1665*795d594fSAndroid Build Coastguard Worker   sd $z1, ($fp)
1666*795d594fSAndroid Build Coastguard Worker.Lentry_stack_next_8:
1667*795d594fSAndroid Build Coastguard Worker   addi $outs, $outs, 8
1668*795d594fSAndroid Build Coastguard Worker   addi $fp, $fp, 8
1669*795d594fSAndroid Build Coastguard Worker   addi $refs, $refs, 8
1670*795d594fSAndroid Build Coastguard Worker   j .Lentry_stack
1671*795d594fSAndroid Build Coastguard Worker
1672*795d594fSAndroid Build Coastguard Worker
1673*795d594fSAndroid Build Coastguard Worker// \outs, \fp are used as iterators, modified.
1674*795d594fSAndroid Build Coastguard Worker%def store_float_outs_to_vregs(outs="", shorty="", fp="", z0="", D="", F="", J="", next=""):
1675*795d594fSAndroid Build Coastguard Worker.Lentry_fstack:
1676*795d594fSAndroid Build Coastguard Worker   lb $z0, ($shorty)         // z0 := next shorty arg spec
1677*795d594fSAndroid Build Coastguard Worker   addi $shorty, $shorty, 1  // Increment char ptr.
1678*795d594fSAndroid Build Coastguard Worker   beqz $z0, $next           // z0 == \0
1679*795d594fSAndroid Build Coastguard Worker   beq $z0, $F, .Lentry_fstack_float
1680*795d594fSAndroid Build Coastguard Worker   beq $z0, $D, .Lentry_fstack_double
1681*795d594fSAndroid Build Coastguard Worker   beq $z0, $J, .Lentry_fstack_next_8
1682*795d594fSAndroid Build Coastguard Worker   // 32-bit arg
1683*795d594fSAndroid Build Coastguard Worker   addi $outs, $outs, 4
1684*795d594fSAndroid Build Coastguard Worker   addi $fp, $fp, 4
1685*795d594fSAndroid Build Coastguard Worker   j .Lentry_fstack
1686*795d594fSAndroid Build Coastguard Worker.Lentry_fstack_float:
1687*795d594fSAndroid Build Coastguard Worker   lwu $z0, ($outs)
1688*795d594fSAndroid Build Coastguard Worker   sw $z0, ($fp)
1689*795d594fSAndroid Build Coastguard Worker   addi $outs, $outs, 4
1690*795d594fSAndroid Build Coastguard Worker   addi $fp, $fp, 4
1691*795d594fSAndroid Build Coastguard Worker   j .Lentry_fstack
1692*795d594fSAndroid Build Coastguard Worker.Lentry_fstack_double:
1693*795d594fSAndroid Build Coastguard Worker   ld $z0, ($outs)
1694*795d594fSAndroid Build Coastguard Worker   sd $z0, ($fp)
1695*795d594fSAndroid Build Coastguard Worker.Lentry_fstack_next_8:
1696*795d594fSAndroid Build Coastguard Worker   addi $outs, $outs, 8
1697*795d594fSAndroid Build Coastguard Worker   addi $fp, $fp, 8
1698*795d594fSAndroid Build Coastguard Worker   j .Lentry_fstack
1699*795d594fSAndroid Build Coastguard Worker
1700