2005-04-25 11:59:26 +08:00
|
|
|
//===- SimplifyLibCalls.cpp - Optimize specific well-known library calls --===//
|
2005-04-25 10:53:12 +08:00
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
2005-07-27 14:12:32 +08:00
|
|
|
// This file was developed by Reid Spencer and is distributed under the
|
2005-04-25 11:59:26 +08:00
|
|
|
// University of Illinois Open Source License. See LICENSE.TXT for details.
|
2005-04-25 10:53:12 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
2005-07-27 14:12:32 +08:00
|
|
|
// This file implements a module pass that applies a variety of small
|
|
|
|
// optimizations for calls to specific well-known function calls (e.g. runtime
|
|
|
|
// library functions). For example, a call to the function "exit(3)" that
|
2005-05-21 08:57:44 +08:00
|
|
|
// occurs within the main() function can be transformed into a simple "return 3"
|
2005-07-27 14:12:32 +08:00
|
|
|
// instruction. Any optimization that takes this form (replace call to library
|
|
|
|
// function with simpler code that provides the same result) belongs in this
|
|
|
|
// file.
|
2005-04-25 10:53:12 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2005-04-27 07:05:17 +08:00
|
|
|
#define DEBUG_TYPE "simplify-libcalls"
|
2005-04-26 05:11:48 +08:00
|
|
|
#include "llvm/Constants.h"
|
2005-04-27 07:02:16 +08:00
|
|
|
#include "llvm/DerivedTypes.h"
|
2005-04-25 10:53:12 +08:00
|
|
|
#include "llvm/Instructions.h"
|
2005-04-27 07:02:16 +08:00
|
|
|
#include "llvm/Module.h"
|
|
|
|
#include "llvm/Pass.h"
|
2005-04-25 11:59:26 +08:00
|
|
|
#include "llvm/ADT/hash_map"
|
2005-04-27 07:02:16 +08:00
|
|
|
#include "llvm/ADT/Statistic.h"
|
2006-01-19 16:36:56 +08:00
|
|
|
#include "llvm/Config/config.h"
|
2005-04-27 07:02:16 +08:00
|
|
|
#include "llvm/Support/Debug.h"
|
2005-04-27 03:13:17 +08:00
|
|
|
#include "llvm/Target/TargetData.h"
|
2005-04-27 07:02:16 +08:00
|
|
|
#include "llvm/Transforms/IPO.h"
|
2005-04-25 10:53:12 +08:00
|
|
|
using namespace llvm;
|
|
|
|
|
2005-04-27 15:54:40 +08:00
|
|
|
/// This statistic keeps track of the total number of library calls that have
|
|
|
|
/// been simplified regardless of which call it is.
|
2006-12-20 06:09:18 +08:00
|
|
|
STATISTIC(SimplifiedLibCalls, "Number of library calls simplified");
|
2005-04-28 05:29:20 +08:00
|
|
|
|
2006-12-20 06:09:18 +08:00
|
|
|
namespace {
|
|
|
|
// Forward declarations
|
|
|
|
class LibCallOptimization;
|
|
|
|
class SimplifyLibCalls;
|
|
|
|
|
2006-01-23 07:10:26 +08:00
|
|
|
/// This list is populated by the constructor for LibCallOptimization class.
|
2005-05-21 09:27:04 +08:00
|
|
|
/// Therefore all subclasses are registered here at static initialization time
|
|
|
|
/// and this list is what the SimplifyLibCalls pass uses to apply the individual
|
|
|
|
/// optimizations to the call sites.
|
2005-04-28 05:29:20 +08:00
|
|
|
/// @brief The list of optimizations deriving from LibCallOptimization
|
2006-01-23 07:10:26 +08:00
|
|
|
static LibCallOptimization *OptList = 0;
|
2005-04-27 15:54:40 +08:00
|
|
|
|
|
|
|
/// This class is the abstract base class for the set of optimizations that
|
2005-04-28 05:29:20 +08:00
|
|
|
/// corresponds to one library call. The SimplifyLibCalls pass will call the
|
2005-04-27 15:54:40 +08:00
|
|
|
/// ValidateCalledFunction method to ask the optimization if a given Function
|
2005-04-28 05:29:20 +08:00
|
|
|
/// is the kind that the optimization can handle. If the subclass returns true,
|
2005-07-27 14:12:32 +08:00
|
|
|
/// then SImplifyLibCalls will also call the OptimizeCall method to perform,
|
2005-04-28 05:29:20 +08:00
|
|
|
/// or attempt to perform, the optimization(s) for the library call. Otherwise,
|
|
|
|
/// OptimizeCall won't be called. Subclasses are responsible for providing the
|
|
|
|
/// name of the library call (strlen, strcpy, etc.) to the LibCallOptimization
|
|
|
|
/// constructor. This is used to efficiently select which call instructions to
|
2005-07-27 14:12:32 +08:00
|
|
|
/// optimize. The criteria for a "lib call" is "anything with well known
|
2005-04-28 05:29:20 +08:00
|
|
|
/// semantics", typically a library function that is defined by an international
|
2005-07-27 14:12:32 +08:00
|
|
|
/// standard. Because the semantics are well known, the optimizations can
|
2005-04-28 05:29:20 +08:00
|
|
|
/// generally short-circuit actually calling the function if there's a simpler
|
|
|
|
/// way (e.g. strlen(X) can be reduced to a constant if X is a constant global).
|
2005-04-27 15:54:40 +08:00
|
|
|
/// @brief Base class for library call optimizations
|
2006-01-23 06:35:08 +08:00
|
|
|
class LibCallOptimization {
|
2006-01-23 07:10:26 +08:00
|
|
|
LibCallOptimization **Prev, *Next;
|
|
|
|
const char *FunctionName; ///< Name of the library call we optimize
|
|
|
|
#ifndef NDEBUG
|
2006-12-07 01:46:33 +08:00
|
|
|
Statistic occurrences; ///< debug statistic (-debug-only=simplify-libcalls)
|
2006-01-23 07:10:26 +08:00
|
|
|
#endif
|
2005-04-29 11:05:44 +08:00
|
|
|
public:
|
2005-07-27 14:12:32 +08:00
|
|
|
/// The \p fname argument must be the name of the library function being
|
2005-04-28 05:29:20 +08:00
|
|
|
/// optimized by the subclass.
|
|
|
|
/// @brief Constructor that registers the optimization.
|
2006-01-23 07:10:26 +08:00
|
|
|
LibCallOptimization(const char *FName, const char *Description)
|
2006-12-20 07:16:47 +08:00
|
|
|
: FunctionName(FName) {
|
|
|
|
|
2005-04-27 08:05:45 +08:00
|
|
|
#ifndef NDEBUG
|
2006-12-20 07:16:47 +08:00
|
|
|
occurrences.construct("simplify-libcalls", Description);
|
2005-04-27 08:05:45 +08:00
|
|
|
#endif
|
2006-01-23 07:10:26 +08:00
|
|
|
// Register this optimizer in the list of optimizations.
|
|
|
|
Next = OptList;
|
|
|
|
OptList = this;
|
|
|
|
Prev = &OptList;
|
|
|
|
if (Next) Next->Prev = &Next;
|
2005-04-25 10:53:12 +08:00
|
|
|
}
|
2006-01-23 07:10:26 +08:00
|
|
|
|
|
|
|
/// getNext - All libcall optimizations are chained together into a list,
|
|
|
|
/// return the next one in the list.
|
|
|
|
LibCallOptimization *getNext() { return Next; }
|
2005-04-25 10:53:12 +08:00
|
|
|
|
2005-04-28 05:29:20 +08:00
|
|
|
/// @brief Deregister from the optlist
|
2006-01-23 07:10:26 +08:00
|
|
|
virtual ~LibCallOptimization() {
|
|
|
|
*Prev = Next;
|
|
|
|
if (Next) Next->Prev = Prev;
|
|
|
|
}
|
2005-04-27 15:54:40 +08:00
|
|
|
|
|
|
|
/// The implementation of this function in subclasses should determine if
|
2005-07-27 14:12:32 +08:00
|
|
|
/// \p F is suitable for the optimization. This method is called by
|
|
|
|
/// SimplifyLibCalls::runOnModule to short circuit visiting all the call
|
|
|
|
/// sites of such a function if that function is not suitable in the first
|
2005-04-28 05:29:20 +08:00
|
|
|
/// place. If the called function is suitabe, this method should return true;
|
2005-07-27 14:12:32 +08:00
|
|
|
/// false, otherwise. This function should also perform any lazy
|
|
|
|
/// initialization that the LibCallOptimization needs to do, if its to return
|
2005-04-27 15:54:40 +08:00
|
|
|
/// true. This avoids doing initialization until the optimizer is actually
|
|
|
|
/// going to be called upon to do some optimization.
|
2005-04-28 05:29:20 +08:00
|
|
|
/// @brief Determine if the function is suitable for optimization
|
2005-04-27 15:54:40 +08:00
|
|
|
virtual bool ValidateCalledFunction(
|
|
|
|
const Function* F, ///< The function that is the target of call sites
|
|
|
|
SimplifyLibCalls& SLC ///< The pass object invoking us
|
|
|
|
) = 0;
|
|
|
|
|
2005-07-27 14:12:32 +08:00
|
|
|
/// The implementations of this function in subclasses is the heart of the
|
|
|
|
/// SimplifyLibCalls algorithm. Sublcasses of this class implement
|
2005-04-27 15:54:40 +08:00
|
|
|
/// OptimizeCall to determine if (a) the conditions are right for optimizing
|
2005-07-27 14:12:32 +08:00
|
|
|
/// the call and (b) to perform the optimization. If an action is taken
|
2005-04-27 15:54:40 +08:00
|
|
|
/// against ci, the subclass is responsible for returning true and ensuring
|
|
|
|
/// that ci is erased from its parent.
|
|
|
|
/// @brief Optimize a call, if possible.
|
|
|
|
virtual bool OptimizeCall(
|
|
|
|
CallInst* ci, ///< The call instruction that should be optimized.
|
|
|
|
SimplifyLibCalls& SLC ///< The pass object invoking us
|
|
|
|
) = 0;
|
|
|
|
|
|
|
|
/// @brief Get the name of the library call being optimized
|
2006-01-23 07:10:26 +08:00
|
|
|
const char *getFunctionName() const { return FunctionName; }
|
2005-04-26 11:26:15 +08:00
|
|
|
|
2005-04-28 05:29:20 +08:00
|
|
|
/// @brief Called by SimplifyLibCalls to update the occurrences statistic.
|
2006-01-23 07:10:26 +08:00
|
|
|
void succeeded() {
|
2005-04-27 15:54:40 +08:00
|
|
|
#ifndef NDEBUG
|
2006-01-23 07:10:26 +08:00
|
|
|
DEBUG(++occurrences);
|
2005-04-27 15:54:40 +08:00
|
|
|
#endif
|
2006-01-23 07:10:26 +08:00
|
|
|
}
|
2005-04-27 15:54:40 +08:00
|
|
|
};
|
|
|
|
|
2005-07-27 14:12:32 +08:00
|
|
|
/// This class is an LLVM Pass that applies each of the LibCallOptimization
|
2005-04-27 15:54:40 +08:00
|
|
|
/// instances to all the call sites in a module, relatively efficiently. The
|
2005-07-27 14:12:32 +08:00
|
|
|
/// purpose of this pass is to provide optimizations for calls to well-known
|
2005-04-27 15:54:40 +08:00
|
|
|
/// functions with well-known semantics, such as those in the c library. The
|
2005-08-25 01:22:17 +08:00
|
|
|
/// class provides the basic infrastructure for handling runOnModule. Whenever
|
|
|
|
/// this pass finds a function call, it asks the appropriate optimizer to
|
2005-04-28 05:29:20 +08:00
|
|
|
/// validate the call (ValidateLibraryCall). If it is validated, then
|
|
|
|
/// the OptimizeCall method is also called.
|
2005-04-27 15:54:40 +08:00
|
|
|
/// @brief A ModulePass for optimizing well-known function calls.
|
2006-01-23 06:35:08 +08:00
|
|
|
class SimplifyLibCalls : public ModulePass {
|
2005-04-29 11:05:44 +08:00
|
|
|
public:
|
2005-04-27 15:54:40 +08:00
|
|
|
/// We need some target data for accurate signature details that are
|
|
|
|
/// target dependent. So we require target data in our AnalysisUsage.
|
2005-04-28 05:29:20 +08:00
|
|
|
/// @brief Require TargetData from AnalysisUsage.
|
2006-01-23 06:35:08 +08:00
|
|
|
virtual void getAnalysisUsage(AnalysisUsage& Info) const {
|
2005-04-27 15:54:40 +08:00
|
|
|
// Ask that the TargetData analysis be performed before us so we can use
|
|
|
|
// the target data.
|
|
|
|
Info.addRequired<TargetData>();
|
|
|
|
}
|
2005-04-27 03:13:17 +08:00
|
|
|
|
2005-04-27 15:54:40 +08:00
|
|
|
/// For this pass, process all of the function calls in the module, calling
|
|
|
|
/// ValidateLibraryCall and OptimizeCall as appropriate.
|
2005-04-28 05:29:20 +08:00
|
|
|
/// @brief Run all the lib call optimizations on a Module.
|
2006-01-23 06:35:08 +08:00
|
|
|
virtual bool runOnModule(Module &M) {
|
2005-04-27 15:54:40 +08:00
|
|
|
reset(M);
|
2005-04-27 03:13:17 +08:00
|
|
|
|
2005-04-27 15:54:40 +08:00
|
|
|
bool result = false;
|
2006-01-23 07:10:26 +08:00
|
|
|
hash_map<std::string, LibCallOptimization*> OptznMap;
|
|
|
|
for (LibCallOptimization *Optzn = OptList; Optzn; Optzn = Optzn->getNext())
|
|
|
|
OptznMap[Optzn->getFunctionName()] = Optzn;
|
2005-04-27 03:13:17 +08:00
|
|
|
|
2005-04-27 15:54:40 +08:00
|
|
|
// The call optimizations can be recursive. That is, the optimization might
|
|
|
|
// generate a call to another function which can also be optimized. This way
|
2005-07-27 14:12:32 +08:00
|
|
|
// we make the LibCallOptimization instances very specific to the case they
|
|
|
|
// handle. It also means we need to keep running over the function calls in
|
2005-04-27 15:54:40 +08:00
|
|
|
// the module until we don't get any more optimizations possible.
|
|
|
|
bool found_optimization = false;
|
2006-01-23 06:35:08 +08:00
|
|
|
do {
|
2005-04-27 15:54:40 +08:00
|
|
|
found_optimization = false;
|
2006-01-23 06:35:08 +08:00
|
|
|
for (Module::iterator FI = M.begin(), FE = M.end(); FI != FE; ++FI) {
|
2005-04-27 15:54:40 +08:00
|
|
|
// All the "well-known" functions are external and have external linkage
|
2005-07-27 14:12:32 +08:00
|
|
|
// because they live in a runtime library somewhere and were (probably)
|
|
|
|
// not compiled by LLVM. So, we only act on external functions that
|
2006-09-15 02:23:27 +08:00
|
|
|
// have external or dllimport linkage and non-empty uses.
|
|
|
|
if (!FI->isExternal() ||
|
|
|
|
!(FI->hasExternalLinkage() || FI->hasDLLImportLinkage()) ||
|
|
|
|
FI->use_empty())
|
2005-04-27 15:54:40 +08:00
|
|
|
continue;
|
|
|
|
|
|
|
|
// Get the optimization class that pertains to this function
|
2006-01-23 07:10:26 +08:00
|
|
|
hash_map<std::string, LibCallOptimization*>::iterator OMI =
|
|
|
|
OptznMap.find(FI->getName());
|
|
|
|
if (OMI == OptznMap.end()) continue;
|
|
|
|
|
|
|
|
LibCallOptimization *CO = OMI->second;
|
2005-04-27 15:54:40 +08:00
|
|
|
|
|
|
|
// Make sure the called function is suitable for the optimization
|
2006-01-23 07:10:26 +08:00
|
|
|
if (!CO->ValidateCalledFunction(FI, *this))
|
2005-04-27 15:54:40 +08:00
|
|
|
continue;
|
|
|
|
|
|
|
|
// Loop over each of the uses of the function
|
2005-07-27 14:12:32 +08:00
|
|
|
for (Value::use_iterator UI = FI->use_begin(), UE = FI->use_end();
|
2006-01-23 06:35:08 +08:00
|
|
|
UI != UE ; ) {
|
2005-04-27 15:54:40 +08:00
|
|
|
// If the use of the function is a call instruction
|
2006-01-23 06:35:08 +08:00
|
|
|
if (CallInst* CI = dyn_cast<CallInst>(*UI++)) {
|
2005-04-27 15:54:40 +08:00
|
|
|
// Do the optimization on the LibCallOptimization.
|
2006-01-23 06:35:08 +08:00
|
|
|
if (CO->OptimizeCall(CI, *this)) {
|
2005-04-27 15:54:40 +08:00
|
|
|
++SimplifiedLibCalls;
|
|
|
|
found_optimization = result = true;
|
2005-04-28 05:29:20 +08:00
|
|
|
CO->succeeded();
|
2005-04-27 15:54:40 +08:00
|
|
|
}
|
2005-04-27 03:13:17 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2005-04-27 15:54:40 +08:00
|
|
|
} while (found_optimization);
|
2006-01-23 07:10:26 +08:00
|
|
|
|
2005-04-27 15:54:40 +08:00
|
|
|
return result;
|
|
|
|
}
|
2005-04-27 03:13:17 +08:00
|
|
|
|
2005-04-27 15:54:40 +08:00
|
|
|
/// @brief Return the *current* module we're working on.
|
2005-04-29 17:39:47 +08:00
|
|
|
Module* getModule() const { return M; }
|
2005-04-27 15:54:40 +08:00
|
|
|
|
|
|
|
/// @brief Return the *current* target data for the module we're working on.
|
2005-04-29 17:39:47 +08:00
|
|
|
TargetData* getTargetData() const { return TD; }
|
|
|
|
|
|
|
|
/// @brief Return the size_t type -- syntactic shortcut
|
|
|
|
const Type* getIntPtrType() const { return TD->getIntPtrType(); }
|
|
|
|
|
2006-06-16 16:36:35 +08:00
|
|
|
/// @brief Return a Function* for the putchar libcall
|
2007-01-07 16:12:01 +08:00
|
|
|
Constant *get_putchar() {
|
2006-06-16 16:36:35 +08:00
|
|
|
if (!putchar_func)
|
2006-12-31 13:48:39 +08:00
|
|
|
putchar_func =
|
|
|
|
M->getOrInsertFunction("putchar", Type::Int32Ty, Type::Int32Ty, NULL);
|
2006-06-16 16:36:35 +08:00
|
|
|
return putchar_func;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// @brief Return a Function* for the puts libcall
|
2007-01-07 16:12:01 +08:00
|
|
|
Constant *get_puts() {
|
2006-06-16 16:36:35 +08:00
|
|
|
if (!puts_func)
|
2006-12-31 13:48:39 +08:00
|
|
|
puts_func = M->getOrInsertFunction("puts", Type::Int32Ty,
|
|
|
|
PointerType::get(Type::Int8Ty),
|
2006-06-16 16:36:35 +08:00
|
|
|
NULL);
|
|
|
|
return puts_func;
|
|
|
|
}
|
|
|
|
|
2005-04-29 17:39:47 +08:00
|
|
|
/// @brief Return a Function* for the fputc libcall
|
2007-01-07 16:12:01 +08:00
|
|
|
Constant *get_fputc(const Type* FILEptr_type) {
|
2005-04-29 17:39:47 +08:00
|
|
|
if (!fputc_func)
|
2006-12-31 13:48:39 +08:00
|
|
|
fputc_func = M->getOrInsertFunction("fputc", Type::Int32Ty, Type::Int32Ty,
|
2006-01-23 06:35:08 +08:00
|
|
|
FILEptr_type, NULL);
|
2005-04-29 17:39:47 +08:00
|
|
|
return fputc_func;
|
|
|
|
}
|
|
|
|
|
2006-06-16 12:52:30 +08:00
|
|
|
/// @brief Return a Function* for the fputs libcall
|
2007-01-07 16:12:01 +08:00
|
|
|
Constant *get_fputs(const Type* FILEptr_type) {
|
2006-06-16 12:52:30 +08:00
|
|
|
if (!fputs_func)
|
2006-12-31 13:48:39 +08:00
|
|
|
fputs_func = M->getOrInsertFunction("fputs", Type::Int32Ty,
|
|
|
|
PointerType::get(Type::Int8Ty),
|
2006-06-16 12:52:30 +08:00
|
|
|
FILEptr_type, NULL);
|
|
|
|
return fputs_func;
|
|
|
|
}
|
|
|
|
|
2005-04-29 17:39:47 +08:00
|
|
|
/// @brief Return a Function* for the fwrite libcall
|
2007-01-07 16:12:01 +08:00
|
|
|
Constant *get_fwrite(const Type* FILEptr_type) {
|
2005-04-29 17:39:47 +08:00
|
|
|
if (!fwrite_func)
|
2006-01-23 06:35:08 +08:00
|
|
|
fwrite_func = M->getOrInsertFunction("fwrite", TD->getIntPtrType(),
|
2006-12-31 13:48:39 +08:00
|
|
|
PointerType::get(Type::Int8Ty),
|
2006-01-23 06:35:08 +08:00
|
|
|
TD->getIntPtrType(),
|
|
|
|
TD->getIntPtrType(),
|
|
|
|
FILEptr_type, NULL);
|
2005-04-29 17:39:47 +08:00
|
|
|
return fwrite_func;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// @brief Return a Function* for the sqrt libcall
|
2007-01-07 16:12:01 +08:00
|
|
|
Constant *get_sqrt() {
|
2005-04-29 17:39:47 +08:00
|
|
|
if (!sqrt_func)
|
2006-01-23 06:35:08 +08:00
|
|
|
sqrt_func = M->getOrInsertFunction("sqrt", Type::DoubleTy,
|
|
|
|
Type::DoubleTy, NULL);
|
2005-04-29 17:39:47 +08:00
|
|
|
return sqrt_func;
|
|
|
|
}
|
2005-04-27 03:13:17 +08:00
|
|
|
|
* Correct the function prototypes for some of the functions to match the
actual spec (int -> uint)
* Add the ability to get/cache the strlen function prototype.
* Make sure generated values are appropriately named for debugging purposes
* Add the SPrintFOptimiation for 4 casts of sprintf optimization:
sprintf(str,cstr) -> llvm.memcpy(str,cstr) (if cstr has no %)
sprintf(str,"") -> store sbyte 0, str
sprintf(str,"%s",src) -> llvm.memcpy(str,src) (if src is constant)
sprintf(str,"%c",chr) -> store chr, str ; store sbyte 0, str+1
The sprintf optimization didn't fire as much as I had hoped:
2 MultiSource/Applications/SPASS
5 MultiSource/Benchmarks/McCat/18-imp
22 MultiSource/Benchmarks/Prolangs-C/TimberWolfMC
1 MultiSource/Benchmarks/Prolangs-C/assembler
6 MultiSource/Benchmarks/Prolangs-C/unix-smail
2 MultiSource/Benchmarks/mediabench/mpeg2/mpeg2dec
llvm-svn: 21679
2005-05-04 11:20:21 +08:00
|
|
|
/// @brief Return a Function* for the strlen libcall
|
2007-01-07 16:12:01 +08:00
|
|
|
Constant *get_strcpy() {
|
* Correct the function prototypes for some of the functions to match the
actual spec (int -> uint)
* Add the ability to get/cache the strlen function prototype.
* Make sure generated values are appropriately named for debugging purposes
* Add the SPrintFOptimiation for 4 casts of sprintf optimization:
sprintf(str,cstr) -> llvm.memcpy(str,cstr) (if cstr has no %)
sprintf(str,"") -> store sbyte 0, str
sprintf(str,"%s",src) -> llvm.memcpy(str,src) (if src is constant)
sprintf(str,"%c",chr) -> store chr, str ; store sbyte 0, str+1
The sprintf optimization didn't fire as much as I had hoped:
2 MultiSource/Applications/SPASS
5 MultiSource/Benchmarks/McCat/18-imp
22 MultiSource/Benchmarks/Prolangs-C/TimberWolfMC
1 MultiSource/Benchmarks/Prolangs-C/assembler
6 MultiSource/Benchmarks/Prolangs-C/unix-smail
2 MultiSource/Benchmarks/mediabench/mpeg2/mpeg2dec
llvm-svn: 21679
2005-05-04 11:20:21 +08:00
|
|
|
if (!strcpy_func)
|
2006-01-23 06:35:08 +08:00
|
|
|
strcpy_func = M->getOrInsertFunction("strcpy",
|
2006-12-31 13:48:39 +08:00
|
|
|
PointerType::get(Type::Int8Ty),
|
|
|
|
PointerType::get(Type::Int8Ty),
|
|
|
|
PointerType::get(Type::Int8Ty),
|
2006-01-23 06:35:08 +08:00
|
|
|
NULL);
|
* Correct the function prototypes for some of the functions to match the
actual spec (int -> uint)
* Add the ability to get/cache the strlen function prototype.
* Make sure generated values are appropriately named for debugging purposes
* Add the SPrintFOptimiation for 4 casts of sprintf optimization:
sprintf(str,cstr) -> llvm.memcpy(str,cstr) (if cstr has no %)
sprintf(str,"") -> store sbyte 0, str
sprintf(str,"%s",src) -> llvm.memcpy(str,src) (if src is constant)
sprintf(str,"%c",chr) -> store chr, str ; store sbyte 0, str+1
The sprintf optimization didn't fire as much as I had hoped:
2 MultiSource/Applications/SPASS
5 MultiSource/Benchmarks/McCat/18-imp
22 MultiSource/Benchmarks/Prolangs-C/TimberWolfMC
1 MultiSource/Benchmarks/Prolangs-C/assembler
6 MultiSource/Benchmarks/Prolangs-C/unix-smail
2 MultiSource/Benchmarks/mediabench/mpeg2/mpeg2dec
llvm-svn: 21679
2005-05-04 11:20:21 +08:00
|
|
|
return strcpy_func;
|
|
|
|
}
|
|
|
|
|
2005-04-27 15:54:40 +08:00
|
|
|
/// @brief Return a Function* for the strlen libcall
|
2007-01-07 16:12:01 +08:00
|
|
|
Constant *get_strlen() {
|
2005-04-27 15:54:40 +08:00
|
|
|
if (!strlen_func)
|
2006-01-23 06:35:08 +08:00
|
|
|
strlen_func = M->getOrInsertFunction("strlen", TD->getIntPtrType(),
|
2006-12-31 13:48:39 +08:00
|
|
|
PointerType::get(Type::Int8Ty),
|
2006-01-23 06:35:08 +08:00
|
|
|
NULL);
|
2005-04-27 15:54:40 +08:00
|
|
|
return strlen_func;
|
2005-04-26 11:26:15 +08:00
|
|
|
}
|
|
|
|
|
2005-05-03 15:23:44 +08:00
|
|
|
/// @brief Return a Function* for the memchr libcall
|
2007-01-07 16:12:01 +08:00
|
|
|
Constant *get_memchr() {
|
2005-05-03 15:23:44 +08:00
|
|
|
if (!memchr_func)
|
2006-01-23 06:35:08 +08:00
|
|
|
memchr_func = M->getOrInsertFunction("memchr",
|
2006-12-31 13:48:39 +08:00
|
|
|
PointerType::get(Type::Int8Ty),
|
|
|
|
PointerType::get(Type::Int8Ty),
|
|
|
|
Type::Int32Ty, TD->getIntPtrType(),
|
2006-01-23 06:35:08 +08:00
|
|
|
NULL);
|
2005-05-03 15:23:44 +08:00
|
|
|
return memchr_func;
|
|
|
|
}
|
|
|
|
|
2005-04-27 15:54:40 +08:00
|
|
|
/// @brief Return a Function* for the memcpy libcall
|
2007-01-07 16:12:01 +08:00
|
|
|
Constant *get_memcpy() {
|
2005-08-25 01:22:17 +08:00
|
|
|
if (!memcpy_func) {
|
2006-12-31 13:48:39 +08:00
|
|
|
const Type *SBP = PointerType::get(Type::Int8Ty);
|
|
|
|
const char *N = TD->getIntPtrType() == Type::Int32Ty ?
|
2006-03-03 09:30:23 +08:00
|
|
|
"llvm.memcpy.i32" : "llvm.memcpy.i64";
|
|
|
|
memcpy_func = M->getOrInsertFunction(N, Type::VoidTy, SBP, SBP,
|
2006-12-31 13:48:39 +08:00
|
|
|
TD->getIntPtrType(), Type::Int32Ty,
|
2006-03-03 09:30:23 +08:00
|
|
|
NULL);
|
2005-04-26 11:26:15 +08:00
|
|
|
}
|
2005-04-27 15:54:40 +08:00
|
|
|
return memcpy_func;
|
2005-04-26 11:26:15 +08:00
|
|
|
}
|
2005-04-26 13:24:00 +08:00
|
|
|
|
2007-01-07 16:12:01 +08:00
|
|
|
Constant *getUnaryFloatFunction(const char *Name, Constant *&Cache) {
|
2006-01-23 14:24:46 +08:00
|
|
|
if (!Cache)
|
|
|
|
Cache = M->getOrInsertFunction(Name, Type::FloatTy, Type::FloatTy, NULL);
|
|
|
|
return Cache;
|
2005-08-25 01:22:17 +08:00
|
|
|
}
|
|
|
|
|
2007-01-07 16:12:01 +08:00
|
|
|
Constant *get_floorf() { return getUnaryFloatFunction("floorf", floorf_func);}
|
|
|
|
Constant *get_ceilf() { return getUnaryFloatFunction( "ceilf", ceilf_func);}
|
|
|
|
Constant *get_roundf() { return getUnaryFloatFunction("roundf", roundf_func);}
|
|
|
|
Constant *get_rintf() { return getUnaryFloatFunction( "rintf", rintf_func);}
|
|
|
|
Constant *get_nearbyintf() { return getUnaryFloatFunction("nearbyintf",
|
2006-01-23 14:24:46 +08:00
|
|
|
nearbyintf_func); }
|
2005-04-27 15:54:40 +08:00
|
|
|
private:
|
2005-04-28 05:29:20 +08:00
|
|
|
/// @brief Reset our cached data for a new Module
|
2006-01-23 06:35:08 +08:00
|
|
|
void reset(Module& mod) {
|
2005-04-27 15:54:40 +08:00
|
|
|
M = &mod;
|
|
|
|
TD = &getAnalysis<TargetData>();
|
2006-06-16 16:36:35 +08:00
|
|
|
putchar_func = 0;
|
|
|
|
puts_func = 0;
|
2005-04-29 17:39:47 +08:00
|
|
|
fputc_func = 0;
|
2006-06-16 12:52:30 +08:00
|
|
|
fputs_func = 0;
|
2005-04-29 17:39:47 +08:00
|
|
|
fwrite_func = 0;
|
2005-04-27 15:54:40 +08:00
|
|
|
memcpy_func = 0;
|
2005-05-03 15:23:44 +08:00
|
|
|
memchr_func = 0;
|
2005-04-29 17:39:47 +08:00
|
|
|
sqrt_func = 0;
|
* Correct the function prototypes for some of the functions to match the
actual spec (int -> uint)
* Add the ability to get/cache the strlen function prototype.
* Make sure generated values are appropriately named for debugging purposes
* Add the SPrintFOptimiation for 4 casts of sprintf optimization:
sprintf(str,cstr) -> llvm.memcpy(str,cstr) (if cstr has no %)
sprintf(str,"") -> store sbyte 0, str
sprintf(str,"%s",src) -> llvm.memcpy(str,src) (if src is constant)
sprintf(str,"%c",chr) -> store chr, str ; store sbyte 0, str+1
The sprintf optimization didn't fire as much as I had hoped:
2 MultiSource/Applications/SPASS
5 MultiSource/Benchmarks/McCat/18-imp
22 MultiSource/Benchmarks/Prolangs-C/TimberWolfMC
1 MultiSource/Benchmarks/Prolangs-C/assembler
6 MultiSource/Benchmarks/Prolangs-C/unix-smail
2 MultiSource/Benchmarks/mediabench/mpeg2/mpeg2dec
llvm-svn: 21679
2005-05-04 11:20:21 +08:00
|
|
|
strcpy_func = 0;
|
2005-04-27 15:54:40 +08:00
|
|
|
strlen_func = 0;
|
2005-08-25 01:22:17 +08:00
|
|
|
floorf_func = 0;
|
2006-01-23 14:24:46 +08:00
|
|
|
ceilf_func = 0;
|
|
|
|
roundf_func = 0;
|
|
|
|
rintf_func = 0;
|
|
|
|
nearbyintf_func = 0;
|
2005-04-27 15:54:40 +08:00
|
|
|
}
|
2005-04-26 13:24:00 +08:00
|
|
|
|
2005-04-27 15:54:40 +08:00
|
|
|
private:
|
2006-01-23 14:24:46 +08:00
|
|
|
/// Caches for function pointers.
|
2007-01-07 16:12:01 +08:00
|
|
|
Constant *putchar_func, *puts_func;
|
|
|
|
Constant *fputc_func, *fputs_func, *fwrite_func;
|
|
|
|
Constant *memcpy_func, *memchr_func;
|
|
|
|
Constant *sqrt_func;
|
|
|
|
Constant *strcpy_func, *strlen_func;
|
|
|
|
Constant *floorf_func, *ceilf_func, *roundf_func;
|
|
|
|
Constant *rintf_func, *nearbyintf_func;
|
2006-01-23 14:24:46 +08:00
|
|
|
Module *M; ///< Cached Module
|
|
|
|
TargetData *TD; ///< Cached TargetData
|
2005-04-27 15:54:40 +08:00
|
|
|
};
|
2005-04-26 13:24:00 +08:00
|
|
|
|
2005-04-27 15:54:40 +08:00
|
|
|
// Register the pass
|
2006-08-28 06:42:52 +08:00
|
|
|
RegisterPass<SimplifyLibCalls>
|
|
|
|
X("simplify-libcalls", "Simplify well-known library calls");
|
2005-04-26 15:45:18 +08:00
|
|
|
|
2005-04-27 15:54:40 +08:00
|
|
|
} // anonymous namespace
|
2005-04-26 15:45:18 +08:00
|
|
|
|
2005-04-27 15:54:40 +08:00
|
|
|
// The only public symbol in this file which just instantiates the pass object
|
2006-01-23 06:35:08 +08:00
|
|
|
ModulePass *llvm::createSimplifyLibCallsPass() {
|
2005-07-27 14:12:32 +08:00
|
|
|
return new SimplifyLibCalls();
|
2005-04-27 15:54:40 +08:00
|
|
|
}
|
2005-04-26 15:45:18 +08:00
|
|
|
|
2005-04-27 15:54:40 +08:00
|
|
|
// Classes below here, in the anonymous namespace, are all subclasses of the
|
|
|
|
// LibCallOptimization class, each implementing all optimizations possible for a
|
|
|
|
// single well-known library call. Each has a static singleton instance that
|
2005-07-27 14:12:32 +08:00
|
|
|
// auto registers it into the "optlist" global above.
|
2005-04-27 15:54:40 +08:00
|
|
|
namespace {
|
2005-04-26 15:45:18 +08:00
|
|
|
|
2005-06-19 01:46:28 +08:00
|
|
|
// Forward declare utility functions.
|
* Don't depend on "guessing" what a FILE* is, just require that the actual
type be obtained from a CallInst we're optimizing.
* Make it possible for getConstantStringLength to return the ConstantArray
that it extracts in case the content is needed by an Optimization.
* Implement the strcmp optimization
* Implement the toascii optimization
This pass is now firing several to many times in the following MultiSource
tests:
Applications/Burg - 7 (strcat,strcpy)
Applications/siod - 13 (strcat,strcpy,strlen)
Applications/spiff - 120 (exit,fputs,strcat,strcpy,strlen)
Applications/treecc - 66 (exit,fputs,strcat,strcpy)
Applications/kimwitu++ - 34 (strcmp,strcpy,strlen)
Applications/SPASS - 588 (exit,fputs,strcat,strcpy,strlen)
llvm-svn: 21626
2005-04-30 11:17:54 +08:00
|
|
|
bool getConstantStringLength(Value* V, uint64_t& len, ConstantArray** A = 0 );
|
2005-06-19 01:46:28 +08:00
|
|
|
Value *CastToCStr(Value *V, Instruction &IP);
|
2005-04-25 10:53:12 +08:00
|
|
|
|
2005-04-27 15:54:40 +08:00
|
|
|
/// This LibCallOptimization will find instances of a call to "exit" that occurs
|
2005-04-25 10:53:12 +08:00
|
|
|
/// within the "main" function and change it to a simple "ret" instruction with
|
2005-04-28 05:29:20 +08:00
|
|
|
/// the same value passed to the exit function. When this is done, it splits the
|
|
|
|
/// basic block at the exit(3) call and deletes the call instruction.
|
2005-04-25 10:53:12 +08:00
|
|
|
/// @brief Replace calls to exit in main with a simple return
|
2006-01-23 06:35:08 +08:00
|
|
|
struct ExitInMainOptimization : public LibCallOptimization {
|
2005-05-03 10:54:54 +08:00
|
|
|
ExitInMainOptimization() : LibCallOptimization("exit",
|
2005-05-08 04:15:59 +08:00
|
|
|
"Number of 'exit' calls simplified") {}
|
2005-04-26 05:11:48 +08:00
|
|
|
|
|
|
|
// Make sure the called function looks like exit (int argument, int return
|
2005-07-27 14:12:32 +08:00
|
|
|
// type, external linkage, not varargs).
|
2006-01-23 06:35:08 +08:00
|
|
|
virtual bool ValidateCalledFunction(const Function *F, SimplifyLibCalls &SLC){
|
2007-01-15 09:55:30 +08:00
|
|
|
return F->arg_size() >= 1 && F->arg_begin()->getType()->isIntegral();
|
2005-04-26 05:11:48 +08:00
|
|
|
}
|
|
|
|
|
2006-01-23 06:35:08 +08:00
|
|
|
virtual bool OptimizeCall(CallInst* ci, SimplifyLibCalls& SLC) {
|
2005-04-26 05:11:48 +08:00
|
|
|
// To be careful, we check that the call to exit is coming from "main", that
|
|
|
|
// main has external linkage, and the return type of main and the argument
|
2005-07-27 14:12:32 +08:00
|
|
|
// to exit have the same type.
|
2005-04-26 05:11:48 +08:00
|
|
|
Function *from = ci->getParent()->getParent();
|
|
|
|
if (from->hasExternalLinkage())
|
|
|
|
if (from->getReturnType() == ci->getOperand(1)->getType())
|
2006-01-23 06:35:08 +08:00
|
|
|
if (from->getName() == "main") {
|
2005-07-27 14:12:32 +08:00
|
|
|
// Okay, time to actually do the optimization. First, get the basic
|
2005-04-26 05:11:48 +08:00
|
|
|
// block of the call instruction
|
|
|
|
BasicBlock* bb = ci->getParent();
|
2005-04-25 11:59:26 +08:00
|
|
|
|
2005-07-27 14:12:32 +08:00
|
|
|
// Create a return instruction that we'll replace the call with.
|
|
|
|
// Note that the argument of the return is the argument of the call
|
2005-04-26 05:11:48 +08:00
|
|
|
// instruction.
|
2006-05-13 07:35:26 +08:00
|
|
|
new ReturnInst(ci->getOperand(1), ci);
|
2005-04-25 11:59:26 +08:00
|
|
|
|
2005-04-26 05:11:48 +08:00
|
|
|
// Split the block at the call instruction which places it in a new
|
|
|
|
// basic block.
|
2005-04-26 11:26:15 +08:00
|
|
|
bb->splitBasicBlock(ci);
|
2005-04-25 11:59:26 +08:00
|
|
|
|
2005-04-26 05:11:48 +08:00
|
|
|
// The block split caused a branch instruction to be inserted into
|
|
|
|
// the end of the original block, right after the return instruction
|
|
|
|
// that we put there. That's not a valid block, so delete the branch
|
|
|
|
// instruction.
|
2005-04-26 11:26:15 +08:00
|
|
|
bb->getInstList().pop_back();
|
2005-04-25 11:59:26 +08:00
|
|
|
|
2005-04-26 05:11:48 +08:00
|
|
|
// Now we can finally get rid of the call instruction which now lives
|
|
|
|
// in the new basic block.
|
|
|
|
ci->eraseFromParent();
|
|
|
|
|
|
|
|
// Optimization succeeded, return true.
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
// We didn't pass the criteria for this optimization so return false
|
|
|
|
return false;
|
2005-04-25 11:59:26 +08:00
|
|
|
}
|
|
|
|
} ExitInMainOptimizer;
|
|
|
|
|
2005-07-27 14:12:32 +08:00
|
|
|
/// This LibCallOptimization will simplify a call to the strcat library
|
|
|
|
/// function. The simplification is possible only if the string being
|
|
|
|
/// concatenated is a constant array or a constant expression that results in
|
|
|
|
/// a constant string. In this case we can replace it with strlen + llvm.memcpy
|
2005-04-28 05:29:20 +08:00
|
|
|
/// of the constant string. Both of these calls are further reduced, if possible
|
|
|
|
/// on subsequent passes.
|
2005-04-26 05:11:48 +08:00
|
|
|
/// @brief Simplify the strcat library function.
|
2006-01-23 06:35:08 +08:00
|
|
|
struct StrCatOptimization : public LibCallOptimization {
|
2005-04-26 11:26:15 +08:00
|
|
|
public:
|
2005-04-28 05:29:20 +08:00
|
|
|
/// @brief Default constructor
|
2005-05-03 10:54:54 +08:00
|
|
|
StrCatOptimization() : LibCallOptimization("strcat",
|
2005-05-08 04:15:59 +08:00
|
|
|
"Number of 'strcat' calls simplified") {}
|
2005-04-26 05:11:48 +08:00
|
|
|
|
2005-04-27 15:54:40 +08:00
|
|
|
public:
|
2005-04-26 11:26:15 +08:00
|
|
|
|
2005-04-26 05:11:48 +08:00
|
|
|
/// @brief Make sure that the "strcat" function has the right prototype
|
2006-01-23 06:35:08 +08:00
|
|
|
virtual bool ValidateCalledFunction(const Function* f, SimplifyLibCalls& SLC){
|
2006-12-31 13:48:39 +08:00
|
|
|
if (f->getReturnType() == PointerType::get(Type::Int8Ty))
|
2005-07-27 14:12:32 +08:00
|
|
|
if (f->arg_size() == 2)
|
2005-04-26 05:11:48 +08:00
|
|
|
{
|
|
|
|
Function::const_arg_iterator AI = f->arg_begin();
|
2006-12-31 13:48:39 +08:00
|
|
|
if (AI++->getType() == PointerType::get(Type::Int8Ty))
|
|
|
|
if (AI->getType() == PointerType::get(Type::Int8Ty))
|
2005-04-26 11:26:15 +08:00
|
|
|
{
|
|
|
|
// Indicate this is a suitable call type.
|
2005-04-26 05:11:48 +08:00
|
|
|
return true;
|
2005-04-26 11:26:15 +08:00
|
|
|
}
|
2005-04-26 05:11:48 +08:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2005-04-27 15:54:40 +08:00
|
|
|
/// @brief Optimize the strcat library function
|
2006-01-23 06:35:08 +08:00
|
|
|
virtual bool OptimizeCall(CallInst* ci, SimplifyLibCalls& SLC) {
|
2005-04-28 01:46:54 +08:00
|
|
|
// Extract some information from the instruction
|
|
|
|
Value* dest = ci->getOperand(1);
|
|
|
|
Value* src = ci->getOperand(2);
|
|
|
|
|
2005-07-27 14:12:32 +08:00
|
|
|
// Extract the initializer (while making numerous checks) from the
|
2005-04-26 13:24:00 +08:00
|
|
|
// source operand of the call to strcat. If we get null back, one of
|
|
|
|
// a variety of checks in get_GVInitializer failed
|
2005-04-26 15:45:18 +08:00
|
|
|
uint64_t len = 0;
|
2005-04-28 01:46:54 +08:00
|
|
|
if (!getConstantStringLength(src,len))
|
2005-04-26 05:11:48 +08:00
|
|
|
return false;
|
|
|
|
|
2005-04-26 15:45:18 +08:00
|
|
|
// Handle the simple, do-nothing case
|
2006-01-23 06:35:08 +08:00
|
|
|
if (len == 0) {
|
2005-04-28 01:46:54 +08:00
|
|
|
ci->replaceAllUsesWith(dest);
|
2005-04-26 11:26:15 +08:00
|
|
|
ci->eraseFromParent();
|
|
|
|
return true;
|
2005-04-26 05:11:48 +08:00
|
|
|
}
|
|
|
|
|
2005-04-26 15:45:18 +08:00
|
|
|
// Increment the length because we actually want to memcpy the null
|
|
|
|
// terminator as well.
|
|
|
|
len++;
|
|
|
|
|
2005-07-27 14:12:32 +08:00
|
|
|
// We need to find the end of the destination string. That's where the
|
|
|
|
// memory is to be moved to. We just generate a call to strlen (further
|
|
|
|
// optimized in another pass). Note that the SLC.get_strlen() call
|
2005-04-26 15:45:18 +08:00
|
|
|
// caches the Function* for us.
|
2005-07-27 14:12:32 +08:00
|
|
|
CallInst* strlen_inst =
|
2005-04-28 01:46:54 +08:00
|
|
|
new CallInst(SLC.get_strlen(), dest, dest->getName()+".len",ci);
|
2005-04-26 15:45:18 +08:00
|
|
|
|
2005-07-27 14:12:32 +08:00
|
|
|
// Now that we have the destination's length, we must index into the
|
2005-04-26 15:45:18 +08:00
|
|
|
// destination's pointer to get the actual memcpy destination (end of
|
|
|
|
// the string .. we're concatenating).
|
|
|
|
std::vector<Value*> idx;
|
|
|
|
idx.push_back(strlen_inst);
|
2005-07-27 14:12:32 +08:00
|
|
|
GetElementPtrInst* gep =
|
2005-04-28 01:46:54 +08:00
|
|
|
new GetElementPtrInst(dest,idx,dest->getName()+".indexed",ci);
|
2005-04-26 15:45:18 +08:00
|
|
|
|
|
|
|
// We have enough information to now generate the memcpy call to
|
|
|
|
// do the concatenation for us.
|
|
|
|
std::vector<Value*> vals;
|
|
|
|
vals.push_back(gep); // destination
|
|
|
|
vals.push_back(ci->getOperand(2)); // source
|
2006-10-20 15:07:24 +08:00
|
|
|
vals.push_back(ConstantInt::get(SLC.getIntPtrType(),len)); // length
|
2006-12-31 13:48:39 +08:00
|
|
|
vals.push_back(ConstantInt::get(Type::Int32Ty,1)); // alignment
|
2005-04-28 01:46:54 +08:00
|
|
|
new CallInst(SLC.get_memcpy(), vals, "", ci);
|
2005-04-26 15:45:18 +08:00
|
|
|
|
2005-07-27 14:12:32 +08:00
|
|
|
// Finally, substitute the first operand of the strcat call for the
|
|
|
|
// strcat call itself since strcat returns its first operand; and,
|
2005-04-26 15:45:18 +08:00
|
|
|
// kill the strcat CallInst.
|
2005-04-28 01:46:54 +08:00
|
|
|
ci->replaceAllUsesWith(dest);
|
2005-04-26 15:45:18 +08:00
|
|
|
ci->eraseFromParent();
|
|
|
|
return true;
|
2005-04-25 11:59:26 +08:00
|
|
|
}
|
|
|
|
} StrCatOptimizer;
|
2005-04-25 10:53:12 +08:00
|
|
|
|
2005-07-27 14:12:32 +08:00
|
|
|
/// This LibCallOptimization will simplify a call to the strchr library
|
2005-05-03 15:23:44 +08:00
|
|
|
/// function. It optimizes out cases where the arguments are both constant
|
|
|
|
/// and the result can be determined statically.
|
|
|
|
/// @brief Simplify the strcmp library function.
|
2006-01-23 06:35:08 +08:00
|
|
|
struct StrChrOptimization : public LibCallOptimization {
|
2005-05-03 15:23:44 +08:00
|
|
|
public:
|
|
|
|
StrChrOptimization() : LibCallOptimization("strchr",
|
2005-05-08 04:15:59 +08:00
|
|
|
"Number of 'strchr' calls simplified") {}
|
2005-05-03 15:23:44 +08:00
|
|
|
|
|
|
|
/// @brief Make sure that the "strchr" function has the right prototype
|
2006-01-23 06:35:08 +08:00
|
|
|
virtual bool ValidateCalledFunction(const Function* f, SimplifyLibCalls& SLC){
|
2006-12-31 13:48:39 +08:00
|
|
|
if (f->getReturnType() == PointerType::get(Type::Int8Ty) &&
|
2005-05-03 15:23:44 +08:00
|
|
|
f->arg_size() == 2)
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2005-05-21 06:22:25 +08:00
|
|
|
/// @brief Perform the strchr optimizations
|
2006-01-23 06:35:08 +08:00
|
|
|
virtual bool OptimizeCall(CallInst *ci, SimplifyLibCalls &SLC) {
|
2005-05-03 15:23:44 +08:00
|
|
|
// If there aren't three operands, bail
|
|
|
|
if (ci->getNumOperands() != 3)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Check that the first argument to strchr is a constant array of sbyte.
|
|
|
|
// If it is, get the length and data, otherwise return false.
|
|
|
|
uint64_t len = 0;
|
2006-10-20 15:07:24 +08:00
|
|
|
ConstantArray* CA = 0;
|
2006-12-31 13:48:39 +08:00
|
|
|
if (!getConstantStringLength(ci->getOperand(1), len, &CA))
|
2005-05-03 15:23:44 +08:00
|
|
|
return false;
|
|
|
|
|
2006-10-20 15:07:24 +08:00
|
|
|
// Check that the second argument to strchr is a constant int. If it isn't
|
|
|
|
// a constant signed integer, we can try an alternate optimization
|
|
|
|
ConstantInt* CSI = dyn_cast<ConstantInt>(ci->getOperand(2));
|
2006-12-31 13:48:39 +08:00
|
|
|
if (!CSI) {
|
2006-10-20 15:07:24 +08:00
|
|
|
// The second operand is not constant, or not signed. Just lower this to
|
|
|
|
// memchr since we know the length of the string since it is constant.
|
2007-01-07 16:12:01 +08:00
|
|
|
Constant *f = SLC.get_memchr();
|
2005-05-03 15:23:44 +08:00
|
|
|
std::vector<Value*> args;
|
|
|
|
args.push_back(ci->getOperand(1));
|
|
|
|
args.push_back(ci->getOperand(2));
|
2006-12-31 13:48:39 +08:00
|
|
|
args.push_back(ConstantInt::get(SLC.getIntPtrType(), len));
|
2007-01-07 16:12:01 +08:00
|
|
|
ci->replaceAllUsesWith(new CallInst(f, args, ci->getName(), ci));
|
2005-05-03 15:23:44 +08:00
|
|
|
ci->eraseFromParent();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the character we're looking for
|
2006-10-20 15:07:24 +08:00
|
|
|
int64_t chr = CSI->getSExtValue();
|
2005-05-03 15:23:44 +08:00
|
|
|
|
|
|
|
// Compute the offset
|
|
|
|
uint64_t offset = 0;
|
|
|
|
bool char_found = false;
|
2006-01-23 06:35:08 +08:00
|
|
|
for (uint64_t i = 0; i < len; ++i) {
|
2006-10-20 15:07:24 +08:00
|
|
|
if (ConstantInt* CI = dyn_cast<ConstantInt>(CA->getOperand(i))) {
|
2005-05-03 15:23:44 +08:00
|
|
|
// Check for the null terminator
|
|
|
|
if (CI->isNullValue())
|
|
|
|
break; // we found end of string
|
2006-10-20 15:07:24 +08:00
|
|
|
else if (CI->getSExtValue() == chr) {
|
2005-05-03 15:23:44 +08:00
|
|
|
char_found = true;
|
|
|
|
offset = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// strchr(s,c) -> offset_of_in(c,s)
|
|
|
|
// (if c is a constant integer and s is a constant string)
|
2006-01-23 06:35:08 +08:00
|
|
|
if (char_found) {
|
2005-05-03 15:23:44 +08:00
|
|
|
std::vector<Value*> indices;
|
2006-12-31 13:48:39 +08:00
|
|
|
indices.push_back(ConstantInt::get(Type::Int64Ty,offset));
|
2005-05-03 15:23:44 +08:00
|
|
|
GetElementPtrInst* GEP = new GetElementPtrInst(ci->getOperand(1),indices,
|
|
|
|
ci->getOperand(1)->getName()+".strchr",ci);
|
|
|
|
ci->replaceAllUsesWith(GEP);
|
2006-01-23 06:35:08 +08:00
|
|
|
} else {
|
2005-05-03 15:23:44 +08:00
|
|
|
ci->replaceAllUsesWith(
|
2006-12-31 13:48:39 +08:00
|
|
|
ConstantPointerNull::get(PointerType::get(Type::Int8Ty)));
|
2006-01-23 06:35:08 +08:00
|
|
|
}
|
2005-05-03 15:23:44 +08:00
|
|
|
ci->eraseFromParent();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
} StrChrOptimizer;
|
|
|
|
|
2005-07-27 14:12:32 +08:00
|
|
|
/// This LibCallOptimization will simplify a call to the strcmp library
|
* Don't depend on "guessing" what a FILE* is, just require that the actual
type be obtained from a CallInst we're optimizing.
* Make it possible for getConstantStringLength to return the ConstantArray
that it extracts in case the content is needed by an Optimization.
* Implement the strcmp optimization
* Implement the toascii optimization
This pass is now firing several to many times in the following MultiSource
tests:
Applications/Burg - 7 (strcat,strcpy)
Applications/siod - 13 (strcat,strcpy,strlen)
Applications/spiff - 120 (exit,fputs,strcat,strcpy,strlen)
Applications/treecc - 66 (exit,fputs,strcat,strcpy)
Applications/kimwitu++ - 34 (strcmp,strcpy,strlen)
Applications/SPASS - 588 (exit,fputs,strcat,strcpy,strlen)
llvm-svn: 21626
2005-04-30 11:17:54 +08:00
|
|
|
/// function. It optimizes out cases where one or both arguments are constant
|
|
|
|
/// and the result can be determined statically.
|
|
|
|
/// @brief Simplify the strcmp library function.
|
2006-01-23 06:35:08 +08:00
|
|
|
struct StrCmpOptimization : public LibCallOptimization {
|
* Don't depend on "guessing" what a FILE* is, just require that the actual
type be obtained from a CallInst we're optimizing.
* Make it possible for getConstantStringLength to return the ConstantArray
that it extracts in case the content is needed by an Optimization.
* Implement the strcmp optimization
* Implement the toascii optimization
This pass is now firing several to many times in the following MultiSource
tests:
Applications/Burg - 7 (strcat,strcpy)
Applications/siod - 13 (strcat,strcpy,strlen)
Applications/spiff - 120 (exit,fputs,strcat,strcpy,strlen)
Applications/treecc - 66 (exit,fputs,strcat,strcpy)
Applications/kimwitu++ - 34 (strcmp,strcpy,strlen)
Applications/SPASS - 588 (exit,fputs,strcat,strcpy,strlen)
llvm-svn: 21626
2005-04-30 11:17:54 +08:00
|
|
|
public:
|
2005-05-03 10:54:54 +08:00
|
|
|
StrCmpOptimization() : LibCallOptimization("strcmp",
|
2005-05-08 04:15:59 +08:00
|
|
|
"Number of 'strcmp' calls simplified") {}
|
* Don't depend on "guessing" what a FILE* is, just require that the actual
type be obtained from a CallInst we're optimizing.
* Make it possible for getConstantStringLength to return the ConstantArray
that it extracts in case the content is needed by an Optimization.
* Implement the strcmp optimization
* Implement the toascii optimization
This pass is now firing several to many times in the following MultiSource
tests:
Applications/Burg - 7 (strcat,strcpy)
Applications/siod - 13 (strcat,strcpy,strlen)
Applications/spiff - 120 (exit,fputs,strcat,strcpy,strlen)
Applications/treecc - 66 (exit,fputs,strcat,strcpy)
Applications/kimwitu++ - 34 (strcmp,strcpy,strlen)
Applications/SPASS - 588 (exit,fputs,strcat,strcpy,strlen)
llvm-svn: 21626
2005-04-30 11:17:54 +08:00
|
|
|
|
2005-05-21 06:22:25 +08:00
|
|
|
/// @brief Make sure that the "strcmp" function has the right prototype
|
2006-01-23 06:35:08 +08:00
|
|
|
virtual bool ValidateCalledFunction(const Function *F, SimplifyLibCalls &SLC){
|
2006-12-31 13:48:39 +08:00
|
|
|
return F->getReturnType() == Type::Int32Ty && F->arg_size() == 2;
|
* Don't depend on "guessing" what a FILE* is, just require that the actual
type be obtained from a CallInst we're optimizing.
* Make it possible for getConstantStringLength to return the ConstantArray
that it extracts in case the content is needed by an Optimization.
* Implement the strcmp optimization
* Implement the toascii optimization
This pass is now firing several to many times in the following MultiSource
tests:
Applications/Burg - 7 (strcat,strcpy)
Applications/siod - 13 (strcat,strcpy,strlen)
Applications/spiff - 120 (exit,fputs,strcat,strcpy,strlen)
Applications/treecc - 66 (exit,fputs,strcat,strcpy)
Applications/kimwitu++ - 34 (strcmp,strcpy,strlen)
Applications/SPASS - 588 (exit,fputs,strcat,strcpy,strlen)
llvm-svn: 21626
2005-04-30 11:17:54 +08:00
|
|
|
}
|
|
|
|
|
2005-05-21 06:22:25 +08:00
|
|
|
/// @brief Perform the strcmp optimization
|
2006-01-23 06:35:08 +08:00
|
|
|
virtual bool OptimizeCall(CallInst* ci, SimplifyLibCalls& SLC) {
|
* Don't depend on "guessing" what a FILE* is, just require that the actual
type be obtained from a CallInst we're optimizing.
* Make it possible for getConstantStringLength to return the ConstantArray
that it extracts in case the content is needed by an Optimization.
* Implement the strcmp optimization
* Implement the toascii optimization
This pass is now firing several to many times in the following MultiSource
tests:
Applications/Burg - 7 (strcat,strcpy)
Applications/siod - 13 (strcat,strcpy,strlen)
Applications/spiff - 120 (exit,fputs,strcat,strcpy,strlen)
Applications/treecc - 66 (exit,fputs,strcat,strcpy)
Applications/kimwitu++ - 34 (strcmp,strcpy,strlen)
Applications/SPASS - 588 (exit,fputs,strcat,strcpy,strlen)
llvm-svn: 21626
2005-04-30 11:17:54 +08:00
|
|
|
// First, check to see if src and destination are the same. If they are,
|
2005-04-30 14:45:47 +08:00
|
|
|
// then the optimization is to replace the CallInst with a constant 0
|
2005-07-27 14:12:32 +08:00
|
|
|
// because the call is a no-op.
|
* Don't depend on "guessing" what a FILE* is, just require that the actual
type be obtained from a CallInst we're optimizing.
* Make it possible for getConstantStringLength to return the ConstantArray
that it extracts in case the content is needed by an Optimization.
* Implement the strcmp optimization
* Implement the toascii optimization
This pass is now firing several to many times in the following MultiSource
tests:
Applications/Burg - 7 (strcat,strcpy)
Applications/siod - 13 (strcat,strcpy,strlen)
Applications/spiff - 120 (exit,fputs,strcat,strcpy,strlen)
Applications/treecc - 66 (exit,fputs,strcat,strcpy)
Applications/kimwitu++ - 34 (strcmp,strcpy,strlen)
Applications/SPASS - 588 (exit,fputs,strcat,strcpy,strlen)
llvm-svn: 21626
2005-04-30 11:17:54 +08:00
|
|
|
Value* s1 = ci->getOperand(1);
|
|
|
|
Value* s2 = ci->getOperand(2);
|
2006-01-23 06:35:08 +08:00
|
|
|
if (s1 == s2) {
|
* Don't depend on "guessing" what a FILE* is, just require that the actual
type be obtained from a CallInst we're optimizing.
* Make it possible for getConstantStringLength to return the ConstantArray
that it extracts in case the content is needed by an Optimization.
* Implement the strcmp optimization
* Implement the toascii optimization
This pass is now firing several to many times in the following MultiSource
tests:
Applications/Burg - 7 (strcat,strcpy)
Applications/siod - 13 (strcat,strcpy,strlen)
Applications/spiff - 120 (exit,fputs,strcat,strcpy,strlen)
Applications/treecc - 66 (exit,fputs,strcat,strcpy)
Applications/kimwitu++ - 34 (strcmp,strcpy,strlen)
Applications/SPASS - 588 (exit,fputs,strcat,strcpy,strlen)
llvm-svn: 21626
2005-04-30 11:17:54 +08:00
|
|
|
// strcmp(x,x) -> 0
|
2006-12-31 13:48:39 +08:00
|
|
|
ci->replaceAllUsesWith(ConstantInt::get(Type::Int32Ty,0));
|
* Don't depend on "guessing" what a FILE* is, just require that the actual
type be obtained from a CallInst we're optimizing.
* Make it possible for getConstantStringLength to return the ConstantArray
that it extracts in case the content is needed by an Optimization.
* Implement the strcmp optimization
* Implement the toascii optimization
This pass is now firing several to many times in the following MultiSource
tests:
Applications/Burg - 7 (strcat,strcpy)
Applications/siod - 13 (strcat,strcpy,strlen)
Applications/spiff - 120 (exit,fputs,strcat,strcpy,strlen)
Applications/treecc - 66 (exit,fputs,strcat,strcpy)
Applications/kimwitu++ - 34 (strcmp,strcpy,strlen)
Applications/SPASS - 588 (exit,fputs,strcat,strcpy,strlen)
llvm-svn: 21626
2005-04-30 11:17:54 +08:00
|
|
|
ci->eraseFromParent();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isstr_1 = false;
|
|
|
|
uint64_t len_1 = 0;
|
|
|
|
ConstantArray* A1;
|
2006-01-23 06:35:08 +08:00
|
|
|
if (getConstantStringLength(s1,len_1,&A1)) {
|
* Don't depend on "guessing" what a FILE* is, just require that the actual
type be obtained from a CallInst we're optimizing.
* Make it possible for getConstantStringLength to return the ConstantArray
that it extracts in case the content is needed by an Optimization.
* Implement the strcmp optimization
* Implement the toascii optimization
This pass is now firing several to many times in the following MultiSource
tests:
Applications/Burg - 7 (strcat,strcpy)
Applications/siod - 13 (strcat,strcpy,strlen)
Applications/spiff - 120 (exit,fputs,strcat,strcpy,strlen)
Applications/treecc - 66 (exit,fputs,strcat,strcpy)
Applications/kimwitu++ - 34 (strcmp,strcpy,strlen)
Applications/SPASS - 588 (exit,fputs,strcat,strcpy,strlen)
llvm-svn: 21626
2005-04-30 11:17:54 +08:00
|
|
|
isstr_1 = true;
|
2006-01-23 06:35:08 +08:00
|
|
|
if (len_1 == 0) {
|
* Don't depend on "guessing" what a FILE* is, just require that the actual
type be obtained from a CallInst we're optimizing.
* Make it possible for getConstantStringLength to return the ConstantArray
that it extracts in case the content is needed by an Optimization.
* Implement the strcmp optimization
* Implement the toascii optimization
This pass is now firing several to many times in the following MultiSource
tests:
Applications/Burg - 7 (strcat,strcpy)
Applications/siod - 13 (strcat,strcpy,strlen)
Applications/spiff - 120 (exit,fputs,strcat,strcpy,strlen)
Applications/treecc - 66 (exit,fputs,strcat,strcpy)
Applications/kimwitu++ - 34 (strcmp,strcpy,strlen)
Applications/SPASS - 588 (exit,fputs,strcat,strcpy,strlen)
llvm-svn: 21626
2005-04-30 11:17:54 +08:00
|
|
|
// strcmp("",x) -> *x
|
2005-07-27 14:12:32 +08:00
|
|
|
LoadInst* load =
|
2005-06-19 01:46:28 +08:00
|
|
|
new LoadInst(CastToCStr(s2,*ci), ci->getName()+".load",ci);
|
2005-07-27 14:12:32 +08:00
|
|
|
CastInst* cast =
|
2006-12-31 13:48:39 +08:00
|
|
|
CastInst::create(Instruction::SExt, load, Type::Int32Ty,
|
2006-11-27 09:05:10 +08:00
|
|
|
ci->getName()+".int", ci);
|
* Don't depend on "guessing" what a FILE* is, just require that the actual
type be obtained from a CallInst we're optimizing.
* Make it possible for getConstantStringLength to return the ConstantArray
that it extracts in case the content is needed by an Optimization.
* Implement the strcmp optimization
* Implement the toascii optimization
This pass is now firing several to many times in the following MultiSource
tests:
Applications/Burg - 7 (strcat,strcpy)
Applications/siod - 13 (strcat,strcpy,strlen)
Applications/spiff - 120 (exit,fputs,strcat,strcpy,strlen)
Applications/treecc - 66 (exit,fputs,strcat,strcpy)
Applications/kimwitu++ - 34 (strcmp,strcpy,strlen)
Applications/SPASS - 588 (exit,fputs,strcat,strcpy,strlen)
llvm-svn: 21626
2005-04-30 11:17:54 +08:00
|
|
|
ci->replaceAllUsesWith(cast);
|
|
|
|
ci->eraseFromParent();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isstr_2 = false;
|
|
|
|
uint64_t len_2 = 0;
|
|
|
|
ConstantArray* A2;
|
2006-01-23 06:35:08 +08:00
|
|
|
if (getConstantStringLength(s2, len_2, &A2)) {
|
* Don't depend on "guessing" what a FILE* is, just require that the actual
type be obtained from a CallInst we're optimizing.
* Make it possible for getConstantStringLength to return the ConstantArray
that it extracts in case the content is needed by an Optimization.
* Implement the strcmp optimization
* Implement the toascii optimization
This pass is now firing several to many times in the following MultiSource
tests:
Applications/Burg - 7 (strcat,strcpy)
Applications/siod - 13 (strcat,strcpy,strlen)
Applications/spiff - 120 (exit,fputs,strcat,strcpy,strlen)
Applications/treecc - 66 (exit,fputs,strcat,strcpy)
Applications/kimwitu++ - 34 (strcmp,strcpy,strlen)
Applications/SPASS - 588 (exit,fputs,strcat,strcpy,strlen)
llvm-svn: 21626
2005-04-30 11:17:54 +08:00
|
|
|
isstr_2 = true;
|
2006-01-23 06:35:08 +08:00
|
|
|
if (len_2 == 0) {
|
* Don't depend on "guessing" what a FILE* is, just require that the actual
type be obtained from a CallInst we're optimizing.
* Make it possible for getConstantStringLength to return the ConstantArray
that it extracts in case the content is needed by an Optimization.
* Implement the strcmp optimization
* Implement the toascii optimization
This pass is now firing several to many times in the following MultiSource
tests:
Applications/Burg - 7 (strcat,strcpy)
Applications/siod - 13 (strcat,strcpy,strlen)
Applications/spiff - 120 (exit,fputs,strcat,strcpy,strlen)
Applications/treecc - 66 (exit,fputs,strcat,strcpy)
Applications/kimwitu++ - 34 (strcmp,strcpy,strlen)
Applications/SPASS - 588 (exit,fputs,strcat,strcpy,strlen)
llvm-svn: 21626
2005-04-30 11:17:54 +08:00
|
|
|
// strcmp(x,"") -> *x
|
2005-07-27 14:12:32 +08:00
|
|
|
LoadInst* load =
|
2005-06-19 01:46:28 +08:00
|
|
|
new LoadInst(CastToCStr(s1,*ci),ci->getName()+".val",ci);
|
2005-07-27 14:12:32 +08:00
|
|
|
CastInst* cast =
|
2006-12-31 13:48:39 +08:00
|
|
|
CastInst::create(Instruction::SExt, load, Type::Int32Ty,
|
2006-11-27 09:05:10 +08:00
|
|
|
ci->getName()+".int", ci);
|
* Don't depend on "guessing" what a FILE* is, just require that the actual
type be obtained from a CallInst we're optimizing.
* Make it possible for getConstantStringLength to return the ConstantArray
that it extracts in case the content is needed by an Optimization.
* Implement the strcmp optimization
* Implement the toascii optimization
This pass is now firing several to many times in the following MultiSource
tests:
Applications/Burg - 7 (strcat,strcpy)
Applications/siod - 13 (strcat,strcpy,strlen)
Applications/spiff - 120 (exit,fputs,strcat,strcpy,strlen)
Applications/treecc - 66 (exit,fputs,strcat,strcpy)
Applications/kimwitu++ - 34 (strcmp,strcpy,strlen)
Applications/SPASS - 588 (exit,fputs,strcat,strcpy,strlen)
llvm-svn: 21626
2005-04-30 11:17:54 +08:00
|
|
|
ci->replaceAllUsesWith(cast);
|
|
|
|
ci->eraseFromParent();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-01-23 06:35:08 +08:00
|
|
|
if (isstr_1 && isstr_2) {
|
* Don't depend on "guessing" what a FILE* is, just require that the actual
type be obtained from a CallInst we're optimizing.
* Make it possible for getConstantStringLength to return the ConstantArray
that it extracts in case the content is needed by an Optimization.
* Implement the strcmp optimization
* Implement the toascii optimization
This pass is now firing several to many times in the following MultiSource
tests:
Applications/Burg - 7 (strcat,strcpy)
Applications/siod - 13 (strcat,strcpy,strlen)
Applications/spiff - 120 (exit,fputs,strcat,strcpy,strlen)
Applications/treecc - 66 (exit,fputs,strcat,strcpy)
Applications/kimwitu++ - 34 (strcmp,strcpy,strlen)
Applications/SPASS - 588 (exit,fputs,strcat,strcpy,strlen)
llvm-svn: 21626
2005-04-30 11:17:54 +08:00
|
|
|
// strcmp(x,y) -> cnst (if both x and y are constant strings)
|
|
|
|
std::string str1 = A1->getAsString();
|
|
|
|
std::string str2 = A2->getAsString();
|
|
|
|
int result = strcmp(str1.c_str(), str2.c_str());
|
2006-12-31 13:48:39 +08:00
|
|
|
ci->replaceAllUsesWith(ConstantInt::get(Type::Int32Ty,result));
|
* Don't depend on "guessing" what a FILE* is, just require that the actual
type be obtained from a CallInst we're optimizing.
* Make it possible for getConstantStringLength to return the ConstantArray
that it extracts in case the content is needed by an Optimization.
* Implement the strcmp optimization
* Implement the toascii optimization
This pass is now firing several to many times in the following MultiSource
tests:
Applications/Burg - 7 (strcat,strcpy)
Applications/siod - 13 (strcat,strcpy,strlen)
Applications/spiff - 120 (exit,fputs,strcat,strcpy,strlen)
Applications/treecc - 66 (exit,fputs,strcat,strcpy)
Applications/kimwitu++ - 34 (strcmp,strcpy,strlen)
Applications/SPASS - 588 (exit,fputs,strcat,strcpy,strlen)
llvm-svn: 21626
2005-04-30 11:17:54 +08:00
|
|
|
ci->eraseFromParent();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} StrCmpOptimizer;
|
|
|
|
|
2005-07-27 14:12:32 +08:00
|
|
|
/// This LibCallOptimization will simplify a call to the strncmp library
|
2005-05-03 09:43:45 +08:00
|
|
|
/// function. It optimizes out cases where one or both arguments are constant
|
|
|
|
/// and the result can be determined statically.
|
|
|
|
/// @brief Simplify the strncmp library function.
|
2006-01-23 06:35:08 +08:00
|
|
|
struct StrNCmpOptimization : public LibCallOptimization {
|
2005-05-03 09:43:45 +08:00
|
|
|
public:
|
2005-05-03 10:54:54 +08:00
|
|
|
StrNCmpOptimization() : LibCallOptimization("strncmp",
|
2005-05-08 04:15:59 +08:00
|
|
|
"Number of 'strncmp' calls simplified") {}
|
2005-05-03 09:43:45 +08:00
|
|
|
|
2005-05-21 06:22:25 +08:00
|
|
|
/// @brief Make sure that the "strncmp" function has the right prototype
|
2006-01-23 06:35:08 +08:00
|
|
|
virtual bool ValidateCalledFunction(const Function* f, SimplifyLibCalls& SLC){
|
2006-12-31 13:48:39 +08:00
|
|
|
if (f->getReturnType() == Type::Int32Ty && f->arg_size() == 3)
|
2005-05-03 09:43:45 +08:00
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// @brief Perform the strncpy optimization
|
2006-01-23 06:35:08 +08:00
|
|
|
virtual bool OptimizeCall(CallInst *ci, SimplifyLibCalls &SLC) {
|
2005-05-03 09:43:45 +08:00
|
|
|
// First, check to see if src and destination are the same. If they are,
|
|
|
|
// then the optimization is to replace the CallInst with a constant 0
|
2005-07-27 14:12:32 +08:00
|
|
|
// because the call is a no-op.
|
2005-05-03 09:43:45 +08:00
|
|
|
Value* s1 = ci->getOperand(1);
|
|
|
|
Value* s2 = ci->getOperand(2);
|
2006-01-23 06:35:08 +08:00
|
|
|
if (s1 == s2) {
|
2005-05-03 09:43:45 +08:00
|
|
|
// strncmp(x,x,l) -> 0
|
2006-12-31 13:48:39 +08:00
|
|
|
ci->replaceAllUsesWith(ConstantInt::get(Type::Int32Ty,0));
|
2005-05-03 09:43:45 +08:00
|
|
|
ci->eraseFromParent();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check the length argument, if it is Constant zero then the strings are
|
|
|
|
// considered equal.
|
|
|
|
uint64_t len_arg = 0;
|
|
|
|
bool len_arg_is_const = false;
|
2006-01-23 06:35:08 +08:00
|
|
|
if (ConstantInt* len_CI = dyn_cast<ConstantInt>(ci->getOperand(3))) {
|
2005-05-03 09:43:45 +08:00
|
|
|
len_arg_is_const = true;
|
2006-10-20 15:07:24 +08:00
|
|
|
len_arg = len_CI->getZExtValue();
|
2006-01-23 06:35:08 +08:00
|
|
|
if (len_arg == 0) {
|
2005-05-03 09:43:45 +08:00
|
|
|
// strncmp(x,y,0) -> 0
|
2006-12-31 13:48:39 +08:00
|
|
|
ci->replaceAllUsesWith(ConstantInt::get(Type::Int32Ty,0));
|
2005-05-03 09:43:45 +08:00
|
|
|
ci->eraseFromParent();
|
|
|
|
return true;
|
2005-07-27 14:12:32 +08:00
|
|
|
}
|
2005-05-03 09:43:45 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
bool isstr_1 = false;
|
|
|
|
uint64_t len_1 = 0;
|
|
|
|
ConstantArray* A1;
|
2006-01-23 06:35:08 +08:00
|
|
|
if (getConstantStringLength(s1, len_1, &A1)) {
|
2005-05-03 09:43:45 +08:00
|
|
|
isstr_1 = true;
|
2006-01-23 06:35:08 +08:00
|
|
|
if (len_1 == 0) {
|
2005-05-03 09:43:45 +08:00
|
|
|
// strncmp("",x) -> *x
|
|
|
|
LoadInst* load = new LoadInst(s1,ci->getName()+".load",ci);
|
2005-07-27 14:12:32 +08:00
|
|
|
CastInst* cast =
|
2006-12-31 13:48:39 +08:00
|
|
|
CastInst::create(Instruction::SExt, load, Type::Int32Ty,
|
2006-11-27 09:05:10 +08:00
|
|
|
ci->getName()+".int", ci);
|
2005-05-03 09:43:45 +08:00
|
|
|
ci->replaceAllUsesWith(cast);
|
|
|
|
ci->eraseFromParent();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isstr_2 = false;
|
|
|
|
uint64_t len_2 = 0;
|
|
|
|
ConstantArray* A2;
|
2006-01-23 06:35:08 +08:00
|
|
|
if (getConstantStringLength(s2,len_2,&A2)) {
|
2005-05-03 09:43:45 +08:00
|
|
|
isstr_2 = true;
|
2006-01-23 06:35:08 +08:00
|
|
|
if (len_2 == 0) {
|
2005-05-03 09:43:45 +08:00
|
|
|
// strncmp(x,"") -> *x
|
|
|
|
LoadInst* load = new LoadInst(s2,ci->getName()+".val",ci);
|
2005-07-27 14:12:32 +08:00
|
|
|
CastInst* cast =
|
2006-12-31 13:48:39 +08:00
|
|
|
CastInst::create(Instruction::SExt, load, Type::Int32Ty,
|
2006-11-27 09:05:10 +08:00
|
|
|
ci->getName()+".int", ci);
|
2005-05-03 09:43:45 +08:00
|
|
|
ci->replaceAllUsesWith(cast);
|
|
|
|
ci->eraseFromParent();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-01-23 06:35:08 +08:00
|
|
|
if (isstr_1 && isstr_2 && len_arg_is_const) {
|
2005-05-03 09:43:45 +08:00
|
|
|
// strncmp(x,y,const) -> constant
|
|
|
|
std::string str1 = A1->getAsString();
|
|
|
|
std::string str2 = A2->getAsString();
|
|
|
|
int result = strncmp(str1.c_str(), str2.c_str(), len_arg);
|
2006-12-31 13:48:39 +08:00
|
|
|
ci->replaceAllUsesWith(ConstantInt::get(Type::Int32Ty,result));
|
2005-05-03 09:43:45 +08:00
|
|
|
ci->eraseFromParent();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} StrNCmpOptimizer;
|
|
|
|
|
2005-07-27 14:12:32 +08:00
|
|
|
/// This LibCallOptimization will simplify a call to the strcpy library
|
|
|
|
/// function. Two optimizations are possible:
|
2005-04-27 15:54:40 +08:00
|
|
|
/// (1) If src and dest are the same and not volatile, just return dest
|
|
|
|
/// (2) If the src is a constant then we can convert to llvm.memmove
|
|
|
|
/// @brief Simplify the strcpy library function.
|
2006-01-23 06:35:08 +08:00
|
|
|
struct StrCpyOptimization : public LibCallOptimization {
|
2005-04-27 15:54:40 +08:00
|
|
|
public:
|
2005-05-03 10:54:54 +08:00
|
|
|
StrCpyOptimization() : LibCallOptimization("strcpy",
|
2005-05-08 04:15:59 +08:00
|
|
|
"Number of 'strcpy' calls simplified") {}
|
2005-04-27 15:54:40 +08:00
|
|
|
|
|
|
|
/// @brief Make sure that the "strcpy" function has the right prototype
|
2006-01-23 06:35:08 +08:00
|
|
|
virtual bool ValidateCalledFunction(const Function* f, SimplifyLibCalls& SLC){
|
2006-12-31 13:48:39 +08:00
|
|
|
if (f->getReturnType() == PointerType::get(Type::Int8Ty))
|
2006-01-23 06:35:08 +08:00
|
|
|
if (f->arg_size() == 2) {
|
2005-04-27 15:54:40 +08:00
|
|
|
Function::const_arg_iterator AI = f->arg_begin();
|
2006-12-31 13:48:39 +08:00
|
|
|
if (AI++->getType() == PointerType::get(Type::Int8Ty))
|
|
|
|
if (AI->getType() == PointerType::get(Type::Int8Ty)) {
|
2005-04-27 15:54:40 +08:00
|
|
|
// Indicate this is a suitable call type.
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// @brief Perform the strcpy optimization
|
2006-01-23 06:35:08 +08:00
|
|
|
virtual bool OptimizeCall(CallInst* ci, SimplifyLibCalls& SLC) {
|
2005-04-27 15:54:40 +08:00
|
|
|
// First, check to see if src and destination are the same. If they are,
|
|
|
|
// then the optimization is to replace the CallInst with the destination
|
2005-07-27 14:12:32 +08:00
|
|
|
// because the call is a no-op. Note that this corresponds to the
|
2005-04-27 15:54:40 +08:00
|
|
|
// degenerate strcpy(X,X) case which should have "undefined" results
|
|
|
|
// according to the C specification. However, it occurs sometimes and
|
|
|
|
// we optimize it as a no-op.
|
|
|
|
Value* dest = ci->getOperand(1);
|
|
|
|
Value* src = ci->getOperand(2);
|
2006-01-23 06:35:08 +08:00
|
|
|
if (dest == src) {
|
2005-04-27 15:54:40 +08:00
|
|
|
ci->replaceAllUsesWith(dest);
|
|
|
|
ci->eraseFromParent();
|
|
|
|
return true;
|
|
|
|
}
|
2005-07-27 14:12:32 +08:00
|
|
|
|
2005-04-27 15:54:40 +08:00
|
|
|
// Get the length of the constant string referenced by the second operand,
|
|
|
|
// the "src" parameter. Fail the optimization if we can't get the length
|
|
|
|
// (note that getConstantStringLength does lots of checks to make sure this
|
|
|
|
// is valid).
|
|
|
|
uint64_t len = 0;
|
|
|
|
if (!getConstantStringLength(ci->getOperand(2),len))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// If the constant string's length is zero we can optimize this by just
|
|
|
|
// doing a store of 0 at the first byte of the destination
|
2006-01-23 06:35:08 +08:00
|
|
|
if (len == 0) {
|
2006-12-31 13:48:39 +08:00
|
|
|
new StoreInst(ConstantInt::get(Type::Int8Ty,0),ci->getOperand(1),ci);
|
2005-04-27 15:54:40 +08:00
|
|
|
ci->replaceAllUsesWith(dest);
|
|
|
|
ci->eraseFromParent();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Increment the length because we actually want to memcpy the null
|
|
|
|
// terminator as well.
|
|
|
|
len++;
|
|
|
|
|
|
|
|
// We have enough information to now generate the memcpy call to
|
|
|
|
// do the concatenation for us.
|
|
|
|
std::vector<Value*> vals;
|
|
|
|
vals.push_back(dest); // destination
|
|
|
|
vals.push_back(src); // source
|
2006-10-20 15:07:24 +08:00
|
|
|
vals.push_back(ConstantInt::get(SLC.getIntPtrType(),len)); // length
|
2006-12-31 13:48:39 +08:00
|
|
|
vals.push_back(ConstantInt::get(Type::Int32Ty,1)); // alignment
|
2005-04-28 01:46:54 +08:00
|
|
|
new CallInst(SLC.get_memcpy(), vals, "", ci);
|
2005-04-27 15:54:40 +08:00
|
|
|
|
2005-07-27 14:12:32 +08:00
|
|
|
// Finally, substitute the first operand of the strcat call for the
|
|
|
|
// strcat call itself since strcat returns its first operand; and,
|
2005-04-27 15:54:40 +08:00
|
|
|
// kill the strcat CallInst.
|
|
|
|
ci->replaceAllUsesWith(dest);
|
|
|
|
ci->eraseFromParent();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
} StrCpyOptimizer;
|
|
|
|
|
2005-07-27 14:12:32 +08:00
|
|
|
/// This LibCallOptimization will simplify a call to the strlen library
|
|
|
|
/// function by replacing it with a constant value if the string provided to
|
2005-04-28 05:29:20 +08:00
|
|
|
/// it is a constant array.
|
2005-04-26 13:24:00 +08:00
|
|
|
/// @brief Simplify the strlen library function.
|
2006-01-23 06:35:08 +08:00
|
|
|
struct StrLenOptimization : public LibCallOptimization {
|
2005-05-03 10:54:54 +08:00
|
|
|
StrLenOptimization() : LibCallOptimization("strlen",
|
2005-05-08 04:15:59 +08:00
|
|
|
"Number of 'strlen' calls simplified") {}
|
2005-04-26 13:24:00 +08:00
|
|
|
|
|
|
|
/// @brief Make sure that the "strlen" function has the right prototype
|
2005-04-27 15:54:40 +08:00
|
|
|
virtual bool ValidateCalledFunction(const Function* f, SimplifyLibCalls& SLC)
|
2005-04-26 13:24:00 +08:00
|
|
|
{
|
2005-04-27 15:54:40 +08:00
|
|
|
if (f->getReturnType() == SLC.getTargetData()->getIntPtrType())
|
2005-07-27 14:12:32 +08:00
|
|
|
if (f->arg_size() == 1)
|
2005-04-26 13:24:00 +08:00
|
|
|
if (Function::const_arg_iterator AI = f->arg_begin())
|
2006-12-31 13:48:39 +08:00
|
|
|
if (AI->getType() == PointerType::get(Type::Int8Ty))
|
2005-04-26 13:24:00 +08:00
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// @brief Perform the strlen optimization
|
2005-04-27 15:54:40 +08:00
|
|
|
virtual bool OptimizeCall(CallInst* ci, SimplifyLibCalls& SLC)
|
2005-04-26 13:24:00 +08:00
|
|
|
{
|
2005-05-08 04:15:59 +08:00
|
|
|
// Make sure we're dealing with an sbyte* here.
|
|
|
|
Value* str = ci->getOperand(1);
|
2006-12-31 13:48:39 +08:00
|
|
|
if (str->getType() != PointerType::get(Type::Int8Ty))
|
2005-05-08 04:15:59 +08:00
|
|
|
return false;
|
|
|
|
|
|
|
|
// Does the call to strlen have exactly one use?
|
2005-07-27 14:12:32 +08:00
|
|
|
if (ci->hasOneUse())
|
2006-12-23 14:05:41 +08:00
|
|
|
// Is that single use a icmp operator?
|
|
|
|
if (ICmpInst* bop = dyn_cast<ICmpInst>(ci->use_back()))
|
2005-05-08 04:15:59 +08:00
|
|
|
// Is it compared against a constant integer?
|
|
|
|
if (ConstantInt* CI = dyn_cast<ConstantInt>(bop->getOperand(1)))
|
|
|
|
{
|
|
|
|
// Get the value the strlen result is compared to
|
2006-10-20 15:07:24 +08:00
|
|
|
uint64_t val = CI->getZExtValue();
|
2005-05-08 04:15:59 +08:00
|
|
|
|
|
|
|
// If its compared against length 0 with == or !=
|
|
|
|
if (val == 0 &&
|
2006-12-23 14:05:41 +08:00
|
|
|
(bop->getPredicate() == ICmpInst::ICMP_EQ ||
|
|
|
|
bop->getPredicate() == ICmpInst::ICMP_NE))
|
2005-05-08 04:15:59 +08:00
|
|
|
{
|
|
|
|
// strlen(x) != 0 -> *x != 0
|
|
|
|
// strlen(x) == 0 -> *x == 0
|
|
|
|
LoadInst* load = new LoadInst(str,str->getName()+".first",ci);
|
2006-12-23 14:05:41 +08:00
|
|
|
ICmpInst* rbop = new ICmpInst(bop->getPredicate(), load,
|
2006-12-31 13:48:39 +08:00
|
|
|
ConstantInt::get(Type::Int8Ty,0),
|
2006-12-23 14:05:41 +08:00
|
|
|
bop->getName()+".strlen", ci);
|
2005-05-08 04:15:59 +08:00
|
|
|
bop->replaceAllUsesWith(rbop);
|
|
|
|
bop->eraseFromParent();
|
|
|
|
ci->eraseFromParent();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the length of the constant string operand
|
2005-04-26 15:45:18 +08:00
|
|
|
uint64_t len = 0;
|
|
|
|
if (!getConstantStringLength(ci->getOperand(1),len))
|
2005-04-26 13:24:00 +08:00
|
|
|
return false;
|
|
|
|
|
2005-05-08 04:15:59 +08:00
|
|
|
// strlen("xyz") -> 3 (for example)
|
2005-08-02 00:52:50 +08:00
|
|
|
const Type *Ty = SLC.getTargetData()->getIntPtrType();
|
2006-12-21 15:15:54 +08:00
|
|
|
ci->replaceAllUsesWith(ConstantInt::get(Ty, len));
|
2005-08-02 00:52:50 +08:00
|
|
|
|
2005-04-26 15:45:18 +08:00
|
|
|
ci->eraseFromParent();
|
|
|
|
return true;
|
2005-04-26 13:24:00 +08:00
|
|
|
}
|
|
|
|
} StrLenOptimizer;
|
|
|
|
|
2005-09-29 12:54:20 +08:00
|
|
|
/// IsOnlyUsedInEqualsComparison - Return true if it only matters that the value
|
|
|
|
/// is equal or not-equal to zero.
|
|
|
|
static bool IsOnlyUsedInEqualsZeroComparison(Instruction *I) {
|
|
|
|
for (Value::use_iterator UI = I->use_begin(), E = I->use_end();
|
|
|
|
UI != E; ++UI) {
|
|
|
|
Instruction *User = cast<Instruction>(*UI);
|
2006-12-23 14:05:41 +08:00
|
|
|
if (ICmpInst *IC = dyn_cast<ICmpInst>(User)) {
|
|
|
|
if ((IC->getPredicate() == ICmpInst::ICMP_NE ||
|
|
|
|
IC->getPredicate() == ICmpInst::ICMP_EQ) &&
|
|
|
|
isa<Constant>(IC->getOperand(1)) &&
|
|
|
|
cast<Constant>(IC->getOperand(1))->isNullValue())
|
2005-09-29 12:54:20 +08:00
|
|
|
continue;
|
|
|
|
} else if (CastInst *CI = dyn_cast<CastInst>(User))
|
2007-01-12 02:21:29 +08:00
|
|
|
if (CI->getType() == Type::Int1Ty)
|
2005-09-29 12:54:20 +08:00
|
|
|
continue;
|
|
|
|
// Unknown instruction.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// This memcmpOptimization will simplify a call to the memcmp library
|
|
|
|
/// function.
|
|
|
|
struct memcmpOptimization : public LibCallOptimization {
|
|
|
|
/// @brief Default Constructor
|
|
|
|
memcmpOptimization()
|
|
|
|
: LibCallOptimization("memcmp", "Number of 'memcmp' calls simplified") {}
|
|
|
|
|
|
|
|
/// @brief Make sure that the "memcmp" function has the right prototype
|
|
|
|
virtual bool ValidateCalledFunction(const Function *F, SimplifyLibCalls &TD) {
|
|
|
|
Function::const_arg_iterator AI = F->arg_begin();
|
|
|
|
if (F->arg_size() != 3 || !isa<PointerType>(AI->getType())) return false;
|
|
|
|
if (!isa<PointerType>((++AI)->getType())) return false;
|
2007-01-15 09:55:30 +08:00
|
|
|
if (!(++AI)->getType()->isIntegral()) return false;
|
|
|
|
if (!F->getReturnType()->isIntegral()) return false;
|
2005-09-29 12:54:20 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Because of alignment and instruction information that we don't have, we
|
|
|
|
/// leave the bulk of this to the code generators.
|
|
|
|
///
|
|
|
|
/// Note that we could do much more if we could force alignment on otherwise
|
|
|
|
/// small aligned allocas, or if we could indicate that loads have a small
|
|
|
|
/// alignment.
|
|
|
|
virtual bool OptimizeCall(CallInst *CI, SimplifyLibCalls &TD) {
|
|
|
|
Value *LHS = CI->getOperand(1), *RHS = CI->getOperand(2);
|
|
|
|
|
|
|
|
// If the two operands are the same, return zero.
|
|
|
|
if (LHS == RHS) {
|
|
|
|
// memcmp(s,s,x) -> 0
|
|
|
|
CI->replaceAllUsesWith(Constant::getNullValue(CI->getType()));
|
|
|
|
CI->eraseFromParent();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make sure we have a constant length.
|
|
|
|
ConstantInt *LenC = dyn_cast<ConstantInt>(CI->getOperand(3));
|
|
|
|
if (!LenC) return false;
|
2006-10-20 15:07:24 +08:00
|
|
|
uint64_t Len = LenC->getZExtValue();
|
2005-09-29 12:54:20 +08:00
|
|
|
|
|
|
|
// If the length is zero, this returns 0.
|
|
|
|
switch (Len) {
|
|
|
|
case 0:
|
|
|
|
// memcmp(s1,s2,0) -> 0
|
|
|
|
CI->replaceAllUsesWith(Constant::getNullValue(CI->getType()));
|
|
|
|
CI->eraseFromParent();
|
|
|
|
return true;
|
|
|
|
case 1: {
|
|
|
|
// memcmp(S1,S2,1) -> *(ubyte*)S1 - *(ubyte*)S2
|
2006-12-31 13:48:39 +08:00
|
|
|
const Type *UCharPtr = PointerType::get(Type::Int8Ty);
|
2006-11-27 09:05:10 +08:00
|
|
|
CastInst *Op1Cast = CastInst::create(
|
|
|
|
Instruction::BitCast, LHS, UCharPtr, LHS->getName(), CI);
|
|
|
|
CastInst *Op2Cast = CastInst::create(
|
|
|
|
Instruction::BitCast, RHS, UCharPtr, RHS->getName(), CI);
|
2005-09-29 12:54:20 +08:00
|
|
|
Value *S1V = new LoadInst(Op1Cast, LHS->getName()+".val", CI);
|
|
|
|
Value *S2V = new LoadInst(Op2Cast, RHS->getName()+".val", CI);
|
|
|
|
Value *RV = BinaryOperator::createSub(S1V, S2V, CI->getName()+".diff",CI);
|
|
|
|
if (RV->getType() != CI->getType())
|
2006-12-13 08:50:17 +08:00
|
|
|
RV = CastInst::createIntegerCast(RV, CI->getType(), false,
|
|
|
|
RV->getName(), CI);
|
2005-09-29 12:54:20 +08:00
|
|
|
CI->replaceAllUsesWith(RV);
|
|
|
|
CI->eraseFromParent();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case 2:
|
|
|
|
if (IsOnlyUsedInEqualsZeroComparison(CI)) {
|
|
|
|
// TODO: IF both are aligned, use a short load/compare.
|
|
|
|
|
|
|
|
// memcmp(S1,S2,2) -> S1[0]-S2[0] | S1[1]-S2[1] iff only ==/!= 0 matters
|
2006-12-31 13:48:39 +08:00
|
|
|
const Type *UCharPtr = PointerType::get(Type::Int8Ty);
|
2006-11-27 09:05:10 +08:00
|
|
|
CastInst *Op1Cast = CastInst::create(
|
|
|
|
Instruction::BitCast, LHS, UCharPtr, LHS->getName(), CI);
|
|
|
|
CastInst *Op2Cast = CastInst::create(
|
|
|
|
Instruction::BitCast, RHS, UCharPtr, RHS->getName(), CI);
|
2005-09-29 12:54:20 +08:00
|
|
|
Value *S1V1 = new LoadInst(Op1Cast, LHS->getName()+".val1", CI);
|
|
|
|
Value *S2V1 = new LoadInst(Op2Cast, RHS->getName()+".val1", CI);
|
|
|
|
Value *D1 = BinaryOperator::createSub(S1V1, S2V1,
|
|
|
|
CI->getName()+".d1", CI);
|
2006-12-31 13:48:39 +08:00
|
|
|
Constant *One = ConstantInt::get(Type::Int32Ty, 1);
|
2005-09-29 12:54:20 +08:00
|
|
|
Value *G1 = new GetElementPtrInst(Op1Cast, One, "next1v", CI);
|
|
|
|
Value *G2 = new GetElementPtrInst(Op2Cast, One, "next2v", CI);
|
|
|
|
Value *S1V2 = new LoadInst(G1, LHS->getName()+".val2", CI);
|
2006-05-13 07:35:26 +08:00
|
|
|
Value *S2V2 = new LoadInst(G2, RHS->getName()+".val2", CI);
|
2005-09-29 12:54:20 +08:00
|
|
|
Value *D2 = BinaryOperator::createSub(S1V2, S2V2,
|
|
|
|
CI->getName()+".d1", CI);
|
|
|
|
Value *Or = BinaryOperator::createOr(D1, D2, CI->getName()+".res", CI);
|
|
|
|
if (Or->getType() != CI->getType())
|
2006-12-13 08:50:17 +08:00
|
|
|
Or = CastInst::createIntegerCast(Or, CI->getType(), false /*ZExt*/,
|
|
|
|
Or->getName(), CI);
|
2005-09-29 12:54:20 +08:00
|
|
|
CI->replaceAllUsesWith(Or);
|
|
|
|
CI->eraseFromParent();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} memcmpOptimizer;
|
|
|
|
|
|
|
|
|
2005-07-27 14:12:32 +08:00
|
|
|
/// This LibCallOptimization will simplify a call to the memcpy library
|
|
|
|
/// function by expanding it out to a single store of size 0, 1, 2, 4, or 8
|
2005-04-28 05:29:20 +08:00
|
|
|
/// bytes depending on the length of the string and the alignment. Additional
|
|
|
|
/// optimizations are possible in code generation (sequence of immediate store)
|
2005-04-26 05:11:48 +08:00
|
|
|
/// @brief Simplify the memcpy library function.
|
2006-03-03 09:30:23 +08:00
|
|
|
struct LLVMMemCpyMoveOptzn : public LibCallOptimization {
|
|
|
|
LLVMMemCpyMoveOptzn(const char* fname, const char* desc)
|
|
|
|
: LibCallOptimization(fname, desc) {}
|
2005-04-26 05:11:48 +08:00
|
|
|
|
|
|
|
/// @brief Make sure that the "memcpy" function has the right prototype
|
2006-01-23 06:35:08 +08:00
|
|
|
virtual bool ValidateCalledFunction(const Function* f, SimplifyLibCalls& TD) {
|
2005-04-27 03:13:17 +08:00
|
|
|
// Just make sure this has 4 arguments per LLVM spec.
|
2005-04-27 07:02:16 +08:00
|
|
|
return (f->arg_size() == 4);
|
2005-04-26 05:11:48 +08:00
|
|
|
}
|
|
|
|
|
2005-04-26 15:45:18 +08:00
|
|
|
/// Because of alignment and instruction information that we don't have, we
|
|
|
|
/// leave the bulk of this to the code generators. The optimization here just
|
|
|
|
/// deals with a few degenerate cases where the length of the string and the
|
|
|
|
/// alignment match the sizes of our intrinsic types so we can do a load and
|
|
|
|
/// store instead of the memcpy call.
|
|
|
|
/// @brief Perform the memcpy optimization.
|
2006-01-23 06:35:08 +08:00
|
|
|
virtual bool OptimizeCall(CallInst* ci, SimplifyLibCalls& TD) {
|
2005-04-27 03:55:57 +08:00
|
|
|
// Make sure we have constant int values to work with
|
|
|
|
ConstantInt* LEN = dyn_cast<ConstantInt>(ci->getOperand(3));
|
|
|
|
if (!LEN)
|
|
|
|
return false;
|
|
|
|
ConstantInt* ALIGN = dyn_cast<ConstantInt>(ci->getOperand(4));
|
|
|
|
if (!ALIGN)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// If the length is larger than the alignment, we can't optimize
|
2006-10-20 15:07:24 +08:00
|
|
|
uint64_t len = LEN->getZExtValue();
|
|
|
|
uint64_t alignment = ALIGN->getZExtValue();
|
2005-05-03 15:23:44 +08:00
|
|
|
if (alignment == 0)
|
|
|
|
alignment = 1; // Alignment 0 is identity for alignment 1
|
2005-04-27 03:13:17 +08:00
|
|
|
if (len > alignment)
|
2005-04-26 15:45:18 +08:00
|
|
|
return false;
|
|
|
|
|
2005-04-28 01:46:54 +08:00
|
|
|
// Get the type we will cast to, based on size of the string
|
2005-04-26 15:45:18 +08:00
|
|
|
Value* dest = ci->getOperand(1);
|
|
|
|
Value* src = ci->getOperand(2);
|
2007-01-08 05:45:41 +08:00
|
|
|
const Type* castType = 0;
|
2005-04-26 15:45:18 +08:00
|
|
|
switch (len)
|
|
|
|
{
|
2005-04-27 03:13:17 +08:00
|
|
|
case 0:
|
2005-04-29 17:39:47 +08:00
|
|
|
// memcpy(d,s,0,a) -> noop
|
2005-04-27 03:13:17 +08:00
|
|
|
ci->eraseFromParent();
|
|
|
|
return true;
|
2006-12-31 13:48:39 +08:00
|
|
|
case 1: castType = Type::Int8Ty; break;
|
|
|
|
case 2: castType = Type::Int16Ty; break;
|
|
|
|
case 4: castType = Type::Int32Ty; break;
|
|
|
|
case 8: castType = Type::Int64Ty; break;
|
2005-04-26 15:45:18 +08:00
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
2005-04-28 01:46:54 +08:00
|
|
|
|
|
|
|
// Cast source and dest to the right sized primitive and then load/store
|
2006-11-27 09:05:10 +08:00
|
|
|
CastInst* SrcCast = CastInst::create(Instruction::BitCast,
|
|
|
|
src, PointerType::get(castType), src->getName()+".cast", ci);
|
|
|
|
CastInst* DestCast = CastInst::create(Instruction::BitCast,
|
|
|
|
dest, PointerType::get(castType),dest->getName()+".cast", ci);
|
2005-04-28 01:46:54 +08:00
|
|
|
LoadInst* LI = new LoadInst(SrcCast,SrcCast->getName()+".val",ci);
|
2006-11-03 04:25:50 +08:00
|
|
|
new StoreInst(LI, DestCast, ci);
|
2005-04-26 15:45:18 +08:00
|
|
|
ci->eraseFromParent();
|
|
|
|
return true;
|
2005-04-26 05:11:48 +08:00
|
|
|
}
|
2006-03-03 09:30:23 +08:00
|
|
|
};
|
2005-04-27 03:13:17 +08:00
|
|
|
|
2006-03-03 09:30:23 +08:00
|
|
|
/// This LibCallOptimization will simplify a call to the memcpy/memmove library
|
|
|
|
/// functions.
|
|
|
|
LLVMMemCpyMoveOptzn LLVMMemCpyOptimizer32("llvm.memcpy.i32",
|
|
|
|
"Number of 'llvm.memcpy' calls simplified");
|
|
|
|
LLVMMemCpyMoveOptzn LLVMMemCpyOptimizer64("llvm.memcpy.i64",
|
|
|
|
"Number of 'llvm.memcpy' calls simplified");
|
|
|
|
LLVMMemCpyMoveOptzn LLVMMemMoveOptimizer32("llvm.memmove.i32",
|
|
|
|
"Number of 'llvm.memmove' calls simplified");
|
|
|
|
LLVMMemCpyMoveOptzn LLVMMemMoveOptimizer64("llvm.memmove.i64",
|
|
|
|
"Number of 'llvm.memmove' calls simplified");
|
2005-05-03 15:23:44 +08:00
|
|
|
|
2005-07-27 14:12:32 +08:00
|
|
|
/// This LibCallOptimization will simplify a call to the memset library
|
|
|
|
/// function by expanding it out to a single store of size 0, 1, 2, 4, or 8
|
|
|
|
/// bytes depending on the length argument.
|
2006-01-23 06:35:08 +08:00
|
|
|
struct LLVMMemSetOptimization : public LibCallOptimization {
|
2005-05-03 15:23:44 +08:00
|
|
|
/// @brief Default Constructor
|
2006-03-03 09:30:23 +08:00
|
|
|
LLVMMemSetOptimization(const char *Name) : LibCallOptimization(Name,
|
2005-05-03 15:23:44 +08:00
|
|
|
"Number of 'llvm.memset' calls simplified") {}
|
|
|
|
|
|
|
|
/// @brief Make sure that the "memset" function has the right prototype
|
2006-01-23 06:35:08 +08:00
|
|
|
virtual bool ValidateCalledFunction(const Function *F, SimplifyLibCalls &TD) {
|
2005-05-03 15:23:44 +08:00
|
|
|
// Just make sure this has 3 arguments per LLVM spec.
|
2006-01-23 06:35:08 +08:00
|
|
|
return F->arg_size() == 4;
|
2005-05-03 15:23:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Because of alignment and instruction information that we don't have, we
|
|
|
|
/// leave the bulk of this to the code generators. The optimization here just
|
|
|
|
/// deals with a few degenerate cases where the length parameter is constant
|
2005-07-27 14:12:32 +08:00
|
|
|
/// and the alignment matches the sizes of our intrinsic types so we can do
|
2005-05-03 15:23:44 +08:00
|
|
|
/// store instead of the memcpy call. Other calls are transformed into the
|
|
|
|
/// llvm.memset intrinsic.
|
|
|
|
/// @brief Perform the memset optimization.
|
2006-01-23 06:35:08 +08:00
|
|
|
virtual bool OptimizeCall(CallInst *ci, SimplifyLibCalls &TD) {
|
2005-05-03 15:23:44 +08:00
|
|
|
// Make sure we have constant int values to work with
|
|
|
|
ConstantInt* LEN = dyn_cast<ConstantInt>(ci->getOperand(3));
|
|
|
|
if (!LEN)
|
|
|
|
return false;
|
|
|
|
ConstantInt* ALIGN = dyn_cast<ConstantInt>(ci->getOperand(4));
|
|
|
|
if (!ALIGN)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Extract the length and alignment
|
2006-10-20 15:07:24 +08:00
|
|
|
uint64_t len = LEN->getZExtValue();
|
|
|
|
uint64_t alignment = ALIGN->getZExtValue();
|
2005-05-03 15:23:44 +08:00
|
|
|
|
|
|
|
// Alignment 0 is identity for alignment 1
|
|
|
|
if (alignment == 0)
|
|
|
|
alignment = 1;
|
|
|
|
|
|
|
|
// If the length is zero, this is a no-op
|
2006-01-23 06:35:08 +08:00
|
|
|
if (len == 0) {
|
2005-05-03 15:23:44 +08:00
|
|
|
// memset(d,c,0,a) -> noop
|
|
|
|
ci->eraseFromParent();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the length is larger than the alignment, we can't optimize
|
|
|
|
if (len > alignment)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Make sure we have a constant ubyte to work with so we can extract
|
|
|
|
// the value to be filled.
|
2006-10-20 15:07:24 +08:00
|
|
|
ConstantInt* FILL = dyn_cast<ConstantInt>(ci->getOperand(2));
|
2005-05-03 15:23:44 +08:00
|
|
|
if (!FILL)
|
|
|
|
return false;
|
2006-12-31 13:48:39 +08:00
|
|
|
if (FILL->getType() != Type::Int8Ty)
|
2005-05-03 15:23:44 +08:00
|
|
|
return false;
|
|
|
|
|
|
|
|
// memset(s,c,n) -> store s, c (for n=1,2,4,8)
|
2005-07-27 14:12:32 +08:00
|
|
|
|
2005-05-03 15:23:44 +08:00
|
|
|
// Extract the fill character
|
2006-10-20 15:07:24 +08:00
|
|
|
uint64_t fill_char = FILL->getZExtValue();
|
2005-05-03 15:23:44 +08:00
|
|
|
uint64_t fill_value = fill_char;
|
|
|
|
|
|
|
|
// Get the type we will cast to, based on size of memory area to fill, and
|
|
|
|
// and the value we will store there.
|
|
|
|
Value* dest = ci->getOperand(1);
|
2007-01-08 05:45:41 +08:00
|
|
|
const Type* castType = 0;
|
2006-01-23 06:35:08 +08:00
|
|
|
switch (len) {
|
2005-07-27 14:12:32 +08:00
|
|
|
case 1:
|
2006-12-31 13:48:39 +08:00
|
|
|
castType = Type::Int8Ty;
|
2005-05-03 15:23:44 +08:00
|
|
|
break;
|
2005-07-27 14:12:32 +08:00
|
|
|
case 2:
|
2006-12-31 13:48:39 +08:00
|
|
|
castType = Type::Int16Ty;
|
2005-05-03 15:23:44 +08:00
|
|
|
fill_value |= fill_char << 8;
|
|
|
|
break;
|
2005-07-27 14:12:32 +08:00
|
|
|
case 4:
|
2006-12-31 13:48:39 +08:00
|
|
|
castType = Type::Int32Ty;
|
2005-05-03 15:23:44 +08:00
|
|
|
fill_value |= fill_char << 8 | fill_char << 16 | fill_char << 24;
|
|
|
|
break;
|
2005-07-27 14:12:32 +08:00
|
|
|
case 8:
|
2006-12-31 13:48:39 +08:00
|
|
|
castType = Type::Int64Ty;
|
2005-05-03 15:23:44 +08:00
|
|
|
fill_value |= fill_char << 8 | fill_char << 16 | fill_char << 24;
|
|
|
|
fill_value |= fill_char << 32 | fill_char << 40 | fill_char << 48;
|
|
|
|
fill_value |= fill_char << 56;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Cast dest to the right sized primitive and then load/store
|
2006-12-13 08:50:17 +08:00
|
|
|
CastInst* DestCast = new BitCastInst(dest, PointerType::get(castType),
|
|
|
|
dest->getName()+".cast", ci);
|
2006-10-20 15:07:24 +08:00
|
|
|
new StoreInst(ConstantInt::get(castType,fill_value),DestCast, ci);
|
2005-05-03 15:23:44 +08:00
|
|
|
ci->eraseFromParent();
|
|
|
|
return true;
|
|
|
|
}
|
2006-03-03 09:30:23 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
LLVMMemSetOptimization MemSet32Optimizer("llvm.memset.i32");
|
|
|
|
LLVMMemSetOptimization MemSet64Optimizer("llvm.memset.i64");
|
|
|
|
|
2005-04-27 03:13:17 +08:00
|
|
|
|
2005-07-27 14:12:32 +08:00
|
|
|
/// This LibCallOptimization will simplify calls to the "pow" library
|
|
|
|
/// function. It looks for cases where the result of pow is well known and
|
2005-04-29 17:39:47 +08:00
|
|
|
/// substitutes the appropriate value.
|
|
|
|
/// @brief Simplify the pow library function.
|
2006-01-23 06:35:08 +08:00
|
|
|
struct PowOptimization : public LibCallOptimization {
|
2005-04-29 17:39:47 +08:00
|
|
|
public:
|
|
|
|
/// @brief Default Constructor
|
2005-05-03 10:54:54 +08:00
|
|
|
PowOptimization() : LibCallOptimization("pow",
|
2005-05-08 04:15:59 +08:00
|
|
|
"Number of 'pow' calls simplified") {}
|
2005-05-03 10:54:54 +08:00
|
|
|
|
2005-04-29 17:39:47 +08:00
|
|
|
/// @brief Make sure that the "pow" function has the right prototype
|
2006-01-23 06:35:08 +08:00
|
|
|
virtual bool ValidateCalledFunction(const Function* f, SimplifyLibCalls& SLC){
|
2005-04-29 17:39:47 +08:00
|
|
|
// Just make sure this has 2 arguments
|
|
|
|
return (f->arg_size() == 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// @brief Perform the pow optimization.
|
2006-01-23 06:35:08 +08:00
|
|
|
virtual bool OptimizeCall(CallInst *ci, SimplifyLibCalls &SLC) {
|
2005-04-29 17:39:47 +08:00
|
|
|
const Type *Ty = cast<Function>(ci->getOperand(0))->getReturnType();
|
|
|
|
Value* base = ci->getOperand(1);
|
|
|
|
Value* expn = ci->getOperand(2);
|
|
|
|
if (ConstantFP *Op1 = dyn_cast<ConstantFP>(base)) {
|
|
|
|
double Op1V = Op1->getValue();
|
2006-01-23 06:35:08 +08:00
|
|
|
if (Op1V == 1.0) {
|
2005-04-29 17:39:47 +08:00
|
|
|
// pow(1.0,x) -> 1.0
|
|
|
|
ci->replaceAllUsesWith(ConstantFP::get(Ty,1.0));
|
|
|
|
ci->eraseFromParent();
|
|
|
|
return true;
|
|
|
|
}
|
2006-01-23 06:35:08 +08:00
|
|
|
} else if (ConstantFP* Op2 = dyn_cast<ConstantFP>(expn)) {
|
2005-04-29 17:39:47 +08:00
|
|
|
double Op2V = Op2->getValue();
|
2006-01-23 06:35:08 +08:00
|
|
|
if (Op2V == 0.0) {
|
2005-04-29 17:39:47 +08:00
|
|
|
// pow(x,0.0) -> 1.0
|
|
|
|
ci->replaceAllUsesWith(ConstantFP::get(Ty,1.0));
|
|
|
|
ci->eraseFromParent();
|
|
|
|
return true;
|
2006-01-23 06:35:08 +08:00
|
|
|
} else if (Op2V == 0.5) {
|
2005-04-29 17:39:47 +08:00
|
|
|
// pow(x,0.5) -> sqrt(x)
|
|
|
|
CallInst* sqrt_inst = new CallInst(SLC.get_sqrt(), base,
|
|
|
|
ci->getName()+".pow",ci);
|
|
|
|
ci->replaceAllUsesWith(sqrt_inst);
|
|
|
|
ci->eraseFromParent();
|
|
|
|
return true;
|
2006-01-23 06:35:08 +08:00
|
|
|
} else if (Op2V == 1.0) {
|
2005-04-29 17:39:47 +08:00
|
|
|
// pow(x,1.0) -> x
|
|
|
|
ci->replaceAllUsesWith(base);
|
|
|
|
ci->eraseFromParent();
|
|
|
|
return true;
|
2006-01-23 06:35:08 +08:00
|
|
|
} else if (Op2V == -1.0) {
|
2005-04-29 17:39:47 +08:00
|
|
|
// pow(x,-1.0) -> 1.0/x
|
2006-10-26 14:15:43 +08:00
|
|
|
BinaryOperator* div_inst= BinaryOperator::createFDiv(
|
2005-04-29 17:39:47 +08:00
|
|
|
ConstantFP::get(Ty,1.0), base, ci->getName()+".pow", ci);
|
|
|
|
ci->replaceAllUsesWith(div_inst);
|
|
|
|
ci->eraseFromParent();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false; // opt failed
|
|
|
|
}
|
|
|
|
} PowOptimizer;
|
|
|
|
|
2006-06-16 16:36:35 +08:00
|
|
|
/// This LibCallOptimization will simplify calls to the "printf" library
|
|
|
|
/// function. It looks for cases where the result of printf is not used and the
|
|
|
|
/// operation can be reduced to something simpler.
|
|
|
|
/// @brief Simplify the printf library function.
|
|
|
|
struct PrintfOptimization : public LibCallOptimization {
|
|
|
|
public:
|
|
|
|
/// @brief Default Constructor
|
|
|
|
PrintfOptimization() : LibCallOptimization("printf",
|
|
|
|
"Number of 'printf' calls simplified") {}
|
|
|
|
|
|
|
|
/// @brief Make sure that the "printf" function has the right prototype
|
|
|
|
virtual bool ValidateCalledFunction(const Function* f, SimplifyLibCalls& SLC){
|
|
|
|
// Just make sure this has at least 1 arguments
|
|
|
|
return (f->arg_size() >= 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// @brief Perform the printf optimization.
|
|
|
|
virtual bool OptimizeCall(CallInst* ci, SimplifyLibCalls& SLC) {
|
|
|
|
// If the call has more than 2 operands, we can't optimize it
|
|
|
|
if (ci->getNumOperands() > 3 || ci->getNumOperands() <= 2)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// If the result of the printf call is used, none of these optimizations
|
|
|
|
// can be made.
|
|
|
|
if (!ci->use_empty())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// All the optimizations depend on the length of the first argument and the
|
|
|
|
// fact that it is a constant string array. Check that now
|
|
|
|
uint64_t len = 0;
|
|
|
|
ConstantArray* CA = 0;
|
|
|
|
if (!getConstantStringLength(ci->getOperand(1), len, &CA))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (len != 2 && len != 3)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// The first character has to be a %
|
|
|
|
if (ConstantInt* CI = dyn_cast<ConstantInt>(CA->getOperand(0)))
|
2006-10-20 15:07:24 +08:00
|
|
|
if (CI->getZExtValue() != '%')
|
2006-06-16 16:36:35 +08:00
|
|
|
return false;
|
|
|
|
|
|
|
|
// Get the second character and switch on its value
|
|
|
|
ConstantInt* CI = dyn_cast<ConstantInt>(CA->getOperand(1));
|
2006-10-20 15:07:24 +08:00
|
|
|
switch (CI->getZExtValue()) {
|
2006-06-16 16:36:35 +08:00
|
|
|
case 's':
|
|
|
|
{
|
|
|
|
if (len != 3 ||
|
2006-10-20 15:07:24 +08:00
|
|
|
dyn_cast<ConstantInt>(CA->getOperand(2))->getZExtValue() != '\n')
|
2006-06-16 16:36:35 +08:00
|
|
|
return false;
|
|
|
|
|
|
|
|
// printf("%s\n",str) -> puts(str)
|
|
|
|
std::vector<Value*> args;
|
2007-01-07 16:12:01 +08:00
|
|
|
new CallInst(SLC.get_puts(), CastToCStr(ci->getOperand(2), *ci),
|
|
|
|
ci->getName(), ci);
|
|
|
|
ci->replaceAllUsesWith(ConstantInt::get(Type::Int32Ty, len));
|
2006-06-16 16:36:35 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 'c':
|
|
|
|
{
|
|
|
|
// printf("%c",c) -> putchar(c)
|
|
|
|
if (len != 2)
|
|
|
|
return false;
|
|
|
|
|
2007-01-07 16:12:01 +08:00
|
|
|
CastInst *Char = CastInst::createSExtOrBitCast(
|
2006-12-31 13:48:39 +08:00
|
|
|
ci->getOperand(2), Type::Int32Ty, CI->getName()+".int", ci);
|
2007-01-07 16:12:01 +08:00
|
|
|
new CallInst(SLC.get_putchar(), Char, "", ci);
|
2006-12-31 13:48:39 +08:00
|
|
|
ci->replaceAllUsesWith(ConstantInt::get(Type::Int32Ty, 1));
|
2006-06-16 16:36:35 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
ci->eraseFromParent();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
} PrintfOptimizer;
|
|
|
|
|
2005-07-27 14:12:32 +08:00
|
|
|
/// This LibCallOptimization will simplify calls to the "fprintf" library
|
Implement the fprintf optimization which converts calls like this:
fprintf(F,"hello") -> fwrite("hello",strlen("hello"),1,F)
fprintf(F,"%s","hello") -> fwrite("hello",strlen("hello"),1,F)
fprintf(F,"%c",'x') -> fputc('c',F)
This optimization fires severals times in llvm-test:
313 MultiSource/Applications/Burg
302 MultiSource/Benchmarks/Prolangs-C/TimberWolfMC
189 MultiSource/Benchmarks/Prolangs-C/mybison
175 MultiSource/Benchmarks/Prolangs-C/football
130 MultiSource/Benchmarks/Prolangs-C/unix-tbl
llvm-svn: 21657
2005-05-03 07:59:26 +08:00
|
|
|
/// function. It looks for cases where the result of fprintf is not used and the
|
|
|
|
/// operation can be reduced to something simpler.
|
2006-06-16 16:36:35 +08:00
|
|
|
/// @brief Simplify the fprintf library function.
|
2006-01-23 06:35:08 +08:00
|
|
|
struct FPrintFOptimization : public LibCallOptimization {
|
Implement the fprintf optimization which converts calls like this:
fprintf(F,"hello") -> fwrite("hello",strlen("hello"),1,F)
fprintf(F,"%s","hello") -> fwrite("hello",strlen("hello"),1,F)
fprintf(F,"%c",'x') -> fputc('c',F)
This optimization fires severals times in llvm-test:
313 MultiSource/Applications/Burg
302 MultiSource/Benchmarks/Prolangs-C/TimberWolfMC
189 MultiSource/Benchmarks/Prolangs-C/mybison
175 MultiSource/Benchmarks/Prolangs-C/football
130 MultiSource/Benchmarks/Prolangs-C/unix-tbl
llvm-svn: 21657
2005-05-03 07:59:26 +08:00
|
|
|
public:
|
|
|
|
/// @brief Default Constructor
|
2005-05-03 10:54:54 +08:00
|
|
|
FPrintFOptimization() : LibCallOptimization("fprintf",
|
2005-05-08 04:15:59 +08:00
|
|
|
"Number of 'fprintf' calls simplified") {}
|
Implement the fprintf optimization which converts calls like this:
fprintf(F,"hello") -> fwrite("hello",strlen("hello"),1,F)
fprintf(F,"%s","hello") -> fwrite("hello",strlen("hello"),1,F)
fprintf(F,"%c",'x') -> fputc('c',F)
This optimization fires severals times in llvm-test:
313 MultiSource/Applications/Burg
302 MultiSource/Benchmarks/Prolangs-C/TimberWolfMC
189 MultiSource/Benchmarks/Prolangs-C/mybison
175 MultiSource/Benchmarks/Prolangs-C/football
130 MultiSource/Benchmarks/Prolangs-C/unix-tbl
llvm-svn: 21657
2005-05-03 07:59:26 +08:00
|
|
|
|
|
|
|
/// @brief Make sure that the "fprintf" function has the right prototype
|
2006-01-23 06:35:08 +08:00
|
|
|
virtual bool ValidateCalledFunction(const Function* f, SimplifyLibCalls& SLC){
|
Implement the fprintf optimization which converts calls like this:
fprintf(F,"hello") -> fwrite("hello",strlen("hello"),1,F)
fprintf(F,"%s","hello") -> fwrite("hello",strlen("hello"),1,F)
fprintf(F,"%c",'x') -> fputc('c',F)
This optimization fires severals times in llvm-test:
313 MultiSource/Applications/Burg
302 MultiSource/Benchmarks/Prolangs-C/TimberWolfMC
189 MultiSource/Benchmarks/Prolangs-C/mybison
175 MultiSource/Benchmarks/Prolangs-C/football
130 MultiSource/Benchmarks/Prolangs-C/unix-tbl
llvm-svn: 21657
2005-05-03 07:59:26 +08:00
|
|
|
// Just make sure this has at least 2 arguments
|
|
|
|
return (f->arg_size() >= 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// @brief Perform the fprintf optimization.
|
2006-01-23 06:35:08 +08:00
|
|
|
virtual bool OptimizeCall(CallInst* ci, SimplifyLibCalls& SLC) {
|
Implement the fprintf optimization which converts calls like this:
fprintf(F,"hello") -> fwrite("hello",strlen("hello"),1,F)
fprintf(F,"%s","hello") -> fwrite("hello",strlen("hello"),1,F)
fprintf(F,"%c",'x') -> fputc('c',F)
This optimization fires severals times in llvm-test:
313 MultiSource/Applications/Burg
302 MultiSource/Benchmarks/Prolangs-C/TimberWolfMC
189 MultiSource/Benchmarks/Prolangs-C/mybison
175 MultiSource/Benchmarks/Prolangs-C/football
130 MultiSource/Benchmarks/Prolangs-C/unix-tbl
llvm-svn: 21657
2005-05-03 07:59:26 +08:00
|
|
|
// If the call has more than 3 operands, we can't optimize it
|
|
|
|
if (ci->getNumOperands() > 4 || ci->getNumOperands() <= 2)
|
|
|
|
return false;
|
|
|
|
|
2005-07-27 14:12:32 +08:00
|
|
|
// If the result of the fprintf call is used, none of these optimizations
|
Implement the fprintf optimization which converts calls like this:
fprintf(F,"hello") -> fwrite("hello",strlen("hello"),1,F)
fprintf(F,"%s","hello") -> fwrite("hello",strlen("hello"),1,F)
fprintf(F,"%c",'x') -> fputc('c',F)
This optimization fires severals times in llvm-test:
313 MultiSource/Applications/Burg
302 MultiSource/Benchmarks/Prolangs-C/TimberWolfMC
189 MultiSource/Benchmarks/Prolangs-C/mybison
175 MultiSource/Benchmarks/Prolangs-C/football
130 MultiSource/Benchmarks/Prolangs-C/unix-tbl
llvm-svn: 21657
2005-05-03 07:59:26 +08:00
|
|
|
// can be made.
|
2005-09-25 06:17:06 +08:00
|
|
|
if (!ci->use_empty())
|
Implement the fprintf optimization which converts calls like this:
fprintf(F,"hello") -> fwrite("hello",strlen("hello"),1,F)
fprintf(F,"%s","hello") -> fwrite("hello",strlen("hello"),1,F)
fprintf(F,"%c",'x') -> fputc('c',F)
This optimization fires severals times in llvm-test:
313 MultiSource/Applications/Burg
302 MultiSource/Benchmarks/Prolangs-C/TimberWolfMC
189 MultiSource/Benchmarks/Prolangs-C/mybison
175 MultiSource/Benchmarks/Prolangs-C/football
130 MultiSource/Benchmarks/Prolangs-C/unix-tbl
llvm-svn: 21657
2005-05-03 07:59:26 +08:00
|
|
|
return false;
|
|
|
|
|
|
|
|
// All the optimizations depend on the length of the second argument and the
|
|
|
|
// fact that it is a constant string array. Check that now
|
2005-07-27 14:12:32 +08:00
|
|
|
uint64_t len = 0;
|
Implement the fprintf optimization which converts calls like this:
fprintf(F,"hello") -> fwrite("hello",strlen("hello"),1,F)
fprintf(F,"%s","hello") -> fwrite("hello",strlen("hello"),1,F)
fprintf(F,"%c",'x') -> fputc('c',F)
This optimization fires severals times in llvm-test:
313 MultiSource/Applications/Burg
302 MultiSource/Benchmarks/Prolangs-C/TimberWolfMC
189 MultiSource/Benchmarks/Prolangs-C/mybison
175 MultiSource/Benchmarks/Prolangs-C/football
130 MultiSource/Benchmarks/Prolangs-C/unix-tbl
llvm-svn: 21657
2005-05-03 07:59:26 +08:00
|
|
|
ConstantArray* CA = 0;
|
|
|
|
if (!getConstantStringLength(ci->getOperand(2), len, &CA))
|
|
|
|
return false;
|
|
|
|
|
2006-01-23 06:35:08 +08:00
|
|
|
if (ci->getNumOperands() == 3) {
|
Implement the fprintf optimization which converts calls like this:
fprintf(F,"hello") -> fwrite("hello",strlen("hello"),1,F)
fprintf(F,"%s","hello") -> fwrite("hello",strlen("hello"),1,F)
fprintf(F,"%c",'x') -> fputc('c',F)
This optimization fires severals times in llvm-test:
313 MultiSource/Applications/Burg
302 MultiSource/Benchmarks/Prolangs-C/TimberWolfMC
189 MultiSource/Benchmarks/Prolangs-C/mybison
175 MultiSource/Benchmarks/Prolangs-C/football
130 MultiSource/Benchmarks/Prolangs-C/unix-tbl
llvm-svn: 21657
2005-05-03 07:59:26 +08:00
|
|
|
// Make sure there's no % in the constant array
|
2006-01-23 06:35:08 +08:00
|
|
|
for (unsigned i = 0; i < len; ++i) {
|
|
|
|
if (ConstantInt* CI = dyn_cast<ConstantInt>(CA->getOperand(i))) {
|
Implement the fprintf optimization which converts calls like this:
fprintf(F,"hello") -> fwrite("hello",strlen("hello"),1,F)
fprintf(F,"%s","hello") -> fwrite("hello",strlen("hello"),1,F)
fprintf(F,"%c",'x') -> fputc('c',F)
This optimization fires severals times in llvm-test:
313 MultiSource/Applications/Burg
302 MultiSource/Benchmarks/Prolangs-C/TimberWolfMC
189 MultiSource/Benchmarks/Prolangs-C/mybison
175 MultiSource/Benchmarks/Prolangs-C/football
130 MultiSource/Benchmarks/Prolangs-C/unix-tbl
llvm-svn: 21657
2005-05-03 07:59:26 +08:00
|
|
|
// Check for the null terminator
|
2006-10-20 15:07:24 +08:00
|
|
|
if (CI->getZExtValue() == '%')
|
Implement the fprintf optimization which converts calls like this:
fprintf(F,"hello") -> fwrite("hello",strlen("hello"),1,F)
fprintf(F,"%s","hello") -> fwrite("hello",strlen("hello"),1,F)
fprintf(F,"%c",'x') -> fputc('c',F)
This optimization fires severals times in llvm-test:
313 MultiSource/Applications/Burg
302 MultiSource/Benchmarks/Prolangs-C/TimberWolfMC
189 MultiSource/Benchmarks/Prolangs-C/mybison
175 MultiSource/Benchmarks/Prolangs-C/football
130 MultiSource/Benchmarks/Prolangs-C/unix-tbl
llvm-svn: 21657
2005-05-03 07:59:26 +08:00
|
|
|
return false; // we found end of string
|
2006-01-23 06:35:08 +08:00
|
|
|
} else {
|
Implement the fprintf optimization which converts calls like this:
fprintf(F,"hello") -> fwrite("hello",strlen("hello"),1,F)
fprintf(F,"%s","hello") -> fwrite("hello",strlen("hello"),1,F)
fprintf(F,"%c",'x') -> fputc('c',F)
This optimization fires severals times in llvm-test:
313 MultiSource/Applications/Burg
302 MultiSource/Benchmarks/Prolangs-C/TimberWolfMC
189 MultiSource/Benchmarks/Prolangs-C/mybison
175 MultiSource/Benchmarks/Prolangs-C/football
130 MultiSource/Benchmarks/Prolangs-C/unix-tbl
llvm-svn: 21657
2005-05-03 07:59:26 +08:00
|
|
|
return false;
|
2006-01-23 06:35:08 +08:00
|
|
|
}
|
Implement the fprintf optimization which converts calls like this:
fprintf(F,"hello") -> fwrite("hello",strlen("hello"),1,F)
fprintf(F,"%s","hello") -> fwrite("hello",strlen("hello"),1,F)
fprintf(F,"%c",'x') -> fputc('c',F)
This optimization fires severals times in llvm-test:
313 MultiSource/Applications/Burg
302 MultiSource/Benchmarks/Prolangs-C/TimberWolfMC
189 MultiSource/Benchmarks/Prolangs-C/mybison
175 MultiSource/Benchmarks/Prolangs-C/football
130 MultiSource/Benchmarks/Prolangs-C/unix-tbl
llvm-svn: 21657
2005-05-03 07:59:26 +08:00
|
|
|
}
|
|
|
|
|
2005-07-27 14:12:32 +08:00
|
|
|
// fprintf(file,fmt) -> fwrite(fmt,strlen(fmt),file)
|
Implement the fprintf optimization which converts calls like this:
fprintf(F,"hello") -> fwrite("hello",strlen("hello"),1,F)
fprintf(F,"%s","hello") -> fwrite("hello",strlen("hello"),1,F)
fprintf(F,"%c",'x') -> fputc('c',F)
This optimization fires severals times in llvm-test:
313 MultiSource/Applications/Burg
302 MultiSource/Benchmarks/Prolangs-C/TimberWolfMC
189 MultiSource/Benchmarks/Prolangs-C/mybison
175 MultiSource/Benchmarks/Prolangs-C/football
130 MultiSource/Benchmarks/Prolangs-C/unix-tbl
llvm-svn: 21657
2005-05-03 07:59:26 +08:00
|
|
|
const Type* FILEptr_type = ci->getOperand(1)->getType();
|
2005-06-29 23:03:18 +08:00
|
|
|
|
|
|
|
// Make sure that the fprintf() and fwrite() functions both take the
|
|
|
|
// same type of char pointer.
|
2007-01-07 16:12:01 +08:00
|
|
|
if (ci->getOperand(2)->getType() != PointerType::get(Type::Int8Ty))
|
2005-06-29 23:03:18 +08:00
|
|
|
return false;
|
|
|
|
|
Implement the fprintf optimization which converts calls like this:
fprintf(F,"hello") -> fwrite("hello",strlen("hello"),1,F)
fprintf(F,"%s","hello") -> fwrite("hello",strlen("hello"),1,F)
fprintf(F,"%c",'x') -> fputc('c',F)
This optimization fires severals times in llvm-test:
313 MultiSource/Applications/Burg
302 MultiSource/Benchmarks/Prolangs-C/TimberWolfMC
189 MultiSource/Benchmarks/Prolangs-C/mybison
175 MultiSource/Benchmarks/Prolangs-C/football
130 MultiSource/Benchmarks/Prolangs-C/unix-tbl
llvm-svn: 21657
2005-05-03 07:59:26 +08:00
|
|
|
std::vector<Value*> args;
|
|
|
|
args.push_back(ci->getOperand(2));
|
2006-10-20 15:07:24 +08:00
|
|
|
args.push_back(ConstantInt::get(SLC.getIntPtrType(),len));
|
|
|
|
args.push_back(ConstantInt::get(SLC.getIntPtrType(),1));
|
Implement the fprintf optimization which converts calls like this:
fprintf(F,"hello") -> fwrite("hello",strlen("hello"),1,F)
fprintf(F,"%s","hello") -> fwrite("hello",strlen("hello"),1,F)
fprintf(F,"%c",'x') -> fputc('c',F)
This optimization fires severals times in llvm-test:
313 MultiSource/Applications/Burg
302 MultiSource/Benchmarks/Prolangs-C/TimberWolfMC
189 MultiSource/Benchmarks/Prolangs-C/mybison
175 MultiSource/Benchmarks/Prolangs-C/football
130 MultiSource/Benchmarks/Prolangs-C/unix-tbl
llvm-svn: 21657
2005-05-03 07:59:26 +08:00
|
|
|
args.push_back(ci->getOperand(1));
|
2007-01-07 16:12:01 +08:00
|
|
|
new CallInst(SLC.get_fwrite(FILEptr_type), args, ci->getName(), ci);
|
2006-12-31 13:48:39 +08:00
|
|
|
ci->replaceAllUsesWith(ConstantInt::get(Type::Int32Ty,len));
|
Implement the fprintf optimization which converts calls like this:
fprintf(F,"hello") -> fwrite("hello",strlen("hello"),1,F)
fprintf(F,"%s","hello") -> fwrite("hello",strlen("hello"),1,F)
fprintf(F,"%c",'x') -> fputc('c',F)
This optimization fires severals times in llvm-test:
313 MultiSource/Applications/Burg
302 MultiSource/Benchmarks/Prolangs-C/TimberWolfMC
189 MultiSource/Benchmarks/Prolangs-C/mybison
175 MultiSource/Benchmarks/Prolangs-C/football
130 MultiSource/Benchmarks/Prolangs-C/unix-tbl
llvm-svn: 21657
2005-05-03 07:59:26 +08:00
|
|
|
ci->eraseFromParent();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The remaining optimizations require the format string to be length 2
|
|
|
|
// "%s" or "%c".
|
|
|
|
if (len != 2)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// The first character has to be a %
|
|
|
|
if (ConstantInt* CI = dyn_cast<ConstantInt>(CA->getOperand(0)))
|
2006-10-20 15:07:24 +08:00
|
|
|
if (CI->getZExtValue() != '%')
|
Implement the fprintf optimization which converts calls like this:
fprintf(F,"hello") -> fwrite("hello",strlen("hello"),1,F)
fprintf(F,"%s","hello") -> fwrite("hello",strlen("hello"),1,F)
fprintf(F,"%c",'x') -> fputc('c',F)
This optimization fires severals times in llvm-test:
313 MultiSource/Applications/Burg
302 MultiSource/Benchmarks/Prolangs-C/TimberWolfMC
189 MultiSource/Benchmarks/Prolangs-C/mybison
175 MultiSource/Benchmarks/Prolangs-C/football
130 MultiSource/Benchmarks/Prolangs-C/unix-tbl
llvm-svn: 21657
2005-05-03 07:59:26 +08:00
|
|
|
return false;
|
|
|
|
|
|
|
|
// Get the second character and switch on its value
|
|
|
|
ConstantInt* CI = dyn_cast<ConstantInt>(CA->getOperand(1));
|
2006-10-20 15:07:24 +08:00
|
|
|
switch (CI->getZExtValue()) {
|
Implement the fprintf optimization which converts calls like this:
fprintf(F,"hello") -> fwrite("hello",strlen("hello"),1,F)
fprintf(F,"%s","hello") -> fwrite("hello",strlen("hello"),1,F)
fprintf(F,"%c",'x') -> fputc('c',F)
This optimization fires severals times in llvm-test:
313 MultiSource/Applications/Burg
302 MultiSource/Benchmarks/Prolangs-C/TimberWolfMC
189 MultiSource/Benchmarks/Prolangs-C/mybison
175 MultiSource/Benchmarks/Prolangs-C/football
130 MultiSource/Benchmarks/Prolangs-C/unix-tbl
llvm-svn: 21657
2005-05-03 07:59:26 +08:00
|
|
|
case 's':
|
|
|
|
{
|
2005-07-27 14:12:32 +08:00
|
|
|
uint64_t len = 0;
|
Implement the fprintf optimization which converts calls like this:
fprintf(F,"hello") -> fwrite("hello",strlen("hello"),1,F)
fprintf(F,"%s","hello") -> fwrite("hello",strlen("hello"),1,F)
fprintf(F,"%c",'x') -> fputc('c',F)
This optimization fires severals times in llvm-test:
313 MultiSource/Applications/Burg
302 MultiSource/Benchmarks/Prolangs-C/TimberWolfMC
189 MultiSource/Benchmarks/Prolangs-C/mybison
175 MultiSource/Benchmarks/Prolangs-C/football
130 MultiSource/Benchmarks/Prolangs-C/unix-tbl
llvm-svn: 21657
2005-05-03 07:59:26 +08:00
|
|
|
ConstantArray* CA = 0;
|
2006-06-16 12:52:30 +08:00
|
|
|
if (getConstantStringLength(ci->getOperand(3), len, &CA)) {
|
|
|
|
// fprintf(file,"%s",str) -> fwrite(str,strlen(str),1,file)
|
|
|
|
const Type* FILEptr_type = ci->getOperand(1)->getType();
|
|
|
|
std::vector<Value*> args;
|
|
|
|
args.push_back(CastToCStr(ci->getOperand(3), *ci));
|
2007-01-07 16:12:01 +08:00
|
|
|
args.push_back(ConstantInt::get(SLC.getIntPtrType(), len));
|
|
|
|
args.push_back(ConstantInt::get(SLC.getIntPtrType(), 1));
|
2006-06-16 12:52:30 +08:00
|
|
|
args.push_back(ci->getOperand(1));
|
2007-01-07 16:12:01 +08:00
|
|
|
new CallInst(SLC.get_fwrite(FILEptr_type), args, ci->getName(), ci);
|
|
|
|
ci->replaceAllUsesWith(ConstantInt::get(Type::Int32Ty, len));
|
2006-06-16 12:52:30 +08:00
|
|
|
} else {
|
|
|
|
// fprintf(file,"%s",str) -> fputs(str,file)
|
|
|
|
const Type* FILEptr_type = ci->getOperand(1)->getType();
|
2007-01-07 16:12:01 +08:00
|
|
|
new CallInst(SLC.get_fputs(FILEptr_type),
|
|
|
|
CastToCStr(ci->getOperand(3), *ci),
|
|
|
|
ci->getOperand(1), ci->getName(),ci);
|
2006-12-31 13:48:39 +08:00
|
|
|
ci->replaceAllUsesWith(ConstantInt::get(Type::Int32Ty,len));
|
2006-06-16 12:52:30 +08:00
|
|
|
}
|
Implement the fprintf optimization which converts calls like this:
fprintf(F,"hello") -> fwrite("hello",strlen("hello"),1,F)
fprintf(F,"%s","hello") -> fwrite("hello",strlen("hello"),1,F)
fprintf(F,"%c",'x') -> fputc('c',F)
This optimization fires severals times in llvm-test:
313 MultiSource/Applications/Burg
302 MultiSource/Benchmarks/Prolangs-C/TimberWolfMC
189 MultiSource/Benchmarks/Prolangs-C/mybison
175 MultiSource/Benchmarks/Prolangs-C/football
130 MultiSource/Benchmarks/Prolangs-C/unix-tbl
llvm-svn: 21657
2005-05-03 07:59:26 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 'c':
|
|
|
|
{
|
2006-06-16 16:36:35 +08:00
|
|
|
// fprintf(file,"%c",c) -> fputc(c,file)
|
Implement the fprintf optimization which converts calls like this:
fprintf(F,"hello") -> fwrite("hello",strlen("hello"),1,F)
fprintf(F,"%s","hello") -> fwrite("hello",strlen("hello"),1,F)
fprintf(F,"%c",'x') -> fputc('c',F)
This optimization fires severals times in llvm-test:
313 MultiSource/Applications/Burg
302 MultiSource/Benchmarks/Prolangs-C/TimberWolfMC
189 MultiSource/Benchmarks/Prolangs-C/mybison
175 MultiSource/Benchmarks/Prolangs-C/football
130 MultiSource/Benchmarks/Prolangs-C/unix-tbl
llvm-svn: 21657
2005-05-03 07:59:26 +08:00
|
|
|
const Type* FILEptr_type = ci->getOperand(1)->getType();
|
2006-12-13 08:50:17 +08:00
|
|
|
CastInst* cast = CastInst::createSExtOrBitCast(
|
2006-12-31 13:48:39 +08:00
|
|
|
ci->getOperand(3), Type::Int32Ty, CI->getName()+".int", ci);
|
2007-01-07 16:12:01 +08:00
|
|
|
new CallInst(SLC.get_fputc(FILEptr_type), cast,ci->getOperand(1),"",ci);
|
2006-12-31 13:48:39 +08:00
|
|
|
ci->replaceAllUsesWith(ConstantInt::get(Type::Int32Ty,1));
|
Implement the fprintf optimization which converts calls like this:
fprintf(F,"hello") -> fwrite("hello",strlen("hello"),1,F)
fprintf(F,"%s","hello") -> fwrite("hello",strlen("hello"),1,F)
fprintf(F,"%c",'x') -> fputc('c',F)
This optimization fires severals times in llvm-test:
313 MultiSource/Applications/Burg
302 MultiSource/Benchmarks/Prolangs-C/TimberWolfMC
189 MultiSource/Benchmarks/Prolangs-C/mybison
175 MultiSource/Benchmarks/Prolangs-C/football
130 MultiSource/Benchmarks/Prolangs-C/unix-tbl
llvm-svn: 21657
2005-05-03 07:59:26 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
ci->eraseFromParent();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
} FPrintFOptimizer;
|
|
|
|
|
2005-07-27 14:12:32 +08:00
|
|
|
/// This LibCallOptimization will simplify calls to the "sprintf" library
|
* Correct the function prototypes for some of the functions to match the
actual spec (int -> uint)
* Add the ability to get/cache the strlen function prototype.
* Make sure generated values are appropriately named for debugging purposes
* Add the SPrintFOptimiation for 4 casts of sprintf optimization:
sprintf(str,cstr) -> llvm.memcpy(str,cstr) (if cstr has no %)
sprintf(str,"") -> store sbyte 0, str
sprintf(str,"%s",src) -> llvm.memcpy(str,src) (if src is constant)
sprintf(str,"%c",chr) -> store chr, str ; store sbyte 0, str+1
The sprintf optimization didn't fire as much as I had hoped:
2 MultiSource/Applications/SPASS
5 MultiSource/Benchmarks/McCat/18-imp
22 MultiSource/Benchmarks/Prolangs-C/TimberWolfMC
1 MultiSource/Benchmarks/Prolangs-C/assembler
6 MultiSource/Benchmarks/Prolangs-C/unix-smail
2 MultiSource/Benchmarks/mediabench/mpeg2/mpeg2dec
llvm-svn: 21679
2005-05-04 11:20:21 +08:00
|
|
|
/// function. It looks for cases where the result of sprintf is not used and the
|
|
|
|
/// operation can be reduced to something simpler.
|
2006-06-16 16:36:35 +08:00
|
|
|
/// @brief Simplify the sprintf library function.
|
2006-01-23 06:35:08 +08:00
|
|
|
struct SPrintFOptimization : public LibCallOptimization {
|
* Correct the function prototypes for some of the functions to match the
actual spec (int -> uint)
* Add the ability to get/cache the strlen function prototype.
* Make sure generated values are appropriately named for debugging purposes
* Add the SPrintFOptimiation for 4 casts of sprintf optimization:
sprintf(str,cstr) -> llvm.memcpy(str,cstr) (if cstr has no %)
sprintf(str,"") -> store sbyte 0, str
sprintf(str,"%s",src) -> llvm.memcpy(str,src) (if src is constant)
sprintf(str,"%c",chr) -> store chr, str ; store sbyte 0, str+1
The sprintf optimization didn't fire as much as I had hoped:
2 MultiSource/Applications/SPASS
5 MultiSource/Benchmarks/McCat/18-imp
22 MultiSource/Benchmarks/Prolangs-C/TimberWolfMC
1 MultiSource/Benchmarks/Prolangs-C/assembler
6 MultiSource/Benchmarks/Prolangs-C/unix-smail
2 MultiSource/Benchmarks/mediabench/mpeg2/mpeg2dec
llvm-svn: 21679
2005-05-04 11:20:21 +08:00
|
|
|
public:
|
|
|
|
/// @brief Default Constructor
|
|
|
|
SPrintFOptimization() : LibCallOptimization("sprintf",
|
2005-05-08 04:15:59 +08:00
|
|
|
"Number of 'sprintf' calls simplified") {}
|
* Correct the function prototypes for some of the functions to match the
actual spec (int -> uint)
* Add the ability to get/cache the strlen function prototype.
* Make sure generated values are appropriately named for debugging purposes
* Add the SPrintFOptimiation for 4 casts of sprintf optimization:
sprintf(str,cstr) -> llvm.memcpy(str,cstr) (if cstr has no %)
sprintf(str,"") -> store sbyte 0, str
sprintf(str,"%s",src) -> llvm.memcpy(str,src) (if src is constant)
sprintf(str,"%c",chr) -> store chr, str ; store sbyte 0, str+1
The sprintf optimization didn't fire as much as I had hoped:
2 MultiSource/Applications/SPASS
5 MultiSource/Benchmarks/McCat/18-imp
22 MultiSource/Benchmarks/Prolangs-C/TimberWolfMC
1 MultiSource/Benchmarks/Prolangs-C/assembler
6 MultiSource/Benchmarks/Prolangs-C/unix-smail
2 MultiSource/Benchmarks/mediabench/mpeg2/mpeg2dec
llvm-svn: 21679
2005-05-04 11:20:21 +08:00
|
|
|
|
|
|
|
/// @brief Make sure that the "fprintf" function has the right prototype
|
2006-01-23 06:35:08 +08:00
|
|
|
virtual bool ValidateCalledFunction(const Function *f, SimplifyLibCalls &SLC){
|
* Correct the function prototypes for some of the functions to match the
actual spec (int -> uint)
* Add the ability to get/cache the strlen function prototype.
* Make sure generated values are appropriately named for debugging purposes
* Add the SPrintFOptimiation for 4 casts of sprintf optimization:
sprintf(str,cstr) -> llvm.memcpy(str,cstr) (if cstr has no %)
sprintf(str,"") -> store sbyte 0, str
sprintf(str,"%s",src) -> llvm.memcpy(str,src) (if src is constant)
sprintf(str,"%c",chr) -> store chr, str ; store sbyte 0, str+1
The sprintf optimization didn't fire as much as I had hoped:
2 MultiSource/Applications/SPASS
5 MultiSource/Benchmarks/McCat/18-imp
22 MultiSource/Benchmarks/Prolangs-C/TimberWolfMC
1 MultiSource/Benchmarks/Prolangs-C/assembler
6 MultiSource/Benchmarks/Prolangs-C/unix-smail
2 MultiSource/Benchmarks/mediabench/mpeg2/mpeg2dec
llvm-svn: 21679
2005-05-04 11:20:21 +08:00
|
|
|
// Just make sure this has at least 2 arguments
|
2006-12-31 13:48:39 +08:00
|
|
|
return (f->getReturnType() == Type::Int32Ty && f->arg_size() >= 2);
|
* Correct the function prototypes for some of the functions to match the
actual spec (int -> uint)
* Add the ability to get/cache the strlen function prototype.
* Make sure generated values are appropriately named for debugging purposes
* Add the SPrintFOptimiation for 4 casts of sprintf optimization:
sprintf(str,cstr) -> llvm.memcpy(str,cstr) (if cstr has no %)
sprintf(str,"") -> store sbyte 0, str
sprintf(str,"%s",src) -> llvm.memcpy(str,src) (if src is constant)
sprintf(str,"%c",chr) -> store chr, str ; store sbyte 0, str+1
The sprintf optimization didn't fire as much as I had hoped:
2 MultiSource/Applications/SPASS
5 MultiSource/Benchmarks/McCat/18-imp
22 MultiSource/Benchmarks/Prolangs-C/TimberWolfMC
1 MultiSource/Benchmarks/Prolangs-C/assembler
6 MultiSource/Benchmarks/Prolangs-C/unix-smail
2 MultiSource/Benchmarks/mediabench/mpeg2/mpeg2dec
llvm-svn: 21679
2005-05-04 11:20:21 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// @brief Perform the sprintf optimization.
|
2006-01-23 06:35:08 +08:00
|
|
|
virtual bool OptimizeCall(CallInst *ci, SimplifyLibCalls &SLC) {
|
* Correct the function prototypes for some of the functions to match the
actual spec (int -> uint)
* Add the ability to get/cache the strlen function prototype.
* Make sure generated values are appropriately named for debugging purposes
* Add the SPrintFOptimiation for 4 casts of sprintf optimization:
sprintf(str,cstr) -> llvm.memcpy(str,cstr) (if cstr has no %)
sprintf(str,"") -> store sbyte 0, str
sprintf(str,"%s",src) -> llvm.memcpy(str,src) (if src is constant)
sprintf(str,"%c",chr) -> store chr, str ; store sbyte 0, str+1
The sprintf optimization didn't fire as much as I had hoped:
2 MultiSource/Applications/SPASS
5 MultiSource/Benchmarks/McCat/18-imp
22 MultiSource/Benchmarks/Prolangs-C/TimberWolfMC
1 MultiSource/Benchmarks/Prolangs-C/assembler
6 MultiSource/Benchmarks/Prolangs-C/unix-smail
2 MultiSource/Benchmarks/mediabench/mpeg2/mpeg2dec
llvm-svn: 21679
2005-05-04 11:20:21 +08:00
|
|
|
// If the call has more than 3 operands, we can't optimize it
|
|
|
|
if (ci->getNumOperands() > 4 || ci->getNumOperands() < 3)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// All the optimizations depend on the length of the second argument and the
|
|
|
|
// fact that it is a constant string array. Check that now
|
2005-07-27 14:12:32 +08:00
|
|
|
uint64_t len = 0;
|
* Correct the function prototypes for some of the functions to match the
actual spec (int -> uint)
* Add the ability to get/cache the strlen function prototype.
* Make sure generated values are appropriately named for debugging purposes
* Add the SPrintFOptimiation for 4 casts of sprintf optimization:
sprintf(str,cstr) -> llvm.memcpy(str,cstr) (if cstr has no %)
sprintf(str,"") -> store sbyte 0, str
sprintf(str,"%s",src) -> llvm.memcpy(str,src) (if src is constant)
sprintf(str,"%c",chr) -> store chr, str ; store sbyte 0, str+1
The sprintf optimization didn't fire as much as I had hoped:
2 MultiSource/Applications/SPASS
5 MultiSource/Benchmarks/McCat/18-imp
22 MultiSource/Benchmarks/Prolangs-C/TimberWolfMC
1 MultiSource/Benchmarks/Prolangs-C/assembler
6 MultiSource/Benchmarks/Prolangs-C/unix-smail
2 MultiSource/Benchmarks/mediabench/mpeg2/mpeg2dec
llvm-svn: 21679
2005-05-04 11:20:21 +08:00
|
|
|
ConstantArray* CA = 0;
|
|
|
|
if (!getConstantStringLength(ci->getOperand(2), len, &CA))
|
|
|
|
return false;
|
|
|
|
|
2006-01-23 06:35:08 +08:00
|
|
|
if (ci->getNumOperands() == 3) {
|
|
|
|
if (len == 0) {
|
* Correct the function prototypes for some of the functions to match the
actual spec (int -> uint)
* Add the ability to get/cache the strlen function prototype.
* Make sure generated values are appropriately named for debugging purposes
* Add the SPrintFOptimiation for 4 casts of sprintf optimization:
sprintf(str,cstr) -> llvm.memcpy(str,cstr) (if cstr has no %)
sprintf(str,"") -> store sbyte 0, str
sprintf(str,"%s",src) -> llvm.memcpy(str,src) (if src is constant)
sprintf(str,"%c",chr) -> store chr, str ; store sbyte 0, str+1
The sprintf optimization didn't fire as much as I had hoped:
2 MultiSource/Applications/SPASS
5 MultiSource/Benchmarks/McCat/18-imp
22 MultiSource/Benchmarks/Prolangs-C/TimberWolfMC
1 MultiSource/Benchmarks/Prolangs-C/assembler
6 MultiSource/Benchmarks/Prolangs-C/unix-smail
2 MultiSource/Benchmarks/mediabench/mpeg2/mpeg2dec
llvm-svn: 21679
2005-05-04 11:20:21 +08:00
|
|
|
// If the length is 0, we just need to store a null byte
|
2006-12-31 13:48:39 +08:00
|
|
|
new StoreInst(ConstantInt::get(Type::Int8Ty,0),ci->getOperand(1),ci);
|
|
|
|
ci->replaceAllUsesWith(ConstantInt::get(Type::Int32Ty,0));
|
* Correct the function prototypes for some of the functions to match the
actual spec (int -> uint)
* Add the ability to get/cache the strlen function prototype.
* Make sure generated values are appropriately named for debugging purposes
* Add the SPrintFOptimiation for 4 casts of sprintf optimization:
sprintf(str,cstr) -> llvm.memcpy(str,cstr) (if cstr has no %)
sprintf(str,"") -> store sbyte 0, str
sprintf(str,"%s",src) -> llvm.memcpy(str,src) (if src is constant)
sprintf(str,"%c",chr) -> store chr, str ; store sbyte 0, str+1
The sprintf optimization didn't fire as much as I had hoped:
2 MultiSource/Applications/SPASS
5 MultiSource/Benchmarks/McCat/18-imp
22 MultiSource/Benchmarks/Prolangs-C/TimberWolfMC
1 MultiSource/Benchmarks/Prolangs-C/assembler
6 MultiSource/Benchmarks/Prolangs-C/unix-smail
2 MultiSource/Benchmarks/mediabench/mpeg2/mpeg2dec
llvm-svn: 21679
2005-05-04 11:20:21 +08:00
|
|
|
ci->eraseFromParent();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make sure there's no % in the constant array
|
2006-01-23 06:35:08 +08:00
|
|
|
for (unsigned i = 0; i < len; ++i) {
|
|
|
|
if (ConstantInt* CI = dyn_cast<ConstantInt>(CA->getOperand(i))) {
|
* Correct the function prototypes for some of the functions to match the
actual spec (int -> uint)
* Add the ability to get/cache the strlen function prototype.
* Make sure generated values are appropriately named for debugging purposes
* Add the SPrintFOptimiation for 4 casts of sprintf optimization:
sprintf(str,cstr) -> llvm.memcpy(str,cstr) (if cstr has no %)
sprintf(str,"") -> store sbyte 0, str
sprintf(str,"%s",src) -> llvm.memcpy(str,src) (if src is constant)
sprintf(str,"%c",chr) -> store chr, str ; store sbyte 0, str+1
The sprintf optimization didn't fire as much as I had hoped:
2 MultiSource/Applications/SPASS
5 MultiSource/Benchmarks/McCat/18-imp
22 MultiSource/Benchmarks/Prolangs-C/TimberWolfMC
1 MultiSource/Benchmarks/Prolangs-C/assembler
6 MultiSource/Benchmarks/Prolangs-C/unix-smail
2 MultiSource/Benchmarks/mediabench/mpeg2/mpeg2dec
llvm-svn: 21679
2005-05-04 11:20:21 +08:00
|
|
|
// Check for the null terminator
|
2006-10-20 15:07:24 +08:00
|
|
|
if (CI->getZExtValue() == '%')
|
* Correct the function prototypes for some of the functions to match the
actual spec (int -> uint)
* Add the ability to get/cache the strlen function prototype.
* Make sure generated values are appropriately named for debugging purposes
* Add the SPrintFOptimiation for 4 casts of sprintf optimization:
sprintf(str,cstr) -> llvm.memcpy(str,cstr) (if cstr has no %)
sprintf(str,"") -> store sbyte 0, str
sprintf(str,"%s",src) -> llvm.memcpy(str,src) (if src is constant)
sprintf(str,"%c",chr) -> store chr, str ; store sbyte 0, str+1
The sprintf optimization didn't fire as much as I had hoped:
2 MultiSource/Applications/SPASS
5 MultiSource/Benchmarks/McCat/18-imp
22 MultiSource/Benchmarks/Prolangs-C/TimberWolfMC
1 MultiSource/Benchmarks/Prolangs-C/assembler
6 MultiSource/Benchmarks/Prolangs-C/unix-smail
2 MultiSource/Benchmarks/mediabench/mpeg2/mpeg2dec
llvm-svn: 21679
2005-05-04 11:20:21 +08:00
|
|
|
return false; // we found a %, can't optimize
|
2006-01-23 06:35:08 +08:00
|
|
|
} else {
|
* Correct the function prototypes for some of the functions to match the
actual spec (int -> uint)
* Add the ability to get/cache the strlen function prototype.
* Make sure generated values are appropriately named for debugging purposes
* Add the SPrintFOptimiation for 4 casts of sprintf optimization:
sprintf(str,cstr) -> llvm.memcpy(str,cstr) (if cstr has no %)
sprintf(str,"") -> store sbyte 0, str
sprintf(str,"%s",src) -> llvm.memcpy(str,src) (if src is constant)
sprintf(str,"%c",chr) -> store chr, str ; store sbyte 0, str+1
The sprintf optimization didn't fire as much as I had hoped:
2 MultiSource/Applications/SPASS
5 MultiSource/Benchmarks/McCat/18-imp
22 MultiSource/Benchmarks/Prolangs-C/TimberWolfMC
1 MultiSource/Benchmarks/Prolangs-C/assembler
6 MultiSource/Benchmarks/Prolangs-C/unix-smail
2 MultiSource/Benchmarks/mediabench/mpeg2/mpeg2dec
llvm-svn: 21679
2005-05-04 11:20:21 +08:00
|
|
|
return false; // initializer is not constant int, can't optimize
|
2006-01-23 06:35:08 +08:00
|
|
|
}
|
* Correct the function prototypes for some of the functions to match the
actual spec (int -> uint)
* Add the ability to get/cache the strlen function prototype.
* Make sure generated values are appropriately named for debugging purposes
* Add the SPrintFOptimiation for 4 casts of sprintf optimization:
sprintf(str,cstr) -> llvm.memcpy(str,cstr) (if cstr has no %)
sprintf(str,"") -> store sbyte 0, str
sprintf(str,"%s",src) -> llvm.memcpy(str,src) (if src is constant)
sprintf(str,"%c",chr) -> store chr, str ; store sbyte 0, str+1
The sprintf optimization didn't fire as much as I had hoped:
2 MultiSource/Applications/SPASS
5 MultiSource/Benchmarks/McCat/18-imp
22 MultiSource/Benchmarks/Prolangs-C/TimberWolfMC
1 MultiSource/Benchmarks/Prolangs-C/assembler
6 MultiSource/Benchmarks/Prolangs-C/unix-smail
2 MultiSource/Benchmarks/mediabench/mpeg2/mpeg2dec
llvm-svn: 21679
2005-05-04 11:20:21 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Increment length because we want to copy the null byte too
|
|
|
|
len++;
|
|
|
|
|
2005-07-27 14:12:32 +08:00
|
|
|
// sprintf(str,fmt) -> llvm.memcpy(str,fmt,strlen(fmt),1)
|
* Correct the function prototypes for some of the functions to match the
actual spec (int -> uint)
* Add the ability to get/cache the strlen function prototype.
* Make sure generated values are appropriately named for debugging purposes
* Add the SPrintFOptimiation for 4 casts of sprintf optimization:
sprintf(str,cstr) -> llvm.memcpy(str,cstr) (if cstr has no %)
sprintf(str,"") -> store sbyte 0, str
sprintf(str,"%s",src) -> llvm.memcpy(str,src) (if src is constant)
sprintf(str,"%c",chr) -> store chr, str ; store sbyte 0, str+1
The sprintf optimization didn't fire as much as I had hoped:
2 MultiSource/Applications/SPASS
5 MultiSource/Benchmarks/McCat/18-imp
22 MultiSource/Benchmarks/Prolangs-C/TimberWolfMC
1 MultiSource/Benchmarks/Prolangs-C/assembler
6 MultiSource/Benchmarks/Prolangs-C/unix-smail
2 MultiSource/Benchmarks/mediabench/mpeg2/mpeg2dec
llvm-svn: 21679
2005-05-04 11:20:21 +08:00
|
|
|
std::vector<Value*> args;
|
|
|
|
args.push_back(ci->getOperand(1));
|
|
|
|
args.push_back(ci->getOperand(2));
|
2006-10-20 15:07:24 +08:00
|
|
|
args.push_back(ConstantInt::get(SLC.getIntPtrType(),len));
|
2006-12-31 13:48:39 +08:00
|
|
|
args.push_back(ConstantInt::get(Type::Int32Ty,1));
|
2007-01-07 16:12:01 +08:00
|
|
|
new CallInst(SLC.get_memcpy(), args, "", ci);
|
2006-12-31 13:48:39 +08:00
|
|
|
ci->replaceAllUsesWith(ConstantInt::get(Type::Int32Ty,len));
|
* Correct the function prototypes for some of the functions to match the
actual spec (int -> uint)
* Add the ability to get/cache the strlen function prototype.
* Make sure generated values are appropriately named for debugging purposes
* Add the SPrintFOptimiation for 4 casts of sprintf optimization:
sprintf(str,cstr) -> llvm.memcpy(str,cstr) (if cstr has no %)
sprintf(str,"") -> store sbyte 0, str
sprintf(str,"%s",src) -> llvm.memcpy(str,src) (if src is constant)
sprintf(str,"%c",chr) -> store chr, str ; store sbyte 0, str+1
The sprintf optimization didn't fire as much as I had hoped:
2 MultiSource/Applications/SPASS
5 MultiSource/Benchmarks/McCat/18-imp
22 MultiSource/Benchmarks/Prolangs-C/TimberWolfMC
1 MultiSource/Benchmarks/Prolangs-C/assembler
6 MultiSource/Benchmarks/Prolangs-C/unix-smail
2 MultiSource/Benchmarks/mediabench/mpeg2/mpeg2dec
llvm-svn: 21679
2005-05-04 11:20:21 +08:00
|
|
|
ci->eraseFromParent();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The remaining optimizations require the format string to be length 2
|
|
|
|
// "%s" or "%c".
|
|
|
|
if (len != 2)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// The first character has to be a %
|
|
|
|
if (ConstantInt* CI = dyn_cast<ConstantInt>(CA->getOperand(0)))
|
2006-10-20 15:07:24 +08:00
|
|
|
if (CI->getZExtValue() != '%')
|
* Correct the function prototypes for some of the functions to match the
actual spec (int -> uint)
* Add the ability to get/cache the strlen function prototype.
* Make sure generated values are appropriately named for debugging purposes
* Add the SPrintFOptimiation for 4 casts of sprintf optimization:
sprintf(str,cstr) -> llvm.memcpy(str,cstr) (if cstr has no %)
sprintf(str,"") -> store sbyte 0, str
sprintf(str,"%s",src) -> llvm.memcpy(str,src) (if src is constant)
sprintf(str,"%c",chr) -> store chr, str ; store sbyte 0, str+1
The sprintf optimization didn't fire as much as I had hoped:
2 MultiSource/Applications/SPASS
5 MultiSource/Benchmarks/McCat/18-imp
22 MultiSource/Benchmarks/Prolangs-C/TimberWolfMC
1 MultiSource/Benchmarks/Prolangs-C/assembler
6 MultiSource/Benchmarks/Prolangs-C/unix-smail
2 MultiSource/Benchmarks/mediabench/mpeg2/mpeg2dec
llvm-svn: 21679
2005-05-04 11:20:21 +08:00
|
|
|
return false;
|
|
|
|
|
|
|
|
// Get the second character and switch on its value
|
|
|
|
ConstantInt* CI = dyn_cast<ConstantInt>(CA->getOperand(1));
|
2006-10-20 15:07:24 +08:00
|
|
|
switch (CI->getZExtValue()) {
|
2005-09-25 06:17:06 +08:00
|
|
|
case 's': {
|
|
|
|
// sprintf(dest,"%s",str) -> llvm.memcpy(dest, str, strlen(str)+1, 1)
|
2007-01-07 16:12:01 +08:00
|
|
|
Value *Len = new CallInst(SLC.get_strlen(),
|
|
|
|
CastToCStr(ci->getOperand(3), *ci),
|
2005-09-25 06:17:06 +08:00
|
|
|
ci->getOperand(3)->getName()+".len", ci);
|
|
|
|
Value *Len1 = BinaryOperator::createAdd(Len,
|
|
|
|
ConstantInt::get(Len->getType(), 1),
|
|
|
|
Len->getName()+"1", ci);
|
2006-02-16 05:13:37 +08:00
|
|
|
if (Len1->getType() != SLC.getIntPtrType())
|
2006-12-13 08:50:17 +08:00
|
|
|
Len1 = CastInst::createIntegerCast(Len1, SLC.getIntPtrType(), false,
|
|
|
|
Len1->getName(), ci);
|
2005-09-25 06:17:06 +08:00
|
|
|
std::vector<Value*> args;
|
|
|
|
args.push_back(CastToCStr(ci->getOperand(1), *ci));
|
|
|
|
args.push_back(CastToCStr(ci->getOperand(3), *ci));
|
|
|
|
args.push_back(Len1);
|
2006-12-31 13:48:39 +08:00
|
|
|
args.push_back(ConstantInt::get(Type::Int32Ty,1));
|
2007-01-07 16:12:01 +08:00
|
|
|
new CallInst(SLC.get_memcpy(), args, "", ci);
|
2005-09-25 06:17:06 +08:00
|
|
|
|
|
|
|
// The strlen result is the unincremented number of bytes in the string.
|
2005-09-25 15:06:48 +08:00
|
|
|
if (!ci->use_empty()) {
|
|
|
|
if (Len->getType() != ci->getType())
|
2006-12-13 08:50:17 +08:00
|
|
|
Len = CastInst::createIntegerCast(Len, ci->getType(), false,
|
|
|
|
Len->getName(), ci);
|
2005-09-25 15:06:48 +08:00
|
|
|
ci->replaceAllUsesWith(Len);
|
|
|
|
}
|
2005-09-25 06:17:06 +08:00
|
|
|
ci->eraseFromParent();
|
|
|
|
return true;
|
* Correct the function prototypes for some of the functions to match the
actual spec (int -> uint)
* Add the ability to get/cache the strlen function prototype.
* Make sure generated values are appropriately named for debugging purposes
* Add the SPrintFOptimiation for 4 casts of sprintf optimization:
sprintf(str,cstr) -> llvm.memcpy(str,cstr) (if cstr has no %)
sprintf(str,"") -> store sbyte 0, str
sprintf(str,"%s",src) -> llvm.memcpy(str,src) (if src is constant)
sprintf(str,"%c",chr) -> store chr, str ; store sbyte 0, str+1
The sprintf optimization didn't fire as much as I had hoped:
2 MultiSource/Applications/SPASS
5 MultiSource/Benchmarks/McCat/18-imp
22 MultiSource/Benchmarks/Prolangs-C/TimberWolfMC
1 MultiSource/Benchmarks/Prolangs-C/assembler
6 MultiSource/Benchmarks/Prolangs-C/unix-smail
2 MultiSource/Benchmarks/mediabench/mpeg2/mpeg2dec
llvm-svn: 21679
2005-05-04 11:20:21 +08:00
|
|
|
}
|
2005-09-25 06:17:06 +08:00
|
|
|
case 'c': {
|
|
|
|
// sprintf(dest,"%c",chr) -> store chr, dest
|
2006-12-13 08:50:17 +08:00
|
|
|
CastInst* cast = CastInst::createTruncOrBitCast(
|
2006-12-31 13:48:39 +08:00
|
|
|
ci->getOperand(3), Type::Int8Ty, "char", ci);
|
2005-09-25 06:17:06 +08:00
|
|
|
new StoreInst(cast, ci->getOperand(1), ci);
|
|
|
|
GetElementPtrInst* gep = new GetElementPtrInst(ci->getOperand(1),
|
2006-12-31 13:48:39 +08:00
|
|
|
ConstantInt::get(Type::Int32Ty,1),ci->getOperand(1)->getName()+".end",
|
2005-09-25 06:17:06 +08:00
|
|
|
ci);
|
2006-12-31 13:48:39 +08:00
|
|
|
new StoreInst(ConstantInt::get(Type::Int8Ty,0),gep,ci);
|
|
|
|
ci->replaceAllUsesWith(ConstantInt::get(Type::Int32Ty,1));
|
2005-09-25 06:17:06 +08:00
|
|
|
ci->eraseFromParent();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
* Correct the function prototypes for some of the functions to match the
actual spec (int -> uint)
* Add the ability to get/cache the strlen function prototype.
* Make sure generated values are appropriately named for debugging purposes
* Add the SPrintFOptimiation for 4 casts of sprintf optimization:
sprintf(str,cstr) -> llvm.memcpy(str,cstr) (if cstr has no %)
sprintf(str,"") -> store sbyte 0, str
sprintf(str,"%s",src) -> llvm.memcpy(str,src) (if src is constant)
sprintf(str,"%c",chr) -> store chr, str ; store sbyte 0, str+1
The sprintf optimization didn't fire as much as I had hoped:
2 MultiSource/Applications/SPASS
5 MultiSource/Benchmarks/McCat/18-imp
22 MultiSource/Benchmarks/Prolangs-C/TimberWolfMC
1 MultiSource/Benchmarks/Prolangs-C/assembler
6 MultiSource/Benchmarks/Prolangs-C/unix-smail
2 MultiSource/Benchmarks/mediabench/mpeg2/mpeg2dec
llvm-svn: 21679
2005-05-04 11:20:21 +08:00
|
|
|
}
|
|
|
|
} SPrintFOptimizer;
|
|
|
|
|
2005-07-27 14:12:32 +08:00
|
|
|
/// This LibCallOptimization will simplify calls to the "fputs" library
|
2005-04-29 17:39:47 +08:00
|
|
|
/// function. It looks for cases where the result of fputs is not used and the
|
|
|
|
/// operation can be reduced to something simpler.
|
2006-06-16 16:36:35 +08:00
|
|
|
/// @brief Simplify the puts library function.
|
2006-01-23 06:35:08 +08:00
|
|
|
struct PutsOptimization : public LibCallOptimization {
|
2005-04-29 17:39:47 +08:00
|
|
|
public:
|
|
|
|
/// @brief Default Constructor
|
2005-05-03 10:54:54 +08:00
|
|
|
PutsOptimization() : LibCallOptimization("fputs",
|
2005-05-08 04:15:59 +08:00
|
|
|
"Number of 'fputs' calls simplified") {}
|
2005-04-29 17:39:47 +08:00
|
|
|
|
|
|
|
/// @brief Make sure that the "fputs" function has the right prototype
|
2006-01-23 06:35:08 +08:00
|
|
|
virtual bool ValidateCalledFunction(const Function *F, SimplifyLibCalls &SLC){
|
2005-04-29 17:39:47 +08:00
|
|
|
// Just make sure this has 2 arguments
|
2006-01-23 06:35:08 +08:00
|
|
|
return F->arg_size() == 2;
|
2005-04-29 17:39:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// @brief Perform the fputs optimization.
|
2006-01-23 06:35:08 +08:00
|
|
|
virtual bool OptimizeCall(CallInst* ci, SimplifyLibCalls& SLC) {
|
2005-04-29 17:39:47 +08:00
|
|
|
// If the result is used, none of these optimizations work
|
2005-09-25 06:17:06 +08:00
|
|
|
if (!ci->use_empty())
|
2005-04-29 17:39:47 +08:00
|
|
|
return false;
|
|
|
|
|
|
|
|
// All the optimizations depend on the length of the first argument and the
|
|
|
|
// fact that it is a constant string array. Check that now
|
2005-07-27 14:12:32 +08:00
|
|
|
uint64_t len = 0;
|
2005-04-29 17:39:47 +08:00
|
|
|
if (!getConstantStringLength(ci->getOperand(1), len))
|
|
|
|
return false;
|
|
|
|
|
2006-01-23 06:35:08 +08:00
|
|
|
switch (len) {
|
2005-04-29 17:39:47 +08:00
|
|
|
case 0:
|
|
|
|
// fputs("",F) -> noop
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
{
|
|
|
|
// fputs(s,F) -> fputc(s[0],F) (if s is constant and strlen(s) == 1)
|
* Don't depend on "guessing" what a FILE* is, just require that the actual
type be obtained from a CallInst we're optimizing.
* Make it possible for getConstantStringLength to return the ConstantArray
that it extracts in case the content is needed by an Optimization.
* Implement the strcmp optimization
* Implement the toascii optimization
This pass is now firing several to many times in the following MultiSource
tests:
Applications/Burg - 7 (strcat,strcpy)
Applications/siod - 13 (strcat,strcpy,strlen)
Applications/spiff - 120 (exit,fputs,strcat,strcpy,strlen)
Applications/treecc - 66 (exit,fputs,strcat,strcpy)
Applications/kimwitu++ - 34 (strcmp,strcpy,strlen)
Applications/SPASS - 588 (exit,fputs,strcat,strcpy,strlen)
llvm-svn: 21626
2005-04-30 11:17:54 +08:00
|
|
|
const Type* FILEptr_type = ci->getOperand(2)->getType();
|
2005-04-29 17:39:47 +08:00
|
|
|
LoadInst* loadi = new LoadInst(ci->getOperand(1),
|
|
|
|
ci->getOperand(1)->getName()+".byte",ci);
|
2006-12-31 13:48:39 +08:00
|
|
|
CastInst* casti = new SExtInst(loadi, Type::Int32Ty,
|
2006-12-13 08:50:17 +08:00
|
|
|
loadi->getName()+".int", ci);
|
2007-01-07 16:12:01 +08:00
|
|
|
new CallInst(SLC.get_fputc(FILEptr_type), casti,
|
|
|
|
ci->getOperand(2), "", ci);
|
2005-04-29 17:39:47 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
2005-07-27 14:12:32 +08:00
|
|
|
{
|
2005-04-29 17:39:47 +08:00
|
|
|
// fputs(s,F) -> fwrite(s,1,len,F) (if s is constant and strlen(s) > 1)
|
* Don't depend on "guessing" what a FILE* is, just require that the actual
type be obtained from a CallInst we're optimizing.
* Make it possible for getConstantStringLength to return the ConstantArray
that it extracts in case the content is needed by an Optimization.
* Implement the strcmp optimization
* Implement the toascii optimization
This pass is now firing several to many times in the following MultiSource
tests:
Applications/Burg - 7 (strcat,strcpy)
Applications/siod - 13 (strcat,strcpy,strlen)
Applications/spiff - 120 (exit,fputs,strcat,strcpy,strlen)
Applications/treecc - 66 (exit,fputs,strcat,strcpy)
Applications/kimwitu++ - 34 (strcmp,strcpy,strlen)
Applications/SPASS - 588 (exit,fputs,strcat,strcpy,strlen)
llvm-svn: 21626
2005-04-30 11:17:54 +08:00
|
|
|
const Type* FILEptr_type = ci->getOperand(2)->getType();
|
2005-04-29 17:39:47 +08:00
|
|
|
std::vector<Value*> parms;
|
|
|
|
parms.push_back(ci->getOperand(1));
|
2006-10-20 15:07:24 +08:00
|
|
|
parms.push_back(ConstantInt::get(SLC.getIntPtrType(),len));
|
|
|
|
parms.push_back(ConstantInt::get(SLC.getIntPtrType(),1));
|
2005-04-29 17:39:47 +08:00
|
|
|
parms.push_back(ci->getOperand(2));
|
2007-01-07 16:12:01 +08:00
|
|
|
new CallInst(SLC.get_fwrite(FILEptr_type), parms, "", ci);
|
2005-04-29 17:39:47 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ci->eraseFromParent();
|
|
|
|
return true; // success
|
|
|
|
}
|
|
|
|
} PutsOptimizer;
|
|
|
|
|
2005-07-27 14:12:32 +08:00
|
|
|
/// This LibCallOptimization will simplify calls to the "isdigit" library
|
2005-05-05 02:58:28 +08:00
|
|
|
/// function. It simply does range checks the parameter explicitly.
|
|
|
|
/// @brief Simplify the isdigit library function.
|
2005-09-29 14:16:11 +08:00
|
|
|
struct isdigitOptimization : public LibCallOptimization {
|
2005-05-05 02:58:28 +08:00
|
|
|
public:
|
2005-09-29 14:16:11 +08:00
|
|
|
isdigitOptimization() : LibCallOptimization("isdigit",
|
2005-05-08 04:15:59 +08:00
|
|
|
"Number of 'isdigit' calls simplified") {}
|
2005-05-05 02:58:28 +08:00
|
|
|
|
2005-09-29 14:16:11 +08:00
|
|
|
/// @brief Make sure that the "isdigit" function has the right prototype
|
2006-01-23 06:35:08 +08:00
|
|
|
virtual bool ValidateCalledFunction(const Function* f, SimplifyLibCalls& SLC){
|
2005-05-05 02:58:28 +08:00
|
|
|
// Just make sure this has 1 argument
|
|
|
|
return (f->arg_size() == 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// @brief Perform the toascii optimization.
|
2006-01-23 06:35:08 +08:00
|
|
|
virtual bool OptimizeCall(CallInst *ci, SimplifyLibCalls &SLC) {
|
|
|
|
if (ConstantInt* CI = dyn_cast<ConstantInt>(ci->getOperand(1))) {
|
2005-05-05 02:58:28 +08:00
|
|
|
// isdigit(c) -> 0 or 1, if 'c' is constant
|
2006-10-20 15:07:24 +08:00
|
|
|
uint64_t val = CI->getZExtValue();
|
2005-05-05 02:58:28 +08:00
|
|
|
if (val >= '0' && val <='9')
|
2006-12-31 13:48:39 +08:00
|
|
|
ci->replaceAllUsesWith(ConstantInt::get(Type::Int32Ty,1));
|
2005-05-05 02:58:28 +08:00
|
|
|
else
|
2006-12-31 13:48:39 +08:00
|
|
|
ci->replaceAllUsesWith(ConstantInt::get(Type::Int32Ty,0));
|
2005-05-05 02:58:28 +08:00
|
|
|
ci->eraseFromParent();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// isdigit(c) -> (unsigned)c - '0' <= 9
|
2006-12-13 08:50:17 +08:00
|
|
|
CastInst* cast = CastInst::createIntegerCast(ci->getOperand(1),
|
2006-12-31 13:48:39 +08:00
|
|
|
Type::Int32Ty, false/*ZExt*/, ci->getOperand(1)->getName()+".uint", ci);
|
2005-08-25 01:22:17 +08:00
|
|
|
BinaryOperator* sub_inst = BinaryOperator::createSub(cast,
|
2006-12-31 13:48:39 +08:00
|
|
|
ConstantInt::get(Type::Int32Ty,0x30),
|
2005-05-05 02:58:28 +08:00
|
|
|
ci->getOperand(1)->getName()+".sub",ci);
|
2006-12-23 14:05:41 +08:00
|
|
|
ICmpInst* setcond_inst = new ICmpInst(ICmpInst::ICMP_ULE,sub_inst,
|
2006-12-31 13:48:39 +08:00
|
|
|
ConstantInt::get(Type::Int32Ty,9),
|
2005-05-05 02:58:28 +08:00
|
|
|
ci->getOperand(1)->getName()+".cmp",ci);
|
2006-12-31 13:48:39 +08:00
|
|
|
CastInst* c2 = new ZExtInst(setcond_inst, Type::Int32Ty,
|
2006-12-13 08:50:17 +08:00
|
|
|
ci->getOperand(1)->getName()+".isdigit", ci);
|
2005-05-05 02:58:28 +08:00
|
|
|
ci->replaceAllUsesWith(c2);
|
|
|
|
ci->eraseFromParent();
|
|
|
|
return true;
|
|
|
|
}
|
2005-09-29 14:16:11 +08:00
|
|
|
} isdigitOptimizer;
|
|
|
|
|
2005-09-29 14:17:27 +08:00
|
|
|
struct isasciiOptimization : public LibCallOptimization {
|
|
|
|
public:
|
|
|
|
isasciiOptimization()
|
|
|
|
: LibCallOptimization("isascii", "Number of 'isascii' calls simplified") {}
|
|
|
|
|
|
|
|
virtual bool ValidateCalledFunction(const Function *F, SimplifyLibCalls &SLC){
|
2007-01-15 09:55:30 +08:00
|
|
|
return F->arg_size() == 1 && F->arg_begin()->getType()->isIntegral() &&
|
|
|
|
F->getReturnType()->isIntegral();
|
2005-09-29 14:17:27 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// @brief Perform the isascii optimization.
|
|
|
|
virtual bool OptimizeCall(CallInst *CI, SimplifyLibCalls &SLC) {
|
|
|
|
// isascii(c) -> (unsigned)c < 128
|
|
|
|
Value *V = CI->getOperand(1);
|
2006-12-23 14:05:41 +08:00
|
|
|
Value *Cmp = new ICmpInst(ICmpInst::ICMP_ULT, V,
|
|
|
|
ConstantInt::get(V->getType(), 128),
|
|
|
|
V->getName()+".isascii", CI);
|
2005-09-29 14:17:27 +08:00
|
|
|
if (Cmp->getType() != CI->getType())
|
2006-12-13 08:50:17 +08:00
|
|
|
Cmp = new BitCastInst(Cmp, CI->getType(), Cmp->getName(), CI);
|
2005-09-29 14:17:27 +08:00
|
|
|
CI->replaceAllUsesWith(Cmp);
|
|
|
|
CI->eraseFromParent();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
} isasciiOptimizer;
|
2005-09-29 14:16:11 +08:00
|
|
|
|
2005-05-05 02:58:28 +08:00
|
|
|
|
2005-07-27 14:12:32 +08:00
|
|
|
/// This LibCallOptimization will simplify calls to the "toascii" library
|
* Don't depend on "guessing" what a FILE* is, just require that the actual
type be obtained from a CallInst we're optimizing.
* Make it possible for getConstantStringLength to return the ConstantArray
that it extracts in case the content is needed by an Optimization.
* Implement the strcmp optimization
* Implement the toascii optimization
This pass is now firing several to many times in the following MultiSource
tests:
Applications/Burg - 7 (strcat,strcpy)
Applications/siod - 13 (strcat,strcpy,strlen)
Applications/spiff - 120 (exit,fputs,strcat,strcpy,strlen)
Applications/treecc - 66 (exit,fputs,strcat,strcpy)
Applications/kimwitu++ - 34 (strcmp,strcpy,strlen)
Applications/SPASS - 588 (exit,fputs,strcat,strcpy,strlen)
llvm-svn: 21626
2005-04-30 11:17:54 +08:00
|
|
|
/// function. It simply does the corresponding and operation to restrict the
|
|
|
|
/// range of values to the ASCII character set (0-127).
|
|
|
|
/// @brief Simplify the toascii library function.
|
2006-01-23 06:35:08 +08:00
|
|
|
struct ToAsciiOptimization : public LibCallOptimization {
|
* Don't depend on "guessing" what a FILE* is, just require that the actual
type be obtained from a CallInst we're optimizing.
* Make it possible for getConstantStringLength to return the ConstantArray
that it extracts in case the content is needed by an Optimization.
* Implement the strcmp optimization
* Implement the toascii optimization
This pass is now firing several to many times in the following MultiSource
tests:
Applications/Burg - 7 (strcat,strcpy)
Applications/siod - 13 (strcat,strcpy,strlen)
Applications/spiff - 120 (exit,fputs,strcat,strcpy,strlen)
Applications/treecc - 66 (exit,fputs,strcat,strcpy)
Applications/kimwitu++ - 34 (strcmp,strcpy,strlen)
Applications/SPASS - 588 (exit,fputs,strcat,strcpy,strlen)
llvm-svn: 21626
2005-04-30 11:17:54 +08:00
|
|
|
public:
|
|
|
|
/// @brief Default Constructor
|
2005-05-03 10:54:54 +08:00
|
|
|
ToAsciiOptimization() : LibCallOptimization("toascii",
|
2005-05-08 04:15:59 +08:00
|
|
|
"Number of 'toascii' calls simplified") {}
|
* Don't depend on "guessing" what a FILE* is, just require that the actual
type be obtained from a CallInst we're optimizing.
* Make it possible for getConstantStringLength to return the ConstantArray
that it extracts in case the content is needed by an Optimization.
* Implement the strcmp optimization
* Implement the toascii optimization
This pass is now firing several to many times in the following MultiSource
tests:
Applications/Burg - 7 (strcat,strcpy)
Applications/siod - 13 (strcat,strcpy,strlen)
Applications/spiff - 120 (exit,fputs,strcat,strcpy,strlen)
Applications/treecc - 66 (exit,fputs,strcat,strcpy)
Applications/kimwitu++ - 34 (strcmp,strcpy,strlen)
Applications/SPASS - 588 (exit,fputs,strcat,strcpy,strlen)
llvm-svn: 21626
2005-04-30 11:17:54 +08:00
|
|
|
|
|
|
|
/// @brief Make sure that the "fputs" function has the right prototype
|
2006-01-23 06:35:08 +08:00
|
|
|
virtual bool ValidateCalledFunction(const Function* f, SimplifyLibCalls& SLC){
|
* Don't depend on "guessing" what a FILE* is, just require that the actual
type be obtained from a CallInst we're optimizing.
* Make it possible for getConstantStringLength to return the ConstantArray
that it extracts in case the content is needed by an Optimization.
* Implement the strcmp optimization
* Implement the toascii optimization
This pass is now firing several to many times in the following MultiSource
tests:
Applications/Burg - 7 (strcat,strcpy)
Applications/siod - 13 (strcat,strcpy,strlen)
Applications/spiff - 120 (exit,fputs,strcat,strcpy,strlen)
Applications/treecc - 66 (exit,fputs,strcat,strcpy)
Applications/kimwitu++ - 34 (strcmp,strcpy,strlen)
Applications/SPASS - 588 (exit,fputs,strcat,strcpy,strlen)
llvm-svn: 21626
2005-04-30 11:17:54 +08:00
|
|
|
// Just make sure this has 2 arguments
|
|
|
|
return (f->arg_size() == 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// @brief Perform the toascii optimization.
|
2006-01-23 06:35:08 +08:00
|
|
|
virtual bool OptimizeCall(CallInst *ci, SimplifyLibCalls &SLC) {
|
* Don't depend on "guessing" what a FILE* is, just require that the actual
type be obtained from a CallInst we're optimizing.
* Make it possible for getConstantStringLength to return the ConstantArray
that it extracts in case the content is needed by an Optimization.
* Implement the strcmp optimization
* Implement the toascii optimization
This pass is now firing several to many times in the following MultiSource
tests:
Applications/Burg - 7 (strcat,strcpy)
Applications/siod - 13 (strcat,strcpy,strlen)
Applications/spiff - 120 (exit,fputs,strcat,strcpy,strlen)
Applications/treecc - 66 (exit,fputs,strcat,strcpy)
Applications/kimwitu++ - 34 (strcmp,strcpy,strlen)
Applications/SPASS - 588 (exit,fputs,strcat,strcpy,strlen)
llvm-svn: 21626
2005-04-30 11:17:54 +08:00
|
|
|
// toascii(c) -> (c & 0x7f)
|
|
|
|
Value* chr = ci->getOperand(1);
|
2005-08-25 01:22:17 +08:00
|
|
|
BinaryOperator* and_inst = BinaryOperator::createAnd(chr,
|
* Don't depend on "guessing" what a FILE* is, just require that the actual
type be obtained from a CallInst we're optimizing.
* Make it possible for getConstantStringLength to return the ConstantArray
that it extracts in case the content is needed by an Optimization.
* Implement the strcmp optimization
* Implement the toascii optimization
This pass is now firing several to many times in the following MultiSource
tests:
Applications/Burg - 7 (strcat,strcpy)
Applications/siod - 13 (strcat,strcpy,strlen)
Applications/spiff - 120 (exit,fputs,strcat,strcpy,strlen)
Applications/treecc - 66 (exit,fputs,strcat,strcpy)
Applications/kimwitu++ - 34 (strcmp,strcpy,strlen)
Applications/SPASS - 588 (exit,fputs,strcat,strcpy,strlen)
llvm-svn: 21626
2005-04-30 11:17:54 +08:00
|
|
|
ConstantInt::get(chr->getType(),0x7F),ci->getName()+".toascii",ci);
|
|
|
|
ci->replaceAllUsesWith(and_inst);
|
|
|
|
ci->eraseFromParent();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
} ToAsciiOptimizer;
|
|
|
|
|
2005-05-15 00:42:52 +08:00
|
|
|
/// This LibCallOptimization will simplify calls to the "ffs" library
|
2005-07-27 14:12:32 +08:00
|
|
|
/// calls which find the first set bit in an int, long, or long long. The
|
2005-05-15 00:42:52 +08:00
|
|
|
/// optimization is to compute the result at compile time if the argument is
|
|
|
|
/// a constant.
|
|
|
|
/// @brief Simplify the ffs library function.
|
2006-01-18 02:27:17 +08:00
|
|
|
struct FFSOptimization : public LibCallOptimization {
|
2005-05-15 00:42:52 +08:00
|
|
|
protected:
|
|
|
|
/// @brief Subclass Constructor
|
|
|
|
FFSOptimization(const char* funcName, const char* description)
|
2006-01-18 02:27:17 +08:00
|
|
|
: LibCallOptimization(funcName, description) {}
|
2005-05-15 00:42:52 +08:00
|
|
|
|
|
|
|
public:
|
|
|
|
/// @brief Default Constructor
|
|
|
|
FFSOptimization() : LibCallOptimization("ffs",
|
|
|
|
"Number of 'ffs' calls simplified") {}
|
|
|
|
|
2006-01-18 02:27:17 +08:00
|
|
|
/// @brief Make sure that the "ffs" function has the right prototype
|
|
|
|
virtual bool ValidateCalledFunction(const Function *F, SimplifyLibCalls &SLC){
|
2005-05-15 00:42:52 +08:00
|
|
|
// Just make sure this has 2 arguments
|
2006-12-31 13:48:39 +08:00
|
|
|
return F->arg_size() == 1 && F->getReturnType() == Type::Int32Ty;
|
2005-05-15 00:42:52 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// @brief Perform the ffs optimization.
|
2006-01-18 02:27:17 +08:00
|
|
|
virtual bool OptimizeCall(CallInst *TheCall, SimplifyLibCalls &SLC) {
|
|
|
|
if (ConstantInt *CI = dyn_cast<ConstantInt>(TheCall->getOperand(1))) {
|
2005-05-15 00:42:52 +08:00
|
|
|
// ffs(cnst) -> bit#
|
|
|
|
// ffsl(cnst) -> bit#
|
2005-05-16 05:19:45 +08:00
|
|
|
// ffsll(cnst) -> bit#
|
2006-10-20 15:07:24 +08:00
|
|
|
uint64_t val = CI->getZExtValue();
|
2005-05-16 05:19:45 +08:00
|
|
|
int result = 0;
|
2006-01-18 02:27:17 +08:00
|
|
|
if (val) {
|
|
|
|
++result;
|
|
|
|
while ((val & 1) == 0) {
|
|
|
|
++result;
|
|
|
|
val >>= 1;
|
|
|
|
}
|
2005-05-16 05:19:45 +08:00
|
|
|
}
|
2006-12-31 13:48:39 +08:00
|
|
|
TheCall->replaceAllUsesWith(ConstantInt::get(Type::Int32Ty, result));
|
2006-01-18 02:27:17 +08:00
|
|
|
TheCall->eraseFromParent();
|
2005-05-15 00:42:52 +08:00
|
|
|
return true;
|
|
|
|
}
|
2005-05-16 05:19:45 +08:00
|
|
|
|
2006-01-18 02:27:17 +08:00
|
|
|
// 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 *ArgType = TheCall->getOperand(1)->getType();
|
|
|
|
const char *CTTZName;
|
For PR1064:
Implement the arbitrary bit-width integer feature. The feature allows
integers of any bitwidth (up to 64) to be defined instead of just 1, 8,
16, 32, and 64 bit integers.
This change does several things:
1. Introduces a new Derived Type, IntegerType, to represent the number of
bits in an integer. The Type classes SubclassData field is used to
store the number of bits. This allows 2^23 bits in an integer type.
2. Removes the five integer Type::TypeID values for the 1, 8, 16, 32 and
64-bit integers. These are replaced with just IntegerType which is not
a primitive any more.
3. Adjust the rest of LLVM to account for this change.
Note that while this incremental change lays the foundation for arbitrary
bit-width integers, LLVM has not yet been converted to actually deal with
them in any significant way. Most optimization passes, for example, will
still only deal with the byte-width integer types. Future increments
will rectify this situation.
llvm-svn: 33113
2007-01-12 15:05:14 +08:00
|
|
|
assert(ArgType->getTypeID() == Type::IntegerTyID &&
|
|
|
|
"llvm.cttz argument is not an integer?");
|
|
|
|
unsigned BitWidth = cast<IntegerType>(ArgType)->getBitWidth();
|
2007-01-13 06:49:11 +08:00
|
|
|
if (BitWidth == 8)
|
For PR1064:
Implement the arbitrary bit-width integer feature. The feature allows
integers of any bitwidth (up to 64) to be defined instead of just 1, 8,
16, 32, and 64 bit integers.
This change does several things:
1. Introduces a new Derived Type, IntegerType, to represent the number of
bits in an integer. The Type classes SubclassData field is used to
store the number of bits. This allows 2^23 bits in an integer type.
2. Removes the five integer Type::TypeID values for the 1, 8, 16, 32 and
64-bit integers. These are replaced with just IntegerType which is not
a primitive any more.
3. Adjust the rest of LLVM to account for this change.
Note that while this incremental change lays the foundation for arbitrary
bit-width integers, LLVM has not yet been converted to actually deal with
them in any significant way. Most optimization passes, for example, will
still only deal with the byte-width integer types. Future increments
will rectify this situation.
llvm-svn: 33113
2007-01-12 15:05:14 +08:00
|
|
|
CTTZName = "llvm.cttz.i8";
|
2007-01-13 06:49:11 +08:00
|
|
|
else if (BitWidth == 16)
|
For PR1064:
Implement the arbitrary bit-width integer feature. The feature allows
integers of any bitwidth (up to 64) to be defined instead of just 1, 8,
16, 32, and 64 bit integers.
This change does several things:
1. Introduces a new Derived Type, IntegerType, to represent the number of
bits in an integer. The Type classes SubclassData field is used to
store the number of bits. This allows 2^23 bits in an integer type.
2. Removes the five integer Type::TypeID values for the 1, 8, 16, 32 and
64-bit integers. These are replaced with just IntegerType which is not
a primitive any more.
3. Adjust the rest of LLVM to account for this change.
Note that while this incremental change lays the foundation for arbitrary
bit-width integers, LLVM has not yet been converted to actually deal with
them in any significant way. Most optimization passes, for example, will
still only deal with the byte-width integer types. Future increments
will rectify this situation.
llvm-svn: 33113
2007-01-12 15:05:14 +08:00
|
|
|
CTTZName = "llvm.cttz.i16";
|
2007-01-13 06:49:11 +08:00
|
|
|
else if (BitWidth == 32)
|
For PR1064:
Implement the arbitrary bit-width integer feature. The feature allows
integers of any bitwidth (up to 64) to be defined instead of just 1, 8,
16, 32, and 64 bit integers.
This change does several things:
1. Introduces a new Derived Type, IntegerType, to represent the number of
bits in an integer. The Type classes SubclassData field is used to
store the number of bits. This allows 2^23 bits in an integer type.
2. Removes the five integer Type::TypeID values for the 1, 8, 16, 32 and
64-bit integers. These are replaced with just IntegerType which is not
a primitive any more.
3. Adjust the rest of LLVM to account for this change.
Note that while this incremental change lays the foundation for arbitrary
bit-width integers, LLVM has not yet been converted to actually deal with
them in any significant way. Most optimization passes, for example, will
still only deal with the byte-width integer types. Future increments
will rectify this situation.
llvm-svn: 33113
2007-01-12 15:05:14 +08:00
|
|
|
CTTZName = "llvm.cttz.i32";
|
2007-01-13 06:49:11 +08:00
|
|
|
else {
|
|
|
|
assert(BitWidth == 64 && "Unknown bitwidth");
|
For PR1064:
Implement the arbitrary bit-width integer feature. The feature allows
integers of any bitwidth (up to 64) to be defined instead of just 1, 8,
16, 32, and 64 bit integers.
This change does several things:
1. Introduces a new Derived Type, IntegerType, to represent the number of
bits in an integer. The Type classes SubclassData field is used to
store the number of bits. This allows 2^23 bits in an integer type.
2. Removes the five integer Type::TypeID values for the 1, 8, 16, 32 and
64-bit integers. These are replaced with just IntegerType which is not
a primitive any more.
3. Adjust the rest of LLVM to account for this change.
Note that while this incremental change lays the foundation for arbitrary
bit-width integers, LLVM has not yet been converted to actually deal with
them in any significant way. Most optimization passes, for example, will
still only deal with the byte-width integer types. Future increments
will rectify this situation.
llvm-svn: 33113
2007-01-12 15:05:14 +08:00
|
|
|
CTTZName = "llvm.cttz.i64";
|
2007-01-13 06:49:11 +08:00
|
|
|
}
|
2006-01-18 02:27:17 +08:00
|
|
|
|
2007-01-07 16:12:01 +08:00
|
|
|
Constant *F = SLC.getModule()->getOrInsertFunction(CTTZName, ArgType,
|
2006-01-18 02:27:17 +08:00
|
|
|
ArgType, NULL);
|
2006-12-13 08:50:17 +08:00
|
|
|
Value *V = CastInst::createIntegerCast(TheCall->getOperand(1), ArgType,
|
|
|
|
false/*ZExt*/, "tmp", TheCall);
|
2006-01-18 02:27:17 +08:00
|
|
|
Value *V2 = new CallInst(F, V, "tmp", TheCall);
|
2006-12-31 13:48:39 +08:00
|
|
|
V2 = CastInst::createIntegerCast(V2, Type::Int32Ty, false/*ZExt*/,
|
2006-12-13 08:50:17 +08:00
|
|
|
"tmp", TheCall);
|
2006-12-31 13:48:39 +08:00
|
|
|
V2 = BinaryOperator::createAdd(V2, ConstantInt::get(Type::Int32Ty, 1),
|
2006-01-18 02:27:17 +08:00
|
|
|
"tmp", TheCall);
|
2006-12-23 14:05:41 +08:00
|
|
|
Value *Cond = new ICmpInst(ICmpInst::ICMP_EQ, V,
|
|
|
|
Constant::getNullValue(V->getType()), "tmp",
|
|
|
|
TheCall);
|
2006-12-31 13:48:39 +08:00
|
|
|
V2 = new SelectInst(Cond, ConstantInt::get(Type::Int32Ty, 0), V2,
|
2006-01-18 02:27:17 +08:00
|
|
|
TheCall->getName(), TheCall);
|
|
|
|
TheCall->replaceAllUsesWith(V2);
|
|
|
|
TheCall->eraseFromParent();
|
2005-05-16 05:19:45 +08:00
|
|
|
return true;
|
2005-05-15 00:42:52 +08:00
|
|
|
}
|
|
|
|
} FFSOptimizer;
|
|
|
|
|
|
|
|
/// This LibCallOptimization will simplify calls to the "ffsl" library
|
|
|
|
/// calls. It simply uses FFSOptimization for which the transformation is
|
|
|
|
/// identical.
|
|
|
|
/// @brief Simplify the ffsl library function.
|
2006-01-23 06:35:08 +08:00
|
|
|
struct FFSLOptimization : public FFSOptimization {
|
2005-05-15 00:42:52 +08:00
|
|
|
public:
|
|
|
|
/// @brief Default Constructor
|
|
|
|
FFSLOptimization() : FFSOptimization("ffsl",
|
|
|
|
"Number of 'ffsl' calls simplified") {}
|
|
|
|
|
|
|
|
} FFSLOptimizer;
|
|
|
|
|
|
|
|
/// This LibCallOptimization will simplify calls to the "ffsll" library
|
|
|
|
/// calls. It simply uses FFSOptimization for which the transformation is
|
|
|
|
/// identical.
|
|
|
|
/// @brief Simplify the ffsl library function.
|
2006-01-23 06:35:08 +08:00
|
|
|
struct FFSLLOptimization : public FFSOptimization {
|
2005-05-15 00:42:52 +08:00
|
|
|
public:
|
|
|
|
/// @brief Default Constructor
|
|
|
|
FFSLLOptimization() : FFSOptimization("ffsll",
|
|
|
|
"Number of 'ffsll' calls simplified") {}
|
|
|
|
|
|
|
|
} FFSLLOptimizer;
|
|
|
|
|
2006-01-23 13:57:36 +08:00
|
|
|
/// This optimizes unary functions that take and return doubles.
|
|
|
|
struct UnaryDoubleFPOptimizer : public LibCallOptimization {
|
|
|
|
UnaryDoubleFPOptimizer(const char *Fn, const char *Desc)
|
|
|
|
: LibCallOptimization(Fn, Desc) {}
|
2005-08-25 01:22:17 +08:00
|
|
|
|
2006-01-23 13:57:36 +08:00
|
|
|
// Make sure that this function has the right prototype
|
2005-08-25 01:22:17 +08:00
|
|
|
virtual bool ValidateCalledFunction(const Function *F, SimplifyLibCalls &SLC){
|
|
|
|
return F->arg_size() == 1 && F->arg_begin()->getType() == Type::DoubleTy &&
|
|
|
|
F->getReturnType() == Type::DoubleTy;
|
|
|
|
}
|
2006-01-23 13:57:36 +08:00
|
|
|
|
|
|
|
/// ShrinkFunctionToFloatVersion - If the input to this function is really a
|
|
|
|
/// float, strength reduce this to a float version of the function,
|
|
|
|
/// e.g. floor((double)FLT) -> (double)floorf(FLT). This can only be called
|
|
|
|
/// when the target supports the destination function and where there can be
|
|
|
|
/// no precision loss.
|
|
|
|
static bool ShrinkFunctionToFloatVersion(CallInst *CI, SimplifyLibCalls &SLC,
|
2007-01-07 16:12:01 +08:00
|
|
|
Constant *(SimplifyLibCalls::*FP)()){
|
2005-08-25 01:22:17 +08:00
|
|
|
if (CastInst *Cast = dyn_cast<CastInst>(CI->getOperand(1)))
|
|
|
|
if (Cast->getOperand(0)->getType() == Type::FloatTy) {
|
2006-01-23 13:57:36 +08:00
|
|
|
Value *New = new CallInst((SLC.*FP)(), Cast->getOperand(0),
|
2005-08-25 01:22:17 +08:00
|
|
|
CI->getName(), CI);
|
2006-11-27 09:05:10 +08:00
|
|
|
New = new FPExtInst(New, Type::DoubleTy, CI->getName(), CI);
|
2005-08-25 01:22:17 +08:00
|
|
|
CI->replaceAllUsesWith(New);
|
|
|
|
CI->eraseFromParent();
|
|
|
|
if (Cast->use_empty())
|
|
|
|
Cast->eraseFromParent();
|
|
|
|
return true;
|
|
|
|
}
|
2006-01-23 13:57:36 +08:00
|
|
|
return false;
|
2005-08-25 01:22:17 +08:00
|
|
|
}
|
2006-01-23 06:35:08 +08:00
|
|
|
};
|
|
|
|
|
2006-01-23 13:57:36 +08:00
|
|
|
|
|
|
|
struct FloorOptimization : public UnaryDoubleFPOptimizer {
|
|
|
|
FloorOptimization()
|
|
|
|
: UnaryDoubleFPOptimizer("floor", "Number of 'floor' calls simplified") {}
|
|
|
|
|
|
|
|
virtual bool OptimizeCall(CallInst *CI, SimplifyLibCalls &SLC) {
|
2006-01-23 06:35:08 +08:00
|
|
|
#ifdef HAVE_FLOORF
|
2006-01-23 13:57:36 +08:00
|
|
|
// If this is a float argument passed in, convert to floorf.
|
|
|
|
if (ShrinkFunctionToFloatVersion(CI, SLC, &SimplifyLibCalls::get_floorf))
|
|
|
|
return true;
|
2006-01-19 16:36:56 +08:00
|
|
|
#endif
|
2006-01-23 13:57:36 +08:00
|
|
|
return false; // opt failed
|
|
|
|
}
|
|
|
|
} FloorOptimizer;
|
2005-08-25 01:22:17 +08:00
|
|
|
|
2006-01-23 14:24:46 +08:00
|
|
|
struct CeilOptimization : public UnaryDoubleFPOptimizer {
|
|
|
|
CeilOptimization()
|
|
|
|
: UnaryDoubleFPOptimizer("ceil", "Number of 'ceil' calls simplified") {}
|
|
|
|
|
|
|
|
virtual bool OptimizeCall(CallInst *CI, SimplifyLibCalls &SLC) {
|
|
|
|
#ifdef HAVE_CEILF
|
|
|
|
// If this is a float argument passed in, convert to ceilf.
|
|
|
|
if (ShrinkFunctionToFloatVersion(CI, SLC, &SimplifyLibCalls::get_ceilf))
|
|
|
|
return true;
|
|
|
|
#endif
|
|
|
|
return false; // opt failed
|
|
|
|
}
|
|
|
|
} CeilOptimizer;
|
|
|
|
|
|
|
|
struct RoundOptimization : public UnaryDoubleFPOptimizer {
|
|
|
|
RoundOptimization()
|
|
|
|
: UnaryDoubleFPOptimizer("round", "Number of 'round' calls simplified") {}
|
|
|
|
|
|
|
|
virtual bool OptimizeCall(CallInst *CI, SimplifyLibCalls &SLC) {
|
|
|
|
#ifdef HAVE_ROUNDF
|
|
|
|
// If this is a float argument passed in, convert to roundf.
|
|
|
|
if (ShrinkFunctionToFloatVersion(CI, SLC, &SimplifyLibCalls::get_roundf))
|
|
|
|
return true;
|
|
|
|
#endif
|
|
|
|
return false; // opt failed
|
|
|
|
}
|
|
|
|
} RoundOptimizer;
|
2005-08-25 01:22:17 +08:00
|
|
|
|
2006-01-23 14:24:46 +08:00
|
|
|
struct RintOptimization : public UnaryDoubleFPOptimizer {
|
|
|
|
RintOptimization()
|
|
|
|
: UnaryDoubleFPOptimizer("rint", "Number of 'rint' calls simplified") {}
|
|
|
|
|
|
|
|
virtual bool OptimizeCall(CallInst *CI, SimplifyLibCalls &SLC) {
|
|
|
|
#ifdef HAVE_RINTF
|
|
|
|
// If this is a float argument passed in, convert to rintf.
|
|
|
|
if (ShrinkFunctionToFloatVersion(CI, SLC, &SimplifyLibCalls::get_rintf))
|
|
|
|
return true;
|
|
|
|
#endif
|
|
|
|
return false; // opt failed
|
|
|
|
}
|
|
|
|
} RintOptimizer;
|
|
|
|
|
|
|
|
struct NearByIntOptimization : public UnaryDoubleFPOptimizer {
|
|
|
|
NearByIntOptimization()
|
|
|
|
: UnaryDoubleFPOptimizer("nearbyint",
|
|
|
|
"Number of 'nearbyint' calls simplified") {}
|
|
|
|
|
|
|
|
virtual bool OptimizeCall(CallInst *CI, SimplifyLibCalls &SLC) {
|
|
|
|
#ifdef HAVE_NEARBYINTF
|
|
|
|
// If this is a float argument passed in, convert to nearbyintf.
|
|
|
|
if (ShrinkFunctionToFloatVersion(CI, SLC,&SimplifyLibCalls::get_nearbyintf))
|
|
|
|
return true;
|
|
|
|
#endif
|
|
|
|
return false; // opt failed
|
|
|
|
}
|
|
|
|
} NearByIntOptimizer;
|
2005-08-25 01:22:17 +08:00
|
|
|
|
2005-04-28 05:29:20 +08:00
|
|
|
/// A function to compute the length of a null-terminated constant array of
|
2005-07-27 14:12:32 +08:00
|
|
|
/// integers. This function can't rely on the size of the constant array
|
|
|
|
/// because there could be a null terminator in the middle of the array.
|
|
|
|
/// We also have to bail out if we find a non-integer constant initializer
|
|
|
|
/// of one of the elements or if there is no null-terminator. The logic
|
2005-04-28 05:29:20 +08:00
|
|
|
/// below checks each of these conditions and will return true only if all
|
|
|
|
/// conditions are met. In that case, the \p len parameter is set to the length
|
|
|
|
/// of the null-terminated string. If false is returned, the conditions were
|
|
|
|
/// not met and len is set to 0.
|
|
|
|
/// @brief Get the length of a constant string (null-terminated array).
|
2006-01-23 06:35:08 +08:00
|
|
|
bool getConstantStringLength(Value *V, uint64_t &len, ConstantArray **CA) {
|
2005-04-27 15:54:40 +08:00
|
|
|
assert(V != 0 && "Invalid args to getConstantStringLength");
|
2005-07-27 14:12:32 +08:00
|
|
|
len = 0; // make sure we initialize this
|
2005-04-27 15:54:40 +08:00
|
|
|
User* GEP = 0;
|
2005-07-27 14:12:32 +08:00
|
|
|
// If the value is not a GEP instruction nor a constant expression with a
|
|
|
|
// GEP instruction, then return false because ConstantArray can't occur
|
2005-04-27 15:54:40 +08:00
|
|
|
// any other way
|
|
|
|
if (GetElementPtrInst* GEPI = dyn_cast<GetElementPtrInst>(V))
|
|
|
|
GEP = GEPI;
|
|
|
|
else if (ConstantExpr* CE = dyn_cast<ConstantExpr>(V))
|
|
|
|
if (CE->getOpcode() == Instruction::GetElementPtr)
|
|
|
|
GEP = CE;
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Make sure the GEP has exactly three arguments.
|
|
|
|
if (GEP->getNumOperands() != 3)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Check to make sure that the first operand of the GEP is an integer and
|
2005-07-27 14:12:32 +08:00
|
|
|
// has value 0 so that we are sure we're indexing into the initializer.
|
2006-01-23 06:35:08 +08:00
|
|
|
if (ConstantInt* op1 = dyn_cast<ConstantInt>(GEP->getOperand(1))) {
|
2005-04-27 15:54:40 +08:00
|
|
|
if (!op1->isNullValue())
|
|
|
|
return false;
|
2006-01-23 06:35:08 +08:00
|
|
|
} else
|
2005-04-27 15:54:40 +08:00
|
|
|
return false;
|
|
|
|
|
|
|
|
// Ensure that the second operand is a ConstantInt. If it isn't then this
|
2005-07-27 14:12:32 +08:00
|
|
|
// GEP is wonky and we're not really sure what were referencing into and
|
2005-04-27 15:54:40 +08:00
|
|
|
// better of not optimizing it. While we're at it, get the second index
|
|
|
|
// value. We'll need this later for indexing the ConstantArray.
|
|
|
|
uint64_t start_idx = 0;
|
|
|
|
if (ConstantInt* CI = dyn_cast<ConstantInt>(GEP->getOperand(2)))
|
2006-10-20 15:07:24 +08:00
|
|
|
start_idx = CI->getZExtValue();
|
2005-04-27 15:54:40 +08:00
|
|
|
else
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// The GEP instruction, constant or instruction, must reference a global
|
|
|
|
// variable that is a constant and is initialized. The referenced constant
|
|
|
|
// initializer is the array that we'll use for optimization.
|
|
|
|
GlobalVariable* GV = dyn_cast<GlobalVariable>(GEP->getOperand(0));
|
|
|
|
if (!GV || !GV->isConstant() || !GV->hasInitializer())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Get the initializer.
|
|
|
|
Constant* INTLZR = GV->getInitializer();
|
|
|
|
|
|
|
|
// Handle the ConstantAggregateZero case
|
2006-11-03 04:25:50 +08:00
|
|
|
if (isa<ConstantAggregateZero>(INTLZR)) {
|
2005-04-27 15:54:40 +08:00
|
|
|
// This is a degenerate case. The initializer is constant zero so the
|
|
|
|
// length of the string must be zero.
|
|
|
|
len = 0;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Must be a Constant Array
|
|
|
|
ConstantArray* A = dyn_cast<ConstantArray>(INTLZR);
|
|
|
|
if (!A)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Get the number of elements in the array
|
|
|
|
uint64_t max_elems = A->getType()->getNumElements();
|
|
|
|
|
|
|
|
// Traverse the constant array from start_idx (derived above) which is
|
2005-07-27 14:12:32 +08:00
|
|
|
// the place the GEP refers to in the array.
|
2006-01-23 06:35:08 +08:00
|
|
|
for (len = start_idx; len < max_elems; len++) {
|
|
|
|
if (ConstantInt *CI = dyn_cast<ConstantInt>(A->getOperand(len))) {
|
2005-04-27 15:54:40 +08:00
|
|
|
// Check for the null terminator
|
|
|
|
if (CI->isNullValue())
|
|
|
|
break; // we found end of string
|
2006-01-23 06:35:08 +08:00
|
|
|
} else
|
2005-04-27 15:54:40 +08:00
|
|
|
return false; // This array isn't suitable, non-int initializer
|
|
|
|
}
|
2006-01-23 06:35:08 +08:00
|
|
|
|
2005-04-27 15:54:40 +08:00
|
|
|
if (len >= max_elems)
|
|
|
|
return false; // This array isn't null terminated
|
|
|
|
|
|
|
|
// Subtract out the initial value from the length
|
|
|
|
len -= start_idx;
|
* Don't depend on "guessing" what a FILE* is, just require that the actual
type be obtained from a CallInst we're optimizing.
* Make it possible for getConstantStringLength to return the ConstantArray
that it extracts in case the content is needed by an Optimization.
* Implement the strcmp optimization
* Implement the toascii optimization
This pass is now firing several to many times in the following MultiSource
tests:
Applications/Burg - 7 (strcat,strcpy)
Applications/siod - 13 (strcat,strcpy,strlen)
Applications/spiff - 120 (exit,fputs,strcat,strcpy,strlen)
Applications/treecc - 66 (exit,fputs,strcat,strcpy)
Applications/kimwitu++ - 34 (strcmp,strcpy,strlen)
Applications/SPASS - 588 (exit,fputs,strcat,strcpy,strlen)
llvm-svn: 21626
2005-04-30 11:17:54 +08:00
|
|
|
if (CA)
|
|
|
|
*CA = A;
|
2005-04-27 15:54:40 +08:00
|
|
|
return true; // success!
|
|
|
|
}
|
|
|
|
|
2005-06-19 01:46:28 +08:00
|
|
|
/// CastToCStr - Return V if it is an sbyte*, otherwise cast it to sbyte*,
|
|
|
|
/// inserting the cast before IP, and return the cast.
|
|
|
|
/// @brief Cast a value to a "C" string.
|
|
|
|
Value *CastToCStr(Value *V, Instruction &IP) {
|
2006-12-13 16:04:32 +08:00
|
|
|
assert(isa<PointerType>(V->getType()) &&
|
2006-12-13 08:50:17 +08:00
|
|
|
"Can't cast non-pointer type to C string type");
|
2006-12-31 13:48:39 +08:00
|
|
|
const Type *SBPTy = PointerType::get(Type::Int8Ty);
|
2005-06-19 01:46:28 +08:00
|
|
|
if (V->getType() != SBPTy)
|
2006-12-13 08:50:17 +08:00
|
|
|
return new BitCastInst(V, SBPTy, V->getName(), &IP);
|
2005-06-19 01:46:28 +08:00
|
|
|
return V;
|
|
|
|
}
|
|
|
|
|
2005-07-27 14:12:32 +08:00
|
|
|
// TODO:
|
2005-04-28 12:40:06 +08:00
|
|
|
// Additional cases that we need to add to this file:
|
|
|
|
//
|
|
|
|
// cbrt:
|
|
|
|
// * cbrt(expN(X)) -> expN(x/3)
|
|
|
|
// * cbrt(sqrt(x)) -> pow(x,1/6)
|
|
|
|
// * cbrt(sqrt(x)) -> pow(x,1/9)
|
|
|
|
//
|
|
|
|
// cos, cosf, cosl:
|
2005-04-29 02:05:16 +08:00
|
|
|
// * cos(-x) -> cos(x)
|
2005-04-28 12:40:06 +08:00
|
|
|
//
|
|
|
|
// exp, expf, expl:
|
|
|
|
// * exp(log(x)) -> x
|
|
|
|
//
|
|
|
|
// log, logf, logl:
|
|
|
|
// * log(exp(x)) -> x
|
|
|
|
// * log(x**y) -> y*log(x)
|
|
|
|
// * log(exp(y)) -> y*log(e)
|
|
|
|
// * log(exp2(y)) -> y*log(2)
|
|
|
|
// * log(exp10(y)) -> y*log(10)
|
|
|
|
// * log(sqrt(x)) -> 0.5*log(x)
|
|
|
|
// * log(pow(x,y)) -> y*log(x)
|
|
|
|
//
|
|
|
|
// lround, lroundf, lroundl:
|
|
|
|
// * lround(cnst) -> cnst'
|
|
|
|
//
|
|
|
|
// memcmp:
|
|
|
|
// * memcmp(x,y,l) -> cnst
|
|
|
|
// (if all arguments are constant and strlen(x) <= l and strlen(y) <= l)
|
|
|
|
//
|
|
|
|
// memmove:
|
2005-07-27 14:12:32 +08:00
|
|
|
// * memmove(d,s,l,a) -> memcpy(d,s,l,a)
|
2005-04-28 12:40:06 +08:00
|
|
|
// (if s is a global constant array)
|
|
|
|
//
|
|
|
|
// pow, powf, powl:
|
|
|
|
// * pow(exp(x),y) -> exp(x*y)
|
|
|
|
// * pow(sqrt(x),y) -> pow(x,y*0.5)
|
|
|
|
// * pow(pow(x,y),z)-> pow(x,y*z)
|
|
|
|
//
|
|
|
|
// puts:
|
|
|
|
// * puts("") -> fputc("\n",stdout) (how do we get "stdout"?)
|
|
|
|
//
|
|
|
|
// round, roundf, roundl:
|
|
|
|
// * round(cnst) -> cnst'
|
|
|
|
//
|
|
|
|
// signbit:
|
|
|
|
// * signbit(cnst) -> cnst'
|
|
|
|
// * signbit(nncst) -> 0 (if pstv is a non-negative constant)
|
|
|
|
//
|
|
|
|
// sqrt, sqrtf, sqrtl:
|
|
|
|
// * sqrt(expN(x)) -> expN(x*0.5)
|
|
|
|
// * sqrt(Nroot(x)) -> pow(x,1/(2*N))
|
|
|
|
// * sqrt(pow(x,y)) -> pow(|x|,y*0.5)
|
|
|
|
//
|
2005-05-08 04:15:59 +08:00
|
|
|
// stpcpy:
|
|
|
|
// * stpcpy(str, "literal") ->
|
|
|
|
// llvm.memcpy(str,"literal",strlen("literal")+1,1)
|
2005-05-03 15:23:44 +08:00
|
|
|
// strrchr:
|
2005-04-28 12:40:06 +08:00
|
|
|
// * strrchr(s,c) -> reverse_offset_of_in(c,s)
|
|
|
|
// (if c is a constant integer and s is a constant string)
|
|
|
|
// * strrchr(s1,0) -> strchr(s1,0)
|
|
|
|
//
|
|
|
|
// strncat:
|
|
|
|
// * strncat(x,y,0) -> x
|
|
|
|
// * strncat(x,y,0) -> x (if strlen(y) = 0)
|
|
|
|
// * strncat(x,y,l) -> strcat(x,y) (if y and l are constants an l > strlen(y))
|
|
|
|
//
|
|
|
|
// strncpy:
|
|
|
|
// * strncpy(d,s,0) -> d
|
|
|
|
// * strncpy(d,s,l) -> memcpy(d,s,l,1)
|
|
|
|
// (if s and l are constants)
|
|
|
|
//
|
|
|
|
// strpbrk:
|
|
|
|
// * strpbrk(s,a) -> offset_in_for(s,a)
|
|
|
|
// (if s and a are both constant strings)
|
|
|
|
// * strpbrk(s,"") -> 0
|
|
|
|
// * strpbrk(s,a) -> strchr(s,a[0]) (if a is constant string of length 1)
|
|
|
|
//
|
|
|
|
// strspn, strcspn:
|
|
|
|
// * strspn(s,a) -> const_int (if both args are constant)
|
|
|
|
// * strspn("",a) -> 0
|
|
|
|
// * strspn(s,"") -> 0
|
|
|
|
// * strcspn(s,a) -> const_int (if both args are constant)
|
|
|
|
// * strcspn("",a) -> 0
|
|
|
|
// * strcspn(s,"") -> strlen(a)
|
|
|
|
//
|
|
|
|
// strstr:
|
|
|
|
// * strstr(x,x) -> x
|
2005-07-27 14:12:32 +08:00
|
|
|
// * strstr(s1,s2) -> offset_of_s2_in(s1)
|
2005-04-28 12:40:06 +08:00
|
|
|
// (if s1 and s2 are constant strings)
|
2005-07-27 14:12:32 +08:00
|
|
|
//
|
2005-04-28 12:40:06 +08:00
|
|
|
// tan, tanf, tanl:
|
|
|
|
// * tan(atan(x)) -> x
|
2005-07-27 14:12:32 +08:00
|
|
|
//
|
2005-04-28 12:40:06 +08:00
|
|
|
// trunc, truncf, truncl:
|
|
|
|
// * trunc(cnst) -> cnst'
|
|
|
|
//
|
2005-07-27 14:12:32 +08:00
|
|
|
//
|
2005-04-25 10:53:12 +08:00
|
|
|
}
|