Skip to content

Commit c1acb35

Browse files
Replace a load with cheaper mov instruction when possible (#83458)
1 parent 8c5cf11 commit c1acb35

File tree

2 files changed

+91
-4
lines changed

2 files changed

+91
-4
lines changed

src/coreclr/jit/emitarm64.cpp

Lines changed: 80 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16183,7 +16183,7 @@ bool emitter::IsRedundantLdStr(
1618316183
// ins - The instruction code
1618416184
// reg1Attr - The emit attribute for register 1
1618516185
// reg1 - Register 1
16186-
// reg2 - Encoded register 2
16186+
// reg2 - Register 2
1618716187
// imm - Immediate offset, prior to scaling by operand size
1618816188
// size - Operand size
1618916189
// fmt - Instruction format
@@ -16194,9 +16194,6 @@ bool emitter::IsRedundantLdStr(
1619416194
bool emitter::ReplaceLdrStrWithPairInstr(
1619516195
instruction ins, emitAttr reg1Attr, regNumber reg1, regNumber reg2, ssize_t imm, emitAttr size, insFormat fmt)
1619616196
{
16197-
// Register 2 needs conversion to unencoded value.
16198-
reg2 = encodingZRtoSP(reg2);
16199-
1620016197
RegisterOrder optimizationOrder = IsOptimizableLdrStrWithPair(ins, reg1, reg2, imm, size, fmt);
1620116198

1620216199
if (optimizationOrder != eRO_none)
@@ -16367,4 +16364,83 @@ emitter::RegisterOrder emitter::IsOptimizableLdrStrWithPair(
1636716364
return optimisationOrder;
1636816365
}
1636916366

16367+
//-----------------------------------------------------------------------------------
16368+
// IsOptimizableLdrToMov: Check if it is possible to optimize a second "ldr"
16369+
// instruction into a cheaper "mov" instruction.
16370+
//
16371+
// Examples: ldr w1, [x20, #0x10]
16372+
// ldr w2, [x20, #0x10] => mov w1, w2
16373+
//
16374+
// Arguments:
16375+
// ins - The instruction code
16376+
// reg1 - Register 1 number
16377+
// reg2 - Register 2 number
16378+
// imm - Immediate offset, prior to scaling by operand size
16379+
// size - Operand size
16380+
// fmt - Instruction format
16381+
//
16382+
// Return Value:
16383+
// true - Optimization of the second instruction is possible
16384+
//
16385+
bool emitter::IsOptimizableLdrToMov(
16386+
instruction ins, regNumber reg1, regNumber reg2, ssize_t imm, emitAttr size, insFormat fmt)
16387+
{
16388+
if (ins != INS_ldr)
16389+
{
16390+
// This instruction is not an "ldr" instruction.
16391+
return false;
16392+
}
16393+
16394+
if (ins != emitLastIns->idIns())
16395+
{
16396+
// Not successive "ldr" instructions.
16397+
return false;
16398+
}
16399+
16400+
regNumber prevReg1 = emitLastIns->idReg1();
16401+
regNumber prevReg2 = emitLastIns->idReg2();
16402+
insFormat lastInsFmt = emitLastIns->idInsFmt();
16403+
emitAttr prevSize = emitLastIns->idOpSize();
16404+
ssize_t prevImm = emitGetInsSC(emitLastIns);
16405+
16406+
if ((reg2 != prevReg2) || !isGeneralRegisterOrSP(reg2))
16407+
{
16408+
// The "register 2" should be same as previous instruction and
16409+
// should either be a general register or stack pointer.
16410+
return false;
16411+
}
16412+
16413+
if (prevImm != imm)
16414+
{
16415+
// Then we are loading from a different immediate offset.
16416+
return false;
16417+
}
16418+
16419+
if (!isGeneralRegister(reg1) || !isGeneralRegister(prevReg1))
16420+
{
16421+
// Either register 1 or previous register 1 is not a general register
16422+
// or the zero register, so we cannot optimise.
16423+
return false;
16424+
}
16425+
16426+
if (lastInsFmt != fmt)
16427+
{
16428+
// The formats of the two instructions differ.
16429+
return false;
16430+
}
16431+
16432+
if (prevReg1 == prevReg2)
16433+
{
16434+
// Then the previous load overwrote the register that we are indexing against.
16435+
return false;
16436+
}
16437+
16438+
if (prevSize != size)
16439+
{
16440+
// Operand sizes differ.
16441+
return false;
16442+
}
16443+
16444+
return true;
16445+
}
1637016446
#endif // defined(TARGET_ARM64)

src/coreclr/jit/emitarm64.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ RegisterOrder IsOptimizableLdrStrWithPair(
130130
instruction ins, regNumber reg1, regNumber reg2, ssize_t imm, emitAttr size, insFormat fmt);
131131
bool ReplaceLdrStrWithPairInstr(
132132
instruction ins, emitAttr reg1Attr, regNumber reg1, regNumber reg2, ssize_t imm, emitAttr size, insFormat fmt);
133+
bool IsOptimizableLdrToMov(instruction ins, regNumber reg1, regNumber reg2, ssize_t imm, emitAttr size, insFormat fmt);
133134

134135
// Try to optimize a Ldr or Str with an alternative instruction.
135136
inline bool OptimizeLdrStr(instruction ins,
@@ -156,6 +157,9 @@ inline bool OptimizeLdrStr(instruction ins,
156157
return true;
157158
}
158159

160+
// Register 2 needs conversion to unencoded value for following optimisation checks.
161+
reg2 = encodingZRtoSP(reg2);
162+
159163
// If the previous instruction was a matching load/store, then try to replace it instead of emitting.
160164
// Don't do this if either instruction had a local variable.
161165
if ((emitLastIns->idIns() == ins) && !localVar && !emitLastIns->idIsLclVar() &&
@@ -164,6 +168,13 @@ inline bool OptimizeLdrStr(instruction ins,
164168
return true;
165169
}
166170

171+
// If we have a second LDR instruction from the same source, then try to replace it with a MOV.
172+
if (IsOptimizableLdrToMov(ins, reg1, reg2, imm, size, fmt))
173+
{
174+
emitIns_Mov(INS_mov, reg1Attr, reg1, emitLastIns->idReg1(), true);
175+
return true;
176+
}
177+
167178
return false;
168179
}
169180

0 commit comments

Comments
 (0)