#include "llvm/Instructions.h"
#include "llvm/IntrinsicInst.h"
#include "llvm/Module.h"
+#include "llvm/ParameterAttributes.h"
#include "llvm/Pass.h"
#include "llvm/Analysis/ConstantFolding.h"
#include "llvm/Target/TargetData.h"
STATISTIC(NumShrunkToBool , "Number of global vars shrunk to booleans");
STATISTIC(NumFastCallFns , "Number of functions converted to fastcc");
STATISTIC(NumCtorsEvaluated, "Number of static ctors evaluated");
+STATISTIC(NumNestRemoved , "Number of nest attributes removed");
namespace {
struct VISIBILITY_HIDDEN GlobalOpt : public ModulePass {
else if (GS.AccessingFunction != F)
GS.HasMultipleAccessingFunctions = true;
}
- if (isa<LoadInst>(I)) {
+ if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
GS.isLoaded = true;
+ if (LI->isVolatile()) return true; // Don't hack on volatile loads.
} else if (StoreInst *SI = dyn_cast<StoreInst>(I)) {
// Don't allow a store OF the address, only stores TO the address.
if (SI->getOperand(0) == V) return true;
+ if (SI->isVolatile()) return true; // Don't hack on volatile stores.
+
// If this is a direct store to the global (i.e., the global is a scalar
// value, not an aggregate), keep more specific information about
// stores.
}
}
+static const ParamAttrsList *StripNest(const ParamAttrsList *Attrs) {
+ if (Attrs) {
+ for (unsigned i = 0, e = Attrs->size(); i != e; ++i) {
+ uint16_t A = Attrs->getParamAttrsAtIndex(i);
+ if (A & ParamAttr::Nest) {
+ Attrs = ParamAttrsList::excludeAttrs(Attrs, Attrs->getParamIndex(i),
+ ParamAttr::Nest);
+ // There can be only one.
+ break;
+ }
+ }
+ }
+
+ return Attrs;
+}
+
+static void RemoveNestAttribute(Function *F) {
+ F->setParamAttrs(StripNest(F->getParamAttrs()));
+ for (Value::use_iterator UI = F->use_begin(), E = F->use_end(); UI != E;++UI){
+ Instruction *User = cast<Instruction>(*UI);
+ if (CallInst *CI = dyn_cast<CallInst>(User)) {
+ CI->setParamAttrs(StripNest(CI->getParamAttrs()));
+ } else {
+ InvokeInst *II = cast<InvokeInst>(User);
+ II->setParamAttrs(StripNest(II->getParamAttrs()));
+ }
+ }
+}
+
bool GlobalOpt::OptimizeFunctions(Module &M) {
bool Changed = false;
// Optimize functions.
M.getFunctionList().erase(F);
Changed = true;
++NumFnDeleted;
- } else if (F->hasInternalLinkage() &&
- F->getCallingConv() == CallingConv::C && !F->isVarArg() &&
- OnlyCalledDirectly(F)) {
- // If this function has C calling conventions, is not a varargs
- // function, and is only called directly, promote it to use the Fast
- // calling convention.
- F->setCallingConv(CallingConv::Fast);
- ChangeCalleesToFastCall(F);
- ++NumFastCallFns;
- Changed = true;
+ } else if (F->hasInternalLinkage()) {
+ if (F->getCallingConv() == CallingConv::C && !F->isVarArg() &&
+ OnlyCalledDirectly(F)) {
+ // If this function has C calling conventions, is not a varargs
+ // function, and is only called directly, promote it to use the Fast
+ // calling convention.
+ F->setCallingConv(CallingConv::Fast);
+ ChangeCalleesToFastCall(F);
+ ++NumFastCallFns;
+ Changed = true;
+ }
+
+ if (F->getParamAttrs() &&
+ F->getParamAttrs()->hasAttrSomewhere(ParamAttr::Nest) &&
+ OnlyCalledDirectly(F)) {
+ // The function is not used by a trampoline intrinsic, so it is safe
+ // to remove the 'nest' attribute.
+ RemoveNestAttribute(F);
+ ++NumNestRemoved;
+ Changed = true;
+ }
}
}
return Changed;