1/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/**
18 * Test arithmetic operations.
19 */
20public class IntMath {
21
22    static void shiftTest1() {
23        System.out.println("IntMath.shiftTest1");
24
25        final int[] mBytes = {
26            0x11, 0x22, 0x33, 0x44, 0x88, 0x99, 0xaa, 0xbb
27        };
28        long l;
29        int i1, i2;
30
31        i1 = mBytes[0] | mBytes[1] << 8 | mBytes[2] << 16 | mBytes[3] << 24;
32        i2 = mBytes[4] | mBytes[5] << 8 | mBytes[6] << 16 | mBytes[7] << 24;
33        l = i1 | ((long)i2 << 32);
34
35        Main.assertTrue(i1 == 0x44332211);
36        Main.assertTrue(i2 == 0xbbaa9988);
37        Main.assertTrue(l == 0xbbaa998844332211L);
38
39        l = (long)mBytes[0]
40            | (long)mBytes[1] << 8
41            | (long)mBytes[2] << 16
42            | (long)mBytes[3] << 24
43            | (long)mBytes[4] << 32
44            | (long)mBytes[5] << 40
45            | (long)mBytes[6] << 48
46            | (long)mBytes[7] << 56;
47
48        Main.assertTrue(l == 0xbbaa998844332211L);
49    }
50
51    static void shiftTest2() {
52        System.out.println("IntMath.shiftTest2");
53
54        long    a = 0x11;
55        long    b = 0x22;
56        long    c = 0x33;
57        long    d = 0x44;
58        long    e = 0x55;
59        long    f = 0x66;
60        long    g = 0x77;
61        long    h = 0x88;
62
63        long    result = ((a << 56) | (b << 48) | (c << 40) | (d << 32) |
64                         (e << 24) | (f << 16) | (g <<  8) | h);
65
66        Main.assertTrue(result == 0x1122334455667788L);
67    }
68
69    static void unsignedShiftTest() {
70        System.out.println("IntMath.unsignedShiftTest");
71
72        byte b = -4;
73        short s = -4;
74        char c = 0xfffc;
75        int i = -4;
76
77        b >>>= 4;
78        s >>>= 4;
79        c >>>= 4;
80        i >>>= 4;
81
82        Main.assertTrue((int) b == -1);
83        Main.assertTrue((int) s == -1);
84        Main.assertTrue((int) c == 0x0fff);
85        Main.assertTrue(i == 268435455);
86    }
87
88    static void shiftTest3(int thirtyTwo) {
89        System.out.println("IntMath.shiftTest3");
90
91        int one = thirtyTwo / 32;
92        int sixteen = thirtyTwo / 2;
93        int thirtyThree = thirtyTwo + 1;
94        int sixtyFour = thirtyTwo * 2;
95
96        Main.assertTrue(1 << thirtyTwo == 1);
97        Main.assertTrue((1 << sixteen) << sixteen == 0);
98        Main.assertTrue(1 << thirtyThree == 2);
99        Main.assertTrue(1 << -one == -2147483648);
100        Main.assertTrue(1 << -thirtyTwo == 1);
101        Main.assertTrue(1 << -thirtyThree == -2147483648);
102        Main.assertTrue(1 << thirtyThree == 2);
103
104        Main.assertTrue(1 >> thirtyTwo == 1);
105        Main.assertTrue((1 >> sixteen) >> sixteen == 0);
106        Main.assertTrue(1 >> thirtyThree == 0);
107        Main.assertTrue(1 >> -one == 0);
108        Main.assertTrue(1 >> -thirtyTwo == 1);
109        Main.assertTrue(1 >> -thirtyThree == 0);
110        Main.assertTrue(-4 >> thirtyThree == -2);
111
112        Main.assertTrue(1 >>> thirtyTwo == 1);
113        Main.assertTrue((1 >>> sixteen) >>> sixteen == 0);
114        Main.assertTrue(1 >>> thirtyThree == 0);
115        Main.assertTrue(1 >>> -one == 0);
116        Main.assertTrue(1 >>> -thirtyTwo == 1);
117        Main.assertTrue(1 >>> -thirtyThree == 0);
118        Main.assertTrue(-4 >>> thirtyThree == 2147483646);
119    }
120
121    static void convTest() {
122        System.out.println("IntMath.convTest");
123
124        float f;
125        double d;
126        int i;
127        long l;
128
129        /* int --> long */
130        i = 7654;
131        l = (long) i;
132        Main.assertTrue(l == 7654L);
133
134        i = -7654;
135        l = (long) i;
136        Main.assertTrue(l == -7654L);
137
138        /* long --> int (with truncation) */
139        l = 5678956789L;
140        i = (int) l;
141        Main.assertTrue(i == 1383989493);
142
143        l = -5678956789L;
144        i = (int) l;
145        Main.assertTrue(i == -1383989493);
146    }
147
148    static void charSubTest() {
149        System.out.println("IntMath.charSubTest");
150
151        char char1 = 0x00e9;
152        char char2 = 0xffff;
153        int i;
154
155        /* chars are unsigned-expanded to ints before subtraction */
156        i = char1 - char2;
157        Main.assertTrue(i == 0xffff00ea);
158    }
159
160    /*
161     * We pass in the arguments and return the results so the compiler
162     * doesn't do the math for us.  (x=70000, y=-3)
163     */
164    static int[] intOperTest(int x, int y) {
165        System.out.println("IntMath.intOperTest");
166
167        int[] results = new int[10];
168
169        /* this seems to generate "op-int" instructions */
170        results[0] = x + y;
171        results[1] = x - y;
172        results[2] = x * y;
173        results[3] = x * x;
174        results[4] = x / y;
175        results[5] = x % -y;
176        results[6] = x & y;
177        results[7] = x | y;
178        results[8] = x ^ y;
179
180        /* this seems to generate "op-int/2addr" instructions */
181        results[9] = x + ((((((((x + y) - y) * y) / y) % y) & y) | y) ^ y);
182
183        return results;
184    }
185    static void intOperCheck(int[] results) {
186        System.out.println("IntMath.intOperCheck");
187
188        /* check this edge case while we're here (div-int/2addr) */
189        int minInt = -2147483648;
190        int negOne = -results[5];
191        int plusOne = 1;
192        int result = (((minInt + plusOne) - plusOne) / negOne) / negOne;
193        Main.assertTrue(result == minInt);
194
195        Main.assertTrue(results[0] == 69997);
196        Main.assertTrue(results[1] == 70003);
197        Main.assertTrue(results[2] == -210000);
198        Main.assertTrue(results[3] == 605032704);    // overflow / truncate
199        Main.assertTrue(results[4] == -23333);
200        Main.assertTrue(results[5] == 1);
201        Main.assertTrue(results[6] == 70000);
202        Main.assertTrue(results[7] == -3);
203        Main.assertTrue(results[8] == -70003);
204        Main.assertTrue(results[9] == 70000);
205    }
206
207    /*
208     * More operations, this time with 16-bit constants.  (x=77777)
209     */
210    static int[] lit16Test(int x) {
211        System.out.println("IntMath.lit16Test");
212
213        int[] results = new int[8];
214
215        /* try to generate op-int/lit16" instructions */
216        results[0] = x + 1000;
217        results[1] = 1000 - x;
218        results[2] = x * 1000;
219        results[3] = x / 1000;
220        results[4] = x % 1000;
221        results[5] = x & 1000;
222        results[6] = x | -1000;
223        results[7] = x ^ -1000;
224        return results;
225    }
226    static void lit16Check(int[] results) {
227        Main.assertTrue(results[0] == 78777);
228        Main.assertTrue(results[1] == -76777);
229        Main.assertTrue(results[2] == 77777000);
230        Main.assertTrue(results[3] == 77);
231        Main.assertTrue(results[4] == 777);
232        Main.assertTrue(results[5] == 960);
233        Main.assertTrue(results[6] == -39);
234        Main.assertTrue(results[7] == -76855);
235    }
236
237    /*
238     * More operations, this time with 8-bit constants.  (x=-55555)
239     */
240    static int[] lit8Test(int x) {
241        System.out.println("IntMath.lit8Test");
242
243        int[] results = new int[8];
244
245        /* try to generate op-int/lit8" instructions */
246        results[0] = x + 10;
247        results[1] = 10 - x;
248        results[2] = x * 10;
249        results[3] = x / 10;
250        results[4] = x % 10;
251        results[5] = x & 10;
252        results[6] = x | -10;
253        results[7] = x ^ -10;
254        return results;
255    }
256    static void lit8Check(int[] results) {
257        //for (int i = 0; i < results.length; i++)
258        //    System.out.println(" " + i + ": " + results[i]);
259
260        /* check this edge case while we're here (div-int/lit8) */
261        int minInt = -2147483648;
262        int result = minInt / -1;
263        Main.assertTrue(result == minInt);
264
265        Main.assertTrue(results[0] == -55545);
266        Main.assertTrue(results[1] == 55565);
267        Main.assertTrue(results[2] == -555550);
268        Main.assertTrue(results[3] == -5555);
269        Main.assertTrue(results[4] == -5);
270        Main.assertTrue(results[5] == 8);
271        Main.assertTrue(results[6] == -1);
272        Main.assertTrue(results[7] == 55563);
273    }
274
275    /*
276     * Make sure special-cased literal division matches
277     * normal division.
278     */
279    static void divLiteralTestBody(int start, int count) {
280       int normal = 0;
281       int special = 0;
282       for (int i = 0; i < count; i++) {
283           for (int j = 3; j < 16; j++) {
284               switch(j) {
285                   case 3:
286                       normal = (start+i) / j;
287                       special = (start+i) / 3;
288                       break;
289                   case 4:
290                       normal = (start+i) / j;
291                       special = (start+i) / 4;
292                       break;
293                   case 5:
294                       normal = (start+i) / j;
295                       special = (start+i) / 5;
296                       break;
297                   case 6:
298                       normal = (start+i) / j;
299                       special = (start+i) / 6;
300                       break;
301                   case 7:
302                       normal = (start+i) / j;
303                       special = (start+i) / 7;
304                       break;
305                   case 8:
306                       normal = (start+i) / j;
307                       special = (start+i) / 8;
308                       break;
309                   case 9:
310                       normal = (start+i) / j;
311                       special = (start+i) / 9;
312                       break;
313                   case 10:
314                       normal = (start+i) / j;
315                       special = (start+i) / 10;
316                       break;
317                   case 11:
318                       normal = (start+i) / j;
319                       special = (start+i) / 11;
320                       break;
321                   case 12:
322                       normal = (start+i) / j;
323                       special = (start+i) / 12;
324                       break;
325                   case 13:
326                       normal = (start+i) / j;
327                       special = (start+i) / 13;
328                       break;
329                   case 14:
330                       normal = (start+i) / j;
331                       special = (start+i) / 14;
332                       break;
333                   case 15:
334                       normal = (start+i) / j;
335                       special = (start+i) / 15;
336                       break;
337               }
338               Main.assertTrue(normal == special);
339           }
340       }
341    }
342
343    static void divLiteralTest() {
344       System.out.println("IntMath.divLiteralTest");
345       divLiteralTestBody(-1000, 2000);
346       divLiteralTestBody(0x7fffffff-2000, 2000);
347       divLiteralTestBody(0xfff0ffff, 2000);
348    }
349
350    /*
351     * Shift some data.  (value=0xff00aa01, dist=8)
352     */
353    static int[] intShiftTest(int value, int dist) {
354        System.out.println("IntMath.intShiftTest");
355
356        int results[] = new int[4];
357
358        results[0] = value << dist;
359        results[1] = value >> dist;
360        results[2] = value >>> dist;
361
362        results[3] = (((value << dist) >> dist) >>> dist) << dist;
363        return results;
364    }
365    static void intShiftCheck(int[] results) {
366        System.out.println("IntMath.intShiftCheck");
367
368        Main.assertTrue(results[0] == 0x00aa0100);
369        Main.assertTrue(results[1] == 0xffff00aa);
370        Main.assertTrue(results[2] == 0x00ff00aa);
371        Main.assertTrue(results[3] == 0xaa00);
372    }
373
374    /*
375     * We pass in the arguments and return the results so the compiler
376     * doesn't do the math for us.  (x=70000000000, y=-3)
377     */
378    static long[] longOperTest(long x, long y) {
379        System.out.println("IntMath.longOperTest");
380
381        long[] results = new long[10];
382
383        /* this seems to generate "op-long" instructions */
384        results[0] = x + y;
385        results[1] = x - y;
386        results[2] = x * y;
387        results[3] = x * x;
388        results[4] = x / y;
389        results[5] = x % -y;
390        results[6] = x & y;
391        results[7] = x | y;
392        results[8] = x ^ y;
393
394        /* this seems to generate "op-long/2addr" instructions */
395        results[9] = x + ((((((((x + y) - y) * y) / y) % y) & y) | y) ^ y);
396
397        return results;
398    }
399    static void longOperCheck(long[] results) {
400        System.out.println("IntMath.longOperCheck");
401
402        /* check this edge case while we're here (div-long/2addr) */
403        long minLong = -9223372036854775808L;
404        long negOne = -results[5];
405        long plusOne = 1;
406        long result = (((minLong + plusOne) - plusOne) / negOne) / negOne;
407        Main.assertTrue(result == minLong);
408
409        Main.assertTrue(results[0] == 69999999997L);
410        Main.assertTrue(results[1] == 70000000003L);
411        Main.assertTrue(results[2] == -210000000000L);
412        Main.assertTrue(results[3] == -6833923606740729856L);    // overflow
413        Main.assertTrue(results[4] == -23333333333L);
414        Main.assertTrue(results[5] == 1);
415        Main.assertTrue(results[6] == 70000000000L);
416        Main.assertTrue(results[7] == -3);
417        Main.assertTrue(results[8] == -70000000003L);
418        Main.assertTrue(results[9] == 70000000000L);
419
420        Main.assertTrue(results.length == 10);
421    }
422
423    /*
424     * Shift some data.  (value=0xd5aa96deff00aa01, dist=8)
425     */
426    static long[] longShiftTest(long value, int dist) {
427        System.out.println("IntMath.longShiftTest");
428
429        long results[] = new long[4];
430
431        results[0] = value << dist;
432        results[1] = value >> dist;
433        results[2] = value >>> dist;
434
435        results[3] = (((value << dist) >> dist) >>> dist) << dist;
436        return results;
437    }
438    static long longShiftCheck(long[] results) {
439        System.out.println("IntMath.longShiftCheck");
440
441        Main.assertTrue(results[0] == 0x96deff00aa010000L);
442        Main.assertTrue(results[1] == 0xffffd5aa96deff00L);
443        Main.assertTrue(results[2] == 0x0000d5aa96deff00L);
444        Main.assertTrue(results[3] == 0xffff96deff000000L);
445
446        Main.assertTrue(results.length == 4);
447
448        return results[0];      // test return-long
449    }
450
451
452    /*
453     * Try to cause some unary operations.
454     */
455    static int unopTest(int x) {
456        x = -x;
457        x ^= 0xffffffff;
458        return x;
459    }
460    static void unopCheck(int result) {
461        Main.assertTrue(result == 37);
462    }
463
464    static class Shorty {
465        public short mShort;
466        public char mChar;
467        public byte mByte;
468    };
469
470    /*
471     * Truncate an int.
472     */
473    static Shorty truncateTest(int x) {
474        System.out.println("IntMath.truncateTest");
475        Shorty shorts = new Shorty();
476
477        shorts.mShort = (short) x;
478        shorts.mChar = (char) x;
479        shorts.mByte = (byte) x;
480        return shorts;
481    }
482    static void truncateCheck(Shorty shorts) {
483        Main.assertTrue(shorts.mShort == -5597);     // 0xea23
484        Main.assertTrue(shorts.mChar == 59939);      // 0xea23
485        Main.assertTrue(shorts.mByte == 35);         // 0x23
486    }
487
488    /*
489     * Verify that we get a divide-by-zero exception.
490     */
491    static void divideByZero(int z) {
492        System.out.println("IntMath.divideByZero");
493
494        try {
495            int x = 100 / z;
496            Main.assertTrue(false);
497        } catch (ArithmeticException ae) {
498        }
499
500        try {
501            int x = 100 % z;
502            Main.assertTrue(false);
503        } catch (ArithmeticException ae) {
504        }
505
506        try {
507            long x = 100L / z;
508            Main.assertTrue(false);
509        } catch (ArithmeticException ae) {
510        }
511
512        try {
513            long x = 100L % z;
514            Main.assertTrue(false);
515        } catch (ArithmeticException ae) {
516        }
517    }
518
519    /*
520     * Check an edge condition: dividing the most-negative integer by -1
521     * returns the most-negative integer, and doesn't cause an exception.
522     *
523     * Pass in -1, -1L.
524     */
525    static void bigDivideOverflow(int idiv, long ldiv) {
526        System.out.println("IntMath.bigDivideOverflow");
527        int mostNegInt = (int) 0x80000000;
528        long mostNegLong = (long) 0x8000000000000000L;
529
530        int intDivResult = mostNegInt / idiv;
531        int intModResult = mostNegInt % idiv;
532        long longDivResult = mostNegLong / ldiv;
533        long longModResult = mostNegLong % ldiv;
534
535        Main.assertTrue(intDivResult == mostNegInt);
536        Main.assertTrue(intModResult == 0);
537        Main.assertTrue(longDivResult == mostNegLong);
538        Main.assertTrue(longModResult == 0);
539    }
540
541    /*
542     * Check "const" instructions.  We use negative values to ensure that
543     * sign-extension is happening.
544     */
545    static void checkConsts(byte small, short medium, int large, long huge) {
546        System.out.println("IntMath.checkConsts");
547
548        Main.assertTrue(small == 1);                     // const/4
549        Main.assertTrue(medium == -256);                 // const/16
550        Main.assertTrue(medium == -256L);                // const-wide/16
551        Main.assertTrue(large == -88888);                // const
552        Main.assertTrue(large == -88888L);               // const-wide/32
553        Main.assertTrue(huge == 0x9922334455667788L);    // const-wide
554    }
555
556    /*
557     * Test some java.lang.Math functions.
558     *
559     * The method arguments are positive values.
560     */
561    static void jlmTests(int ii, long ll) {
562        System.out.println("IntMath.jlmTests");
563
564        Main.assertTrue(Math.abs(ii) == ii);
565        Main.assertTrue(Math.abs(-ii) == ii);
566        Main.assertTrue(Math.min(ii, -5) == -5);
567        Main.assertTrue(Math.max(ii, -5) == ii);
568
569        Main.assertTrue(Math.abs(ll) == ll);
570        Main.assertTrue(Math.abs(-ll) == ll);
571        Main.assertTrue(Math.min(ll, -5L) == -5L);
572        Main.assertTrue(Math.max(ll, -5L) == ll);
573    }
574
575    public static void run() {
576        shiftTest1();
577        shiftTest2();
578        unsignedShiftTest();
579        shiftTest3(32);
580        convTest();
581        charSubTest();
582
583        int[] intResults;
584        long[] longResults;
585
586        intResults = intOperTest(70000, -3);
587        intOperCheck(intResults);
588        longResults = longOperTest(70000000000L, -3L);
589        longOperCheck(longResults);
590
591        intResults = lit16Test(77777);
592        lit16Check(intResults);
593        intResults = lit8Test(-55555);
594        lit8Check(intResults);
595        divLiteralTest();
596
597        intResults = intShiftTest(0xff00aa01, 8);
598        intShiftCheck(intResults);
599        longResults = longShiftTest(0xd5aa96deff00aa01L, 16);
600        long longRet = longShiftCheck(longResults);
601        Main.assertTrue(longRet == 0x96deff00aa010000L);
602
603        Shorty shorts = truncateTest(-16717277);    // 0xff00ea23
604        truncateCheck(shorts);
605
606        divideByZero(0);
607        bigDivideOverflow(-1, -1L);
608
609        checkConsts((byte) 1, (short) -256, -88888, 0x9922334455667788L);
610
611        unopCheck(unopTest(38));
612
613        jlmTests(12345, 0x1122334455667788L);
614    }
615}
616