Replace a load with cheaper mov instruction when possible (#83458)
authorSwapnilGaikwad <swapnil.gaikwad@arm.com>
Tue, 21 Mar 2023 12:39:01 +0000 (12:39 +0000)
committerGitHub <noreply@github.com>
Tue, 21 Mar 2023 12:39:01 +0000 (05:39 -0700)
src/coreclr/jit/emitarm64.cpp
src/coreclr/jit/emitarm64.h

index ce39079d467ae19e6b5fea928e59381b0e3b3103..cc865da38e7484d6b8311e9d4d32f027765a2681 100644 (file)
@@ -16183,7 +16183,7 @@ bool emitter::IsRedundantLdStr(
 //     ins      - The instruction code
 //     reg1Attr - The emit attribute for register 1
 //     reg1     - Register 1
-//     reg2     - Encoded register 2
+//     reg2     - Register 2
 //     imm      - Immediate offset, prior to scaling by operand size
 //     size     - Operand size
 //     fmt      - Instruction format
@@ -16194,9 +16194,6 @@ bool emitter::IsRedundantLdStr(
 bool emitter::ReplaceLdrStrWithPairInstr(
     instruction ins, emitAttr reg1Attr, regNumber reg1, regNumber reg2, ssize_t imm, emitAttr size, insFormat fmt)
 {
-    // Register 2 needs conversion to unencoded value.
-    reg2 = encodingZRtoSP(reg2);
-
     RegisterOrder optimizationOrder = IsOptimizableLdrStrWithPair(ins, reg1, reg2, imm, size, fmt);
 
     if (optimizationOrder != eRO_none)
@@ -16367,4 +16364,83 @@ emitter::RegisterOrder emitter::IsOptimizableLdrStrWithPair(
     return optimisationOrder;
 }
 
+//-----------------------------------------------------------------------------------
+// IsOptimizableLdrToMov: Check if it is possible to optimize a second "ldr"
+//                        instruction into a cheaper "mov" instruction.
+//
+// Examples:            ldr     w1, [x20, #0x10]
+//                      ldr     w2, [x20, #0x10]    =>  mov     w1, w2
+//
+// Arguments:
+//     ins  - The instruction code
+//     reg1 - Register 1 number
+//     reg2 - Register 2 number
+//     imm  - Immediate offset, prior to scaling by operand size
+//     size - Operand size
+//     fmt  - Instruction format
+//
+// Return Value:
+//    true       - Optimization of the second instruction is possible
+//
+bool emitter::IsOptimizableLdrToMov(
+    instruction ins, regNumber reg1, regNumber reg2, ssize_t imm, emitAttr size, insFormat fmt)
+{
+    if (ins != INS_ldr)
+    {
+        // This instruction is not an "ldr" instruction.
+        return false;
+    }
+
+    if (ins != emitLastIns->idIns())
+    {
+        // Not successive "ldr" instructions.
+        return false;
+    }
+
+    regNumber prevReg1   = emitLastIns->idReg1();
+    regNumber prevReg2   = emitLastIns->idReg2();
+    insFormat lastInsFmt = emitLastIns->idInsFmt();
+    emitAttr  prevSize   = emitLastIns->idOpSize();
+    ssize_t   prevImm    = emitGetInsSC(emitLastIns);
+
+    if ((reg2 != prevReg2) || !isGeneralRegisterOrSP(reg2))
+    {
+        // The "register 2" should be same as previous instruction and
+        // should either be a general register or stack pointer.
+        return false;
+    }
+
+    if (prevImm != imm)
+    {
+        // Then we are loading from a different immediate offset.
+        return false;
+    }
+
+    if (!isGeneralRegister(reg1) || !isGeneralRegister(prevReg1))
+    {
+        // Either register 1 or previous register 1 is not a general register
+        // or the zero register, so we cannot optimise.
+        return false;
+    }
+
+    if (lastInsFmt != fmt)
+    {
+        // The formats of the two instructions differ.
+        return false;
+    }
+
+    if (prevReg1 == prevReg2)
+    {
+        // Then the previous load overwrote the register that we are indexing against.
+        return false;
+    }
+
+    if (prevSize != size)
+    {
+        // Operand sizes differ.
+        return false;
+    }
+
+    return true;
+}
 #endif // defined(TARGET_ARM64)
index d82f7dd833a1faa268ea662f7514620b899cdb55..7c8fac3e772c35340f3e8f979ffd8a2a0ee7ec62 100644 (file)
@@ -130,6 +130,7 @@ RegisterOrder IsOptimizableLdrStrWithPair(
     instruction ins, regNumber reg1, regNumber reg2, ssize_t imm, emitAttr size, insFormat fmt);
 bool ReplaceLdrStrWithPairInstr(
     instruction ins, emitAttr reg1Attr, regNumber reg1, regNumber reg2, ssize_t imm, emitAttr size, insFormat fmt);
+bool IsOptimizableLdrToMov(instruction ins, regNumber reg1, regNumber reg2, ssize_t imm, emitAttr size, insFormat fmt);
 
 // Try to optimize a Ldr or Str with an alternative instruction.
 inline bool OptimizeLdrStr(instruction ins,
@@ -156,6 +157,9 @@ inline bool OptimizeLdrStr(instruction ins,
         return true;
     }
 
+    // Register 2 needs conversion to unencoded value for following optimisation checks.
+    reg2 = encodingZRtoSP(reg2);
+
     // If the previous instruction was a matching load/store, then try to replace it instead of emitting.
     // Don't do this if either instruction had a local variable.
     if ((emitLastIns->idIns() == ins) && !localVar && !emitLastIns->idIsLclVar() &&
@@ -164,6 +168,13 @@ inline bool OptimizeLdrStr(instruction ins,
         return true;
     }
 
+    // If we have a second LDR instruction from the same source, then try to replace it with a MOV.
+    if (IsOptimizableLdrToMov(ins, reg1, reg2, imm, size, fmt))
+    {
+        emitIns_Mov(INS_mov, reg1Attr, reg1, emitLastIns->idReg1(), true);
+        return true;
+    }
+
     return false;
 }