From e949aa1c91132094a9073c82a8aef729fa8c9eca Mon Sep 17 00:00:00 2001 From: Chandler Carruth Date: Fri, 28 Dec 2012 14:23:29 +0000 Subject: [PATCH] Teach instsimplify to use the constant folder where appropriate for 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 | 4 +- lib/Analysis/InstructionSimplify.cpp | 37 +++++++++++---- test/Transforms/InstSimplify/call.ll | 52 +++++++++++++++++++++ 3 files changed, 83 insertions(+), 10 deletions(-) create mode 100644 test/Transforms/InstSimplify/call.ll diff --git a/include/llvm/Analysis/InstructionSimplify.h b/include/llvm/Analysis/InstructionSimplify.h index dd643a04693..e70bfe2860a 100644 --- a/include/llvm/Analysis/InstructionSimplify.h +++ b/include/llvm/Analysis/InstructionSimplify.h @@ -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 Args, + Value *SimplifyCall(Value *V, ArrayRef Args, const DataLayout *TD = 0, const TargetLibraryInfo *TLI = 0, const DominatorTree *DT = 0); diff --git a/lib/Analysis/InstructionSimplify.cpp b/lib/Analysis/InstructionSimplify.cpp index f0696f070d8..e1207f1e47c 100644 --- a/lib/Analysis/InstructionSimplify.cpp +++ b/lib/Analysis/InstructionSimplify.cpp @@ -2870,32 +2870,53 @@ Value *llvm::SimplifyCmpInst(unsigned Predicate, Value *LHS, Value *RHS, } template -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 +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(Ty)) Ty = PTy->getElementType(); FunctionType *FTy = cast(Ty); // call undef -> undef - if (isa(F)) + if (isa(V)) return UndefValue::get(FTy->getReturnType()); - return 0; + Function *F = dyn_cast(V); + if (!F) + return 0; + + if (!canConstantFoldCallTo(F)) + return 0; + + SmallVector ConstantArgs; + ConstantArgs.reserve(ArgEnd - ArgBegin); + for (IterTy I = ArgBegin, E = ArgEnd; I != E; ++I) { + Constant *C = dyn_cast(*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 Args, +Value *llvm::SimplifyCall(Value *V, ArrayRef 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 index 00000000000..1a8d0c25bd2 --- /dev/null +++ b/test/Transforms/InstSimplify/call.ll @@ -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 +} -- 2.34.1