File: arithmetic.S

package info (click to toggle)
android-platform-art 10.0.0%2Br36-3
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 78,308 kB
  • sloc: cpp: 488,455; java: 151,268; asm: 29,126; python: 9,122; sh: 5,840; ansic: 4,161; xml: 2,846; perl: 77; makefile: 57
file content (458 lines) | stat: -rw-r--r-- 16,209 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
%def binop(preinstr="", result="a0", chkzero="0", instr=""):
    /*
     * Generic 32-bit binary operation.  Provide an "instr" line that
     * specifies an instruction that performs "result = a0 op a1".
     * This could be a MIPS instruction or a function call.  (If the result
     * comes back in a register other than a0, you can override "result".)
     *
     * If "chkzero" is set to 1, we perform a divide-by-zero check on
     * vCC (a1).  Useful for integer division and modulus.  Note that we
     * *don't* check for (INT_MIN / -1) here, because the CPU handles it
     * correctly.
     *
     * For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
     *      xor-int, shl-int, shr-int, ushr-int
     */
    /* binop vAA, vBB, vCC */
    srl     a4, rINST, 8                # a4 <- AA
    lbu     a2, 2(rPC)                  # a2 <- BB
    lbu     a3, 3(rPC)                  # a3 <- CC
    GET_VREG a0, a2                     # a0 <- vBB
    GET_VREG a1, a3                     # a1 <- vCC
    .if $chkzero
    beqz    a1, common_errDivideByZero  # is second operand zero?
    .endif
    FETCH_ADVANCE_INST 2                # advance rPC, load rINST
    $preinstr                           # optional op
    $instr                              # $result <- op, a0-a3 changed
    GET_INST_OPCODE v0                  # extract opcode from rINST
    SET_VREG $result, a4                # vAA <- $result
    GOTO_OPCODE v0                      # jump to next instruction

%def binop2addr(preinstr="", result="a0", chkzero="0", instr=""):
    /*
     * Generic 32-bit "/2addr" binary operation.  Provide an "instr" line
     * that specifies an instruction that performs "result = a0 op a1".
     * This could be a MIPS instruction or a function call.  (If the result
     * comes back in a register other than a0, you can override "result".)
     *
     * If "chkzero" is set to 1, we perform a divide-by-zero check on
     * vB (a1).  Useful for integer division and modulus.  Note that we
     * *don't* check for (INT_MIN / -1) here, because the CPU handles it
     * correctly.
     *
     * For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
     *      rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
     *      shl-int/2addr, shr-int/2addr, ushr-int/2addr
     */
    /* binop/2addr vA, vB */
    ext     a2, rINST, 8, 4             # a2 <- A
    ext     a3, rINST, 12, 4            # a3 <- B
    GET_VREG a0, a2                     # a0 <- vA
    GET_VREG a1, a3                     # a1 <- vB
    .if $chkzero
    beqz    a1, common_errDivideByZero  # is second operand zero?
    .endif
    FETCH_ADVANCE_INST 1                # advance rPC, load rINST
    $preinstr                           # optional op
    $instr                              # $result <- op, a0-a3 changed
    GET_INST_OPCODE v0                  # extract opcode from rINST
    SET_VREG $result, a2                # vA <- $result
    GOTO_OPCODE v0                      # jump to next instruction

%def binopLit16(preinstr="", result="a0", chkzero="0", instr=""):
    /*
     * Generic 32-bit "lit16" binary operation.  Provide an "instr" line
     * that specifies an instruction that performs "result = a0 op a1".
     * This could be an MIPS instruction or a function call.  (If the result
     * comes back in a register other than a0, you can override "result".)
     *
     * If "chkzero" is set to 1, we perform a divide-by-zero check on
     * CCCC (a1).  Useful for integer division and modulus.
     *
     * For: add-int/lit16, rsub-int, mul-int/lit16, div-int/lit16,
     *      rem-int/lit16, and-int/lit16, or-int/lit16, xor-int/lit16
     */
    /* binop/lit16 vA, vB, #+CCCC */
    lh      a1, 2(rPC)                  # a1 <- sign-extended CCCC
    ext     a2, rINST, 8, 4             # a2 <- A
    ext     a3, rINST, 12, 4            # a3 <- B
    GET_VREG a0, a3                     # a0 <- vB
    .if $chkzero
    beqz    a1, common_errDivideByZero  # is second operand zero?
    .endif
    FETCH_ADVANCE_INST 2                # advance rPC, load rINST
    $preinstr                           # optional op
    $instr                              # $result <- op, a0-a3 changed
    GET_INST_OPCODE v0                  # extract opcode from rINST
    SET_VREG $result, a2                # vA <- $result
    GOTO_OPCODE v0                      # jump to next instruction


