using System; /* * Register allocator tests. */ public class Tests { public static int Main (String[] args) { return TestDriver.RunTests (typeof (Tests)); } static void call_clobber_inner () { } public static int test_15_clobber_1 () { int a = 0; int b = 0; for (int i = 0; i < 10; ++i) a ++; for (int i = 0; i < 5; ++i) b ++; // clob == '1' and dreg == sreg2 a = b + a; return a; } public static int test_15_clobber_1_fp () { float a = 0; float b = 0; for (int i = 0; i < 10; ++i) a ++; for (int i = 0; i < 5; ++i) b ++; // clob == '1' and dreg == sreg2 a = b + a; return (int)a; } public static int test_5_call_clobber () { // A call clobbers some registers so variables in those registers need to be spilled // and later reloaded to a register int a = 2; int b = 3; call_clobber_inner (); return a + b; } static int call_clobber_inner2 () { return 3; } public static int test_7_call_clobber_dreg () { // A call doesn't clobber its dreg int a = 3; int b = 4; a = call_clobber_inner2 (); return a + b; } public static int test_9_spill_if_then_else () { // Spilling variables in one branch of an if-then-else int a = 4; int b = 5; if (a != b) { } else { call_clobber_inner (); } return a + b; } public static int test_3_spill_reload_if_then_else () { // Spilling and reloading variables in one branch of an if-then-else int a = 4; int b = 5; int c = 3; if (a != b) { } else { call_clobber_inner (); c = a + b; } return c; } public static int test_5_spill_loop () { int i; for (i = 0; i < 5; ++i) call_clobber_inner (); return i; } public unsafe static int test_0_volatile () { int i = 1; int*p = &i; if (*p != 1) return 1; if (i != 1) return 2; *p = 5; if (i != 5) return 3; i = 2; if (i != 2) return 4; if (*p != 2) return 5; return 0; } public unsafe static int test_0_volatile_unused () { int i = 1; int*p = &i; if (*p != 1) return 1; return 0; } public unsafe static int test_0_volatile_unused_2 () { int i = 1; int *p = &i; i = 2; if (i != 2) return 1; return 0; } static int ref_int (int i, ref int b, int j) { int res = b; b = 1; return res; } public static int test_0_volatile_unused_3 () { // b's def has no use so its interval is split at a position not covered by the interval int b = 42; if (ref_int (99, ref b, 100) != 42) return 1; b = 43; if (ref_int (99, ref b, 100) != 43) return 2; if (b != 1) return 13; return 0; } static int ref_bool (int i, ref bool b1, ref bool b2, ref bool b3) { b1 = !b1; b2 = !b2; b3 = !b3; return 0; } public static int test_0_volatile_regress_1 () { // Spill stores should precede spill loads at a given position for (int i = 0; i < 8; i++) { bool b1 = (i & 4) != 0; bool b2 = (i & 2) != 0; bool b3 = (i & 1) != 0; bool orig_b1 = b1, orig_b2 = b2, orig_b3 = b3; if (ref_bool(i, ref b1, ref b2, ref b3) != 0) return 4 * i + 1; if (b1 != !orig_b1) return 4 * i + 2; if (b2 != !orig_b2) return 4 * i + 3; if (b3 != !orig_b3) return 4 * i + 4; } return 0; } static int decode_len (out int pos) { pos = 19; return 10; } static void clobber_all (int pos) { for (int i = 0; i < 10; ++i) for (int j = 0; j < 10; ++j) for (int k = 0; k < 10; ++k) for (int l = 0; l < 10; ++l) ; } public static int test_29_volatile_regress_2 () { int pos = 0; int len = decode_len (out pos); call_clobber_inner (); pos += len; clobber_all (pos); return pos; } public static int test_0_clobber_regress_1 () { object[] a11 = new object [10]; object o = new Object (); // A spill load is inserted before the backward branch, clobbering one of the // registers used in the comparison for (int i = 0; i < 10; ++i) a11 [i] = null; return 0; } static int return_arg (int i) { return i; } public static int test_0_spill_regress_1 () { int j = 5; for (int i = 0; i < 3; i++) { // i is spilled by the call, then reloaded for the loop check // make sure the move from its first reg to its second is inserted in the // if body bblock, not the for body bblock if (i == 0) { } else { if (return_arg (j) != 5) return 1; } } return 0; } public static int test_0_spill_regress_2 () { double[] temporaries = new double[3]; for (int i = 0; i < 3; i++) { // i and temporaries are spilled by the call, then reloaded after the call // make sure the two moves inserted in the if bblock are in the proper order if (i == 0) { } else { temporaries [i] = return_arg (i); } } return 0; } static int many_args_unused (int i, int j, int k, int l, int m, int n, int p, int q) { return 0; } public static int test_0_unused_args () { return many_args_unused (0, 1, 2, 3, 4, 5, 6, 7); } public unsafe void ClearBuffer (byte *buffer, int i) { // Avoid inlining byte *b = stackalloc byte [4]; } public unsafe bool instance_method_1 (string s, string target, int start, int length, int opt) { byte* alwaysMatchFlags = stackalloc byte [16]; byte* neverMatchFlags = stackalloc byte [16]; byte* targetSortKey = stackalloc byte [4]; byte* sk1 = stackalloc byte [4]; byte* sk2 = stackalloc byte [4]; ClearBuffer (alwaysMatchFlags, 16); ClearBuffer (neverMatchFlags, 16); ClearBuffer (targetSortKey, 4); ClearBuffer (sk1, 4); ClearBuffer (sk2, 4); return this == null && s == target && start == length && length == opt && alwaysMatchFlags == neverMatchFlags && neverMatchFlags == targetSortKey && sk1 == sk2; } public static int test_0_spill_regress_3 () { new Tests ().instance_method_1 (null, null, 0, 0, 0); return 0; } unsafe bool MatchesBackward (string s, ref int idx, int end, int orgStart, int ti, byte* sortkey, bool noLv4, ref object ctx) { // Avoid inlining byte *b = stackalloc byte [4]; if (ctx == null) throw new Exception (); idx -= 1; return false; } unsafe int LastIndexOfSortKey (string s, int start, int orgStart, int length, byte* sortkey, int ti, bool noLv4, ref object ctx) { // ctx is initially allocated to the stack, when it is reloaded before the call, // %rax is spilled to free up the register, then ctx is allocated to %rax for its // whole lifetime, but %rax is not available for this since it is clobbered by the // call int end = start - length; int idx = start; while (idx > end) { int cur = idx; if (MatchesBackward (s, ref idx, end, orgStart, ti, sortkey, noLv4, ref ctx)) return cur; } return -1; } public unsafe static int test_0_spill_regress_4 () { object o = new Object (); new Tests ().LastIndexOfSortKey ("", 10, 0, 5, null, 0, false, ref o); return 0; } public static bool IsEqual (Type type, Type base_type) { return (type.GetHashCode () == base_type.GetHashCode ()); } public static bool IsNestedFamilyAccessible (Type type, Type base_type) { do { if (IsEqual (type, base_type)) return true; type = type.DeclaringType; } while (type != null); return false; } public static int test_0_do_while_critical_edges () { IsNestedFamilyAccessible (typeof (int), typeof (object)); return 0; } public static string return_string (string s) { for (int i = 0; i < 1000; ++i) ; return s; } public static int test_0_switch_critical_edges () { // A spill load is inserted at the end of the bblock containing the OP_BR_REG, // overwriting the source reg of the OP_BR_REG. The edge is not really // a critical edge, since its source bblock only has 1 exit, but it must // be treated as such. for (int i=0; i < UInt16.MaxValue; i++) { Char c = Convert.ToChar (i); switch (i) { case 0x0009: case 0x000A: case 0x000B: case 0x2028: case 0x2029: case 0x202F: case 0x205F: case 0x3000: //Console.WriteLine ((i.ToString () + (int)c)); return_string ((i.ToString () + (int)c)); break; default: break; } } return 0; } }