Skip to content

Commit a5e172f

Browse files
committed
Cranelift: update ValueDataPacked to support full Value range.
This updates the `ValueDataPacked` scheme from the old ``` (enum tag) (CLIF type) (value 1) (value 2) /// | tag:2 | type:14 | x:24 | y:24 | ``` encoding in a `u64` to a new ``` /// | tag:2 | type:14 | x:32 | y:32 | ``` encoding, with a `packed` tag attribute to ensure the struct fits in 10 bytes. This permits the full range of `Value` (a `u32` entity index) to be encoded, removing the remaining major limit on function body size after the work in #12611 to address #12229. Curiously, this appears to be a *speedup* in compile time of 3-5% on bz2 and 3% on spidermonkey-json (Sightglass, 50 data points each). My best guess as to why is that putting the value fields in their own `u32`s allows for quick access without shifts/masks, which is actually better than the unaligned accesses (caused by 10-byte size) -- which have no penalty on modern mainstream CPUs -- and 25% size inflation of the value-definitions array.
1 parent 7357e7c commit a5e172f

1 file changed

Lines changed: 30 additions & 60 deletions

File tree

  • cranelift/codegen/src/ir

cranelift/codegen/src/ir/dfg.rs

Lines changed: 30 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -718,7 +718,7 @@ enum ValueData {
718718
/// Layout:
719719
///
720720
/// ```plain
721-
/// | tag:2 | type:14 | x:24 | y:24 |
721+
/// | tag:2 | type:14 | x:32 | y:32 |
722722
///
723723
/// Inst 00 ty inst output inst index
724724
/// Param 01 ty blockparam num block index
@@ -727,76 +727,50 @@ enum ValueData {
727727
/// ```
728728
#[derive(Clone, Copy, Debug, PartialEq, Hash)]
729729
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
730-
struct ValueDataPacked(u64);
731-
732-
/// Encodes a value in 0..2^32 into 0..2^n, where n is less than 32
733-
/// (and is implied by `mask`), by translating 2^32-1 (0xffffffff)
734-
/// into 2^n-1 and panic'ing on 2^n..2^32-1.
735-
fn encode_narrow_field(x: u32, bits: u8) -> u32 {
736-
let max = (1 << bits) - 1;
737-
if x == 0xffff_ffff {
738-
max
739-
} else {
740-
debug_assert!(
741-
x < max,
742-
"{x} does not fit into {bits} bits (must be less than {max} to \
743-
allow for a 0xffffffff sentinel)"
744-
);
745-
x
746-
}
747-
}
748-
749-
/// The inverse of the above `encode_narrow_field`: unpacks 2^n-1 into
750-
/// 2^32-1.
751-
fn decode_narrow_field(x: u32, bits: u8) -> u32 {
752-
if x == (1 << bits) - 1 { 0xffff_ffff } else { x }
730+
#[repr(Rust, packed)]
731+
struct ValueDataPacked {
732+
x: u32,
733+
y: u32,
734+
flags_and_type: u16,
753735
}
754736

755737
impl ValueDataPacked {
756-
const Y_SHIFT: u8 = 0;
757-
const Y_BITS: u8 = 24;
758-
const X_SHIFT: u8 = Self::Y_SHIFT + Self::Y_BITS;
759-
const X_BITS: u8 = 24;
760-
const TYPE_SHIFT: u8 = Self::X_SHIFT + Self::X_BITS;
738+
const TYPE_SHIFT: u8 = 0;
761739
const TYPE_BITS: u8 = 14;
762740
const TAG_SHIFT: u8 = Self::TYPE_SHIFT + Self::TYPE_BITS;
763741
const TAG_BITS: u8 = 2;
764742

765-
const TAG_INST: u64 = 0;
766-
const TAG_PARAM: u64 = 1;
767-
const TAG_ALIAS: u64 = 2;
768-
const TAG_UNION: u64 = 3;
743+
const TAG_INST: u16 = 0;
744+
const TAG_PARAM: u16 = 1;
745+
const TAG_ALIAS: u16 = 2;
746+
const TAG_UNION: u16 = 3;
769747

770-
fn make(tag: u64, ty: Type, x: u32, y: u32) -> ValueDataPacked {
748+
fn make(tag: u16, ty: Type, x: u32, y: u32) -> ValueDataPacked {
771749
debug_assert!(tag < (1 << Self::TAG_BITS));
772750
debug_assert!(ty.repr() < (1 << Self::TYPE_BITS));
773751

774-
let x = encode_narrow_field(x, Self::X_BITS);
775-
let y = encode_narrow_field(y, Self::Y_BITS);
776-
777-
ValueDataPacked(
778-
(tag << Self::TAG_SHIFT)
779-
| ((ty.repr() as u64) << Self::TYPE_SHIFT)
780-
| ((x as u64) << Self::X_SHIFT)
781-
| ((y as u64) << Self::Y_SHIFT),
782-
)
752+
ValueDataPacked {
753+
x,
754+
y,
755+
flags_and_type: (tag << Self::TAG_SHIFT) | (ty.repr() << Self::TYPE_SHIFT),
756+
}
783757
}
784758

785759
#[inline(always)]
786-
fn field(self, shift: u8, bits: u8) -> u64 {
787-
(self.0 >> shift) & ((1 << bits) - 1)
760+
fn field(self, shift: u8, bits: u8) -> u16 {
761+
(self.flags_and_type >> shift) & ((1 << bits) - 1)
788762
}
789763

790764
#[inline(always)]
791765
fn ty(self) -> Type {
792-
let ty = self.field(ValueDataPacked::TYPE_SHIFT, ValueDataPacked::TYPE_BITS) as u16;
766+
let ty = self.field(ValueDataPacked::TYPE_SHIFT, ValueDataPacked::TYPE_BITS);
793767
Type::from_repr(ty)
794768
}
795769

796770
#[inline(always)]
797771
fn set_type(&mut self, ty: Type) {
798-
self.0 &= !(((1 << Self::TYPE_BITS) - 1) << Self::TYPE_SHIFT);
799-
self.0 |= (ty.repr() as u64) << Self::TYPE_SHIFT;
772+
self.flags_and_type &= !(((1 << Self::TYPE_BITS) - 1) << Self::TYPE_SHIFT);
773+
self.flags_and_type |= ty.repr() << Self::TYPE_SHIFT;
800774
}
801775
}
802776

@@ -824,33 +798,29 @@ impl From<ValueDataPacked> for ValueData {
824798
let tag = data.field(ValueDataPacked::TAG_SHIFT, ValueDataPacked::TAG_BITS);
825799
let ty = u16::try_from(data.field(ValueDataPacked::TYPE_SHIFT, ValueDataPacked::TYPE_BITS))
826800
.expect("Mask should ensure result fits in a u16");
827-
let x = u32::try_from(data.field(ValueDataPacked::X_SHIFT, ValueDataPacked::X_BITS))
828-
.expect("Mask should ensure result fits in a u32");
829-
let y = u32::try_from(data.field(ValueDataPacked::Y_SHIFT, ValueDataPacked::Y_BITS))
830-
.expect("Mask should ensure result fits in a u32");
831801

832802
let ty = Type::from_repr(ty);
833803
match tag {
834804
ValueDataPacked::TAG_INST => ValueData::Inst {
835805
ty,
836-
num: u16::try_from(x).expect("Inst result num should fit in u16"),
837-
inst: Inst::from_bits(decode_narrow_field(y, ValueDataPacked::Y_BITS)),
806+
num: u16::try_from(data.x).expect("Inst result num should fit in u16"),
807+
inst: Inst::from_bits(data.y),
838808
},
839809
ValueDataPacked::TAG_PARAM => ValueData::Param {
840810
ty,
841-
num: u16::try_from(x).expect("Blockparam index should fit in u16"),
842-
block: Block::from_bits(decode_narrow_field(y, ValueDataPacked::Y_BITS)),
811+
num: u16::try_from(data.x).expect("Blockparam index should fit in u16"),
812+
block: Block::from_bits(data.y),
843813
},
844814
ValueDataPacked::TAG_ALIAS => ValueData::Alias {
845815
ty,
846-
original: Value::from_bits(decode_narrow_field(y, ValueDataPacked::Y_BITS)),
816+
original: Value::from_bits(data.y),
847817
},
848818
ValueDataPacked::TAG_UNION => ValueData::Union {
849819
ty,
850-
x: Value::from_bits(decode_narrow_field(x, ValueDataPacked::X_BITS)),
851-
y: Value::from_bits(decode_narrow_field(y, ValueDataPacked::Y_BITS)),
820+
x: Value::from_bits(data.x),
821+
y: Value::from_bits(data.y),
852822
},
853-
_ => panic!("Invalid tag {} in ValueDataPacked 0x{:x}", tag, data.0),
823+
_ => panic!("Invalid tag {} in ValueDataPacked", tag),
854824
}
855825
}
856826
}

0 commit comments

Comments
 (0)