For example in a loop, just removing a lifetime.end intrinsic can
interact badly with loop rotation, which might move the corresponding
lifetime.start intrinsic to the end of the loop.
So with the lifetime.end intrinsic removed you can end up with something
like:
block: store i8 %foo, i8* %bar call void @llvm.lifetime.start(i64 1, i8* %bar)
Without a corresponding lifetime.end, meaning that the store is invalid.
If the lifetime.end intrinsic is kept, we get this instead:
block: store i8 %foo, i8* %bar call void @llvm.lifetime.end(i64 1, i8* %bar) call void @llvm.lifetime.start(i64 1, i8* %bar)
Which is fine, since the store is within a valid lifetime region.