<commit_before>//===-------------- ARCAnalysis.cpp - SIL ARC Analysis --------------------===//
//
// 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 "sil-arc-analysis"
#include "swift/SILAnalysis/ARCAnalysis.h"
#include "swift/Basic/Fallthrough.h"
#include "swift/SIL/SILFunction.h"
#include "swift/SIL/SILInstruction.h"
#include "swift/SILAnalysis/AliasAnalysis.h"
#include "swift/SILAnalysis/ValueTracking.h"
#include "swift/SILPasses/Utils/Local.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/Debug.h"

using namespace swift;
using namespace swift::arc;

//===----------------------------------------------------------------------===//
//                             Decrement Analysis
//===----------------------------------------------------------------------===//

static bool isKnownToNotDecrementRefCount(FunctionRefInst *FRI) {
   return llvm::StringSwitch<bool>(FRI->getReferencedFunction()->getName())
     .Case("swift_keepAlive", true)
     .Case("_swift_isUniquelyReferenced", true)
     .Default(false);
}

static bool canApplyDecrementRefCount(ApplyInst *AI, SILValue Ptr,
                                      AliasAnalysis *AA) {
  // Ignore any thick functions for now due to us not handling the ref-counted
  // nature of its context.
  if (auto FTy = AI->getCallee().getType().getAs<SILFunctionType>())
    if (FTy->getExtInfo().hasContext())
      return true;

  // If we have a builtin that is side effect free, we can commute the
  // ApplyInst and the retain.
  if (auto *BI = dyn_cast<BuiltinFunctionRefInst>(AI->getCallee()))
    if (isSideEffectFree(BI))
      return false;

  // swift_keepAlive can not retain values. Remove this when we get rid of that.
  if (auto *FRI = dyn_cast<FunctionRefInst>(AI->getCallee()))
    if (isKnownToNotDecrementRefCount(FRI))
      return false;

  // Ok, this apply *MAY* decrement ref counts. Now our strategy is to attempt
  // to use properties of the pointer, the function's arguments, and the
  // function itself to prove that the pointer can not have its ref count be
  // effected by function.

  // TODO: Put in function property check section here when we get access to
  // such information.

  // First make sure that the underlying object of ptr is a local object which
  // does not escape. This prevents the apply from indirectly via the global
  // affecting the reference count of the pointer.
  if (!isNonEscapingLocalObject(getUnderlyingObject(Ptr)))
    return true;

  // Now that we know that the function can not affect the pointer indirectly,
  // make sure that the apply can not affect the pointer directly via the
  // applies arguments by proving that the pointer can not alias any of the
  // functions arguments.
  for (auto Op : AI->getArgumentsWithoutIndirectResult()) {
    for (int i = 0, e = Ptr->getNumTypes(); i < e; i++) {
      if (!AA->isNoAlias(Op, SILValue(Ptr.getDef(), i)))
        return true;
    }
  }

  // Success! The apply inst can not affect the reference count of ptr!
  return false;
}

/// Is the may have side effects user by the definition of its value kind unable
/// to decrement ref counts.
static bool canDecrementRefCountsByValueKind(SILInstruction *User) {
  assert(User->getMemoryBehavior()
           ==  SILInstruction::MemoryBehavior::MayHaveSideEffects &&
         "Invalid argument. Function is only applicable to isntructions with "
         "side effects.");
  switch (User->getKind()) {
  case ValueKind::DeallocStackInst:
  case ValueKind::StrongRetainInst:
  case ValueKind::StrongRetainAutoreleasedInst:
  case ValueKind::StrongRetainUnownedInst:
  case ValueKind::UnownedRetainInst:
  case ValueKind::PartialApplyInst:
  case ValueKind::FixLifetimeInst:
  case ValueKind::CopyBlockInst:
  case ValueKind::RetainValueInst:
  case ValueKind::CondFailInst:
    return false;

  case ValueKind::CopyAddrInst: {
    auto *CA = cast<CopyAddrInst>(User);
    if (CA->isInitializationOfDest() == IsInitialization_t::IsInitialization)
      return false;
  }
  SWIFT_FALLTHROUGH;
  default:
    return true;
  }
}

bool swift::arc::canDecrementRefCount(SILInstruction *User,
                                      SILValue Ptr, AliasAnalysis *AA) {
  // If we have an instruction that does not have *pure* side effects, it can
  // not affect ref counts.
  //
  // This distinguishes in between a "write" side effect and ref count side
  // effects.
  if (User->getMemoryBehavior() !=
      SILInstruction::MemoryBehavior::MayHaveSideEffects)
    return false;

  // Ok, we know that this instruction's generic behavior is
  // "MayHaveSideEffects". That is a criterion (it has effects not represented
  // by use-def chains) that is broader than ours (does it effect a particular
  // pointers ref counts). Thus begin by attempting to prove that the type of
  // instruction that the user is by definition can not decrement ref counts.
  if (!canDecrementRefCountsByValueKind(User))
    return false;

  // Ok, this instruction may have ref counts. If it is an apply, attempt to
  // prove that the callee is unable to affect Ptr.
  if (auto *AI = dyn_cast<ApplyInst>(User))
    return canApplyDecrementRefCount(AI, Ptr, AA);

  // We can not conservatively prove that this instruction can not decrement the
  // ref count of Ptr. So assume that it does.
  return true;
}

//===----------------------------------------------------------------------===//
//                                Use Analysis
//===----------------------------------------------------------------------===//

/// Returns true if a builtin apply can not use reference counted values.
///
/// The main case that this handles here are builtins that via read none imply
/// that they can not read globals and at the same time do not take any
/// non-trivial types via the arguments. The reason why we care about taking
/// non-trivial types as arguments is that we want to be careful in the face of
/// intrinsics that may be equivalent to bitcast and inttoptr operations.
static bool canApplyOfBuiltinUseNonTrivialValues(ApplyInst *AI,
                                                 BuiltinFunctionRefInst *BFRI) {
  SILModule &Mod = AI->getModule();

  auto &II = BFRI->getIntrinsicInfo();
  if (II.ID != llvm::Intrinsic::not_intrinsic) {
    if (II.hasAttribute(llvm::Attribute::ReadNone)) {
      for (auto &Op : AI->getArgumentOperands()) {
        if (!Op.get().getType().isTrivial(Mod)) {
          return false;
        }
      }
    }

    return true;
  }

  auto &BI = BFRI->getBuiltinInfo();
  if (BI.isReadNone()) {
    for (auto &Op : AI->getArgumentOperands()) {
      if (!Op.get().getType().isTrivial(Mod)) {
        return false;
      }
    }
  }

  return true;
}

/// Returns true if Inst is a function that we know never uses ref count values.
static bool canInstUseRefCountValues(SILInstruction *Inst) {
  switch (Inst->getKind()) {
  // These instructions do not use other values.
  case ValueKind::FunctionRefInst:
  case ValueKind::BuiltinFunctionRefInst:
  case ValueKind::IntegerLiteralInst:
  case ValueKind::FloatLiteralInst:
  case ValueKind::StringLiteralInst:
  case ValueKind::AllocStackInst:
  case ValueKind::AllocRefInst:
  case ValueKind::AllocRefDynamicInst:
  case ValueKind::AllocBoxInst:
  case ValueKind::AllocArrayInst:
  case ValueKind::MetatypeInst:
  case ValueKind::WitnessMethodInst:
    return true;

  // DeallocStackInst do not use reference counted values, only local storage
  // handles.
  case ValueKind::DeallocStackInst:
    return true;

  // Debug values do not use referenced counted values in a manner we care
  // about.
  case ValueKind::DebugValueInst:
  case ValueKind::DebugValueAddrInst:
    return true;

  // Casts do not use pointers in a manner that we care about since we strip
  // them during our analysis. The reason for this is if the cast is not dead
  // then there must be some other use after the cast that we will protect if a
  // release is not in between the cast and the use.
  case ValueKind::UpcastInst:
  case ValueKind::AddressToPointerInst:
  case ValueKind::PointerToAddressInst:
  case ValueKind::UncheckedRefCastInst:
  case ValueKind::UncheckedAddrCastInst:
  case ValueKind::RefToRawPointerInst:
  case ValueKind::RawPointerToRefInst:
  case ValueKind::UnconditionalCheckedCastInst:
    return true;

  // Typed GEPs do not use pointers. The user of the typed GEP may but we will
  // catch that via the dataflow.
  case ValueKind::StructExtractInst:
  case ValueKind::TupleExtractInst:
  case ValueKind::StructElementAddrInst:
  case ValueKind::TupleElementAddrInst:
  case ValueKind::UncheckedTakeEnumDataAddrInst:
  case ValueKind::RefElementAddrInst:
  case ValueKind::UncheckedEnumDataInst:
  case ValueKind::IndexAddrInst:
  case ValueKind::IndexRawPointerInst:
      return true;

  // Aggregate formation by themselves do not create new uses since it is their
  // users that would create the appropriate uses.
  case ValueKind::EnumInst:
  case ValueKind::StructInst:
  case ValueKind::TupleInst:
    return true;

  // Only uses non reference counted values.
  case ValueKind::CondFailInst:
    return true;

  case ValueKind::ApplyInst: {
    auto *AI = cast<ApplyInst>(Inst);

    // Certain builtin function refs we know can never use non-trivial values.
    if (auto *BFRI = dyn_cast<BuiltinFunctionRefInst>(AI->getCallee()))
      return canApplyOfBuiltinUseNonTrivialValues(AI, BFRI);

    return false;
  }

  default:
    return false;
  }
}

bool swift::arc::canUseValue(SILInstruction *User, SILValue Ptr,
                             AliasAnalysis *AA) {
  // If Inst is an instruction that we know can never use values with reference
  // semantics, return true.
  if (canInstUseRefCountValues(User))
    return false;

  // If the user is a load or a store and we can prove that it does not access
  // the object then return true.
  // Notice that we need to check all of the values of the object.
  if (isa<StoreInst>(User)) {
    for (int i = 0, e = Ptr->getNumTypes(); i < e; i++) {
      if (AA->mayWriteToMemory(User, SILValue(Ptr.getDef(), i)))
        return true;
    }
    return false;
  }

  if (isa<LoadInst>(User) ) {
    for (int i = 0, e = Ptr->getNumTypes(); i < e; i++) {
      if (AA->mayReadFromMemory(User, SILValue(Ptr.getDef(), i)))
        return true;
    }
    return false;
  }

  // TODO: If we add in alias analysis support here for apply inst, we will need
  // to check that the pointer does not escape.

  // Otherwise, assume that Inst can use Target.
  return true;
}

//===----------------------------------------------------------------------===//
// Utility Methods for determining use, decrement of values in a contiguous
// instruction range in one BB.
//===----------------------------------------------------------------------===//

/// Return true if \p Op has arc uses in the instruction range [Start, End). We
/// assume that Start and End are both in the same basic block.
bool swift::arc::
valueHasARCUsesInInstructionRange(SILValue Op,
                                  SILBasicBlock::iterator Start,
                                  SILBasicBlock::iterator End,
                                  AliasAnalysis *AA) {
  assert(Start->getParent() == End->getParent() &&
         "Start and End should be in the same basic block");

  // If Start == End, then we have an empty range, return false.
  if (Start == End)
    return false;

  // Otherwise, until Start != End.
  while (Start != End) {
    // Check if Start can use Op in an ARC relevant way. If so, return true.
    if (canUseValue(&*Start, Op, AA))
      return true;

    // Otherwise, increment our iterator.
    ++Start;
  }

  // If all such instructions can not use Op, return false.
  return false;
}

