Skip to content

Commit

Permalink
add soft slices for integer-typed parameters
Browse files Browse the repository at this point in the history
  • Loading branch information
hlorenzi committed Feb 21, 2020
1 parent 1b3d436 commit 27687bb
Show file tree
Hide file tree
Showing 7 changed files with 116 additions and 37 deletions.
2 changes: 1 addition & 1 deletion src/asm/cpudef/cpudef.rs
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ impl<'t> CpuDefParser<'t>

fn parse_rule_production(&mut self, rule: &mut Rule) -> Result<(), ()>
{
let expr = Expression::parse(&mut self.parser)?;
let expr = Expression::parse_for_rule(&mut self.parser, &rule.params)?;

let width = match expr.width()
{
Expand Down
44 changes: 41 additions & 3 deletions src/expr/eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,9 +186,19 @@ impl Expression

BinaryOp::Concat =>
{
// FIXME: wrongly evaluates lhs and rhs again, with possible duplicated side-effects
let lhs_sliced = lhs_expr.eval_slice(report.clone(), ctx, eval_var, eval_fn)?;
let rhs_sliced = rhs_expr.eval_slice(report.clone(), ctx, eval_var, eval_fn)?;

let (lhs_sliced, rhs_sliced) = match (lhs_sliced, rhs_sliced)
{
(ExpressionValue::Integer(lhs), ExpressionValue::Integer(rhs)) => (lhs, rhs),
_ => unreachable!()
};

match (lhs_expr.width(), rhs_expr.width())
{
(Some(lhs_width), Some(rhs_width)) => Ok(ExpressionValue::Integer(bigint_concat(lhs, lhs_width, rhs, rhs_width))),
(Some(lhs_width), Some(rhs_width)) => Ok(ExpressionValue::Integer(bigint_concat(lhs_sliced, (lhs_width - 1, 0), rhs_sliced, (rhs_width - 1, 0)))),
(None, _) => Err(report.error_span("argument to concatenation with no known width", &lhs_expr.span())),
(_, None) => Err(report.error_span("argument to concatenation with no known width", &rhs_expr.span()))
}
Expand Down Expand Up @@ -235,6 +245,11 @@ impl Expression
}
}

&Expression::SoftSlice(_, _, _, _, ref inner) =>
{
inner.eval(report, ctx, eval_var, eval_fn)
}

&Expression::Block(_, ref exprs) =>
{
let mut result = ExpressionValue::Void;
Expand Down Expand Up @@ -267,6 +282,27 @@ impl Expression
}
}
}


pub fn eval_slice<FVar, FFn>(&self, report: RcReport, ctx: &mut ExpressionEvalContext, eval_var: &FVar, eval_fn: &FFn) -> Result<ExpressionValue, ()>
where
FVar: Fn(RcReport, &str, &Span) -> Result<ExpressionValue, bool>,
FFn: Fn(RcReport, usize, Vec<ExpressionValue>, &Span) -> Result<ExpressionValue, bool>
{
match self
{
&Expression::SoftSlice(ref span, _, left, right, ref inner) =>
{
match inner.eval(report.clone(), ctx, eval_var, eval_fn)?
{
ExpressionValue::Integer(x) => Ok(ExpressionValue::Integer(bigint_slice(x, left, right))),
_ => Err(report.error_span("invalid argument type to slice", &span))
}
}

_ => self.eval(report, ctx, eval_var, eval_fn)
}
}
}


Expand Down Expand Up @@ -359,9 +395,11 @@ fn bigint_shr(lhs: BigInt, rhs: BigInt) -> Option<BigInt>
}


fn bigint_concat(lhs: BigInt, _lhs_width: usize, rhs: BigInt, rhs_width: usize) -> BigInt
fn bigint_concat(lhs: BigInt, lhs_slice: (usize, usize), rhs: BigInt, rhs_slice: (usize, usize)) -> BigInt
{
bigint_or(lhs << rhs_width, rhs)
bigint_or(
bigint_slice(lhs, lhs_slice.0, lhs_slice.1) << (rhs_slice.0 + 1 - rhs_slice.1),
bigint_slice(rhs, rhs_slice.0, rhs_slice.1))
}


Expand Down
2 changes: 2 additions & 0 deletions src/expr/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ pub enum Expression
BinaryOp(Span, Span, BinaryOp, Box<Expression>, Box<Expression>),
TernaryOp(Span, Box<Expression>, Box<Expression>, Box<Expression>),
BitSlice(Span, Span, usize, usize, Box<Expression>),
SoftSlice(Span, Span, usize, usize, Box<Expression>),
Block(Span, Vec<Expression>),
Call(Span, Box<Expression>, Vec<Expression>)
}
Expand Down Expand Up @@ -66,6 +67,7 @@ impl Expression
&Expression::BinaryOp (ref span, ..) => span.clone(),
&Expression::TernaryOp(ref span, ..) => span.clone(),
&Expression::BitSlice (ref span, ..) => span.clone(),
&Expression::SoftSlice(ref span, ..) => span.clone(),
&Expression::Block (ref span, ..) => span.clone(),
&Expression::Call (ref span, ..) => span.clone()
}
Expand Down
39 changes: 13 additions & 26 deletions src/expr/inspect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@ use super::BinaryOp;
impl Expression
{
pub fn width(&self) -> Option<usize>
{
if let Some(slice) = self.slice()
{ Some(slice.0 + 1 - slice.1) }
else
{ None }
}


pub fn slice(&self) -> Option<(usize, usize)>
{
match self
{
Expand All @@ -17,10 +26,11 @@ impl Expression
if lhs_width.is_none() || rhs_width.is_none()
{ return None; }

Some(lhs_width.unwrap() + rhs_width.unwrap())
Some((lhs_width.unwrap() + rhs_width.unwrap() - 1, 0))
}

&Expression::BitSlice(_, _, left, right, _) => Some(left + 1 - right),
&Expression::BitSlice(_, _, left, right, _) => Some((left, right)),
&Expression::SoftSlice(_, _, left, right, _) => Some((left, right)),

&Expression::TernaryOp(_, _, ref true_branch, ref false_branch) =>
{
Expand All @@ -33,32 +43,9 @@ impl Expression
if true_width.unwrap() != false_width.unwrap()
{ return None; }

Some(true_width.unwrap())
}

&Expression::Block(_, ref exprs) =>
{
match exprs.last()
{
None => None,
Some(expr) => expr.width()
}
Some((true_width.unwrap() - 1, 0))
}

_ => None
}
}


