OSDN Git Service

[SimplifyLibCalls] Lower fls() to llvm.ctlz().
authorDavide Italiano <davide@freebsd.org>
Thu, 15 Dec 2016 23:45:11 +0000 (23:45 +0000)
committerDavide Italiano <davide@freebsd.org>
Thu, 15 Dec 2016 23:45:11 +0000 (23:45 +0000)
Differential Revision:  https://reviews.llvm.org/D14590

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

include/llvm/Transforms/Utils/SimplifyLibCalls.h
lib/Analysis/TargetLibraryInfo.cpp
lib/Transforms/Utils/SimplifyLibCalls.cpp
test/Transforms/InstCombine/fls.ll [new file with mode: 0644]

index 92ee246..cadc2cc 100644 (file)
@@ -137,6 +137,7 @@ private:
 
   // Integer Library Call Optimizations
   Value *optimizeFFS(CallInst *CI, IRBuilder<> &B);
+  Value *optimizeFls(CallInst *CI, IRBuilder<> &B);
   Value *optimizeAbs(CallInst *CI, IRBuilder<> &B);
   Value *optimizeIsDigit(CallInst *CI, IRBuilder<> &B);
   Value *optimizeIsAscii(CallInst *CI, IRBuilder<> &B);
index db0e86a..112118a 100644 (file)
@@ -986,6 +986,9 @@ bool TargetLibraryInfoImpl::isValidProtoForLibFunc(const FunctionType &FTy,
   case LibFunc::ffs:
   case LibFunc::ffsl:
   case LibFunc::ffsll:
+  case LibFunc::fls:
+  case LibFunc::flsl:
+  case LibFunc::flsll:
     return (NumParams == 1 && FTy.getReturnType()->isIntegerTy(32) &&
             FTy.getParamType(0)->isIntegerTy());
 
@@ -995,9 +998,6 @@ bool TargetLibraryInfoImpl::isValidProtoForLibFunc(const FunctionType &FTy,
     return (NumParams == 1 && FTy.getReturnType()->isIntegerTy(32) &&
             FTy.getReturnType() == FTy.getParamType(0));
 
-  case LibFunc::fls:
-  case LibFunc::flsl:
-  case LibFunc::flsll:
   case LibFunc::abs:
   case LibFunc::labs:
   case LibFunc::llabs:
index d3eae6e..d11c215 100644 (file)
@@ -1534,6 +1534,18 @@ Value *LibCallSimplifier::optimizeFFS(CallInst *CI, IRBuilder<> &B) {
   return B.CreateSelect(Cond, V, B.getInt32(0));
 }
 
+Value *LibCallSimplifier::optimizeFls(CallInst *CI, IRBuilder<> &B) {
+  // fls(x) -> (i32)(sizeInBits(x) - llvm.ctlz(x, false))
+  Value *Op = CI->getArgOperand(0);
+  Type *ArgType = Op->getType();
+  Value *F = Intrinsic::getDeclaration(CI->getCalledFunction()->getParent(),
+                                       Intrinsic::ctlz, ArgType);
+  Value *V = B.CreateCall(F, {Op, B.getFalse()}, "ctlz");
+  V = B.CreateSub(ConstantInt::get(V->getType(), ArgType->getIntegerBitWidth()),
+                  V);
+  return B.CreateIntCast(V, CI->getType(), false);
+}
+
 Value *LibCallSimplifier::optimizeAbs(CallInst *CI, IRBuilder<> &B) {
   // abs(x) -> x >s -1 ? x : -x
   Value *Op = CI->getArgOperand(0);
@@ -2070,6 +2082,10 @@ Value *LibCallSimplifier::optimizeCall(CallInst *CI) {
     case LibFunc::ffsl:
     case LibFunc::ffsll:
       return optimizeFFS(CI, Builder);
+    case LibFunc::fls:
+    case LibFunc::flsl:
+    case LibFunc::flsll:
+      return optimizeFls(CI, Builder);
     case LibFunc::abs:
     case LibFunc::labs:
     case LibFunc::llabs:
diff --git a/test/Transforms/InstCombine/fls.ll b/test/Transforms/InstCombine/fls.ll
new file mode 100644 (file)
index 0000000..bf608b3
--- /dev/null
@@ -0,0 +1,48 @@
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+target triple = "x86_64-unknown-freebsd11.0"
+
+
+; CHECK-LABEL: define i32 @myfls(
+; CHECK: ret i32 6
+; CHECK: }
+
+define i32 @myfls() {
+entry:
+  %call = call i32 @fls(i32 42)
+  ret i32 %call
+}
+
+; CHECK-LABEL: define i32 @myflsl(
+; CHECK: ret i32 6
+; CHECK: }
+
+define i32 @myflsl() {
+  %patatino = call i32 @flsl(i64 42)
+  ret i32 %patatino
+}
+
+; CHECK-LABEL: define i32 @myflsll(
+; CHECK: ret i32 6
+; CHECK: }
+
+define i32 @myflsll() {
+  %whatever = call i32 @flsll(i64 42)
+  ret i32 %whatever
+}
+
+; Lower to llvm.ctlz() if the argument is not a constant
+; CHECK-LABEL: define i32 @flsnotconst(
+; CHECK-NEXT:  %ctlz = call i64 @llvm.ctlz.i64(i64 %z, i1 false)
+; CHECK-NEXT:  %1 = sub nsw i64 64, %ctlz
+; CHECK-NEXT:  %2 = trunc i64 %1 to i32
+; CHECK-NEXT:  ret i32 %2
+
+define i32 @flsnotconst(i64 %z) {
+  %goo = call i32 @flsl(i64 %z)
+  ret i32 %goo
+}
+
+declare i32 @fls(i32)
+declare i32 @flsl(i64)
+declare i32 @flsll(i64)