Skip to content

Commit

Permalink
cranelift: Add f16const and f128const instructions
Browse files Browse the repository at this point in the history
  • Loading branch information
beetrees committed Jul 4, 2024
1 parent 8fc4186 commit ac8fe08
Show file tree
Hide file tree
Showing 16 changed files with 249 additions and 14 deletions.
3 changes: 3 additions & 0 deletions cranelift/codegen/meta/src/shared/formats.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ pub(crate) struct Formats {
pub(crate) unary: Rc<InstructionFormat>,
pub(crate) unary_const: Rc<InstructionFormat>,
pub(crate) unary_global_value: Rc<InstructionFormat>,
pub(crate) unary_ieee16: Rc<InstructionFormat>,
pub(crate) unary_ieee32: Rc<InstructionFormat>,
pub(crate) unary_ieee64: Rc<InstructionFormat>,
pub(crate) unary_imm: Rc<InstructionFormat>,
Expand All @@ -48,6 +49,8 @@ impl Formats {

unary_imm: Builder::new("UnaryImm").imm(&imm.imm64).build(),

unary_ieee16: Builder::new("UnaryIeee16").imm(&imm.ieee16).build(),

unary_ieee32: Builder::new("UnaryIeee32").imm(&imm.ieee32).build(),

unary_ieee64: Builder::new("UnaryIeee64").imm(&imm.ieee64).build(),
Expand Down
10 changes: 10 additions & 0 deletions cranelift/codegen/meta/src/shared/immediates.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ pub(crate) struct Immediates {
/// This is used to represent an immediate address offset in load/store instructions.
pub offset32: OperandKind,

/// A 16-bit immediate floating point operand.
///
/// IEEE 754-2008 binary16 interchange format.
pub ieee16: OperandKind,

/// A 32-bit immediate floating point operand.
///
/// IEEE 754-2008 binary32 interchange format.
Expand Down Expand Up @@ -119,6 +124,11 @@ impl Immediates {
"ir::immediates::Offset32",
"A 32-bit immediate signed offset.",
),
ieee16: new_imm(
"imm",
"ir::immediates::Ieee16",
"A 16-bit immediate floating point number.",
),
ieee32: new_imm(
"imm",
"ir::immediates::Ieee32",
Expand Down
34 changes: 34 additions & 0 deletions cranelift/codegen/meta/src/shared/instructions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -599,8 +599,10 @@ pub(crate) fn define(

// Operand kind shorthands.
let i8: &TypeVar = &ValueType::from(LaneType::from(types::Int::I8)).into();
let f16_: &TypeVar = &ValueType::from(LaneType::from(types::Float::F16)).into();
let f32_: &TypeVar = &ValueType::from(LaneType::from(types::Float::F32)).into();
let f64_: &TypeVar = &ValueType::from(LaneType::from(types::Float::F64)).into();
let f128_: &TypeVar = &ValueType::from(LaneType::from(types::Float::F128)).into();

// Starting definitions.
let Int = &TypeVar::new(
Expand Down Expand Up @@ -1285,6 +1287,22 @@ pub(crate) fn define(
]),
);

ig.push(
Inst::new(
"f16const",
r#"
Floating point constant.
Create a `f16` SSA value with an immediate constant value.
"#,
&formats.unary_ieee16,
)
.operands_in(vec![Operand::new("N", &imm.ieee16)])
.operands_out(vec![
Operand::new("a", f16_).with_doc("A constant f16 scalar value")
]),
);

ig.push(
Inst::new(
"f32const",
Expand Down Expand Up @@ -1317,6 +1335,22 @@ pub(crate) fn define(
]),
);

ig.push(
Inst::new(
"f128const",
r#"
Floating point constant.
Create a `f128` SSA value with an immediate constant value.
"#,
&formats.unary_const,
)
.operands_in(vec![Operand::new("N", &imm.pool_constant)])
.operands_out(vec![
Operand::new("a", f128_).with_doc("A constant f128 scalar value")
]),
);

ig.push(
Inst::new(
"vconst",
Expand Down
1 change: 1 addition & 0 deletions cranelift/codegen/src/inst_predicates.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ pub fn is_constant_64bit(func: &Function, inst: Inst) -> Option<u64> {
}
match data {
&InstructionData::UnaryImm { imm, .. } => Some(imm.bits() as u64),
&InstructionData::UnaryIeee16 { imm, .. } => Some(imm.bits() as u64),
&InstructionData::UnaryIeee32 { imm, .. } => Some(imm.bits() as u64),
&InstructionData::UnaryIeee64 { imm, .. } => Some(imm.bits()),
_ => None,
Expand Down
29 changes: 28 additions & 1 deletion cranelift/codegen/src/ir/constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
//! - ensuring alignment of constants within the pool,
//! - bucketing constants by size.
use crate::ir::immediates::{IntoBytes, V128Imm};
use crate::ir::immediates::{Ieee128, IntoBytes, V128Imm};
use crate::ir::Constant;
use alloc::collections::BTreeMap;
use alloc::vec::Vec;
Expand Down Expand Up @@ -54,6 +54,22 @@ impl From<V128Imm> for ConstantData {
}
}

impl From<Ieee128> for ConstantData {
fn from(v: Ieee128) -> Self {
Self(v.into_bytes())
}
}

impl TryFrom<&ConstantData> for Ieee128 {
type Error = <[u8; 16] as TryFrom<&'static [u8]>>::Error;

fn try_from(value: &ConstantData) -> Result<Self, Self::Error> {
Ok(Ieee128::with_bits(u128::from_le_bytes(
value.as_slice().try_into()?,
)))
}
}

impl ConstantData {
/// Return the number of bytes in the constant.
pub fn len(&self) -> usize {
Expand Down Expand Up @@ -459,4 +475,15 @@ mod tests {
[0x78, 0x56, 0x34, 0x12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
);
}

#[test]
fn constant_ieee128() {
let value = Ieee128::with_bits(0x000102030405060708090a0b0c0d0e0f);
let constant = ConstantData::from(value);
assert_eq!(
constant.as_slice(),
&[0xf, 0xe, 0xd, 0xc, 0xb, 0xa, 0x9, 0x8, 0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1, 0x0]
);
assert_eq!(Ieee128::try_from(&constant).unwrap().bits(), value.bits());
}
}
2 changes: 2 additions & 0 deletions cranelift/codegen/src/ir/entities.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,10 @@ impl Block {
/// [`InstBuilder`](super::InstBuilder) instructions:
///
/// - [`iconst`](super::InstBuilder::iconst) for integer constants
/// - [`f16const`](super::InstBuilder::f16const) for 16-bit float constants
/// - [`f32const`](super::InstBuilder::f32const) for 32-bit float constants
/// - [`f64const`](super::InstBuilder::f64const) for 64-bit float constants
/// - [`f128const`](super::InstBuilder::f128const) for 128-bit float constants
/// - [`vconst`](super::InstBuilder::vconst) for vector constants
/// - [`null`](super::InstBuilder::null) for null reference constants
///
Expand Down
12 changes: 12 additions & 0 deletions cranelift/codegen/src/ir/immediates.rs
Original file line number Diff line number Diff line change
Expand Up @@ -843,6 +843,12 @@ impl FromStr for Ieee16 {
}
}

impl IntoBytes for Ieee16 {
fn into_bytes(self) -> Vec<u8> {
self.bits().to_le_bytes().to_vec()
}
}

impl Ieee32 {
/// Create a new `Ieee32` containing the bits of `x`.
pub fn with_bits(x: u32) -> Self {
Expand Down Expand Up @@ -1357,6 +1363,12 @@ impl FromStr for Ieee128 {
}
}

impl IntoBytes for Ieee128 {
fn into_bytes(self) -> Vec<u8> {
self.bits().to_le_bytes().to_vec()
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
9 changes: 8 additions & 1 deletion cranelift/codegen/src/machinst/isle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ macro_rules! isle_lower_prelude_methods {
return self.zero_value(arg);
}
InstructionData::UnaryConst {
opcode: Opcode::Vconst,
opcode: Opcode::Vconst | Opcode::F128const,
constant_handle,
} => {
let constant_data =
Expand All @@ -271,6 +271,13 @@ macro_rules! isle_lower_prelude_methods {
return None;
}
}
InstructionData::UnaryIeee16 { imm, .. } => {
if imm.bits() == 0 {
return Some(value);
} else {
return None;
}
}
InstructionData::UnaryIeee32 { imm, .. } => {
if imm.bits() == 0 {
return Some(value);
Expand Down
2 changes: 1 addition & 1 deletion cranelift/codegen/src/opts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use crate::egraph::{NewOrExistingInst, OptimizeCtx};
pub use crate::ir::condcodes::{FloatCC, IntCC};
use crate::ir::dfg::ValueDef;
pub use crate::ir::immediates::{Ieee32, Ieee64, Imm64, Offset32, Uimm8, V128Imm};
pub use crate::ir::immediates::{Ieee16, Ieee32, Ieee64, Imm64, Offset32, Uimm8, V128Imm};
use crate::ir::instructions::InstructionFormat;
pub use crate::ir::types::*;
pub use crate::ir::{
Expand Down
12 changes: 9 additions & 3 deletions cranelift/codegen/src/verifier/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -671,11 +671,11 @@ impl<'a> Verifier<'a> {
self.verify_bitcast(inst, flags, arg, errors)?;
}
UnaryConst {
opcode: Opcode::Vconst,
opcode: opcode @ (Opcode::Vconst | Opcode::F128const),
constant_handle,
..
} => {
self.verify_constant_size(inst, constant_handle, errors)?;
self.verify_constant_size(inst, opcode, constant_handle, errors)?;
}

// Exhaustive list so we can't forget to add new formats
Expand All @@ -686,6 +686,7 @@ impl<'a> Verifier<'a> {
| Unary { .. }
| UnaryConst { .. }
| UnaryImm { .. }
| UnaryIeee16 { .. }
| UnaryIeee32 { .. }
| UnaryIeee64 { .. }
| Binary { .. }
Expand Down Expand Up @@ -1034,10 +1035,15 @@ impl<'a> Verifier<'a> {
fn verify_constant_size(
&self,
inst: Inst,
opcode: Opcode,
constant: Constant,
errors: &mut VerifierErrors,
) -> VerifierStepResult {
let type_size = self.func.dfg.ctrl_typevar(inst).bytes() as usize;
let type_size = match opcode {
Opcode::F128const => types::F128.bytes(),
Opcode::Vconst => self.func.dfg.ctrl_typevar(inst).bytes(),
_ => unreachable!("unexpected opcode {opcode:?}"),
} as usize;
let constant_size = self.func.dfg.constants.get(constant).len();
if type_size != constant_size {
errors.fatal((
Expand Down
11 changes: 10 additions & 1 deletion cranelift/codegen/src/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
use crate::entity::SecondaryMap;
use crate::ir::entities::AnyEntity;
use crate::ir::immediates::Ieee128;
use crate::ir::pcc::Fact;
use crate::ir::{Block, DataFlowGraph, Function, Inst, SigRef, Type, Value, ValueDef};
use crate::ir::{Block, DataFlowGraph, Function, Inst, Opcode, SigRef, Type, Value, ValueDef};
use crate::packed_option::ReservedValue;
use alloc::string::{String, ToString};
use alloc::vec::Vec;
Expand Down Expand Up @@ -396,6 +397,7 @@ pub fn write_operands(w: &mut dyn Write, dfg: &DataFlowGraph, inst: Inst) -> fmt
StoreNoOffset { flags, args, .. } => write!(w, "{} {}, {}", flags, args[0], args[1]),
Unary { arg, .. } => write!(w, " {}", arg),
UnaryImm { imm, .. } => write!(w, " {}", imm),
UnaryIeee16 { imm, .. } => write!(w, " {}", imm),
UnaryIeee32 { imm, .. } => write!(w, " {}", imm),
UnaryIeee64 { imm, .. } => write!(w, " {}", imm),
UnaryGlobalValue { global_value, .. } => write!(w, " {}", global_value),
Expand Down Expand Up @@ -494,8 +496,15 @@ pub fn write_operands(w: &mut dyn Write, dfg: &DataFlowGraph, inst: Inst) -> fmt
if let ValueDef::Result(src, _) = dfg.value_def(arg) {
let imm = match dfg.insts[src] {
UnaryImm { imm, .. } => imm.to_string(),
UnaryIeee16 { imm, .. } => imm.to_string(),
UnaryIeee32 { imm, .. } => imm.to_string(),
UnaryIeee64 { imm, .. } => imm.to_string(),
UnaryConst {
constant_handle,
opcode: Opcode::F128const,
} => Ieee128::try_from(dfg.constants.get(constant_handle))
.expect("16-byte f128 constant")
.to_string(),
UnaryConst {
constant_handle, ..
} => constant_handle.to_string(),
Expand Down
53 changes: 53 additions & 0 deletions cranelift/filetests/filetests/runtests/f128const.clif
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
test interpret


;; These values are special for RISC-V since it has a dedicated
;; instruction to generate them.

function %special_f128_values() -> f128, f128, f128, f128, f128, f128, f128, f128, f128, f128, f128, f128, f128, f128, f128, f128, f128, f128, f128, f128, f128, f128, f128, f128, f128, f128, f128, f128, f128, f128, f128, f128 {
block0:
v0 = f128const -0x1.p0
v1 = f128const 0x1.p-16382
v2 = f128const 0x1.p-16
v3 = f128const 0x1.p-15
v4 = f128const 0x1.p-8
v5 = f128const 0x1.p-7
v6 = f128const 0x1.p-4
v7 = f128const 0x1.p-3
v8 = f128const 0x1.p-2
v9 = f128const 0x1.4p-2
v10 = f128const 0x1.8p-2
v11 = f128const 0x1.cp-2
v12 = f128const 0x1.p-1
v13 = f128const 0x1.4p-1
v14 = f128const 0x1.8p-1
v15 = f128const 0x1.cp-1
v16 = f128const 0x1.p0
v17 = f128const 0x1.4p0
v18 = f128const 0x1.8p0
v19 = f128const 0x1.cp0
v20 = f128const 0x1.p1
v21 = f128const 0x1.4p1
v22 = f128const 0x1.8p1
v23 = f128const 0x1.p2
v24 = f128const 0x1.p3
v25 = f128const 0x1.p4
v26 = f128const 0x1.p7
v27 = f128const 0x1.p8
v28 = f128const 0x1.p15
v29 = f128const 0x1.p16
v30 = f128const +Inf
v31 = f128const +NaN

return v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31
}

; run: %special_f128_values() == [-0x1.p0, 0x1.p-16382, 0x1.p-16, 0x1.p-15, 0x1.p-8, 0x1.p-7, 0x1.p-4, 0x1.p-3, 0x1.p-2, 0x1.4p-2, 0x1.8p-2, 0x1.cp-2, 0x1.p-1, 0x1.4p-1, 0x1.8p-1, 0x1.cp-1, 0x1.p0, 0x1.4p0, 0x1.8p0, 0x1.cp0, 0x1.p1, 0x1.4p1, 0x1.8p1, 0x1.p2, 0x1.p3, 0x1.p4, 0x1.p7, 0x1.p8, 0x1.p15, 0x1.p16, +Inf, +NaN]

function %f128const_neg_nan() -> f128 {
block0:
v0 = f128const -NaN
return v0
}

; run: %f128const_neg_nan() == -NaN
Loading

0 comments on commit ac8fe08

Please sign in to comment.