pub fn slice(&self) -> Option<(usize, usize)>
{
match self
{
&Expression::BinaryOp(_, _, BinaryOp::Concat, _, _) => self.width().map(|w| (w - 1, 0)),
&Expression::BitSlice(_, _, left, right, _) => Some((left, right)),

&Expression::TernaryOp(_, _, _, _) => self.width().map(|w| (w - 1, 0)),

&Expression::Block(_, ref exprs) =>
{
match exprs.last()
Expand Down
47 changes: 40 additions & 7 deletions src/expr/parser.rs
Original file line number Diff line number Diff line change
@@ -1,29 +1,38 @@
use crate::syntax::{TokenKind, Parser, excerpt_as_usize, excerpt_as_bigint};
use crate::asm::cpudef::{RuleParameter, RuleParameterType};
use super::{Expression, ExpressionValue, UnaryOp, BinaryOp};


pub struct ExpressionParser<'a>
{
parser: &'a mut Parser
parser: &'a mut Parser,
rule_params: Option<&'a [RuleParameter]>,
}


impl Expression
{
pub fn parse(parser: &mut Parser) -> Result<Expression, ()>
{
ExpressionParser::new(parser).parse_expr()
ExpressionParser::new(parser, None).parse_expr()
}


pub fn parse_for_rule(parser: &mut Parser, rule_params: &[RuleParameter]) -> Result<Expression, ()>
{
ExpressionParser::new(parser, Some(rule_params)).parse_expr()
}
}


impl<'a> ExpressionParser<'a>
{
pub fn new(parser: &mut Parser) -> ExpressionParser
pub fn new(parser: &'a mut Parser, rule_params: Option<&'a [RuleParameter]>) -> ExpressionParser<'a>
{
ExpressionParser
{
parser: parser
parser,
rule_params,
}
}

Expand Down Expand Up @@ -390,10 +399,34 @@ impl<'a> ExpressionParser<'a>
let tk_name = self.parser.expect(TokenKind::Identifier)?;
name.push_str(&tk_name.excerpt.clone().unwrap());

if let Some(tk_dot) = tk_dot
{ Ok(Expression::Variable(tk_dot.span.join(&tk_name.span), name)) }
let expr_span = if let Some(tk_dot) = tk_dot
{ tk_dot.span.join(&tk_name.span) }
else
{ Ok(Expression::Variable(tk_name.span.clone(), name)) }
{ tk_name.span.clone() };

let expr_var = Expression::Variable(expr_span.clone(), name.clone());

if let Some(rule_params) = self.rule_params
{
if let Some(rule_param) = rule_params.iter().find(|p| p.name == name)
{
let width = match rule_param.typ
{
RuleParameterType::Unsigned(w) => Some(w),
RuleParameterType::Signed(w) => Some(w),
RuleParameterType::Integer(w) => Some(w),
_ => None
};

if let Some(width) = width
{
if width > 0
{ return Ok(Expression::SoftSlice(expr_span.clone(), expr_span.clone(), width - 1, 0, Box::new(expr_var))); }
}
}
}

Ok(expr_var)
}


Expand Down
19 changes: 19 additions & 0 deletions src/test/asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,25 @@ fn test_parameter_types()
}


#[test]
fn test_parameter_soft_slices()
{
test("load {a: u3} -> 0b11111 @ a", "load 0x5", Pass((4, "fd")));

test("load {a: u8 } -> 0x12 @ a", "load 0x34", Pass((4, "1234")));
test("load {a: u16} -> 0x12 @ a", "load 0x3456", Pass((4, "123456")));

test("load {a: s8 } -> 0x12 @ a", "load 0x34", Pass((4, "1234")));
test("load {a: s8 } -> 0x12 @ a", "load -0x01", Pass((4, "12ff")));
test("load {a: s8 } -> 0x12 @ a", "load -0x80", Pass((4, "1280")));
test("load {a: s16} -> 0x12 @ a", "load -0x8000", Pass((4, "128000")));

test("load {a: s8} -> 0x12 @ a[15:0]", "load -1", Pass((4, "12ffff")));

test("load {a: s8} -> 0x12 @ (a + a)[15:0]", "load -1", Pass((4, "12fffe")));
}


#[test]
fn test_tokendef()
{
Expand Down
Binary file modified web/customasm.gc.wasm
Binary file not shown.

0 comments on commit 27687bb

Please sign in to comment.