use crate::{Bf16, Differentiable, Shape};
pub trait Emittable: Differentiable + PartialEq {
const ELEMENT: &'static str;
const ZERO: &'static str;
const NEGATIVE_INFINITY: &'static str;
const ACCUMULATION: Option<&'static str> = None;
fn literal(&self) -> String;
}
impl Emittable for f32 {
const ELEMENT: &'static str = "f32";
const ZERO: &'static str = "0.0";
const NEGATIVE_INFINITY: &'static str = "0xFF800000";
fn literal(&self) -> String {
if self.is_finite() {
return dotted(format!("{self:?}"));
}
format!("0x{:08X}", self.to_bits())
}
}
impl Emittable for f64 {
const ELEMENT: &'static str = "f64";
const ZERO: &'static str = "0.0";
const NEGATIVE_INFINITY: &'static str = "0xFFF0000000000000";
fn literal(&self) -> String {
if self.is_finite() {
return dotted(format!("{self:?}"));
}
format!("0x{:016X}", self.to_bits())
}
}
impl Emittable for Bf16 {
const ELEMENT: &'static str = "bf16";
const ZERO: &'static str = "0.0";
const NEGATIVE_INFINITY: &'static str = "0xFF80";
const ACCUMULATION: Option<&'static str> = Some("f32");
fn literal(&self) -> String {
let expanded = self.to_f32();
if expanded.is_finite() {
return dotted(format!("{expanded:?}"));
}
format!("0x{:04X}", self.to_bits())
}
}
fn dotted(rendered: String) -> String {
if rendered.contains('.') {
return rendered;
}
match rendered.split_once('e') {
Some((mantissa, exponent)) => format!("{mantissa}.0e{exponent}"),
None => format!("{rendered}.0"),
}
}
pub(crate) fn tensor_type<Element: Emittable>(shape: &Shape) -> String {
let mut dimensions = String::new();
for extent in shape.axes() {
dimensions.push_str(&extent.to_string());
dimensions.push('x');
}
format!("tensor<{dimensions}{}>", Element::ELEMENT)
}
pub(crate) fn named_tensor_type(shape: &Shape, element: &str) -> String {
let mut dimensions = String::new();
for extent in shape.axes() {
dimensions.push_str(&extent.to_string());
dimensions.push('x');
}
format!("tensor<{dimensions}{element}>")
}
pub(crate) fn dense_literal<Element: Emittable>(shape: &Shape, elements: &[Element]) -> String {
if let Some(first) = elements.first()
&& elements.iter().all(|element| element == first)
{
return format!("dense<{}>", first.literal());
}
format!("dense<{}>", nested(shape.axes(), elements))
}
fn nested<Element: Emittable>(axes: &[usize], elements: &[Element]) -> String {
match axes.split_first() {
None => elements[0].literal(),
Some((&extent, rest)) => {
let stride = elements.len() / extent;
let rows: Vec<String> = (0..extent)
.map(|row| nested(rest, &elements[row * stride..(row + 1) * stride]))
.collect();
format!("[{}]", rows.join(", "))
}
}
}
pub(crate) fn pred_tensor_type(shape: &Shape) -> String {
let mut dimensions = String::new();
for extent in shape.axes() {
dimensions.push_str(&extent.to_string());
dimensions.push('x');
}
format!("tensor<{dimensions}i1>")
}
pub(crate) fn index_tensor_type(axes: &[usize]) -> String {
let mut dimensions = String::new();
for extent in axes {
dimensions.push_str(&extent.to_string());
dimensions.push('x');
}
format!("tensor<{dimensions}i64>")
}
pub(crate) fn dense_index_literal(axes: &[usize], indices: &[usize]) -> String {
format!("dense<{}>", nested_indices(axes, indices))
}
fn nested_indices(axes: &[usize], indices: &[usize]) -> String {
match axes.split_first() {
None => indices[0].to_string(),
Some((&extent, rest)) => {
let stride = indices.len() / extent;
let rows: Vec<String> = (0..extent)
.map(|row| nested_indices(rest, &indices[row * stride..(row + 1) * stride]))
.collect();
format!("[{}]", rows.join(", "))
}
}
}
#[cfg(test)]
#[path = "tests/builder_tests.rs"]
mod tests;