<commit_before>//===---- CapturePropagation.cpp - Propagate closure capture constants ----===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "capture-prop"
#include "swift/SILPasses/Passes.h"
#include "swift/Basic/Demangle.h"
#include "swift/SIL/Mangle.h"
#include "swift/SIL/SILCloner.h"
#include "swift/SIL/SILInstruction.h"
#include "swift/SILAnalysis/ColdBlockInfo.h"
#include "swift/SILAnalysis/DominanceAnalysis.h"
#include "swift/SILPasses/Transforms.h"
#include "swift/SILPasses/Utils/Local.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/Debug.h"

using namespace swift;

STATISTIC(NumCapturesPropagated, "Number of constant captures propagated");

namespace {
/// Propagate constants through closure captures by specializing the partially
/// applied function.
class CapturePropagation : public SILModuleTransform
{
public:
  void run() override;

  StringRef getName() override { return "Captured Constant Propagation"; }

protected:
  bool optimizePartialApply(PartialApplyInst *PAI);
  SILFunction *specializeConstClosure(PartialApplyInst *PAI,
                                      SILFunction *SubstF);
  void rewritePartialApply(PartialApplyInst *PAI, SILFunction *SpecialF);
};
} // namespace

static LiteralInst *getConstant(SILValue V) {
  if (auto I = dyn_cast<ThinToThickFunctionInst>(V))
    return getConstant(I->getOperand());
  return dyn_cast<LiteralInst>(V);
}

static bool isOptimizableConstant(SILValue V) {
  // We do not optimize string literals of length > 32 since we would need to
  // encode them into the symbol name for uniqueness.
  if (auto *SLI = dyn_cast<StringLiteralInst>(V))
    return SLI->getValue().size() <= 32;
  return true;
}

static bool isConstant(SILValue V) {
  V = getConstant(V);
  return V && isOptimizableConstant(V);
}

static llvm::SmallString<64> getClonedName(PartialApplyInst *PAI,
                                           SILFunction *F) {
  llvm::SmallString<64> ClonedName;

  llvm::raw_svector_ostream buffer(ClonedName);
  Mangle::Mangler M(buffer);
  auto P = Mangle::SpecializationPass::CapturePropagation;
  Mangle::FunctionSignatureSpecializationMangler Mangler(P, M, F);

  // We know that all arguments are literal insts.
  auto Args = PAI->getArguments();
  for (unsigned i : indices(Args))
    Mangler.setArgumentConstantProp(i, getConstant(Args[i]));
  Mangler.mangle();

  return ClonedName;
}

namespace {
/// Clone the partially applied function, replacing incoming arguments with
/// literal constants.
///
/// The cloned literals will retain the SILLocation from the partial apply's
/// caller, so the cloned function will have a mix of locations from different
/// functions.
class CapturePropagationCloner
  : public SILClonerWithScopes<CapturePropagationCloner> {
  using SuperTy = SILClonerWithScopes<CapturePropagationCloner>;
  friend class SILVisitor<CapturePropagationCloner>;
  friend class SILCloner<CapturePropagationCloner>;

  SILFunction *OrigF;
  bool IsCloningConstant;
public:
  CapturePropagationCloner(SILFunction *OrigF, SILFunction *NewF)
    : SuperTy(*NewF), OrigF(OrigF), IsCloningConstant(false) {}

  void cloneBlocks(OperandValueArrayRef Args);

protected:
  /// Literals cloned from the caller drop their location so the debug line
  /// tables don't senselessly jump around. As a placeholder give them the
  /// location of the newly cloned function.
  SILLocation remapLocation(SILLocation InLoc) {
    if (IsCloningConstant)
      return getBuilder().getFunction().getLocation();
    return InLoc;
  }

  /// Literals cloned from the caller take on the new function's debug scope.
  void postProcess(SILInstruction *Orig, SILInstruction *Cloned) {
    assert(IsCloningConstant == (Orig->getFunction() != OrigF) &&
           "Expect only cloned constants from the caller function.");
    if (IsCloningConstant) {
      Cloned->setDebugScope(getBuilder().getFunction().getDebugScope());
      SILCloner<CapturePropagationCloner>::postProcess(Orig, Cloned);
    } else
      SILClonerWithScopes<CapturePropagationCloner>::postProcess(Orig, Cloned);
  }

  void cloneConstValue(SILValue Const);
};
} // namespace

/// Clone a constant value. Recursively walk the operand chain through cast
/// instructions to ensure that all dependents are cloned. Note that the
/// original value may not belong to the same function as the one being cloned
/// by cloneBlocks() (they may be from the partial apply caller).
void CapturePropagationCloner::cloneConstValue(SILValue Val) {
  assert(IsCloningConstant && "incorrect mode");

  auto Inst = dyn_cast<SILInstruction>(Val);
  if (!Inst)
    return;

  auto II = InstructionMap.find(Inst);
  if (II != InstructionMap.end())
    return;

  if (Inst->getNumOperands() > 0) {
    // Only handle single operands for simple recursion without a worklist.
    assert(Inst->getNumOperands() == 1 && "expected single-operand cast");
    cloneConstValue(Inst->getOperand(0));
  }
  visit(Inst);
}

/// Clone the original partially applied function into the new specialized
/// function, replacing some arguments with literals.
void CapturePropagationCloner::cloneBlocks(
  OperandValueArrayRef PartialApplyArgs) {

  SILFunction &CloneF = getBuilder().getFunction();
  SILModule &M = CloneF.getModule();

  // Create the entry basic block with the function arguments.
  SILBasicBlock *OrigEntryBB = OrigF->begin();
  SILBasicBlock *ClonedEntryBB = new (M) SILBasicBlock(&CloneF);
  CanSILFunctionType CloneFTy = CloneF.getLoweredFunctionType();

  // Only clone the arguments that remain in the new function type. The trailing
  // arguments are now propagated through the partial apply.
  assert(!IsCloningConstant && "incorrect mode");
  unsigned ParamIdx = 0;
  for (unsigned NewParamEnd = CloneFTy->getParameters().size();
       ParamIdx != NewParamEnd; ++ParamIdx) {

    SILArgument *Arg = OrigEntryBB->getBBArg(ParamIdx);

    SILValue MappedValue = new (M)
        SILArgument(ClonedEntryBB, remapType(Arg->getType()), Arg->getDecl());
    ValueMap.insert(std::make_pair(Arg, MappedValue));
  }
  assert(OrigEntryBB->bbarg_size() - ParamIdx == PartialApplyArgs.size()
         && "unexpected number of partial apply arguments");

  // Replace the rest of the old arguments with constants.
  BBMap.insert(std::make_pair(OrigEntryBB, ClonedEntryBB));
  getBuilder().setInsertionPoint(ClonedEntryBB);
  IsCloningConstant = true;
  for (SILValue PartialApplyArg : PartialApplyArgs) {
    assert(isConstant(PartialApplyArg) &&
           "expected a constant arg to partial apply");

    cloneConstValue(PartialApplyArg);

    // The PartialApplyArg from the caller is now mapped to its cloned
    // instruction.  Also map the original argument to the cloned instruction.
    SILArgument *InArg = OrigEntryBB->getBBArg(ParamIdx);
    ValueMap.insert(std::make_pair(InArg, remapValue(PartialApplyArg)));
    ++ParamIdx;
  }
  IsCloningConstant = false;
  // Recursively visit original BBs in depth-first preorder, starting with the
  // entry block, cloning all instructions other than terminators.
  visitSILBasicBlock(OrigEntryBB);

  // Now iterate over the BBs and fix up the terminators.
  for (auto BI = BBMap.begin(), BE = BBMap.end(); BI != BE; ++BI) {
    getBuilder().setInsertionPoint(BI->second);
    visit(BI->first->getTerminator());
  }
}

/// Given a partial_apply instruction, create a specialized callee by removing
/// all constant arguments and adding constant literals to the specialized
/// function body.
SILFunction *CapturePropagation::specializeConstClosure(PartialApplyInst *PAI,
                                                        SILFunction *OrigF) {
  llvm::SmallString<64> Name = getClonedName(PAI, OrigF);

  // See if we already have a version of this function in the module. If so,
  // just return it.
  if (auto *NewF = OrigF->getModule().lookUpFunction(Name.str())) {
    DEBUG(llvm::dbgs() << "  Found an already specialized version of the callee: ";
          NewF->printName(llvm::dbgs()); llvm::dbgs() << "\n");
    return NewF;
  }

  // The new partial_apply will no longer take any arguments--they are all
  // expressed as literals. So its callee signature will be the same as its
  // return signature.
  CanSILFunctionType NewFTy =
    Lowering::adjustFunctionType(PAI->getType().castTo<SILFunctionType>(),
                                 FunctionType::Representation::Thin);
  SILFunction *NewF = SILFunction::create(
      *getModule(), SILLinkage::Shared, Name, NewFTy,
      /*contextGenericParams*/ nullptr, OrigF->getLocation(), OrigF->isBare(),
      OrigF->isTransparent(), OrigF->isFragile(), OrigF->isThunk(),
      OrigF->getClassVisibility(),
      OrigF->getInlineStrategy(), OrigF->getEffectsKind(),
      /*InsertBefore*/ OrigF, OrigF->getDebugScope(), OrigF->getDeclContext());
  DEBUG(llvm::dbgs() << "  Specialize callee as ";
        NewF->printName(llvm::dbgs()); llvm::dbgs() << " " << NewFTy << "\n");

  CapturePropagationCloner cloner(OrigF, NewF);
  cloner.cloneBlocks(PAI->getArguments());
  return NewF;
}

void CapturePropagation::rewritePartialApply(PartialApplyInst *OrigPAI,
                                             SILFunction *SpecialF) {
  SILBuilderWithScope<2> Builder(OrigPAI);
  auto FuncRef = Builder.createFunctionRef(OrigPAI->getLoc(), SpecialF);
  auto NewPAI = Builder.createPartialApply(OrigPAI->getLoc(),
                                           FuncRef,
                                           SpecialF->getLoweredType(),
                                           ArrayRef<Substitution>(),
                                           ArrayRef<SILValue>(),
                                           OrigPAI->getType());
  OrigPAI->replaceAllUsesWith(NewPAI);
  recursivelyDeleteTriviallyDeadInstructions(OrigPAI, true);
  DEBUG(llvm::dbgs() << "  Rewrote caller:\n" << *NewPAI);
}

/// For now, we conservative only specialize if doing so can eliminate dynamic
/// dispatch.
///
/// TODO: Check for other profitable constant propagation, like builtin compare.
static bool isProfitable(SILFunction *Callee) {
  SILBasicBlock *EntryBB = Callee->begin();
  for (auto *Arg : EntryBB->getBBArgs()) {
    for (auto *Operand : Arg->getUses()) {
      if (auto *AI = dyn_cast<ApplyInst>(Operand->getUser())) {
        if (AI->getCallee() == Operand->get())
          return true;
      }
    }
  }
  return false;
}

