Merge pull request #5714 from alexischr/update_bockbuild
[mono.git] / mono / mini / ratests.cs
1 using System;
2
3 /*
4  * Register allocator tests.
5  */
6
7 public class Tests {
8
9         public static int Main (String[] args) {
10                 return TestDriver.RunTests (typeof (Tests));
11         }
12
13         static void call_clobber_inner () {
14         }
15
16         public static int test_15_clobber_1 () {
17                 int a = 0;
18                 int b = 0;
19                 for (int i = 0; i < 10; ++i)
20                         a ++;
21                 for (int i = 0; i < 5; ++i)
22                         b ++;
23
24                 // clob == '1' and dreg == sreg2
25                 a = b + a;
26                 return a;
27         }
28
29         public static int test_15_clobber_1_fp () {
30                 float a = 0;
31                 float b = 0;
32                 for (int i = 0; i < 10; ++i)
33                         a ++;
34                 for (int i = 0; i < 5; ++i)
35                         b ++;
36
37                 // clob == '1' and dreg == sreg2
38                 a = b + a;
39                 return (int)a;
40         }
41
42         public static int test_5_call_clobber () {
43                 // A call clobbers some registers so variables in those registers need to be spilled
44                 // and later reloaded to a register
45                 int a = 2;
46                 int b = 3;
47
48                 call_clobber_inner ();
49
50                 return a + b;
51         }
52
53         static int call_clobber_inner2 () {
54                 return 3;
55         }
56
57         public static int test_7_call_clobber_dreg () {
58                 // A call doesn't clobber its dreg
59                 int a = 3;
60                 int b = 4;
61
62                 a = call_clobber_inner2 ();
63
64                 return a + b;
65         }
66
67         public static int test_9_spill_if_then_else () {
68                 // Spilling variables in one branch of an if-then-else
69                 int a = 4;
70                 int b = 5;
71
72                 if (a != b) {
73                 } else {
74                         call_clobber_inner ();
75                 }
76
77                 return a + b;
78         }
79
80         public static int test_3_spill_reload_if_then_else () {
81                 // Spilling and reloading variables in one branch of an if-then-else
82                 int a = 4;
83                 int b = 5;
84                 int c = 3;
85
86                 if (a != b) {
87                 } else {
88                         call_clobber_inner ();
89                         c = a + b;
90                 }
91
92                 return c;
93         }
94
95         public static int test_5_spill_loop () {
96                 int i;
97
98                 for (i = 0; i < 5; ++i)
99                         call_clobber_inner ();
100
101                 return i;
102         }
103
104         public unsafe static int test_0_volatile () {
105                 int i = 1;
106                 int*p = &i;
107
108                 if (*p != 1)
109                         return 1;
110                 if (i != 1)
111                         return 2;
112                 *p = 5;
113                 if (i != 5)
114                         return 3;
115                 i = 2;
116                 if (i != 2)
117                         return 4;
118                 if (*p != 2)
119                         return 5;
120
121                 return 0;
122         }
123
124         public unsafe static int test_0_volatile_unused () {
125                 int i = 1;
126                 int*p = &i;
127
128                 if (*p != 1)
129                         return 1;
130
131                 return 0;
132         }
133
134         public unsafe static int test_0_volatile_unused_2 () {
135                 int i = 1;
136                 int *p = &i;
137
138                 i = 2;
139                 if (i != 2)
140                         return 1;
141
142                 return 0;
143         }
144
145         static int ref_int (int i, ref int b, int j) {
146                 int res = b;
147                 b = 1;
148                 return res;
149         }
150
151         public static int test_0_volatile_unused_3 () {
152                 // b's def has no use so its interval is split at a position not covered by the interval
153                 int b = 42;
154                 if (ref_int (99, ref b, 100) != 42)
155                         return 1;
156                 b = 43;
157                 if (ref_int (99, ref b, 100) != 43)
158                         return 2;
159                 if (b != 1)
160                         return 13;
161                 return 0;
162         }
163
164         static int ref_bool (int i, ref bool b1, ref bool b2, ref bool b3) {
165                 b1 = !b1;
166                 b2 = !b2;
167                 b3 = !b3;
168
169                 return 0;
170         }
171
172         public static int test_0_volatile_regress_1 () {
173                 // Spill stores should precede spill loads at a given position
174                 for (int i = 0; i < 8; i++) {
175                         bool b1 = (i & 4) != 0;
176                         bool b2 = (i & 2) != 0;
177                         bool b3 = (i & 1) != 0;
178                         bool orig_b1 = b1, orig_b2 = b2, orig_b3 = b3;
179                         if (ref_bool(i, ref b1, ref b2, ref b3) != 0)
180                                 return 4 * i + 1;
181                         if (b1 != !orig_b1)
182                                 return 4 * i + 2;
183                         if (b2 != !orig_b2)
184                                 return 4 * i + 3;
185                         if (b3 != !orig_b3)
186                                 return 4 * i + 4;
187                 }
188
189                 return 0;
190         }
191
192         static int decode_len (out int pos) {
193                 pos = 19;
194                 return 10;
195         }
196
197         static void clobber_all (int pos) {
198                 for (int i = 0; i < 10; ++i)
199                         for (int j = 0; j < 10; ++j)
200                                 for (int k = 0; k < 10; ++k)
201                                         for (int l = 0; l < 10; ++l)
202                                                 ;
203         }
204
205         public static int test_29_volatile_regress_2 () {
206                 int pos = 0;
207
208                 int len = decode_len (out pos);
209                 call_clobber_inner ();
210                 pos += len;
211
212                 clobber_all (pos);
213                 return pos;
214         }
215
216         public static int test_0_clobber_regress_1 () {
217                 object[] a11 = new object [10];
218                 object o = new Object ();
219                 // A spill load is inserted before the backward branch, clobbering one of the
220                 // registers used in the comparison
221                 for (int i = 0; i < 10; ++i)
222                         a11 [i] = null;
223
224                 return 0;
225         }
226
227         static int return_arg (int i) {
228                 return i;
229         }
230
231         public static int test_0_spill_regress_1 () {
232                 int j = 5;
233                 for (int i = 0; i < 3; i++) {
234                         // i is spilled by the call, then reloaded for the loop check
235                         // make sure the move from its first reg to its second is inserted in the
236                         // if body bblock, not the for body bblock
237                         if (i == 0) {
238                         } else {
239                                 if (return_arg (j) != 5)
240                                         return 1;
241                         }
242                 }
243
244                 return 0;
245         }
246
247         public static int test_0_spill_regress_2 () {
248                 double[] temporaries = new double[3];
249                 for (int i = 0; i < 3; i++) {
250                         // i and temporaries are spilled by the call, then reloaded after the call
251                         // make sure the two moves inserted in the if bblock are in the proper order
252                         if (i == 0) {
253                         } else {
254                                 temporaries [i] = return_arg (i);
255                         }
256                 }
257
258                 return 0;
259         }
260
261         static int many_args_unused (int i, int j, int k, int l, int m, int n, int p, int q) {
262                 return 0;
263         }
264
265         public static int test_0_unused_args () {
266                 return many_args_unused (0, 1, 2, 3, 4, 5, 6, 7);
267         }
268                         
269         public unsafe void ClearBuffer (byte *buffer, int i) {
270                 // Avoid inlining
271                 byte *b = stackalloc byte [4];
272         }
273
274         public unsafe bool instance_method_1 (string s, string target, int start, int length, int opt) {
275                 byte* alwaysMatchFlags = stackalloc byte [16];
276                 byte* neverMatchFlags = stackalloc byte [16];
277                 byte* targetSortKey = stackalloc byte [4];
278                 byte* sk1 = stackalloc byte [4];
279                 byte* sk2 = stackalloc byte [4];
280                 ClearBuffer (alwaysMatchFlags, 16);
281                 ClearBuffer (neverMatchFlags, 16);
282                 ClearBuffer (targetSortKey, 4);
283                 ClearBuffer (sk1, 4);
284                 ClearBuffer (sk2, 4);
285
286                 return this == null && s == target && start == length && length == opt && alwaysMatchFlags == neverMatchFlags && neverMatchFlags == targetSortKey && sk1 == sk2;
287         }
288
289         public static int test_0_spill_regress_3 () {
290                 new Tests ().instance_method_1 (null, null, 0, 0, 0);
291                 return 0;
292         }
293
294         unsafe bool MatchesBackward (string s, ref int idx, int end, int orgStart, int ti, byte* sortkey, bool noLv4, ref object ctx) {
295                 // Avoid inlining
296                 byte *b = stackalloc byte [4];
297
298                 if (ctx == null)
299                         throw new Exception ();
300
301                 idx -= 1;
302                 return false;
303         }
304
305         unsafe int LastIndexOfSortKey (string s, int start, int orgStart, int length, byte* sortkey, int ti, bool noLv4, ref object ctx)
306         {
307                 // ctx is initially allocated to the stack, when it is reloaded before the call,
308                 // %rax is spilled to free up the register, then ctx is allocated to %rax for its
309                 // whole lifetime, but %rax is not available for this since it is clobbered by the
310                 // call
311                 int end = start - length;
312                 int idx = start;
313                 while (idx > end) {
314                         int cur = idx;
315                         if (MatchesBackward (s, ref idx, end, orgStart,
316                                                                  ti, sortkey, noLv4, ref ctx))
317                                 return cur;
318                 }
319                 return -1;
320         }
321
322         public unsafe static int test_0_spill_regress_4 () {
323                 object o = new Object ();
324                 new Tests ().LastIndexOfSortKey ("", 10, 0, 5, null, 0, false, ref o);
325
326                 return 0;
327         }
328
329         public static bool IsEqual (Type type, Type base_type) {
330                 return (type.GetHashCode () == base_type.GetHashCode ());
331         }
332
333         public static bool IsNestedFamilyAccessible (Type type, Type base_type)
334         {
335                 do {
336                         if (IsEqual (type, base_type))
337                                 return true;
338
339                         type = type.DeclaringType;
340                 } while (type != null);
341
342                 return false;
343         }
344
345         public static int test_0_do_while_critical_edges () {
346                 IsNestedFamilyAccessible (typeof (int), typeof (object));
347
348                 return 0;
349         }
350
351         public static string return_string (string s) {
352                 for (int i = 0; i < 1000; ++i)
353                         ;
354                 return s;
355         }
356
357         public static int test_0_switch_critical_edges () {
358                 // A spill load is inserted at the end of the bblock containing the OP_BR_REG,
359                 // overwriting the source reg of the OP_BR_REG. The edge is not really 
360                 // a critical edge, since its source bblock only has 1 exit, but it must
361                 // be treated as such.
362                 for (int i=0; i < UInt16.MaxValue; i++) {
363                         Char c = Convert.ToChar (i);
364                         switch (i) {
365                         case 0x0009:
366                         case 0x000A:
367                         case 0x000B:
368                         case 0x2028:
369                         case 0x2029:
370                         case 0x202F:
371                         case 0x205F:
372                         case 0x3000:
373                                 //Console.WriteLine ((i.ToString () + (int)c));
374                                 return_string ((i.ToString () + (int)c));
375                                 break;
376                         default:
377                                 break;
378                         }
379                 }
380
381                 return 0;
382         }
383 }