%def binopLit8(preinstr="", result="a0", chkzero="0", instr=""):
    /*
     * Generic 32-bit "lit8" binary operation.  Provide an "instr" line
     * that specifies an instruction that performs "result = a0 op a1".
     * This could be an MIPS instruction or a function call.  (If the result
     * comes back in a register other than a0, you can override "result".)
     *
     * If "chkzero" is set to 1, we perform a divide-by-zero check on
     * CC (a1).  Useful for integer division and modulus.
     *
     * For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
     *      rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
     *      shl-int/lit8, shr-int/lit8, ushr-int/lit8
     */
    /* binop/lit8 vAA, vBB, #+CC */
    lbu     a3, 2(rPC)                  # a3 <- BB
    lb      a1, 3(rPC)                  # a1 <- sign-extended CC
    srl     a2, rINST, 8                # a2 <- AA
    GET_VREG a0, a3                     # a0 <- vBB
    .if $chkzero
    beqz    a1, common_errDivideByZero  # is second operand zero?
    .endif
    FETCH_ADVANCE_INST 2                # advance rPC, load rINST
    $preinstr                           # optional op
    $instr                              # $result <- op, a0-a3 changed
    GET_INST_OPCODE v0                  # extract opcode from rINST
    SET_VREG $result, a2                # vAA <- $result
    GOTO_OPCODE v0                      # jump to next instruction


%def binopWide(preinstr="", result="a0", chkzero="0", instr=""):
    /*
     * Generic 64-bit binary operation.  Provide an "instr" line that
     * specifies an instruction that performs "result = a0 op a1".
     * This could be a MIPS instruction or a function call.  (If the result
     * comes back in a register other than a0, you can override "result".)
     *
     * If "chkzero" is set to 1, we perform a divide-by-zero check on
     * vCC (a1).  Useful for integer division and modulus.  Note that we
     * *don't* check for (LONG_MIN / -1) here, because the CPU handles it
     * correctly.
     *
     * For: add-long, sub-long, mul-long, div-long, rem-long, and-long, or-long,
     *      xor-long, shl-long, shr-long, ushr-long
     */
    /* binop vAA, vBB, vCC */
    srl     a4, rINST, 8                # a4 <- AA
    lbu     a2, 2(rPC)                  # a2 <- BB
    lbu     a3, 3(rPC)                  # a3 <- CC
    GET_VREG_WIDE a0, a2                # a0 <- vBB
    GET_VREG_WIDE a1, a3                # a1 <- vCC
    .if $chkzero
    beqz    a1, common_errDivideByZero  # is second operand zero?
    .endif
    FETCH_ADVANCE_INST 2                # advance rPC, load rINST
    $preinstr                           # optional op
    $instr                              # $result <- op, a0-a3 changed
    GET_INST_OPCODE v0                  # extract opcode from rINST
    SET_VREG_WIDE $result, a4           # vAA <- $result
    GOTO_OPCODE v0                      # jump to next instruction

%def binopWide2addr(preinstr="", result="a0", chkzero="0", instr=""):
    /*
     * Generic 64-bit "/2addr" binary operation.  Provide an "instr" line
     * that specifies an instruction that performs "result = a0 op a1".
     * This could be a MIPS instruction or a function call.  (If the result
     * comes back in a register other than a0, you can override "result".)
     *
     * If "chkzero" is set to 1, we perform a divide-by-zero check on
     * vB (a1).  Useful for integer division and modulus.  Note that we
     * *don't* check for (LONG_MIN / -1) here, because the CPU handles it
     * correctly.
     *
     * For: add-long/2addr, sub-long/2addr, mul-long/2addr, div-long/2addr,
     *      rem-long/2addr, and-long/2addr, or-long/2addr, xor-long/2addr,
     *      shl-long/2addr, shr-long/2addr, ushr-long/2addr
     */
    /* binop/2addr vA, vB */
    ext     a2, rINST, 8, 4             # a2 <- A
    ext     a3, rINST, 12, 4            # a3 <- B
    GET_VREG_WIDE a0, a2                # a0 <- vA
    GET_VREG_WIDE a1, a3                # a1 <- vB
    .if $chkzero
    beqz    a1, common_errDivideByZero  # is second operand zero?
    .endif
    FETCH_ADVANCE_INST 1                # advance rPC, load rINST
    $preinstr                           # optional op
    $instr                              # $result <- op, a0-a3 changed
    GET_INST_OPCODE v0                  # extract opcode from rINST
    SET_VREG_WIDE $result, a2           # vA <- $result
    GOTO_OPCODE v0                      # jump to next instruction

