Teach instsimplify to use the constant folder where appropriate for
authorChandler Carruth <chandlerc@gmail.com>
Fri, 28 Dec 2012 14:23:29 +0000 (14:23 +0000)
committerChandler Carruth <chandlerc@gmail.com>
Fri, 28 Dec 2012 14:23:29 +0000 (14:23 +0000)
constant folding calls. Add the initial tests for this which show that
now instsimplify can simplify blindingly obvious code patterns expressed
with both intrinsics and library calls.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@171194 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/Analysis/InstructionSimplify.h
lib/Analysis/InstructionSimplify.cpp
test/Transforms/InstSimplify/call.ll [new file with mode: 0644]

index dd643a0469387c603da5d93783071dd2d9355017..e70bfe2860a7d48f728451359bc7ae926da67fd2 100644 (file)
@@ -211,7 +211,7 @@ namespace llvm {
   /// the result.
   ///
   /// If this call could not be simplified returns null.
-  Value *SimplifyCall(Value *F, User::op_iterator ArgBegin,
+  Value *SimplifyCall(Value *V, User::op_iterator ArgBegin,
                       User::op_iterator ArgEnd, const DataLayout *TD = 0,
                       const TargetLibraryInfo *TLI = 0,
                       const DominatorTree *DT = 0);
@@ -220,7 +220,7 @@ namespace llvm {
   /// result.
   ///
   /// If this call could not be simplified returns null.
-  Value *SimplifyCall(Value *F, ArrayRef<Value *> Args,
+  Value *SimplifyCall(Value *V, ArrayRef<Value *> Args,
                       const DataLayout *TD = 0,
                       const TargetLibraryInfo *TLI = 0,
                       const DominatorTree *DT = 0);
index f0696f070d89947f8ca29ee65eb6f9a33c824740..e1207f1e47cfe2cfb2b9d060c4fcb9aa083883b1 100644 (file)
@@ -2870,32 +2870,53 @@ Value *llvm::SimplifyCmpInst(unsigned Predicate, Value *LHS, Value *RHS,
 }
 
 template <typename IterTy>
-static Value *SimplifyCall(Value *F, IterTy ArgBegin, IterTy ArgEnd,
+static Value *SimplifyIntrinsic(Intrinsic::ID IID, IterTy ArgBegin, IterTy ArgEnd,
+                                const Query &Q, unsigned MaxRecurse) {
+}
+
+template <typename IterTy>
+static Value *SimplifyCall(Value *V, IterTy ArgBegin, IterTy ArgEnd,
                            const Query &Q, unsigned MaxRecurse) {
-  Type *Ty = F->getType();
+  Type *Ty = V->getType();
   if (PointerType *PTy = dyn_cast<PointerType>(Ty))
     Ty = PTy->getElementType();
   FunctionType *FTy = cast<FunctionType>(Ty);
 
   // call undef -> undef
-  if (isa<UndefValue>(F))
+  if (isa<UndefValue>(V))
     return UndefValue::get(FTy->getReturnType());
 
-  return 0;
+  Function *F = dyn_cast<Function>(V);
+  if (!F)
+    return 0;
+
+  if (!canConstantFoldCallTo(F))
+    return 0;
+
+  SmallVector<Constant *, 4> ConstantArgs;
+  ConstantArgs.reserve(ArgEnd - ArgBegin);
+  for (IterTy I = ArgBegin, E = ArgEnd; I != E; ++I) {
+    Constant *C = dyn_cast<Constant>(*I);
+    if (!C)
+      return 0;
+    ConstantArgs.push_back(C);
+  }
+
+  return ConstantFoldCall(F, ConstantArgs, Q.TLI);
 }
 
-Value *llvm::SimplifyCall(Value *F, User::op_iterator ArgBegin,
+Value *llvm::SimplifyCall(Value *V, User::op_iterator ArgBegin,
                           User::op_iterator ArgEnd, const DataLayout *TD,
                           const TargetLibraryInfo *TLI,
                           const DominatorTree *DT) {
-  return ::SimplifyCall(F, ArgBegin, ArgEnd, Query(TD, TLI, DT),
+  return ::SimplifyCall(V, ArgBegin, ArgEnd, Query(TD, TLI, DT),
                         RecursionLimit);
 }
 
-Value *llvm::SimplifyCall(Value *F, ArrayRef<Value *> Args,
+Value *llvm::SimplifyCall(Value *V, ArrayRef<Value *> Args,
                           const DataLayout *TD, const TargetLibraryInfo *TLI,
                           const DominatorTree *DT) {
-  return ::SimplifyCall(F, Args.begin(), Args.end(), Query(TD, TLI, DT),
+  return ::SimplifyCall(V, Args.begin(), Args.end(), Query(TD, TLI, DT),
                         RecursionLimit);
 }
 
diff --git a/test/Transforms/InstSimplify/call.ll b/test/Transforms/InstSimplify/call.ll
new file mode 100644 (file)
index 0000000..1a8d0c2
--- /dev/null
@@ -0,0 +1,52 @@
+; RUN: opt < %s -instsimplify -S | FileCheck %s
+
+declare {i8, i1} @llvm.uadd.with.overflow.i8(i8 %a, i8 %b)
+
+define i1 @test_uadd1() {
+; CHECK: @test_uadd1
+  %x = call {i8, i1} @llvm.uadd.with.overflow.i8(i8 254, i8 3)
+  %overflow = extractvalue {i8, i1} %x, 1
+  ret i1 %overflow
+; CHECK-NEXT: ret i1 true
+}
+
+define i8 @test_uadd2() {
+; CHECK: @test_uadd2
+  %x = call {i8, i1} @llvm.uadd.with.overflow.i8(i8 254, i8 44)
+  %result = extractvalue {i8, i1} %x, 0
+  ret i8 %result
+; CHECK-NEXT: ret i8 42
+}
+
+declare i256 @llvm.cttz.i256(i256 %src, i1 %is_zero_undef)
+
+define i256 @test_cttz() {
+; CHECK: @test_cttz
+  %x = call i256 @llvm.cttz.i256(i256 10, i1 false)
+  ret i256 %x
+; CHECK-NEXT: ret i256 1
+}
+
+declare i256 @llvm.ctpop.i256(i256 %src)
+
+define i256 @test_ctpop() {
+; CHECK: @test_ctpop
+  %x = call i256 @llvm.ctpop.i256(i256 10)
+  ret i256 %x
+; CHECK-NEXT: ret i256 2
+}
+
+; Test a non-intrinsic that we know about as a library call.
+declare float @fabs(float %x)
+
+define float @test_fabs_libcall() {
+; CHECK: @test_fabs_libcall
+
+  %x = call float @fabs(float -42.0)
+; This is still a real function call, so instsimplify won't nuke it -- other
+; passes have to do that.
+; CHECK-NEXT: call float @fabs
+
+  ret float %x
+; CHECK-NEXT: ret float 4.2{{0+}}e+01
+}