JIT: Handle primitive-sized remainders overlapping padding/promotions in physical promotion (#88109)
The remainder may be separated by a bit of padding or other promoted fields but
still fit into a primitive; in this case it is still beneficial to copy it all
as a primitive, instead of falling back to a full block copy.
Example:
```csharp
private S _s;
void Foo()
{
S s = new();
s.A = 10;
s.D = 20;
s.F = 30; // A, D, F gets promoted
_s = s;
}
private struct S
{
public byte A;
public byte B;
public byte C;
public byte D;
public byte E;
public byte F;
}
```
```diff
Processing block operation [000018] that involves replacements
dst+003 <- V04 (V01.[003..004)) (last use)
dst+005 <- V05 (V01.[005..006)) (last use)
Block op remainder: [001..003) [004..005)
- => Remainder strategy: retain a full block op
+ => Remainder strategy: int at +001
```
```diff
; V00 this [V00,T01] ( 3, 3 ) ref -> rcx this class-hnd single-def
;* V01 loc0 [V01 ] ( 0, 0 ) struct ( 8) zero-ref do-not-enreg[SF] ld-addr-op
;# V02 OutArgs [V02 ] ( 1, 1 ) struct ( 0) [rsp+00H] do-not-enreg[XS] addr-exposed "OutgoingArgSpace"
;* V03 tmp1 [V03 ] ( 0, 0 ) ubyte -> zero-ref "V01.[000..001)"
;* V04 tmp2 [V04 ] ( 0, 0 ) ubyte -> zero-ref "V01.[003..004)"
;* V05 tmp3 [V05 ] ( 0, 0 ) ubyte -> zero-ref "V01.[005..006)"
; V06 tmp4 [V06,T00] ( 5, 10 ) byref -> rcx single-def "Spilling address for field-by-field copy"
;
; Lcl frame size = 0
G_M52879_IG01: ;; offset=0000H
;; size=0 bbWeight=1 PerfScore 0.00
G_M52879_IG02: ;; offset=0000H
add rcx, 8
xor eax, eax
- mov dword ptr [rcx], eax
- mov dword ptr [rcx+02H], eax
+ mov dword ptr [rcx+01H], eax
mov byte ptr [rcx], 10
mov byte ptr [rcx+03H], 20
mov byte ptr [rcx+05H], 30
- ;; size=22 bbWeight=1 PerfScore 5.50
-G_M52879_IG03: ;; offset=0016H
+ ;; size=20 bbWeight=1 PerfScore 4.50
+G_M52879_IG03: ;; offset=0014H
ret
;; size=1 bbWeight=1 PerfScore 1.00
-; Total bytes of code 23, prolog size 0, PerfScore 8.80, instruction count 8, allocated bytes for code 23 (MethodHash=
1da13170) for method Program:Foo():this (FullOpts)
+; Total bytes of code 21, prolog size 0, PerfScore 7.60, instruction count 7, allocated bytes for code 21 (MethodHash=
1da13170) for method Program:Foo():this (FullOpts)
; ============================================================
```
We have to be careful, however, since the covering segment can now contain
promoted fields. If this happens we need to make sure we write the promoted
field _after_ the remainder.