Skip to content

Conversation

@saethlin
Copy link
Contributor

Currently, rustlantis tends to generate a lot of assignments to the same place within the same basic block. This is especially silly when the assignments to the same place occur next to each other. For example, this is the first basic block that comes out of generate with seed 0:

{
_1 = !63487_u16;
_4 = !1390730785_u32;
RET = 9852_i16 as f64;
_3 = (-138109794282916576908390722958742720726_i128) << _1;
_4 = !688210538_u32;
_1 = !35107_u16;
RET = _3 as f64;
_4 = 562135920_u32 + 3663929644_u32;
RET = (-2719951640687674442_i64) as f64;
_3 = 1981794491838386707_u64 as i128;
RET = 5_usize as f64;
_3 = 125582680801400656974857784996786910228_i128 + (-49121485659754867407561513453388421295_i128);
_1 = 31074_u16;
_6 = -RET;
_6 = RET - RET;
_4 = !3232469644_u32;
_2 = '\u{65a79}';
_2 = '\u{756c8}';
_8 = _1 >> _3;
_2 = '\u{216e4}';
_3 = 126_u8 as i128;
_8 = _1 & _1;
_6 = RET * RET;
Goto(bb1)
}

In particular, I think this is wasteful:

_6 = -RET;
_6 = RET - RET;
_2 = '\u{65a79}';
_2 = '\u{756c8}';

So this PR is a very hacky way to prevent those. It works, but I'd appreciate advice on making it more elegant.

@cbeuw
Copy link
Owner

cbeuw commented Dec 21, 2025

I've tried to mitigating this issue previously, by reducing the weight of Places with high complexity1 when generating LHS: 70e2b0a. But I think I did it wrong and I eventually removed weight's dependency on complexity for LHS altogether. I'm more keen on trying something on this front again.

For the issue in particular where a place is getting assigned with literals repeatedly, e.g.

_2 = '\u{65a79}';
_2 = '\u{756c8}';

This is a sign that there isn't enough variables in the function for Rustlantis to find a non-literal Rvalue, since a literal operand is only generated as a last resort:

operand.or_else(|_| {
let literalble: Vec<TyId> = tys
.iter()
.filter(|ty| <dyn RngCore>::is_literalble(**ty, &self.tcx))
.copied()
.collect();
if literalble.is_empty() {
Err(SelectionError::Exhausted)
} else {
let selected = literalble
.iter()
.choose(&mut *self.rng.borrow_mut())
.unwrap();
let literal = self
.rng
.borrow_mut()
.gen_literal(*selected, &self.tcx)
.expect("can always generate a literal of a literalble type");
Ok(Operand::Constant(literal))
}
})

I made a separate PR to address this #13, by giving each function more variables to play with. I think it helps a bit, but a more data-flow-ish guided LHS selection is still desirable on top of this

Footnotes

  1. This is a proxy for the amount of reaching definitions for a Place's current value. If place = literal + literal then its complexity is 2. If it's then assigned with place = place + place' where place' has complexity 4, then place's new complexity is 2+4=6

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants