Skip to main content

Invariant

Struct Invariant 

Source
pub struct Invariant { /* private fields */ }
Expand description

A value that does not change inside the loop, read as on + scale * value + offset.

The value is a value defined outside the loop, or None when the linear part is a plain number. Keeping the shape rather than a bare Value is what lets j = 2 * i + 3 come out as {3, +, 2} instead of unknown: the base and the step of that chrec are expressions nothing in the function computes, so a representation that could only name existing values would have to give up.

The on is a second symbol, and it is there for one shape: a pointer plus an index the loop did not start at zero. a[i] with i starting at a parameter has a first address of a + start * 4, which is two symbols, and a representation with room for one has to answer unknown to it. Nothing scales on and nothing negates it, because the thing it was added for is a pointer and a pointer is not something a loop multiplies. It is an Anchor rather than a value so that the address of a global can be one of them.

The read is the other half of the same shape, since in C that index is an int and what reaches the address is sext(start). It is described rather than named, for the reason on Widening. The two together are what let a[start + i] be followed, and on the SQLite amalgamation they take 158 checks and 12 sites off the largest row of loop splitting’s census. See tamnd/rucc#810.

Arithmetic on two of these is refused once the sum would need a third symbol, because x + y + z is not of this shape. That is the boundary of the subset and it is where the answer becomes unknown rather than wrong.

The fields are private on purpose. Every reader has to go through Invariant::plain, which hands back the one symbol reading and refuses when there is a pointer in it, or through Invariant::on, which hands back both halves. A reader that helped itself to value and scale would quietly drop the on and build an address off the wrong object.

Implementations§

Source§

impl Invariant

Source

pub fn number(offset: i128) -> Self

A plain number.

Source

pub fn of(value: Value) -> Self

One of a value.

Source

pub fn scaled(value: Value, scale: i128, offset: i128) -> Self

So many of a value, plus a number.

Source

pub fn address(symbol: Symbol) -> Self

The address of a global.

It goes straight into the on slot rather than into value, because that slot is the one for the thing an address is measured from and an address is the only thing this ever is. Nothing scales it and nothing negates it, which the rest of the arithmetic here already refuses for whatever is in that slot.

Source

pub fn plain(self) -> Option<Plain>

The one symbol reading, and None when there is a second symbol in it.

Source

pub fn on(self) -> Option<(Anchor, Plain)>

What it is measured from and how far past that, when there is a second symbol in it.

Exactly one of this and Invariant::plain answers, so a reader that handles both has handled every invariant there is.

Source

pub fn alike(self, other: Self) -> bool

Whether the two are the same expression apart from the number added to them.

Source

pub fn offset(self) -> i128

The number added to it, whatever else it has in it.

Source

pub fn as_number(self) -> Option<i128>

The number this is, when it is one.

Source

pub fn is_zero(self) -> bool

Whether this is the number zero.

Source

pub fn plus(self, other: Self) -> Option<Self>

The two added, when the sum is of this shape.

Source

pub fn minus(self, other: Self) -> Option<Self>

The second subtracted from the first, when the difference is of this shape.

Source

pub fn negated(self) -> Option<Self>

This with its sign flipped, which needs nothing to measure from.

A pointer is not a thing to negate, and the second symbol is only ever there because a pointer put it there.

Source

pub fn times(self, other: Self) -> Option<Self>

The two multiplied, which needs one of them to be a plain number and neither to be measured from anything.

Trait Implementations§

Source§

impl Clone for Invariant

Source§

fn clone(&self) -> Invariant

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Copy for Invariant

Source§

impl Debug for Invariant

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Eq for Invariant

Source§

impl PartialEq for Invariant

Source§

fn eq(&self, other: &Invariant) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl StructuralPartialEq for Invariant

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.