In mono/metadata:
[mono.git] / mono / mini / ratests.cs
blob870d9c719e0bbbc7276ce8493f95b4823eee535e
1 using System;
3 /*
4 * Register allocator tests.
5 */
7 public class Tests {
9 public static int Main (String[] args) {
10 return TestDriver.RunTests (typeof (Tests));
13 static void call_clobber_inner () {
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 ++;
24 // clob == '1' and dreg == sreg2
25 a = b + a;
26 return a;
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 ++;
37 // clob == '1' and dreg == sreg2
38 a = b + a;
39 return (int)a;
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;
48 call_clobber_inner ();
50 return a + b;
53 static int call_clobber_inner2 () {
54 return 3;
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;
62 a = call_clobber_inner2 ();
64 return a + b;
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;
72 if (a != b) {
73 } else {
74 call_clobber_inner ();
77 return a + b;
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;
86 if (a != b) {
87 } else {
88 call_clobber_inner ();
89 c = a + b;
92 return c;
95 public static int test_5_spill_loop () {
96 int i;
98 for (i = 0; i < 5; ++i)
99 call_clobber_inner ();
101 return i;
104 public unsafe static int test_0_volatile () {
105 int i = 1;
106 int*p = &i;
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;
121 return 0;
124 public unsafe static int test_0_volatile_unused () {
125 int i = 1;
126 int*p = &i;
128 if (*p != 1)
129 return 1;
131 return 0;
134 public unsafe static int test_0_volatile_unused_2 () {
135 int i = 1;
136 int *p = &i;
138 i = 2;
139 if (i != 2)
140 return 1;
142 return 0;
145 static int ref_int (int i, ref int b, int j) {
146 int res = b;
147 b = 1;
148 return res;
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;
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;
169 return 0;
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;
189 return 0;
192 static int decode_len (out int pos) {
193 pos = 19;
194 return 10;
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)
205 public static int test_29_volatile_regress_2 () {
206 int pos = 0;
208 int len = decode_len (out pos);
209 call_clobber_inner ();
210 pos += len;
212 clobber_all (pos);
213 return pos;
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;
224 return 0;
227 static int return_arg (int i) {
228 return i;
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;
244 return 0;
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);
258 return 0;
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;
265 public static int test_0_unused_args () {
266 return many_args_unused (0, 1, 2, 3, 4, 5, 6, 7);
269 public unsafe void ClearBuffer (byte *buffer, int i) {
270 // Avoid inlining
271 byte *b = stackalloc byte [4];
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);
286 return this == null && s == target && start == length && length == opt && alwaysMatchFlags == neverMatchFlags && neverMatchFlags == targetSortKey && sk1 == sk2;
289 public static int test_0_spill_regress_3 () {
290 new Tests ().instance_method_1 (null, null, 0, 0, 0);
291 return 0;
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];
298 if (ctx == null)
299 throw new Exception ();
301 idx -= 1;
302 return false;
305 unsafe int LastIndexOfSortKey (string s, int start, int orgStart, int length, byte* sortkey, int ti, bool noLv4, ref object ctx)
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;
319 return -1;
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);
326 return 0;
329 public static bool IsEqual (Type type, Type base_type) {
330 return (type.GetHashCode () == base_type.GetHashCode ());
333 public static bool IsNestedFamilyAccessible (Type type, Type base_type)
335 do {
336 if (IsEqual (type, base_type))
337 return true;
339 type = type.DeclaringType;
340 } while (type != null);
342 return false;
345 public static int test_0_do_while_critical_edges () {
346 IsNestedFamilyAccessible (typeof (int), typeof (object));
348 return 0;
351 public static string return_string (string s) {
352 for (int i = 0; i < 1000; ++i)
354 return s;
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;
381 return 0;