Provide this optimization as well:
authorReid Spencer <rspencer@reidspencer.com>
Sun, 15 May 2005 21:19:45 +0000 (21:19 +0000)
committerReid Spencer <rspencer@reidspencer.com>
Sun, 15 May 2005 21:19:45 +0000 (21:19 +0000)
ffs(x) -> (x == 0 ? 0 : 1+llvm.cttz(x))

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

lib/Transforms/IPO/SimplifyLibCalls.cpp

index c7734a814f81ff1d7fc77cd92ea5501f890fea31..f3b28bd6cbc1ae64564b39e85496dafecc197a1a 100644 (file)
@@ -27,7 +27,6 @@
 #include "llvm/Support/Debug.h"
 #include "llvm/Target/TargetData.h"
 #include "llvm/Transforms/IPO.h"
-#include "llvm/Config/config.h"
 #include <iostream>
 using namespace llvm;
 
@@ -1673,7 +1672,6 @@ public:
   }
 } ToAsciiOptimizer;
 
-#if defined(HAVE_FFSLL)
 /// This LibCallOptimization will simplify calls to the "ffs" library
 /// calls which find the first set bit in an int, long, or long long. The 
 /// optimization is to compute the result at compile time if the argument is
@@ -1709,13 +1707,43 @@ public:
     {
       // ffs(cnst)  -> bit#
       // ffsl(cnst) -> bit#
+      // ffsll(cnst) -> bit#
       uint64_t val = CI->getRawValue();
-      int result = ffsll(static_cast<long long>(val));
+      int result = 0;
+      while (val != 0) {
+        result +=1;
+        if (val&1)
+          break;
+        val >>= 1;
+      }
       ci->replaceAllUsesWith(ConstantSInt::get(Type::IntTy, result));
       ci->eraseFromParent();
       return true;
     }
-    return false;
+
+    // ffs(x) -> ( x == 0 ? 0 : llvm.cttz(x)+1)
+    // ffsl(x) -> ( x == 0 ? 0 : llvm.cttz(x)+1)
+    // ffsll(x) -> ( x == 0 ? 0 : llvm.cttz(x)+1)
+    const Type* arg_type = ci->getOperand(1)->getType();
+    std::vector<const Type*> args;
+    args.push_back(arg_type);
+    FunctionType* llvm_cttz_type = FunctionType::get(arg_type,args,false);
+    Function* F = 
+      SLC.getModule()->getOrInsertFunction("llvm.cttz",llvm_cttz_type);
+    std::string inst_name(ci->getName()+".ffs");
+    Instruction* call = 
+      new CallInst(F, ci->getOperand(1), inst_name, ci);
+    if (arg_type != Type::IntTy)
+      call = new CastInst(call, Type::IntTy, inst_name, ci);
+    BinaryOperator* add = BinaryOperator::create(Instruction::Add, call,
+      ConstantSInt::get(Type::IntTy,1), inst_name, ci);
+    SetCondInst* eq = new SetCondInst(Instruction::SetEQ,ci->getOperand(1),
+      ConstantSInt::get(ci->getOperand(1)->getType(),0),inst_name,ci);
+    SelectInst* select = new SelectInst(eq,ConstantSInt::get(Type::IntTy,0),add,
+      inst_name,ci);
+    ci->replaceAllUsesWith(select);
+    ci->eraseFromParent();
+    return true;
   }
 } FFSOptimizer;
 
@@ -1745,7 +1773,19 @@ public:
 
 } FFSLLOptimizer;
 
-#endif
+/// This LibCallOptimization will simplify calls to the "__builtin_ffs" 
+/// function which is generated by the CFE (its GCC specific). 
+/// It simply uses FFSOptimization for which the transformation is
+/// identical.
+/// @brief Simplify the ffsl library function.
+struct BuiltinFFSOptimization : public FFSOptimization
+{
+public:
+  /// @brief Default Constructor
+  BuiltinFFSOptimization() : FFSOptimization("__builtin_ffs",
+      "Number of '__builtin_ffs' calls simplified") {}
+
+} BuiltinFFSOptimization;
 
 /// A function to compute the length of a null-terminated constant array of
 /// integers.  This function can't rely on the size of the constant array