forked from libre-chip/fayalite
deduce_structural_eq_flags: use expressions' literal_bits to improve deduction around cast_bits_to
This commit is contained in:
parent
e2ca80af97
commit
1b16118ce5
2 changed files with 3097 additions and 800 deletions
|
|
@ -2,28 +2,29 @@
|
||||||
// See Notices.txt for copyright information
|
// See Notices.txt for copyright information
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
bundle::BundleType,
|
bundle::{BundleField, BundleType},
|
||||||
enum_::EnumType,
|
enum_::{EnumType, EnumVariant},
|
||||||
expr::{
|
expr::{
|
||||||
ExprEnum,
|
ExprEnum, ToLiteralBits,
|
||||||
ops::{
|
ops::{
|
||||||
ArrayIndex, FieldAccess, StructuralEq, StructuralEqFlags, TraceAsStringAsInner,
|
ArrayIndex, FieldAccess, StructuralEq, StructuralEqFlags, TraceAsStringAsInner,
|
||||||
VariantAccess,
|
VariantAccess,
|
||||||
},
|
},
|
||||||
target::TargetBase,
|
target::TargetBase,
|
||||||
},
|
},
|
||||||
intern::{Intern, InternSlice, Interned, Memoize},
|
intern::{Intern, InternSlice, Interned, MemoizeGeneric},
|
||||||
module::{
|
module::{
|
||||||
ModuleBody, Stmt, StmtConnect, StmtDeclaration, StmtInstance, StmtReg, StmtWire,
|
ModuleBody, Stmt, StmtConnect, StmtDeclaration, StmtInstance, StmtReg, StmtWire,
|
||||||
transform::visit::{Fold, Folder, Visit, Visitor},
|
transform::visit::{Fold, Folder, Visit, Visitor},
|
||||||
},
|
},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
util::{
|
util::{
|
||||||
HashMap,
|
BitSliceWriteWithBase, HashMap,
|
||||||
indented_print::{PushIndent, indented_println},
|
indented_print::{PushIndent, indented_println},
|
||||||
union_find_map::{Entry, UnionFindMap},
|
union_find_map::{Entry, UnionFindMap},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
use bitvec::{order::Lsb0, view::BitView};
|
||||||
use std::{convert::Infallible, fmt};
|
use std::{convert::Infallible, fmt};
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
|
|
@ -77,6 +78,181 @@ impl fmt::Debug for FlagsTree {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
|
enum FlagsTreeSourceValue<'a> {
|
||||||
|
LiteralBits { bits: &'a BitSlice },
|
||||||
|
Flags { assume_padding_is_zeroed: bool },
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> fmt::Debug for FlagsTreeSourceValue<'a> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::LiteralBits { bits } => f
|
||||||
|
.debug_struct("LiteralBits")
|
||||||
|
.field(
|
||||||
|
"bits",
|
||||||
|
&fmt::from_fn(|f| write!(f, "{:#b}", BitSliceWriteWithBase(bits))),
|
||||||
|
)
|
||||||
|
.finish(),
|
||||||
|
Self::Flags {
|
||||||
|
assume_padding_is_zeroed,
|
||||||
|
} => f
|
||||||
|
.debug_struct("Flags")
|
||||||
|
.field("assume_padding_is_zeroed", assume_padding_is_zeroed)
|
||||||
|
.finish(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
|
enum FlagsTreeSourceValueOwned {
|
||||||
|
LiteralBits { bits: Interned<BitSlice> },
|
||||||
|
Flags { assume_padding_is_zeroed: bool },
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FlagsTreeSourceValueOwned {
|
||||||
|
fn as_ref(&self) -> FlagsTreeSourceValue<'_> {
|
||||||
|
match *self {
|
||||||
|
Self::LiteralBits { ref bits } => FlagsTreeSourceValue::LiteralBits { bits },
|
||||||
|
Self::Flags {
|
||||||
|
assume_padding_is_zeroed,
|
||||||
|
} => FlagsTreeSourceValue::Flags {
|
||||||
|
assume_padding_is_zeroed,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> FlagsTreeSourceValue<'a> {
|
||||||
|
fn to_owned(self) -> FlagsTreeSourceValueOwned {
|
||||||
|
match self {
|
||||||
|
Self::LiteralBits { bits } => FlagsTreeSourceValueOwned::LiteralBits {
|
||||||
|
bits: bits.intern(),
|
||||||
|
},
|
||||||
|
Self::Flags {
|
||||||
|
assume_padding_is_zeroed,
|
||||||
|
} => FlagsTreeSourceValueOwned::Flags {
|
||||||
|
assume_padding_is_zeroed,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn visit_array_body<T, R: FromIterator<T>>(
|
||||||
|
self,
|
||||||
|
element_ty: CanonicalType,
|
||||||
|
f: impl FnMut(Self) -> T,
|
||||||
|
) -> R {
|
||||||
|
match self {
|
||||||
|
Self::LiteralBits { bits } => {
|
||||||
|
let bit_width = element_ty.bit_width();
|
||||||
|
if bit_width == 0 {
|
||||||
|
R::from_iter([])
|
||||||
|
} else {
|
||||||
|
bits.chunks(bit_width)
|
||||||
|
.map(|bits| Self::LiteralBits { bits })
|
||||||
|
.map(f)
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Self::Flags { .. } => [self].into_iter().map(f).collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn visit_bundle_body<T, R: FromIterator<T>>(
|
||||||
|
self,
|
||||||
|
bundle: Bundle,
|
||||||
|
mut f: impl FnMut(usize, &BundleField, Self) -> T,
|
||||||
|
) -> R {
|
||||||
|
match self {
|
||||||
|
Self::LiteralBits { bits } => bundle
|
||||||
|
.fields()
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.scan(bits, |bundle_bits, (field_index, field)| {
|
||||||
|
let field_bit_width = field.ty.bit_width();
|
||||||
|
let bits;
|
||||||
|
(bits, *bundle_bits) = bundle_bits.split_at(field_bit_width);
|
||||||
|
Some(f(field_index, field, Self::LiteralBits { bits }))
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
Self::Flags { .. } => bundle
|
||||||
|
.fields()
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(move |(field_index, field)| f(field_index, field, self))
|
||||||
|
.collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn visit_enum_body<T, R: FromIterator<T>>(
|
||||||
|
self,
|
||||||
|
enum_: Enum,
|
||||||
|
debug_trace: bool,
|
||||||
|
mut f: impl FnMut(&EnumVariant, Self) -> T,
|
||||||
|
) -> (R, bool) {
|
||||||
|
let collected;
|
||||||
|
let padding_is_zeroed;
|
||||||
|
match self {
|
||||||
|
Self::LiteralBits { bits } => {
|
||||||
|
let mut discriminant = 0usize;
|
||||||
|
let discriminant_bit_width = enum_.discriminant_bit_width();
|
||||||
|
let (discriminant_bits, bits) = bits.split_at(discriminant_bit_width);
|
||||||
|
if debug_trace {
|
||||||
|
indented_println!(
|
||||||
|
"discriminant_bits={:#b}",
|
||||||
|
BitSliceWriteWithBase(discriminant_bits)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
discriminant.view_bits_mut::<Lsb0>()[..discriminant_bit_width]
|
||||||
|
.copy_from_bitslice(discriminant_bits);
|
||||||
|
let (bits, padding) = bits.split_at(
|
||||||
|
enum_
|
||||||
|
.variants()
|
||||||
|
.get(discriminant)
|
||||||
|
.and_then(|variant| variant.ty)
|
||||||
|
.map_or(0, |variant_ty| variant_ty.bit_width()),
|
||||||
|
);
|
||||||
|
if debug_trace {
|
||||||
|
indented_println!(
|
||||||
|
"bits={:#b}\npadding={:#b}",
|
||||||
|
BitSliceWriteWithBase(bits),
|
||||||
|
BitSliceWriteWithBase(padding),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
collected = enum_
|
||||||
|
.variants()
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(variant_index, variant)| {
|
||||||
|
f(
|
||||||
|
variant,
|
||||||
|
if variant_index == discriminant {
|
||||||
|
Self::LiteralBits { bits }
|
||||||
|
} else {
|
||||||
|
Self::Flags {
|
||||||
|
assume_padding_is_zeroed: true,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
padding_is_zeroed = !padding.any();
|
||||||
|
if debug_trace {
|
||||||
|
indented_println!("padding_is_zeroed={padding_is_zeroed:?}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Self::Flags {
|
||||||
|
assume_padding_is_zeroed,
|
||||||
|
} => {
|
||||||
|
collected = enum_
|
||||||
|
.variants()
|
||||||
|
.iter()
|
||||||
|
.map(|variant| f(variant, self))
|
||||||
|
.collect();
|
||||||
|
padding_is_zeroed = assume_padding_is_zeroed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(collected, padding_is_zeroed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl FlagsTree {
|
impl FlagsTree {
|
||||||
fn contains_padding(&self) -> bool {
|
fn contains_padding(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
|
|
@ -97,8 +273,19 @@ impl FlagsTree {
|
||||||
Self::NoPadding => true,
|
Self::NoPadding => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn new_inner(ty: CanonicalType, assume_padding_is_zeroed: bool) -> Interned<Self> {
|
fn new_inner<'a>(
|
||||||
match ty {
|
ty: &CanonicalType,
|
||||||
|
source_value: FlagsTreeSourceValue<'a>,
|
||||||
|
debug_trace: bool,
|
||||||
|
) -> Interned<Self> {
|
||||||
|
let _push_indent;
|
||||||
|
if debug_trace {
|
||||||
|
indented_println!("FlagsTree::new_inner()");
|
||||||
|
_push_indent = PushIndent::new();
|
||||||
|
indented_println!("ty: {ty:?}");
|
||||||
|
indented_println!("source_value: {source_value:?}");
|
||||||
|
}
|
||||||
|
let retval = match ty {
|
||||||
CanonicalType::UInt(_)
|
CanonicalType::UInt(_)
|
||||||
| CanonicalType::SInt(_)
|
| CanonicalType::SInt(_)
|
||||||
| CanonicalType::Bool(_)
|
| CanonicalType::Bool(_)
|
||||||
|
|
@ -109,25 +296,33 @@ impl FlagsTree {
|
||||||
| CanonicalType::PhantomConst(_)
|
| CanonicalType::PhantomConst(_)
|
||||||
| CanonicalType::DynSimOnly(_) => Self::NoPadding.intern_sized(),
|
| CanonicalType::DynSimOnly(_) => Self::NoPadding.intern_sized(),
|
||||||
CanonicalType::Array(ty) => {
|
CanonicalType::Array(ty) => {
|
||||||
if ty.is_empty() {
|
let mut retval = None;
|
||||||
Self::NoPadding.intern_sized()
|
let element_ty = ty.element();
|
||||||
} else {
|
let () =
|
||||||
Self::new(ty.element(), assume_padding_is_zeroed)
|
source_value.visit_array_body(element_ty, |source_value| match &mut retval {
|
||||||
|
Some(retval) => {
|
||||||
|
*retval = FlagsTree::new(element_ty, source_value, debug_trace)
|
||||||
|
.merged(*retval)
|
||||||
}
|
}
|
||||||
|
None => retval = Some(Self::new(element_ty, source_value, debug_trace)),
|
||||||
|
});
|
||||||
|
retval.unwrap_or_else(|| Self::NoPadding.intern_sized())
|
||||||
}
|
}
|
||||||
CanonicalType::Enum(ty) => {
|
CanonicalType::Enum(ty) => {
|
||||||
let mut expected_bit_width = None;
|
let mut expected_bit_width = None;
|
||||||
let mut variants = Vec::with_capacity(ty.variants().len());
|
|
||||||
let mut contains_padding = false;
|
let mut contains_padding = false;
|
||||||
for variant in ty.variants() {
|
let mut assume_padding_is_zeroed = true;
|
||||||
|
let (variants, padding_is_zeroed): (Vec<_>, _) =
|
||||||
|
source_value.visit_enum_body(*ty, debug_trace, |variant, source_value| {
|
||||||
|
let (variant_flags_tree, bit_width) = if let Some(variant_ty) = variant.ty {
|
||||||
let variant_flags_tree =
|
let variant_flags_tree =
|
||||||
variant.ty.map(|ty| Self::new(ty, assume_padding_is_zeroed));
|
Self::new(variant_ty, source_value, debug_trace);
|
||||||
variants.push(variant_flags_tree);
|
contains_padding |= variant_flags_tree.contains_padding();
|
||||||
contains_padding |= variant_flags_tree.is_some_and(|v| v.contains_padding());
|
assume_padding_is_zeroed &=
|
||||||
let bit_width = if let Some(ty) = variant.ty {
|
variant_flags_tree.assume_padding_is_zeroed();
|
||||||
ty.bit_width()
|
(Some(variant_flags_tree), variant_ty.bit_width())
|
||||||
} else {
|
} else {
|
||||||
0
|
(None, 0)
|
||||||
};
|
};
|
||||||
if expected_bit_width
|
if expected_bit_width
|
||||||
.replace(bit_width)
|
.replace(bit_width)
|
||||||
|
|
@ -135,7 +330,9 @@ impl FlagsTree {
|
||||||
{
|
{
|
||||||
contains_padding = true;
|
contains_padding = true;
|
||||||
}
|
}
|
||||||
}
|
variant_flags_tree
|
||||||
|
});
|
||||||
|
assume_padding_is_zeroed &= padding_is_zeroed;
|
||||||
if contains_padding {
|
if contains_padding {
|
||||||
Self::Enum {
|
Self::Enum {
|
||||||
variants: variants.intern_slice(),
|
variants: variants.intern_slice(),
|
||||||
|
|
@ -148,11 +345,14 @@ impl FlagsTree {
|
||||||
}
|
}
|
||||||
CanonicalType::Bundle(ty) => {
|
CanonicalType::Bundle(ty) => {
|
||||||
let mut contains_padding = false;
|
let mut contains_padding = false;
|
||||||
let fields = Vec::from_iter(ty.fields().iter().map(|field| {
|
let mut assume_padding_is_zeroed = true;
|
||||||
let flags_tree = Self::new(field.ty, assume_padding_is_zeroed);
|
let fields: Vec<_> =
|
||||||
|
source_value.visit_bundle_body(*ty, |_field_index, field, source_value| {
|
||||||
|
let flags_tree = Self::new(field.ty, source_value, debug_trace);
|
||||||
contains_padding |= flags_tree.contains_padding();
|
contains_padding |= flags_tree.contains_padding();
|
||||||
|
assume_padding_is_zeroed &= flags_tree.assume_padding_is_zeroed();
|
||||||
flags_tree
|
flags_tree
|
||||||
}));
|
});
|
||||||
if contains_padding {
|
if contains_padding {
|
||||||
Self::Bundle {
|
Self::Bundle {
|
||||||
fields: fields.intern_slice(),
|
fields: fields.intern_slice(),
|
||||||
|
|
@ -163,31 +363,77 @@ impl FlagsTree {
|
||||||
Self::NoPadding.intern_sized()
|
Self::NoPadding.intern_sized()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CanonicalType::TraceAsString(ty) => Self::new(ty.inner_ty(), assume_padding_is_zeroed),
|
CanonicalType::TraceAsString(ty) => Self::new(ty.inner_ty(), source_value, debug_trace),
|
||||||
|
};
|
||||||
|
if debug_trace {
|
||||||
|
indented_println!("return: {retval:#?}");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
fn new(ty: CanonicalType, assume_padding_is_zeroed: bool) -> Interned<Self> {
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
|
||||||
struct MyMemoize {
|
|
||||||
assume_padding_is_zeroed: bool,
|
|
||||||
}
|
|
||||||
impl Memoize for MyMemoize {
|
|
||||||
type Input = CanonicalType;
|
|
||||||
type InputOwned = CanonicalType;
|
|
||||||
type Output = Interned<FlagsTree>;
|
|
||||||
|
|
||||||
fn inner(self, input: &Self::Input) -> Self::Output {
|
|
||||||
let Self {
|
|
||||||
assume_padding_is_zeroed,
|
|
||||||
} = self;
|
|
||||||
let retval = FlagsTree::new_inner(*input, assume_padding_is_zeroed);
|
|
||||||
retval
|
retval
|
||||||
}
|
}
|
||||||
|
fn new(
|
||||||
|
ty: CanonicalType,
|
||||||
|
source_value: FlagsTreeSourceValue<'_>,
|
||||||
|
debug_trace: bool,
|
||||||
|
) -> Interned<Self> {
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
|
struct MyMemoize {
|
||||||
|
debug_trace: bool,
|
||||||
}
|
}
|
||||||
MyMemoize {
|
enum InputCow<'a> {
|
||||||
assume_padding_is_zeroed,
|
Borrowed {
|
||||||
|
ty: &'a CanonicalType,
|
||||||
|
source_value: FlagsTreeSourceValue<'a>,
|
||||||
|
},
|
||||||
|
Owned {
|
||||||
|
ty: CanonicalType,
|
||||||
|
source_value: FlagsTreeSourceValueOwned,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
.get_owned(ty)
|
impl MemoizeGeneric for MyMemoize {
|
||||||
|
type InputRef<'a> = (&'a CanonicalType, FlagsTreeSourceValue<'a>);
|
||||||
|
type InputOwned = (CanonicalType, FlagsTreeSourceValueOwned);
|
||||||
|
type InputCow<'a> = InputCow<'a>;
|
||||||
|
type Output = Interned<FlagsTree>;
|
||||||
|
|
||||||
|
fn input_eq(a: Self::InputRef<'_>, b: Self::InputRef<'_>) -> bool {
|
||||||
|
a == b
|
||||||
|
}
|
||||||
|
|
||||||
|
fn input_borrow(input: &Self::InputOwned) -> Self::InputRef<'_> {
|
||||||
|
let (ty, source_value) = input;
|
||||||
|
(ty, source_value.as_ref())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn input_cow_into_owned(input: Self::InputCow<'_>) -> Self::InputOwned {
|
||||||
|
match input {
|
||||||
|
InputCow::Borrowed { ty, source_value } => (*ty, source_value.to_owned()),
|
||||||
|
InputCow::Owned { ty, source_value } => (ty, source_value),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn input_cow_borrow<'a>(input: &'a Self::InputCow<'_>) -> Self::InputRef<'a> {
|
||||||
|
match input {
|
||||||
|
&InputCow::Borrowed { ty, source_value } => (ty, source_value),
|
||||||
|
InputCow::Owned { ty, source_value } => (ty, source_value.as_ref()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn input_cow_from_owned<'a>(input: Self::InputOwned) -> Self::InputCow<'a> {
|
||||||
|
let (ty, source_value) = input;
|
||||||
|
InputCow::Owned { ty, source_value }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn input_cow_from_ref(input: Self::InputRef<'_>) -> Self::InputCow<'_> {
|
||||||
|
let (ty, source_value) = input;
|
||||||
|
InputCow::Borrowed { ty, source_value }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn inner(self, input: Self::InputRef<'_>) -> Self::Output {
|
||||||
|
let (ty, source_value) = input;
|
||||||
|
FlagsTree::new_inner(ty, source_value, self.debug_trace)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MyMemoize { debug_trace }.get((&ty, source_value))
|
||||||
}
|
}
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn merged(self, other: Interned<FlagsTree>) -> Interned<FlagsTree> {
|
fn merged(self, other: Interned<FlagsTree>) -> Interned<FlagsTree> {
|
||||||
|
|
@ -596,12 +842,6 @@ impl<T: Type> ExprOrUnknown<T> {
|
||||||
Self::Unknown(ty) => ExprOrUnknown::Unknown(map_ty(ty)),
|
Self::Unknown(ty) => ExprOrUnknown::Unknown(map_ty(ty)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn map_unwrap<U>(self, map_ty: impl FnOnce(T) -> U, map_expr: impl FnOnce(Expr<T>) -> U) -> U {
|
|
||||||
match self {
|
|
||||||
Self::Expr(expr) => map_expr(expr),
|
|
||||||
Self::Unknown(ty) => map_ty(ty),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn from_canonical(v: ExprOrUnknown<CanonicalType>) -> Self {
|
fn from_canonical(v: ExprOrUnknown<CanonicalType>) -> Self {
|
||||||
match v {
|
match v {
|
||||||
ExprOrUnknown::Expr(expr) => Self::Expr(Expr::from_canonical(expr)),
|
ExprOrUnknown::Expr(expr) => Self::Expr(Expr::from_canonical(expr)),
|
||||||
|
|
@ -735,7 +975,13 @@ impl State {
|
||||||
fn visit_expr_or_unknown(&mut self, expr: ExprOrUnknown<CanonicalType>) -> Interned<FlagsTree> {
|
fn visit_expr_or_unknown(&mut self, expr: ExprOrUnknown<CanonicalType>) -> Interned<FlagsTree> {
|
||||||
match expr {
|
match expr {
|
||||||
ExprOrUnknown::Expr(expr) => self.visit_canonical_expr(expr),
|
ExprOrUnknown::Expr(expr) => self.visit_canonical_expr(expr),
|
||||||
ExprOrUnknown::Unknown(ty) => FlagsTree::new(ty, false),
|
ExprOrUnknown::Unknown(ty) => FlagsTree::new(
|
||||||
|
ty,
|
||||||
|
FlagsTreeSourceValue::Flags {
|
||||||
|
assume_padding_is_zeroed: false,
|
||||||
|
},
|
||||||
|
self.debug_trace,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn connect(
|
fn connect(
|
||||||
|
|
@ -880,7 +1126,13 @@ impl State {
|
||||||
let visited = self.exprs_visited.entry(expr_enum).or_insert(false);
|
let visited = self.exprs_visited.entry(expr_enum).or_insert(false);
|
||||||
let flags = *self.expr_flags.entry(expr_enum).or_insert_with(|| {
|
let flags = *self.expr_flags.entry(expr_enum).or_insert_with(|| {
|
||||||
self.any_changes = true;
|
self.any_changes = true;
|
||||||
FlagsTree::new(ty, true)
|
FlagsTree::new(
|
||||||
|
ty,
|
||||||
|
FlagsTreeSourceValue::Flags {
|
||||||
|
assume_padding_is_zeroed: true,
|
||||||
|
},
|
||||||
|
self.debug_trace,
|
||||||
|
)
|
||||||
});
|
});
|
||||||
if std::mem::replace(visited, true) {
|
if std::mem::replace(visited, true) {
|
||||||
return flags;
|
return flags;
|
||||||
|
|
@ -898,7 +1150,18 @@ impl State {
|
||||||
let (flags, _) = this.connect(ExprOrUnknown::Expr(expr), init);
|
let (flags, _) = this.connect(ExprOrUnknown::Expr(expr), init);
|
||||||
*flags
|
*flags
|
||||||
};
|
};
|
||||||
|
let literal_bits = expr_enum.to_literal_bits();
|
||||||
let flags = match *expr_enum {
|
let flags = match *expr_enum {
|
||||||
|
_ if literal_bits.is_ok() => {
|
||||||
|
let Ok(bits) = &literal_bits else {
|
||||||
|
unreachable!();
|
||||||
|
};
|
||||||
|
*FlagsTree::new(
|
||||||
|
ty,
|
||||||
|
FlagsTreeSourceValue::LiteralBits { bits },
|
||||||
|
self.debug_trace,
|
||||||
|
)
|
||||||
|
}
|
||||||
ExprEnum::UIntLiteral(_)
|
ExprEnum::UIntLiteral(_)
|
||||||
| ExprEnum::SIntLiteral(_)
|
| ExprEnum::SIntLiteral(_)
|
||||||
| ExprEnum::BoolLiteral(_)
|
| ExprEnum::BoolLiteral(_)
|
||||||
|
|
@ -948,7 +1211,13 @@ impl State {
|
||||||
}
|
}
|
||||||
*flags
|
*flags
|
||||||
}
|
}
|
||||||
ExprEnum::Uninit(_) => *FlagsTree::new(ty, false),
|
ExprEnum::Uninit(_) => *FlagsTree::new(
|
||||||
|
ty,
|
||||||
|
FlagsTreeSourceValue::Flags {
|
||||||
|
assume_padding_is_zeroed: false,
|
||||||
|
},
|
||||||
|
self.debug_trace,
|
||||||
|
),
|
||||||
ExprEnum::NotU(_)
|
ExprEnum::NotU(_)
|
||||||
| ExprEnum::NotS(_)
|
| ExprEnum::NotS(_)
|
||||||
| ExprEnum::NotB(_)
|
| ExprEnum::NotB(_)
|
||||||
|
|
@ -1113,7 +1382,13 @@ impl State {
|
||||||
| ExprEnum::SliceUInt(_)
|
| ExprEnum::SliceUInt(_)
|
||||||
| ExprEnum::SliceSInt(_)
|
| ExprEnum::SliceSInt(_)
|
||||||
| ExprEnum::CastToBits(_) => *flags,
|
| ExprEnum::CastToBits(_) => *flags,
|
||||||
ExprEnum::CastBitsTo(_) => *FlagsTree::new(ty, false),
|
ExprEnum::CastBitsTo(_) => *FlagsTree::new(
|
||||||
|
ty,
|
||||||
|
FlagsTreeSourceValue::Flags {
|
||||||
|
assume_padding_is_zeroed: false,
|
||||||
|
},
|
||||||
|
self.debug_trace,
|
||||||
|
),
|
||||||
ExprEnum::ToTraceAsString(expr) => {
|
ExprEnum::ToTraceAsString(expr) => {
|
||||||
self.visit_canonical_expr(Expr::canonical(expr.inner()));
|
self.visit_canonical_expr(Expr::canonical(expr.inner()));
|
||||||
// FlagsTree treats TraceAsString transparently, so just union them together.
|
// FlagsTree treats TraceAsString transparently, so just union them together.
|
||||||
|
|
@ -1143,8 +1418,20 @@ impl State {
|
||||||
ExprEnum::Reg(reg) => handle_reg(self, reg.init()),
|
ExprEnum::Reg(reg) => handle_reg(self, reg.init()),
|
||||||
ExprEnum::RegSync(reg) => handle_reg(self, reg.init()),
|
ExprEnum::RegSync(reg) => handle_reg(self, reg.init()),
|
||||||
ExprEnum::RegAsync(reg) => handle_reg(self, reg.init()),
|
ExprEnum::RegAsync(reg) => handle_reg(self, reg.init()),
|
||||||
ExprEnum::MemPort(_) => *FlagsTree::new(ty, false),
|
ExprEnum::MemPort(_) => *FlagsTree::new(
|
||||||
ExprEnum::FormalInput(_) => *FlagsTree::new(ty, false),
|
ty,
|
||||||
|
FlagsTreeSourceValue::Flags {
|
||||||
|
assume_padding_is_zeroed: false,
|
||||||
|
},
|
||||||
|
self.debug_trace,
|
||||||
|
),
|
||||||
|
ExprEnum::FormalInput(_) => *FlagsTree::new(
|
||||||
|
ty,
|
||||||
|
FlagsTreeSourceValue::Flags {
|
||||||
|
assume_padding_is_zeroed: false,
|
||||||
|
},
|
||||||
|
self.debug_trace,
|
||||||
|
),
|
||||||
ExprEnum::SimIoForGlobal(_) => {
|
ExprEnum::SimIoForGlobal(_) => {
|
||||||
unreachable!("Module is known to not contain SimIoForGlobal from validation")
|
unreachable!("Module is known to not contain SimIoForGlobal from validation")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue