When trying to negate a value, V, we try to avoid materializing the negated value by scanning the use list of V to see if we already have one. If we do find a negated version and that version is in the block we're currently optimizing, moving that instruction may invalidate our iterator.
Example:
define void @fn1(i32 %a, i1 %c, i32* %ptr) {
entry:
br label %for.cond
for.cond:
%d.0 = phi i32 [ 1, %entry ], [ 2, %for.body ]
br i1 %c, label %for.end, label %for.body
for.body:
%sub1 = sub i32 %a, %d.0
%dead1 = add i32 %sub1, 1
%dead2 = mul i32 %dead1, 3
%dead3 = mul i32 %dead2, %sub1
%sub2 = sub nsw i32 0, %d.0
store i32 %sub2, i32* %ptr, align 4
br label %for.cond
for.end:
ret void
}The invalidation occurs as follows:
- Assume we're optimizing %dead3, which is trivially dead.
- The BB iterator is incremented (now pointing to %sub2) and EraseInst is called to delete %dead3.
- When the %dead3 instruction is removed its operand %sub1 is added to the RedoInst list.
- When %sub1 is reoptimized the ShouldBreakUpSubtract() function returns true and the BreakUpSubtract() function is called. This didn't happen the first time %sub1 was optimized because it had more than one use (i.e., %dead1 and %dead3).
- The NegateValue() function then hoists the %sub2 (as it is the negated form of %d.0) instruction into the for.cond block invalidating the iterator and causing the assertion. Without the assert we would dereference an invalid iterator and segfault.
Please take a look,
Chad