/// Return true if \p Op has instructions in the instruction range (Start, End]
/// which may decrement it. We assume that Start and End are both in the same
/// basic block.
bool swift::arc::
valueHasARCDecrementsInInstructionRange(SILValue Op,
                                        SILBasicBlock::iterator Start,
                                        SILBasicBlock::iterator End,
                                        AliasAnalysis *AA) {
  assert(Start->getParent() == End->getParent() &&
         "Start and End should be in the same basic block");

  // If Start == End, then we have an empty range, return false.
  if (Start == End)
    return false;

  // Otherwise, until Start != End.
  while (Start != End) {
    // Check if Start can decrement Op's ref count. If so, return true.
    if (canDecrementRefCount(&*Start, Op, AA))
      return true;
    // Otherwise, increment our iterator.
    ++Start;
  }

  // If all such instructions can not decrement Op, return false.
  return false;
}
<commit_msg>[arc-analysis] unchecked_ref_bit_cast can never use reference count values in a way we care about. Trivial bit casts do not either as long as we are not converting a ref count value to a trivial value.<commit_after>//===-------------- ARCAnalysis.cpp - SIL ARC Analysis --------------------===//
//
// 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 "sil-arc-analysis"
#include "swift/SILAnalysis/ARCAnalysis.h"
#include "swift/Basic/Fallthrough.h"
#include "swift/SIL/SILFunction.h"
#include "swift/SIL/SILInstruction.h"
#include "swift/SILAnalysis/AliasAnalysis.h"
#include "swift/SILAnalysis/ValueTracking.h"
#include "swift/SILPasses/Utils/Local.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/Debug.h"

using namespace swift;
using namespace swift::arc;

//===----------------------------------------------------------------------===//
//                             Decrement Analysis
//===----------------------------------------------------------------------===//

static bool isKnownToNotDecrementRefCount(FunctionRefInst *FRI) {
   return llvm::StringSwitch<bool>(FRI->getReferencedFunction()->getName())
     .Case("swift_keepAlive", true)
     .Case("_swift_isUniquelyReferenced", true)
     .Default(false);
}

static bool canApplyDecrementRefCount(ApplyInst *AI, SILValue Ptr,
                                      AliasAnalysis *AA) {
  // Ignore any thick functions for now due to us not handling the ref-counted
  // nature of its context.
  if (auto FTy = AI->getCallee().getType().getAs<SILFunctionType>())
    if (FTy->getExtInfo().hasContext())
      return true;

  // If we have a builtin that is side effect free, we can commute the
  // ApplyInst and the retain.
  if (auto *BI = dyn_cast<BuiltinFunctionRefInst>(AI->getCallee()))
    if (isSideEffectFree(BI))
      return false;

  // swift_keepAlive can not retain values. Remove this when we get rid of that.
  if (auto *FRI = dyn_cast<FunctionRefInst>(AI->getCallee()))
    if (isKnownToNotDecrementRefCount(FRI))
      return false;

  // Ok, this apply *MAY* decrement ref counts. Now our strategy is to attempt
  // to use properties of the pointer, the function's arguments, and the
  // function itself to prove that the pointer can not have its ref count be
  // effected by function.

  // TODO: Put in function property check section here when we get access to
  // such information.

  // First make sure that the underlying object of ptr is a local object which
  // does not escape. This prevents the apply from indirectly via the global
  // affecting the reference count of the pointer.
  if (!isNonEscapingLocalObject(getUnderlyingObject(Ptr)))
    return true;

  // Now that we know that the function can not affect the pointer indirectly,
  // make sure that the apply can not affect the pointer directly via the
  // applies arguments by proving that the pointer can not alias any of the
  // functions arguments.
  for (auto Op : AI->getArgumentsWithoutIndirectResult()) {
    for (int i = 0, e = Ptr->getNumTypes(); i < e; i++) {
      if (!AA->isNoAlias(Op, SILValue(Ptr.getDef(), i)))
        return true;
    }
  }

  // Success! The apply inst can not affect the reference count of ptr!
  return false;
}

/// Is the may have side effects user by the definition of its value kind unable
/// to decrement ref counts.
static bool canDecrementRefCountsByValueKind(SILInstruction *User) {
  assert(User->getMemoryBehavior()
           ==  SILInstruction::MemoryBehavior::MayHaveSideEffects &&
         "Invalid argument. Function is only applicable to isntructions with "
         "side effects.");
  switch (User->getKind()) {
  case ValueKind::DeallocStackInst:
  case ValueKind::StrongRetainInst:
  case ValueKind::StrongRetainAutoreleasedInst:
  case ValueKind::StrongRetainUnownedInst:
  case ValueKind::UnownedRetainInst:
  case ValueKind::PartialApplyInst:
  case ValueKind::FixLifetimeInst:
  case ValueKind::CopyBlockInst:
  case ValueKind::RetainValueInst:
  case ValueKind::CondFailInst:
    return false;

  case ValueKind::CopyAddrInst: {
    auto *CA = cast<CopyAddrInst>(User);
    if (CA->isInitializationOfDest() == IsInitialization_t::IsInitialization)
      return false;
  }
  SWIFT_FALLTHROUGH;
  default:
    return true;
  }
}

bool swift::arc::canDecrementRefCount(SILInstruction *User,
                                      SILValue Ptr, AliasAnalysis *AA) {
  // If we have an instruction that does not have *pure* side effects, it can
  // not affect ref counts.
  //
  // This distinguishes in between a "write" side effect and ref count side
  // effects.
  if (User->getMemoryBehavior() !=
      SILInstruction::MemoryBehavior::MayHaveSideEffects)
    return false;

  // Ok, we know that this instruction's generic behavior is
  // "MayHaveSideEffects". That is a criterion (it has effects not represented
  // by use-def chains) that is broader than ours (does it effect a particular
  // pointers ref counts). Thus begin by attempting to prove that the type of
  // instruction that the user is by definition can not decrement ref counts.
  if (!canDecrementRefCountsByValueKind(User))
    return false;

  // Ok, this instruction may have ref counts. If it is an apply, attempt to
  // prove that the callee is unable to affect Ptr.
  if (auto *AI = dyn_cast<ApplyInst>(User))
    return canApplyDecrementRefCount(AI, Ptr, AA);

  // We can not conservatively prove that this instruction can not decrement the
  // ref count of Ptr. So assume that it does.
  return true;
}

//===----------------------------------------------------------------------===//
//                                Use Analysis
//===----------------------------------------------------------------------===//

/// Returns true if a builtin apply can not use reference counted values.
///
/// The main case that this handles here are builtins that via read none imply
/// that they can not read globals and at the same time do not take any
/// non-trivial types via the arguments. The reason why we care about taking
/// non-trivial types as arguments is that we want to be careful in the face of
/// intrinsics that may be equivalent to bitcast and inttoptr operations.
static bool canApplyOfBuiltinUseNonTrivialValues(ApplyInst *AI,
                                                 BuiltinFunctionRefInst *BFRI) {
  SILModule &Mod = AI->getModule();

  auto &II = BFRI->getIntrinsicInfo();
  if (II.ID != llvm::Intrinsic::not_intrinsic) {
    if (II.hasAttribute(llvm::Attribute::ReadNone)) {
      for (auto &Op : AI->getArgumentOperands()) {
        if (!Op.get().getType().isTrivial(Mod)) {
          return false;
        }
      }
    }

    return true;
  }

  auto &BI = BFRI->getBuiltinInfo();
  if (BI.isReadNone()) {
    for (auto &Op : AI->getArgumentOperands()) {
      if (!Op.get().getType().isTrivial(Mod)) {
        return false;
      }
    }
  }

  return true;
}

/// Returns true if Inst is a function that we know never uses ref count values.
static bool canInstUseRefCountValues(SILInstruction *Inst) {
  switch (Inst->getKind()) {
  // These instructions do not use other values.
  case ValueKind::FunctionRefInst:
  case ValueKind::BuiltinFunctionRefInst:
  case ValueKind::IntegerLiteralInst:
  case ValueKind::FloatLiteralInst:
  case ValueKind::StringLiteralInst:
  case ValueKind::AllocStackInst:
  case ValueKind::AllocRefInst:
  case ValueKind::AllocRefDynamicInst:
  case ValueKind::AllocBoxInst:
  case ValueKind::AllocArrayInst:
  case ValueKind::MetatypeInst:
  case ValueKind::WitnessMethodInst:
    return true;

  // DeallocStackInst do not use reference counted values, only local storage
  // handles.
  case ValueKind::DeallocStackInst:
    return true;

  // Debug values do not use referenced counted values in a manner we care
  // about.
  case ValueKind::DebugValueInst:
  case ValueKind::DebugValueAddrInst:
    return true;

  // Casts do not use pointers in a manner that we care about since we strip
  // them during our analysis. The reason for this is if the cast is not dead
  // then there must be some other use after the cast that we will protect if a
  // release is not in between the cast and the use.
  case ValueKind::UpcastInst:
  case ValueKind::AddressToPointerInst:
  case ValueKind::PointerToAddressInst:
  case ValueKind::UncheckedRefCastInst:
  case ValueKind::UncheckedAddrCastInst:
  case ValueKind::RefToRawPointerInst:
  case ValueKind::RawPointerToRefInst:
  case ValueKind::UnconditionalCheckedCastInst:
  case ValueKind::UncheckedRefBitCastInst:
    return true;

  // If we have a trivial bit cast between trivial types, it is not something
  // that can use ref count ops in a way we care about. We do need to be careful
  // with uses with ref count inputs. In such a case, we assume conservatively
  // that the bit cast could use it.
  //
  // The reason why this is different from the ref bitcast is b/c the use of a
  // ref bit cast is still a ref typed value implying that our ARC dataflow will
  // properly handle its users. A conversion of a reference count value to a
  // trivial value though could be used as a trivial value in ways that ARC
  // dataflow will not understand implying we need to treat it as a use to be
  // safe.
  case ValueKind::UncheckedTrivialBitCastInst: {
    SILValue Op = cast<UncheckedTrivialBitCastInst>(Inst)->getOperand();
    return Op.getType().isTrivial(Inst->getModule());
  }

  // Typed GEPs do not use pointers. The user of the typed GEP may but we will
  // catch that via the dataflow.
  case ValueKind::StructExtractInst:
  case ValueKind::TupleExtractInst:
  case ValueKind::StructElementAddrInst:
  case ValueKind::TupleElementAddrInst:
  case ValueKind::UncheckedTakeEnumDataAddrInst:
  case ValueKind::RefElementAddrInst:
  case ValueKind::UncheckedEnumDataInst:
  case ValueKind::IndexAddrInst:
  case ValueKind::IndexRawPointerInst:
      return true;

  // Aggregate formation by themselves do not create new uses since it is their
  // users that would create the appropriate uses.
  case ValueKind::EnumInst:
  case ValueKind::StructInst:
  case ValueKind::TupleInst:
    return true;

  // Only uses non reference counted values.
  case ValueKind::CondFailInst:
    return true;

  case ValueKind::ApplyInst: {
    auto *AI = cast<ApplyInst>(Inst);

    // Certain builtin function refs we know can never use non-trivial values.
    if (auto *BFRI = dyn_cast<BuiltinFunctionRefInst>(AI->getCallee()))
      return canApplyOfBuiltinUseNonTrivialValues(AI, BFRI);

    return false;
  }

  default:
    return false;
  }
}

bool swift::arc::canUseValue(SILInstruction *User, SILValue Ptr,
                             AliasAnalysis *AA) {
  // If Inst is an instruction that we know can never use values with reference
  // semantics, return true.
  if (canInstUseRefCountValues(User))
    return false;

  // If the user is a load or a store and we can prove that it does not access
  // the object then return true.
  // Notice that we need to check all of the values of the object.
  if (isa<StoreInst>(User)) {
    for (int i = 0, e = Ptr->getNumTypes(); i < e; i++) {
      if (AA->mayWriteToMemory(User, SILValue(Ptr.getDef(), i)))
        return true;
    }
    return false;
  }

  if (isa<LoadInst>(User) ) {
    for (int i = 0, e = Ptr->getNumTypes(); i < e; i++) {
      if (AA->mayReadFromMemory(User, SILValue(Ptr.getDef(), i)))
        return true;
    }
    return false;
  }

  // TODO: If we add in alias analysis support here for apply inst, we will need
  // to check that the pointer does not escape.

  // Otherwise, assume that Inst can use Target.
  return true;
}

//===----------------------------------------------------------------------===//
// Utility Methods for determining use, decrement of values in a contiguous
// instruction range in one BB.
//===----------------------------------------------------------------------===//

