Skip to content

Commit 87b69c5

Browse files
authored
JIT: Expand recognition of struct field offset pattern (#122297)
The JIT has an optimization to recognize recomputations of field offsets, but this optimization failed to trigger in certain cases when the struct was promoted with old promotion. ```csharp public unsafe nint Test() { MyStruct dummy; return (nint)((byte*)&dummy.Field - (byte*)&dummy); } private struct MyStruct { public int A; public int Field; } ``` Before: ```asm G_M27992_IG01: ;; offset=0x0000 push rax xor eax, eax mov qword ptr [rsp], rax ;; size=7 bbWeight=1 PerfScore 2.25 G_M27992_IG02: ;; offset=0x0007 lea rax, [rsp+0x04] lea rcx, [rsp] sub rax, rcx ;; size=12 bbWeight=1 PerfScore 1.25 G_M27992_IG03: ;; offset=0x0013 add rsp, 8 ret ;; size=5 bbWeight=1 PerfScore 1.25 ``` After: ```asm G_M27992_IG02: ;; offset=0x0000 mov eax, 4 ;; size=5 bbWeight=1 PerfScore 0.25 G_M27992_IG03: ;; offset=0x0005 ret ;; size=1 bbWeight=1 PerfScore 1.00 ```
1 parent 15663b5 commit 87b69c5

1 file changed

Lines changed: 35 additions & 13 deletions

File tree

src/coreclr/jit/lclmorph.cpp

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1142,21 +1142,43 @@ class LocalAddressVisitor final : public GenTreeVisitor<LocalAddressVisitor>
11421142
{
11431143
Value& rhs = TopValue(0);
11441144
Value& lhs = TopValue(1);
1145-
if (m_compiler->opts.OptimizationEnabled() && lhs.IsAddress() && rhs.IsAddress() &&
1146-
(lhs.LclNum() == rhs.LclNum()) && (rhs.Offset() <= lhs.Offset()) &&
1147-
FitsIn<int>(lhs.Offset() - rhs.Offset()))
1145+
if (m_compiler->opts.OptimizationEnabled() && lhs.IsAddress() && rhs.IsAddress())
11481146
{
1149-
// TODO-Bug: Due to inlining we may end up with incorrectly typed SUB trees here.
1150-
assert(node->TypeIs(TYP_I_IMPL, TYP_BYREF));
1147+
LclVarDsc* lhsDsc = m_compiler->lvaGetDesc(lhs.LclNum());
1148+
LclVarDsc* rhsDsc = m_compiler->lvaGetDesc(rhs.LclNum());
11511149

1152-
ssize_t result = (ssize_t)(lhs.Offset() - rhs.Offset());
1153-
node->BashToConst(result, TYP_I_IMPL);
1154-
INDEBUG(lhs.Consume());
1155-
INDEBUG(rhs.Consume());
1156-
PopValue();
1157-
PopValue();
1158-
m_stmtModified = true;
1159-
break;
1150+
unsigned lhsLclNum = lhs.LclNum();
1151+
unsigned rhsLclNum = rhs.LclNum();
1152+
1153+
unsigned lhsOffset = lhs.Offset();
1154+
unsigned rhsOffset = rhs.Offset();
1155+
1156+
if (lhsDsc->lvIsStructField)
1157+
{
1158+
lhsLclNum = lhsDsc->lvParentLcl;
1159+
lhsOffset += lhsDsc->lvFldOffset;
1160+
}
1161+
1162+
if (rhsDsc->lvIsStructField)
1163+
{
1164+
rhsLclNum = rhsDsc->lvParentLcl;
1165+
rhsOffset += rhsDsc->lvFldOffset;
1166+
}
1167+
1168+
if ((lhsLclNum == rhsLclNum) && (rhsOffset <= lhsOffset) && FitsIn<int>(lhsOffset - rhsOffset))
1169+
{
1170+
// TODO-Bug: Due to inlining we may end up with incorrectly typed SUB trees here.
1171+
assert(node->TypeIs(TYP_I_IMPL, TYP_BYREF));
1172+
1173+
ssize_t result = (ssize_t)(lhsOffset - rhsOffset);
1174+
node->BashToConst(result, TYP_I_IMPL);
1175+
INDEBUG(lhs.Consume());
1176+
INDEBUG(rhs.Consume());
1177+
PopValue();
1178+
PopValue();
1179+
m_stmtModified = true;
1180+
break;
1181+
}
11601182
}
11611183

11621184
EscapeValue(TopValue(0), node);

0 commit comments

Comments
 (0)