fn simplify<'a>(
    cx: &impl Context<'a>,
    root: &'a Assignment<'a>,
    lhs: &'a Lvalue<'a>,
    rhs: &'a Rvalue<'a>,
    into: &mut Vec<&'a Assignment<'a>>,
) {
    trace!("Simplifying {:?}", root);
    match lhs.kind {
        LvalueKind::Transmute(value) => simplify(cx, root, value, rhs, into),
        LvalueKind::Concat(ref values) if values.len() == 1 => {
            let mut a = root.clone();
            a.lhs = values[0];
            let a = cx.arena().alloc_mir_assignment(a);
            simplify(cx, a, a.lhs, a.rhs, into);
        }
        LvalueKind::Concat(ref values) => {
            let mut base = 0;
            for value in values.iter().rev() {
                // The value must be of a simple bit vector type, as enforced
                // by the casting logic.
                let sbvt = value.ty.simple_bit_vector(cx, value.span);
                trace!(
                    "- Splitting subassignment to `{}` ({}) at {}",
                    value.span.extract(),
                    sbvt,
                    base
                );

                // Slice the relevant part of the assignment out from the RHS.
                let builder = lower::rvalue::Builder {
                    cx,
                    span: rhs.span,
                    expr: rhs.id,
                    env: rhs.env,
                };
                let base_rv = builder.constant_u32(base as u32);
                let index = builder.build(
                    sbvt.to_unpacked(cx),
                    RvalueKind::Index {
                        value: rhs,
                        base: base_rv,
                        length: sbvt.size,
                    },
                );

                // Formulate a new assignment.
                let mut a = root.clone();
                a.lhs = value;
                a.rhs = index;
                let a = cx.arena().alloc_mir_assignment(a);
                simplify(cx, a, a.lhs, a.rhs, into);

                base += sbvt.size;
            }
        }
        LvalueKind::Index {
            value,
            base,
            length,
        } => match value.kind {
            // If we index into a concatenation, we simply add the (shifted)
            // index to each concatenated value, and emit an individual
            // assignment for each.
            LvalueKind::Concat(ref values) => {
                trace!("Refactoring index into concatenation:\n{:?}", lhs);
                let mut shift = 0;
                for value in values.iter().rev() {
                    // The value must be of a simple bit vector type, as enforced
                    // by the casting logic.
                    let sbvt = value.ty.simple_bit_vector(cx, value.span);

                    // Compute the shifted assignment index.
                    let rbuilder = lower::rvalue::Builder {
                        cx,
                        span: value.span,
                        expr: value.id,
                        env: value.env,
                    };
                    let shift_rv = rbuilder.constant_u32(shift as u32);
                    let base_shifted = rbuilder.build(
                        base.ty,
                        RvalueKind::IntBinaryArith {
                            op: IntBinaryArithOp::Sub,
                            domain: base.ty.domain(),
                            sign: base.ty.sign(),
                            lhs: base,
                            rhs: shift_rv,
                        },
                    );

                    // Add a slice around this concatenated value.
                    let lbuilder = lower::lvalue::Builder {
                        cx,
                        span: value.span,
                        expr: value.id,
                        env: value.env,
                    };
                    let index = lbuilder.build(
                        lhs.ty,
                        LvalueKind::Index {
                            value,
                            base: base_shifted,
                            length,
                        },
                    );

                    // Formulate a new assignment.
                    let mut a = root.clone();
                    a.lhs = index;
                    a.rhs = rhs;
                    let a = cx.arena().alloc_mir_assignment(a);
                    simplify(cx, a, a.lhs, a.rhs, into);

                    shift += sbvt.size;
                }
            }
            _ => {
                into.push(root);
            }
        },
        _ => {
            into.push(root);
        }
    }
}
/// Inner function called recursively to simplify assignments.
Inner function called recursively to simplify assignments.
Inner function called recursively to simplify assignments .
fn simplify<'a>(
    cx: &impl Context<'a>,
    root: &'a Assignment<'a>,
    lhs: &'a Lvalue<'a>,
    rhs: &'a Rvalue<'a>,
    into: &mut Vec<&'a Assignment<'a>>,
) {
    trace!("Simplifying {:?}", root);
    match lhs.kind {
        LvalueKind::Transmute(value) => simplify(cx, root, value, rhs, into),
        LvalueKind::Concat(ref values) if values.len() == 1 => {
            let mut a = root.clone();
            a.lhs = values[0];
            let a = cx.arena().alloc_mir_assignment(a);
            simplify(cx, a, a.lhs, a.rhs, into);
        }
        LvalueKind::Concat(ref values) => {
            let mut base = 0;
            for value in values.iter().rev() {
                // The value must be of a simple bit vector type, as enforced
                // by the casting logic.
                let sbvt = value.ty.simple_bit_vector(cx, value.span);
                trace!(
                    "- Splitting subassignment to `{}` ({}) at {}",
                    value.span.extract(),
                    sbvt,
                    base
                );
                // Slice the relevant part of the assignment out from the RHS.
                let builder = lower::rvalue::Builder {
                    cx,
                    span: rhs.span,
                    expr: rhs.id,
                    env: rhs.env,
                };
                let base_rv = builder.constant_u32(base as u32);
                let index = builder.build(
                    sbvt.to_unpacked(cx),
                    RvalueKind::Index {
                        value: rhs,
                        base: base_rv,
                        length: sbvt.size,
                    },
                );
                // Formulate a new assignment.
                let mut a = root.clone();
                a.lhs = value;
                a.rhs = index;
                let a = cx.arena().alloc_mir_assignment(a);
                simplify(cx, a, a.lhs, a.rhs, into);
                base += sbvt.size;
            }
        }
        LvalueKind::Index {
            value,
            base,
            length,
        } => match value.kind {
            // If we index into a concatenation, we simply add the (shifted)
            // index to each concatenated value, and emit an individual
            // assignment for each.
            LvalueKind::Concat(ref values) => {
                trace!("Refactoring index into concatenation:\n{:?}", lhs);
                let mut shift = 0;
                for value in values.iter().rev() {
                    // The value must be of a simple bit vector type, as enforced
                    // by the casting logic.
                    let sbvt = value.ty.simple_bit_vector(cx, value.span);
                    // Compute the shifted assignment index.
                    let rbuilder = lower::rvalue::Builder {
                        cx,
                        span: value.span,
                        expr: value.id,
                        env: value.env,
                    };
                    let shift_rv = rbuilder.constant_u32(shift as u32);
                    let base_shifted = rbuilder.build(
                        base.ty,
                        RvalueKind::IntBinaryArith {
                            op: IntBinaryArithOp::Sub,
                            domain: base.ty.domain(),
                            sign: base.ty.sign(),
                            lhs: base,
                            rhs: shift_rv,
                        },
                    );
                    // Add a slice around this concatenated value.
                    let lbuilder = lower::lvalue::Builder {
                        cx,
                        span: value.span,
                        expr: value.id,
                        env: value.env,
                    };
                    let index = lbuilder.build(
                        lhs.ty,
                        LvalueKind::Index {
                            value,
                            base: base_shifted,
                            length,
                        },
                    );
                    // Formulate a new assignment.
                    let mut a = root.clone();
                    a.lhs = index;
                    a.rhs = rhs;
                    let a = cx.arena().alloc_mir_assignment(a);
                    simplify(cx, a, a.lhs, a.rhs, into);
                    shift += sbvt.size;
                }
            }
            _ => {
                into.push(root);
            }
        },
        _ => {
            into.push(root);
        }
    }
}
fn simplify < ' a > ( cx : & impl Context < ' a > , root : & ' a Assignment < ' a > , lhs : & ' a Lvalue < ' a > , rhs : & ' a Rvalue < ' a > , into : & mut Vec < & ' a Assignment < ' a > > , ) { trace ! ( " " root ) ; match lhs . kind { LvalueKind :: Transmute ( value ) => simplify ( cx , root , value , rhs , into ) , LvalueKind :: Concat ( ref values ) if values . len ( ) == 1 => { let mut a = root . clone ( ) ; a . lhs = values [ 0 ] ; let a = cx . arena ( ) . alloc_mir_assignment ( a ) ; simplify ( cx , a , a . lhs , a . rhs , into ) ; } LvalueKind :: Concat ( ref values ) => { let mut base = 0 ; for value in values . iter ( ) . rev ( ) { // The value must be of a simple bit vector type, as enforced // by the casting logic. let sbvt = value . ty . simple_bit_vector ( cx , value . span ) ; trace ! ( " " value span extract ( ) sbvt base ) ; // Slice the relevant part of the assignment out from the RHS. let builder = lower :: rvalue :: Builder { cx , span : rhs . span , expr : rhs . id , env : rhs . env , } ; let base_rv = builder . constant_u32 ( base as u32 ) ; let index = builder . build ( sbvt . to_unpacked ( cx ) , RvalueKind :: Index { value : rhs , base : base_rv , length : sbvt . size , } , ) ; // Formulate a new assignment. let mut a = root . clone ( ) ; a . lhs = value ; a . rhs = index ; let a = cx . arena ( ) . alloc_mir_assignment ( a ) ; simplify ( cx , a , a . lhs , a . rhs , into ) ; base += sbvt . size ; } } LvalueKind :: Index { value , base , length , } => match value . kind { // If we index into a concatenation, we simply add the (shifted) // index to each concatenated value, and emit an individual // assignment for each. LvalueKind :: Concat ( ref values ) => { trace ! ( " \n " lhs ) ; let mut shift = 0 ; for value in values . iter ( ) . rev ( ) { // The value must be of a simple bit vector type, as enforced // by the casting logic. let sbvt = value . ty . simple_bit_vector ( cx , value . span ) ; // Compute the shifted assignment index. let rbuilder = lower :: rvalue :: Builder { cx , span : value . span , expr : value . id , env : value . env , } ; let shift_rv = rbuilder . constant_u32 ( shift as u32 ) ; let base_shifted = rbuilder . build ( base . ty , RvalueKind :: IntBinaryArith { op : IntBinaryArithOp :: Sub , domain : base . ty . domain ( ) , sign : base . ty . sign ( ) , lhs : base , rhs : shift_rv , } , ) ; // Add a slice around this concatenated value. let lbuilder = lower :: lvalue :: Builder { cx , span : value . span , expr : value . id , env : value . env , } ; let index = lbuilder . build ( lhs . ty , LvalueKind :: Index { value , base : base_shifted , length , } , ) ; // Formulate a new assignment. let mut a = root . clone ( ) ; a . lhs = index ; a . rhs = rhs ; let a = cx . arena ( ) . alloc_mir_assignment ( a ) ; simplify ( cx , a , a . lhs , a . rhs , into ) ; shift += sbvt . size ; } } _ => { into . push ( root ) ; } } , _ => { into . push ( root ) ; } } }
Inner function called recursively to simplify assignments.
Inner function called recursively to simplify assignments .
cx
&impl Context<'a>
root
&'a Assignment<'a>
lhs
&'a Lvalue<'a>
rhs
&'a Rvalue<'a>
into
&mut Vec<&'a Assignment<'a>>
cx
&impl Context<'a>
root
&'a Assignment<'a>
lhs
&'a Lvalue<'a>
rhs
&'a Rvalue<'a>
into
&mut Vec<&'a Assignment<'a>>