[llvm-commits] PATCH: Make instsimplify survive degenerate, unreachable code formations
Duncan Sands
baldrick at free.fr
Fri Mar 23 11:19:31 PDT 2012
Hi Chandler,
> The current instsimplify ReplaceAndSimplifyAllUses function has a bug that
> impacts its usage from inside the inliner, or in other contexts where it may
> try to simplify code inside of an unreachable block. It checks initially
> that From != To, but it then uses a WeakVH to keep track of both From and
> To. The result is that mutually recursive values can, in some very strange
> situations, end up replacing the From instruction with the To instruction
> deep inside of a recursion. When popping back out, the WeakVH tracks this,
> and we end up in an infinite loop trying to simplify an instruction with >0
> uses into itself.
> --- a/include/llvm/Analysis/InstructionSimplify.h
> +++ b/include/llvm/Analysis/InstructionSimplify.h
> @@ -189,16 +189,29 @@ namespace llvm {
> const DominatorTree *DT = 0);
>
>
> - /// ReplaceAndSimplifyAllUses - Perform From->replaceAllUsesWith(To) and then
> - /// delete the From instruction. In addition to a basic RAUW, this does a
> - /// recursive simplification of the updated instructions. This catches
> - /// things where one simplification exposes other opportunities. This only
> - /// simplifies and deletes scalar operations, it does not change the CFG.
> + /// \brief Replace all uses of 'I' with 'SimpleV' and simplify the uses
> + /// recursively.
> ///
> - void ReplaceAndSimplifyAllUses(Instruction *From, Value *To,
> - const TargetData *TD = 0,
> - const TargetLibraryInfo *TLI = 0,
> - const DominatorTree *DT = 0);
> + /// This first performs a normal RAUW of I with SimpleV. It then recursively
> + /// attempts to simplify those users updated by the operation. The 'I'
> + /// instruction must not be equal to the simplified value 'SimpleV'.
> + ///
> + /// The function returns true if any recursive simplifications were
> + /// performed.
maybe: The function returns true if any simplifications were performed.
> + bool replaceAndRecursivelySimplify(Instruction *I, Value *SimpleV,
> + const TargetData *TD = 0,
> + const TargetLibraryInfo *TLI = 0,
> + const DominatorTree *DT = 0);
> +
> + /// \brief Recursively attempt to simplify an instruction.
> + ///
> + /// This routine uses SimplifyInstruction to simplify 'I', and if successful
> + /// replaces uses of 'I' with the simplified value. It then recurses on each
> + /// of the users impacted. It returns true iff 'I' simplified successfully.
While it is logically equivalent, I think it would be better to say:
It returns true if any simplifications were performed.
> +/// This routine returns 'true' only when *it* simplifies something. The passed
> +/// in simplified value does not count toward this.
> +static bool replaceAndRecursivelySimplifyImpl(Instruction *I, Value *SimpleV,
> + const TargetData *TD,
> + const TargetLibraryInfo *TLI,
> + const DominatorTree *DT) {
> + bool Simplified = false;
> + SmallVector<Instruction *, 8> Worklist;
> +
> + // If we have an explicit value to collapse to, do that round of the
> + // simplification loop by hand initially.
> + if (SimpleV) {
> + for (Value::use_iterator UI = I->use_begin(), UE = I->use_end(); UI != UE;
> + ++UI)
> + Worklist.push_back(cast<Instruction>(*UI));
> +
> + // Replace the instruction with its simpler
^ The end of the comment seems to be missing.
> + I->replaceAllUsesWith(SimpleV);
> + I->eraseFromParent();
Why assume that I has a parent here?
> + } else {
> + Worklist.push_back(I);
> + }
>
> - // Recursively simplify this user to the new value.
> - ReplaceAndSimplifyAllUses(User, SimplifiedVal, TD, TLI, DT);
> - From = dyn_cast_or_null<Instruction>((Value*)FromHandle);
> - To = ToHandle;
> + while (!Worklist.empty()) {
> + I = Worklist.pop_back_val();
>
> - assert(ToHandle && "To value deleted by recursive simplification?");
> + // See if this instruction can simplify.
can simplify -> simplifies
> + SimpleV = SimplifyInstruction(I, TD, TLI, DT);
> + if (!SimpleV)
> + continue;
> +
> + Simplified = true;
> +
> + // Stash away all the uses of the old instruction so we can check them for
> + // recursive simplifications after a RAUW. This is cheaper than checking all
> + // uses of To on the recursive step in most cases.
> + for (Value::use_iterator UI = I->use_begin(), UE = I->use_end(); UI != UE;
> + ++UI)
> + Worklist.push_back(cast<Instruction>(*UI));
>
> - // If the recursive simplification ended up revisiting and deleting
> - // 'From' then we're done.
> - if (From == 0)
> - return;
> + // Replace the instruction with its simpler
^ Unterminated comment.
> + I->replaceAllUsesWith(SimpleV);
> +
> + // Gracefully handle edge cases where the instruction is not wired into any
> + // parent block.
> + if (I->getParent())
> + I->eraseFromParent();
> }
> + return Simplified;
> +}
Otherwise LGTM.
Ciao, Duncan.
More information about the llvm-commits
mailing list