bool CapturePropagation::optimizePartialApply(PartialApplyInst *PAI) {
  // Check if the partial_apply has generic substitutions.
  // FIXME: We could handle generic thunks if it's worthwhile.
  if (PAI->hasSubstitutions())
    return false;

  auto *FRI = dyn_cast<FunctionRefInst>(PAI->getCallee());
  if (!FRI)
    return false;

  assert(!FRI->getFunctionType()->isPolymorphic() &&
         "cannot specialize generic partial apply");

  for (auto Arg : PAI->getArguments()) {
    if (!isConstant(Arg))
      return false;
  }
  SILFunction *SubstF = FRI->getReferencedFunction();
  if (SubstF->isExternalDeclaration() || !isProfitable(SubstF))
    return false;

  DEBUG(llvm::dbgs() << "Specializing closure for constant arguments:\n"
        << "  " << SubstF->getName() << "\n" << *PAI);
  ++NumCapturesPropagated;
  SILFunction *NewF = specializeConstClosure(PAI, SubstF);
  rewritePartialApply(PAI, NewF);
  return true;
}

void CapturePropagation::run() {
  DominanceAnalysis *DA = PM->getAnalysis<DominanceAnalysis>();
  bool HasChanged = false;
  for (auto &F : *getModule()) {
    // Cache cold blocks per function.
    ColdBlockInfo ColdBlocks(DA);
    for (auto &BB : F) {
      if (ColdBlocks.isCold(&BB))
        continue;

      auto I = BB.begin();
      while (I != BB.end()) {
        SILInstruction *Inst = &*I;
        ++I;
        if (PartialApplyInst *PAI = dyn_cast<PartialApplyInst>(Inst))
          HasChanged |= optimizePartialApply(PAI);
      }
    }
  }
  // FIXME: This conservatively invalidates everything. But the transform
  // actually changes neither the CFG nor the static call graph. I only made
  // this conservative in case someone implements interprocedural/dynamic call
  // graph analysis later.
  if (HasChanged)
    invalidateAnalysis(SILAnalysis::PreserveKind::Nothing);
}

SILTransform *swift::createCapturePropagation() {
  return new CapturePropagation();
}
<commit_msg>Make the capture propagation pass report that it does not change the cfg.<commit_after>//===---- CapturePropagation.cpp - Propagate closure capture constants ----===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "capture-prop"
#include "swift/SILPasses/Passes.h"
#include "swift/Basic/Demangle.h"
#include "swift/SIL/Mangle.h"
#include "swift/SIL/SILCloner.h"
#include "swift/SIL/SILInstruction.h"
#include "swift/SILAnalysis/ColdBlockInfo.h"
#include "swift/SILAnalysis/DominanceAnalysis.h"
#include "swift/SILPasses/Transforms.h"
#include "swift/SILPasses/Utils/Local.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/Debug.h"

using namespace swift;

STATISTIC(NumCapturesPropagated, "Number of constant captures propagated");

namespace {
/// Propagate constants through closure captures by specializing the partially
/// applied function.
class CapturePropagation : public SILModuleTransform
{
public:
  void run() override;

  StringRef getName() override { return "Captured Constant Propagation"; }

protected:
  bool optimizePartialApply(PartialApplyInst *PAI);
  SILFunction *specializeConstClosure(PartialApplyInst *PAI,
                                      SILFunction *SubstF);
  void rewritePartialApply(PartialApplyInst *PAI, SILFunction *SpecialF);
};
} // namespace

static LiteralInst *getConstant(SILValue V) {
  if (auto I = dyn_cast<ThinToThickFunctionInst>(V))
    return getConstant(I->getOperand());
  return dyn_cast<LiteralInst>(V);
}

static bool isOptimizableConstant(SILValue V) {
  // We do not optimize string literals of length > 32 since we would need to
  // encode them into the symbol name for uniqueness.
  if (auto *SLI = dyn_cast<StringLiteralInst>(V))
    return SLI->getValue().size() <= 32;
  return true;
}

static bool isConstant(SILValue V) {
  V = getConstant(V);
  return V && isOptimizableConstant(V);
}

static llvm::SmallString<64> getClonedName(PartialApplyInst *PAI,
                                           SILFunction *F) {
  llvm::SmallString<64> ClonedName;

  llvm::raw_svector_ostream buffer(ClonedName);
  Mangle::Mangler M(buffer);
  auto P = Mangle::SpecializationPass::CapturePropagation;
  Mangle::FunctionSignatureSpecializationMangler Mangler(P, M, F);

  // We know that all arguments are literal insts.
  auto Args = PAI->getArguments();
  for (unsigned i : indices(Args))
    Mangler.setArgumentConstantProp(i, getConstant(Args[i]));
  Mangler.mangle();

  return ClonedName;
}

namespace {
/// Clone the partially applied function, replacing incoming arguments with
/// literal constants.
///
/// The cloned literals will retain the SILLocation from the partial apply's
/// caller, so the cloned function will have a mix of locations from different
/// functions.
class CapturePropagationCloner
  : public SILClonerWithScopes<CapturePropagationCloner> {
  using SuperTy = SILClonerWithScopes<CapturePropagationCloner>;
  friend class SILVisitor<CapturePropagationCloner>;
  friend class SILCloner<CapturePropagationCloner>;

  SILFunction *OrigF;
  bool IsCloningConstant;
public:
  CapturePropagationCloner(SILFunction *OrigF, SILFunction *NewF)
    : SuperTy(*NewF), OrigF(OrigF), IsCloningConstant(false) {}

  void cloneBlocks(OperandValueArrayRef Args);

protected:
  /// Literals cloned from the caller drop their location so the debug line
  /// tables don't senselessly jump around. As a placeholder give them the
  /// location of the newly cloned function.
  SILLocation remapLocation(SILLocation InLoc) {
    if (IsCloningConstant)
      return getBuilder().getFunction().getLocation();
    return InLoc;
  }

  /// Literals cloned from the caller take on the new function's debug scope.
  void postProcess(SILInstruction *Orig, SILInstruction *Cloned) {
    assert(IsCloningConstant == (Orig->getFunction() != OrigF) &&
           "Expect only cloned constants from the caller function.");
    if (IsCloningConstant) {
      Cloned->setDebugScope(getBuilder().getFunction().getDebugScope());
      SILCloner<CapturePropagationCloner>::postProcess(Orig, Cloned);
    } else
      SILClonerWithScopes<CapturePropagationCloner>::postProcess(Orig, Cloned);
  }

  void cloneConstValue(SILValue Const);
};
} // namespace

/// Clone a constant value. Recursively walk the operand chain through cast
/// instructions to ensure that all dependents are cloned. Note that the
/// original value may not belong to the same function as the one being cloned
/// by cloneBlocks() (they may be from the partial apply caller).
void CapturePropagationCloner::cloneConstValue(SILValue Val) {
  assert(IsCloningConstant && "incorrect mode");

  auto Inst = dyn_cast<SILInstruction>(Val);
  if (!Inst)
    return;

  auto II = InstructionMap.find(Inst);
  if (II != InstructionMap.end())
    return;

  if (Inst->getNumOperands() > 0) {
    // Only handle single operands for simple recursion without a worklist.
    assert(Inst->getNumOperands() == 1 && "expected single-operand cast");
    cloneConstValue(Inst->getOperand(0));
  }
  visit(Inst);
}

/// Clone the original partially applied function into the new specialized
/// function, replacing some arguments with literals.
void CapturePropagationCloner::cloneBlocks(
  OperandValueArrayRef PartialApplyArgs) {

  SILFunction &CloneF = getBuilder().getFunction();
  SILModule &M = CloneF.getModule();

  // Create the entry basic block with the function arguments.
  SILBasicBlock *OrigEntryBB = OrigF->begin();
  SILBasicBlock *ClonedEntryBB = new (M) SILBasicBlock(&CloneF);
  CanSILFunctionType CloneFTy = CloneF.getLoweredFunctionType();

  // Only clone the arguments that remain in the new function type. The trailing
  // arguments are now propagated through the partial apply.
  assert(!IsCloningConstant && "incorrect mode");
  unsigned ParamIdx = 0;
  for (unsigned NewParamEnd = CloneFTy->getParameters().size();
       ParamIdx != NewParamEnd; ++ParamIdx) {

    SILArgument *Arg = OrigEntryBB->getBBArg(ParamIdx);

    SILValue MappedValue = new (M)
        SILArgument(ClonedEntryBB, remapType(Arg->getType()), Arg->getDecl());
    ValueMap.insert(std::make_pair(Arg, MappedValue));
  }
  assert(OrigEntryBB->bbarg_size() - ParamIdx == PartialApplyArgs.size()
         && "unexpected number of partial apply arguments");

  // Replace the rest of the old arguments with constants.
  BBMap.insert(std::make_pair(OrigEntryBB, ClonedEntryBB));
  getBuilder().setInsertionPoint(ClonedEntryBB);
  IsCloningConstant = true;
  for (SILValue PartialApplyArg : PartialApplyArgs) {
    assert(isConstant(PartialApplyArg) &&
           "expected a constant arg to partial apply");

    cloneConstValue(PartialApplyArg);

    // The PartialApplyArg from the caller is now mapped to its cloned
    // instruction.  Also map the original argument to the cloned instruction.
    SILArgument *InArg = OrigEntryBB->getBBArg(ParamIdx);
    ValueMap.insert(std::make_pair(InArg, remapValue(PartialApplyArg)));
    ++ParamIdx;
  }
  IsCloningConstant = false;
  // Recursively visit original BBs in depth-first preorder, starting with the
  // entry block, cloning all instructions other than terminators.
  visitSILBasicBlock(OrigEntryBB);

  // Now iterate over the BBs and fix up the terminators.
  for (auto BI = BBMap.begin(), BE = BBMap.end(); BI != BE; ++BI) {
    getBuilder().setInsertionPoint(BI->second);
    visit(BI->first->getTerminator());
  }
}

/// Given a partial_apply instruction, create a specialized callee by removing
/// all constant arguments and adding constant literals to the specialized
/// function body.
SILFunction *CapturePropagation::specializeConstClosure(PartialApplyInst *PAI,
                                                        SILFunction *OrigF) {
  llvm::SmallString<64> Name = getClonedName(PAI, OrigF);

  // See if we already have a version of this function in the module. If so,
  // just return it.
  if (auto *NewF = OrigF->getModule().lookUpFunction(Name.str())) {
    DEBUG(llvm::dbgs() << "  Found an already specialized version of the callee: ";
          NewF->printName(llvm::dbgs()); llvm::dbgs() << "\n");
    return NewF;
  }

  // The new partial_apply will no longer take any arguments--they are all
  // expressed as literals. So its callee signature will be the same as its
  // return signature.
  CanSILFunctionType NewFTy =
    Lowering::adjustFunctionType(PAI->getType().castTo<SILFunctionType>(),
                                 FunctionType::Representation::Thin);
  SILFunction *NewF = SILFunction::create(
      *getModule(), SILLinkage::Shared, Name, NewFTy,
      /*contextGenericParams*/ nullptr, OrigF->getLocation(), OrigF->isBare(),
      OrigF->isTransparent(), OrigF->isFragile(), OrigF->isThunk(),
      OrigF->getClassVisibility(),
      OrigF->getInlineStrategy(), OrigF->getEffectsKind(),
      /*InsertBefore*/ OrigF, OrigF->getDebugScope(), OrigF->getDeclContext());
  DEBUG(llvm::dbgs() << "  Specialize callee as ";
        NewF->printName(llvm::dbgs()); llvm::dbgs() << " " << NewFTy << "\n");

  CapturePropagationCloner cloner(OrigF, NewF);
  cloner.cloneBlocks(PAI->getArguments());
  return NewF;
}

