summaryrefslogtreecommitdiffstats
path: root/llvm
diff options
context:
space:
mode:
authorAmara Emerson <aemerson@apple.com>2018-10-11 14:51:11 +0000
committerAmara Emerson <aemerson@apple.com>2018-10-11 14:51:11 +0000
commit54f60255a2ee960776cc3aa4a6a9340fc8a2ea7f (patch)
treedccf215b777a1119f52e3cc730b9c5f9d734cb50 /llvm
parent7d2f783e7d08c1f6cb162250c828cf6d54108802 (diff)
downloadbcm5719-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')
-rw-r--r--llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h23
-rw-r--r--llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp6
-rw-r--r--llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp24
-rw-r--r--llvm/test/Transforms/InstCombine/simplify-libcalls-erased.ll25
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 }
OpenPOWER on IntegriCloud