%def unop(preinstr="", instr=""):
    /*
     * Generic 32-bit unary operation.  Provide an "instr" line that
     * specifies an instruction that performs "a0 = op a0".
     *
     * for: int-to-byte, int-to-char, int-to-short,
     *      not-int, neg-int
     */
    /* unop vA, vB */
    ext     a3, rINST, 12, 4            # a3 <- B
    GET_VREG a0, a3                     # a0 <- vB
    ext     a2, rINST, 8, 4             # a2 <- A
    $preinstr                           # optional op
    FETCH_ADVANCE_INST 1                # advance rPC, load rINST
    $instr                              # a0 <- op, a0-a3 changed
    GET_INST_OPCODE v0                  # extract opcode from rINST
    SET_VREG a0, a2                     # vA <- a0
    GOTO_OPCODE v0                      # jump to next instruction

%def unopWide(preinstr="", instr=""):
    /*
     * Generic 64-bit unary operation.  Provide an "instr" line that
     * specifies an instruction that performs "a0 = op a0".
     *
     * For: not-long, neg-long
     */
    /* unop vA, vB */
    ext     a3, rINST, 12, 4            # a3 <- B
    GET_VREG_WIDE a0, a3                # a0 <- vB
    ext     a2, rINST, 8, 4             # a2 <- A
    $preinstr                           # optional op
    FETCH_ADVANCE_INST 1                # advance rPC, load rINST
    $instr                              # a0 <- op, a0-a3 changed
    GET_INST_OPCODE v0                  # extract opcode from rINST
    SET_VREG_WIDE a0, a2                # vA <- a0
    GOTO_OPCODE v0                      # jump to next instruction

%def op_add_int():
%  binop(instr="addu a0, a0, a1")

%def op_add_int_2addr():
%  binop2addr(instr="addu a0, a0, a1")

%def op_add_int_lit16():
%  binopLit16(instr="addu a0, a0, a1")

%def op_add_int_lit8():
%  binopLit8(instr="addu a0, a0, a1")

%def op_add_long():
%  binopWide(instr="daddu a0, a0, a1")

%def op_add_long_2addr():
%  binopWide2addr(instr="daddu a0, a0, a1")

%def op_and_int():
%  binop(instr="and a0, a0, a1")

%def op_and_int_2addr():
%  binop2addr(instr="and a0, a0, a1")

%def op_and_int_lit16():
%  binopLit16(instr="and a0, a0, a1")

%def op_and_int_lit8():
%  binopLit8(instr="and a0, a0, a1")

%def op_and_long():
%  binopWide(instr="and a0, a0, a1")

%def op_and_long_2addr():
%  binopWide2addr(instr="and a0, a0, a1")

%def op_cmp_long():
    /* cmp-long vAA, vBB, vCC */
    lbu     a2, 2(rPC)                  # a2 <- BB
    lbu     a3, 3(rPC)                  # a3 <- CC
    srl     a4, rINST, 8                # a4 <- AA
    GET_VREG_WIDE a0, a2                # a0 <- vBB
    GET_VREG_WIDE a1, a3                # a1 <- vCC
    FETCH_ADVANCE_INST 2                # advance rPC, load rINST
    slt     a2, a0, a1
    slt     a0, a1, a0
    subu    a0, a0, a2
    GET_INST_OPCODE v0                  # extract opcode from rINST
    SET_VREG a0, a4                     # vAA <- result
    GOTO_OPCODE v0                      # jump to next instruction

%def op_div_int():
%  binop(instr="div a0, a0, a1", chkzero="1")

%def op_div_int_2addr():
%  binop2addr(instr="div a0, a0, a1", chkzero="1")

%def op_div_int_lit16():
%  binopLit16(instr="div a0, a0, a1", chkzero="1")

%def op_div_int_lit8():
%  binopLit8(instr="div a0, a0, a1", chkzero="1")

%def op_div_long():
%  binopWide(instr="ddiv a0, a0, a1", chkzero="1")

%def op_div_long_2addr():
%  binopWide2addr(instr="ddiv a0, a0, a1", chkzero="1")

%def op_int_to_byte():
%  unop(instr="seb     a0, a0")

%def op_int_to_char():
%  unop(instr="and     a0, a0, 0xffff")

%def op_int_to_long():
    /* int-to-long vA, vB */
    ext     a3, rINST, 12, 4            # a3 <- B
    GET_VREG a0, a3                     # a0 <- vB (sign-extended to 64 bits)
    ext     a2, rINST, 8, 4             # a2 <- A
    FETCH_ADVANCE_INST 1                # advance rPC, load rINST
    GET_INST_OPCODE v0                  # extract opcode from rINST
    SET_VREG_WIDE a0, a2                # vA <- vB
    GOTO_OPCODE v0                      # jump to next instruction

