1 /*
2  * Copyright (C) 2020 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 public class Main {
expectEquals(long expected, long result)18   private static void expectEquals(long expected, long result) {
19     if (expected != result) {
20       throw new Error("Expected: " + expected + ", found: " + result);
21     }
22   }
23 
expectEquals(long[] div_rem_expected, long[] result)24   private static void expectEquals(long[] div_rem_expected, long[] result) {
25     expectEquals(div_rem_expected[0], result[0]);
26     expectEquals(div_rem_expected[1], result[1]);
27   }
28 
remInt()29   private static void remInt() {
30     expectEquals(1L, $noinline$IntDivRemBy18(1));
31     expectEquals(1L << 32 | 2L, $noinline$IntDivRemBy18(20));
32 
33     expectEquals(1L, $noinline$IntRemDivBy18(1));
34     expectEquals(1L << 32 | 2L, $noinline$IntRemDivBy18(20));
35 
36     expectEquals(1L, $noinline$IntDivRemBy18(1, false));
37     expectEquals(1L << 32 | 2L, $noinline$IntDivRemBy18(20, true));
38 
39     expectEquals(1L, $noinline$IntDivRemByMinus18(1));
40     expectEquals(-1L, $noinline$IntDivRemBy18(-1));
41     expectEquals((-1L << 32) | 2L, $noinline$IntDivRemByMinus18(20));
42     expectEquals((1L << 32) | (-2L & 0x00000000ffffffff), $noinline$IntDivRemByMinus18(-20));
43 
44     expectEquals(0L, $noinline$IntDivRemBy5(0));
45     expectEquals(1L, $noinline$IntDivRemBy5(1));
46     expectEquals(1L << 32, $noinline$IntDivRemBy5(5));
47     expectEquals((1L << 32) | 1L, $noinline$IntDivRemBy5(6));
48     expectEquals((-1L << 32) | 0x00000000ffffffff, $noinline$IntDivRemBy5(-6));
49     expectEquals(-1L << 32, $noinline$IntDivRemBy5(-5));
50     expectEquals(0x00000000ffffffff, $noinline$IntDivRemBy5(-1));
51 
52     expectEquals(0L, $noinline$IntDivRemByMinus5(0));
53     expectEquals(1L, $noinline$IntDivRemByMinus5(1));
54     expectEquals(-1L << 32, $noinline$IntDivRemByMinus5(5));
55     expectEquals((-1L << 32) | 1L, $noinline$IntDivRemByMinus5(6));
56     expectEquals((1L << 32) | 0x00000000ffffffff, $noinline$IntDivRemByMinus5(-6));
57     expectEquals(1L << 32, $noinline$IntDivRemByMinus5(-5));
58     expectEquals(0x00000000ffffffff, $noinline$IntDivRemByMinus5(-1));
59 
60     expectEquals(0L, $noinline$IntDivRemBy7(0));
61     expectEquals(1L, $noinline$IntDivRemBy7(1));
62     expectEquals(1L << 32, $noinline$IntDivRemBy7(7));
63     expectEquals((1L << 32) | 1L, $noinline$IntDivRemBy7(8));
64     expectEquals((-1L << 32) | 0x00000000ffffffff, $noinline$IntDivRemBy7(-8));
65     expectEquals(-1L << 32, $noinline$IntDivRemBy7(-7));
66     expectEquals(0x00000000ffffffff, $noinline$IntDivRemBy7(-1));
67 
68     expectEquals(0L, $noinline$IntDivRemByMinus7(0));
69     expectEquals(1L, $noinline$IntDivRemByMinus7(1));
70     expectEquals(-1L << 32, $noinline$IntDivRemByMinus7(7));
71     expectEquals((-1L << 32) | 1L, $noinline$IntDivRemByMinus7(8));
72     expectEquals((1L << 32) | 0x00000000ffffffff, $noinline$IntDivRemByMinus7(-8));
73     expectEquals(1L << 32, $noinline$IntDivRemByMinus7(-7));
74     expectEquals(0x00000000ffffffff, $noinline$IntDivRemByMinus7(-1));
75 
76     expectEquals(0L, $noinline$IntDivRemByMaxInt(0));
77     expectEquals(1L, $noinline$IntDivRemByMaxInt(1));
78     expectEquals(1L << 32, $noinline$IntDivRemByMaxInt(Integer.MAX_VALUE));
79     expectEquals(Integer.MAX_VALUE - 1, $noinline$IntDivRemByMaxInt(Integer.MAX_VALUE - 1));
80     expectEquals((-1L << 32) | 0x00000000ffffffff, $noinline$IntDivRemByMaxInt(Integer.MIN_VALUE));
81     expectEquals(0x00000000ffffffff, $noinline$IntDivRemByMaxInt(-1));
82   }
83 
84   // A test case to check:
85   //  If there is HDiv with the same inputs as HRem, it is reused.
86   //
87   /// CHECK-START: long Main.$noinline$IntDivRemBy18(int) instruction_simplifier (before)
88   /// CHECK:           Div
89   /// CHECK:           Rem
90   //
91   /// CHECK-START: long Main.$noinline$IntDivRemBy18(int) instruction_simplifier (after)
92   /// CHECK:           Div
93   /// CHECK-NEXT:      Mul
94   /// CHECK-NEXT:      Sub
95   //
96   /// CHECK-START-ARM64: long Main.$noinline$IntDivRemBy18(int) disassembly (after)
97   /// CHECK:                 asr x{{\d+}}, x{{\d+}}, #34
98   /// CHECK-NEXT:            add w{{\d+}}, w{{\d+}}, w{{\d+}}, lsr #31
99   /// CHECK:                 msub w{{\d+}}, w{{\d+}}, w{{\d+}}, w{{\d+}}
$noinline$IntDivRemBy18(int v)100   private static long $noinline$IntDivRemBy18(int v) {
101     int q = v / 18;
102     int r = v % 18;
103     return ((long)q << 32) | r;
104   }
105 
106   // A test case to check:
107   //  If there is HDiv with the same inputs as HRem, it is reused.
108   //
109   /// CHECK-START: long Main.$noinline$IntDivRemByMinus18(int) instruction_simplifier (before)
110   /// CHECK:           Div
111   /// CHECK:           Rem
112   //
113   /// CHECK-START: long Main.$noinline$IntDivRemByMinus18(int) instruction_simplifier (after)
114   /// CHECK:           Div
115   /// CHECK-NEXT:      Mul
116   /// CHECK-NEXT:      Sub
117   //
118   /// CHECK-START-ARM64: long Main.$noinline$IntDivRemByMinus18(int) disassembly (after)
119   /// CHECK:                 asr x{{\d+}}, x{{\d+}}, #34
120   /// CHECK-NEXT:            add w{{\d+}}, w{{\d+}}, w{{\d+}}, lsr #31
121   /// CHECK:                 msub w{{\d+}}, w{{\d+}}, w{{\d+}}, w{{\d+}}
$noinline$IntDivRemByMinus18(int v)122   private static long $noinline$IntDivRemByMinus18(int v) {
123     int q = v / -18;
124     int r = v % -18;
125     return ((long)q << 32) | r;
126   }
127 
128   // A test case to check:
129   //  If there is HDiv with the same inputs as HRem, it is reused.
130   //
131   /// CHECK-START: long Main.$noinline$IntRemDivBy18(int) instruction_simplifier (before)
132   /// CHECK:           Rem
133   /// CHECK:           Div
134   //
135   /// CHECK-START: long Main.$noinline$IntRemDivBy18(int) instruction_simplifier (after)
136   /// CHECK:           Div
137   /// CHECK-NEXT:      Mul
138   /// CHECK-NEXT:      Sub
139   //
140   /// CHECK-START-ARM64: long Main.$noinline$IntRemDivBy18(int) disassembly (after)
141   /// CHECK:                 asr x{{\d+}}, x{{\d+}}, #34
142   /// CHECK-NEXT:            add w{{\d+}}, w{{\d+}}, w{{\d+}}, lsr #31
143   /// CHECK:                 msub w{{\d+}}, w{{\d+}}, w{{\d+}}, w{{\d+}}
$noinline$IntRemDivBy18(int v)144   private static long $noinline$IntRemDivBy18(int v) {
145     int r = v % 18;
146     int q = v / 18;
147     return ((long)q << 32) | r;
148   }
149 
150   // A test case to check:
151   //  If there is HDiv with the same inputs as HRem, it is reused.
152   //
153   /// CHECK-START: long Main.$noinline$IntDivRemBy5(int) instruction_simplifier (before)
154   /// CHECK:           Div
155   /// CHECK:           Rem
156   //
157   /// CHECK-START: long Main.$noinline$IntDivRemBy5(int) instruction_simplifier (after)
158   /// CHECK:           Div
159   /// CHECK-NEXT:      Shl
160   /// CHECK-NEXT:      Add
161   /// CHECK-NEXT:      Sub
162   //
163   /// CHECK-START-ARM64: long Main.$noinline$IntDivRemBy5(int) disassembly (after)
164   /// CHECK:                 asr x{{\d+}}, x{{\d+}}, #33
165   /// CHECK-NEXT:            add w{{\d+}}, w{{\d+}}, w{{\d+}}, lsr #31
166   /// CHECK:                 add w{{\d+}}, w{{\d+}}, w{{\d+}}, lsl #2
167   /// CHECK:                 sub w{{\d+}}, w{{\d+}}, w{{\d+}}
$noinline$IntDivRemBy5(int v)168   private static long $noinline$IntDivRemBy5(int v) {
169     int q = v / 5;
170     int r = v % 5;
171     return ((long)q << 32) | r;
172   }
173 
174   // A test case to check:
175   //  If there is HDiv with the same inputs as HRem, it is reused.
176   //
177   /// CHECK-START: long Main.$noinline$IntDivRemByMinus5(int) instruction_simplifier (before)
178   /// CHECK:           Div
179   /// CHECK:           Rem
180   //
181   /// CHECK-START: long Main.$noinline$IntDivRemByMinus5(int) instruction_simplifier (after)
182   /// CHECK:           Div
183   /// CHECK-NEXT:      Mul
184   /// CHECK-NEXT:      Sub
185   //
186   /// CHECK-START-ARM64: long Main.$noinline$IntDivRemByMinus5(int) disassembly (after)
187   /// CHECK:                 asr x{{\d+}}, x{{\d+}}, #33
188   /// CHECK-NEXT:            add w{{\d+}}, w{{\d+}}, w{{\d+}}, lsr #31
189   /// CHECK:                 msub w{{\d+}}, w{{\d+}}, w{{\d+}}, w{{\d+}}
$noinline$IntDivRemByMinus5(int v)190   private static long $noinline$IntDivRemByMinus5(int v) {
191     int q = v / -5;
192     int r = v % -5;
193     return ((long)q << 32) | r;
194   }
195 
196   // A test case to check:
197   //  If there is HDiv with the same inputs as HRem, it is reused.
198   //
199   /// CHECK-START: long Main.$noinline$IntDivRemBy7(int) instruction_simplifier (before)
200   /// CHECK:           Div
201   /// CHECK:           Rem
202   //
203   /// CHECK-START: long Main.$noinline$IntDivRemBy7(int) instruction_simplifier (after)
204   /// CHECK:           Div
205   /// CHECK-NEXT:      Shl
206   /// CHECK-NEXT:      Sub
207   /// CHECK-NEXT:      Sub
208   //
209   /// CHECK-START-ARM64: long Main.$noinline$IntDivRemBy7(int) instruction_simplifier_arm64 (after)
210   /// CHECK:                 Div
211   /// CHECK-NEXT:            DataProcWithShifterOp
212   /// CHECK-NEXT:            Add
213   //
214   /// CHECK-START-ARM64: long Main.$noinline$IntDivRemBy7(int) disassembly (after)
215   /// CHECK:                 asr x{{\d+}}, x{{\d+}}, #34
216   /// CHECK-NEXT:            cinc w{{\d+}}, w{{\d+}}, mi
217   /// CHECK:                 sub w{{\d+}}, w{{\d+}}, w{{\d+}}, lsl #3
218   /// CHECK:                 add w{{\d+}}, w{{\d+}}, w{{\d+}}
219   //
220   /// CHECK-START-ARM: long Main.$noinline$IntDivRemBy7(int) instruction_simplifier_arm (after)
221   /// CHECK:               Div
222   /// CHECK-NEXT:          DataProcWithShifterOp
223   /// CHECK-NEXT:          Add
224   //
225   /// CHECK-START-ARM: long Main.$noinline$IntDivRemBy7(int) disassembly (after)
226   /// CHECK:               asr{{s?}} r{{\d+}}, #2
227   /// CHECK-NEXT:          sub       r{{\d+}}, r{{\d+}}, r{{\d+}}, asr #31
228   /// CHECK:               sub       r{{\d+}}, r{{\d+}}, r{{\d+}}, lsl #3
229   /// CHECK:               add{{s?}} r{{\d+}}, r{{\d+}}, r{{\d+}}
$noinline$IntDivRemBy7(int v)230   private static long $noinline$IntDivRemBy7(int v) {
231     int q = v / 7;
232     int r = v % 7;
233     return ((long)q << 32) | r;
234   }
235 
236   // A test case to check:
237   //  If there is HDiv with the same inputs as HRem, it is reused.
238   //
239   /// CHECK-START: long Main.$noinline$IntDivRemByMinus7(int) instruction_simplifier (before)
240   /// CHECK:           Div
241   /// CHECK:           Rem
242   //
243   /// CHECK-START: long Main.$noinline$IntDivRemByMinus7(int) instruction_simplifier (after)
244   /// CHECK:           Div
245   /// CHECK-NEXT:      Mul
246   /// CHECK-NEXT:      Sub
247   //
248   /// CHECK-START-ARM64: long Main.$noinline$IntDivRemByMinus7(int) disassembly (after)
249   /// CHECK:                 asr x{{\d+}}, x{{\d+}}, #34
250   /// CHECK-NEXT:            cinc w{{\d+}}, w{{\d+}}, mi
251   /// CHECK:                 msub w{{\d+}}, w{{\d+}}, w{{\d+}}, w{{\d+}}
$noinline$IntDivRemByMinus7(int v)252   private static long $noinline$IntDivRemByMinus7(int v) {
253     int q = v / -7;
254     int r = v % -7;
255     return ((long)q << 32) | r;
256   }
257 
258   // A test case to check:
259   //  If there is HDiv with the same inputs as HRem, it is reused.
260   //
261   /// CHECK-START: long Main.$noinline$IntDivRemByMaxInt(int) instruction_simplifier (before)
262   /// CHECK:           Div
263   /// CHECK-NEXT:      Rem
264   //
265   /// CHECK-START: long Main.$noinline$IntDivRemByMaxInt(int) instruction_simplifier (after)
266   /// CHECK:           Div
267   /// CHECK-NEXT:      Shl
268   /// CHECK-NEXT:      Sub
269   /// CHECK-NEXT:      Sub
270   //
271   /// CHECK-START-ARM64: long Main.$noinline$IntDivRemByMaxInt(int) instruction_simplifier_arm64 (after)
272   /// CHECK:                 Div
273   /// CHECK-NEXT:            DataProcWithShifterOp
274   /// CHECK-NEXT:            Add
275   //
276   /// CHECK-START-ARM64: long Main.$noinline$IntDivRemByMaxInt(int) disassembly (after)
277   /// CHECK:                 asr x{{\d+}}, x{{\d+}}, #61
278   /// CHECK-NEXT:            add w{{\d+}}, w{{\d+}}, w{{\d+}}, lsr #31
279   /// CHECK:                 sub w{{\d+}}, w{{\d+}}, w{{\d+}}, lsl #31
280   /// CHECK:                 add w{{\d+}}, w{{\d+}}, w{{\d+}}
281   //
282   /// CHECK-START-ARM: long Main.$noinline$IntDivRemByMaxInt(int) instruction_simplifier_arm (after)
283   /// CHECK:               Div
284   /// CHECK-NEXT:          DataProcWithShifterOp
285   /// CHECK-NEXT:          Add
286   //
287   /// CHECK-START-ARM: long Main.$noinline$IntDivRemByMaxInt(int) disassembly (after)
288   /// CHECK:               asr{{s?}}  r{{\d+}}, #29
289   /// CHECK-NEXT:          sub        r{{\d+}}, r{{\d+}}, r{{\d+}}, asr #31
290   /// CHECK:               sub        r{{\d+}}, r{{\d+}}, r{{\d+}}, lsl #31
291   /// CHECK:               add{{s?}}  r{{\d+}}, r{{\d+}}, r{{\d+}}
$noinline$IntDivRemByMaxInt(int v)292   private static long $noinline$IntDivRemByMaxInt(int v) {
293     int q = v / Integer.MAX_VALUE;
294     int r = v % Integer.MAX_VALUE;
295     return ((long)q << 32) | r;
296   }
297 
298   // A test case to check:
299   //  HDiv with the same inputs as HRem but in another basic block is not reused.
300   //
301   /// CHECK-START: long Main.$noinline$IntDivRemBy18(int, boolean) instruction_simplifier (before)
302   /// CHECK:           Div
303   /// CHECK:           Rem
304   //
305   /// CHECK-START: long Main.$noinline$IntDivRemBy18(int, boolean) instruction_simplifier (after)
306   /// CHECK:           Div
307   /// CHECK:           Rem
$noinline$IntDivRemBy18(int v, boolean do_division)308   private static long $noinline$IntDivRemBy18(int v, boolean do_division) {
309     long result = 0;
310     if (do_division) {
311       int q = v / 18;
312       result = (long)q << 32;
313     }
314     int r = v % 18;
315     return result | r;
316   }
317 
318   // A test case to check:
319   //  If there is HDiv with the same inputs as HRem, it is reused.
320   //
321   /// CHECK-START: long Main.$noinline$IntDivRem(int, int) instruction_simplifier$after_gvn (before)
322   /// CHECK:           Div
323   /// CHECK-NEXT:      Rem
324   //
325   /// CHECK-START: long Main.$noinline$IntDivRem(int, int) instruction_simplifier$after_gvn (after)
326   /// CHECK:           Div
327   /// CHECK-NEXT:      Mul
328   /// CHECK-NEXT:      Sub
$noinline$IntDivRem(int v, int s)329   private static long $noinline$IntDivRem(int v, int s) {
330     int q = v / s;
331     int r = v % s;
332     return ((long)q << 32) | r;
333   }
334 
335   // A test case to check:
336   //  If there is HDiv with the same inputs as HRem, it is reused.
337   //
338   /// CHECK-START: long Main.$noinline$IntRemDiv(int, int) instruction_simplifier$after_gvn (before)
339   /// CHECK:           Rem
340   /// CHECK-NEXT:      Div
341   //
342   /// CHECK-START: long Main.$noinline$IntRemDiv(int, int) instruction_simplifier$after_gvn (after)
343   /// CHECK:           Div
344   /// CHECK-NEXT:      Mul
345   /// CHECK-NEXT:      Sub
$noinline$IntRemDiv(int v, int s)346   private static long $noinline$IntRemDiv(int v, int s) {
347     int r = v % s;
348     int q = v / s;
349     return ((long)q << 32) | r;
350   }
351 
352   // A test case to check:
353   //  HDiv with the same inputs as HRem but in another basic block is not reused.
354   //
355   /// CHECK-START: long Main.$noinline$IntDivRem(int, int, boolean) instruction_simplifier (before)
356   /// CHECK:           Div
357   /// CHECK:           Rem
358   //
359   /// CHECK-START: long Main.$noinline$IntDivRem(int, int, boolean) instruction_simplifier (after)
360   /// CHECK:           Div
361   /// CHECK:           Rem
$noinline$IntDivRem(int v, int s, boolean do_division)362   private static long $noinline$IntDivRem(int v, int s, boolean do_division) {
363     long result = 0;
364     if (do_division) {
365       int q = v / s;
366       result = (long)q << 32;
367     }
368     int r = v % s;
369     return result | r;
370   }
371 
372   // A test case to check:
373   //  If HRem is in a loop, the instruction simplifier postpones its optimization till
374   //  loop analysis/optimizations are done.
375   //
376   /// CHECK-START: int Main.$noinline$IntRemBy18InLoop(int) instruction_simplifier (before)
377   /// CHECK:           Div loop:B{{\d+}}
378   /// CHECK-NEXT:      Rem loop:B{{\d+}}
379   //
380   /// CHECK-START: int Main.$noinline$IntRemBy18InLoop(int) instruction_simplifier (after)
381   /// CHECK:           Div loop:B{{\d+}}
382   /// CHECK-NEXT:      Rem loop:B{{\d+}}
383   //
384   /// CHECK-START: int Main.$noinline$IntRemBy18InLoop(int) instruction_simplifier$after_bce (before)
385   /// CHECK:           Div loop:B{{\d+}}
386   /// CHECK-NEXT:      Rem loop:B{{\d+}}
387   //
388   /// CHECK-START: int Main.$noinline$IntRemBy18InLoop(int) instruction_simplifier$after_bce (after)
389   /// CHECK-NOT:       Rem
390   /// CHECK:           Div loop:B{{\d+}}
391   /// CHECK-NEXT:      Mul loop:B{{\d+}}
392   /// CHECK-NEXT:      Sub loop:B{{\d+}}
$noinline$IntRemBy18InLoop(int v)393   private static int $noinline$IntRemBy18InLoop(int v) {
394     int[] values = new int[v];
395     for (int i = 0; i < values.length; ++i) {
396       int q = i / 18;
397       int r = i % 18;
398       values[i] = q + r;
399     }
400     return values[v - 1];
401   }
402 
403   // A test case to check:
404   //  FP type HRem is not optimized by the instruction simplifier.
405   //
406   /// CHECK-START: float Main.$noinline$FloatRemBy18(float) instruction_simplifier (before)
407   /// CHECK:           Div
408   /// CHECK-NEXT:      Rem
409   //
410   /// CHECK-START: float Main.$noinline$FloatRemBy18(float) instruction_simplifier (after)
411   /// CHECK:           Div
412   /// CHECK-NEXT:      Rem
$noinline$FloatRemBy18(float v)413   private static float $noinline$FloatRemBy18(float v) {
414     float q = v / 18.0f;
415     float r = v % 18.0f;
416     return q + r;
417   }
418 
419   // A test case to check:
420   //  FP type HRem is not optimized by the instruction simplifier.
421   //
422   /// CHECK-START: double Main.$noinline$DoubleRemBy18(double) instruction_simplifier (before)
423   /// CHECK:           Div
424   /// CHECK-NEXT:      Rem
425   //
426   /// CHECK-START: double Main.$noinline$DoubleRemBy18(double) instruction_simplifier (after)
427   /// CHECK:           Div
428   /// CHECK-NEXT:      Rem
$noinline$DoubleRemBy18(double v)429   private static double $noinline$DoubleRemBy18(double v) {
430     double q = v / 18.0;
431     double r = v % 18.0;
432     return q + r;
433   }
434 
435   // A test case to check:
436   //  HRem with a divisor of power 2 is not optimized by the instruction simplifier because
437   //  the case is optimized by the code generator.
438   //
439   /// CHECK-START: int Main.$noinline$IntRemByIntMin(int) instruction_simplifier (before)
440   /// CHECK:           Div
441   /// CHECK-NEXT:      Rem
442   //
443   /// CHECK-START: int Main.$noinline$IntRemByIntMin(int) instruction_simplifier (after)
444   /// CHECK:           Div
445   /// CHECK-NEXT:      Rem
$noinline$IntRemByIntMin(int v)446   private static int $noinline$IntRemByIntMin(int v) {
447     int q = v / Integer.MIN_VALUE;
448     int r = v % Integer.MIN_VALUE;
449     return q + r;
450   }
451 
remLong()452   private static void remLong() {
453     expectEquals(1L, $noinline$LongDivRemBy18(1L));
454     expectEquals(1L << 32 | 2L, $noinline$LongDivRemBy18(20L));
455 
456     expectEquals(1L, $noinline$LongRemDivBy18(1L));
457     expectEquals(1L << 32 | 2L, $noinline$LongRemDivBy18(20L));
458 
459     expectEquals(1L, $noinline$LongDivRemBy18(1L, false));
460     expectEquals(1L << 32 | 2L, $noinline$LongDivRemBy18(20L, true));
461 
462     expectEquals(new long[] {0L, 1L}, $noinline$LongDivRemByMinus18(1));
463     expectEquals(new long[] {0L, -1L}, $noinline$LongDivRemByMinus18(-1));
464     expectEquals(new long[] {-1L, 2L}, $noinline$LongDivRemByMinus18(20));
465     expectEquals(new long[] {1L, -2L}, $noinline$LongDivRemByMinus18(-20));
466 
467     expectEquals(new long[] {0L, 0L}, $noinline$LongDivRemBy5(0));
468     expectEquals(new long[] {0L, 1L}, $noinline$LongDivRemBy5(1));
469     expectEquals(new long[] {1L, 0L}, $noinline$LongDivRemBy5(5));
470     expectEquals(new long[] {1L, 1L}, $noinline$LongDivRemBy5(6));
471     expectEquals(new long[] {-1L, -1L}, $noinline$LongDivRemBy5(-6));
472     expectEquals(new long[] {-1L, 0L}, $noinline$LongDivRemBy5(-5));
473     expectEquals(new long[] {0L, -1L}, $noinline$LongDivRemBy5(-1));
474 
475     expectEquals(new long[] {0L, 0L}, $noinline$LongDivRemByMinus5(0));
476     expectEquals(new long[] {0L, 1L}, $noinline$LongDivRemByMinus5(1));
477     expectEquals(new long[] {-1L, 0L}, $noinline$LongDivRemByMinus5(5));
478     expectEquals(new long[] {-1L, 1L}, $noinline$LongDivRemByMinus5(6));
479     expectEquals(new long[] {1L, -1L}, $noinline$LongDivRemByMinus5(-6));
480     expectEquals(new long[] {1L, 0L}, $noinline$LongDivRemByMinus5(-5));
481     expectEquals(new long[] {0L, -1L}, $noinline$LongDivRemByMinus5(-1));
482 
483     expectEquals(new long[] {0L, 0L}, $noinline$LongDivRemBy7(0));
484     expectEquals(new long[] {0L, 1L}, $noinline$LongDivRemBy7(1));
485     expectEquals(new long[] {1L, 0L}, $noinline$LongDivRemBy7(7));
486     expectEquals(new long[] {1L, 1L}, $noinline$LongDivRemBy7(8));
487     expectEquals(new long[] {-1L, -1L}, $noinline$LongDivRemBy7(-8));
488     expectEquals(new long[] {-1L, 0L}, $noinline$LongDivRemBy7(-7));
489     expectEquals(new long[] {0L, -1L}, $noinline$LongDivRemBy7(-1));
490 
491     expectEquals(new long[] {0L, 0L}, $noinline$LongDivRemByMinus7(0));
492     expectEquals(new long[] {0L, 1L}, $noinline$LongDivRemByMinus7(1));
493     expectEquals(new long[] {-1L, 0L}, $noinline$LongDivRemByMinus7(7));
494     expectEquals(new long[] {-1L, 1L}, $noinline$LongDivRemByMinus7(8));
495     expectEquals(new long[] {1L, -1L}, $noinline$LongDivRemByMinus7(-8));
496     expectEquals(new long[] {1L, 0L}, $noinline$LongDivRemByMinus7(-7));
497     expectEquals(new long[] {0L, -1L}, $noinline$LongDivRemByMinus7(-1));
498 
499     expectEquals(new long[] {0L, 0L}, $noinline$LongDivRemByMaxLong(0));
500     expectEquals(new long[] {0L, 1L}, $noinline$LongDivRemByMaxLong(1));
501     expectEquals(new long[] {1L, 0L}, $noinline$LongDivRemByMaxLong(Long.MAX_VALUE));
502     expectEquals(new long[] {0L, Long.MAX_VALUE - 1},
503                  $noinline$LongDivRemByMaxLong(Long.MAX_VALUE - 1));
504     expectEquals(new long[] {-1L, -1L}, $noinline$LongDivRemByMaxLong(Long.MIN_VALUE));
505     expectEquals(new long[] {0L, -1L}, $noinline$LongDivRemByMaxLong(-1));
506   }
507 
508   // A test case to check:
509   //  If there is HDiv with the same inputs as HRem, it is reused.
510   //
511   /// CHECK-START: long Main.$noinline$LongDivRemBy18(long) instruction_simplifier (before)
512   /// CHECK:           Div
513   /// CHECK:           Rem
514   //
515   /// CHECK-START: long Main.$noinline$LongDivRemBy18(long) instruction_simplifier (after)
516   /// CHECK:           Div
517   /// CHECK-NEXT:      Mul
518   /// CHECK-NEXT:      Sub
$noinline$LongDivRemBy18(long v)519   private static long $noinline$LongDivRemBy18(long v) {
520     long q = v / 18L;
521     long r = v % 18L;
522     return (q << 32) | r;
523   }
524 
525   // A test case to check:
526   //  If there is HDiv with the same inputs as HRem, it is reused.
527   //
528   /// CHECK-START: long[] Main.$noinline$LongDivRemByMinus18(long) instruction_simplifier (before)
529   /// CHECK:           Div
530   /// CHECK:           Rem
531   //
532   /// CHECK-START: long[] Main.$noinline$LongDivRemByMinus18(long) instruction_simplifier (after)
533   /// CHECK:           Div
534   /// CHECK-NEXT:      Mul
535   /// CHECK-NEXT:      Sub
536   //
537   /// CHECK-START-ARM64: long[] Main.$noinline$LongDivRemByMinus18(long) disassembly (after)
538   /// CHECK:                 smulh x{{\d+}}, x{{\d+}}, x{{\d+}}
539   /// CHECK-NEXT:            add   x{{\d+}}, x{{\d+}}, x{{\d+}}, lsr #63
540   /// CHECK:                 msub  x{{\d+}}, x{{\d+}}, x{{\d+}}, x{{\d+}}
$noinline$LongDivRemByMinus18(long v)541   private static long[] $noinline$LongDivRemByMinus18(long v) {
542     long q = v / -18L;
543     long r = v % -18L;
544     return new long[] {q, r};
545   }
546 
547   // A test case to check:
548   //  If there is HDiv with the same inputs as HRem, it is reused.
549   //
550   /// CHECK-START: long Main.$noinline$LongRemDivBy18(long) instruction_simplifier (before)
551   /// CHECK:           Rem
552   /// CHECK:           Div
553   //
554   /// CHECK-START: long Main.$noinline$LongRemDivBy18(long) instruction_simplifier (after)
555   /// CHECK:           Div
556   /// CHECK-NEXT:      Mul
557   /// CHECK-NEXT:      Sub
$noinline$LongRemDivBy18(long v)558   private static long $noinline$LongRemDivBy18(long v) {
559     long r = v % 18L;
560     long q = v / 18L;
561     return (q << 32) | r;
562   }
563 
564   // A test case to check:
565   //  If there is HDiv with the same inputs as HRem, it is reused.
566   //
567   /// CHECK-START: long[] Main.$noinline$LongDivRemBy5(long) instruction_simplifier (before)
568   /// CHECK:           Div
569   /// CHECK:           Rem
570   //
571   /// CHECK-START: long[] Main.$noinline$LongDivRemBy5(long) instruction_simplifier (after)
572   /// CHECK:           Div
573   /// CHECK-NEXT:      Shl
574   /// CHECK-NEXT:      Add
575   /// CHECK-NEXT:      Sub
576   //
577   /// CHECK-START-ARM64: long[] Main.$noinline$LongDivRemBy5(long) disassembly (after)
578   /// CHECK:                 asr x{{\d+}}, x{{\d+}}, #1
579   /// CHECK-NEXT:            add x{{\d+}}, x{{\d+}}, x{{\d+}}, lsr #63
580   /// CHECK:                 add x{{\d+}}, x{{\d+}}, x{{\d+}}, lsl #2
581   /// CHECK:                 sub x{{\d+}}, x{{\d+}}, x{{\d+}}
$noinline$LongDivRemBy5(long v)582   private static long[] $noinline$LongDivRemBy5(long v) {
583     long q = v / 5L;
584     long r = v % 5L;
585     return new long[] {q, r};
586   }
587 
588   // A test case to check:
589   //  If there is HDiv with the same inputs as HRem, it is reused.
590   //
591   /// CHECK-START: long[] Main.$noinline$LongDivRemByMinus5(long) instruction_simplifier (before)
592   /// CHECK:           Div
593   /// CHECK:           Rem
594   //
595   /// CHECK-START: long[] Main.$noinline$LongDivRemByMinus5(long) instruction_simplifier (after)
596   /// CHECK:           Div
597   /// CHECK-NEXT:      Mul
598   /// CHECK-NEXT:      Sub
599   //
600   /// CHECK-START-ARM64: long[] Main.$noinline$LongDivRemByMinus5(long) disassembly (after)
601   /// CHECK:                 asr x{{\d+}}, x{{\d+}}, #1
602   /// CHECK-NEXT:            add x{{\d+}}, x{{\d+}}, x{{\d+}}, lsr #63
603   /// CHECK:                 msub x{{\d+}}, x{{\d+}}, x{{\d+}}, x{{\d+}}
$noinline$LongDivRemByMinus5(long v)604   private static long[] $noinline$LongDivRemByMinus5(long v) {
605     long q = v / -5L;
606     long r = v % -5L;
607     return new long[] {q, r};
608   }
609 
610   // A test case to check:
611   //  If there is HDiv with the same inputs as HRem, it is reused.
612   //
613   /// CHECK-START: long[] Main.$noinline$LongDivRemBy7(long) instruction_simplifier (before)
614   /// CHECK:           Div
615   /// CHECK:           Rem
616   //
617   /// CHECK-START: long[] Main.$noinline$LongDivRemBy7(long) instruction_simplifier (after)
618   /// CHECK:           Div
619   /// CHECK-NEXT:      Shl
620   /// CHECK-NEXT:      Sub
621   /// CHECK-NEXT:      Sub
622   //
623   /// CHECK-START-ARM64: long[] Main.$noinline$LongDivRemBy7(long) instruction_simplifier_arm64 (after)
624   /// CHECK:                 Div
625   /// CHECK-NEXT:            DataProcWithShifterOp
626   /// CHECK-NEXT:            Add
627   //
628   /// CHECK-START-ARM64: long[] Main.$noinline$LongDivRemBy7(long) disassembly (after)
629   /// CHECK:                 asr x{{\d+}}, x{{\d+}}, #1
630   /// CHECK-NEXT:            add x{{\d+}}, x{{\d+}}, x{{\d+}}, lsr #63
631   /// CHECK:                 sub x{{\d+}}, x{{\d+}}, x{{\d+}}, lsl #3
632   /// CHECK:                 add x{{\d+}}, x{{\d+}}, x{{\d+}}
633   //
634   /// CHECK-START-ARM: long[] Main.$noinline$LongDivRemBy7(long) instruction_simplifier_arm (after)
635   /// CHECK:               Div
636   /// CHECK-NEXT:          DataProcWithShifterOp
637   /// CHECK-NEXT:          Add
638   //
639   /// CHECK-START-ARM: long[] Main.$noinline$LongDivRemBy7(long) disassembly (after)
640   /// CHECK:               blx lr
641   //  CHECK:               lsl ip, r{{\d}}, #3
642   //  CHECK-NEXT:          orr       ip, r{{\d}}, lsr #29
643   //  CHECK-NEXT:          sub       r{{\d}}, r{{\d}}, r{{\d}}, lsl #3
644   //  CHECK-NEXT:          sbc{{s?}} r{{\d}}, r{{\d}}, ip
645   /// CHECK:               add{{s?}} r{{\d}}, r{{\d}}
646   /// CHECK-NEXT:          adc{{s?}} r{{\d}}, r{{\d}}
$noinline$LongDivRemBy7(long v)647   private static long[] $noinline$LongDivRemBy7(long v) {
648     long q = v / 7L;
649     long r = v % 7L;
650     return new long[] {q, r};
651   }
652 
653   // A test case to check:
654   //  If there is HDiv with the same inputs as HRem, it is reused.
655   //
656   /// CHECK-START: long[] Main.$noinline$LongDivRemByMinus7(long) instruction_simplifier (before)
657   /// CHECK:           Div
658   /// CHECK:           Rem
659   //
660   /// CHECK-START: long[] Main.$noinline$LongDivRemByMinus7(long) instruction_simplifier (after)
661   /// CHECK:           Div
662   /// CHECK-NEXT:      Mul
663   /// CHECK-NEXT:      Sub
664   //
665   /// CHECK-START-ARM64: long[] Main.$noinline$LongDivRemByMinus7(long) disassembly (after)
666   /// CHECK:                 asr x{{\d+}}, x{{\d+}}, #1
667   /// CHECK-NEXT:            add x{{\d+}}, x{{\d+}}, x{{\d+}}, lsr #63
668   /// CHECK:                 msub x{{\d+}}, x{{\d+}}, x{{\d+}}, x{{\d+}}
$noinline$LongDivRemByMinus7(long v)669   private static long[] $noinline$LongDivRemByMinus7(long v) {
670     long q = v / -7L;
671     long r = v % -7L;
672     return new long[] {q, r};
673   }
674 
675   // A test case to check:
676   //  If there is HDiv with the same inputs as HRem, it is reused.
677   //
678   /// CHECK-START: long[] Main.$noinline$LongDivRemByMaxLong(long) instruction_simplifier (before)
679   /// CHECK:           Div
680   /// CHECK:           Rem
681   //
682   /// CHECK-START: long[] Main.$noinline$LongDivRemByMaxLong(long) instruction_simplifier (after)
683   /// CHECK:           Div
684   /// CHECK-NEXT:      Shl
685   /// CHECK-NEXT:      Sub
686   /// CHECK-NEXT:      Sub
687   //
688   /// CHECK-START-ARM64: long[] Main.$noinline$LongDivRemByMaxLong(long) instruction_simplifier_arm64 (after)
689   /// CHECK:           Div
690   /// CHECK-NEXT:      DataProcWithShifterOp
691   /// CHECK-NEXT:      Add
692   //
693   /// CHECK-START-ARM64: long[] Main.$noinline$LongDivRemByMaxLong(long) disassembly (after)
694   /// CHECK:                 asr x{{\d+}}, x{{\d+}}, #61
695   /// CHECK-NEXT:            add x{{\d+}}, x{{\d+}}, x{{\d+}}, lsr #63
696   /// CHECK:                 sub x{{\d+}}, x{{\d+}}, x{{\d+}}, lsl #63
697   /// CHECK:                 add x{{\d+}}, x{{\d+}}, x{{\d+}}
698   //
699   /// CHECK-START-ARM: long[] Main.$noinline$LongDivRemByMaxLong(long) instruction_simplifier_arm (after)
700   /// CHECK:           Div
701   /// CHECK-NEXT:      DataProcWithShifterOp
702   /// CHECK-NEXT:      Add
703   //
704   /// CHECK-START-ARM: long[] Main.$noinline$LongDivRemByMaxLong(long) disassembly (after)
705   /// CHECK:               blx lr
706   //  CHECK:               sub       r{{\d}}, r{{\d}}, r{{\d}}, lsl #31
707   //  CHECK-NEXT:          mov{{s?}} r{{\d}}, r{{\d}}
708   /// CHECK:               add{{s?}} r{{\d}}, r{{\d}}
709   /// CHECK-NEXT:          adc{{s?}} r{{\d}}, r{{\d}}
$noinline$LongDivRemByMaxLong(long v)710   private static long[] $noinline$LongDivRemByMaxLong(long v) {
711     long q = v / Long.MAX_VALUE;
712     long r = v % Long.MAX_VALUE;
713     return new long[] {q, r};
714   }
715 
716   // A test case to check:
717   //  HDiv with the same inputs as HRem but in another basic block is not reused.
718   //
719   /// CHECK-START: long Main.$noinline$LongDivRemBy18(long, boolean) instruction_simplifier (before)
720   /// CHECK:           Div
721   /// CHECK:           Rem
722   //
723   /// CHECK-START: long Main.$noinline$LongDivRemBy18(long, boolean) instruction_simplifier (after)
724   /// CHECK:           Div
725   /// CHECK:           Rem
$noinline$LongDivRemBy18(long v, boolean do_division)726   private static long $noinline$LongDivRemBy18(long v, boolean do_division) {
727     long result = 0;
728     if (do_division) {
729       long q = v / 18L;
730       result = q << 32;
731     }
732     long r = v % 18L;
733     return result | r;
734   }
735 
736   // A test case to check:
737   //  If there is HDiv with the same inputs as HRem, it is reused.
738   //
739   /// CHECK-START: long Main.$noinline$LongDivRem(long, long) instruction_simplifier$after_gvn (before)
740   /// CHECK:           Div
741   /// CHECK-NEXT:      Rem
742   //
743   /// CHECK-START: long Main.$noinline$LongDivRem(long, long) instruction_simplifier$after_gvn (after)
744   /// CHECK:           Div
745   /// CHECK-NEXT:      Mul
746   /// CHECK-NEXT:      Sub
$noinline$LongDivRem(long v, long s)747   private static long $noinline$LongDivRem(long v, long s) {
748     long q = v / s;
749     long r = v % s;
750     return (q << 32) | r;
751   }
752 
753   // A test case to check:
754   //  If there is HDiv with the same inputs as HRem, it is reused.
755   //
756   /// CHECK-START: long Main.$noinline$LongRemDiv(long, long) instruction_simplifier$after_gvn (before)
757   /// CHECK:           Rem
758   /// CHECK-NEXT:      Div
759   //
760   /// CHECK-START: long Main.$noinline$LongRemDiv(long, long) instruction_simplifier$after_gvn (after)
761   /// CHECK:           Div
762   /// CHECK-NEXT:      Mul
763   /// CHECK-NEXT:      Sub
$noinline$LongRemDiv(long v, long s)764   private static long $noinline$LongRemDiv(long v, long s) {
765     long r = v % s;
766     long q = v / s;
767     return (q << 32) | r;
768   }
769 
770   // A test case to check:
771   //  HDiv with the same inputs as HRem but in another basic block is not reused.
772   //
773   /// CHECK-START: long Main.$noinline$LongDivRem(long, long, boolean) instruction_simplifier (before)
774   /// CHECK:           Div
775   /// CHECK:           Rem
776   //
777   /// CHECK-START: long Main.$noinline$LongDivRem(long, long, boolean) instruction_simplifier (after)
778   /// CHECK:           Div
779   /// CHECK:           Rem
$noinline$LongDivRem(long v, long s, boolean do_division)780   private static long $noinline$LongDivRem(long v, long s, boolean do_division) {
781     long result = 0;
782     if (do_division) {
783       long q = v / s;
784       result = q << 32;
785     }
786     long r = v % s;
787     return result | r;
788   }
789 
790   // A test case to check:
791   //  If HRem is in a loop, the instruction simplifier postpones its optimization till
792   //  loop analysis/optimizations are done.
793   //
794   /// CHECK-START: long Main.$noinline$LongRemBy18InLoop(long) instruction_simplifier (before)
795   /// CHECK:           Div loop:B{{\d+}}
796   /// CHECK-NEXT:      Rem loop:B{{\d+}}
797   //
798   /// CHECK-START: long Main.$noinline$LongRemBy18InLoop(long) instruction_simplifier (after)
799   /// CHECK:           Div loop:B{{\d+}}
800   /// CHECK-NEXT:      Rem loop:B{{\d+}}
801   //
802   /// CHECK-START: long Main.$noinline$LongRemBy18InLoop(long) instruction_simplifier$after_bce (before)
803   /// CHECK:           Div loop:B{{\d+}}
804   /// CHECK-NEXT:      Rem loop:B{{\d+}}
805   //
806   /// CHECK-START: long Main.$noinline$LongRemBy18InLoop(long) instruction_simplifier$after_bce (after)
807   /// CHECK-NOT:       Rem
808   /// CHECK:           Div loop:B{{\d+}}
809   /// CHECK-NEXT:      Mul loop:B{{\d+}}
810   /// CHECK-NEXT:      Sub loop:B{{\d+}}
$noinline$LongRemBy18InLoop(long v)811   private static long $noinline$LongRemBy18InLoop(long v) {
812     long[] values = new long[(int)v];
813     for (int i = 0; i < values.length; ++i) {
814       long d = (long)i;
815       long q = d / 18L;
816       long r = d % 18L;
817       values[i] = q + r;
818     }
819     return values[values.length - 1];
820   }
821 
822   // A test case to check:
823   //  HRem with a divisor of power 2 is not optimized by the instruction simplifier because
824   //  the case is optimized by the code generator.
825   //
826   /// CHECK-START: long Main.$noinline$LongRemByLongMin(long) instruction_simplifier (before)
827   /// CHECK:           Div
828   /// CHECK-NEXT:      Rem
829   //
830   /// CHECK-START: long Main.$noinline$LongRemByLongMin(long) instruction_simplifier (after)
831   /// CHECK:           Div
832   /// CHECK-NEXT:      Rem
$noinline$LongRemByLongMin(long v)833   private static long $noinline$LongRemByLongMin(long v) {
834     long q = v / Long.MIN_VALUE;
835     long r = v % Long.MIN_VALUE;
836     return q + r;
837   }
838 
main(String args[])839   public static void main(String args[]) {
840     remInt();
841     remLong();
842   }
843 }
844