Skip to content

Commit

Permalink
comparisons return ints
Browse files Browse the repository at this point in the history
  • Loading branch information
enricozb committed Apr 15, 2024
1 parent 9621d33 commit 5d3bb02
Show file tree
Hide file tree
Showing 11 changed files with 61 additions and 67 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "hvm-core"
version = "0.2.24"
version = "0.2.25"
edition = "2021"
description = "HVM-Core is a massively parallel Interaction Combinator evaluator."
license = "MIT"
Expand Down
9 changes: 4 additions & 5 deletions src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,17 @@
//!
//! [interaction calculus]: https://en.wikipedia.org/wiki/Interaction_nets#Interaction_calculus
use crate::prelude::*;
use arrayvec::ArrayVec;
use ordered_float::OrderedFloat;

use crate::{
ops::TypedOp as Op,
prelude::*,
run::Lab,
util::{array_vec, deref, maybe_grow},
};

use alloc::collections::BTreeMap;
use arrayvec::ArrayVec;
use core::str::FromStr;
use ordered_float::OrderedFloat;
use TSPL::{new_parser, Parser};

/// The top level AST node, representing a collection of named nets.
Expand Down Expand Up @@ -311,7 +310,7 @@ impl<'i> HvmcParser<'i> {
// Int = "#" [-] Int
// F32 = "#" [-] ( Int "." Int | "NaN" | "inf" )
Some('#') => {
self.advance_char();
self.advance_one();
let is_neg = self.consume("-").is_ok();
let num = self.take_while(|c| c.is_alphanumeric() || c == '.');

Expand Down
70 changes: 41 additions & 29 deletions src/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,19 +51,20 @@ bi_enum! {
"/$": DivS = 5,
"%": Rem = 6,
"%$": RemS = 7,
"==": Eq = 8,
"!=": Ne = 9,
"<": Lt = 10,
">": Gt = 11,
"<=": Le = 12,
">=": Ge = 13,
"&": And = 14,
"|": Or = 15,
"^": Xor = 16,
"<<": Shl = 17,
"<<$": ShlS = 18,
">>": Shr = 19,
">>$": ShrS = 20,
"&": And = 8,
"|": Or = 9,
"^": Xor = 10,
"<<": Shl = 11,
"<<$": ShlS = 12,
">>": Shr = 13,
">>$": ShrS = 14,
// operators returning ints should go after `Eq`
"==": Eq = 15,
"!=": Ne = 16,
"<": Lt = 17,
">": Gt = 18,
"<=": Le = 19,
">=": Ge = 20,
}
}

Expand All @@ -82,23 +83,23 @@ impl Op {
Self::DivS => Self::Div,
Self::Rem => Self::RemS,
Self::RemS => Self::Rem,
Self::Eq => Self::Eq,
Self::Ne => Self::Ne,
Self::Lt => Self::Gt,
Self::Gt => Self::Lt,
Self::Le => Self::Ge,
Self::Ge => Self::Le,
Self::And => Self::And,
Self::Or => Self::Or,
Self::Xor => Self::Xor,
Self::Shl => Self::ShlS,
Self::ShlS => Self::Shl,
Self::Shr => Self::ShrS,
Self::ShrS => Self::Shr,
Self::Eq => Self::Eq,
Self::Ne => Self::Ne,
Self::Lt => Self::Gt,
Self::Gt => Self::Lt,
Self::Le => Self::Ge,
Self::Ge => Self::Le,
}
}