void CapturePropagation::rewritePartialApply(PartialApplyInst *OrigPAI,
                                             SILFunction *SpecialF) {
  SILBuilderWithScope<2> Builder(OrigPAI);
  auto FuncRef = Builder.createFunctionRef(OrigPAI->getLoc(), SpecialF);
  auto NewPAI = Builder.createPartialApply(OrigPAI->getLoc(),
                                           FuncRef,
                                           SpecialF->getLoweredType(),
                                           ArrayRef<Substitution>(),
                                           ArrayRef<SILValue>(),
                                           OrigPAI->getType());
  OrigPAI->replaceAllUsesWith(NewPAI);
  recursivelyDeleteTriviallyDeadInstructions(OrigPAI, true);
  DEBUG(llvm::dbgs() << "  Rewrote caller:\n" << *NewPAI);
}

/// For now, we conservative only specialize if doing so can eliminate dynamic
/// dispatch.
///
/// TODO: Check for other profitable constant propagation, like builtin compare.
static bool isProfitable(SILFunction *Callee) {
  SILBasicBlock *EntryBB = Callee->begin();
  for (auto *Arg : EntryBB->getBBArgs()) {
    for (auto *Operand : Arg->getUses()) {
      if (auto *AI = dyn_cast<ApplyInst>(Operand->getUser())) {
        if (AI->getCallee() == Operand->get())
          return true;
      }
    }
  }
  return false;
}

bool CapturePropagation::optimizePartialApply(PartialApplyInst *PAI) {
  // Check if the partial_apply has generic substitutions.
  // FIXME: We could handle generic thunks if it's worthwhile.
  if (PAI->hasSubstitutions())
    return false;

  auto *FRI = dyn_cast<FunctionRefInst>(PAI->getCallee());
  if (!FRI)
    return false;

  assert(!FRI->getFunctionType()->isPolymorphic() &&
         "cannot specialize generic partial apply");

  for (auto Arg : PAI->getArguments()) {
    if (!isConstant(Arg))
      return false;
  }
  SILFunction *SubstF = FRI->getReferencedFunction();
  if (SubstF->isExternalDeclaration() || !isProfitable(SubstF))
    return false;

  DEBUG(llvm::dbgs() << "Specializing closure for constant arguments:\n"
        << "  " << SubstF->getName() << "\n" << *PAI);
  ++NumCapturesPropagated;
  SILFunction *NewF = specializeConstClosure(PAI, SubstF);
  rewritePartialApply(PAI, NewF);
  return true;
}

void CapturePropagation::run() {
  DominanceAnalysis *DA = PM->getAnalysis<DominanceAnalysis>();
  bool HasChanged = false;
  for (auto &F : *getModule()) {
    // Cache cold blocks per function.
    ColdBlockInfo ColdBlocks(DA);
    for (auto &BB : F) {
      if (ColdBlocks.isCold(&BB))
        continue;

      auto I = BB.begin();
      while (I != BB.end()) {
        SILInstruction *Inst = &*I;
        ++I;
        if (PartialApplyInst *PAI = dyn_cast<PartialApplyInst>(Inst))
          HasChanged |= optimizePartialApply(PAI);
      }
    }
  }

  if (HasChanged)
    invalidateAnalysis(SILAnalysis::PreserveKind::Branches);
}

SILTransform *swift::createCapturePropagation() {
  return new CapturePropagation();
}
<|endoftext|>


<commit_before>//===-- TargetMachineRegistry.cpp - Target Auto Registration Impl ---------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file exposes the RegisterTarget class, which TargetMachine
// implementations should use to register themselves with the system.  This file
// also exposes the TargetMachineRegistry class, which allows tools to inspect
// all of registered targets.
//
//===----------------------------------------------------------------------===//

#include "llvm/Target/TargetMachineRegistry.h"
#include <algorithm>
using namespace llvm;

const TargetMachineRegistry::Entry *TargetMachineRegistry::List = 0;

/// getClosestStaticTargetForModule - Given an LLVM module, pick the best target
/// that is compatible with the module.  If no close target can be found, this
/// returns null and sets the Error string to a reason.
const TargetMachineRegistry::Entry *
TargetMachineRegistry::getClosestStaticTargetForModule(const Module &M,
                                                       std::string &Error) {
  std::vector<std::pair<unsigned, const Entry *> > UsableTargets;
  for (const Entry *E = getList(); E; E = E->getNext())
    if (unsigned Qual = E->ModuleMatchQualityFn(M))
      UsableTargets.push_back(std::make_pair(Qual, E));

  if (UsableTargets.empty()) {
    Error = "No available targets are compatible with this module";
    return 0;
  } else if (UsableTargets.size() == 1)
    return UsableTargets.back().second;

  // Otherwise, take the best target, but make sure we don't have to equally
  // good best targets.
  std::sort(UsableTargets.begin(), UsableTargets.end());
  if (UsableTargets.back().first ==UsableTargets[UsableTargets.size()-2].first){
    Error = "Cannot choose between targets \"" +
      std::string(UsableTargets.back().second->Name) + "\" and \"" +
      std::string(UsableTargets[UsableTargets.size()-2].second->Name) + "\"";
    return 0;
  }
  return UsableTargets.back().second;
}

/// getClosestTargetForJIT - Given an LLVM module, pick the best target that
/// is compatible with the current host and the specified module.  If no
/// close target can be found, this returns null and sets the Error string
/// to a reason.
const TargetMachineRegistry::Entry *
TargetMachineRegistry::getClosestTargetForJIT(std::string &Error) {
  std::vector<std::pair<unsigned, const Entry *> > UsableTargets;
  for (const Entry *E = getList(); E; E = E->getNext())
    if (unsigned Qual = E->JITMatchQualityFn())
      UsableTargets.push_back(std::make_pair(Qual, E));

  if (UsableTargets.empty()) {
    Error = "No JIT is available for this host";
    return 0;
  } else if (UsableTargets.size() == 1)
    return UsableTargets.back().second;

  // Otherwise, take the best target.  If there is a tie, just pick one.
  unsigned MaxQual = UsableTargets.front().first;
  const Entry *MaxQualTarget = UsableTargets.front().second;

  for (unsigned i = 1, e = UsableTargets.size(); i != e; ++i)
    if (UsableTargets[i].first > MaxQual) {
      MaxQual = UsableTargets[i].first;
      MaxQualTarget = UsableTargets[i].second;
    }

  return MaxQualTarget;
}

<commit_msg>Implement TargetRegistrationListener<commit_after>//===-- TargetMachineRegistry.cpp - Target Auto Registration Impl ---------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file exposes the RegisterTarget class, which TargetMachine
// implementations should use to register themselves with the system.  This file
// also exposes the TargetMachineRegistry class, which allows tools to inspect
// all of registered targets.
//
//===----------------------------------------------------------------------===//

#include "llvm/Target/TargetMachineRegistry.h"
#include <algorithm>
using namespace llvm;

/// List - This is the main list of all of the registered target machines.
const TargetMachineRegistry::Entry *TargetMachineRegistry::List = 0;

/// Listeners - All of the listeners registered to get notified when new targets
/// are loaded.
static TargetRegistrationListener *Listeners = 0;

TargetMachineRegistry::Entry::Entry(const char *N, const char *SD,
                       TargetMachine *(*CF)(const Module &, IntrinsicLowering*),
                           unsigned (*MMF)(const Module &M), unsigned (*JMF)())
  : Name(N), ShortDesc(SD), CtorFn(CF), ModuleMatchQualityFn(MMF),
    JITMatchQualityFn(JMF), Next(List) {
  List = this;
  for (TargetRegistrationListener *L = Listeners; L; L = L->getNext())
    L->targetRegistered(this);
}

TargetRegistrationListener::TargetRegistrationListener() {
  Next = Listeners;
  if (Next) Next->Prev = &Next;
  Prev = &Listeners;
  Listeners = this;
}

TargetRegistrationListener::~TargetRegistrationListener() {
  *Prev = Next;
}

/// getClosestStaticTargetForModule - Given an LLVM module, pick the best target
/// that is compatible with the module.  If no close target can be found, this
/// returns null and sets the Error string to a reason.
const TargetMachineRegistry::Entry *
TargetMachineRegistry::getClosestStaticTargetForModule(const Module &M,
                                                       std::string &Error) {
  std::vector<std::pair<unsigned, const Entry *> > UsableTargets;
  for (const Entry *E = getList(); E; E = E->getNext())
    if (unsigned Qual = E->ModuleMatchQualityFn(M))
      UsableTargets.push_back(std::make_pair(Qual, E));

  if (UsableTargets.empty()) {
    Error = "No available targets are compatible with this module";
    return 0;
  } else if (UsableTargets.size() == 1)
    return UsableTargets.back().second;

  // Otherwise, take the best target, but make sure we don't have to equally
  // good best targets.
  std::sort(UsableTargets.begin(), UsableTargets.end());
  if (UsableTargets.back().first ==UsableTargets[UsableTargets.size()-2].first){
    Error = "Cannot choose between targets \"" +
      std::string(UsableTargets.back().second->Name) + "\" and \"" +
      std::string(UsableTargets[UsableTargets.size()-2].second->Name) + "\"";
    return 0;
  }
  return UsableTargets.back().second;
}

/// getClosestTargetForJIT - Given an LLVM module, pick the best target that
/// is compatible with the current host and the specified module.  If no
/// close target can be found, this returns null and sets the Error string
/// to a reason.
const TargetMachineRegistry::Entry *
TargetMachineRegistry::getClosestTargetForJIT(std::string &Error) {
  std::vector<std::pair<unsigned, const Entry *> > UsableTargets;
  for (const Entry *E = getList(); E; E = E->getNext())
    if (unsigned Qual = E->JITMatchQualityFn())
      UsableTargets.push_back(std::make_pair(Qual, E));

  if (UsableTargets.empty()) {
    Error = "No JIT is available for this host";
    return 0;
  } else if (UsableTargets.size() == 1)
    return UsableTargets.back().second;

  // Otherwise, take the best target.  If there is a tie, just pick one.
  unsigned MaxQual = UsableTargets.front().first;
  const Entry *MaxQualTarget = UsableTargets.front().second;

  for (unsigned i = 1, e = UsableTargets.size(); i != e; ++i)
    if (UsableTargets[i].first > MaxQual) {
      MaxQual = UsableTargets[i].first;
      MaxQualTarget = UsableTargets[i].second;
    }

  return MaxQualTarget;
}

<|endoftext|>


<commit_before>//===- ConstantMerge.cpp - Merge duplicate global constants ---------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the interface to a pass that merges duplicate global
// constants together into a single constant that is shared.  This is useful
// because some passes (ie TraceValues) insert a lot of string constants into
// the program, regardless of whether or not an existing string is available.
//
// Algorithm: ConstantMerge is designed to build up a map of available constants
// and eliminate duplicates when it is initialized.
//
//===----------------------------------------------------------------------===//

#include "llvm/Transforms/IPO/ConstantMerge.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/GlobalValue.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
#include "llvm/Support/Casting.h"
#include "llvm/Transforms/IPO.h"
#include <algorithm>
#include <cassert>
#include <utility>

using namespace llvm;

#define DEBUG_TYPE "constmerge"

STATISTIC(NumMerged, "Number of global constants merged");

/// Find values that are marked as llvm.used.
static void FindUsedValues(GlobalVariable *LLVMUsed,
                           SmallPtrSetImpl<const GlobalValue*> &UsedValues) {
  if (!LLVMUsed) return;
  ConstantArray *Inits = cast<ConstantArray>(LLVMUsed->getInitializer());

  for (unsigned i = 0, e = Inits->getNumOperands(); i != e; ++i) {
    Value *Operand = Inits->getOperand(i)->stripPointerCastsNoFollowAliases();
    GlobalValue *GV = cast<GlobalValue>(Operand);
    UsedValues.insert(GV);
  }
}

