[runtime] Emit the necessary left shift anding in the LambdaCompiler
authorAlexander Kyte <alexmkyte@gmail.com>
Mon, 1 Jun 2015 18:14:00 +0000 (18:14 +0000)
committerAlexander Kyte <alexmkyte@gmail.com>
Tue, 2 Jun 2015 19:31:00 +0000 (19:31 +0000)
We were observing dtest-006.exe test failing on armhf. This test
checks that a right shift with a negative shift amount and a
dynamic base is shifted by the right amount.

We were failing it because we were excluding the step that we
do in regular code generation, which is to do a binary and of the shift
amount so it behaves like we are shifting by the original shift
amount modulo 32. The C# spec defines left shift like so.

This commit adds that to the LambdaCompiler.

mcs/class/dlr/Runtime/Microsoft.Scripting.Core/Compiler/LambdaCompiler.Binary.cs
mcs/tests/dtest-061.cs [new file with mode: 0644]

index a089b81222dbe6bee0fc3f37fafe6c16f0ef4b0f..3c9ec62326ebec9c3bac530b44415aacaa4a0e2c 100644 (file)
@@ -275,6 +275,12 @@ namespace System.Linq.Expressions.Compiler {
                     if (rightType != typeof(int)) {
                         throw ContractUtils.Unreachable;
                     }
+                    // Note: If this code is made to handle unsigned
+                    // rightType types, emit the following when rightType:
+                    // is unsigned
+                    //_ilg.EmitInt(0x3f);
+                    _ilg.EmitInt(0x1f);
+                    _ilg.Emit(OpCodes.And);
                     _ilg.Emit(OpCodes.Shl);
                     break;
                 case ExpressionType.RightShift:
diff --git a/mcs/tests/dtest-061.cs b/mcs/tests/dtest-061.cs
new file mode 100644 (file)
index 0000000..de16049
--- /dev/null
@@ -0,0 +1,63 @@
+using System;
+
+namespace Test
+{
+       public class Program
+       {
+               static int[] testValues = {0, -1, 200, -200, 32, -32, 64, -128, 333, 5};
+
+               dynamic dynBase;
+               dynamic dynAmt;
+
+               int? optBase;
+               int? optAmt;
+
+               int normBase;
+               int normAmt;
+
+               dynamic uDynBase;
+
+               public static void Main ()
+               {
+                       var tester = new Program ();
+
+                       foreach (int baseVal in testValues)
+                               foreach (int amt in testValues)
+                                       tester.ShiftTest (baseVal, amt);
+               }
+
+               public static void AreEqual<A, B> (A a, B b)
+               {
+                       if (!a.Equals (b))
+                               throw new Exception (
+                                       String.Format (
+                                               "Shift Equality Assertion Failed: Had {0} and expected {1}", a, b));
+               }
+
+               public void ShiftTest (int shiftBase, int shiftAmt)
+               {
+                       optBase = dynBase = normBase = shiftBase;
+                       optAmt = dynAmt = normAmt = shiftAmt;
+                       int immediate = shiftBase << shiftAmt;
+
+                       AreEqual<int?, int?> (dynBase << dynAmt, immediate);
+                       AreEqual<int?, int?> (dynBase << optAmt, immediate);
+                       AreEqual<int?, int?> (dynBase << normAmt, immediate);
+
+                       AreEqual<int?, int?> (optBase << dynAmt, immediate);
+                       AreEqual<int?, int?> (optBase << optAmt, immediate);
+                       AreEqual<int?, int?> (optBase << normAmt, immediate);
+
+                       AreEqual<int?, int?> (normBase << dynAmt, immediate);
+                       AreEqual<int?, int?> (normBase << optAmt, immediate);
+                       AreEqual<int?, int?> (normBase << normAmt, immediate);
+
+                       uint uShiftBase = (uint)shiftBase;
+                       uDynBase = uShiftBase;
+
+                       AreEqual<uint?, uint?> (uShiftBase << dynAmt, uDynBase << dynAmt);
+                       AreEqual<uint?, uint?> (uShiftBase << optAmt, uDynBase << optAmt);
+                       AreEqual<uint?, uint?> (uShiftBase << normAmt, uDynBase << normAmt);
+               }
+       }
+}