public void IsARM64CallingConvention() { IgnoreIfNotLinkAll(); #if __WATCHOS__ if (!Runtime.IsARM64CallingConvention && Runtime.Arch == Arch.DEVICE) { Assert.Ignore("Can't inline when running on armv7k."); } #endif #if DEBUG // Release builds will strip IL, so any IL checking has to be done in debug builds. MethodInfo method; IEnumerable <ILInstruction> instructions; IEnumerable <ILInstruction> call_instructions; method = typeof(BaseOptimizeGeneratedCodeTest).GetMethod(nameof(GetIsARM64CallingConventionOptimized), BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static); instructions = new ILReader(method); call_instructions = instructions.Where((v) => v.OpCode.Name == "ldsfld"); Assert.AreEqual(0, call_instructions.Count(), "optimized: no ldsfld instruction"); method = typeof(BaseOptimizeGeneratedCodeTest).GetMethod(nameof(GetIsARM64CallingConventionNotOptimized), BindingFlags.NonPublic | BindingFlags.Instance); instructions = new ILReader(method); call_instructions = instructions.Where((v) => v.OpCode.Name == "ldsfld"); Assert.AreEqual(1, call_instructions.Count(), "not optimized: 1 ldsfld instruction"); method = typeof(Runtime).GetMethod("GetIsARM64CallingConvention", BindingFlags.Static | BindingFlags.NonPublic); instructions = new ILReader(method); Assert.AreEqual(2, instructions.Count(), "IL Count"); Assert.That(instructions.Skip(0).First().OpCode, Is.EqualTo(OpCodes.Ldc_I4_0).Or.EqualTo(OpCodes.Ldc_I4_1), "IL 1"); Assert.That(instructions.Skip(1).First().OpCode, Is.EqualTo(OpCodes.Ret), "IL 2"); #endif Assert.AreEqual(Runtime.IsARM64CallingConvention, GetIsARM64CallingConventionOptimized(), "Value optimized"); Assert.AreEqual(Runtime.IsARM64CallingConvention, GetIsARM64CallingConventionNotOptimized(), "Value unoptimized"); }
public void IntPtrSizeTest() { var S8methods = new MethodInfo [] { GetType().GetMethod(nameof(Size8Test), BindingFlags.NonPublic | BindingFlags.Instance), GetType().GetMethod(nameof(Size8Test_Optimizable), BindingFlags.NonPublic | BindingFlags.Instance) }; var S4methods = new MethodInfo [] { GetType().GetMethod(nameof(Size4Test), BindingFlags.NonPublic | BindingFlags.Instance), GetType().GetMethod(nameof(Size4Test_Optimizable), BindingFlags.NonPublic | BindingFlags.Instance) }; MethodInfo[] passingMethods = null; MethodInfo[] failingMethods = null; switch (IntPtr.Size) { case 4: Size4Test(); Size4Test_Optimizable(); passingMethods = S4methods; failingMethods = S8methods; break; case 8: Size8Test(); Size8Test_Optimizable(); passingMethods = S8methods; failingMethods = S4methods; break; default: Assert.Fail("Invalid size: {0}", IntPtr.Size); break; } #if !DEBUG // Verify that the passing method is completely empty (save for nop instructions and a final ret instruction). // Unfortunately in debug mode csc produces IL sequences the optimizer doesn't understand (a lot of unnecessary instructions), // which means we can only check this in release mode. Also on device this will probably always pass, // since we strip assemblies (and the methods will always be empty), but running the test shouldn't hurt. foreach (var passingMethod in passingMethods) { IEnumerable <ILInstruction> passingInstructions = new ILReader(passingMethod); passingInstructions = passingInstructions.Where((v) => v.OpCode.Name != "nop"); Assert.AreEqual(1, passingInstructions.Count(), "empty body"); } foreach (var failingMethod in failingMethods) { IEnumerable <ILInstruction> failingInstructions = new ILReader(failingMethod); failingInstructions = failingInstructions.Where((v) => v.OpCode.Name != "nop"); Assert.That(failingInstructions.Count(), Is.GreaterThan(1), "non-empty body"); } #endif }