/// Return true if \p Op has arc uses in the instruction range [Start, End). We
/// assume that Start and End are both in the same basic block.
bool swift::arc::
valueHasARCUsesInInstructionRange(SILValue Op,
                                  SILBasicBlock::iterator Start,
                                  SILBasicBlock::iterator End,
                                  AliasAnalysis *AA) {
  assert(Start->getParent() == End->getParent() &&
         "Start and End should be in the same basic block");

  // If Start == End, then we have an empty range, return false.
  if (Start == End)
    return false;

  // Otherwise, until Start != End.
  while (Start != End) {
    // Check if Start can use Op in an ARC relevant way. If so, return true.
    if (canUseValue(&*Start, Op, AA))
      return true;

    // Otherwise, increment our iterator.
    ++Start;
  }

  // If all such instructions can not use Op, return false.
  return false;
}

/// Return true if \p Op has instructions in the instruction range (Start, End]
/// which may decrement it. We assume that Start and End are both in the same
/// basic block.
bool swift::arc::
valueHasARCDecrementsInInstructionRange(SILValue Op,
                                        SILBasicBlock::iterator Start,
                                        SILBasicBlock::iterator End,
                                        AliasAnalysis *AA) {
  assert(Start->getParent() == End->getParent() &&
         "Start and End should be in the same basic block");

  // If Start == End, then we have an empty range, return false.
  if (Start == End)
    return false;

  // Otherwise, until Start != End.
  while (Start != End) {
    // Check if Start can decrement Op's ref count. If so, return true.
    if (canDecrementRefCount(&*Start, Op, AA))
      return true;
    // Otherwise, increment our iterator.
    ++Start;
  }

  // If all such instructions can not decrement Op, return false.
  return false;
}
<|endoftext|>


<commit_before>//===- SILCodeMotion.cpp - Code Motion Optimizations ----------------------===//
//
// 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 "codemotion"
#include "swift/SILPasses/Passes.h"
#include "swift/SIL/Dominance.h"
#include "swift/SIL/SILModule.h"
#include "swift/SIL/SILType.h"
#include "swift/SIL/SILValue.h"
#include "swift/SIL/SILBuilder.h"
#include "swift/SIL/SILVisitor.h"
#include "swift/SILPasses/Utils/Local.h"
#include "swift/SILPasses/Transforms.h"
#include "swift/SILAnalysis/AliasAnalysis.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/ScopedHashTable.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/RecyclingAllocator.h"

STATISTIC(NumSunk,   "Number of instructions sunk");
STATISTIC(NumDeadStores, "Number of dead stores removed");
STATISTIC(NumDupLoads,   "Number of dup loads removed");

using namespace swift;

static const int SinkSearchWindow = 6;

static bool isWriteMemBehavior(SILInstruction::MemoryBehavior B) {
  switch (B) {
  case SILInstruction::MemoryBehavior::MayWrite:
  case SILInstruction::MemoryBehavior::MayReadWrite:
  case SILInstruction::MemoryBehavior::MayHaveSideEffects:
    return true;
  case SILInstruction::MemoryBehavior::None:
  case SILInstruction::MemoryBehavior::MayRead:
    return false;
  }
}

namespace {

/// An abstract representation of a SIL Projection that allows one to refer to
/// either nominal fields or tuple indices.
class Projection {
  SILType Type;
  VarDecl *Decl;
  unsigned Index;

public:
  Projection(SILType T, VarDecl *D) : Type(T), Decl(D), Index(-1) { }
  Projection(SILType T, unsigned I) : Type(T), Decl(nullptr), Index(I) { }

  SILType getType() const { return Type; }
  VarDecl *getDecl() const { return Decl; }
  unsigned getIndex() const { return Index; }

  bool operator==(Projection &Other) const {
    if (Decl)
      return Decl == Other.getDecl();
    else
      return !Other.getDecl() && Index == Other.getIndex();
  }

  bool operator<(Projection Other) const {
    // If Proj1 is a decl...
    if (Decl) {
      // It should be sorted before Proj2 is Proj2 is not a decl. Otherwise
      // compare the pointers.
      if (auto OtherDecl = Other.getDecl())
        return uintptr_t(Decl) < uintptr_t(OtherDecl);
      return true;
    }

    // If Proj1 is not a decl, then if Proj2 is a decl, Proj1 is not before
    // Proj2. If Proj2 is not a decl, compare the indices.
    return !Other.getDecl() && (Index < Other.Index);
  }
};

} // end anonymous namespace.

static bool isAddressProjection(SILValue V) {
  switch (V->getKind()) {
  case ValueKind::StructElementAddrInst:
  case ValueKind::TupleElementAddrInst:
    return true;
  default:
    return false;
  }
}

// Given an already emitted load PrevLd, see if we can
static SILValue findExtractPathBetweenValues(LoadInst *PrevLI, LoadInst *LI) {
  SILValue PrevLIOp = PrevLI->getOperand();
  SILValue LIOp = LI->getOperand();

  // If they are equal, just return PrevLI.
  if (PrevLIOp == LIOp)
    return PrevLI;

  // Otherwise see if LI can be projection extracted from PrevLI. First see if
  // LI is a projection at all.
  llvm::SmallVector<Projection, 4> Projections;
  auto Iter = LIOp;
  while (isAddressProjection(Iter) && PrevLIOp != Iter) {
    if (auto *SEA = dyn_cast<StructElementAddrInst>(Iter.getDef()))
      Projections.push_back(Projection(Iter.getType(), SEA->getField()));
    else
      Projections.push_back(
        Projection(Iter.getType(),
                   cast<TupleElementAddrInst>(*Iter).getFieldNo()));
    Iter = cast<SILInstruction>(*Iter).getOperand(0);
  }

  // We could not find an extract path in between the two values.
  if (Projections.empty() || PrevLIOp != Iter)
    return SILValue();

  // Use the projection list we created to create the relevant extracts
  SILValue LastExtract = PrevLI;
  SILBuilder Builder(LI);
  while (!Projections.empty()) {
    auto P = Projections.pop_back_val();
    if (auto *D = P.getDecl()) {
      LastExtract = Builder.createStructExtract(LI->getLoc(), LastExtract,
                                                D,
                                                P.getType().getObjectType());
      cast<StructExtractInst>(*LastExtract).getStructDecl();
    } else {
      LastExtract = Builder.createTupleExtract(LI->getLoc(), LastExtract,
                                               P.getIndex(),
                                               P.getType().getObjectType());
      cast<TupleExtractInst>(*LastExtract).getTupleType();
    }
  }

  // Return the last extract we created.
  return LastExtract;
}

static void
invalidateAliasingLoads(SILInstruction *Inst,
                        llvm::SmallPtrSetImpl<LoadInst *> &Loads,
                        AliasAnalysis *AA) {
  llvm::SmallVector<LoadInst *, 4> InvalidatedLoadList;
  for (auto *LI : Loads)
    if (isWriteMemBehavior(AA->getMemoryBehavior(Inst, LI->getOperand())))
      InvalidatedLoadList.push_back(LI);
  for (auto *LI : InvalidatedLoadList) {
    DEBUG(llvm::dbgs() << "    Found an instruction that writes to memory "
          "such that a load is invalidated:" << *LI);
    Loads.erase(LI);
  }
}

/// \brief Promote stored values to loads, remove dead stores and merge
/// duplicated loads.
bool promoteMemoryOperationsInBlock(SILBasicBlock *BB, AliasAnalysis *AA) {
  bool Changed = false;
  StoreInst *PrevStore = 0;
  llvm::SmallPtrSet<LoadInst *, 8> Loads;

  auto II = BB->begin(), E = BB->end();
  while (II != E) {
    SILInstruction *Inst = II++;

    DEBUG(llvm::dbgs() << "Visiting: " << *Inst);

    // This is a StoreInst. Let's see if we can remove the previous stores.
    if (StoreInst *SI = dyn_cast<StoreInst>(Inst)) {
      // Invalidate any load that we can not prove does not read from the stores
      // destination.
      invalidateAliasingLoads(Inst, Loads, AA);

      // If we are storing to the previously stored address then delete the old
      // store.
      if (PrevStore && PrevStore->getDest() == SI->getDest()) {
        DEBUG(llvm::dbgs() << "    Found a dead previous store... Removing...:"
              << *PrevStore);
        Changed = true;
        recursivelyDeleteTriviallyDeadInstructions(PrevStore, true);
        PrevStore = SI;
        NumDeadStores++;
        continue;
      }
      PrevStore = SI;
      continue;
    }

    if (LoadInst *LI = dyn_cast<LoadInst>(Inst)) {
      // If we are loading a value that we just saved then use the saved value.
      if (PrevStore && PrevStore->getDest() == LI->getOperand()) {
        DEBUG(llvm::dbgs() << "    Forwarding store from: " << *PrevStore);
        SILValue(LI, 0).replaceAllUsesWith(PrevStore->getSrc());
        recursivelyDeleteTriviallyDeadInstructions(LI, true);
        Changed = true;
        NumDupLoads++;
        continue;
      }

      // Search the previous loads and replace the current load with one of the
      // previous loads.
      for (auto PrevLI : Loads) {
        SILValue ForwardingExtract = findExtractPathBetweenValues(PrevLI, LI);
        if (!ForwardingExtract)
          continue;

        DEBUG(llvm::dbgs() << "    Replacing with previous load: "
              << *ForwardingExtract);
        SILValue(LI, 0).replaceAllUsesWith(ForwardingExtract);
        recursivelyDeleteTriviallyDeadInstructions(LI, true);
        Changed = true;
        LI = 0;
        NumDupLoads++;
        break;
      }

      if (LI)
        Loads.insert(LI);
      continue;
    }

    // Retains write to memory but they don't affect loads and stores.
    if (isa<StrongRetainInst>(Inst)) {
      DEBUG(llvm::dbgs() << "    Found strong retain, does not affect loads and"
            " stores.\n");
      continue;
    }

    // Dealloc stack does not affect loads and stores.
    if (isa<DeallocStackInst>(Inst)) {
      DEBUG(llvm::dbgs() << "Found a dealloc stack. Does not affect loads and "
            "stores.\n");
      continue;
    }

    if (auto *AI = dyn_cast<ApplyInst>(Inst))
      if (auto *BI = dyn_cast<BuiltinFunctionRefInst>(&*AI->getCallee()))
        if (isReadNone(BI)) {
          DEBUG(llvm::dbgs() << "    Found readnone builtin, does not affect "
                "loads and stores.\n");
          continue;
        }

    // cond_fail does not read/write memory in a manner that we care about.
    if (isa<CondFailInst>(Inst)) {
      DEBUG(llvm::dbgs() << "    Found a cond fail, does not affect "
            "loads and stores.\n");
      continue;
    }

    // All other instructions that read from memory invalidate the store.
    if (Inst->mayReadFromMemory()) {
      DEBUG(llvm::dbgs() << "    Found an instruction that reads from memory."
            " Invalidating store.\n");
      PrevStore = 0;
    }

    // If we have an instruction that may write to memory and we can not prove
    // that it and its operands can not alias a load we have visited, invalidate
    // that load.
    if (Inst->mayWriteToMemory())
      // Invalidate any load that we can not prove does not read from one of the
      // writing instructions operands.
      invalidateAliasingLoads(Inst, Loads, AA);
  }

  return Changed;
}

/// \brief Returns True if we can sink this instruction to another basic block.
static bool canSinkInstruction(SILInstruction *Inst) {
  return Inst->use_empty() && !isa<TermInst>(Inst);
}

/// \brief Returns true if this instruction is a skip barrier, which means that
/// we can't sink other instructions past it.
static bool isSinkBarrier(SILInstruction *Inst) {
  // We know that some calls do not have side effects.
  if (const ApplyInst *AI = dyn_cast<ApplyInst>(Inst))
    if (BuiltinFunctionRefInst *FR =
        dyn_cast<BuiltinFunctionRefInst>(AI->getCallee().getDef()))
      return !isSideEffectFree(FR);

  if (isa<TermInst>(Inst))
    return false;

  if (Inst->mayHaveSideEffects())
    return true;

  return false;
}