fn op<T: Numeric + PartialEq + PartialOrd>(self, a: T, b: T) -> T {
fn op_monoid<T: Numeric>(self, a: T, b: T) -> T {

Check warning on line 102 in src/ops.rs

View workflow job for this annotation

GitHub Actions / cspell

Unknown word (monoid)
match self {
Self::Add => T::add(a, b),
Self::Sub => T::sub(a, b),
Expand All @@ -108,24 +109,34 @@ impl Op {
Self::DivS => T::div(b, a),
Self::Rem => T::rem(a, b),
Self::RemS => T::rem(b, a),
Self::Eq => T::from_bool(a == b),
Self::Ne => T::from_bool(a != b),
Self::Lt => T::from_bool(a < b),
Self::Le => T::from_bool(a <= b),
Self::Gt => T::from_bool(a > b),
Self::Ge => T::from_bool(a >= b),
Self::And => T::and(a, b),
Self::Or => T::or(a, b),
Self::Xor => T::xor(a, b),
Self::Shl => T::shl(a, b),
Self::ShlS => T::shl(b, a),
Self::Shr => T::shr(a, b),
Self::ShrS => T::shr(b, a),

Self::Eq | Self::Ne | Self::Lt | Self::Le | Self::Gt | Self::Ge => unreachable!("non-monoid operation {self}"),

Check warning on line 120 in src/ops.rs

View workflow job for this annotation

GitHub Actions / cspell

Unknown word (monoid)
}
}

fn op_word<T: Numeric + FromWord + ToWord>(self, a: u64, b: u64) -> u64 {
match self {
Self::Eq => (T::from_word(a) == T::from_word(b)).into(),
Self::Ne => (T::from_word(a) != T::from_word(b)).into(),
Self::Lt => (T::from_word(a) < T::from_word(b)).into(),
Self::Le => (T::from_word(a) <= T::from_word(b)).into(),
Self::Gt => (T::from_word(a) > T::from_word(b)).into(),
Self::Ge => (T::from_word(a) >= T::from_word(b)).into(),

op => op.op_monoid(T::from_word(a), T::from_word(b)).to_word(),

Check warning on line 133 in src/ops.rs

View workflow job for this annotation

GitHub Actions / cspell

Unknown word (monoid)
}
}

fn op_word<T: Numeric + PartialOrd + PartialEq + FromWord + ToWord>(self, a: u64, b: u64) -> u64 {
self.op(T::from_word(a), T::from_word(b)).to_word()
#[inline(always)]
fn is_int(&self) -> bool {
self >= &Self::Eq
}
}

Expand All @@ -144,8 +155,9 @@ impl TypedOp {
std::mem::transmute(val)
}

#[inline(always)]
pub fn is_int(&self) -> bool {
self.ty < Ty::F32
(self.ty < Ty::F32) || self.op.is_int()
}

pub fn swap(self) -> Self {
Expand Down
2 changes: 1 addition & 1 deletion src/ops/num.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#[rustfmt::skip]
pub trait Numeric: Sized {
pub trait Numeric: PartialEq + PartialOrd + Sized {
const ZERO: Self;
const ONE: Self;

Expand Down
25 changes: 2 additions & 23 deletions src/ops/word.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,7 @@ pub trait ToWord {
fn to_word(self) -> u64;
}

macro_rules! impl_signed {
( $($ty:ty),+ ) => {
$(
impl FromWord for $ty {
#[inline(always)]
fn from_word(bits: u64) -> Self {
unsafe { std::mem::transmute::<_, i64>(bits) as Self }
}
}

impl ToWord for $ty {
#[inline(always)]
fn to_word(self) -> u64 {
unsafe { std::mem::transmute(self as i64) }
}
}
)*
};
}

macro_rules! impl_unsigned {
macro_rules! impl_word {
( $($ty:ty),+ ) => {
$(
impl FromWord for $ty {
Expand All @@ -46,8 +26,7 @@ macro_rules! impl_unsigned {
};
}

impl_signed! { i8, i16, i32 }
impl_unsigned! { u8, u16, u32, u64 }
impl_word! { u8, u16, u32, u64, i8, i16, i32 }

impl FromWord for f32 {
#[inline(always)]
Expand Down
4 changes: 2 additions & 2 deletions src/run/instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ impl<'a, M: Mode> Net<'a, M> {
self.rwts.anni += 1;
(Trg::wire(node.p1), Trg::wire(node.p2))
// TODO: fast copy?
} else if false && !M::LAZY && (port.is_num() == Int || port.tag() == Ref && lab >= port.lab()) {
} else if false && !M::LAZY && (port.is_num() || port.tag() == Ref && lab >= port.lab()) {
self.rwts.comm += 1;
self.free_trg(trg);
(Trg::port(port.clone()), Trg::port(port))
Expand All @@ -136,7 +136,7 @@ impl<'a, M: Mode> Net<'a, M> {
pub(crate) fn do_op(&mut self, op: Op, trg: Trg) -> (Trg, Trg) {
trace!(self.tracer, op, trg);
let port = trg.target();
if !M::LAZY && (port.tag() == Int || port.tag() == F32) {
if !M::LAZY && port.is_num() {
self.free_trg(trg);
let n = self.create_node(Op, op.swap().into());
n.p1.wire().set_target(port);
Expand Down
4 changes: 2 additions & 2 deletions src/run/interact.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ impl<'a, M: Mode> Net<'a, M> {
}
}

/// Interacts an int and a binary numeric operation node.
/// Interacts a number and a binary numeric operation node.
///
/// ```text
/// |
Expand Down Expand Up @@ -253,7 +253,7 @@ impl<'a, M: Mode> Net<'a, M> {
let a = a.consume_node();
let op = unsafe { Op::try_from(a.lab).unwrap_unchecked() };
let a1 = a.p1.load_target();
if a1.tag() == Int || a1.tag() == F32 {
if a1.is_num() {
self.rwts.oper += 1;
self.half_free(a.p1.addr());

Expand Down
6 changes: 4 additions & 2 deletions src/run/port.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,16 +209,18 @@ impl Port {
/// Accesses the float value of this port; this is valid for [`F32`] ports.
#[inline(always)]
pub fn float(&self) -> f32 {
f32::from_bits((self.0 >> 4) as u32)
f32::from_bits(self.num() as u32)
}

/// Accesses the numeric value of this port; this is valid for [`Int`] or
/// [`F32`] ports. This is meant for numeric operations to defer
/// interpreting this port as an integer or as a float until the operation
/// type is known.
///
/// The intermediate cast to `i64` is to sign-extend during bit-shift.
#[inline(always)]
pub const fn num(&self) -> u64 {
self.0 >> 4
((self.0 as i64) >> 4) as u64
}

/// Accesses the wire leaving this port; this is valid for [`Var`] ports and
Expand Down
2 changes: 1 addition & 1 deletion src/transform/eta_reduce.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ impl Phase2 {
if a == b {
let reducible = match a {
NodeType::Var(delta) => self.nodes[head_index.wrapping_add_signed(delta)] == NodeType::Ctr(lab),
NodeType::Era | NodeType::Int(_) => true,
NodeType::Era | NodeType::Int(_) | NodeType::F32(_) => true,
_ => false,
};
if reducible {
Expand Down
2 changes: 2 additions & 0 deletions tests/programs/f32.hvmc
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
& x ~ [n x] & @half ~ <f32.* #2.3 n> // 1.15
& x ~ [n x] & @half ~ <f32./ #2.0 n> // 0.25
& x ~ [n x] & @half ~ <f32.% #2.0 n> // 0.5

// comparisons (returning ints)
& x ~ [n x] & @half ~ <f32.== #2.0 n> // 0
& x ~ [n x] & @half ~ <f32.!= #2.0 n> // 1
& x ~ [n x] & @half ~ <f32.< #2.0 n> // 1
Expand Down

0 comments on commit 5d3bb02

Please sign in to comment.