// True if A is better than B.
static bool IsBetterCanonical(const GlobalVariable &A,
                              const GlobalVariable &B) {
  if (!A.hasLocalLinkage() && B.hasLocalLinkage())
    return true;

  if (A.hasLocalLinkage() && !B.hasLocalLinkage())
    return false;

  return A.hasGlobalUnnamedAddr();
}

static bool hasMetadataOtherThanDebugLoc(const GlobalVariable *GV) {
  SmallVector<std::pair<unsigned, MDNode *>, 4> MDs;
  GV->getAllMetadata(MDs);
  for (const auto &V : MDs)
    if (V.first != LLVMContext::MD_dbg)
      return true;
  return false;
}

static void copyDebugLocMetadata(const GlobalVariable *From,
                                 GlobalVariable *To) {
  SmallVector<DIGlobalVariableExpression *, 1> MDs;
  From->getDebugInfo(MDs);
  for (auto MD : MDs)
    To->addDebugInfo(MD);
}

static unsigned getAlignment(GlobalVariable *GV) {
  unsigned Align = GV->getAlignment();
  if (Align)
    return Align;
  return GV->getParent()->getDataLayout().getPreferredAlignment(GV);
}

enum class CanMerge { No, Yes };
static CanMerge makeMergeable(GlobalVariable *Old, GlobalVariable *New) {
  if (!Old->hasGlobalUnnamedAddr() && !New->hasGlobalUnnamedAddr())
    return CanMerge::No;
  if (hasMetadataOtherThanDebugLoc(Old))
    return CanMerge::No;
  assert(!hasMetadataOtherThanDebugLoc(New));
  if (!Old->hasGlobalUnnamedAddr())
    New->setUnnamedAddr(GlobalValue::UnnamedAddr::None);
  return CanMerge::Yes;
}

static void replace(Module &M, GlobalVariable *Old, GlobalVariable *New) {
  Constant *NewConstant = New;

  LLVM_DEBUG(dbgs() << "Replacing global: @" << Old->getName() << " -> @"
                    << New->getName() << "\n");

  // Bump the alignment if necessary.
  if (Old->getAlignment() || New->getAlignment())
    New->setAlignment(std::max(getAlignment(Old), getAlignment(New)));

  copyDebugLocMetadata(Old, New);
  Old->replaceAllUsesWith(NewConstant);

  // Delete the global value from the module.
  assert(Old->hasLocalLinkage() &&
         "Refusing to delete an externally visible global variable.");
  Old->eraseFromParent();
}

static bool mergeConstants(Module &M) {
  // Find all the globals that are marked "used".  These cannot be merged.
  SmallPtrSet<const GlobalValue*, 8> UsedGlobals;
  FindUsedValues(M.getGlobalVariable("llvm.used"), UsedGlobals);
  FindUsedValues(M.getGlobalVariable("llvm.compiler.used"), UsedGlobals);

  // Map unique constants to globals.
  DenseMap<Constant *, GlobalVariable *> CMap;

  // Replacements - This vector contains a list of replacements to perform.
  SmallVector<std::pair<GlobalVariable*, GlobalVariable*>, 32> Replacements;

  bool MadeChange = false;

  // Iterate constant merging while we are still making progress.  Merging two
  // constants together may allow us to merge other constants together if the
  // second level constants have initializers which point to the globals that
  // were just merged.
  while (true) {
    // First: Find the canonical constants others will be merged with.
    for (Module::global_iterator GVI = M.global_begin(), E = M.global_end();
         GVI != E; ) {
      GlobalVariable *GV = &*GVI++;

      // If this GV is dead, remove it.
      GV->removeDeadConstantUsers();
      if (GV->use_empty() && GV->hasLocalLinkage()) {
        GV->eraseFromParent();
        continue;
      }

      // Only process constants with initializers in the default address space.
      if (!GV->isConstant() || !GV->hasDefinitiveInitializer() ||
          GV->getType()->getAddressSpace() != 0 || GV->hasSection() ||
          // Don't touch values marked with attribute(used).
          UsedGlobals.count(GV))
        continue;

      // This transformation is legal for weak ODR globals in the sense it
      // doesn't change semantics, but we really don't want to perform it
      // anyway; it's likely to pessimize code generation, and some tools
      // (like the Darwin linker in cases involving CFString) don't expect it.
      if (GV->isWeakForLinker())
        continue;

      // Don't touch globals with metadata other then !dbg.
      if (hasMetadataOtherThanDebugLoc(GV))
        continue;

      Constant *Init = GV->getInitializer();

      // Check to see if the initializer is already known.
      GlobalVariable *&Slot = CMap[Init];

      // If this is the first constant we find or if the old one is local,
      // replace with the current one. If the current is externally visible
      // it cannot be replace, but can be the canonical constant we merge with.
      bool FirstConstantFound = !Slot;
      if (FirstConstantFound || IsBetterCanonical(*GV, *Slot)) {
        Slot = GV;
        LLVM_DEBUG(dbgs() << "Cmap[" << *Init << "] = " << GV->getName()
                          << (FirstConstantFound ? "\n" : " (updated)\n"));
      }
    }

    // Second: identify all globals that can be merged together, filling in
    // the Replacements vector.  We cannot do the replacement in this pass
    // because doing so may cause initializers of other globals to be rewritten,
    // invalidating the Constant* pointers in CMap.
    for (Module::global_iterator GVI = M.global_begin(), E = M.global_end();
         GVI != E; ) {
      GlobalVariable *GV = &*GVI++;

      // Only process constants with initializers in the default address space.
      if (!GV->isConstant() || !GV->hasDefinitiveInitializer() ||
          GV->getType()->getAddressSpace() != 0 || GV->hasSection() ||
          // Don't touch values marked with attribute(used).
          UsedGlobals.count(GV))
        continue;

      // We can only replace constant with local linkage.
      if (!GV->hasLocalLinkage())
        continue;

      Constant *Init = GV->getInitializer();

      // Check to see if the initializer is already known.
      auto Found = CMap.find(Init);
      if (Found == CMap.end())
        continue;

      GlobalVariable *Slot = Found->second;
      if (Slot == GV)
        continue;

      if (makeMergeable(GV, Slot) == CanMerge::No)
        continue;

      // Make all uses of the duplicate constant use the canonical version.
      LLVM_DEBUG(dbgs() << "Will replace: @" << GV->getName() << " -> @"
                        << Slot->getName() << "\n");
      Replacements.push_back(std::make_pair(GV, Slot));
    }

    if (Replacements.empty())
      return MadeChange;
    CMap.clear();

    // Now that we have figured out which replacements must be made, do them all
    // now.  This avoid invalidating the pointers in CMap, which are unneeded
    // now.
    for (unsigned i = 0, e = Replacements.size(); i != e; ++i) {
      GlobalVariable *Old = Replacements[i].first;
      GlobalVariable *New = Replacements[i].second;
      replace(M, Old, New);
      MadeChange = true;
    }

    NumMerged += Replacements.size();
    Replacements.clear();
  }
}

PreservedAnalyses ConstantMergePass::run(Module &M, ModuleAnalysisManager &) {
  if (!mergeConstants(M))
    return PreservedAnalyses::all();
  return PreservedAnalyses::none();
}

namespace {

struct ConstantMergeLegacyPass : public ModulePass {
  static char ID; // Pass identification, replacement for typeid

  ConstantMergeLegacyPass() : ModulePass(ID) {
    initializeConstantMergeLegacyPassPass(*PassRegistry::getPassRegistry());
  }

  // For this pass, process all of the globals in the module, eliminating
  // duplicate constants.
  bool runOnModule(Module &M) override {
    if (skipModule(M))
      return false;
    return mergeConstants(M);
  }
};

} // end anonymous namespace

char ConstantMergeLegacyPass::ID = 0;

INITIALIZE_PASS(ConstantMergeLegacyPass, "constmerge",
                "Merge Duplicate Global Constants", false, false)

ModulePass *llvm::createConstantMergePass() {
  return new ConstantMergeLegacyPass();
}
<commit_msg>Re-commit "[NFC] More ConstantMerge refactoring"<commit_after>//===- ConstantMerge.cpp - Merge duplicate global constants ---------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the interface to a pass that merges duplicate global
// constants together into a single constant that is shared.  This is useful
// because some passes (ie TraceValues) insert a lot of string constants into
// the program, regardless of whether or not an existing string is available.
//
// Algorithm: ConstantMerge is designed to build up a map of available constants
// and eliminate duplicates when it is initialized.
//
//===----------------------------------------------------------------------===//

#include "llvm/Transforms/IPO/ConstantMerge.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/GlobalValue.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
#include "llvm/Support/Casting.h"
#include "llvm/Transforms/IPO.h"
#include <algorithm>
#include <cassert>
#include <utility>

using namespace llvm;

#define DEBUG_TYPE "constmerge"

STATISTIC(NumIdenticalMerged, "Number of identical global constants merged");

/// Find values that are marked as llvm.used.
static void FindUsedValues(GlobalVariable *LLVMUsed,
                           SmallPtrSetImpl<const GlobalValue*> &UsedValues) {
  if (!LLVMUsed) return;
  ConstantArray *Inits = cast<ConstantArray>(LLVMUsed->getInitializer());

  for (unsigned i = 0, e = Inits->getNumOperands(); i != e; ++i) {
    Value *Operand = Inits->getOperand(i)->stripPointerCastsNoFollowAliases();
    GlobalValue *GV = cast<GlobalValue>(Operand);
    UsedValues.insert(GV);
  }
}

// True if A is better than B.
static bool IsBetterCanonical(const GlobalVariable &A,
                              const GlobalVariable &B) {
  if (!A.hasLocalLinkage() && B.hasLocalLinkage())
    return true;

  if (A.hasLocalLinkage() && !B.hasLocalLinkage())
    return false;

  return A.hasGlobalUnnamedAddr();
}

static bool hasMetadataOtherThanDebugLoc(const GlobalVariable *GV) {
  SmallVector<std::pair<unsigned, MDNode *>, 4> MDs;
  GV->getAllMetadata(MDs);
  for (const auto &V : MDs)
    if (V.first != LLVMContext::MD_dbg)
      return true;
  return false;
}

static void copyDebugLocMetadata(const GlobalVariable *From,
                                 GlobalVariable *To) {
  SmallVector<DIGlobalVariableExpression *, 1> MDs;
  From->getDebugInfo(MDs);
  for (auto MD : MDs)
    To->addDebugInfo(MD);
}

static unsigned getAlignment(GlobalVariable *GV) {
  unsigned Align = GV->getAlignment();
  if (Align)
    return Align;
  return GV->getParent()->getDataLayout().getPreferredAlignment(GV);
}

enum class CanMerge { No, Yes };
static CanMerge makeMergeable(GlobalVariable *Old, GlobalVariable *New) {
  if (!Old->hasGlobalUnnamedAddr() && !New->hasGlobalUnnamedAddr())
    return CanMerge::No;
  if (hasMetadataOtherThanDebugLoc(Old))
    return CanMerge::No;
  assert(!hasMetadataOtherThanDebugLoc(New));
  if (!Old->hasGlobalUnnamedAddr())
    New->setUnnamedAddr(GlobalValue::UnnamedAddr::None);
  return CanMerge::Yes;
}