/// \brief Search for an instruction that is identical to \p Iden by scanning
/// \p BB starting at the end of the block, stopping on sink barriers.
SILInstruction *findIdenticalInBlock(SILBasicBlock *BB, SILInstruction *Iden) {
  int SkipBudget = SinkSearchWindow;

  SILBasicBlock::iterator InstToSink = BB->getTerminator();

  while (SkipBudget) {
    // If we found a sinkable instruction that is identical to our goal
    // then return it.
    if (canSinkInstruction(InstToSink) && Iden->isIdenticalTo(InstToSink)) {
      DEBUG(llvm::dbgs() << "Found an identical instruction.");
      return InstToSink;
    }

    // If this instruction is a skip-barrier end the scan.
    if (isSinkBarrier(InstToSink))
      return nullptr;

    // If this is the first instruction in the block then we are done.
    if (InstToSink == BB->begin())
      return nullptr;

    SkipBudget--;
    InstToSink = std::prev(InstToSink);
    DEBUG(llvm::dbgs() << "Continuing scan. Next inst: " << *InstToSink);
  }

  return nullptr;
}

static bool sinkCodeFromPredecessors(SILBasicBlock *BB) {
  bool Changed = false;
  if (BB->pred_empty())
    return Changed;

  // This block must be the only successor of all the predecessors.
  for (auto P : BB->getPreds())
    if (P->getSingleSuccessor() != BB)
      return Changed;

  SILBasicBlock *FirstPred = *BB->pred_begin();
  // The first Pred must have at least one non-terminator.
  if (FirstPred->getTerminator() == FirstPred->begin())
    return Changed;

  DEBUG(llvm::dbgs() << " Sinking values from predecessors.\n");

  unsigned SkipBudget = SinkSearchWindow;

  // Start scanning backwards from the terminator.
  SILBasicBlock::iterator InstToSink = FirstPred->getTerminator();

  while (SkipBudget) {
    DEBUG(llvm::dbgs() << "Processing: " << *InstToSink);

    // Save the duplicated instructions in case we need to remove them.
    SmallVector<SILInstruction *, 4> Dups;

    if (canSinkInstruction(InstToSink)) {
      // For all preds:
      for (auto P : BB->getPreds()) {
        if (P == FirstPred)
          continue;

        // Search the duplicated instruction in the predecessor.
        if (SILInstruction *DupInst = findIdenticalInBlock(P, InstToSink)) {
          Dups.push_back(DupInst);
        } else {
          DEBUG(llvm::dbgs() << "Instruction mismatch.\n");
          Dups.clear();
          break;
        }
      }

      // If we found duplicated instructions, sink one of the copies and delete
      // the rest.
      if (Dups.size()) {
        DEBUG(llvm::dbgs() << "Moving: " << *InstToSink);
        InstToSink->moveBefore(BB->begin());
        Changed = true;
        for (auto I : Dups) {
          I->replaceAllUsesWith(InstToSink);
          I->eraseFromParent();
          NumSunk++;
        }

        // Restart the scan.
        InstToSink = FirstPred->getTerminator();
        DEBUG(llvm::dbgs() << "Restarting scan. Next inst: " << *InstToSink);
        continue;
      }
    }

    // If this instruction was a barrier then we can't sink anything else.
    if (isSinkBarrier(InstToSink)) {
      DEBUG(llvm::dbgs() << "Aborting on barrier: " << *InstToSink);
      return Changed;
    }

    // This is the first instruction, we are done.
    if (InstToSink == FirstPred->begin()) {
      DEBUG(llvm::dbgs() << "Reached the first instruction.");
      return Changed;
    }

    SkipBudget--;
    InstToSink = std::prev(InstToSink);
    DEBUG(llvm::dbgs() << "Continuing scan. Next inst: " << *InstToSink);
  }

  return Changed;
}

class SILCodeMotion : public SILFunctionTransform {

  /// The entry point to the transformation.
  void run() {
    SILFunction &F = *getFunction();

    DEBUG(llvm::dbgs() << "***** CodeMotion on function: " << F.getName() <<
          " *****\n");

    AliasAnalysis *AA = PM->getAnalysis<AliasAnalysis>();

    bool Changed = false;

    // Remove dead stores and merge duplicate loads.
    for (auto &BB : F)
      Changed |= promoteMemoryOperationsInBlock(&BB, AA);

    // Sink duplicated code from predecessors.
    for (auto &BB : F)
      Changed |= sinkCodeFromPredecessors(&BB);

    if (Changed)
      invalidateAnalysis(SILAnalysis::InvalidationKind::Instructions);
  }

  StringRef getName() override { return "SIL Code Motion"; }
};

SILTransform *swift::createCodeMotion() {
  return new SILCodeMotion();
}
<commit_msg>[sil-code-motion] Change debug assert into a proper assert.<commit_after>//===- SILCodeMotion.cpp - Code Motion Optimizations ----------------------===//
//
// 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 "codemotion"
#include "swift/SILPasses/Passes.h"
#include "swift/SIL/Dominance.h"
#include "swift/SIL/SILModule.h"
#include "swift/SIL/SILType.h"
#include "swift/SIL/SILValue.h"
#include "swift/SIL/SILBuilder.h"
#include "swift/SIL/SILVisitor.h"
#include "swift/SILPasses/Utils/Local.h"
#include "swift/SILPasses/Transforms.h"
#include "swift/SILAnalysis/AliasAnalysis.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/ScopedHashTable.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/RecyclingAllocator.h"

STATISTIC(NumSunk,   "Number of instructions sunk");
STATISTIC(NumDeadStores, "Number of dead stores removed");
STATISTIC(NumDupLoads,   "Number of dup loads removed");

using namespace swift;

static const int SinkSearchWindow = 6;

static bool isWriteMemBehavior(SILInstruction::MemoryBehavior B) {
  switch (B) {
  case SILInstruction::MemoryBehavior::MayWrite:
  case SILInstruction::MemoryBehavior::MayReadWrite:
  case SILInstruction::MemoryBehavior::MayHaveSideEffects:
    return true;
  case SILInstruction::MemoryBehavior::None:
  case SILInstruction::MemoryBehavior::MayRead:
    return false;
  }
}

namespace {

/// An abstract representation of a SIL Projection that allows one to refer to
/// either nominal fields or tuple indices.
class Projection {
  SILType Type;
  VarDecl *Decl;
  unsigned Index;

public:
  Projection(SILType T, VarDecl *D) : Type(T), Decl(D), Index(-1) { }
  Projection(SILType T, unsigned I) : Type(T), Decl(nullptr), Index(I) { }

  SILType getType() const { return Type; }
  VarDecl *getDecl() const { return Decl; }
  unsigned getIndex() const { return Index; }

  bool operator==(Projection &Other) const {
    if (Decl)
      return Decl == Other.getDecl();
    else
      return !Other.getDecl() && Index == Other.getIndex();
  }

  bool operator<(Projection Other) const {
    // If Proj1 is a decl...
    if (Decl) {
      // It should be sorted before Proj2 is Proj2 is not a decl. Otherwise
      // compare the pointers.
      if (auto OtherDecl = Other.getDecl())
        return uintptr_t(Decl) < uintptr_t(OtherDecl);
      return true;
    }

    // If Proj1 is not a decl, then if Proj2 is a decl, Proj1 is not before
    // Proj2. If Proj2 is not a decl, compare the indices.
    return !Other.getDecl() && (Index < Other.Index);
  }
};

} // end anonymous namespace.

static bool isAddressProjection(SILValue V) {
  switch (V->getKind()) {
  case ValueKind::StructElementAddrInst:
  case ValueKind::TupleElementAddrInst:
    return true;
  default:
    return false;
  }
}

// Given an already emitted load PrevLd, see if we can
static SILValue findExtractPathBetweenValues(LoadInst *PrevLI, LoadInst *LI) {
  SILValue PrevLIOp = PrevLI->getOperand();
  SILValue LIOp = LI->getOperand();

  // If they are equal, just return PrevLI.
  if (PrevLIOp == LIOp)
    return PrevLI;

  // Otherwise see if LI can be projection extracted from PrevLI. First see if
  // LI is a projection at all.
  llvm::SmallVector<Projection, 4> Projections;
  auto Iter = LIOp;
  while (isAddressProjection(Iter) && PrevLIOp != Iter) {
    if (auto *SEA = dyn_cast<StructElementAddrInst>(Iter.getDef()))
      Projections.push_back(Projection(Iter.getType(), SEA->getField()));
    else
      Projections.push_back(
        Projection(Iter.getType(),
                   cast<TupleElementAddrInst>(*Iter).getFieldNo()));
    Iter = cast<SILInstruction>(*Iter).getOperand(0);
  }

  // We could not find an extract path in between the two values.
  if (Projections.empty() || PrevLIOp != Iter)
    return SILValue();

  // Use the projection list we created to create the relevant extracts
  SILValue LastExtract = PrevLI;
  SILBuilder Builder(LI);
  while (!Projections.empty()) {
    auto P = Projections.pop_back_val();
    if (auto *D = P.getDecl()) {
      LastExtract = Builder.createStructExtract(LI->getLoc(), LastExtract,
                                                D,
                                                P.getType().getObjectType());
      assert(cast<StructExtractInst>(*LastExtract).getStructDecl() &&
             "Instruction must have a struct decl!");
    } else {
      LastExtract = Builder.createTupleExtract(LI->getLoc(), LastExtract,
                                               P.getIndex(),
                                               P.getType().getObjectType());
      assert(cast<TupleExtractInst>(*LastExtract).getTupleType() &&
             "Instruction must have a tuple type!");
    }
  }

  // Return the last extract we created.
  return LastExtract;
}

static void
invalidateAliasingLoads(SILInstruction *Inst,
                        llvm::SmallPtrSetImpl<LoadInst *> &Loads,
                        AliasAnalysis *AA) {
  llvm::SmallVector<LoadInst *, 4> InvalidatedLoadList;
  for (auto *LI : Loads)
    if (isWriteMemBehavior(AA->getMemoryBehavior(Inst, LI->getOperand())))
      InvalidatedLoadList.push_back(LI);
  for (auto *LI : InvalidatedLoadList) {
    DEBUG(llvm::dbgs() << "    Found an instruction that writes to memory "
          "such that a load is invalidated:" << *LI);
    Loads.erase(LI);
  }
}

