Skip to content

Commit b0a593d

Browse files
authored
Implement chained field access fusion (#20249)
1 parent 068e53b commit b0a593d

38 files changed

Lines changed: 3417 additions & 383 deletions

third_party/move/mono-move/core/src/instruction/mod.rs

Lines changed: 150 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,9 @@ pub enum MicroOp {
362362
imm: Box<[u8; 32]>,
363363
},
364364

365-
/// Copy 8 bytes from `src` to `dst`.
365+
/// Copy 8 bytes from `src` to `dst`. Neither slot need be 8-aligned: a
366+
/// size-8 aggregate (e.g. `{u32, u32}`, align 4) can sit at a 4-aligned
367+
/// field offset.
366368
Move8 {
367369
dst: FrameOffset,
368370
src: FrameOffset,
@@ -953,6 +955,25 @@ pub enum MicroOp {
953955
size: u32,
954956
},
955957

958+
/// Read within a heap object at a static offset: `obj_ref` is a fat pointer
959+
/// whose target holds the heap object pointer; copies `size` bytes at byte
960+
/// `offset` within the object into `dst`.
961+
HeapReadOffset {
962+
dst: FrameOffset,
963+
obj_ref: FrameOffset,
964+
offset: u32,
965+
size: u32,
966+
},
967+
968+
/// Write within a heap object at a static offset: copies `size` bytes
969+
/// from `src` to byte `offset` within the object.
970+
HeapWriteOffset {
971+
obj_ref: FrameOffset,
972+
offset: u32,
973+
src: FrameOffset,
974+
size: u32,
975+
},
976+
956977
/// Copies the 16-byte fat pointer from `src_ref` to `dst_ref`, while
957978
/// adding `offset` to the offset part of the fat pointer.
958979
///
@@ -1012,6 +1033,9 @@ pub enum MicroOp {
10121033
},
10131034

10141035
/// Copy 8 bytes from a heap object at `heap_ptr + offset` into `dst`.
1036+
/// Neither `dst` nor `heap_ptr + offset` need be 8-aligned: a size-8
1037+
/// aggregate (e.g. `{u32, u32}`, align 4) can sit at a 4-aligned slot
1038+
/// or field offset.
10151039
HeapMoveFrom8 {
10161040
dst: FrameOffset,
10171041
heap_ptr: FrameOffset,
@@ -1027,13 +1051,17 @@ pub enum MicroOp {
10271051
},
10281052

10291053
/// Copy 8 bytes from `src` into a heap object at `heap_ptr + offset`.
1054+
/// Neither `src` nor `heap_ptr + offset` need be 8-aligned: a size-8
1055+
/// aggregate (e.g. `{u32, u32}`, align 4) can sit at a 4-aligned slot
1056+
/// or field offset.
10301057
HeapMoveTo8 {
10311058
heap_ptr: FrameOffset,
10321059
offset: u32,
10331060
src: FrameOffset,
10341061
},
10351062

10361063
/// Write an immediate u64 into a heap object at `heap_ptr + offset`.
1064+
/// `heap_ptr + offset` need not be 8-aligned (see `HeapMoveTo8`).
10371065
HeapMoveToImm8 {
10381066
heap_ptr: FrameOffset,
10391067
offset: u32,
@@ -1177,12 +1205,13 @@ pub enum MicroOp {
11771205
/// If `None` (the runtime variant does not declare the field), aborts with
11781206
/// a variant mismatch (expected Move semantics).
11791207
///
1180-
/// `off` is the full object-relative offset (already includes
1181-
/// `ENUM_DATA_OFFSET`); indexing by tag handles a field shared across
1182-
/// variants that sits at different byte offsets in each. An access whose
1183-
/// handle covers every variant, all placing the field at one fixed offset,
1184-
/// uses the static `enum_borrow` (`HeapBorrow`) fast path instead.
1185-
EnumBorrowVariantField {
1208+
/// Each `off` is measured from the object's start — the `ENUM_DATA_OFFSET`
1209+
/// tag skip is folded in when the op is constructed. Indexing by tag
1210+
/// handles a field shared across variants that sits at different byte
1211+
/// offsets in each. An access whose handle covers every variant, all
1212+
/// placing the field at one fixed offset, uses the [`MicroOp::HeapBorrow`]
1213+
/// fast path instead.
1214+
EnumBorrowVariantFieldByTag {
11861215
dst: FrameOffset,
11871216
enum_ref: FrameOffset,
11881217
// TODO(perf): the boxed slice is a separate allocation and a
@@ -1215,38 +1244,33 @@ pub enum MicroOp {
12151244
variant: VariantTag,
12161245
},
12171246

1218-
/// Read a variant field by value through an enum reference at a static
1219-
/// object-relative `offset`. The uniform-offset fast path: the access's
1220-
/// handle covers every variant, all placing the field at the same offset,
1221-
/// so no runtime tag dispatch or mismatch check is needed. Derefs the
1222-
/// 16-byte `enum_ref` fat pointer to the heap object (a double deref), then
1223-
/// copies `size` bytes from `obj + offset` into `dst`. Fuses the
1224-
/// `HeapBorrow` + `ReadRef` (the divergent path still routes through a
1225-
/// scratch reference).
1226-
///
1227-
// TODO(cleanup): nothing here is enum-specific — this reads any field through a
1228-
// reference at a static offset. Rename to a non-enum-specific name as part
1229-
// of a naming-consistency pass.
1230-
EnumReadVariantField {
1247+
/// Read a variant field by value through an enum reference, selecting the
1248+
/// field's object byte offset by the runtime variant tag: derefs the
1249+
/// 16-byte `enum_ref` fat pointer to the heap object, reads the tag, and
1250+
/// if `offsets[tag]` is `Some(off)` copies `size` bytes at byte `off`
1251+
/// within the object into `dst`; a `None` hole (the runtime variant does
1252+
/// not declare the field) aborts with a variant mismatch. Each `off` is
1253+
/// measured from the object's start — the `ENUM_DATA_OFFSET` tag skip is
1254+
/// folded in when the op is constructed. When every variant places the
1255+
/// field at one offset, [`MicroOp::HeapReadOffset`] is used instead.
1256+
EnumReadVariantFieldByTag {
12311257
dst: FrameOffset,
12321258
enum_ref: FrameOffset,
1233-
offset: u32,
1259+
// See `EnumBorrowVariantFieldByTag::offsets` for the boxed-slice rationale
1260+
// and the `size_of::<MicroOp>() == 48` constraint.
1261+
offsets: Box<[Option<u32>]>,
12341262
size: u32,
12351263
},
12361264

1237-
/// Write a variant field by value through an enum reference at a static
1238-
/// object-relative `offset` (uniform-offset fast path; see
1239-
/// [`MicroOp::EnumReadVariantField`]). Derefs the 16-byte `enum_ref` fat
1240-
/// pointer to the heap object, then copies `size` bytes from `src` into
1241-
/// `obj + offset`. Fuses `HeapBorrow` + `WriteRef` (the divergent path
1242-
/// still routes through a scratch reference).
1243-
///
1244-
// TODO(cleanup): nothing here is enum-specific — this writes any field through a
1245-
// reference at a static offset, and is reusable when fusing. Rename to a
1246-
// non-enum-specific name as part of a naming-consistency pass.
1247-
EnumWriteVariantField {
1265+
/// Write a variant field by value through an enum reference, selecting the
1266+
/// field's object byte offset by the runtime variant tag (symmetric
1267+
/// counterpart to [`MicroOp::EnumReadVariantFieldByTag`]). Aborts with a
1268+
/// variant mismatch when `offsets[tag]` is `None`. When every variant
1269+
/// places the field at one offset, [`MicroOp::HeapWriteOffset`] is used
1270+
/// instead.
1271+
EnumWriteVariantFieldByTag {
12481272
enum_ref: FrameOffset,
1249-
offset: u32,
1273+
offsets: Box<[Option<u32>]>,
12501274
src: FrameOffset,
12511275
size: u32,
12521276
},
@@ -1944,14 +1968,14 @@ impl fmt::Display for MicroOp {
19441968
dst.0, enum_ref.0, variant
19451969
)
19461970
},
1947-
MicroOp::EnumBorrowVariantField {
1971+
MicroOp::EnumBorrowVariantFieldByTag {
19481972
dst,
19491973
enum_ref,
19501974
offsets,
19511975
} => {
19521976
write!(
19531977
f,
1954-
"EnumBorrowVariantField [{}] <- &(*[{}]) by tag {:?}",
1978+
"EnumBorrowVariantFieldByTag [{}] <- &(*[{}]) by tag {:?}",
19551979
dst.0, enum_ref.0, offsets
19561980
)
19571981
},
@@ -1973,28 +1997,52 @@ impl fmt::Display for MicroOp {
19731997
dst.0, descriptor_id, variant
19741998
)
19751999
},
1976-
MicroOp::EnumReadVariantField {
2000+
MicroOp::HeapReadOffset {
19772001
dst,
1978-
enum_ref,
2002+
obj_ref,
19792003
offset,
19802004
size,
19812005
} => {
19822006
write!(
19832007
f,
1984-
"EnumReadVariantField({}) [{}] <- (*[{}]).{}",
1985-
size, dst.0, enum_ref.0, offset
2008+
"HeapReadOffset({}) [{}] <- (*[{}]).{}",
2009+
size, dst.0, obj_ref.0, offset
19862010
)
19872011
},
1988-
MicroOp::EnumWriteVariantField {
1989-
enum_ref,
2012+
MicroOp::HeapWriteOffset {
2013+
obj_ref,
19902014
offset,
19912015
src,
19922016
size,
19932017
} => {
19942018
write!(
19952019
f,
1996-
"EnumWriteVariantField({}) (*[{}]).{} <- [{}]",
1997-
size, enum_ref.0, offset, src.0
2020+
"HeapWriteOffset({}) (*[{}]).{} <- [{}]",
2021+
size, obj_ref.0, offset, src.0
2022+
)
2023+
},
2024+
MicroOp::EnumReadVariantFieldByTag {
2025+
dst,
2026+
enum_ref,
2027+
offsets,
2028+
size,
2029+
} => {
2030+
write!(
2031+
f,
2032+
"EnumReadVariantFieldByTag({}) [{}] <- (*[{}]) by tag {:?}",
2033+
size, dst.0, enum_ref.0, offsets
2034+
)
2035+
},
2036+
MicroOp::EnumWriteVariantFieldByTag {
2037+
enum_ref,
2038+
offsets,
2039+
src,
2040+
size,
2041+
} => {
2042+
write!(
2043+
f,
2044+
"EnumWriteVariantFieldByTag({}) (*[{}]) <- [{}] by tag {:?}",
2045+
size, enum_ref.0, src.0, offsets
19982046
)
19992047
},
20002048
MicroOp::DeepCopyHeapPtrs { base, offsets } => {
@@ -2267,10 +2315,12 @@ impl MicroOp {
22672315
| MicroOp::BoolAnd { .. }
22682316
| MicroOp::BoolOr { .. }
22692317
| MicroOp::EnumTestTag { .. }
2270-
| MicroOp::EnumBorrowVariantField { .. }
2318+
| MicroOp::EnumBorrowVariantFieldByTag { .. }
22712319
| MicroOp::EnumCheckVariant { .. }
2272-
| MicroOp::EnumReadVariantField { .. }
2273-
| MicroOp::EnumWriteVariantField { .. } => false,
2320+
| MicroOp::HeapReadOffset { .. }
2321+
| MicroOp::HeapWriteOffset { .. }
2322+
| MicroOp::EnumReadVariantFieldByTag { .. }
2323+
| MicroOp::EnumWriteVariantFieldByTag { .. } => false,
22742324
}
22752325
}
22762326

@@ -2343,24 +2393,30 @@ impl MicroOp {
23432393
}
23442394
}
23452395

2396+
/// Shift each present data-region-relative offset by [`ENUM_DATA_OFFSET`] to
2397+
/// a full object-relative offset; `None` holes (variants lacking the field)
2398+
/// pass through.
2399+
fn to_object_relative_offsets(data_relative_offsets: &[Option<u32>]) -> Box<[Option<u32>]> {
2400+
data_relative_offsets
2401+
.iter()
2402+
.map(|maybe_offset| maybe_offset.map(|offset| ENUM_DATA_OFFSET as u32 + offset))
2403+
.collect()
2404+
}
2405+
23462406
/// Tag-dispatched variant-field borrow. `data_relative_offsets[tag]` is the
23472407
/// field's data-region-relative offset in that variant, or `None` if the
23482408
/// variant does not declare the field (borrowing it aborts). Offsets are
23492409
/// shifted by `ENUM_DATA_OFFSET` to full object-relative offsets, matching
23502410
/// `enum_borrow`.
2351-
pub fn enum_borrow_variant_field(
2411+
pub fn enum_borrow_variant_field_by_tag(
23522412
enum_ref: FrameOffset,
23532413
data_relative_offsets: &[Option<u32>],
23542414
dst: FrameOffset,
23552415
) -> Self {
2356-
let offsets = data_relative_offsets
2357-
.iter()
2358-
.map(|maybe_offset| maybe_offset.map(|offset| ENUM_DATA_OFFSET as u32 + offset))
2359-
.collect();
2360-
MicroOp::EnumBorrowVariantField {
2416+
MicroOp::EnumBorrowVariantFieldByTag {
23612417
dst,
23622418
enum_ref,
2363-
offsets,
2419+
offsets: Self::to_object_relative_offsets(data_relative_offsets),
23642420
}
23652421
}
23662422

@@ -2380,14 +2436,14 @@ impl MicroOp {
23802436
/// data-region-relative and shifted by `ENUM_DATA_OFFSET` to a full
23812437
/// object-relative offset, matching [`MicroOp::enum_borrow`].
23822438
pub fn enum_read_variant_field(
2383-
enum_ref: FrameOffset,
2439+
obj_ref: FrameOffset,
23842440
field_offset: u32,
23852441
dst: FrameOffset,
23862442
size: u32,
23872443
) -> Self {
2388-
MicroOp::EnumReadVariantField {
2444+
MicroOp::HeapReadOffset {
23892445
dst,
2390-
enum_ref,
2446+
obj_ref,
23912447
offset: ENUM_DATA_OFFSET as u32 + field_offset,
23922448
size,
23932449
}
@@ -2396,19 +2452,54 @@ impl MicroOp {
23962452
/// Uniform-offset variant-field write by value; offset handling mirrors
23972453
/// [`MicroOp::enum_read_variant_field`].
23982454
pub fn enum_write_variant_field(
2399-
enum_ref: FrameOffset,
2455+
obj_ref: FrameOffset,
24002456
field_offset: u32,
24012457
src: FrameOffset,
24022458
size: u32,
24032459
) -> Self {
2404-
MicroOp::EnumWriteVariantField {
2405-
enum_ref,
2460+
MicroOp::HeapWriteOffset {
2461+
obj_ref,
24062462
offset: ENUM_DATA_OFFSET as u32 + field_offset,
24072463
src,
24082464
size,
24092465
}
24102466
}
24112467

2468+
/// Tag-dispatched variant-field read by value. `data_relative_offsets[tag]`
2469+
/// is the field's data-region-relative offset in that variant, or `None`
2470+
/// when the variant lacks the field (reading it aborts). Offsets are shifted
2471+
/// by `ENUM_DATA_OFFSET` to full object-relative offsets, matching
2472+
/// [`MicroOp::enum_borrow_variant_field_by_tag`].
2473+
pub fn enum_read_variant_field_by_tag(
2474+
enum_ref: FrameOffset,
2475+
data_relative_offsets: &[Option<u32>],
2476+
dst: FrameOffset,
2477+
size: u32,
2478+
) -> Self {
2479+
MicroOp::EnumReadVariantFieldByTag {
2480+
dst,
2481+
enum_ref,
2482+
offsets: Self::to_object_relative_offsets(data_relative_offsets),
2483+
size,
2484+
}
2485+
}
2486+
2487+
/// Tag-dispatched variant-field write by value; offset handling mirrors
2488+
/// [`MicroOp::enum_read_variant_field_by_tag`].
2489+
pub fn enum_write_variant_field_by_tag(
2490+
enum_ref: FrameOffset,
2491+
data_relative_offsets: &[Option<u32>],
2492+
src: FrameOffset,
2493+
size: u32,
2494+
) -> Self {
2495+
MicroOp::EnumWriteVariantFieldByTag {
2496+
enum_ref,
2497+
offsets: Self::to_object_relative_offsets(data_relative_offsets),
2498+
src,
2499+
size,
2500+
}
2501+
}
2502+
24122503
/// Deep-copy the owned heap pointers at the given byte offsets within the
24132504
/// value at `base`, making a freshly byte-copied value independent.
24142505
pub fn deep_copy_heap_ptrs(base: FrameOffset, offsets: Box<[u32]>) -> Self {

third_party/move/mono-move/core/src/memory.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
// Licensed pursuant to the Innovation-Enabling Source Code License, available at https://github.com/aptos-labs/aptos-core/blob/main/LICENSE
33

44
//! Raw, typed read/write of values at a byte offset from a base pointer.
5+
//!
6+
//! TODO(correctness): audit every caller of the aligned accessors below —
7+
//! any slot or field offset not guaranteed to meet the accessed type's
8+
//! alignment must use an unaligned access instead.
59
610
use crate::align::MAX_ALIGN;
711
use move_core_types::account_address::AccountAddress;

0 commit comments

Comments
 (0)