%def op_int_to_short():
%  unop(instr="seh     a0, a0")

%def op_long_to_int():
/* we ignore the high word, making this equivalent to a 32-bit reg move */
%  op_move()

%def op_mul_int():
%  binop(instr="mul a0, a0, a1")

%def op_mul_int_2addr():
%  binop2addr(instr="mul a0, a0, a1")

%def op_mul_int_lit16():
%  binopLit16(instr="mul a0, a0, a1")

%def op_mul_int_lit8():
%  binopLit8(instr="mul a0, a0, a1")

%def op_mul_long():
%  binopWide(instr="dmul a0, a0, a1")

%def op_mul_long_2addr():
%  binopWide2addr(instr="dmul a0, a0, a1")

%def op_neg_int():
%  unop(instr="subu    a0, zero, a0")

%def op_neg_long():
%  unopWide(instr="dsubu   a0, zero, a0")

%def op_not_int():
%  unop(instr="nor     a0, zero, a0")

%def op_not_long():
%  unopWide(instr="nor     a0, zero, a0")

%def op_or_int():
%  binop(instr="or a0, a0, a1")

%def op_or_int_2addr():
%  binop2addr(instr="or a0, a0, a1")

%def op_or_int_lit16():
%  binopLit16(instr="or a0, a0, a1")

%def op_or_int_lit8():
%  binopLit8(instr="or a0, a0, a1")

%def op_or_long():
%  binopWide(instr="or a0, a0, a1")

%def op_or_long_2addr():
%  binopWide2addr(instr="or a0, a0, a1")

%def op_rem_int():
%  binop(instr="mod a0, a0, a1", chkzero="1")

%def op_rem_int_2addr():
%  binop2addr(instr="mod a0, a0, a1", chkzero="1")

%def op_rem_int_lit16():
%  binopLit16(instr="mod a0, a0, a1", chkzero="1")

%def op_rem_int_lit8():
%  binopLit8(instr="mod a0, a0, a1", chkzero="1")

%def op_rem_long():
%  binopWide(instr="dmod a0, a0, a1", chkzero="1")

%def op_rem_long_2addr():
%  binopWide2addr(instr="dmod a0, a0, a1", chkzero="1")

%def op_rsub_int():
%  binopLit16(instr="subu a0, a1, a0")

%def op_rsub_int_lit8():
%  binopLit8(instr="subu a0, a1, a0")

%def op_shl_int():
%  binop(instr="sll a0, a0, a1")

%def op_shl_int_2addr():
%  binop2addr(instr="sll a0, a0, a1")

%def op_shl_int_lit8():
%  binopLit8(instr="sll a0, a0, a1")

%def op_shl_long():
%  binopWide(instr="dsll a0, a0, a1")

%def op_shl_long_2addr():
%  binopWide2addr(instr="dsll a0, a0, a1")

%def op_shr_int():
%  binop(instr="sra a0, a0, a1")

%def op_shr_int_2addr():
%  binop2addr(instr="sra a0, a0, a1")

%def op_shr_int_lit8():
%  binopLit8(instr="sra a0, a0, a1")

%def op_shr_long():
%  binopWide(instr="dsra a0, a0, a1")

%def op_shr_long_2addr():
%  binopWide2addr(instr="dsra a0, a0, a1")

%def op_sub_int():
%  binop(instr="subu a0, a0, a1")

%def op_sub_int_2addr():
%  binop2addr(instr="subu a0, a0, a1")

%def op_sub_long():
%  binopWide(instr="dsubu a0, a0, a1")

%def op_sub_long_2addr():
%  binopWide2addr(instr="dsubu a0, a0, a1")

%def op_ushr_int():
%  binop(instr="srl a0, a0, a1")

%def op_ushr_int_2addr():
%  binop2addr(instr="srl a0, a0, a1")

%def op_ushr_int_lit8():
%  binopLit8(instr="srl a0, a0, a1")

%def op_ushr_long():
%  binopWide(instr="dsrl a0, a0, a1")

%def op_ushr_long_2addr():
%  binopWide2addr(instr="dsrl a0, a0, a1")

%def op_xor_int():
%  binop(instr="xor a0, a0, a1")

%def op_xor_int_2addr():
%  binop2addr(instr="xor a0, a0, a1")

%def op_xor_int_lit16():
%  binopLit16(instr="xor a0, a0, a1")

%def op_xor_int_lit8():
%  binopLit8(instr="xor a0, a0, a1")

%def op_xor_long():
%  binopWide(instr="xor a0, a0, a1")

%def op_xor_long_2addr():
%  binopWide2addr(instr="xor a0, a0, a1")