/// \brief Promote stored values to loads, remove dead stores and merge
/// duplicated loads.
bool promoteMemoryOperationsInBlock(SILBasicBlock *BB, AliasAnalysis *AA) {
  bool Changed = false;
  StoreInst *PrevStore = 0;
  llvm::SmallPtrSet<LoadInst *, 8> Loads;

  auto II = BB->begin(), E = BB->end();
  while (II != E) {
    SILInstruction *Inst = II++;

    DEBUG(llvm::dbgs() << "Visiting: " << *Inst);

    // This is a StoreInst. Let's see if we can remove the previous stores.
    if (StoreInst *SI = dyn_cast<StoreInst>(Inst)) {
      // Invalidate any load that we can not prove does not read from the stores
      // destination.
      invalidateAliasingLoads(Inst, Loads, AA);

      // If we are storing to the previously stored address then delete the old
      // store.
      if (PrevStore && PrevStore->getDest() == SI->getDest()) {
        DEBUG(llvm::dbgs() << "    Found a dead previous store... Removing...:"
              << *PrevStore);
        Changed = true;
        recursivelyDeleteTriviallyDeadInstructions(PrevStore, true);
        PrevStore = SI;
        NumDeadStores++;
        continue;
      }
      PrevStore = SI;
      continue;
    }

    if (LoadInst *LI = dyn_cast<LoadInst>(Inst)) {
      // If we are loading a value that we just saved then use the saved value.
      if (PrevStore && PrevStore->getDest() == LI->getOperand()) {
        DEBUG(llvm::dbgs() << "    Forwarding store from: " << *PrevStore);
        SILValue(LI, 0).replaceAllUsesWith(PrevStore->getSrc());
        recursivelyDeleteTriviallyDeadInstructions(LI, true);
        Changed = true;
        NumDupLoads++;
        continue;
      }

      // Search the previous loads and replace the current load with one of the
      // previous loads.
      for (auto PrevLI : Loads) {
        SILValue ForwardingExtract = findExtractPathBetweenValues(PrevLI, LI);
        if (!ForwardingExtract)
          continue;

        DEBUG(llvm::dbgs() << "    Replacing with previous load: "
              << *ForwardingExtract);
        SILValue(LI, 0).replaceAllUsesWith(ForwardingExtract);
        recursivelyDeleteTriviallyDeadInstructions(LI, true);
        Changed = true;
        LI = 0;
        NumDupLoads++;
        break;
      }

      if (LI)
        Loads.insert(LI);
      continue;
    }

    // Retains write to memory but they don't affect loads and stores.
    if (isa<StrongRetainInst>(Inst)) {
      DEBUG(llvm::dbgs() << "    Found strong retain, does not affect loads and"
            " stores.\n");
      continue;
    }

    // Dealloc stack does not affect loads and stores.
    if (isa<DeallocStackInst>(Inst)) {
      DEBUG(llvm::dbgs() << "Found a dealloc stack. Does not affect loads and "
            "stores.\n");
      continue;
    }

    if (auto *AI = dyn_cast<ApplyInst>(Inst))
      if (auto *BI = dyn_cast<BuiltinFunctionRefInst>(&*AI->getCallee()))
        if (isReadNone(BI)) {
          DEBUG(llvm::dbgs() << "    Found readnone builtin, does not affect "
                "loads and stores.\n");
          continue;
        }

    // cond_fail does not read/write memory in a manner that we care about.
    if (isa<CondFailInst>(Inst)) {
      DEBUG(llvm::dbgs() << "    Found a cond fail, does not affect "
            "loads and stores.\n");
      continue;
    }

    // All other instructions that read from memory invalidate the store.
    if (Inst->mayReadFromMemory()) {
      DEBUG(llvm::dbgs() << "    Found an instruction that reads from memory."
            " Invalidating store.\n");
      PrevStore = 0;
    }

    // If we have an instruction that may write to memory and we can not prove
    // that it and its operands can not alias a load we have visited, invalidate
    // that load.
    if (Inst->mayWriteToMemory())
      // Invalidate any load that we can not prove does not read from one of the
      // writing instructions operands.
      invalidateAliasingLoads(Inst, Loads, AA);
  }

  return Changed;
}

/// \brief Returns True if we can sink this instruction to another basic block.
static bool canSinkInstruction(SILInstruction *Inst) {
  return Inst->use_empty() && !isa<TermInst>(Inst);
}

/// \brief Returns true if this instruction is a skip barrier, which means that
/// we can't sink other instructions past it.
static bool isSinkBarrier(SILInstruction *Inst) {
  // We know that some calls do not have side effects.
  if (const ApplyInst *AI = dyn_cast<ApplyInst>(Inst))
    if (BuiltinFunctionRefInst *FR =
        dyn_cast<BuiltinFunctionRefInst>(AI->getCallee().getDef()))
      return !isSideEffectFree(FR);

  if (isa<TermInst>(Inst))
    return false;

  if (Inst->mayHaveSideEffects())
    return true;

  return false;
}

/// \brief Search for an instruction that is identical to \p Iden by scanning
/// \p BB starting at the end of the block, stopping on sink barriers.
SILInstruction *findIdenticalInBlock(SILBasicBlock *BB, SILInstruction *Iden) {
  int SkipBudget = SinkSearchWindow;

  SILBasicBlock::iterator InstToSink = BB->getTerminator();

  while (SkipBudget) {
    // If we found a sinkable instruction that is identical to our goal
    // then return it.
    if (canSinkInstruction(InstToSink) && Iden->isIdenticalTo(InstToSink)) {
      DEBUG(llvm::dbgs() << "Found an identical instruction.");
      return InstToSink;
    }

    // If this instruction is a skip-barrier end the scan.
    if (isSinkBarrier(InstToSink))
      return nullptr;

    // If this is the first instruction in the block then we are done.
    if (InstToSink == BB->begin())
      return nullptr;

    SkipBudget--;
    InstToSink = std::prev(InstToSink);
    DEBUG(llvm::dbgs() << "Continuing scan. Next inst: " << *InstToSink);
  }

  return nullptr;
}

static bool sinkCodeFromPredecessors(SILBasicBlock *BB) {
  bool Changed = false;
  if (BB->pred_empty())
    return Changed;

  // This block must be the only successor of all the predecessors.
  for (auto P : BB->getPreds())
    if (P->getSingleSuccessor() != BB)
      return Changed;

  SILBasicBlock *FirstPred = *BB->pred_begin();
  // The first Pred must have at least one non-terminator.
  if (FirstPred->getTerminator() == FirstPred->begin())
    return Changed;

  DEBUG(llvm::dbgs() << " Sinking values from predecessors.\n");

  unsigned SkipBudget = SinkSearchWindow;

  // Start scanning backwards from the terminator.
  SILBasicBlock::iterator InstToSink = FirstPred->getTerminator();

  while (SkipBudget) {
    DEBUG(llvm::dbgs() << "Processing: " << *InstToSink);

    // Save the duplicated instructions in case we need to remove them.
    SmallVector<SILInstruction *, 4> Dups;

    if (canSinkInstruction(InstToSink)) {
      // For all preds:
      for (auto P : BB->getPreds()) {
        if (P == FirstPred)
          continue;

        // Search the duplicated instruction in the predecessor.
        if (SILInstruction *DupInst = findIdenticalInBlock(P, InstToSink)) {
          Dups.push_back(DupInst);
        } else {
          DEBUG(llvm::dbgs() << "Instruction mismatch.\n");
          Dups.clear();
          break;
        }
      }

      // If we found duplicated instructions, sink one of the copies and delete
      // the rest.
      if (Dups.size()) {
        DEBUG(llvm::dbgs() << "Moving: " << *InstToSink);
        InstToSink->moveBefore(BB->begin());
        Changed = true;
        for (auto I : Dups) {
          I->replaceAllUsesWith(InstToSink);
          I->eraseFromParent();
          NumSunk++;
        }

        // Restart the scan.
        InstToSink = FirstPred->getTerminator();
        DEBUG(llvm::dbgs() << "Restarting scan. Next inst: " << *InstToSink);
        continue;
      }
    }

    // If this instruction was a barrier then we can't sink anything else.
    if (isSinkBarrier(InstToSink)) {
      DEBUG(llvm::dbgs() << "Aborting on barrier: " << *InstToSink);
      return Changed;
    }

    // This is the first instruction, we are done.
    if (InstToSink == FirstPred->begin()) {
      DEBUG(llvm::dbgs() << "Reached the first instruction.");
      return Changed;
    }

    SkipBudget--;
    InstToSink = std::prev(InstToSink);
    DEBUG(llvm::dbgs() << "Continuing scan. Next inst: " << *InstToSink);
  }

  return Changed;
}

class SILCodeMotion : public SILFunctionTransform {

  /// The entry point to the transformation.
  void run() {
    SILFunction &F = *getFunction();

    DEBUG(llvm::dbgs() << "***** CodeMotion on function: " << F.getName() <<
          " *****\n");

    AliasAnalysis *AA = PM->getAnalysis<AliasAnalysis>();

    bool Changed = false;

    // Remove dead stores and merge duplicate loads.
    for (auto &BB : F)
      Changed |= promoteMemoryOperationsInBlock(&BB, AA);

    // Sink duplicated code from predecessors.
    for (auto &BB : F)
      Changed |= sinkCodeFromPredecessors(&BB);

    if (Changed)
      invalidateAnalysis(SILAnalysis::InvalidationKind::Instructions);
  }

  StringRef getName() override { return "SIL Code Motion"; }
};

SILTransform *swift::createCodeMotion() {
  return new SILCodeMotion();
}
<|endoftext|>


<commit_before>//===- SILCodeMotion.cpp - Code Motion Optimizations ----------------------===//
//
// 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 "codemotion"
#include "swift/SILPasses/Passes.h"
#include "swift/SIL/Dominance.h"
#include "swift/SIL/SILModule.h"
#include "swift/SIL/SILType.h"
#include "swift/SIL/SILValue.h"
#include "swift/SIL/SILBuilder.h"
#include "swift/SIL/SILVisitor.h"
#include "swift/SIL/Projection.h"
#include "swift/SILPasses/Utils/Local.h"
#include "swift/SILPasses/Transforms.h"
#include "swift/SILAnalysis/AliasAnalysis.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/ScopedHashTable.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/RecyclingAllocator.h"

STATISTIC(NumSunk,   "Number of instructions sunk");

using namespace swift;

static const int SinkSearchWindow = 6;

/// \brief Returns True if we can sink this instruction to another basic block.
static bool canSinkInstruction(SILInstruction *Inst) {
  return Inst->use_empty() && !isa<TermInst>(Inst);
}

/// \brief Returns true if this instruction is a skip barrier, which means that
/// we can't sink other instructions past it.
static bool isSinkBarrier(SILInstruction *Inst) {
  // We know that some calls do not have side effects.
  if (const ApplyInst *AI = dyn_cast<ApplyInst>(Inst))
    if (BuiltinFunctionRefInst *FR =
        dyn_cast<BuiltinFunctionRefInst>(AI->getCallee()))
      return !isSideEffectFree(FR);

  if (isa<TermInst>(Inst))
    return false;

  if (Inst->mayHaveSideEffects())
    return true;

  return false;
}

/// \brief Search for an instruction that is identical to \p Iden by scanning
/// \p BB starting at the end of the block, stopping on sink barriers.
SILInstruction *findIdenticalInBlock(SILBasicBlock *BB, SILInstruction *Iden) {
  int SkipBudget = SinkSearchWindow;

  SILBasicBlock::iterator InstToSink = BB->getTerminator();

  while (SkipBudget) {
    // If we found a sinkable instruction that is identical to our goal
    // then return it.
    if (canSinkInstruction(InstToSink) && Iden->isIdenticalTo(InstToSink)) {
      DEBUG(llvm::dbgs() << "Found an identical instruction.");
      return InstToSink;
    }

    // If this instruction is a skip-barrier end the scan.
    if (isSinkBarrier(InstToSink))
      return nullptr;

    // If this is the first instruction in the block then we are done.
    if (InstToSink == BB->begin())
      return nullptr;

    SkipBudget--;
    InstToSink = std::prev(InstToSink);
    DEBUG(llvm::dbgs() << "Continuing scan. Next inst: " << *InstToSink);
  }

  return nullptr;
}

static bool sinkCodeFromPredecessors(SILBasicBlock *BB) {
  bool Changed = false;
  if (BB->pred_empty())
    return Changed;

  // This block must be the only successor of all the predecessors.
  for (auto P : BB->getPreds())
    if (P->getSingleSuccessor() != BB)
      return Changed;

  SILBasicBlock *FirstPred = *BB->pred_begin();
  // The first Pred must have at least one non-terminator.
  if (FirstPred->getTerminator() == FirstPred->begin())
    return Changed;

  DEBUG(llvm::dbgs() << " Sinking values from predecessors.\n");

  unsigned SkipBudget = SinkSearchWindow;

  // Start scanning backwards from the terminator.
  SILBasicBlock::iterator InstToSink = FirstPred->getTerminator();

  while (SkipBudget) {
    DEBUG(llvm::dbgs() << "Processing: " << *InstToSink);

    // Save the duplicated instructions in case we need to remove them.
    SmallVector<SILInstruction *, 4> Dups;

    if (canSinkInstruction(InstToSink)) {
      // For all preds:
      for (auto P : BB->getPreds()) {
        if (P == FirstPred)
          continue;

        // Search the duplicated instruction in the predecessor.
        if (SILInstruction *DupInst = findIdenticalInBlock(P, InstToSink)) {
          Dups.push_back(DupInst);
        } else {
          DEBUG(llvm::dbgs() << "Instruction mismatch.\n");
          Dups.clear();
          break;
        }
      }

      // If we found duplicated instructions, sink one of the copies and delete
      // the rest.
      if (Dups.size()) {
        DEBUG(llvm::dbgs() << "Moving: " << *InstToSink);
        InstToSink->moveBefore(BB->begin());
        Changed = true;
        for (auto I : Dups) {
          I->replaceAllUsesWith(InstToSink);
          I->eraseFromParent();
          NumSunk++;
        }

        // Restart the scan.
        InstToSink = FirstPred->getTerminator();
        DEBUG(llvm::dbgs() << "Restarting scan. Next inst: " << *InstToSink);
        continue;
      }
    }

    // If this instruction was a barrier then we can't sink anything else.
    if (isSinkBarrier(InstToSink)) {
      DEBUG(llvm::dbgs() << "Aborting on barrier: " << *InstToSink);
      return Changed;
    }

    // This is the first instruction, we are done.
    if (InstToSink == FirstPred->begin()) {
      DEBUG(llvm::dbgs() << "Reached the first instruction.");
      return Changed;
    }

    SkipBudget--;
    InstToSink = std::prev(InstToSink);
    DEBUG(llvm::dbgs() << "Continuing scan. Next inst: " << *InstToSink);
  }

  return Changed;
}

