Fix StubLinkerCPU::EmitMovConstant (#53510)
authorJan Vorlicek <jan.vorlicek@volny.cz>
Tue, 1 Jun 2021 04:59:48 +0000 (06:59 +0200)
committerGitHub <noreply@github.com>
Tue, 1 Jun 2021 04:59:48 +0000 (21:59 -0700)
The method has a bug that caused it to early out for constants with
lowest 16, 24 or 32 bit being zero. The checks are inverse.
This issue caused failures in System.CodeDom.Tests after my change that
changed code heaps and resulted in the allocations starting at 64kB
aligned address. The failure could happen even before my change, but
extremely rarely, depending on where the heap virtual memory is located.

This change fixes the problem.

src/coreclr/vm/arm64/stubs.cpp

index acacdf8..bfff364 100644 (file)
@@ -1331,23 +1331,19 @@ void StubLinkerCPU::EmitMovConstant(IntReg target, UINT64 constant)
         // MOVK Rd, <2nd word>, LSL 1
         // MOVK Rd, <3nd word>, LSL 2
         // MOVK Rd, <4nd word>, LSL 3
-        WORD word = (WORD) (constant & WORD_MASK);
-        Emit32((DWORD)(0xD2<<24 | (4)<<21 | word<<5 | target));
-        if (!(constant & 0xFFFF)) return;
-
-        word = (WORD) ((constant>>16) & WORD_MASK);
-        if (word != 0)
-            Emit32((DWORD)(0xF2<<24 | (5)<<21 | word<<5 | target));
-        if (!(constant & 0xFFFFFFFF)) return;
-
-        word = (WORD) ((constant>>32) & WORD_MASK);
-        if (word != 0)
-            Emit32((DWORD)(0xF2<<24 | (6)<<21 | word<<5 | target));
-        if (!(constant & 0xFFFFFFFFFFFF)) return;
-
-        word = (WORD) ((constant>>48) & WORD_MASK);
-        if (word != 0)
-            Emit32((DWORD)(0xF2<<24 | (7)<<21 | word<<5 | target));
+
+        DWORD movInstr = 0xD2; // MOVZ
+        int shift = 0;
+        do
+        {
+            WORD word = (WORD) (constant & WORD_MASK);
+            Emit32((DWORD)(movInstr<<24 | (1 << 23) | (shift)<<21 | word<<5 | target));
+            shift++;
+            movInstr = 0xF2; // MOVK
+        }
+        while ((constant >>= 16) != 0);
+
+
 #undef WORD_MASK
 }