static void replace(Module &M, GlobalVariable *Old, GlobalVariable *New) {
  Constant *NewConstant = New;

  LLVM_DEBUG(dbgs() << "Replacing global: @" << Old->getName() << " -> @"
                    << New->getName() << "\n");

  // Bump the alignment if necessary.
  if (Old->getAlignment() || New->getAlignment())
    New->setAlignment(std::max(getAlignment(Old), getAlignment(New)));

  copyDebugLocMetadata(Old, New);
  Old->replaceAllUsesWith(NewConstant);

  // Delete the global value from the module.
  assert(Old->hasLocalLinkage() &&
         "Refusing to delete an externally visible global variable.");
  Old->eraseFromParent();
}

static bool mergeConstants(Module &M) {
  // Find all the globals that are marked "used".  These cannot be merged.
  SmallPtrSet<const GlobalValue*, 8> UsedGlobals;
  FindUsedValues(M.getGlobalVariable("llvm.used"), UsedGlobals);
  FindUsedValues(M.getGlobalVariable("llvm.compiler.used"), UsedGlobals);

  // Map unique constants to globals.
  DenseMap<Constant *, GlobalVariable *> CMap;

  SmallVector<std::pair<GlobalVariable *, GlobalVariable *>, 32>
      SameContentReplacements;

  size_t ChangesMade = 0;
  size_t OldChangesMade = 0;

  // Iterate constant merging while we are still making progress.  Merging two
  // constants together may allow us to merge other constants together if the
  // second level constants have initializers which point to the globals that
  // were just merged.
  while (true) {
    // Find the canonical constants others will be merged with.
    for (Module::global_iterator GVI = M.global_begin(), E = M.global_end();
         GVI != E; ) {
      GlobalVariable *GV = &*GVI++;

      // If this GV is dead, remove it.
      GV->removeDeadConstantUsers();
      if (GV->use_empty() && GV->hasLocalLinkage()) {
        GV->eraseFromParent();
        ++ChangesMade;
        continue;
      }

      // Only process constants with initializers in the default address space.
      if (!GV->isConstant() || !GV->hasDefinitiveInitializer() ||
          GV->getType()->getAddressSpace() != 0 || GV->hasSection() ||
          // Don't touch values marked with attribute(used).
          UsedGlobals.count(GV))
        continue;

      // This transformation is legal for weak ODR globals in the sense it
      // doesn't change semantics, but we really don't want to perform it
      // anyway; it's likely to pessimize code generation, and some tools
      // (like the Darwin linker in cases involving CFString) don't expect it.
      if (GV->isWeakForLinker())
        continue;

      // Don't touch globals with metadata other then !dbg.
      if (hasMetadataOtherThanDebugLoc(GV))
        continue;

      Constant *Init = GV->getInitializer();

      // Check to see if the initializer is already known.
      GlobalVariable *&Slot = CMap[Init];

      // If this is the first constant we find or if the old one is local,
      // replace with the current one. If the current is externally visible
      // it cannot be replace, but can be the canonical constant we merge with.
      bool FirstConstantFound = !Slot;
      if (FirstConstantFound || IsBetterCanonical(*GV, *Slot)) {
        Slot = GV;
        LLVM_DEBUG(dbgs() << "Cmap[" << *Init << "] = " << GV->getName()
                          << (FirstConstantFound ? "\n" : " (updated)\n"));
      }
    }

    // Identify all globals that can be merged together, filling in the
    // SameContentReplacements vector. We cannot do the replacement in this pass
    // because doing so may cause initializers of other globals to be rewritten,
    // invalidating the Constant* pointers in CMap.
    for (Module::global_iterator GVI = M.global_begin(), E = M.global_end();
         GVI != E; ) {
      GlobalVariable *GV = &*GVI++;

      // Only process constants with initializers in the default address space.
      if (!GV->isConstant() || !GV->hasDefinitiveInitializer() ||
          GV->getType()->getAddressSpace() != 0 || GV->hasSection() ||
          // Don't touch values marked with attribute(used).
          UsedGlobals.count(GV))
        continue;

      // We can only replace constant with local linkage.
      if (!GV->hasLocalLinkage())
        continue;

      Constant *Init = GV->getInitializer();

      // Check to see if the initializer is already known.
      auto Found = CMap.find(Init);
      if (Found == CMap.end())
        continue;

      GlobalVariable *Slot = Found->second;
      if (Slot == GV)
        continue;

      if (makeMergeable(GV, Slot) == CanMerge::No)
        continue;

      // Make all uses of the duplicate constant use the canonical version.
      LLVM_DEBUG(dbgs() << "Will replace: @" << GV->getName() << " -> @"
                        << Slot->getName() << "\n");
      SameContentReplacements.push_back(std::make_pair(GV, Slot));
    }

    // Now that we have figured out which replacements must be made, do them all
    // now.  This avoid invalidating the pointers in CMap, which are unneeded
    // now.
    for (unsigned i = 0, e = SameContentReplacements.size(); i != e; ++i) {
      GlobalVariable *Old = SameContentReplacements[i].first;
      GlobalVariable *New = SameContentReplacements[i].second;
      replace(M, Old, New);
      ++ChangesMade;
      ++NumIdenticalMerged;
    }

    if (ChangesMade == OldChangesMade)
      break;
    OldChangesMade = ChangesMade;

    SameContentReplacements.clear();
    CMap.clear();
  }

  return ChangesMade;
}

PreservedAnalyses ConstantMergePass::run(Module &M, ModuleAnalysisManager &) {
  if (!mergeConstants(M))
    return PreservedAnalyses::all();
  return PreservedAnalyses::none();
}

namespace {

struct ConstantMergeLegacyPass : public ModulePass {
  static char ID; // Pass identification, replacement for typeid

  ConstantMergeLegacyPass() : ModulePass(ID) {
    initializeConstantMergeLegacyPassPass(*PassRegistry::getPassRegistry());
  }

  // For this pass, process all of the globals in the module, eliminating
  // duplicate constants.
  bool runOnModule(Module &M) override {
    if (skipModule(M))
      return false;
    return mergeConstants(M);
  }
};

} // end anonymous namespace

char ConstantMergeLegacyPass::ID = 0;

INITIALIZE_PASS(ConstantMergeLegacyPass, "constmerge",
                "Merge Duplicate Global Constants", false, false)