namespace {
class SILCodeMotion : public SILFunctionTransform {

  /// The entry point to the transformation.
  void run() {
    SILFunction &F = *getFunction();

    DEBUG(llvm::dbgs() << "***** CodeMotion on function: " << F.getName() <<
          " *****\n");

    // Sink duplicated code from predecessors.
    bool Changed = false;
    for (auto &BB : F)
      Changed |= sinkCodeFromPredecessors(&BB);

    if (Changed)
      invalidateAnalysis(SILAnalysis::InvalidationKind::Instructions);
  }

  StringRef getName() override { return "SIL Code Motion"; }
};
} // end anonymous namespace

SILTransform *swift::createCodeMotion() {
  return new SILCodeMotion();
}
<commit_msg>Remove include of unused header.<commit_after>//===- SILCodeMotion.cpp - Code Motion Optimizations ----------------------===//
//
// 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 "codemotion"
#include "swift/SILPasses/Passes.h"
#include "swift/SIL/SILModule.h"
#include "swift/SIL/SILType.h"
#include "swift/SIL/SILValue.h"
#include "swift/SIL/SILBuilder.h"
#include "swift/SIL/SILVisitor.h"
#include "swift/SIL/Projection.h"
#include "swift/SILPasses/Utils/Local.h"
#include "swift/SILPasses/Transforms.h"
#include "swift/SILAnalysis/AliasAnalysis.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/ScopedHashTable.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/RecyclingAllocator.h"

STATISTIC(NumSunk,   "Number of instructions sunk");

using namespace swift;

static const int SinkSearchWindow = 6;

/// \brief Returns True if we can sink this instruction to another basic block.
static bool canSinkInstruction(SILInstruction *Inst) {
  return Inst->use_empty() && !isa<TermInst>(Inst);
}

/// \brief Returns true if this instruction is a skip barrier, which means that
/// we can't sink other instructions past it.
static bool isSinkBarrier(SILInstruction *Inst) {
  // We know that some calls do not have side effects.
  if (const ApplyInst *AI = dyn_cast<ApplyInst>(Inst))
    if (BuiltinFunctionRefInst *FR =
        dyn_cast<BuiltinFunctionRefInst>(AI->getCallee()))
      return !isSideEffectFree(FR);

  if (isa<TermInst>(Inst))
    return false;

  if (Inst->mayHaveSideEffects())
    return true;

  return false;
}

/// \brief Search for an instruction that is identical to \p Iden by scanning
/// \p BB starting at the end of the block, stopping on sink barriers.
SILInstruction *findIdenticalInBlock(SILBasicBlock *BB, SILInstruction *Iden) {
  int SkipBudget = SinkSearchWindow;

  SILBasicBlock::iterator InstToSink = BB->getTerminator();

  while (SkipBudget) {
    // If we found a sinkable instruction that is identical to our goal
    // then return it.
    if (canSinkInstruction(InstToSink) && Iden->isIdenticalTo(InstToSink)) {
      DEBUG(llvm::dbgs() << "Found an identical instruction.");
      return InstToSink;
    }

    // If this instruction is a skip-barrier end the scan.
    if (isSinkBarrier(InstToSink))
      return nullptr;

    // If this is the first instruction in the block then we are done.
    if (InstToSink == BB->begin())
      return nullptr;

    SkipBudget--;
    InstToSink = std::prev(InstToSink);
    DEBUG(llvm::dbgs() << "Continuing scan. Next inst: " << *InstToSink);
  }

  return nullptr;
}

static bool sinkCodeFromPredecessors(SILBasicBlock *BB) {
  bool Changed = false;
  if (BB->pred_empty())
    return Changed;

  // This block must be the only successor of all the predecessors.
  for (auto P : BB->getPreds())
    if (P->getSingleSuccessor() != BB)
      return Changed;

  SILBasicBlock *FirstPred = *BB->pred_begin();
  // The first Pred must have at least one non-terminator.
  if (FirstPred->getTerminator() == FirstPred->begin())
    return Changed;

  DEBUG(llvm::dbgs() << " Sinking values from predecessors.\n");

  unsigned SkipBudget = SinkSearchWindow;

  // Start scanning backwards from the terminator.
  SILBasicBlock::iterator InstToSink = FirstPred->getTerminator();

  while (SkipBudget) {
    DEBUG(llvm::dbgs() << "Processing: " << *InstToSink);

    // Save the duplicated instructions in case we need to remove them.
    SmallVector<SILInstruction *, 4> Dups;

    if (canSinkInstruction(InstToSink)) {
      // For all preds:
      for (auto P : BB->getPreds()) {
        if (P == FirstPred)
          continue;

        // Search the duplicated instruction in the predecessor.
        if (SILInstruction *DupInst = findIdenticalInBlock(P, InstToSink)) {
          Dups.push_back(DupInst);
        } else {
          DEBUG(llvm::dbgs() << "Instruction mismatch.\n");
          Dups.clear();
          break;
        }
      }

      // If we found duplicated instructions, sink one of the copies and delete
      // the rest.
      if (Dups.size()) {
        DEBUG(llvm::dbgs() << "Moving: " << *InstToSink);
        InstToSink->moveBefore(BB->begin());
        Changed = true;
        for (auto I : Dups) {
          I->replaceAllUsesWith(InstToSink);
          I->eraseFromParent();
          NumSunk++;
        }

        // Restart the scan.
        InstToSink = FirstPred->getTerminator();
        DEBUG(llvm::dbgs() << "Restarting scan. Next inst: " << *InstToSink);
        continue;
      }
    }

    // If this instruction was a barrier then we can't sink anything else.
    if (isSinkBarrier(InstToSink)) {
      DEBUG(llvm::dbgs() << "Aborting on barrier: " << *InstToSink);
      return Changed;
    }

    // This is the first instruction, we are done.
    if (InstToSink == FirstPred->begin()) {
      DEBUG(llvm::dbgs() << "Reached the first instruction.");
      return Changed;
    }

    SkipBudget--;
    InstToSink = std::prev(InstToSink);
    DEBUG(llvm::dbgs() << "Continuing scan. Next inst: " << *InstToSink);
  }

  return Changed;
}

namespace {
class SILCodeMotion : public SILFunctionTransform {

  /// The entry point to the transformation.
  void run() {
    SILFunction &F = *getFunction();

    DEBUG(llvm::dbgs() << "***** CodeMotion on function: " << F.getName() <<
          " *****\n");

    // Sink duplicated code from predecessors.
    bool Changed = false;
    for (auto &BB : F)
      Changed |= sinkCodeFromPredecessors(&BB);

    if (Changed)
      invalidateAnalysis(SILAnalysis::InvalidationKind::Instructions);
  }

  StringRef getName() override { return "SIL Code Motion"; }
};
} // end anonymous namespace

SILTransform *swift::createCodeMotion() {
  return new SILCodeMotion();
}
<|endoftext|>


<commit_before>// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.

#ifndef MFEM_MESH_OPERATORS
#define MFEM_MESH_OPERATORS

#include "../config/config.hpp"
#include "../general/array.hpp"
#include "mesh.hpp"
#include "../fem/estimators.hpp"

#include <limits>

namespace mfem
{

/** @brief The MeshOperator class serves as base for mesh manipulation classes.

    The purpose of the class is to provide a common abstraction for various
    AMR mesh control schemes. The typical use in an AMR loop is illustrated
    in examples 6/6p and 15/15p.

    A more general loop that also supports sequences of mesh operators with
    multiple updates looks like this:
    \code
       for (...)
       {
          // computations on the current mesh ...
          while (mesh_operator->Apply(mesh))
          {
             // update FiniteElementSpaces and interpolate GridFunctions ...
             if (mesh_operator->Continue()) { break; }
          }
          if (mesh_operator->Stop()) { break; }
       }
    \endcode
 */
class MeshOperator
{
private:
   int mod;

protected:
   friend class MeshOperatorSequence;

   /** @brief Implementation of the mesh operation. Invoked by the Apply()
              public method.
       @return Combination of ActionInfo constants. */
   virtual int ApplyImpl(Mesh &mesh) = 0;

   /// Constructor to be used by derived classes.
   MeshOperator() : mod(NONE) { }

public:
   /** @brief Action and information constants and masks.

       Combinations of constants are returned by the Apply() virtual method and
       can be accessed directly with GetActionInfo() or indirectly with methods
       like Stop(), Continue(), etc. The information bits (MASK_INFO) can be set
       only when the update bit is set (see MASK_UPDATE). */
   enum Action
   {
      NONE        = 0, /**< continue with computations without updating spaces
                            or grid-functions, i.e. the mesh was not modified */
      CONTINUE    = 1, /**< update spaces and grid-functions and continue
                            computations with the new mesh */
      STOP        = 2, ///< a stopping criterion was satisfied
      REPEAT      = 3, /**< update spaces and grid-functions and call the
                            operator Apply() method again */
      MASK_UPDATE = 1, ///< bit mask for the "update" bit
      MASK_ACTION = 3  ///< bit mask for all "action" bits
   };

   enum Info
   {
      REFINED     = 4*1, ///< the mesh was refined
      DEREFINED   = 4*2, ///< the mesh was de-refined
      REBALANCED  = 4*3, ///< the mesh was rebalanced
      MASK_INFO   = ~3   ///< bit mask for all "info" bits
   };

   /** @brief Perform the mesh operation.
       @return true if FiniteElementSpaces and GridFunctions need to be updated.
   */
   bool Apply(Mesh &mesh) { return ((mod = ApplyImpl(mesh)) & MASK_UPDATE); }

   /** @brief Check if STOP action is requested, e.g. stopping criterion is
       satisfied. */
   bool Stop() const { return ((mod & MASK_ACTION) == STOP); }
   /** @brief Check if REPEAT action is requested, i.e. FiniteElementSpaces and
       GridFunctions need to be updated, and Apply() must be called again. */
   bool Repeat() const { return ((mod & MASK_ACTION) == REPEAT); }
   /** @brief Check if CONTINUE action is requested, i.e. FiniteElementSpaces
       and GridFunctions need to be updated and computations should continue. */
   bool Continue() const { return ((mod & MASK_ACTION) == CONTINUE); }

   /// Check if the mesh was refined.
   bool Refined() const { return ((mod & MASK_INFO) == REFINED); }
   /// Check if the mesh was de-refined.
   bool Derefined() const { return ((mod & MASK_INFO) == DEREFINED); }
   /// Check if the mesh was rebalanced.
   bool Rebalanced() const { return ((mod & MASK_INFO) == REBALANCED); }

   /** @brief Get the full ActionInfo value generated by the last call to
       Apply(). */
   int GetActionInfo() const { return mod; }

   /// Reset the MeshOperator.
   virtual void Reset() = 0;

   /// The destructor is virtual.
   virtual ~MeshOperator() { }
};

/** Composition of MeshOperators into a sequence. Use the Append() method to
    create the sequence. */
class MeshOperatorSequence : public MeshOperator
{
protected:
   int step;
   Array<MeshOperator*> sequence; ///< MeshOperators sequence, owned by us.

