xref: /aosp_15_r20/art/runtime/interpreter/mterp/armng/control_flow.S (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker%def bincmp(condition=""):
2*795d594fSAndroid Build Coastguard Worker    /*
3*795d594fSAndroid Build Coastguard Worker     * Generic two-operand compare-and-branch operation.  Provide a "condition"
4*795d594fSAndroid Build Coastguard Worker     * fragment that specifies the comparison to perform.
5*795d594fSAndroid Build Coastguard Worker     *
6*795d594fSAndroid Build Coastguard Worker     * For: if-eq, if-ne, if-lt, if-ge, if-gt, if-le
7*795d594fSAndroid Build Coastguard Worker     */
8*795d594fSAndroid Build Coastguard Worker    /* if-cmp vA, vB, +CCCC */
9*795d594fSAndroid Build Coastguard Worker    mov     r1, rINST, lsr #12          @ r1<- B
10*795d594fSAndroid Build Coastguard Worker    ubfx    r0, rINST, #8, #4           @ r0<- A
11*795d594fSAndroid Build Coastguard Worker    GET_VREG r3, r1                     @ r3<- vB
12*795d594fSAndroid Build Coastguard Worker    GET_VREG r0, r0                     @ r0<- vA
13*795d594fSAndroid Build Coastguard Worker    FETCH_S rINST, 1                    @ rINST<- branch offset, in code units
14*795d594fSAndroid Build Coastguard Worker    cmp     r0, r3                      @ compare (vA, vB)
15*795d594fSAndroid Build Coastguard Worker    b${condition} 1f
16*795d594fSAndroid Build Coastguard Worker    FETCH_ADVANCE_INST 2
17*795d594fSAndroid Build Coastguard Worker    GET_INST_OPCODE ip                  // extract opcode from rINST
18*795d594fSAndroid Build Coastguard Worker    GOTO_OPCODE ip                      // jump to next instruction
19*795d594fSAndroid Build Coastguard Worker1:
20*795d594fSAndroid Build Coastguard Worker    FETCH_S rINST, 1                    // rINST<- branch offset, in code units
21*795d594fSAndroid Build Coastguard Worker    BRANCH
22*795d594fSAndroid Build Coastguard Worker
23*795d594fSAndroid Build Coastguard Worker%def zcmp(condition=""):
24*795d594fSAndroid Build Coastguard Worker    /*
25*795d594fSAndroid Build Coastguard Worker     * Generic one-operand compare-and-branch operation.  Provide a "condition"
26*795d594fSAndroid Build Coastguard Worker     * fragment that specifies the comparison to perform.
27*795d594fSAndroid Build Coastguard Worker     *
28*795d594fSAndroid Build Coastguard Worker     * for: if-eqz, if-nez, if-ltz, if-gez, if-gtz, if-lez
29*795d594fSAndroid Build Coastguard Worker     */
30*795d594fSAndroid Build Coastguard Worker    /* if-cmp vAA, +BBBB */
31*795d594fSAndroid Build Coastguard Worker    mov     r0, rINST, lsr #8           @ r0<- AA
32*795d594fSAndroid Build Coastguard Worker    GET_VREG r0, r0                     @ r0<- vAA
33*795d594fSAndroid Build Coastguard Worker    FETCH_S rINST, 1                    @ rINST<- branch offset, in code units
34*795d594fSAndroid Build Coastguard Worker    cmp     r0, #0                      // compare (vA, 0)
35*795d594fSAndroid Build Coastguard Worker    b${condition} 1f
36*795d594fSAndroid Build Coastguard Worker    FETCH_ADVANCE_INST 2
37*795d594fSAndroid Build Coastguard Worker    GET_INST_OPCODE ip                  // extract opcode from rINST
38*795d594fSAndroid Build Coastguard Worker    GOTO_OPCODE ip                      // jump to next instruction
39*795d594fSAndroid Build Coastguard Worker1:
40*795d594fSAndroid Build Coastguard Worker    FETCH_S rINST, 1                    // rINST<- branch offset, in code units
41*795d594fSAndroid Build Coastguard Worker    BRANCH
42*795d594fSAndroid Build Coastguard Worker
43*795d594fSAndroid Build Coastguard Worker%def op_goto():
44*795d594fSAndroid Build Coastguard Worker/*
45*795d594fSAndroid Build Coastguard Worker * Unconditional branch, 8-bit offset.
46*795d594fSAndroid Build Coastguard Worker *
47*795d594fSAndroid Build Coastguard Worker * The branch distance is a signed code-unit offset, which we need to
48*795d594fSAndroid Build Coastguard Worker * double to get a byte offset.
49*795d594fSAndroid Build Coastguard Worker */
50*795d594fSAndroid Build Coastguard Worker    /* goto +AA */
51*795d594fSAndroid Build Coastguard Worker    sbfx    rINST, rINST, #8, #8           // rINST<- ssssssAA (sign-extended)
52*795d594fSAndroid Build Coastguard Worker    BRANCH
53*795d594fSAndroid Build Coastguard Worker
54*795d594fSAndroid Build Coastguard Worker%def op_goto_16():
55*795d594fSAndroid Build Coastguard Worker/*
56*795d594fSAndroid Build Coastguard Worker * Unconditional branch, 16-bit offset.
57*795d594fSAndroid Build Coastguard Worker *
58*795d594fSAndroid Build Coastguard Worker * The branch distance is a signed code-unit offset, which we need to
59*795d594fSAndroid Build Coastguard Worker * double to get a byte offset.
60*795d594fSAndroid Build Coastguard Worker */
61*795d594fSAndroid Build Coastguard Worker    /* goto/16 +AAAA */
62*795d594fSAndroid Build Coastguard Worker    FETCH_S rINST, 1                    // wINST<- ssssAAAA (sign-extended)
63*795d594fSAndroid Build Coastguard Worker    BRANCH
64*795d594fSAndroid Build Coastguard Worker
65*795d594fSAndroid Build Coastguard Worker%def op_goto_32():
66*795d594fSAndroid Build Coastguard Worker/*
67*795d594fSAndroid Build Coastguard Worker * Unconditional branch, 32-bit offset.
68*795d594fSAndroid Build Coastguard Worker *
69*795d594fSAndroid Build Coastguard Worker * The branch distance is a signed code-unit offset, which we need to
70*795d594fSAndroid Build Coastguard Worker * double to get a byte offset.
71*795d594fSAndroid Build Coastguard Worker *
72*795d594fSAndroid Build Coastguard Worker * Because we need the SF bit set, we'll use an adds
73*795d594fSAndroid Build Coastguard Worker * to convert from Dalvik offset to byte offset.
74*795d594fSAndroid Build Coastguard Worker */
75*795d594fSAndroid Build Coastguard Worker    /* goto/32 +AAAAAAAA */
76*795d594fSAndroid Build Coastguard Worker    FETCH r0, 1                         // r0<- aaaa (lo)
77*795d594fSAndroid Build Coastguard Worker    FETCH r1, 2                         // r1<- AAAA (hi)
78*795d594fSAndroid Build Coastguard Worker    orrs     rINST, r0, r1, lsl #16      // wINST<- AAAAaaaa
79*795d594fSAndroid Build Coastguard Worker    BRANCH
80*795d594fSAndroid Build Coastguard Worker
81*795d594fSAndroid Build Coastguard Worker%def op_if_eq():
82*795d594fSAndroid Build Coastguard Worker%  bincmp(condition="eq")
83*795d594fSAndroid Build Coastguard Worker
84*795d594fSAndroid Build Coastguard Worker%def op_if_eqz():
85*795d594fSAndroid Build Coastguard Worker%  zcmp(condition="eq")
86*795d594fSAndroid Build Coastguard Worker
87*795d594fSAndroid Build Coastguard Worker%def op_if_ge():
88*795d594fSAndroid Build Coastguard Worker%  bincmp(condition="ge")
89*795d594fSAndroid Build Coastguard Worker
90*795d594fSAndroid Build Coastguard Worker%def op_if_gez():
91*795d594fSAndroid Build Coastguard Worker%  zcmp(condition="ge")
92*795d594fSAndroid Build Coastguard Worker
93*795d594fSAndroid Build Coastguard Worker%def op_if_gt():
94*795d594fSAndroid Build Coastguard Worker%  bincmp(condition="gt")
95*795d594fSAndroid Build Coastguard Worker
96*795d594fSAndroid Build Coastguard Worker%def op_if_gtz():
97*795d594fSAndroid Build Coastguard Worker%  zcmp(condition="gt")
98*795d594fSAndroid Build Coastguard Worker
99*795d594fSAndroid Build Coastguard Worker%def op_if_le():
100*795d594fSAndroid Build Coastguard Worker%  bincmp(condition="le")
101*795d594fSAndroid Build Coastguard Worker
102*795d594fSAndroid Build Coastguard Worker%def op_if_lez():
103*795d594fSAndroid Build Coastguard Worker%  zcmp(condition="le")
104*795d594fSAndroid Build Coastguard Worker
105*795d594fSAndroid Build Coastguard Worker%def op_if_lt():
106*795d594fSAndroid Build Coastguard Worker%  bincmp(condition="lt")
107*795d594fSAndroid Build Coastguard Worker
108*795d594fSAndroid Build Coastguard Worker%def op_if_ltz():
109*795d594fSAndroid Build Coastguard Worker%  zcmp(condition="lt")
110*795d594fSAndroid Build Coastguard Worker
111*795d594fSAndroid Build Coastguard Worker%def op_if_ne():
112*795d594fSAndroid Build Coastguard Worker%  bincmp(condition="ne")
113*795d594fSAndroid Build Coastguard Worker
114*795d594fSAndroid Build Coastguard Worker%def op_if_nez():
115*795d594fSAndroid Build Coastguard Worker%  zcmp(condition="ne")
116*795d594fSAndroid Build Coastguard Worker
117*795d594fSAndroid Build Coastguard Worker%def op_packed_switch(func="NterpDoPackedSwitch"):
118*795d594fSAndroid Build Coastguard Worker/*
119*795d594fSAndroid Build Coastguard Worker * Handle a packed-switch or sparse-switch instruction.  In both cases
120*795d594fSAndroid Build Coastguard Worker * we decode it and hand it off to a helper function.
121*795d594fSAndroid Build Coastguard Worker *
122*795d594fSAndroid Build Coastguard Worker * We don't really expect backward branches in a switch statement, but
123*795d594fSAndroid Build Coastguard Worker * they're perfectly legal, so we check for them here.
124*795d594fSAndroid Build Coastguard Worker *
125*795d594fSAndroid Build Coastguard Worker * for: packed-switch, sparse-switch
126*795d594fSAndroid Build Coastguard Worker */
127*795d594fSAndroid Build Coastguard Worker    /* op vAA, +BBBB */
128*795d594fSAndroid Build Coastguard Worker    FETCH r0, 1                         @ r0<- bbbb (lo)
129*795d594fSAndroid Build Coastguard Worker    FETCH r1, 2                         @ r1<- BBBB (hi)
130*795d594fSAndroid Build Coastguard Worker    mov     r3, rINST, lsr #8           @ r3<- AA
131*795d594fSAndroid Build Coastguard Worker    orr     r0, r0, r1, lsl #16         @ r0<- BBBBbbbb
132*795d594fSAndroid Build Coastguard Worker    GET_VREG r1, r3                     @ r1<- vAA
133*795d594fSAndroid Build Coastguard Worker    add     r0, rPC, r0, lsl #1         @ r0<- PC + BBBBbbbb*2
134*795d594fSAndroid Build Coastguard Worker    bl      $func                       @ r0<- code-unit branch offset
135*795d594fSAndroid Build Coastguard Worker    mov     rINST, r0
136*795d594fSAndroid Build Coastguard Worker    BRANCH
137*795d594fSAndroid Build Coastguard Worker
138*795d594fSAndroid Build Coastguard Worker%def op_sparse_switch():
139*795d594fSAndroid Build Coastguard Worker%  op_packed_switch(func="NterpDoSparseSwitch")
140*795d594fSAndroid Build Coastguard Worker
141*795d594fSAndroid Build Coastguard Worker/*
142*795d594fSAndroid Build Coastguard Worker * Return a 32-bit value.
143*795d594fSAndroid Build Coastguard Worker */
144*795d594fSAndroid Build Coastguard Worker%def op_return(is_object="0", is_void="0", is_wide="0"):
145*795d594fSAndroid Build Coastguard Worker    .if $is_void
146*795d594fSAndroid Build Coastguard Worker      // Thread fence for constructor
147*795d594fSAndroid Build Coastguard Worker      dmb ishst
148*795d594fSAndroid Build Coastguard Worker    .else
149*795d594fSAndroid Build Coastguard Worker      mov     r2, rINST, lsr #8           @ r2<- AA
150*795d594fSAndroid Build Coastguard Worker      .if $is_wide
151*795d594fSAndroid Build Coastguard Worker        VREG_INDEX_TO_ADDR r2, r2
152*795d594fSAndroid Build Coastguard Worker        GET_VREG_WIDE_BY_ADDR r0, r1, r2 // r0,r1 <- vAA
153*795d594fSAndroid Build Coastguard Worker        // In case we're going back to compiled code, put the
154*795d594fSAndroid Build Coastguard Worker        // result also in d0.
155*795d594fSAndroid Build Coastguard Worker        vmov d0, r0, r1
156*795d594fSAndroid Build Coastguard Worker      .else
157*795d594fSAndroid Build Coastguard Worker        GET_VREG r0, r2                     // r0<- vAA
158*795d594fSAndroid Build Coastguard Worker        .if !$is_object
159*795d594fSAndroid Build Coastguard Worker        // In case we're going back to compiled code, put the
160*795d594fSAndroid Build Coastguard Worker        // result also in s0.
161*795d594fSAndroid Build Coastguard Worker        vmov s0, r0
162*795d594fSAndroid Build Coastguard Worker        .endif
163*795d594fSAndroid Build Coastguard Worker      .endif
164*795d594fSAndroid Build Coastguard Worker    .endif
165*795d594fSAndroid Build Coastguard Worker    .cfi_remember_state
166*795d594fSAndroid Build Coastguard Worker    ldr ip, [rREFS, #-4]
167*795d594fSAndroid Build Coastguard Worker    mov sp, ip
168*795d594fSAndroid Build Coastguard Worker    .cfi_def_cfa sp, CALLEE_SAVES_SIZE
169*795d594fSAndroid Build Coastguard Worker    RESTORE_ALL_CALLEE_SAVES lr_to_pc=1
170*795d594fSAndroid Build Coastguard Worker    .cfi_restore_state
171*795d594fSAndroid Build Coastguard Worker    CFI_DEF_CFA_BREG_PLUS_UCONST CFI_REFS, -4, CALLEE_SAVES_SIZE
172*795d594fSAndroid Build Coastguard Worker
173*795d594fSAndroid Build Coastguard Worker%def op_return_object():
174*795d594fSAndroid Build Coastguard Worker%  op_return(is_object="1", is_void="0", is_wide="0")
175*795d594fSAndroid Build Coastguard Worker
176*795d594fSAndroid Build Coastguard Worker%def op_return_void():
177*795d594fSAndroid Build Coastguard Worker%  op_return(is_object="0", is_void="1", is_wide="0")
178*795d594fSAndroid Build Coastguard Worker
179*795d594fSAndroid Build Coastguard Worker%def op_return_wide():
180*795d594fSAndroid Build Coastguard Worker%  op_return(is_object="0", is_void="0", is_wide="1")
181*795d594fSAndroid Build Coastguard Worker
182*795d594fSAndroid Build Coastguard Worker%def op_throw():
183*795d594fSAndroid Build Coastguard Worker  EXPORT_PC
184*795d594fSAndroid Build Coastguard Worker  mov      r2, rINST, lsr #8           @ r2<- AA
185*795d594fSAndroid Build Coastguard Worker  GET_VREG r0, r2                      @ r0<- vAA (exception object)
186*795d594fSAndroid Build Coastguard Worker  mov r1, rSELF
187*795d594fSAndroid Build Coastguard Worker  bl art_quick_deliver_exception
188*795d594fSAndroid Build Coastguard Worker  bkpt 0
189