RyuJIT/ARM32: encodable offsets for ld/st
authorMikhail Skvortcov <m.skvortcov@partner.samsung.com>
Wed, 12 Apr 2017 06:18:08 +0000 (09:18 +0300)
committerMikhail Skvortcov <m.skvortcov@partner.samsung.com>
Wed, 12 Apr 2017 06:32:32 +0000 (09:32 +0300)
Commit migrated from https://github.com/dotnet/coreclr/commit/21b64422dc80a21eee8dfb8a64b9136ef7a0adcc

src/coreclr/src/jit/emitarm.cpp
src/coreclr/src/jit/emitarm.h
src/coreclr/src/jit/lsraarmarch.cpp

index ebefa27..53ee88b 100644 (file)
@@ -1422,6 +1422,20 @@ DONE:
 
 /*****************************************************************************
  *
+ *  emitIns_valid_imm_for_ldst_offset() returns true when the immediate 'imm'
+ *   can be encoded as the offset in a ldr/str instruction.
+ */
+/*static*/ bool emitter::emitIns_valid_imm_for_ldst_offset(int imm, emitAttr size)
+{
+    if ((imm & 0x0fff) == imm)
+        return true; // encodable using IF_T2_K1
+    if (unsigned_abs(imm) <= 0x0ff)
+        return true; // encodable using IF_T2_H0
+    return false;
+}
+
+/*****************************************************************************
+ *
  *  Add an instruction with no operands.
  */
 
@@ -7608,10 +7622,26 @@ void emitter::emitInsLoadStoreOp(instruction ins, emitAttr attr, regNumber dataR
                 }
             }
         }
-        else
+        else // no Index
         {
-            // TODO check offset is valid for encoding
-            emitIns_R_R_I(ins, attr, dataReg, memBase->gtRegNum, offset);
+            if (emitIns_valid_imm_for_ldst_offset(offset, attr))
+            {
+                // Then load/store dataReg from/to [memBase + offset]
+                emitIns_R_R_I(ins, attr, dataReg, memBase->gtRegNum, offset);
+            }
+            else
+            {
+                // We require a tmpReg to hold the offset
+                regMaskTP tmpRegMask = indir->gtRsvdRegs;
+                regNumber tmpReg     = genRegNumFromMask(tmpRegMask);
+                noway_assert(tmpReg != REG_NA);
+
+                // First load/store tmpReg with the large offset constant
+                codeGen->instGen_Set_Reg_To_Imm(EA_PTRSIZE, tmpReg, offset);
+
+                // Then load/store dataReg from/to [memBase + tmpReg]
+                emitIns_R_R_R(ins, attr, dataReg, memBase->gtRegNum, tmpReg);
+            }
         }
     }
     else
index 4ec1893..d7c8d4d 100644 (file)
@@ -243,6 +243,7 @@ static bool emitIns_valid_imm_for_small_mov(regNumber reg, int imm, insFlags fla
 static bool emitIns_valid_imm_for_add(int imm, insFlags flags);
 static bool emitIns_valid_imm_for_cmp(int imm, insFlags flags);
 static bool emitIns_valid_imm_for_add_sp(int imm);
+static bool emitIns_valid_imm_for_ldst_offset(int imm, emitAttr size);
 
 void emitIns(instruction ins);
 
index 11fc490..7d999d8 100644 (file)
@@ -291,19 +291,13 @@ void Lowering::TreeNodeInfoInitIndir(GenTreePtr indirTree)
     if (index != nullptr && !modifiedSources)
     {
         info->srcCount++;
-
-#ifdef _TARGET_ARM_
-        info->internalIntCount++;
-#endif // _TARGET_ARM_
     }
 
-#ifdef _TARGET_ARM64_
-
-    // On ARM64 we may need a single internal register
+    // On ARM we may need a single internal register
     // (when both conditions are true then we still only need a single internal register)
     if ((index != nullptr) && (cns != 0))
     {
-        // ARM64 does not support both Index and offset so we need an internal register
+        // ARM does not support both Index and offset so we need an internal register
         info->internalIntCount = 1;
     }
     else if (!emitter::emitIns_valid_imm_for_ldst_offset(cns, emitTypeSize(indirTree)))
@@ -311,8 +305,6 @@ void Lowering::TreeNodeInfoInitIndir(GenTreePtr indirTree)
         // This offset can't be contained in the ldr/str instruction, so we need an internal register
         info->internalIntCount = 1;
     }
-
-#endif // _TARGET_ARM64_
 }
 
 //------------------------------------------------------------------------