// 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
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)
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)
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,
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() &&
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;
}