diff options
author | Amara Emerson <aemerson@apple.com> | 2018-10-11 14:51:11 +0000 |
---|---|---|
committer | Amara Emerson <aemerson@apple.com> | 2018-10-11 14:51:11 +0000 |
commit | 54f60255a2ee960776cc3aa4a6a9340fc8a2ea7f (patch) | |
tree | dccf215b777a1119f52e3cc730b9c5f9d734cb50 /llvm | |
parent | 7d2f783e7d08c1f6cb162250c828cf6d54108802 (diff) | |
download | bcm5719-llvm-54f60255a2ee960776cc3aa4a6a9340fc8a2ea7f.tar.gz bcm5719-llvm-54f60255a2ee960776cc3aa4a6a9340fc8a2ea7f.zip |
[InstCombine] Fix SimplifyLibCalls erasing an instruction while IC still had references to it.
InstCombine keeps a worklist and assumes that optimizations don't
eraseFromParent() the instruction, which SimplifyLibCalls violates. This change
adds a new callback to SimplifyLibCalls to let clients specify their own hander
for erasing actions.
Differential Revision: https://reviews.llvm.org/D52729
llvm-svn: 344251
Diffstat (limited to 'llvm')
4 files changed, 62 insertions, 16 deletions
diff --git a/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h b/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h index 2b344f44107..025bcd44e31 100644 --- a/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h +++ b/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h @@ -77,21 +77,34 @@ private: OptimizationRemarkEmitter &ORE; bool UnsafeFPShrink; function_ref<void(Instruction *, Value *)> Replacer; + function_ref<void(Instruction *)> Eraser; /// Internal wrapper for RAUW that is the default implementation. /// /// Other users may provide an alternate function with this signature instead /// of this one. - static void replaceAllUsesWithDefault(Instruction *I, Value *With); + static void replaceAllUsesWithDefault(Instruction *I, Value *With) { + I->replaceAllUsesWith(With); + } + + /// Internal wrapper for eraseFromParent that is the default implementation. + static void eraseFromParentDefault(Instruction *I) { I->eraseFromParent(); } /// Replace an instruction's uses with a value using our replacer. void replaceAllUsesWith(Instruction *I, Value *With); + /// Erase an instruction from its parent with our eraser. + void eraseFromParent(Instruction *I); + + Value *foldMallocMemset(CallInst *Memset, IRBuilder<> &B); + public: - LibCallSimplifier(const DataLayout &DL, const TargetLibraryInfo *TLI, - OptimizationRemarkEmitter &ORE, - function_ref<void(Instruction *, Value *)> Replacer = - &replaceAllUsesWithDefault); + LibCallSimplifier( + const DataLayout &DL, const TargetLibraryInfo *TLI, + OptimizationRemarkEmitter &ORE, + function_ref<void(Instruction *, Value *)> Replacer = + &replaceAllUsesWithDefault, + function_ref<void(Instruction *)> Eraser = &eraseFromParentDefault); /// optimizeCall - Take the given call instruction and return a more /// optimal value to replace the instruction with or 0 if a more diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp index 4e404933a22..714c6176884 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -3960,7 +3960,11 @@ Instruction *InstCombiner::tryOptimizeCall(CallInst *CI) { auto InstCombineRAUW = [this](Instruction *From, Value *With) { replaceInstUsesWith(*From, With); }; - LibCallSimplifier Simplifier(DL, &TLI, ORE, InstCombineRAUW); + auto InstCombineErase = [this](Instruction *I) { + eraseInstFromFunction(*I); + }; + LibCallSimplifier Simplifier(DL, &TLI, ORE, InstCombineRAUW, + InstCombineErase); if (Value *With = Simplifier.optimizeCall(CI)) { ++NumSimplified; return CI->use_empty() ? CI : replaceInstUsesWith(*CI, With); diff --git a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp index 3789181a898..41a495a0484 100644 --- a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp @@ -923,8 +923,7 @@ Value *LibCallSimplifier::optimizeMemMove(CallInst *CI, IRBuilder<> &B) { } /// Fold memset[_chk](malloc(n), 0, n) --> calloc(1, n). -static Value *foldMallocMemset(CallInst *Memset, IRBuilder<> &B, - const TargetLibraryInfo &TLI) { +Value *LibCallSimplifier::foldMallocMemset(CallInst *Memset, IRBuilder<> &B) { // This has to be a memset of zeros (bzero). auto *FillValue = dyn_cast<ConstantInt>(Memset->getArgOperand(1)); if (!FillValue || FillValue->getZExtValue() != 0) @@ -944,7 +943,7 @@ static Value *foldMallocMemset(CallInst *Memset, IRBuilder<> &B, return nullptr; LibFunc Func; - if (!TLI.getLibFunc(*InnerCallee, Func) || !TLI.has(Func) || + if (!TLI->getLibFunc(*InnerCallee, Func) || !TLI->has(Func) || Func != LibFunc_malloc) return nullptr; @@ -959,18 +958,18 @@ static Value *foldMallocMemset(CallInst *Memset, IRBuilder<> &B, IntegerType *SizeType = DL.getIntPtrType(B.GetInsertBlock()->getContext()); Value *Calloc = emitCalloc(ConstantInt::get(SizeType, 1), Malloc->getArgOperand(0), Malloc->getAttributes(), - B, TLI); + B, *TLI); if (!Calloc) return nullptr; Malloc->replaceAllUsesWith(Calloc); - Malloc->eraseFromParent(); + eraseFromParent(Malloc); return Calloc; } Value *LibCallSimplifier::optimizeMemSet(CallInst *CI, IRBuilder<> &B) { - if (auto *Calloc = foldMallocMemset(CI, B, *TLI)) + if (auto *Calloc = foldMallocMemset(CI, B)) return Calloc; // memset(p, v, n) -> llvm.memset(align 1 p, v, n) @@ -1246,7 +1245,7 @@ Value *LibCallSimplifier::replacePowWithExp(CallInst *Pow, IRBuilder<> &B) { // effects (e.g., errno). When the only consumer for the original // exp{,2}() is pow(), then it has to be explicitly erased. BaseFn->replaceAllUsesWith(ExpFn); - BaseFn->eraseFromParent(); + eraseFromParent(BaseFn); return ExpFn; } @@ -2591,7 +2590,7 @@ Value *LibCallSimplifier::optimizeCall(CallInst *CI) { if (Value *V = optimizeStringMemoryLibCall(SimplifiedCI, TmpBuilder)) { // If we were able to further simplify, remove the now redundant call. SimplifiedCI->replaceAllUsesWith(V); - SimplifiedCI->eraseFromParent(); + eraseFromParent(SimplifiedCI); return V; } } @@ -2670,15 +2669,20 @@ Value *LibCallSimplifier::optimizeCall(CallInst *CI) { LibCallSimplifier::LibCallSimplifier( const DataLayout &DL, const TargetLibraryInfo *TLI, OptimizationRemarkEmitter &ORE, - function_ref<void(Instruction *, Value *)> Replacer) + function_ref<void(Instruction *, Value *)> Replacer, + function_ref<void(Instruction *)> Eraser) : FortifiedSimplifier(TLI), DL(DL), TLI(TLI), ORE(ORE), - UnsafeFPShrink(false), Replacer(Replacer) {} + UnsafeFPShrink(false), Replacer(Replacer), Eraser(Eraser) {} void LibCallSimplifier::replaceAllUsesWith(Instruction *I, Value *With) { // Indirect through the replacer used in this instance. Replacer(I, With); } +void LibCallSimplifier::eraseFromParent(Instruction *I) { + Eraser(I); +} + // TODO: // Additional cases that we need to add to this file: // diff --git a/llvm/test/Transforms/InstCombine/simplify-libcalls-erased.ll b/llvm/test/Transforms/InstCombine/simplify-libcalls-erased.ll new file mode 100644 index 00000000000..19cfcf8eba9 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/simplify-libcalls-erased.ll @@ -0,0 +1,25 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -S < %s -instcombine | FileCheck %s + +target triple = "x86_64" + +define double @pow_exp(double %x, double %y) { +; CHECK-LABEL: @pow_exp( +; CHECK-NEXT: [[MUL:%.*]] = fmul fast double [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[EXP:%.*]] = call fast double @llvm.exp.f64(double [[MUL]]) +; CHECK-NEXT: ret double [[EXP]] +; + %A = alloca i1 + %call = call fast double @exp(double %x) #1 + %pow = call fast double @llvm.pow.f64(double %call, double %y) + %C1 = fcmp ule double %call, %pow + store i1 %C1, i1* %A + ret double %pow +} + +declare double @exp(double) + +declare double @llvm.pow.f64(double, double) #0 + +attributes #0 = { nounwind readnone speculatable } +attributes #1 = { nounwind readnone } |