   /// Do not allow copy construction, due to assumed ownership.
   MeshOperatorSequence(const MeshOperatorSequence &) { }

   /** @brief Apply the MeshOperatorSequence.
       @return ActionInfo value corresponding to the last applied operator from
       the sequence. */
   virtual int ApplyImpl(Mesh &mesh);

public:
   /// Constructor. Use the Append() method to create the sequence.
   MeshOperatorSequence() : step(-1) { }

   /// Delete all operators from the sequence.
   virtual ~MeshOperatorSequence();

   /** @brief Add an operator to the end of the sequence.
       The MeshOperatorSequence assumes ownership of the operator. */
   void Append(MeshOperator *mc) { sequence.Append(mc); }

   /// Access the underlying sequence.
   Array<MeshOperator*> &GetSequence() { return sequence; }

   /// Reset all MeshOperators in the sequence.
   virtual void Reset();
};

/** @brief Mesh refinement operator using an error threshold.

    This class uses the given ErrorEstimator to estimate local element errors
    and then marks for refinement all elements i such that loc_err_i > threshold.
    The threshold is computed as
    \code
       threshold = max(total_err * total_fraction * pow(num_elements,-1.0/p),
                       local_err_goal);
    \endcode
    where p (=total_norm_p), total_fraction, and local_err_goal are settable
    parameters, total_err = (sum_i local_err_i^p)^{1/p}, when p < inf,
    or total_err = max_i local_err_i, when p = inf.
*/
class ThresholdRefiner : public MeshOperator
{
protected:
   ErrorEstimator &estimator;
   AnisotropicErrorEstimator *aniso_estimator;

   double total_norm_p;
   double total_err_goal;
   double total_fraction;
   double local_err_goal;
   long   max_elements;

   double threshold;
   long num_marked_elements;

   Array<Refinement> marked_elements;
   long current_sequence;

   int non_conforming;
   int nc_limit;

   double GetNorm(const Vector &local_err, Mesh &mesh) const;

   /** @brief Apply the operator to the mesh.
       @return STOP if a stopping criterion is satisfied or no elements were
       marked for refinement; REFINED + CONTINUE otherwise. */
   virtual int ApplyImpl(Mesh &mesh);

public:
   /// Construct a ThresholdRefiner using the given ErrorEstimator.
   ThresholdRefiner(ErrorEstimator &est);

   // default destructor (virtual)

   /** @brief Set the exponent, p, of the discrete p-norm used to compute the
       total error from the local element errors. */
   void SetTotalErrorNormP(double norm_p = infinity())
   { total_norm_p = norm_p; }

   /** @brief Set the total error stopping criterion: stop when
       total_err <= total_err_goal. The default value is zero. */
   void SetTotalErrorGoal(double err_goal) { total_err_goal = err_goal; }

   /** @brief Set the total fraction used in the computation of the threshold.
       The default value is 1/2.
       @note If fraction == 0, total_err is essentially ignored in the threshold
       computation, i.e. threshold = local error goal. */
   void SetTotalErrorFraction(double fraction) { total_fraction = fraction; }

   /** @brief Set the local stopping criterion: stop when
       local_err_i <= local_err_goal. The default value is zero.
       @note If local_err_goal == 0, it is essentially ignored in the threshold
       computation. */
   void SetLocalErrorGoal(double err_goal) { local_err_goal = err_goal; }

   /** @brief Set the maximum number of elements stopping criterion: stop when
       the input mesh has num_elements >= max_elem. The default value is
       LONG_MAX. */
   void SetMaxElements(long max_elem) { max_elements = max_elem; }

   /// Use nonconforming refinement, if possible (triangles, quads, hexes).
   void PreferNonconformingRefinement() { non_conforming = 1; }

   /** @brief Use conforming refinement, if possible (triangles, tetrahedra)
       -- this is the default. */
   void PreferConformingRefinement() { non_conforming = -1; }

   /** @brief Set the maximum ratio of refinement levels of adjacent elements
       (0 = unlimited). */
   void SetNCLimit(int nc_limit)
   {
      MFEM_ASSERT(nc_limit >= 0, "Invalid NC limit");
      this->nc_limit = nc_limit;
   }

   /// Get the number of marked elements in the last Apply() call.
   long GetNumMarkedElements() const { return num_marked_elements; }

   /// Get the threshold used in the last Apply() call.
   double GetThreshold() const { return threshold; }

   /// Reset the associated estimator.
   virtual void Reset();
};

// TODO: BulkRefiner to refine a portion of the global error

/** @brief De-refinement operator using an error threshold.

    This de-refinement operator marks elements in the hierarchy whose children
    are leaves and their combined error is below a given threshold. The
    errors of the children are combined by one of the following operations:
    - op = 0: minimum of the errors
    - op = 1: sum of the errors (default)
    - op = 2: maximum of the errors. */
class ThresholdDerefiner : public MeshOperator
{
protected:
   ErrorEstimator &estimator;

   double threshold;
   int nc_limit, op;

   /** @brief Apply the operator to the mesh.
       @return DEREFINED + CONTINUE if some elements were de-refined; NONE
       otherwise. */
   virtual int ApplyImpl(Mesh &mesh);

public:
   /// Construct a ThresholdDerefiner using the given ErrorEstimator.
   ThresholdDerefiner(ErrorEstimator &est)
      : estimator(est)
   {
      threshold = 0.0;
      nc_limit = 0;
      op = 1;
   }

   // default destructor (virtual)

   /// Set the de-refinement threshold. The default value is zero.
   void SetThreshold(double thresh) { threshold = thresh; }

   void SetOp(int op) { this->op = op; }

   /** @brief Set the maximum ratio of refinement levels of adjacent elements
       (0 = unlimited). */
   void SetNCLimit(int nc_limit)
   {
      MFEM_ASSERT(nc_limit >= 0, "Invalid NC limit");
      this->nc_limit = nc_limit;
   }

   /// Reset the associated estimator.
   virtual void Reset() { estimator.Reset(); }
};

/** @brief Refinement operator to control data oscillation.

    This class uses the given computes osc_K(f) := || h ⋅ (I - Π) f ||_K  at
    each element K. Here, Π is the L2-projection and ||⋅||_K is the
    L2-norm, restricted to the element K. All elements satisfying the inequality
    \code
       osc_K(f) > threshold ⋅ ||f|| / sqrt(n_el),
    \endcode
    are refined. Here, threshold is a postive parameter, ||⋅|| is the
    L2-norm over the entire domain Ω, and n_el is the number of elements in the
    mesh.

    Note that if osc(f) = threshold ⋅ ||f|| / sqrt(n_el) for each K, then
    \code
       osc(f) = sqrt( sum_K osc_K^2(f)) = threshold ⋅ ||f||.
    \endcode
    This is the reason for the 1/sqrt(n_el) factor. */
class CoefficientRefiner : public MeshOperator
{
protected:
   int nc_limit = 1;
   int nonconforming = -1;
   int order;
   long max_elements = std::numeric_limits<long>::max();
   double threshold = 1.0e-2;
   double global_osc = 0.0;
   Array<int> mesh_refinements;
   Vector element_oscs;
   Coefficient *coeff = NULL;
   GridFunction *gf;
   const IntegrationRule *ir_default[Geometry::NumGeom];
   const IntegrationRule **irs = NULL;

   /** @brief Apply the operator to the mesh once.
       @return STOP if a stopping criterion is satisfied or no elements were
       marked for refinement; REFINED + CONTINUE otherwise. */
   virtual int ApplyImpl(Mesh &mesh);

public:
   /// Constructor
   CoefficientRefiner(int order_) : order(order_) { }

   /** @brief Apply the operator to the mesh max_it times or until tolerance
    *  achieved.
       @return STOP if a stopping criterion is satisfied or no elements were
       marked for refinement; REFINED + CONTINUE otherwise. */
   virtual int PreprocessMesh(Mesh &mesh, int max_it);

   int PreprocessMesh(Mesh &mesh)
   {
      int max_it = 10;
      return PreprocessMesh(mesh, max_it);
   }

   /// Set the refinement threshold. The default value is 1.0e-3.
   void SetThreshold(double threshold_) { threshold = threshold_; }

   /** @brief Set the maximum number of elements stopping criterion: stop when
       the input mesh has num_elements >= max_elem. The default value is
       LONG_MAX. */
   void SetMaxElements(long max_elements_) { max_elements = max_elements_; }

   /// Set the function f
   void SetCoefficient(Coefficient &coeff_)
   {
      global_osc = 0.0;
      coeff = &coeff_;
   }

   /// Reset the oscillation order
   void SetOrder(double order_) { order = order_; }

   /** @brief Set the maximum ratio of refinement levels of adjacent elements
       (0 = unlimited). The default value is 1, which helps ensure appropriate
       refinements in pathological situations where the default quadrature
       order is too low.  */
   void SetNCLimit(int nc_limit_)
   {
      MFEM_ASSERT(nc_limit_ >= 0, "Invalid NC limit");
      nc_limit = nc_limit_;
   }

   // Set a custom integration rule
   void SetIntRule(const IntegrationRule *irs_[]) { irs = irs_; }

   // Return the value of the global relative data oscillation
   double GetOsc() { return global_osc; }

   // Return the local relative data oscillation errors
   Vector GetLocalOscs()
   {
      MFEM_ASSERT(element_oscs.Size() > 0,
                  "Local oscillations have not been computed yet")
      return element_oscs;
   }

   /// Reset
   virtual void Reset();
};

/** @brief ParMesh rebalancing operator.

    If the mesh is a parallel mesh, perform rebalancing; otherwise, do nothing.
*/
class Rebalancer : public MeshOperator
{
protected:
   /** @brief Rebalance a parallel mesh (only non-conforming parallel meshes are
       supported).
       @return CONTINUE + REBALANCE on success, NONE otherwise. */
   virtual int ApplyImpl(Mesh &mesh);

public:
   /// Empty.
   virtual void Reset() { }
};

} // namespace mfem

#endif // MFEM_MESH_OPERATORS
<commit_msg>typo in comment<commit_after>// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.

#ifndef MFEM_MESH_OPERATORS
#define MFEM_MESH_OPERATORS

#include "../config/config.hpp"
#include "../general/array.hpp"
#include "mesh.hpp"
#include "../fem/estimators.hpp"

#include <limits>

namespace mfem
{

/** @brief The MeshOperator class serves as base for mesh manipulation classes.

    The purpose of the class is to provide a common abstraction for various
    AMR mesh control schemes. The typical use in an AMR loop is illustrated
    in examples 6/6p and 15/15p.

    A more general loop that also supports sequences of mesh operators with
    multiple updates looks like this:
    \code
       for (...)
       {
          // computations on the current mesh ...
          while (mesh_operator->Apply(mesh))
          {
             // update FiniteElementSpaces and interpolate GridFunctions ...
             if (mesh_operator->Continue()) { break; }
          }
          if (mesh_operator->Stop()) { break; }
       }
    \endcode
 */
class MeshOperator
{
private:
   int mod;

protected:
   friend class MeshOperatorSequence;

   /** @brief Implementation of the mesh operation. Invoked by the Apply()
              public method.
       @return Combination of ActionInfo constants. */
   virtual int ApplyImpl(Mesh &mesh) = 0;

   /// Constructor to be used by derived classes.
   MeshOperator() : mod(NONE) { }

public:
   /** @brief Action and information constants and masks.

       Combinations of constants are returned by the Apply() virtual method and
       can be accessed directly with GetActionInfo() or indirectly with methods
       like Stop(), Continue(), etc. The information bits (MASK_INFO) can be set
       only when the update bit is set (see MASK_UPDATE). */
   enum Action
   {
      NONE        = 0, /**< continue with computations without updating spaces
                            or grid-functions, i.e. the mesh was not modified */
      CONTINUE    = 1, /**< update spaces and grid-functions and continue
                            computations with the new mesh */
      STOP        = 2, ///< a stopping criterion was satisfied
      REPEAT      = 3, /**< update spaces and grid-functions and call the
                            operator Apply() method again */
      MASK_UPDATE = 1, ///< bit mask for the "update" bit
      MASK_ACTION = 3  ///< bit mask for all "action" bits
   };

