@@ -5844,6 +5844,12 @@ void emitter::emitIns_R_R_I(instruction ins,
5844
5844
return;
5845
5845
}
5846
5846
5847
+ if ((reg1 == reg2) && (EA_SIZE(attr) == EA_PTRSIZE) && emitComp->opts.OptimizationEnabled() &&
5848
+ OptimizePostIndexed(ins, reg1, imm, attr))
5849
+ {
5850
+ return;
5851
+ }
5852
+
5847
5853
reg1 = encodingSPtoZR(reg1);
5848
5854
reg2 = encodingSPtoZR(reg2);
5849
5855
}
@@ -11070,6 +11076,37 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp)
11070
11076
code |= ((code_t)imm << 12); // iiiiiiiii
11071
11077
code |= insEncodeReg_Rn(id->idReg2()); // nnnnn
11072
11078
dst += emitOutput_Instr(dst, code);
11079
+
11080
+ // With pre or post-indexing we may have a second GC register to
11081
+ // update.
11082
+ if (insOptsIndexed(id->idInsOpt()) && !id->idIsSmallDsc())
11083
+ {
11084
+ if (emitInsIsLoad(ins))
11085
+ {
11086
+ // Load will write the destination (reg1).
11087
+ if (id->idGCref() != GCT_NONE)
11088
+ {
11089
+ emitGCregLiveUpd(id->idGCref(), id->idReg1(), dst);
11090
+ }
11091
+ else
11092
+ {
11093
+ emitGCregDeadUpd(id->idReg1(), dst);
11094
+ }
11095
+ }
11096
+
11097
+ // We will always write reg2.
11098
+ if (id->idGCrefReg2() != GCT_NONE)
11099
+ {
11100
+ emitGCregLiveUpd(id->idGCrefReg2(), id->idReg2(), dst);
11101
+ }
11102
+ else
11103
+ {
11104
+ emitGCregDeadUpd(id->idReg2(), dst);
11105
+ }
11106
+
11107
+ goto SKIP_GC_UPDATE;
11108
+ }
11109
+
11073
11110
break;
11074
11111
11075
11112
case IF_LS_2D: // LS_2D .Q.............. ....ssnnnnnttttt Vt Rn
@@ -17150,6 +17187,127 @@ bool emitter::IsOptimizableLdrToMov(
17150
17187
return true;
17151
17188
}
17152
17189
17190
+ //-----------------------------------------------------------------------------------
17191
+ // OptimizePostIndexed: Optimize an addition/subtraction from a register by
17192
+ // replacing the previous instruction with a post-indexed addressing form if
17193
+ // possible.
17194
+ //
17195
+ // Arguments:
17196
+ // ins - Whether this is an add or subtraction
17197
+ // reg - The register that is being updated
17198
+ // imm - Immediate that is being added/subtracted
17199
+ //
17200
+ // Returns:
17201
+ // True if the previous instruction was optimized to perform the add/sub.
17202
+ //
17203
+ bool emitter::OptimizePostIndexed(instruction ins, regNumber reg, ssize_t imm, emitAttr regAttr)
17204
+ {
17205
+ assert((ins == INS_add) || (ins == INS_sub));
17206
+
17207
+ if (!emitCanPeepholeLastIns() || !emitInsIsLoadOrStore(emitLastIns->idIns()))
17208
+ {
17209
+ return false;
17210
+ }
17211
+
17212
+ if ((emitLastIns->idInsFmt() != IF_LS_2A) || emitLastIns->idIsTlsGD())
17213
+ {
17214
+ return false;
17215
+ }
17216
+
17217
+ // Cannot allow post indexing if the load itself is already modifying the
17218
+ // register.
17219
+ regNumber loadStoreDataReg = emitLastIns->idReg1();
17220
+ if (loadStoreDataReg == reg)
17221
+ {
17222
+ return false;
17223
+ }
17224
+
17225
+ // We must be updating the same register that the addressing is happening
17226
+ // on. The SP register is stored as ZR, so make sure to normalize that too.
17227
+ regNumber loadStoreAddrReg = encodingZRtoSP(emitLastIns->idReg2());
17228
+ if (loadStoreAddrReg != reg)
17229
+ {
17230
+ return false;
17231
+ }
17232
+
17233
+ // Only some stores/loads are eligible
17234
+ switch (emitLastIns->idIns())
17235
+ {
17236
+ case INS_ldrb:
17237
+ case INS_strb:
17238
+ case INS_ldurb:
17239
+ case INS_sturb:
17240
+ case INS_ldrh:
17241
+ case INS_strh:
17242
+ case INS_ldurh:
17243
+ case INS_sturh:
17244
+ case INS_ldrsb:
17245
+ case INS_ldursb:
17246
+ case INS_ldrsh:
17247
+ case INS_ldursh:
17248
+ case INS_ldrsw:
17249
+ case INS_ldursw:
17250
+ case INS_ldr:
17251
+ case INS_str:
17252
+ case INS_ldur:
17253
+ case INS_stur:
17254
+ break;
17255
+
17256
+ default:
17257
+ return false;
17258
+ }
17259
+
17260
+ if (ins == INS_sub)
17261
+ {
17262
+ imm = -imm;
17263
+ }
17264
+
17265
+ // Only some post-indexing offsets can be represented.
17266
+ if ((imm < -256) || (imm >= 256))
17267
+ {
17268
+ return false;
17269
+ }
17270
+
17271
+ instruction newIns = emitLastIns->idIns();
17272
+ emitAttr newAttr;
17273
+
17274
+ switch (emitLastIns->idGCref())
17275
+ {
17276
+ case GCT_BYREF:
17277
+ newAttr = EA_BYREF;
17278
+ break;
17279
+ case GCT_GCREF:
17280
+ newAttr = EA_GCREF;
17281
+ break;
17282
+ default:
17283
+ newAttr = emitLastIns->idOpSize();
17284
+ break;
17285
+ }
17286
+
17287
+ emitRemoveLastInstruction();
17288
+
17289
+ instrDesc* id = emitNewInstrCns(newAttr, imm);
17290
+ id->idIns(newIns);
17291
+ id->idInsFmt(IF_LS_2C);
17292
+ id->idInsOpt(INS_OPTS_POST_INDEX);
17293
+
17294
+ id->idReg1(loadStoreDataReg);
17295
+ id->idReg2(encodingSPtoZR(loadStoreAddrReg));
17296
+
17297
+ if (EA_IS_BYREF(regAttr))
17298
+ {
17299
+ id->idGCrefReg2(GCT_BYREF);
17300
+ }
17301
+ else if (EA_IS_GCREF(regAttr))
17302
+ {
17303
+ id->idGCrefReg2(GCT_GCREF);
17304
+ }
17305
+
17306
+ dispIns(id);
17307
+ appendToCurIG(id);
17308
+ return true;
17309
+ }
17310
+
17153
17311
#if defined(FEATURE_SIMD)
17154
17312
//-----------------------------------------------------------------------------------
17155
17313
// emitStoreSimd12ToLclOffset: store SIMD12 value from dataReg to varNum+offset.
0 commit comments