Skip to content

Commit

Permalink
Merge pull request #934 from vext01/bit-twiddle-tweaks
Browse files Browse the repository at this point in the history
Bit twiddle tweaks
  • Loading branch information
ltratt authored Jan 10, 2024
2 parents 6c68b00 + f71ff52 commit b79409b
Showing 1 changed file with 31 additions and 16 deletions.
47 changes: 31 additions & 16 deletions ykrt/src/compile/jitc_yk/jit_ir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,24 @@ const SHORT_INSTR_MAX_OPERANDS: u64 = 3;
/// In the constants below:
/// - `*_SIZE`: the size of a field in bits.
/// - `*_MASK`: a mask with one bits occupying the field in question.
/// - `*_SHIFT`: the number of bits required to left shift a field's value into position (from the
/// LSB).
///
/// Bit fiddling for a short operands:
const SHORT_OPERAND_SIZE: u64 = 18;
const SHORT_OPERAND_KIND_SIZE: u64 = 3;
const SHORT_OPERAND_KIND_MASK: u64 = 7;
const SHORT_OPERAND_VALUE_SIZE: u64 = 15;
const SHORT_OPERAND_VALUE_SHIFT: u64 = SHORT_OPERAND_KIND_SIZE;
const SHORT_OPERAND_MAX_VALUE: u64 = !(u64::MAX << SHORT_OPERAND_VALUE_SIZE);
const SHORT_OPERAND_MASK: u64 = 0x3ffff;
/// Bit fiddling for instructions.
const INSTR_ISSHORT_SIZE: u64 = 1;
const INSTR_ISSHORT_MASK: u64 = 1;
const INSTR_OPCODE_MASK: u64 = 0xe;
/// Bit fiddling for short instructions.
const SHORT_INSTR_OPCODE_MASK: u64 = 0xe;
const SHORT_INSTR_OPCODE_SHIFT: u64 = INSTR_ISSHORT_SIZE;
const SHORT_INSTR_FIRST_OPERAND_SHIFT: u64 = INSTR_ISSHORT_SIZE + OPCODE_SIZE;

/// An instruction is identified by its index in the instruction vector.
#[derive(Copy, Clone)]
Expand Down Expand Up @@ -95,7 +102,7 @@ pub enum Operand {
impl Operand {
pub(crate) fn new(kind: OpKind, val: u64) -> Self {
// check if the operand's value can fit in a short operand.
if val & (u64::MAX << SHORT_OPERAND_VALUE_SIZE) == 0 {
if val <= SHORT_OPERAND_MAX_VALUE {
Self::Short(ShortOperand::new(kind, val))
} else {
todo!()
Expand Down Expand Up @@ -146,15 +153,15 @@ pub struct ShortOperand(u64);

impl ShortOperand {
fn new(kind: OpKind, val: u64) -> ShortOperand {
ShortOperand((kind as u64) | (val << SHORT_OPERAND_KIND_SIZE))
ShortOperand((kind as u64) | (val << SHORT_OPERAND_VALUE_SHIFT))
}

fn kind(&self) -> OpKind {
OpKind::from(self.0 & SHORT_OPERAND_KIND_MASK)
}

fn val(&self) -> u64 {
self.0 >> SHORT_OPERAND_KIND_SIZE
self.0 >> SHORT_OPERAND_VALUE_SHIFT
}
}

Expand Down Expand Up @@ -199,7 +206,7 @@ pub(crate) struct Instruction(u64);

impl Instruction {
fn new_short(opcode: OpCode) -> Self {
Self(((opcode as u64) << INSTR_ISSHORT_SIZE) | INSTR_ISSHORT_MASK)
Self(((opcode as u64) << SHORT_INSTR_OPCODE_SHIFT) | INSTR_ISSHORT_MASK)
}

/// Returns true if the instruction is short.
Expand All @@ -210,14 +217,21 @@ impl Instruction {
/// Returns the opcode.
fn opcode(&self) -> OpCode {
debug_assert!(self.is_short());
OpCode::from((self.0 & INSTR_OPCODE_MASK) >> INSTR_ISSHORT_SIZE)
OpCode::from((self.0 & SHORT_INSTR_OPCODE_MASK) >> SHORT_INSTR_OPCODE_SHIFT)
}

/// For short instrucitons, return the bit offset of the specified short operand.
fn short_operand_bit_off(&self, index: u64) -> u64 {
debug_assert!(self.is_short());
debug_assert!(index < SHORT_INSTR_MAX_OPERANDS);
SHORT_INSTR_FIRST_OPERAND_SHIFT + SHORT_OPERAND_SIZE * index
}

/// Returns the specified operand.
fn operand(&self, index: u64) -> Operand {
if self.is_short() {
// Shift operand down the the LSB.
let op = self.0 >> (INSTR_ISSHORT_SIZE + OPCODE_SIZE + SHORT_OPERAND_SIZE * index);
let op = self.0 >> self.short_operand_bit_off(index);
// Then mask it out.
Operand::Short(ShortOperand(op & SHORT_OPERAND_MASK))
} else {
Expand Down Expand Up @@ -261,7 +275,7 @@ impl Instruction {
fn set_short_operand(&mut self, op: Operand, idx: u64) {
debug_assert!(self.is_short());
debug_assert!(idx < SHORT_INSTR_MAX_OPERANDS);
self.0 |= op.raw() << (INSTR_ISSHORT_SIZE + OPCODE_SIZE + SHORT_OPERAND_SIZE * idx);
self.0 |= op.raw() << self.short_operand_bit_off(idx);
}

/// Returns `true` if the instruction defines a local variable.
Expand Down Expand Up @@ -380,14 +394,12 @@ mod tests {
fn short_operand_getters() {
let mut word = 1; // short instruction.

let skip_lsbits = INSTR_ISSHORT_SIZE + OPCODE_SIZE;

// operand0:
word |= 0x0aaa8 << skip_lsbits;
word |= 0x0aaa8 << SHORT_INSTR_FIRST_OPERAND_SHIFT;
// operand1:
word |= 0x1bbb1 << skip_lsbits + SHORT_OPERAND_SIZE;
word |= 0x1bbb1 << SHORT_INSTR_FIRST_OPERAND_SHIFT + SHORT_OPERAND_SIZE;
// operand2:
word |= 0x2ccc8 << skip_lsbits + SHORT_OPERAND_SIZE * 2;
word |= 0x2ccc8 << SHORT_INSTR_FIRST_OPERAND_SHIFT + SHORT_OPERAND_SIZE * 2;

let inst = Instruction(word);

Expand Down Expand Up @@ -428,13 +440,16 @@ mod tests {
#[test]
fn does_fit_short_operand() {
for i in 0..SHORT_OPERAND_VALUE_SIZE {
Operand::new(OpKind::Local, 1 << i);
matches!(Operand::new(OpKind::Local, 1 << i), Operand::Short(_));
}
}

#[test]
#[should_panic]
#[should_panic] // Once long operands are implemented, remove.
fn doesnt_fit_short_operand() {
Operand::new(OpKind::Local, 1 << SHORT_OPERAND_VALUE_SIZE);
matches!(
Operand::new(OpKind::Local, 1 << SHORT_OPERAND_VALUE_SIZE),
Operand::Long(_)
);
}
}

0 comments on commit b79409b

Please sign in to comment.