   enum Info
   {
      REFINED     = 4*1, ///< the mesh was refined
      DEREFINED   = 4*2, ///< the mesh was de-refined
      REBALANCED  = 4*3, ///< the mesh was rebalanced
      MASK_INFO   = ~3   ///< bit mask for all "info" bits
   };

   /** @brief Perform the mesh operation.
       @return true if FiniteElementSpaces and GridFunctions need to be updated.
   */
   bool Apply(Mesh &mesh) { return ((mod = ApplyImpl(mesh)) & MASK_UPDATE); }

   /** @brief Check if STOP action is requested, e.g. stopping criterion is
       satisfied. */
   bool Stop() const { return ((mod & MASK_ACTION) == STOP); }
   /** @brief Check if REPEAT action is requested, i.e. FiniteElementSpaces and
       GridFunctions need to be updated, and Apply() must be called again. */
   bool Repeat() const { return ((mod & MASK_ACTION) == REPEAT); }
   /** @brief Check if CONTINUE action is requested, i.e. FiniteElementSpaces
       and GridFunctions need to be updated and computations should continue. */
   bool Continue() const { return ((mod & MASK_ACTION) == CONTINUE); }

   /// Check if the mesh was refined.
   bool Refined() const { return ((mod & MASK_INFO) == REFINED); }
   /// Check if the mesh was de-refined.
   bool Derefined() const { return ((mod & MASK_INFO) == DEREFINED); }
   /// Check if the mesh was rebalanced.
   bool Rebalanced() const { return ((mod & MASK_INFO) == REBALANCED); }

   /** @brief Get the full ActionInfo value generated by the last call to
       Apply(). */
   int GetActionInfo() const { return mod; }

   /// Reset the MeshOperator.
   virtual void Reset() = 0;

   /// The destructor is virtual.
   virtual ~MeshOperator() { }
};

/** Composition of MeshOperators into a sequence. Use the Append() method to
    create the sequence. */
class MeshOperatorSequence : public MeshOperator
{
protected:
   int step;
   Array<MeshOperator*> sequence; ///< MeshOperators sequence, owned by us.

   /// Do not allow copy construction, due to assumed ownership.
   MeshOperatorSequence(const MeshOperatorSequence &) { }

   /** @brief Apply the MeshOperatorSequence.
       @return ActionInfo value corresponding to the last applied operator from
       the sequence. */
   virtual int ApplyImpl(Mesh &mesh);

public:
   /// Constructor. Use the Append() method to create the sequence.
   MeshOperatorSequence() : step(-1) { }

   /// Delete all operators from the sequence.
   virtual ~MeshOperatorSequence();

   /** @brief Add an operator to the end of the sequence.
       The MeshOperatorSequence assumes ownership of the operator. */
   void Append(MeshOperator *mc) { sequence.Append(mc); }

   /// Access the underlying sequence.
   Array<MeshOperator*> &GetSequence() { return sequence; }

   /// Reset all MeshOperators in the sequence.
   virtual void Reset();
};

/** @brief Mesh refinement operator using an error threshold.

    This class uses the given ErrorEstimator to estimate local element errors
    and then marks for refinement all elements i such that loc_err_i > threshold.
    The threshold is computed as
    \code
       threshold = max(total_err * total_fraction * pow(num_elements,-1.0/p),
                       local_err_goal);
    \endcode
    where p (=total_norm_p), total_fraction, and local_err_goal are settable
    parameters, total_err = (sum_i local_err_i^p)^{1/p}, when p < inf,
    or total_err = max_i local_err_i, when p = inf.
*/
class ThresholdRefiner : public MeshOperator
{
protected:
   ErrorEstimator &estimator;
   AnisotropicErrorEstimator *aniso_estimator;

   double total_norm_p;
   double total_err_goal;
   double total_fraction;
   double local_err_goal;
   long   max_elements;

   double threshold;
   long num_marked_elements;

   Array<Refinement> marked_elements;
   long current_sequence;

   int non_conforming;
   int nc_limit;

   double GetNorm(const Vector &local_err, Mesh &mesh) const;

   /** @brief Apply the operator to the mesh.
       @return STOP if a stopping criterion is satisfied or no elements were
       marked for refinement; REFINED + CONTINUE otherwise. */
   virtual int ApplyImpl(Mesh &mesh);

public:
   /// Construct a ThresholdRefiner using the given ErrorEstimator.
   ThresholdRefiner(ErrorEstimator &est);

   // default destructor (virtual)

   /** @brief Set the exponent, p, of the discrete p-norm used to compute the
       total error from the local element errors. */
   void SetTotalErrorNormP(double norm_p = infinity())
   { total_norm_p = norm_p; }

   /** @brief Set the total error stopping criterion: stop when
       total_err <= total_err_goal. The default value is zero. */
   void SetTotalErrorGoal(double err_goal) { total_err_goal = err_goal; }

   /** @brief Set the total fraction used in the computation of the threshold.
       The default value is 1/2.
       @note If fraction == 0, total_err is essentially ignored in the threshold
       computation, i.e. threshold = local error goal. */
   void SetTotalErrorFraction(double fraction) { total_fraction = fraction; }

   /** @brief Set the local stopping criterion: stop when
       local_err_i <= local_err_goal. The default value is zero.
       @note If local_err_goal == 0, it is essentially ignored in the threshold
       computation. */
   void SetLocalErrorGoal(double err_goal) { local_err_goal = err_goal; }

   /** @brief Set the maximum number of elements stopping criterion: stop when
       the input mesh has num_elements >= max_elem. The default value is
       LONG_MAX. */
   void SetMaxElements(long max_elem) { max_elements = max_elem; }

   /// Use nonconforming refinement, if possible (triangles, quads, hexes).
   void PreferNonconformingRefinement() { non_conforming = 1; }

   /** @brief Use conforming refinement, if possible (triangles, tetrahedra)
       -- this is the default. */
   void PreferConformingRefinement() { non_conforming = -1; }

   /** @brief Set the maximum ratio of refinement levels of adjacent elements
       (0 = unlimited). */
   void SetNCLimit(int nc_limit)
   {
      MFEM_ASSERT(nc_limit >= 0, "Invalid NC limit");
      this->nc_limit = nc_limit;
   }

   /// Get the number of marked elements in the last Apply() call.
   long GetNumMarkedElements() const { return num_marked_elements; }

   /// Get the threshold used in the last Apply() call.
   double GetThreshold() const { return threshold; }

   /// Reset the associated estimator.
   virtual void Reset();
};

// TODO: BulkRefiner to refine a portion of the global error

/** @brief De-refinement operator using an error threshold.

    This de-refinement operator marks elements in the hierarchy whose children
    are leaves and their combined error is below a given threshold. The
    errors of the children are combined by one of the following operations:
    - op = 0: minimum of the errors
    - op = 1: sum of the errors (default)
    - op = 2: maximum of the errors. */
class ThresholdDerefiner : public MeshOperator
{
protected:
   ErrorEstimator &estimator;

   double threshold;
   int nc_limit, op;

   /** @brief Apply the operator to the mesh.
       @return DEREFINED + CONTINUE if some elements were de-refined; NONE
       otherwise. */
   virtual int ApplyImpl(Mesh &mesh);

public:
   /// Construct a ThresholdDerefiner using the given ErrorEstimator.
   ThresholdDerefiner(ErrorEstimator &est)
      : estimator(est)
   {
      threshold = 0.0;
      nc_limit = 0;
      op = 1;
   }

   // default destructor (virtual)

   /// Set the de-refinement threshold. The default value is zero.
   void SetThreshold(double thresh) { threshold = thresh; }

   void SetOp(int op) { this->op = op; }

   /** @brief Set the maximum ratio of refinement levels of adjacent elements
       (0 = unlimited). */
   void SetNCLimit(int nc_limit)
   {
      MFEM_ASSERT(nc_limit >= 0, "Invalid NC limit");
      this->nc_limit = nc_limit;
   }

   /// Reset the associated estimator.
   virtual void Reset() { estimator.Reset(); }
};

/** @brief Refinement operator to control data oscillation.

    This class computes osc_K(f) := || h ⋅ (I - Π) f ||_K  at each element K.
    Here, Π is the L2-projection and ||⋅||_K is the L2-norm, restricted to the
    element K. All elements satisfying the inequality
    \code
       osc_K(f) > threshold ⋅ ||f|| / sqrt(n_el),
    \endcode
    are refined. Here, threshold is a postive parameter, ||⋅|| is the L2-norm
    over the entire domain Ω, and n_el is the number of elements in the mesh.

    Note that if osc(f) = threshold ⋅ ||f|| / sqrt(n_el) for each K, then
    \code
       osc(f) = sqrt( sum_K osc_K^2(f)) = threshold ⋅ ||f||.
    \endcode
    This is the reason for the 1/sqrt(n_el) factor. */
class CoefficientRefiner : public MeshOperator
{
protected:
   int nc_limit = 1;
   int nonconforming = -1;
   int order;
   long max_elements = std::numeric_limits<long>::max();
   double threshold = 1.0e-2;
   double global_osc = 0.0;
   Array<int> mesh_refinements;
   Vector element_oscs;
   Coefficient *coeff = NULL;
   GridFunction *gf;
   const IntegrationRule *ir_default[Geometry::NumGeom];
   const IntegrationRule **irs = NULL;

   /** @brief Apply the operator to the mesh once.
       @return STOP if a stopping criterion is satisfied or no elements were
       marked for refinement; REFINED + CONTINUE otherwise. */
   virtual int ApplyImpl(Mesh &mesh);

public:
   /// Constructor
   CoefficientRefiner(int order_) : order(order_) { }

   /** @brief Apply the operator to the mesh max_it times or until tolerance
    *  achieved.
       @return STOP if a stopping criterion is satisfied or no elements were
       marked for refinement; REFINED + CONTINUE otherwise. */
   virtual int PreprocessMesh(Mesh &mesh, int max_it);

   int PreprocessMesh(Mesh &mesh)
   {
      int max_it = 10;
      return PreprocessMesh(mesh, max_it);
   }

   /// Set the refinement threshold. The default value is 1.0e-3.
   void SetThreshold(double threshold_) { threshold = threshold_; }

   /** @brief Set the maximum number of elements stopping criterion: stop when
       the input mesh has num_elements >= max_elem. The default value is
       LONG_MAX. */
   void SetMaxElements(long max_elements_) { max_elements = max_elements_; }

   /// Set the function f
   void SetCoefficient(Coefficient &coeff_)
   {
      global_osc = 0.0;
      coeff = &coeff_;
   }

   /// Reset the oscillation order
   void SetOrder(double order_) { order = order_; }

   /** @brief Set the maximum ratio of refinement levels of adjacent elements
       (0 = unlimited). The default value is 1, which helps ensure appropriate
       refinements in pathological situations where the default quadrature
       order is too low.  */
   void SetNCLimit(int nc_limit_)
   {
      MFEM_ASSERT(nc_limit_ >= 0, "Invalid NC limit");
      nc_limit = nc_limit_;
   }

   // Set a custom integration rule
   void SetIntRule(const IntegrationRule *irs_[]) { irs = irs_; }

   // Return the value of the global relative data oscillation
   double GetOsc() { return global_osc; }

   // Return the local relative data oscillation errors
   Vector GetLocalOscs()
   {
      MFEM_ASSERT(element_oscs.Size() > 0,
                  "Local oscillations have not been computed yet")
      return element_oscs;
   }

   /// Reset
   virtual void Reset();
};

/** @brief ParMesh rebalancing operator.

    If the mesh is a parallel mesh, perform rebalancing; otherwise, do nothing.
*/
class Rebalancer : public MeshOperator
{
protected:
   /** @brief Rebalance a parallel mesh (only non-conforming parallel meshes are
       supported).
       @return CONTINUE + REBALANCE on success, NONE otherwise. */
   virtual int ApplyImpl(Mesh &mesh);

public:
   /// Empty.
   virtual void Reset() { }
};

} // namespace mfem

#endif // MFEM_MESH_OPERATORS
<|endoftext|>