ModulePass *llvm::createConstantMergePass() {
  return new ConstantMergeLegacyPass();
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2009, 2010, Gostai S.A.S.
 *
 * This software is provided "as is" without warranty of any kind,
 * either expressed or implied, including but not limited to the
 * implied warranties of fitness for a particular purpose.
 *
 * See the LICENSE file for more information.
 */

// If you experience failures in debug mode (singular iterator used),
// then you probably have a problem with Boost.  See
// http://groups.google.com/group/boost-list/browse_thread/thread/5eecec53397d0c52/05b272fb9a9000c5:
//
//   The code can be fixed (although there may be other occurrences of
//   similar problems) by changing around line 220 on asio/detail/
//   hash_map.hpp from:
//        // Update number of buckets and initialise all buckets to empty.
//        buckets_.resize(num_buckets);
//        for (std::size_t i = 0; i < buckets_.size(); ++i)
//          buckets_[i].first = buckets_[i].last = end;
//   to:
//        // Update number of buckets and initialise all buckets to empty.
//        bucket_type bucket;
//        bucket.first = bucket.last = end;
//        buckets_.resize(num_buckets, bucket);
//

#include <libport/test.hh>
#include <libport/sysexits.hh>

using libport::test_suite;

#include <libport/asio.hh>
#include <libport/lexical-cast.hh>
#include <libport/thread.hh>
#include <libport/utime.hh>
#include <libport/unistd.h>

bool abort_ctor = false;

const char* msg = "coincoin\n";

// On OSX:
//   listen            connect        status
// "127.0.0.1"       "127.0.0.1"       PASS  IPv4
// "localhost"       "localhost"       PASS  IPv6
// ""                "localhost"       PASS  IPv6
// ""                "127.0.0.1"       FAIL
// ""                ""                PASS  IPv6
static const char* listen_host = "127.0.0.1";
static const char* connect_host = "127.0.0.1";

template<class T>
void
hold_for(T, libport::utime_t duration)
{
  usleep(duration);
  BOOST_TEST_MESSAGE("Done holding your T");
}

void
delayed_response(boost::shared_ptr<libport::UDPLink> l,
                 libport::utime_t duration)
{
  usleep(duration);
  l->reply("hop hop\n");
}

// Hack until we can kill listenig sockets.
static bool enable_delay = false;
void reply_delay(const void*, int,
                 boost::shared_ptr<libport::UDPLink> l,
                 libport::utime_t duration)
{
  libport::startThread(boost::bind(&delayed_response, l, duration));
}

void echo(const void* d, int s, boost::shared_ptr<libport::UDPLink> l)
{
  if (enable_delay)
    reply_delay(d, s, l, 500000);
  else
    l->reply(d, s);
}

class TestSocket: public libport::Socket
{
  public:
  TestSocket()
    : nRead(0), echo(false), dump(false)
    {
      BOOST_CHECK(!abort_ctor);
      nInstance++;
    }
  TestSocket(bool echo, bool dump)
    : nRead(0), echo(echo), dump(dump)
    {
      BOOST_CHECK(!abort_ctor);
      nInstance++;
    }
  virtual ~TestSocket()
  {
    nInstance--;
    // BOOST_TEST_MESSAGE(this << " dying, in " << K_get()
    //                    << " lasterror=" << lastError.message());
    // assert(false);
  }

  size_t onRead(const void* data, size_t size)
  {
    nRead++;
    //BOOST_TEST_MESSAGE(this << " read " << size);
    if (echo)
      write(data, size);
    if (dump)
      received += std::string((const char*)data, size);
    return size;
  }

  void onError(boost::system::error_code erc)
  {
    lastError = erc;
    destroy();
  }
  // Number of times read callback was called
  size_t nRead;
  // Echo back what is received.
  bool echo;
  // Store what is received in received.
  bool dump;
  std::string received;
  boost::system::error_code lastError;
  static TestSocket* factory()
    {
      return lastInstance = new TestSocket();
    }
  static TestSocket* factoryEx(bool echo, bool dump)
    {
      return lastInstance = new TestSocket(echo, dump);
    }
  static size_t nInstance;
  // Last factory-created instance.
  static TestSocket* lastInstance;
};

size_t TestSocket::nInstance = 0u;
TestSocket* TestSocket::lastInstance = 0;

// Delay in microseconds used to sleep when something asynchronous
// is happening.
static const useconds_t delay = 200000;

static const int AVAIL_PORT = 7890;
static const std::string S_AVAIL_PORT = string_cast(AVAIL_PORT);

void test_one(bool proto)
{
  TestSocket* client = new TestSocket(false, true);
  boost::system::error_code err
    = client->connect(connect_host, S_AVAIL_PORT, proto);
  BOOST_REQUIRE_MESSAGE(!err, err.message());
  BOOST_CHECK_NO_THROW(client->send(msg));
  usleep(delay);
  BOOST_CHECK_EQUAL(TestSocket::nInstance, proto ? 1u : 2u);
  BOOST_CHECK_EQUAL(client->received, msg);
  if (!proto)
    BOOST_CHECK_EQUAL(TestSocket::lastInstance->received,
                      msg);
  BOOST_CHECK_EQUAL(client->getRemotePort(), AVAIL_PORT);
  if (!proto)
    BOOST_CHECK_EQUAL(TestSocket::lastInstance->getLocalPort(),
                      AVAIL_PORT);
  if (!proto)
    BOOST_CHECK_EQUAL(TestSocket::lastInstance->getRemotePort(),
                      client->getLocalPort());
  // Close client-end. Should send error both ways and destroy all sockets.
  client->close();
  usleep(delay);
  BOOST_CHECK_EQUAL(TestSocket::nInstance, 0u);
}

static
void
test()
{
  // Basic TCP
  BOOST_TEST_MESSAGE("##Safe destruction");
  boost::system::error_code err;
  TestSocket* s = new TestSocket(false, false);
  s->connect(connect_host, S_AVAIL_PORT, false);
  s->destroy();
  usleep(delay);
  libport::Socket* h = new libport::Socket();
  // Try listening on an IP that is not ours.
  BOOST_TEST_MESSAGE("Invalid IP in listen()");
  err = h->listen(boost::bind(&TestSocket::factoryEx, true, true),
	"1.2.3.4", "1212", false);
  BOOST_CHECK(err);
  err = h->listen(boost::bind(&TestSocket::factoryEx, true, true),
                  listen_host, S_AVAIL_PORT, false);
  BOOST_CHECK_MESSAGE(!err, err.message());
  BOOST_CHECK_EQUAL(h->getLocalPort(), AVAIL_PORT);

  BOOST_TEST_MESSAGE("##One client");
  test_one(false);
  BOOST_CHECK_EQUAL(h->getLocalPort(), AVAIL_PORT);
  test_one(false);
  BOOST_CHECK_EQUAL(h->getLocalPort(), AVAIL_PORT);
  test_one(false);
  BOOST_TEST_MESSAGE("Socket on stack");
  {
    TestSocket s(false, true);
    err = s.connect(connect_host, S_AVAIL_PORT, false);
    BOOST_CHECK_MESSAGE(!err, err.message());
    s.send(msg);
    usleep(delay);
  }
  usleep(delay*2);
  BOOST_CHECK_EQUAL(TestSocket::nInstance, 0u);

  test_one(false);
  BOOST_TEST_MESSAGE("##many clients");
  std::vector<TestSocket*> clients;
  for (int i=0; i<10; i++)
  {
    TestSocket* client = new TestSocket(false, true);
    err = client->connect(connect_host, S_AVAIL_PORT, false);
    BOOST_CHECK_MESSAGE(!err, err.message());
    client->send(msg);
    clients.push_back(client);
  }
  usleep(delay*3);
  BOOST_CHECK_EQUAL(TestSocket::nInstance, 20u);
  foreach(TestSocket* s, clients)
  {
    BOOST_CHECK_EQUAL(s->received, msg);
    s->close();
  }
  usleep(delay*3);
  BOOST_CHECK_EQUAL(TestSocket::nInstance, 0u);

  BOOST_TEST_MESSAGE("##Failing connections");
  {
    TestSocket* client = new TestSocket();
    err = client->connect("auunsinsr.nosuch.hostaufisgiu.com.", "20000", false);
    BOOST_CHECK_MESSAGE(err, err.message());

    err = client->connect(connect_host, "nosuchport", false);
    BOOST_CHECK_MESSAGE(err, err.message());

    // Try to reuse that wasted socket.
    err = client->connect(connect_host, S_AVAIL_PORT, false);
    BOOST_CHECK_MESSAGE(!err, err.message());
    // Destroy without closing.
    client->destroy();
    usleep(delay);
    BOOST_CHECK_EQUAL(TestSocket::nInstance, 0u);
  }

  // Timeout
  BOOST_TEST_MESSAGE("##Timeout connect");
  {
    TestSocket* client = new TestSocket();
    libport::utime_t start = libport::utime();
    err = client->connect("1.1.1.1", "10000", false, 1000000);
    BOOST_CHECK_MESSAGE(err, err.message());
    libport::utime_t timeout = libport::utime() - start;
    // Give it a good margin.
    BOOST_CHECK_LT(timeout, 1400000);
    client->destroy();
  }

  BOOST_TEST_MESSAGE("##Destruction locking");
  {
    TestSocket* client = new TestSocket();
    err = client->connect(connect_host, S_AVAIL_PORT, false);
    BOOST_CHECK_MESSAGE(!err, err.message());
    usleep(delay);
    libport::startThread(
      boost::bind(&hold_for<libport::Destructible::DestructionLock>,
                  client->getDestructionLock(),
                  1000000));
    client->destroy();
    usleep(500000);
    // There can be 1 or 2 sockets at this point. Client must be still
    // alive because of the lock, but server might have died.
    BOOST_CHECK_MESSAGE(TestSocket::nInstance, TestSocket::nInstance);
    usleep(500000+delay);
    BOOST_CHECK_EQUAL(TestSocket::nInstance, 0u);
  }

  BOOST_TEST_MESSAGE("Destroy listener");
  {
    h->close();
    usleep(delay);
    TestSocket* client = new TestSocket();
    abort_ctor = true;
    err = client->connect(connect_host, S_AVAIL_PORT, false);
    BOOST_CHECK_MESSAGE(err, err.message());
    client->destroy();
    h->destroy();
    usleep(delay);
    abort_ctor = false;
  }

  BOOST_TEST_MESSAGE("##UDP");
  {
    libport::Socket::Handle hu =
      libport::Socket::listenUDP(listen_host, S_AVAIL_PORT, &echo, err);
    (void)hu;
    BOOST_CHECK_MESSAGE(!err, err.message());
    test_one(true);
    usleep(delay);
    test_one(true);

    TestSocket* client = new TestSocket();
    err = client->connect("auunsinsr.nosuch.hostaufisgiu.com.", "20000", true);
    BOOST_CHECK_MESSAGE(err, err.message());

    err = client->connect(connect_host, "nosuchport", true);
    BOOST_CHECK_MESSAGE(err, err.message());

    // Try to reuse that wasted socket.
    err = client->connect(connect_host, S_AVAIL_PORT, true);
    BOOST_CHECK_MESSAGE(!err, err.message());
    // Destroy without closing.
    client->destroy();
    usleep(delay);
    BOOST_CHECK_EQUAL(TestSocket::nInstance, 0u);

    // Check one-write-one-packet semantic
    client = new TestSocket(false, true);
    err = client->connect(connect_host, S_AVAIL_PORT, true);
    BOOST_CHECK_MESSAGE(!err, err.message());
    client->send("coin");
    client->send("pan");
    usleep(delay*2);
    BOOST_CHECK_EQUAL(client->received, "coinpan");
    BOOST_CHECK_EQUAL(client->nRead, 2u);

    enable_delay = true;
    client = new TestSocket(false, true);
    err = client->connect(connect_host, S_AVAIL_PORT, true);
    BOOST_CHECK_MESSAGE(!err, err.message());
    client->send("coin");
    usleep(500000+delay);
    BOOST_CHECK_EQUAL(client->received, "hop hop\n");
  }
}

static void test_pipe()
{
  TestSocket* s1 = new TestSocket(false, true);
  TestSocket* s2 = new TestSocket(false, true);

  libport::makePipe(std::make_pair(s2, s1));

  // First element is reader, second is writer.
  s1->send("canard");
  usleep(delay*2);
  BOOST_CHECK_EQUAL("canard", s2->received);
  s1->send("coin");
  usleep(delay*2);
  BOOST_CHECK_EQUAL(s2->received, "canardcoin");
  usleep(delay);
  // FIXME: fix the bug that SEGV when a pipe socket is destroyed.
  s1->destroy();
  s2->destroy();
  usleep(delay*2);
}

test_suite*
init_test_suite()
{
  test_suite* suite = BOOST_TEST_SUITE("libport::asio test suite");
  skip_if("Qemu");
  skip_if("Wine");
  /*
  if (!running("Qemu") && !running("Wine"))
  {
    suite->add(BOOST_TEST_CASE(test));
    suite->add(BOOST_TEST_CASE(test_pipe));
  }*/
  return suite;
}
<commit_msg>Properly *not* skip the asio test under not win32.<commit_after>/*
 * Copyright (C) 2009, 2010, Gostai S.A.S.
 *
 * This software is provided "as is" without warranty of any kind,
 * either expressed or implied, including but not limited to the
 * implied warranties of fitness for a particular purpose.
 *
 * See the LICENSE file for more information.
 */

// If you experience failures in debug mode (singular iterator used),
// then you probably have a problem with Boost.  See
// http://groups.google.com/group/boost-list/browse_thread/thread/5eecec53397d0c52/05b272fb9a9000c5:
//
//   The code can be fixed (although there may be other occurrences of
//   similar problems) by changing around line 220 on asio/detail/
//   hash_map.hpp from:
//        // Update number of buckets and initialise all buckets to empty.
//        buckets_.resize(num_buckets);
//        for (std::size_t i = 0; i < buckets_.size(); ++i)
//          buckets_[i].first = buckets_[i].last = end;
//   to:
//        // Update number of buckets and initialise all buckets to empty.
//        bucket_type bucket;
//        bucket.first = bucket.last = end;
//        buckets_.resize(num_buckets, bucket);
//

#include <libport/test.hh>
#include <libport/sysexits.hh>

using libport::test_suite;

#include <libport/asio.hh>
#include <libport/lexical-cast.hh>
#include <libport/thread.hh>
#include <libport/utime.hh>
#include <libport/unistd.h>

bool abort_ctor = false;

const char* msg = "coincoin\n";

// On OSX:
//   listen            connect        status
// "127.0.0.1"       "127.0.0.1"       PASS  IPv4
// "localhost"       "localhost"       PASS  IPv6
// ""                "localhost"       PASS  IPv6
// ""                "127.0.0.1"       FAIL
// ""                ""                PASS  IPv6
static const char* listen_host = "127.0.0.1";
static const char* connect_host = "127.0.0.1";

template<class T>
void
hold_for(T, libport::utime_t duration)
{
  usleep(duration);
  BOOST_TEST_MESSAGE("Done holding your T");
}

void
delayed_response(boost::shared_ptr<libport::UDPLink> l,
                 libport::utime_t duration)
{
  usleep(duration);
  l->reply("hop hop\n");
}

// Hack until we can kill listenig sockets.
static bool enable_delay = false;
void reply_delay(const void*, int,
                 boost::shared_ptr<libport::UDPLink> l,
                 libport::utime_t duration)
{
  libport::startThread(boost::bind(&delayed_response, l, duration));
}

void echo(const void* d, int s, boost::shared_ptr<libport::UDPLink> l)
{
  if (enable_delay)
    reply_delay(d, s, l, 500000);
  else
    l->reply(d, s);
}

class TestSocket: public libport::Socket
{
  public:
  TestSocket()
    : nRead(0), echo(false), dump(false)
    {
      BOOST_CHECK(!abort_ctor);
      nInstance++;
    }
  TestSocket(bool echo, bool dump)
    : nRead(0), echo(echo), dump(dump)
    {
      BOOST_CHECK(!abort_ctor);
      nInstance++;
    }
  virtual ~TestSocket()
  {
    nInstance--;
    // BOOST_TEST_MESSAGE(this << " dying, in " << K_get()
    //                    << " lasterror=" << lastError.message());
    // assert(false);
  }

  size_t onRead(const void* data, size_t size)
  {
    nRead++;
    //BOOST_TEST_MESSAGE(this << " read " << size);
    if (echo)
      write(data, size);
    if (dump)
      received += std::string((const char*)data, size);
    return size;
  }

  void onError(boost::system::error_code erc)
  {
    lastError = erc;
    destroy();
  }
  // Number of times read callback was called
  size_t nRead;
  // Echo back what is received.
  bool echo;
  // Store what is received in received.
  bool dump;
  std::string received;
  boost::system::error_code lastError;
  static TestSocket* factory()
    {
      return lastInstance = new TestSocket();
    }
  static TestSocket* factoryEx(bool echo, bool dump)
    {
      return lastInstance = new TestSocket(echo, dump);
    }
  static size_t nInstance;
  // Last factory-created instance.
  static TestSocket* lastInstance;
};

size_t TestSocket::nInstance = 0u;
TestSocket* TestSocket::lastInstance = 0;

// Delay in microseconds used to sleep when something asynchronous
// is happening.
static const useconds_t delay = 200000;

static const int AVAIL_PORT = 7890;
static const std::string S_AVAIL_PORT = string_cast(AVAIL_PORT);

void test_one(bool proto)
{
  TestSocket* client = new TestSocket(false, true);
  boost::system::error_code err
    = client->connect(connect_host, S_AVAIL_PORT, proto);
  BOOST_REQUIRE_MESSAGE(!err, err.message());
  BOOST_CHECK_NO_THROW(client->send(msg));
  usleep(delay);
  BOOST_CHECK_EQUAL(TestSocket::nInstance, proto ? 1u : 2u);
  BOOST_CHECK_EQUAL(client->received, msg);
  if (!proto)
    BOOST_CHECK_EQUAL(TestSocket::lastInstance->received,
                      msg);
  BOOST_CHECK_EQUAL(client->getRemotePort(), AVAIL_PORT);
  if (!proto)
    BOOST_CHECK_EQUAL(TestSocket::lastInstance->getLocalPort(),
                      AVAIL_PORT);
  if (!proto)
    BOOST_CHECK_EQUAL(TestSocket::lastInstance->getRemotePort(),
                      client->getLocalPort());
  // Close client-end. Should send error both ways and destroy all sockets.
  client->close();
  usleep(delay);
  BOOST_CHECK_EQUAL(TestSocket::nInstance, 0u);
}

static
void
test()
{
  // Basic TCP
  BOOST_TEST_MESSAGE("##Safe destruction");
  boost::system::error_code err;
  TestSocket* s = new TestSocket(false, false);
  s->connect(connect_host, S_AVAIL_PORT, false);
  s->destroy();
  usleep(delay);
  libport::Socket* h = new libport::Socket();
  // Try listening on an IP that is not ours.
  BOOST_TEST_MESSAGE("Invalid IP in listen()");
  err = h->listen(boost::bind(&TestSocket::factoryEx, true, true),
	"1.2.3.4", "1212", false);
  BOOST_CHECK(err);
  err = h->listen(boost::bind(&TestSocket::factoryEx, true, true),
                  listen_host, S_AVAIL_PORT, false);
  BOOST_CHECK_MESSAGE(!err, err.message());
  BOOST_CHECK_EQUAL(h->getLocalPort(), AVAIL_PORT);

  BOOST_TEST_MESSAGE("##One client");
  test_one(false);
  BOOST_CHECK_EQUAL(h->getLocalPort(), AVAIL_PORT);
  test_one(false);
  BOOST_CHECK_EQUAL(h->getLocalPort(), AVAIL_PORT);
  test_one(false);
  BOOST_TEST_MESSAGE("Socket on stack");
  {
    TestSocket s(false, true);
    err = s.connect(connect_host, S_AVAIL_PORT, false);
    BOOST_CHECK_MESSAGE(!err, err.message());
    s.send(msg);
    usleep(delay);
  }
  usleep(delay*2);
  BOOST_CHECK_EQUAL(TestSocket::nInstance, 0u);

  test_one(false);
  BOOST_TEST_MESSAGE("##many clients");
  std::vector<TestSocket*> clients;
  for (int i=0; i<10; i++)
  {
    TestSocket* client = new TestSocket(false, true);
    err = client->connect(connect_host, S_AVAIL_PORT, false);
    BOOST_CHECK_MESSAGE(!err, err.message());
    client->send(msg);
    clients.push_back(client);
  }
  usleep(delay*3);
  BOOST_CHECK_EQUAL(TestSocket::nInstance, 20u);
  foreach(TestSocket* s, clients)
  {
    BOOST_CHECK_EQUAL(s->received, msg);
    s->close();
  }
  usleep(delay*3);
  BOOST_CHECK_EQUAL(TestSocket::nInstance, 0u);

  BOOST_TEST_MESSAGE("##Failing connections");
  {
    TestSocket* client = new TestSocket();
    err = client->connect("auunsinsr.nosuch.hostaufisgiu.com.", "20000", false);
    BOOST_CHECK_MESSAGE(err, err.message());

    err = client->connect(connect_host, "nosuchport", false);
    BOOST_CHECK_MESSAGE(err, err.message());

    // Try to reuse that wasted socket.
    err = client->connect(connect_host, S_AVAIL_PORT, false);
    BOOST_CHECK_MESSAGE(!err, err.message());
    // Destroy without closing.
    client->destroy();
    usleep(delay);
    BOOST_CHECK_EQUAL(TestSocket::nInstance, 0u);
  }

  // Timeout
  BOOST_TEST_MESSAGE("##Timeout connect");
  {
    TestSocket* client = new TestSocket();
    libport::utime_t start = libport::utime();
    err = client->connect("1.1.1.1", "10000", false, 1000000);
    BOOST_CHECK_MESSAGE(err, err.message());
    libport::utime_t timeout = libport::utime() - start;
    // Give it a good margin.
    BOOST_CHECK_LT(timeout, 1400000);
    client->destroy();
  }

  BOOST_TEST_MESSAGE("##Destruction locking");
  {
    TestSocket* client = new TestSocket();
    err = client->connect(connect_host, S_AVAIL_PORT, false);
    BOOST_CHECK_MESSAGE(!err, err.message());
    usleep(delay);
    libport::startThread(
      boost::bind(&hold_for<libport::Destructible::DestructionLock>,
                  client->getDestructionLock(),
                  1000000));
    client->destroy();
    usleep(500000);
    // There can be 1 or 2 sockets at this point. Client must be still
    // alive because of the lock, but server might have died.
    BOOST_CHECK_MESSAGE(TestSocket::nInstance, TestSocket::nInstance);
    usleep(500000+delay);
    BOOST_CHECK_EQUAL(TestSocket::nInstance, 0u);
  }

  BOOST_TEST_MESSAGE("Destroy listener");
  {
    h->close();
    usleep(delay);
    TestSocket* client = new TestSocket();
    abort_ctor = true;
    err = client->connect(connect_host, S_AVAIL_PORT, false);
    BOOST_CHECK_MESSAGE(err, err.message());
    client->destroy();
    h->destroy();
    usleep(delay);
    abort_ctor = false;
  }

  BOOST_TEST_MESSAGE("##UDP");
  {
    libport::Socket::Handle hu =
      libport::Socket::listenUDP(listen_host, S_AVAIL_PORT, &echo, err);
    (void)hu;
    BOOST_CHECK_MESSAGE(!err, err.message());
    test_one(true);
    usleep(delay);
    test_one(true);

    TestSocket* client = new TestSocket();
    err = client->connect("auunsinsr.nosuch.hostaufisgiu.com.", "20000", true);
    BOOST_CHECK_MESSAGE(err, err.message());

    err = client->connect(connect_host, "nosuchport", true);
    BOOST_CHECK_MESSAGE(err, err.message());

    // Try to reuse that wasted socket.
    err = client->connect(connect_host, S_AVAIL_PORT, true);
    BOOST_CHECK_MESSAGE(!err, err.message());
    // Destroy without closing.
    client->destroy();
    usleep(delay);
    BOOST_CHECK_EQUAL(TestSocket::nInstance, 0u);

    // Check one-write-one-packet semantic
    client = new TestSocket(false, true);
    err = client->connect(connect_host, S_AVAIL_PORT, true);
    BOOST_CHECK_MESSAGE(!err, err.message());
    client->send("coin");
    client->send("pan");
    usleep(delay*2);
    BOOST_CHECK_EQUAL(client->received, "coinpan");
    BOOST_CHECK_EQUAL(client->nRead, 2u);

    enable_delay = true;
    client = new TestSocket(false, true);
    err = client->connect(connect_host, S_AVAIL_PORT, true);
    BOOST_CHECK_MESSAGE(!err, err.message());
    client->send("coin");
    usleep(500000+delay);
    BOOST_CHECK_EQUAL(client->received, "hop hop\n");
  }
}

static void test_pipe()
{
  TestSocket* s1 = new TestSocket(false, true);
  TestSocket* s2 = new TestSocket(false, true);

  libport::makePipe(std::make_pair(s2, s1));

  // First element is reader, second is writer.
  s1->send("canard");
  usleep(delay*2);
  BOOST_CHECK_EQUAL("canard", s2->received);
  s1->send("coin");
  usleep(delay*2);
  BOOST_CHECK_EQUAL(s2->received, "canardcoin");
  usleep(delay);
  // FIXME: fix the bug that SEGV when a pipe socket is destroyed.
  s1->destroy();
  s2->destroy();
  usleep(delay*2);
}

test_suite*
init_test_suite()
{
  skip_if("Qemu");
  skip_if("Wine");
  test_suite* suite = BOOST_TEST_SUITE("libport::asio test suite");
  suite->add(BOOST_TEST_CASE(test));
  suite->add(BOOST_TEST_CASE(test_pipe));
  return suite;
}
<|endoftext|>


<commit_before>#define CATCH_CONFIG_MAIN
#include "catch.hpp"

#include "stud/string.h"

TEST_CASE("Default constructor") {
    REQUIRE(stud::string() == std::string());
}

TEST_CASE("Copy constructor") {
    stud::string s("Hello world");
    REQUIRE(stud::string(s) == std::string("Hello world"));
}

TEST_CASE("Move constructor") {
    REQUIRE(stud::string(stud::string("Hello world")) == std::string("Hello world"));
}

TEST_CASE("Copy assignment") {
    stud::string s("Hello world");
    stud::string s2 = s;
    REQUIRE(s2 == std::string("Hello world"));
}

TEST_CASE("Move assignment") {
    stud::string s = stud::string("Hello world");
    REQUIRE(s == std::string("Hello world"));
}

TEST_CASE("Raw string constructor") {
    stud::string s("Hello world");
    REQUIRE(s == std::string("Hello world"));
}

TEST_CASE("Raw string constructor with length") {
    stud::string s("Hello world", 5);
    REQUIRE(s == std::string("Hello"));
}

TEST_CASE("Filled character constructor") {
    stud::string s(5, 'H');
    REQUIRE(s == std::string("HHHHH"));
}

TEST_CASE("String constructor") {
    stud::string s(std::string("Hello world"));
    REQUIRE(s == std::string("Hello world"));
}

TEST_CASE("String constructor with position and length") {
    stud::string s(std::string("Hello world"), 4, 3);
    REQUIRE(s == std::string("o w"));
}

TEST_CASE("Initializer list of characters constructor") {
    stud::string s{'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd'};
    REQUIRE(s == std::string("Hello world"));
}

TEST_CASE("Iterator constructor from string") {
    std::string s_from("Hello world");
    stud::string s(s_from.begin(), s_from.begin() + 5);
    REQUIRE(s == std::string("Hello"));
}
<commit_msg>Add additional string tests<commit_after>#define CATCH_CONFIG_MAIN
#include "catch.hpp"

#include <utility>

#include "stud/string.h"

TEST_CASE("Default constructor") {
    REQUIRE(stud::string() == std::string());
}

TEST_CASE("Copy constructor") {
    stud::string s("Hello world");
    REQUIRE(stud::string(s) == std::string("Hello world"));
}

TEST_CASE("Move constructor") {
    stud::string to_move("Hello world");
    stud::string s(std::move(to_move));
    REQUIRE(s == std::string("Hello world"));
}

TEST_CASE("Copy assignment") {
    stud::string s("Hello world");
    stud::string s2;
    s2 = s;
    REQUIRE(s2 == std::string("Hello world"));
}

TEST_CASE("Move assignment") {
    stud::string s;
    s = std::move(stud::string("Hello world"));
    REQUIRE(s == std::string("Hello world"));
}

TEST_CASE("Raw string constructor") {
    stud::string s("Hello world");
    REQUIRE(s == std::string("Hello world"));
}

TEST_CASE("Raw string constructor with length") {
    stud::string s("Hello world", 5);
    REQUIRE(s == std::string("Hello"));
}

TEST_CASE("Filled character constructor") {
    stud::string s(5, 'H');
    REQUIRE(s == std::string("HHHHH"));
}

TEST_CASE("String constructor") {
    stud::string s(std::string("Hello world"));
    REQUIRE(s == std::string("Hello world"));
}

TEST_CASE("String constructor with position and length") {
    stud::string s(std::string("Hello world"), 4, 3);
    REQUIRE(s == std::string("o w"));
}

TEST_CASE("Initializer list of characters constructor") {
    stud::string s{'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd'};
    REQUIRE(s == std::string("Hello world"));
}

TEST_CASE("Iterator constructor from string") {
    std::string s_from("Hello world");
    stud::string s(s_from.begin(), s_from.begin() + 5);
    REQUIRE(s == std::string("Hello"));
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: WrappedTextRotationProperty.cxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: hr $ $Date: 2007-08-03 12:34:18 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_chart2.hxx"

#include "WrappedTextRotationProperty.hxx"
#include "macros.hxx"

using ::com::sun::star::uno::Any;
using ::rtl::OUString;

//.............................................................................
namespace chart
{
//.............................................................................

WrappedTextRotationProperty::WrappedTextRotationProperty()
    : ::chart::WrappedProperty( C2U( "TextRotation" ), C2U( "TextRotation" ) )
{
}
WrappedTextRotationProperty::~WrappedTextRotationProperty()
{
}
Any WrappedTextRotationProperty::convertInnerToOuterValue( const Any& rInnerValue ) const
{
    Any aRet;
    double fVal = 0;
    if( rInnerValue >>= fVal )
    {
        sal_Int32 n100thDegrees = static_cast< sal_Int32 >( fVal * 100.0 );
        aRet <<= n100thDegrees;
    }
    return aRet;
}
Any WrappedTextRotationProperty::convertOuterToInnerValue( const Any& rOuterValue ) const
{
    Any aRet;
    sal_Int32 nVal = 0;
    if( rOuterValue >>= nVal )
    {
        double fDoubleDegrees = ( static_cast< double >( nVal ) / 100.0 );
        aRet <<= fDoubleDegrees;
    }
    return aRet;
}

//.............................................................................
} //namespace chart
//.............................................................................
<commit_msg>INTEGRATION: CWS changefileheader (1.3.92); FILE MERGED 2008/03/28 16:43:19 rt 1.3.92.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: WrappedTextRotationProperty.cxx,v $
 * $Revision: 1.4 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_chart2.hxx"

#include "WrappedTextRotationProperty.hxx"
#include "macros.hxx"

using ::com::sun::star::uno::Any;
using ::rtl::OUString;

//.............................................................................
namespace chart
{
//.............................................................................

WrappedTextRotationProperty::WrappedTextRotationProperty()
    : ::chart::WrappedProperty( C2U( "TextRotation" ), C2U( "TextRotation" ) )
{
}
WrappedTextRotationProperty::~WrappedTextRotationProperty()
{
}
Any WrappedTextRotationProperty::convertInnerToOuterValue( const Any& rInnerValue ) const
{
    Any aRet;
    double fVal = 0;
    if( rInnerValue >>= fVal )
    {
        sal_Int32 n100thDegrees = static_cast< sal_Int32 >( fVal * 100.0 );
        aRet <<= n100thDegrees;
    }
    return aRet;
}
Any WrappedTextRotationProperty::convertOuterToInnerValue( const Any& rOuterValue ) const
{
    Any aRet;
    sal_Int32 nVal = 0;
    if( rOuterValue >>= nVal )
    {
        double fDoubleDegrees = ( static_cast< double >( nVal ) / 100.0 );
        aRet <<= fDoubleDegrees;
    }
    return aRet;
}

//.............................................................................
} //namespace chart
//.............................................................................
<|endoftext|>


<commit_before>#if HAVE_CONFIG_H
#include <config.h>
#endif

#include <fstream>

#include <xorg/gtest/xorg-gtest.h>

#include "input-driver-test.h"
#include "device-interface.h"
#include "helpers.h"

class EventQueueTest : public InputDriverTest,
                       public DeviceInterface {
public:
    /**
     * Initializes a standard mouse device.
     */
    virtual void SetUp() {
        SetDevice("mice/PIXART-USB-OPTICAL-MOUSE-HWHEEL.desc");
        InputDriverTest::SetUp();
    }

    /**
     * Sets up an xorg.conf for a single evdev CoreKeyboard device based on
     * the evemu device. The input from GetParam() is used as XkbLayout.
     */
    virtual void SetUpConfigAndLog(const std::string &param) {

        config.AddDefaultScreenWithDriver();
        config.AddInputSection("evdev", "--device--",
                               "Option \"CorePointer\" \"on\"\n"
                               "Option \"Device\" \"" + dev->GetDeviceNode() + "\"");
        /* add default keyboard device to avoid server adding our device again */
        config.AddInputSection("kbd", "kbd-device",
                               "Option \"CoreKeyboard\" \"on\"\n");
        config.WriteConfig("/tmp/eventqueue-test.conf");
        server.SetOption("-logfile", "/tmp/Xorg-eventqueue-test.log");
        server.SetOption("-config", config.GetPath());
    }
};

TEST_F(EventQueueTest, mieqOverflow)
{
    SCOPED_TRACE("\n"
                 "TESTCASE: overflow the event queue and force a resize.\n"
                 "Search the server log for the error message.\n");

    for (int i = 0; i < 2048; i++)
        dev->PlayOne(EV_REL, REL_X, -1, true);
    XSync(Display(), False);
    ASSERT_EQ(server.GetState(), xorg::testing::Process::RUNNING);

    std::ifstream logfile(server.GetLogFilePath().c_str());
    std::string line;
    std::string bug_warn("EQ overflowing");
    bool found = false;
    ASSERT_TRUE(logfile.is_open());
    while(!found && getline(logfile, line))
        found = line.find(bug_warn);

    ASSERT_TRUE(found) << "Expected message '" << bug_warn << "' in the log "
                       << "but couldn't find it";
}

int main(int argc, char **argv) {
    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}
<commit_msg>server/misc: write segfault handler test<commit_after>#if HAVE_CONFIG_H
#include <config.h>
#endif

#include <fstream>

#include <xorg/gtest/xorg-gtest.h>

#include "input-driver-test.h"
#include "device-interface.h"
#include "helpers.h"

using namespace xorg::testing;

class EventQueueTest : public InputDriverTest,
                       public DeviceInterface {
public:
    /**
     * Initializes a standard mouse device.
     */
    virtual void SetUp() {
        SetDevice("mice/PIXART-USB-OPTICAL-MOUSE-HWHEEL.desc");
        InputDriverTest::SetUp();
    }

    /**
     * Sets up an xorg.conf for a single evdev CoreKeyboard device based on
     * the evemu device. The input from GetParam() is used as XkbLayout.
     */
    virtual void SetUpConfigAndLog(const std::string &param) {

        config.AddDefaultScreenWithDriver();
        config.AddInputSection("evdev", "--device--",
                               "Option \"CorePointer\" \"on\"\n"
                               "Option \"Device\" \"" + dev->GetDeviceNode() + "\"");
        /* add default keyboard device to avoid server adding our device again */
        config.AddInputSection("kbd", "kbd-device",
                               "Option \"CoreKeyboard\" \"on\"\n");
        config.WriteConfig("/tmp/eventqueue-test.conf");
        server.SetOption("-logfile", "/tmp/Xorg-eventqueue-test.log");
        server.SetOption("-config", config.GetPath());
    }
};

TEST_F(EventQueueTest, mieqOverflow)
{
    SCOPED_TRACE("\n"
                 "TESTCASE: overflow the event queue and force a resize.\n"
                 "Search the server log for the error message.\n");

    for (int i = 0; i < 2048; i++)
        dev->PlayOne(EV_REL, REL_X, -1, true);
    XSync(Display(), False);
    ASSERT_EQ(server.GetState(), xorg::testing::Process::RUNNING);

    std::ifstream logfile(server.GetLogFilePath().c_str());
    std::string line;
    std::string bug_warn("EQ overflowing");
    bool found = false;
    ASSERT_TRUE(logfile.is_open());
    while(!found && getline(logfile, line))
        found = line.find(bug_warn);

    ASSERT_TRUE(found) << "Expected message '" << bug_warn << "' in the log "
                       << "but couldn't find it";
}

TEST(MiscServerTest, DoubleSegfault)
{
    SCOPED_TRACE("\n"
                 "TESTCASE: SIGSEGV the server. The server must catch the "
                 "signal, clean up and then call abort().\n");

    std::string logpath = "/tmp/Xorg-sigsegv.log";
    XServer server;
    server.SetOption("-logfile", logpath);
    server.Start();

    ASSERT_EQ(server.GetState(), xorg::testing::Process::RUNNING);

    /* We connect and run XSync, this usually takes long enough for some
       devices to come up. That way, input devices are part of the close
       down procedure */
    ::Display *dpy = XOpenDisplay(server.GetDisplayString().c_str());
    XSync(dpy, False);

    kill(server.Pid(), SIGSEGV);

    int status = 1;
    while(WIFEXITED(status) == false)
        if (waitpid(server.Pid(), &status, 0) == -1)
            break;

    ASSERT_TRUE(WIFSIGNALED(status));
    int termsig = WTERMSIG(status);
    ASSERT_EQ(termsig, SIGABRT)
        << "Expected SIGABRT, got " << termsig << " (" << strsignal(termsig) << ")";

    std::ifstream logfile(server.GetLogFilePath().c_str());
    std::string line;
    std::string signal_caught_msg("Caught signal");
    int signal_count = 0;
    ASSERT_TRUE(logfile.is_open());
    while(getline(logfile, line)) {
        if (line.find(signal_caught_msg) != std::string::npos)
            signal_count++;
    }

    ASSERT_EQ(signal_count, 1) << "Expected one signal to show up in the log\n";

    unlink(logpath.c_str());

    /* The XServer destructor tries to terminate the server and prints
       warnings if it fails */
    std::cout << "Note: below warnings about server termination failures server are false positives\n";
    server.Terminate(); /* explicitly terminate instead of destructor to
                           only get one warning */
}

int main(int argc, char **argv) {
    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}
<|endoftext|>