Changeset - c94c99d87e48
[Not reviewed]
0 3 0
MH - 3 years ago 2022-02-08 15:17:28
contact@maxhenger.nl
WIP: Rewriting select guards by inserting temp variables
3 files changed with 180 insertions and 4 deletions:
0 comments (0 inline, 0 general)
src/collections/string_pool.rs
Show inline comments
 
use std::ptr::null_mut;
 
use std::ptr::{null_mut, null};
 
use std::hash::{Hash, Hasher};
 
use std::marker::PhantomData;
 
use std::fmt::{Debug, Display, Formatter, Result as FmtResult};
 
@@ -29,6 +29,12 @@ impl<'a> StringRef<'a> {
 
        StringRef{ data, length, _phantom: PhantomData }
 
    }
 

	
 
    /// `new_empty` creates a empty StringRef. It is a null pointer with a
 
    /// length of zero.
 
    pub(crate) fn new_empty() -> StringRef<'static> {
 
        StringRef{ data: null(), length: 0, _phantom: PhantomData }
 
    }
 

	
 
    pub fn as_str(&self) -> &'a str {
 
        unsafe {
 
            let slice = std::slice::from_raw_parts::<'a, u8>(self.data, self.length);
 
@@ -161,6 +167,13 @@ unsafe impl Send for StringPool {}
 
mod tests {
 
    use super::*;
 

	
 
    #[test]
 
    fn display_empty_string_ref() {
 
        // Makes sure that null pointer inside StringRef will not cause issues
 
        let v = StringRef::new_empty();
 
        let val = format!("{}{:?}", v, v);
 
    }
 

	
 
    #[test]
 
    fn test_string_just_fits() {
 
        let large = "0".repeat(SLAB_SIZE);
src/protocol/ast.rs
Show inline comments
 
@@ -340,6 +340,15 @@ pub struct Identifier {
 
    pub value: StringRef<'static>,
 
}
 

	
 
impl Identifier {
 
    pub(crate) fn new_empty(span: InputSpan) -> Identifier {
 
        return Identifier{
 
            span,
 
            value: StringRef::new_empty(),
 
        };
 
    }
 
}
 

	
 
impl PartialEq for Identifier {
 
    fn eq(&self, other: &Self) -> bool {
 
        return self.value == other.value
 
@@ -1432,7 +1441,7 @@ pub enum ExpressionParent {
 
    Return(ReturnStatementId),
 
    New(NewStatementId),
 
    ExpressionStmt(ExpressionStatementId),
 
    Expression(ExpressionId, u32) // index within expression (e.g LHS or RHS of expression)
 
    Expression(ExpressionId, u32) // index within expression (e.g LHS or RHS of expression, or index in array literal, etc.)
 
}
 

	
 
impl ExpressionParent {
 
@@ -1530,6 +1539,23 @@ impl Expression {
 
        }
 
    }
 

	
 
    pub fn parent_mut(&mut self) -> &mut ExpressionParent {
 
        match self {
 
            Expression::Assignment(expr) => &mut expr.parent,
 
            Expression::Binding(expr) => &mut expr.parent,
 
            Expression::Conditional(expr) => &mut expr.parent,
 
            Expression::Binary(expr) => &mut expr.parent,
 
            Expression::Unary(expr) => &mut expr.parent,
 
            Expression::Indexing(expr) => &mut expr.parent,
 
            Expression::Slicing(expr) => &mut expr.parent,
 
            Expression::Select(expr) => &mut expr.parent,
 
            Expression::Literal(expr) => &mut expr.parent,
 
            Expression::Cast(expr) => &mut expr.parent,
 
            Expression::Call(expr) => &mut expr.parent,
 
            Expression::Variable(expr) => &mut expr.parent,
 
        }
 
    }
 

	
 
    pub fn parent_expr_id(&self) -> Option<ExpressionId> {
 
        if let ExpressionParent::Expression(id, _) = self.parent() {
 
            Some(*id)
 
@@ -1875,5 +1901,5 @@ pub struct VariableExpression {
 
    pub declaration: Option<VariableId>,
 
    pub used_as_binding_target: bool,
 
    pub parent: ExpressionParent,
 
    pub unique_id_in_definition: i32,
 
    pub unique_id_in_definition: i32, // used to index into type table after all types are determined
 
}
 
\ No newline at end of file
src/protocol/parser/pass_rewriting.rs
Show inline comments
 
@@ -4,13 +4,19 @@ use crate::protocol::*;
 
use super::visitor::*;
 

	
 
pub(crate) struct PassRewriting {
 
    current_scope: BlockStatementId,
 
    statement_buffer: ScopedBuffer<StatementId>,
 
    call_expr_buffer: ScopedBuffer<CallExpressionId>,
 
    expression_buffer: ScopedBuffer<ExpressionId>,
 
}
 

	
 
impl PassRewriting {
 
    pub(crate) fn new() -> Self {
 
        Self{
 
            current_scope: BlockStatementId::new_invalid(),
 
            statement_buffer: ScopedBuffer::with_capacity(16),
 
            call_expr_buffer: ScopedBuffer::with_capacity(16),
 
            expression_buffer: ScopedBuffer::with_capacity(16),
 
        }
 
    }
 
}
 
@@ -36,6 +42,7 @@ impl Visitor for PassRewriting {
 
        let block_stmt = &ctx.heap[id];
 
        let stmt_section = self.statement_buffer.start_section_initialized(&block_stmt.statements);
 

	
 
        self.current_scope = id;
 
        for stmt_idx in 0..stmt_section.len() {
 
            self.visit_stmt(ctx, stmt_section[stmt_idx])?;
 
        }
 
@@ -69,12 +76,142 @@ impl Visitor for PassRewriting {
 
        return self.visit_block_stmt(ctx, body_id);
 
    }
 

	
 
    fn visit_synchronous_stmt(&mut self, ctx: &mut Ctx, id: SynchronousStatementId) -> VisitorResult {
 
        let sync_stmt = &ctx.heap[id];
 
        let body_id = sync_stmt.body;
 
        return self.visit_block_stmt(ctx, body_id);
 
    }
 

	
 
    // --- Visiting the select statement
 

	
 
    fn visit_select_stmt(&mut self, ctx: &mut Ctx, id: SelectStatementId) -> VisitorResult {
 
        let stmt = &ctx.heap[id];
 
        // We're going to transform the select statement by a block statement
 
        // containing builtin runtime-calls. And to do so we create temporary
 
        // variables and move some other statements around.
 
        let select_stmt = &ctx.heap[id];
 
        let mut total_num_cases = select_stmt.cases.len();
 
        let mut total_num_ports = 0;
 

	
 
        // Put heap IDs into temporary buffers to handle borrowing rules
 
        let mut call_id_section = self.call_expr_buffer.start_section();
 
        let mut expr_id_section = self.expression_buffer.start_section();
 

	
 
        for case in select_stmt.cases.iter() {
 
            total_num_ports += case.involved_ports.len();
 
            for (call_id, expr_id) in case.involved_ports.iter().copied() {
 
                call_id_section.push(call_id);
 
                expr_id_section.push(expr_id);
 
            }
 
        }
 

	
 
        // Transform all of the call expressions by takings its argument (the
 
        // port from which we `get`) and turning it into a temporary variable.
 
        let mut transformed_stmts = Vec::with_capacity(total_num_ports); // TODO: Recompute this preallocated length, put assert at the end
 
        let mut locals = Vec::with_capacity(total_num_ports);
 

	
 
        for port_var_idx in 0..call_id_section.len() {
 
            let call_id = call_id_section[port_var_idx];
 
            let expr_id = expr_id_section[port_var_idx];
 
            let (replacement_variable_id, variable_stmt_id) = self.modify_call_and_create_replacement_variable(ctx, call_id, expr_id);
 
            transformed_stmts.push(variable_stmt_id);
 
            locals.push(replacement_variable_id);
 
        }
 

	
 
        call_id_section.forget();
 
        expr_id_section.forget();
 

	
 
        // let block = ctx.heap.alloc_block_statement(|this| BlockStatement{
 
        //     this,
 
        //     is_implicit: true,
 
        //     span: stmt.span,
 
        //     statements: vec![],
 
        //     end_block: EndBlockStatementId(),
 
        //     scope_node: ScopeNode {},
 
        //     first_unique_id_in_scope: 0,
 
        //     next_unique_id_in_scope: 0,
 
        //     locals,
 
        //     labels: vec![],
 
        //     next: ()
 
        // });
 

	
 
        return Ok(())
 
    }
 
}
 

	
 
impl PassRewriting {
 
    fn modify_call_and_create_replacement_variable(&self, ctx: &mut Ctx, call_expr_id: CallExpressionId, port_expr_id: ExpressionId) -> (VariableId, MemoryStatementId) {
 
        // Retrieve original expression which we're going to transplant into
 
        // its own variable
 
        let port_expr = &ctx.heap[port_expr_id];
 
        let port_expr_span = port_expr.full_span();
 
        let port_expr_unique_id = port_expr.get_unique_id_in_definition();
 

	
 
        // Create the entries in the heap
 
        let variable_expr_id = ctx.heap.alloc_variable_expression(|this| VariableExpression{
 
            this,
 
            identifier: Identifier::new_empty(port_expr_span),
 
            declaration: None,
 
            used_as_binding_target: false,
 
            parent: ExpressionParent::None,
 
            unique_id_in_definition: port_expr_unique_id,
 
        });
 
        let initial_expr_id = ctx.heap.alloc_assignment_expression(|this| AssignmentExpression{
 
            this,
 
            operator_span: port_expr_span,
 
            full_span: port_expr_span,
 
            left: variable_expr_id.upcast(),
 
            operation: AssignmentOperator::Set,
 
            right: port_expr_id,
 
            parent: ExpressionParent::None,
 
            unique_id_in_definition: -1,
 
        });
 
        let variable_id = ctx.heap.alloc_variable(|this| Variable{
 
            this,
 
            kind: VariableKind::Local,
 
            parser_type: ParserType{ elements: vec![ParserTypeElement{
 
                    element_span: port_expr_span,
 
                    variant: ParserTypeVariant::Inferred,
 
                }],
 
                full_span: port_expr_span
 
            },
 
            identifier: Identifier::new_empty(port_expr_span),
 
            relative_pos_in_block: 0,
 
            unique_id_in_scope: 0,
 
        });
 
        let variable_decl_stmt = ctx.heap.alloc_memory_statement(|this| MemoryStatement{
 
            this,
 
            span: port_expr_span,
 
            variable: variable_id,
 
            initial_expr: initial_expr_id,
 
            next: StatementId::new_invalid(),
 
        });
 

	
 
        // Modify all entries that required access other heap entries
 
        let variable_expr = &mut ctx.heap[variable_expr_id];
 
        variable_expr.declaration = Some(variable_id);
 
        variable_expr.parent = ExpressionParent::Expression(initial_expr_id.upcast(), 1);
 

	
 
        let initial_expr = &mut ctx.heap[initial_expr_id];
 
        initial_expr.parent = ExpressionParent::Memory(variable_decl_stmt);
 

	
 
        // Modify the parent of the expression that we just transplanted
 
        let port_expr = &mut ctx.heap[port_expr_id];
 
        *port_expr.parent_mut() = ExpressionParent::Expression(initial_expr_id.upcast(), 1);
 

	
 
        // Modify the call expression (that should contain the port expression
 
        // as the first argument) to point to the new variable
 
        let call_arg_expr_id = ctx.heap.alloc_variable_expression(|this| VariableExpression{
 
            this,
 
            identifier: Identifier::new_empty(port_expr_span),
 
            declaration: Some(variable_id),
 
            used_as_binding_target: false,
 
            parent: ExpressionParent::Expression(call_expr_id.upcast(), 0),
 
            unique_id_in_definition: port_expr_unique_id,
 
        });
 
        let call_expr = &mut ctx.heap[call_expr_id];
 
        debug_assert!(call_expr.arguments.len() == 1 && call_expr.arguments[0] == port_expr_id);
 
        call_expr.arguments[0] = call_arg_expr_id.upcast();
 

	
 
        return (variable_id, variable_decl_stmt);
 
    }
 
}
 
\ No newline at end of file
0 comments (0 inline, 0 general)