<commit_before>/*
Copyright libCellML Contributors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#include "libcellml/types.h"

#include "libcellml/component.h"
#include "libcellml/importsource.h"
#include "libcellml/model.h"
#include "libcellml/reset.h"
#include "libcellml/units.h"
#include "libcellml/variable.h"

#include "anycellmlelement_p.h"
#include "internaltypes.h"

namespace libcellml {

/**
 * @brief The UnitsItem::UnitsItemImpl struct.
 *
 * The private implementation for the UnitsItem class.
 */
struct UnitsItem::UnitsItemImpl
{
    UnitsWeakPtr mUnits; /**< Units that owns this units item.*/
    size_t mIndex = std::numeric_limits<size_t>::max(); /**< Index of this units item.*/
};

UnitsItem::UnitsItem(const UnitsPtr &units, size_t index)
    : mPimpl(new UnitsItemImpl())
{
    mPimpl->mUnits = units;
    mPimpl->mIndex = index;
}

UnitsItem::~UnitsItem()
{
    delete mPimpl;
}

UnitsItemPtr UnitsItem::create(const UnitsPtr &units, size_t index) noexcept
{
    return std::shared_ptr<UnitsItem> {new UnitsItem {units, index}};
}

UnitsPtr UnitsItem::units() const
{
    return mPimpl->mUnits.lock();
}

size_t UnitsItem::index() const
{
    return mPimpl->mIndex;
}

bool UnitsItem::isValid() const
{
    return mPimpl->mIndex < mPimpl->mUnits.lock()->unitCount();
}

/**
 * @brief The VariablePair::VariablePairImpl struct.
 *
 * The private implementation for the VariablePair class.
 */
struct VariablePair::VariablePairImpl
{
    VariableWeakPtr mVariable1; /**< Variable 1 for the pair.*/
    VariableWeakPtr mVariable2; /**< Variable 2 for the pair.*/
};

VariablePair::VariablePair(const VariablePtr &variable1, const VariablePtr &variable2)
    : mPimpl(new VariablePairImpl())
{
    mPimpl->mVariable1 = variable1;
    mPimpl->mVariable2 = variable2;
}

VariablePairPtr VariablePair::create(const VariablePtr &variable1, const VariablePtr &variable2) noexcept
{
    return std::shared_ptr<VariablePair> {new VariablePair {variable1, variable2}};
}

VariablePair::~VariablePair()
{
    delete mPimpl;
}

VariablePtr VariablePair::variable1() const
{
    return mPimpl->mVariable1.lock();
}

VariablePtr VariablePair::variable2() const
{
    return mPimpl->mVariable2.lock();
}

bool VariablePair::isValid() const
{
    return (mPimpl->mVariable1.lock() != nullptr) && (mPimpl->mVariable2.lock() != nullptr);
}

void AnyCellmlElement::AnyCellmlElementImpl::setComponent(const ComponentPtr &component, CellmlElementType type)
{
    mType = type;
    mItem = component;
}

void AnyCellmlElement::AnyCellmlElementImpl::setImportSource(const ImportSourcePtr &importSource)
{
    mType = CellmlElementType::IMPORT;
    mItem = importSource;
}

void AnyCellmlElement::AnyCellmlElementImpl::setModel(const ModelPtr &model, CellmlElementType type)
{
    mType = type;
    mItem = model;
}

void AnyCellmlElement::AnyCellmlElementImpl::setReset(const ResetPtr &reset, CellmlElementType type)
{
    mType = type;
    mItem = reset;
}

void AnyCellmlElement::AnyCellmlElementImpl::setUnits(const UnitsPtr &units)
{
    mType = CellmlElementType::UNITS;
    mItem = units;
}

void AnyCellmlElement::AnyCellmlElementImpl::setUnitsItem(const UnitsItemPtr &unitsItem)
{
    mType = CellmlElementType::UNIT;
    mItem = unitsItem;
}

void AnyCellmlElement::AnyCellmlElementImpl::setVariable(const VariablePtr &variable)
{
    mType = CellmlElementType::VARIABLE;
    mItem = variable;
}

void AnyCellmlElement::AnyCellmlElementImpl::setVariablePair(const VariablePairPtr &pair, CellmlElementType type)
{
    mType = type;
    mItem = pair;
}

void AnyCellmlElement::AnyCellmlElementImpl::setVariablePair(const VariablePtr &variable1, const VariablePtr &variable2, CellmlElementType type)
{
    mType = type;
    mItem = VariablePair::create(variable1, variable2);
}

AnyCellmlElement::AnyCellmlElement()
    : mPimpl(new AnyCellmlElementImpl())
{
}

AnyCellmlElement::~AnyCellmlElement()
{
    delete mPimpl;
}

CellmlElementType AnyCellmlElement::type() const
{
    return mPimpl->mType;
}

ComponentPtr AnyCellmlElement::component() const
{
    if ((mPimpl->mType == CellmlElementType::COMPONENT)
        || (mPimpl->mType == CellmlElementType::COMPONENT_REF)) {
        try {
            return std::any_cast<ComponentPtr>(mPimpl->mItem);
        } catch(const std::bad_any_cast& e) {
            return nullptr;
        }
    }

    return nullptr;
}

VariablePairPtr AnyCellmlElement::variablePair() const
{
    if ((mPimpl->mType == CellmlElementType::CONNECTION)
        || (mPimpl->mType == CellmlElementType::MAP_VARIABLES)) {
        try {
            return std::any_cast<VariablePairPtr>(mPimpl->mItem);
        } catch(const std::bad_any_cast& e) {
            return nullptr;
        }
    }

    return nullptr;
}

ImportSourcePtr AnyCellmlElement::importSource() const
{
    if (mPimpl->mType == CellmlElementType::IMPORT) {
        try {
            return std::any_cast<ImportSourcePtr>(mPimpl->mItem);
        } catch(const std::bad_any_cast& e) {
            return nullptr;
        }
    }

    return nullptr;
}

ModelPtr AnyCellmlElement::model() const
{
    if ((mPimpl->mType == CellmlElementType::ENCAPSULATION)
        || (mPimpl->mType == CellmlElementType::MODEL)) {
        try {
            return std::any_cast<ModelPtr>(mPimpl->mItem);
        } catch(const std::bad_any_cast& e) {
            return nullptr;
        }
    }

    return nullptr;
}

ResetPtr AnyCellmlElement::reset() const
{
    if (mPimpl->mType == CellmlElementType::RESET) {
        try {
            return std::any_cast<ResetPtr>(mPimpl->mItem);
        } catch(const std::bad_any_cast& e) {
            return nullptr;
        }
    }

    return nullptr;
}

ResetPtr AnyCellmlElement::resetValue() const
{
    if (mPimpl->mType == CellmlElementType::RESET_VALUE) {
        try {
            return std::any_cast<ResetPtr>(mPimpl->mItem);
        } catch(const std::bad_any_cast& e) {
            return nullptr;
        }
    }

    return nullptr;
}

ResetPtr AnyCellmlElement::testValue() const
{
    if (mPimpl->mType == CellmlElementType::TEST_VALUE) {
        try {
            return std::any_cast<ResetPtr>(mPimpl->mItem);
        } catch(const std::bad_any_cast& e) {
            return nullptr;
        }
    }

    return nullptr;
}

UnitsPtr AnyCellmlElement::units() const
{
    if (mPimpl->mType == CellmlElementType::UNITS) {
        try {
            return std::any_cast<UnitsPtr>(mPimpl->mItem);
        } catch(const std::bad_any_cast& e) {
            return nullptr;
        }
    }

    return nullptr;
}

UnitsItemPtr AnyCellmlElement::unitsItem() const
{
    if (mPimpl->mType == CellmlElementType::UNIT) {
        try {
            return std::any_cast<UnitsItemPtr>(mPimpl->mItem);
        } catch(const std::bad_any_cast& e) {
            return nullptr;
        }
    }

    return nullptr;
}

VariablePtr AnyCellmlElement::variable() const
{
    if (mPimpl->mType == CellmlElementType::VARIABLE) {
        try {
            return std::any_cast<VariablePtr>(mPimpl->mItem);
        } catch(const std::bad_any_cast& e) {
            return nullptr;
        }
    }

    return nullptr;
}

} // namespace libcellml
<commit_msg>Make MSVC and Clang happy.<commit_after>/*
Copyright libCellML Contributors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#include "libcellml/types.h"

#include "libcellml/component.h"
#include "libcellml/importsource.h"
#include "libcellml/model.h"
#include "libcellml/reset.h"
#include "libcellml/units.h"
#include "libcellml/variable.h"

#include "anycellmlelement_p.h"
#include "internaltypes.h"

namespace libcellml {

/**
 * @brief The UnitsItem::UnitsItemImpl struct.
 *
 * The private implementation for the UnitsItem class.
 */
struct UnitsItem::UnitsItemImpl
{
    UnitsWeakPtr mUnits; /**< Units that owns this units item.*/
    size_t mIndex = std::numeric_limits<size_t>::max(); /**< Index of this units item.*/
};

UnitsItem::UnitsItem(const UnitsPtr &units, size_t index)
    : mPimpl(new UnitsItemImpl())
{
    mPimpl->mUnits = units;
    mPimpl->mIndex = index;
}

UnitsItem::~UnitsItem()
{
    delete mPimpl;
}

UnitsItemPtr UnitsItem::create(const UnitsPtr &units, size_t index) noexcept
{
    return std::shared_ptr<UnitsItem> {new UnitsItem {units, index}};
}

UnitsPtr UnitsItem::units() const
{
    return mPimpl->mUnits.lock();
}

size_t UnitsItem::index() const
{
    return mPimpl->mIndex;
}

bool UnitsItem::isValid() const
{
    return mPimpl->mIndex < mPimpl->mUnits.lock()->unitCount();
}

/**
 * @brief The VariablePair::VariablePairImpl struct.
 *
 * The private implementation for the VariablePair class.
 */
struct VariablePair::VariablePairImpl
{
    VariableWeakPtr mVariable1; /**< Variable 1 for the pair.*/
    VariableWeakPtr mVariable2; /**< Variable 2 for the pair.*/
};

VariablePair::VariablePair(const VariablePtr &variable1, const VariablePtr &variable2)
    : mPimpl(new VariablePairImpl())
{
    mPimpl->mVariable1 = variable1;
    mPimpl->mVariable2 = variable2;
}

VariablePairPtr VariablePair::create(const VariablePtr &variable1, const VariablePtr &variable2) noexcept
{
    return std::shared_ptr<VariablePair> {new VariablePair {variable1, variable2}};
}

VariablePair::~VariablePair()
{
    delete mPimpl;
}

VariablePtr VariablePair::variable1() const
{
    return mPimpl->mVariable1.lock();
}

VariablePtr VariablePair::variable2() const
{
    return mPimpl->mVariable2.lock();
}

bool VariablePair::isValid() const
{
    return (mPimpl->mVariable1.lock() != nullptr) && (mPimpl->mVariable2.lock() != nullptr);
}

void AnyCellmlElement::AnyCellmlElementImpl::setComponent(const ComponentPtr &component, CellmlElementType type)
{
    mType = type;
    mItem = component;
}

void AnyCellmlElement::AnyCellmlElementImpl::setImportSource(const ImportSourcePtr &importSource)
{
    mType = CellmlElementType::IMPORT;
    mItem = importSource;
}

void AnyCellmlElement::AnyCellmlElementImpl::setModel(const ModelPtr &model, CellmlElementType type)
{
    mType = type;
    mItem = model;
}

void AnyCellmlElement::AnyCellmlElementImpl::setReset(const ResetPtr &reset, CellmlElementType type)
{
    mType = type;
    mItem = reset;
}

void AnyCellmlElement::AnyCellmlElementImpl::setUnits(const UnitsPtr &units)
{
    mType = CellmlElementType::UNITS;
    mItem = units;
}

void AnyCellmlElement::AnyCellmlElementImpl::setUnitsItem(const UnitsItemPtr &unitsItem)
{
    mType = CellmlElementType::UNIT;
    mItem = unitsItem;
}

void AnyCellmlElement::AnyCellmlElementImpl::setVariable(const VariablePtr &variable)
{
    mType = CellmlElementType::VARIABLE;
    mItem = variable;
}

void AnyCellmlElement::AnyCellmlElementImpl::setVariablePair(const VariablePairPtr &pair, CellmlElementType type)
{
    mType = type;
    mItem = pair;
}

void AnyCellmlElement::AnyCellmlElementImpl::setVariablePair(const VariablePtr &variable1, const VariablePtr &variable2, CellmlElementType type)
{
    mType = type;
    mItem = VariablePair::create(variable1, variable2);
}

AnyCellmlElement::AnyCellmlElement()
    : mPimpl(new AnyCellmlElementImpl())
{
}

AnyCellmlElement::~AnyCellmlElement()
{
    delete mPimpl;
}

CellmlElementType AnyCellmlElement::type() const
{
    return mPimpl->mType;
}

ComponentPtr AnyCellmlElement::component() const
{
    if ((mPimpl->mType == CellmlElementType::COMPONENT)
        || (mPimpl->mType == CellmlElementType::COMPONENT_REF)) {
        try {
            return std::any_cast<ComponentPtr>(mPimpl->mItem);
        } catch (const std::bad_any_cast &) {
            return nullptr;
        }
    }

    return nullptr;
}

VariablePairPtr AnyCellmlElement::variablePair() const
{
    if ((mPimpl->mType == CellmlElementType::CONNECTION)
        || (mPimpl->mType == CellmlElementType::MAP_VARIABLES)) {
        try {
            return std::any_cast<VariablePairPtr>(mPimpl->mItem);
        } catch (const std::bad_any_cast &) {
            return nullptr;
        }
    }

    return nullptr;
}

ImportSourcePtr AnyCellmlElement::importSource() const
{
    if (mPimpl->mType == CellmlElementType::IMPORT) {
        try {
            return std::any_cast<ImportSourcePtr>(mPimpl->mItem);
        } catch (const std::bad_any_cast &) {
            return nullptr;
        }
    }

    return nullptr;
}

ModelPtr AnyCellmlElement::model() const
{
    if ((mPimpl->mType == CellmlElementType::ENCAPSULATION)
        || (mPimpl->mType == CellmlElementType::MODEL)) {
        try {
            return std::any_cast<ModelPtr>(mPimpl->mItem);
        } catch (const std::bad_any_cast &) {
            return nullptr;
        }
    }

    return nullptr;
}

ResetPtr AnyCellmlElement::reset() const
{
    if (mPimpl->mType == CellmlElementType::RESET) {
        try {
            return std::any_cast<ResetPtr>(mPimpl->mItem);
        } catch (const std::bad_any_cast &) {
            return nullptr;
        }
    }

    return nullptr;
}

ResetPtr AnyCellmlElement::resetValue() const
{
    if (mPimpl->mType == CellmlElementType::RESET_VALUE) {
        try {
            return std::any_cast<ResetPtr>(mPimpl->mItem);
        } catch (const std::bad_any_cast &) {
            return nullptr;
        }
    }

    return nullptr;
}

ResetPtr AnyCellmlElement::testValue() const
{
    if (mPimpl->mType == CellmlElementType::TEST_VALUE) {
        try {
            return std::any_cast<ResetPtr>(mPimpl->mItem);
        } catch (const std::bad_any_cast &) {
            return nullptr;
        }
    }

    return nullptr;
}

UnitsPtr AnyCellmlElement::units() const
{
    if (mPimpl->mType == CellmlElementType::UNITS) {
        try {
            return std::any_cast<UnitsPtr>(mPimpl->mItem);
        } catch (const std::bad_any_cast &) {
            return nullptr;
        }
    }

    return nullptr;
}

UnitsItemPtr AnyCellmlElement::unitsItem() const
{
    if (mPimpl->mType == CellmlElementType::UNIT) {
        try {
            return std::any_cast<UnitsItemPtr>(mPimpl->mItem);
        } catch (const std::bad_any_cast &) {
            return nullptr;
        }
    }

    return nullptr;
}

VariablePtr AnyCellmlElement::variable() const
{
    if (mPimpl->mType == CellmlElementType::VARIABLE) {
        try {
            return std::any_cast<VariablePtr>(mPimpl->mItem);
        } catch (const std::bad_any_cast &) {
            return nullptr;
        }
    }

    return nullptr;
}

} // namespace libcellml
<|endoftext|>


<commit_before>//===--- SILGlobalVariable.cpp - Defines SILGlobalVariable structure ------===//
//
// 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
//
//===----------------------------------------------------------------------===//

#include "swift/SIL/SILGlobalVariable.h"
#include "swift/SIL/SILModule.h"

using namespace swift;

SILGlobalVariable *SILGlobalVariable::create(SILModule &M, SILLinkage linkage,
                                             bool IsFragile,
                                             StringRef name,
                                             SILType loweredType,
                                             Optional<SILLocation> loc,
                                             VarDecl *Decl) {
  // Get a StringMapEntry for the variable.  As a sop to error cases,
  // allow the name to have an empty string.
  llvm::StringMapEntry<SILGlobalVariable*> *entry = nullptr;
  if (!name.empty()) {
    entry = &*M.GlobalVariableTable.insert(std::make_pair(name, nullptr)).first;
    assert(!entry->getValue() && "global variable already exists");
    name = entry->getKey();
  }

  auto var = new (M) SILGlobalVariable(M, linkage, IsFragile, name,
                                       loweredType, loc, Decl);

  if (entry) entry->setValue(var);
  return var;
}

SILGlobalVariable::SILGlobalVariable(SILModule &Module, SILLinkage Linkage,
                                     bool IsFragile,
                                     StringRef Name, SILType LoweredType,
                                     Optional<SILLocation> Loc, VarDecl *Decl)
  : Module(Module),
    Name(Name),
    LoweredType(LoweredType),
    Location(Loc),
    Linkage(unsigned(Linkage)),
    Fragile(IsFragile),
	VDecl(Decl) {
  IsDeclaration = isAvailableExternally(Linkage);
  setLet(Decl ? Decl->isLet() : false);
  InitializerF = nullptr;
  Module.silGlobals.push_back(this);
}

void SILGlobalVariable::setInitializer(SILFunction *InitF) {
  if (InitializerF)
    InitializerF->decrementRefCount();
  // Increment the ref count to make sure it will not be eliminated.
  InitF->incrementRefCount();
  InitializerF = InitF;
}

SILGlobalVariable::~SILGlobalVariable() {
  getModule().GlobalVariableTable.erase(Name);
}

static bool analyzeStaticInitializer(SILFunction *F, SILInstruction *&Val,
                                     SILGlobalVariable *&GVar) {
  Val = nullptr;
  GVar = nullptr;
  // We only handle a single SILBasicBlock for now.
  if (F->size() != 1)
    return false;

  SILBasicBlock *BB = &F->front();
  GlobalAddrInst *SGA = nullptr;
  bool HasStore = false;
  for (auto &I : *BB) {
    // Make sure we have a single GlobalAddrInst and a single StoreInst.
    // And the StoreInst writes to the GlobalAddrInst.
    if (auto *sga = dyn_cast<GlobalAddrInst>(&I)) {
      if (SGA)
        return false;
      SGA = sga;
      GVar = SGA->getReferencedGlobal();
    } else if (auto *SI = dyn_cast<StoreInst>(&I)) {
      if (HasStore || SI->getDest().getDef() != SGA)
        return false;
      HasStore = true;
      Val = dyn_cast<SILInstruction>(SI->getSrc().getDef());

      // We only handle StructInst being stored to a global variable for now.
      if (!isa<StructInst>(Val))
        return false;
    } else if (auto *ti = dyn_cast<TupleInst>(&I)) {
      if (ti->getNumOperands())
        return false;
    } else {
      if (I.getKind() != ValueKind::ReturnInst &&
          I.getKind() != ValueKind::StructInst &&
          I.getKind() != ValueKind::IntegerLiteralInst &&
          I.getKind() != ValueKind::FloatLiteralInst &&
          I.getKind() != ValueKind::StringLiteralInst)
        return false;
    }
  }
  return true;
}

bool SILGlobalVariable::canBeStaticInitializer(SILFunction *F) {
  SILInstruction *dummySI;
  SILGlobalVariable *dummyGV;
  return analyzeStaticInitializer(F, dummySI, dummyGV);
}

/// Check if a given SILFunction can be a static initializer. If yes, return
/// the SILGlobalVariable that it writes to.
SILGlobalVariable *SILGlobalVariable::getVariableOfStaticInitializer(
                     SILFunction *F) {
  SILInstruction *dummySI;
  SILGlobalVariable *GV;
  if(analyzeStaticInitializer(F, dummySI, GV))
    return GV;
  return nullptr;
}

/// Return the value that is written into the global variable.
SILInstruction *SILGlobalVariable::getValueOfStaticInitializer() {
  if (!InitializerF)
    return nullptr;

  SILInstruction *SI;
  SILGlobalVariable *dummyGV;
  if(analyzeStaticInitializer(InitializerF, SI, dummyGV))
    return SI;
  return nullptr;
}
<commit_msg>[globalopt] fptrunc(float_literal) can be considered to be a simple static initializer.<commit_after>//===--- SILGlobalVariable.cpp - Defines SILGlobalVariable structure ------===//
//
// 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
//
//===----------------------------------------------------------------------===//

#include "swift/SIL/SILGlobalVariable.h"
#include "swift/SIL/SILModule.h"

using namespace swift;

SILGlobalVariable *SILGlobalVariable::create(SILModule &M, SILLinkage linkage,
                                             bool IsFragile,
                                             StringRef name,
                                             SILType loweredType,
                                             Optional<SILLocation> loc,
                                             VarDecl *Decl) {
  // Get a StringMapEntry for the variable.  As a sop to error cases,
  // allow the name to have an empty string.
  llvm::StringMapEntry<SILGlobalVariable*> *entry = nullptr;
  if (!name.empty()) {
    entry = &*M.GlobalVariableTable.insert(std::make_pair(name, nullptr)).first;
    assert(!entry->getValue() && "global variable already exists");
    name = entry->getKey();
  }

  auto var = new (M) SILGlobalVariable(M, linkage, IsFragile, name,
                                       loweredType, loc, Decl);

  if (entry) entry->setValue(var);
  return var;
}

SILGlobalVariable::SILGlobalVariable(SILModule &Module, SILLinkage Linkage,
                                     bool IsFragile,
                                     StringRef Name, SILType LoweredType,
                                     Optional<SILLocation> Loc, VarDecl *Decl)
  : Module(Module),
    Name(Name),
    LoweredType(LoweredType),
    Location(Loc),
    Linkage(unsigned(Linkage)),
    Fragile(IsFragile),
	VDecl(Decl) {
  IsDeclaration = isAvailableExternally(Linkage);
  setLet(Decl ? Decl->isLet() : false);
  InitializerF = nullptr;
  Module.silGlobals.push_back(this);
}

void SILGlobalVariable::setInitializer(SILFunction *InitF) {
  if (InitializerF)
    InitializerF->decrementRefCount();
  // Increment the ref count to make sure it will not be eliminated.
  InitF->incrementRefCount();
  InitializerF = InitF;
}

SILGlobalVariable::~SILGlobalVariable() {
  getModule().GlobalVariableTable.erase(Name);
}

static bool analyzeStaticInitializer(SILFunction *F, SILInstruction *&Val,
                                     SILGlobalVariable *&GVar) {
  Val = nullptr;
  GVar = nullptr;
  // We only handle a single SILBasicBlock for now.
  if (F->size() != 1)
    return false;

  SILBasicBlock *BB = &F->front();
  GlobalAddrInst *SGA = nullptr;
  bool HasStore = false;
  for (auto &I : *BB) {
    // Make sure we have a single GlobalAddrInst and a single StoreInst.
    // And the StoreInst writes to the GlobalAddrInst.
    if (auto *sga = dyn_cast<GlobalAddrInst>(&I)) {
      if (SGA)
        return false;
      SGA = sga;
      GVar = SGA->getReferencedGlobal();
    } else if (auto *SI = dyn_cast<StoreInst>(&I)) {
      if (HasStore || SI->getDest().getDef() != SGA)
        return false;
      HasStore = true;
      Val = dyn_cast<SILInstruction>(SI->getSrc().getDef());

      // We only handle StructInst being stored to a global variable for now.
      if (!isa<StructInst>(Val))
        return false;
    } else if (auto *ti = dyn_cast<TupleInst>(&I)) {
      if (ti->getNumOperands())
        return false;
    } else {

      if (auto *bi = dyn_cast<BuiltinInst>(&I)) {
        switch (bi->getBuiltinInfo().ID) {
        case BuiltinValueKind::FPTrunc:
          if (isa<LiteralInst>(bi->getArguments()[0]))
            continue;
          break;
        default:
          return false;
        }
      }

      if (I.getKind() != ValueKind::ReturnInst &&
          I.getKind() != ValueKind::StructInst &&
          I.getKind() != ValueKind::IntegerLiteralInst &&
          I.getKind() != ValueKind::FloatLiteralInst &&
          I.getKind() != ValueKind::StringLiteralInst)
        return false;
    }
  }
  return true;
}

bool SILGlobalVariable::canBeStaticInitializer(SILFunction *F) {
  SILInstruction *dummySI;
  SILGlobalVariable *dummyGV;
  return analyzeStaticInitializer(F, dummySI, dummyGV);
}

/// Check if a given SILFunction can be a static initializer. If yes, return
/// the SILGlobalVariable that it writes to.
SILGlobalVariable *SILGlobalVariable::getVariableOfStaticInitializer(
                     SILFunction *F) {
  SILInstruction *dummySI;
  SILGlobalVariable *GV;
  if(analyzeStaticInitializer(F, dummySI, GV))
    return GV;
  return nullptr;
}

/// Return the value that is written into the global variable.
SILInstruction *SILGlobalVariable::getValueOfStaticInitializer() {
  if (!InitializerF)
    return nullptr;

  SILInstruction *SI;
  SILGlobalVariable *dummyGV;
  if(analyzeStaticInitializer(InitializerF, SI, dummyGV))
    return SI;
  return nullptr;
}
<|endoftext|>


<commit_before>//===-- X86JITInfo.cpp - Implement the JIT interfaces for the X86 target --===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the JIT interfaces for the X86 target.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "jit"
#include "X86JITInfo.h"
#include "X86Relocations.h"
#include "llvm/CodeGen/MachineCodeEmitter.h"
#include "llvm/Config/alloca.h"
#include <cstdlib>
#include <iostream>
using namespace llvm;

#ifdef _MSC_VER
  extern "C" void *_AddressOfReturnAddress(void);
  #pragma intrinsic(_AddressOfReturnAddress)
#endif

void X86JITInfo::replaceMachineCodeForFunction(void *Old, void *New) {
  unsigned char *OldByte = (unsigned char *)Old;
  *OldByte++ = 0xE9;                // Emit JMP opcode.
  unsigned *OldWord = (unsigned *)OldByte;
  unsigned NewAddr = (intptr_t)New;
  unsigned OldAddr = (intptr_t)OldWord;
  *OldWord = NewAddr - OldAddr - 4; // Emit PC-relative addr of New code.
}

/// JITCompilerFunction - This contains the address of the JIT function used to
/// compile a function lazily.
static TargetJITInfo::JITCompilerFn JITCompilerFunction;

// Provide a wrapper for X86CompilationCallback2 that saves non-traditional
// callee saved registers, for the fastcc calling convention.
extern "C" {
#if defined(__i386__) || defined(i386) || defined(_M_IX86)
#ifndef _MSC_VER
  void X86CompilationCallback(void);
  asm(
    ".text\n"
    ".align 8\n"
#if defined(__CYGWIN__) || defined(__APPLE__) || defined(__MINGW32__)
    ".globl _X86CompilationCallback\n"
  "_X86CompilationCallback:\n"
#else
    ".globl X86CompilationCallback\n"
  "X86CompilationCallback:\n"
#endif
    "pushl   %ebp\n"
    "movl    %esp, %ebp\n"    // Standard prologue
    "pushl   %eax\n"
    "pushl   %edx\n"          // save EAX/EDX
#if defined(__CYGWIN__) || defined(__MINGW32__)
    "call    _X86CompilationCallback2\n"
#elif defined(__APPLE__)
    "movl    4(%ebp), %eax\n" // load the address of return address
    "movl    $24, %edx\n"     // if the opcode of the instruction at the
    "cmpb    $-51, (%eax)\n"  // return address is our 0xCD marker, then
    "movl    $12, %eax\n"     // subtract 24 from %esp to realign it to 16
    "cmovne  %eax, %edx\n"    // bytes after the push of edx, the amount to.
    "subl    %edx, %esp\n"    // the push of edx to keep it aligned.
    "pushl   %edx\n"          // subtract.  Otherwise, subtract 12 bytes after
    "call    _X86CompilationCallback2\n"
    "popl    %edx\n"
    "addl    %edx, %esp\n"
#else
    "call X86CompilationCallback2\n"
#endif
    "popl    %edx\n"
    "popl    %eax\n"
    "popl    %ebp\n"
    "ret\n");
#else
  void X86CompilationCallback2(void);

  _declspec(naked) void X86CompilationCallback(void) {
    __asm {
      push  eax
      push  edx
      call  X86CompilationCallback2
      pop   edx
      pop   eax
      ret
    }
  }
#endif // _MSC_VER

#else // Not an i386 host
  void X86CompilationCallback() {
    std::cerr << "Cannot call X86CompilationCallback() on a non-x86 arch!\n";
    abort();
  }
#endif
}

/// X86CompilationCallback - This is the target-specific function invoked by the
/// function stub when we did not know the real target of a call.  This function
/// must locate the start of the stub or call site and pass it into the JIT
/// compiler function.
extern "C" void X86CompilationCallback2() {
#ifdef _MSC_VER
  assert(sizeof(size_t) == 4); // FIXME: handle Win64
  unsigned *RetAddrLoc = (unsigned *)_AddressOfReturnAddress();
  RetAddrLoc += 3;  // skip over ret addr, edx, eax
  unsigned RetAddr = *RetAddrLoc;
#else
  unsigned *StackPtr = (unsigned*)__builtin_frame_address(1);
  unsigned RetAddr = (unsigned)(intptr_t)__builtin_return_address(1);
  unsigned *RetAddrLoc = &StackPtr[1];

  // NOTE: __builtin_frame_address doesn't work if frame pointer elimination has
  // been performed.  Having a variable sized alloca disables frame pointer
  // elimination currently, even if it's dead.  This is a gross hack.
  alloca(10+(RetAddr >> 31));

#endif
  assert(*RetAddrLoc == RetAddr &&
         "Could not find return address on the stack!");

  // It's a stub if there is an interrupt marker after the call.
  bool isStub = ((unsigned char*)(intptr_t)RetAddr)[0] == 0xCD;

  // The call instruction should have pushed the return value onto the stack...
  RetAddr -= 4;  // Backtrack to the reference itself...

#if 0
  DEBUG(std::cerr << "In callback! Addr=" << (void*)RetAddr
                  << " ESP=" << (void*)StackPtr
                  << ": Resolving call to function: "
                  << TheVM->getFunctionReferencedName((void*)RetAddr) << "\n");
#endif

  // Sanity check to make sure this really is a call instruction.
  assert(((unsigned char*)(intptr_t)RetAddr)[-1] == 0xE8 &&"Not a call instr!");

  unsigned NewVal = (intptr_t)JITCompilerFunction((void*)(intptr_t)RetAddr);

  // Rewrite the call target... so that we don't end up here every time we
  // execute the call.
  *(unsigned*)(intptr_t)RetAddr = NewVal-RetAddr-4;

  if (isStub) {
    // If this is a stub, rewrite the call into an unconditional branch
    // instruction so that two return addresses are not pushed onto the stack
    // when the requested function finally gets called.  This also makes the
    // 0xCD byte (interrupt) dead, so the marker doesn't effect anything.
    ((unsigned char*)(intptr_t)RetAddr)[-1] = 0xE9;
  }

  // Change the return address to reexecute the call instruction...
  *RetAddrLoc -= 5;
}

TargetJITInfo::LazyResolverFn
X86JITInfo::getLazyResolverFunction(JITCompilerFn F) {
  JITCompilerFunction = F;
  return X86CompilationCallback;
}

void *X86JITInfo::emitFunctionStub(void *Fn, MachineCodeEmitter &MCE) {
  if (Fn != (void*)X86CompilationCallback) {
    MCE.startFunctionStub(5);
    MCE.emitByte(0xE9);
    MCE.emitWordLE((intptr_t)Fn-MCE.getCurrentPCValue()-4);
    return MCE.finishFunctionStub(0);
  }

  MCE.startFunctionStub(6);
  MCE.emitByte(0xE8);   // Call with 32 bit pc-rel destination...

  MCE.emitWordLE((intptr_t)Fn-MCE.getCurrentPCValue()-4);

  MCE.emitByte(0xCD);   // Interrupt - Just a marker identifying the stub!
  return MCE.finishFunctionStub(0);
}

/// relocate - Before the JIT can run a block of code that has been emitted,
/// it must rewrite the code to contain the actual addresses of any
/// referenced global symbols.
void X86JITInfo::relocate(void *Function, MachineRelocation *MR,
                          unsigned NumRelocs, unsigned char* GOTBase) {
  for (unsigned i = 0; i != NumRelocs; ++i, ++MR) {
    void *RelocPos = (char*)Function + MR->getMachineCodeOffset();
    intptr_t ResultPtr = (intptr_t)MR->getResultPointer();
    switch ((X86::RelocationType)MR->getRelocationType()) {
    case X86::reloc_pcrel_word:
      // PC relative relocation, add the relocated value to the value already in
      // memory, after we adjust it for where the PC is.
      ResultPtr = ResultPtr-(intptr_t)RelocPos-4;
      *((intptr_t*)RelocPos) += ResultPtr;
      break;
    case X86::reloc_absolute_word:
      // Absolute relocation, just add the relocated value to the value already
      // in memory.
      *((intptr_t*)RelocPos) += ResultPtr;
      break;
    }
  }
}
<commit_msg>Silence -pedantic warning.<commit_after>//===-- X86JITInfo.cpp - Implement the JIT interfaces for the X86 target --===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the JIT interfaces for the X86 target.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "jit"
#include "X86JITInfo.h"
#include "X86Relocations.h"
#include "llvm/CodeGen/MachineCodeEmitter.h"
#include "llvm/Config/alloca.h"
#include <cstdlib>
#include <iostream>
using namespace llvm;

#ifdef _MSC_VER
  extern "C" void *_AddressOfReturnAddress(void);
  #pragma intrinsic(_AddressOfReturnAddress)
#endif

void X86JITInfo::replaceMachineCodeForFunction(void *Old, void *New) {
  unsigned char *OldByte = (unsigned char *)Old;
  *OldByte++ = 0xE9;                // Emit JMP opcode.
  unsigned *OldWord = (unsigned *)OldByte;
  unsigned NewAddr = (intptr_t)New;
  unsigned OldAddr = (intptr_t)OldWord;
  *OldWord = NewAddr - OldAddr - 4; // Emit PC-relative addr of New code.
}

/// JITCompilerFunction - This contains the address of the JIT function used to
/// compile a function lazily.
static TargetJITInfo::JITCompilerFn JITCompilerFunction;

// Provide a wrapper for X86CompilationCallback2 that saves non-traditional
// callee saved registers, for the fastcc calling convention.
extern "C" {
#if defined(__i386__) || defined(i386) || defined(_M_IX86)
#ifndef _MSC_VER
  void X86CompilationCallback(void);
  asm(
    ".text\n"
    ".align 8\n"
#if defined(__CYGWIN__) || defined(__APPLE__) || defined(__MINGW32__)
    ".globl _X86CompilationCallback\n"
  "_X86CompilationCallback:\n"
#else
    ".globl X86CompilationCallback\n"
  "X86CompilationCallback:\n"
#endif
    "pushl   %ebp\n"
    "movl    %esp, %ebp\n"    // Standard prologue
    "pushl   %eax\n"
    "pushl   %edx\n"          // save EAX/EDX
#if defined(__CYGWIN__) || defined(__MINGW32__)
    "call    _X86CompilationCallback2\n"
#elif defined(__APPLE__)
    "movl    4(%ebp), %eax\n" // load the address of return address
    "movl    $24, %edx\n"     // if the opcode of the instruction at the
    "cmpb    $-51, (%eax)\n"  // return address is our 0xCD marker, then
    "movl    $12, %eax\n"     // subtract 24 from %esp to realign it to 16
    "cmovne  %eax, %edx\n"    // bytes after the push of edx, the amount to.
    "subl    %edx, %esp\n"    // the push of edx to keep it aligned.
    "pushl   %edx\n"          // subtract.  Otherwise, subtract 12 bytes after
    "call    _X86CompilationCallback2\n"
    "popl    %edx\n"
    "addl    %edx, %esp\n"
#else
    "call X86CompilationCallback2\n"
#endif
    "popl    %edx\n"
    "popl    %eax\n"
    "popl    %ebp\n"
    "ret\n");
#else
  void X86CompilationCallback2(void);

  _declspec(naked) void X86CompilationCallback(void) {
    __asm {
      push  eax
      push  edx
      call  X86CompilationCallback2
      pop   edx
      pop   eax
      ret
    }
  }
#endif // _MSC_VER

#else // Not an i386 host
  void X86CompilationCallback() {
    std::cerr << "Cannot call X86CompilationCallback() on a non-x86 arch!\n";
    abort();
  }
#endif
}

/// X86CompilationCallback - This is the target-specific function invoked by the
/// function stub when we did not know the real target of a call.  This function
/// must locate the start of the stub or call site and pass it into the JIT
/// compiler function.
extern "C" void X86CompilationCallback2() {
#ifdef _MSC_VER
  assert(sizeof(size_t) == 4); // FIXME: handle Win64
  unsigned *RetAddrLoc = (unsigned *)_AddressOfReturnAddress();
  RetAddrLoc += 3;  // skip over ret addr, edx, eax
  unsigned RetAddr = *RetAddrLoc;
#else
  unsigned *StackPtr = (unsigned*)__builtin_frame_address(1);
  unsigned RetAddr = (unsigned)(intptr_t)__builtin_return_address(1);
  unsigned *RetAddrLoc = &StackPtr[1];

  // NOTE: __builtin_frame_address doesn't work if frame pointer elimination has
  // been performed.  Having a variable sized alloca disables frame pointer
  // elimination currently, even if it's dead.  This is a gross hack.
  alloca(10+(RetAddr >> 31));

#endif
  assert(*RetAddrLoc == RetAddr &&
         "Could not find return address on the stack!");

  // It's a stub if there is an interrupt marker after the call.
  bool isStub = ((unsigned char*)(intptr_t)RetAddr)[0] == 0xCD;

  // The call instruction should have pushed the return value onto the stack...
  RetAddr -= 4;  // Backtrack to the reference itself...

#if 0
  DEBUG(std::cerr << "In callback! Addr=" << (void*)RetAddr
                  << " ESP=" << (void*)StackPtr
                  << ": Resolving call to function: "
                  << TheVM->getFunctionReferencedName((void*)RetAddr) << "\n");
#endif

  // Sanity check to make sure this really is a call instruction.
  assert(((unsigned char*)(intptr_t)RetAddr)[-1] == 0xE8 &&"Not a call instr!");

  unsigned NewVal = (intptr_t)JITCompilerFunction((void*)(intptr_t)RetAddr);

  // Rewrite the call target... so that we don't end up here every time we
  // execute the call.
  *(unsigned*)(intptr_t)RetAddr = NewVal-RetAddr-4;

  if (isStub) {
    // If this is a stub, rewrite the call into an unconditional branch
    // instruction so that two return addresses are not pushed onto the stack
    // when the requested function finally gets called.  This also makes the
    // 0xCD byte (interrupt) dead, so the marker doesn't effect anything.
    ((unsigned char*)(intptr_t)RetAddr)[-1] = 0xE9;
  }

  // Change the return address to reexecute the call instruction...
  *RetAddrLoc -= 5;
}

TargetJITInfo::LazyResolverFn
X86JITInfo::getLazyResolverFunction(JITCompilerFn F) {
  JITCompilerFunction = F;
  return X86CompilationCallback;
}

void *X86JITInfo::emitFunctionStub(void *Fn, MachineCodeEmitter &MCE) {
  // Note, we cast to intptr_t here to silence a -pedantic warning that
  // complains about casting a function pointer to a normal pointer.
  if (Fn != (void*)(intptr_t)X86CompilationCallback) {
    MCE.startFunctionStub(5);
    MCE.emitByte(0xE9);
    MCE.emitWordLE((intptr_t)Fn-MCE.getCurrentPCValue()-4);
    return MCE.finishFunctionStub(0);
  }

  MCE.startFunctionStub(6);
  MCE.emitByte(0xE8);   // Call with 32 bit pc-rel destination...

  MCE.emitWordLE((intptr_t)Fn-MCE.getCurrentPCValue()-4);

  MCE.emitByte(0xCD);   // Interrupt - Just a marker identifying the stub!
  return MCE.finishFunctionStub(0);
}

/// relocate - Before the JIT can run a block of code that has been emitted,
/// it must rewrite the code to contain the actual addresses of any
/// referenced global symbols.
void X86JITInfo::relocate(void *Function, MachineRelocation *MR,
                          unsigned NumRelocs, unsigned char* GOTBase) {
  for (unsigned i = 0; i != NumRelocs; ++i, ++MR) {
    void *RelocPos = (char*)Function + MR->getMachineCodeOffset();
    intptr_t ResultPtr = (intptr_t)MR->getResultPointer();
    switch ((X86::RelocationType)MR->getRelocationType()) {
    case X86::reloc_pcrel_word:
      // PC relative relocation, add the relocated value to the value already in
      // memory, after we adjust it for where the PC is.
      ResultPtr = ResultPtr-(intptr_t)RelocPos-4;
      *((intptr_t*)RelocPos) += ResultPtr;
      break;
    case X86::reloc_absolute_word:
      // Absolute relocation, just add the relocated value to the value already
      // in memory.
      *((intptr_t*)RelocPos) += ResultPtr;
      break;
    }
  }
}
<|endoftext|>


<commit_before>#include <cmath>
#include <cassert>
#include <sstream>

#include "libinterpreter/builtins.h"

const Value builtins::dispatch(BuiltinAtom::Id atom_id,  ExecutionContext& ctxt,
                               const std::vector<Value>& arguments) {
  switch (atom_id) {
    case BuiltinAtom::Id::POW:
      return std::move(pow(arguments[0], arguments[1]));

    case BuiltinAtom::Id::HEX:
      return std::move(hex(arguments[0]));

    case BuiltinAtom::Id::NTH:
      return std::move(nth(arguments[0], arguments[1]));

    case BuiltinAtom::Id::APP:
      return std::move(app(ctxt, arguments[0], arguments[1]));

    case BuiltinAtom::Id::CONS:
      return std::move(cons(ctxt, arguments[0], arguments[1]));

    case BuiltinAtom::Id::TAIL:
      return std::move(tail(ctxt, arguments[0]));

    case BuiltinAtom::Id::LEN:
      return std::move(len(arguments[0]));

    case BuiltinAtom::Id::PEEK:
      return std::move(peek(arguments[0]));

    case BuiltinAtom::Id::BOOLEAN2INT:
      return std::move(boolean2int(arguments[0]));

    case BuiltinAtom::Id::INT2BOOLEAN:
      return std::move(int2boolean(arguments[0]));

    case BuiltinAtom::Id::ENUM2INT:
      return std::move(enum2int(arguments[0]));

    case BuiltinAtom::Id::ASINT:
      return std::move(asint(arguments[0]));

    case BuiltinAtom::Id::ASFLOAT:
      return std::move(asfloat(arguments[0]));

    case BuiltinAtom::Id::ASRATIONAL:
      return std::move(asrational(arguments[0]));

    case BuiltinAtom::Id::SYMBOLIC:
      return std::move(symbolic(arguments[0]));

    default: return std::move(shared::dispatch(atom_id, arguments, ctxt));
  }
}

const Value builtins::pow(const Value& base, const Value& power) {
  switch (base.type) {
    case TypeType::INT:
      return std::move(Value((INT_T)std::pow(base.value.ival, power.value.ival)));

    case TypeType::FLOAT:
      return std::move(Value((FLOAT_T)std::pow(base.value.fval, power.value.fval)));
    default: assert(0);
  }
}

const Value builtins::hex(const Value& arg) {
  // TODO LEAK!
  if (arg.is_undef()) {
    return std::move(Value(new std::string("undef")));
  }

  std::stringstream ss;
  if (arg.value.ival < 0) {
    ss << "-" << std::hex << (-1) * arg.value.ival;
  } else {
    ss << std::hex << arg.value.ival;
  }
  return std::move(Value(new std::string(ss.str())));
}

const Value builtins::nth(const Value& list_arg, const Value& index ) {
  if (list_arg.is_undef() || index.is_undef()) {
    return Value();
  }

  List *list = list_arg.value.list;
  List::const_iterator iter = list->begin();
  INT_T i = 1;

  while (iter != list->end() && i < index.value.ival) {
    i++;
    iter++;
  }
  if (i == index.value.ival && iter != list->end()) {
    return std::move(Value(*iter));
  } else {
    return std::move(Value());
  }
}

const Value builtins::app(ExecutionContext& ctxt, const Value& list, const Value& val) {
  // TODO LEAK
  if (list.is_undef()) {
    return std::move(Value());
  }

  List *current = list.value.list;

  while (1 == 1) {
    if (current->list_type == List::ListType::HEAD) {
      current = reinterpret_cast<HeadList*>(current)->right;
    }
    if (current->list_type == List::ListType::SKIP) {
      current = reinterpret_cast<SkipList*>(current)->bottom;
    }
    if (current->list_type == List::ListType::BOTTOM) {
      BottomList *bottom = reinterpret_cast<BottomList*>(current);
      if (bottom->tail) {
        current = bottom->tail;
      } else {
        break;
      }
    }
    if (current->list_type == List::ListType::TAIL) {
      TailList *tail = reinterpret_cast<TailList*>(current);
      if (tail->right) {
        current = tail->right;
      } else {
        break;
      }
    }
  }

  TailList *tail = new TailList(nullptr, val);
  ctxt.temp_lists.push_back(tail);

  if (current->list_type == List::ListType::TAIL) {
    reinterpret_cast<TailList*>(current)->right = tail;
  } else if (current->list_type == List::ListType::BOTTOM) {
    reinterpret_cast<BottomList*>(current)->tail = tail;
  } else {
    assert(0);
  }
  return std::move(Value(list.type, list.value.list));
}

const Value builtins::cons(ExecutionContext& ctxt, const Value& val, const Value& list) {
  // TODO LEAK
  if (list.is_undef()) {
    return std::move(Value());
  }

  HeadList *consed_list = new HeadList(list.value.list, val);
  ctxt.temp_lists.push_back(consed_list);
  return Value(list.type, consed_list);
}

const Value builtins::tail(ExecutionContext& ctxt, const Value& arg_list) {
  if (arg_list.is_undef()) {
    return std::move(Value());
  }

  List *list = arg_list.value.list;

  if (list->is_head()) {
    return std::move(Value(arg_list.type, reinterpret_cast<HeadList*>(list)->right));
  } else if (list->is_bottom()) {
    BottomList *btm = reinterpret_cast<BottomList*>(list);
    SkipList *skip = new SkipList(1, btm);
    ctxt.temp_lists.push_back(skip);
    return std::move(Value(arg_list.type, skip));
  } else {
    SkipList *old_skip = reinterpret_cast<SkipList*>(list);
    SkipList *skip = new SkipList(old_skip->skip+1, old_skip->bottom);
    ctxt.temp_lists.push_back(skip);
    return std::move(Value(arg_list.type, skip));
  }
}

const Value builtins::len(const Value& list_arg) {
  // TODO len is really slow right now, it itertes over complete list
  if (list_arg.is_undef()) {
    return std::move(Value());
  }

  List *list = list_arg.value.list;
  List::const_iterator iter = list->begin();

  size_t count = 0;

  while (iter != list->end()) {
    count++;
    iter++;
  }
  return std::move(Value((INT_T) count));
}

const Value builtins::peek(const Value& arg_list) {
  if (arg_list.is_undef()) {
    return std::move(Value());
  }

  List *list = arg_list.value.list;

  if (list->begin() != list->end()) {
    return std::move(Value(*(list->begin())));
  } else {
    return std::move(Value());
  }
}

const Value builtins::boolean2int(const Value& arg) {
  if (arg.is_undef()) {
    return std::move(arg);
  }

  return std::move(Value((INT_T)arg.value.bval));
}

const Value builtins::int2boolean(const Value& arg) {
  if (arg.is_undef()) {
    return std::move(arg);
  }

  return std::move(Value((bool)arg.value.ival));
}

const Value builtins::enum2int(const Value& arg) {
  if (arg.is_undef()) {
    return std::move(arg);
  }

  return std::move(Value((INT_T)arg.value.enum_val->id));
}

const Value builtins::asint(const Value& arg) {
  if (arg.is_undef()) {
    return std::move(arg);
  }

  switch (arg.type) {
    case TypeType::INT:
      return std::move(Value(arg.value.ival));
    case TypeType::FLOAT:
      return std::move(Value((INT_T)arg.value.fval));
    case TypeType::RATIONAL:
      return std::move(Value((INT_T)(arg.value.rat->numerator / arg.value.rat->denominator)));
    default: assert(0);
  }
}

const Value builtins::asfloat(const Value& arg) {
  if (arg.is_undef()) {
    return std::move(arg);
  }

  switch (arg.type) {
    case TypeType::INT:
      return std::move(Value((FLOAT_T) arg.value.ival));
    case TypeType::FLOAT:
      return std::move(Value(arg.value.fval));
    case TypeType::RATIONAL:
      return std::move(Value(((FLOAT_T)arg.value.rat->numerator) / arg.value.rat->denominator));
    default: assert(0);
  }
}

void get_numerator_denominator(double x, int64_t *num, int64_t *denom) {
  // thanks to
  // http://stackoverflow.com/a/96035/781502
  uint64_t m[2][2];
  double startx = x;
  int64_t maxden = 10000000000;
  int64_t ai;

  /* initialize matrix */
  m[0][0] = m[1][1] = 1;
  m[0][1] = m[1][0] = 0;

  /* loop finding terms until denom gets too big */
  while (m[1][0] *  ( ai = (int64_t)x ) + m[1][1] <= maxden) {
      long t;
      t = m[0][0] * ai + m[0][1];
      m[0][1] = m[0][0];
      m[0][0] = t;
      t = m[1][0] * ai + m[1][1];
      m[1][1] = m[1][0];
      m[1][0] = t;
      if(x==(double)ai) break;     // AF: division by zero
      x = 1/(x - (double) ai);
      if(x>(double)0x7FFFFFFF) break;  // AF: representation failure
  }

  /* now remaining x is between 0 and 1/ai */
  /* approx as either 0 or 1/m where m is max that will fit in maxden */
  /* first try zero */

  double error1 = startx - ((double) m[0][0] / (double) m[1][0]);

  *num = m[0][0];
  *denom =  m[1][0];

  /* now try other possibility */
  ai = (maxden - m[1][1]) / m[1][0];
  m[0][0] = m[0][0] * ai + m[0][1];
  m[1][0] = m[1][0] * ai + m[1][1];
  double error2 = startx - ((double) m[0][0] / (double) m[1][0]);

  if (abs(error1) > abs(error2)) {
    *num = m[0][0];
    *denom =  m[1][0];
  }
}

const Value builtins::asrational(const Value& arg) {
  if (arg.is_undef()) {
    return std::move(arg);
  }

  rational_t *result = (rational_t*) pp_mem_alloc(
      &(ExecutionContext::value_stack), sizeof(rational_t)
  );
  switch (arg.type) {
    case TypeType::INT:
      result->numerator = arg.value.ival;
      result->denominator = 1;
      return std::move(Value(result));
    case TypeType::FLOAT:
      get_numerator_denominator(arg.value.fval, &result->numerator, &result->denominator);
      return std::move(Value(result));
    case TypeType::RATIONAL:
      return std::move(Value(arg.value.rat));
    default: assert(0);
  }
}

const Value builtins::symbolic(const Value& arg) {
  if (arg.is_symbolic() && !arg.value.sym->list) {
    return std::move(Value(true));
  } else {
    return std::move(Value(false));
  }
}

namespace builtins {
namespace shared {
  #include "shared_glue.h"

  IGNORE_VARIADIC_WARNINGS

  // the CASM runtime heavily depens on macros, whatever you think of it ...
  // here we need to provide all definitions ...
  #define TRUE                    1
  #define FALSE                   0
  #define ARG(TYPE, NAME)             TYPE* NAME
  #define SARG(VAR) #VAR              " {0x%lx,%u}"
  #define PARG(TYPE, VAR)             (uint64_t)VAR->value, VAR->defined
  #define CASM_RT(FORMAT, ARGS...)        /* printf-able */
  #define CASM_INFO(FORMAT, ARGS...)      /* printf-able */

  // create concrete variants of the shareds
  #define CASM_CALL_SHARED(NAME, VALUE, ARGS...)  NAME(VALUE, ##ARGS)
  #define DEFINE_CASM_SHARED(NAME, VALUE, ARGS...) void NAME(VALUE, ##ARGS)
  #include "libcasmrt/pp_casm_shared.h"

  namespace symbolic {
    // create symbolic variants of shareds
    namespace BV {
      // mock BV namespace as expected by the pp_casm_shared builtins
      struct helper_t {
        bool next() { return true; }
      };
      static helper_t symbolic_nopointer;
      helper_t *symbolic_ = &symbolic_nopointer;
    }

    #undef CASM_CALL_SHARED
    #undef DEFINE_CASM_SHARED
    #define SYMBOLIC
    #define CASM_CALL_SHARED(NAME, VALUE, ARGS...)  symbolic_##NAME(VALUE, ##ARGS)
    #define DEFINE_CASM_SHARED(NAME, VALUE, ARGS...) void symbolic_##NAME(VALUE, ##ARGS)
    #include "libcasmrt/pp_casm_shared.h"
  }

  REENABLE_VARIADIC_WARNINGS

  const Value dispatch(BuiltinAtom::Id builtin_id,
                       const std::vector<Value>& arguments, ExecutionContext& ctxt) {
    const char *sym_name;
    Int ret;
    Int arg0;
    Int arg1;
    Int arg2;
    Int arg3;
    Int arg4;
    switch (builtin_id) {
      SHARED_DISPATCH
      default: assert(0);
    }

    if (ret.defined == TRUE) {
      return std::move(Value((INT_T)ret.value));
    } else if (ctxt.symbolic && ret.sym) {
      Value v(new symbol_t(::symbolic::next_symbol_id()));
      ::symbolic::dump_builtin(ctxt.trace, sym_name, arguments, v);
      return std::move(v);
    } else {
      return std::move(Value());
    }
  }
}
}
<commit_msg>Disable unused-warnings for shared-builtins<commit_after>#include <cmath>
#include <cassert>
#include <sstream>

#include "libinterpreter/builtins.h"

const Value builtins::dispatch(BuiltinAtom::Id atom_id,  ExecutionContext& ctxt,
                               const std::vector<Value>& arguments) {
  switch (atom_id) {
    case BuiltinAtom::Id::POW:
      return std::move(pow(arguments[0], arguments[1]));

    case BuiltinAtom::Id::HEX:
      return std::move(hex(arguments[0]));

    case BuiltinAtom::Id::NTH:
      return std::move(nth(arguments[0], arguments[1]));

    case BuiltinAtom::Id::APP:
      return std::move(app(ctxt, arguments[0], arguments[1]));

    case BuiltinAtom::Id::CONS:
      return std::move(cons(ctxt, arguments[0], arguments[1]));

    case BuiltinAtom::Id::TAIL:
      return std::move(tail(ctxt, arguments[0]));

    case BuiltinAtom::Id::LEN:
      return std::move(len(arguments[0]));

    case BuiltinAtom::Id::PEEK:
      return std::move(peek(arguments[0]));

    case BuiltinAtom::Id::BOOLEAN2INT:
      return std::move(boolean2int(arguments[0]));

    case BuiltinAtom::Id::INT2BOOLEAN:
      return std::move(int2boolean(arguments[0]));

    case BuiltinAtom::Id::ENUM2INT:
      return std::move(enum2int(arguments[0]));

    case BuiltinAtom::Id::ASINT:
      return std::move(asint(arguments[0]));

    case BuiltinAtom::Id::ASFLOAT:
      return std::move(asfloat(arguments[0]));

    case BuiltinAtom::Id::ASRATIONAL:
      return std::move(asrational(arguments[0]));

    case BuiltinAtom::Id::SYMBOLIC:
      return std::move(symbolic(arguments[0]));

    default: return std::move(shared::dispatch(atom_id, arguments, ctxt));
  }
}

const Value builtins::pow(const Value& base, const Value& power) {
  switch (base.type) {
    case TypeType::INT:
      return std::move(Value((INT_T)std::pow(base.value.ival, power.value.ival)));

    case TypeType::FLOAT:
      return std::move(Value((FLOAT_T)std::pow(base.value.fval, power.value.fval)));
    default: assert(0);
  }
}

const Value builtins::hex(const Value& arg) {
  // TODO LEAK!
  if (arg.is_undef()) {
    return std::move(Value(new std::string("undef")));
  }

  std::stringstream ss;
  if (arg.value.ival < 0) {
    ss << "-" << std::hex << (-1) * arg.value.ival;
  } else {
    ss << std::hex << arg.value.ival;
  }
  return std::move(Value(new std::string(ss.str())));
}

const Value builtins::nth(const Value& list_arg, const Value& index ) {
  if (list_arg.is_undef() || index.is_undef()) {
    return Value();
  }

  List *list = list_arg.value.list;
  List::const_iterator iter = list->begin();
  INT_T i = 1;

  while (iter != list->end() && i < index.value.ival) {
    i++;
    iter++;
  }
  if (i == index.value.ival && iter != list->end()) {
    return std::move(Value(*iter));
  } else {
    return std::move(Value());
  }
}

const Value builtins::app(ExecutionContext& ctxt, const Value& list, const Value& val) {
  // TODO LEAK
  if (list.is_undef()) {
    return std::move(Value());
  }

  List *current = list.value.list;

  while (1 == 1) {
    if (current->list_type == List::ListType::HEAD) {
      current = reinterpret_cast<HeadList*>(current)->right;
    }
    if (current->list_type == List::ListType::SKIP) {
      current = reinterpret_cast<SkipList*>(current)->bottom;
    }
    if (current->list_type == List::ListType::BOTTOM) {
      BottomList *bottom = reinterpret_cast<BottomList*>(current);
      if (bottom->tail) {
        current = bottom->tail;
      } else {
        break;
      }
    }
    if (current->list_type == List::ListType::TAIL) {
      TailList *tail = reinterpret_cast<TailList*>(current);
      if (tail->right) {
        current = tail->right;
      } else {
        break;
      }
    }
  }

  TailList *tail = new TailList(nullptr, val);
  ctxt.temp_lists.push_back(tail);

  if (current->list_type == List::ListType::TAIL) {
    reinterpret_cast<TailList*>(current)->right = tail;
  } else if (current->list_type == List::ListType::BOTTOM) {
    reinterpret_cast<BottomList*>(current)->tail = tail;
  } else {
    assert(0);
  }
  return std::move(Value(list.type, list.value.list));
}

const Value builtins::cons(ExecutionContext& ctxt, const Value& val, const Value& list) {
  // TODO LEAK
  if (list.is_undef()) {
    return std::move(Value());
  }

  HeadList *consed_list = new HeadList(list.value.list, val);
  ctxt.temp_lists.push_back(consed_list);
  return Value(list.type, consed_list);
}

const Value builtins::tail(ExecutionContext& ctxt, const Value& arg_list) {
  if (arg_list.is_undef()) {
    return std::move(Value());
  }

  List *list = arg_list.value.list;

  if (list->is_head()) {
    return std::move(Value(arg_list.type, reinterpret_cast<HeadList*>(list)->right));
  } else if (list->is_bottom()) {
    BottomList *btm = reinterpret_cast<BottomList*>(list);
    SkipList *skip = new SkipList(1, btm);
    ctxt.temp_lists.push_back(skip);
    return std::move(Value(arg_list.type, skip));
  } else {
    SkipList *old_skip = reinterpret_cast<SkipList*>(list);
    SkipList *skip = new SkipList(old_skip->skip+1, old_skip->bottom);
    ctxt.temp_lists.push_back(skip);
    return std::move(Value(arg_list.type, skip));
  }
}

const Value builtins::len(const Value& list_arg) {
  // TODO len is really slow right now, it itertes over complete list
  if (list_arg.is_undef()) {
    return std::move(Value());
  }

  List *list = list_arg.value.list;
  List::const_iterator iter = list->begin();

  size_t count = 0;

  while (iter != list->end()) {
    count++;
    iter++;
  }
  return std::move(Value((INT_T) count));
}

const Value builtins::peek(const Value& arg_list) {
  if (arg_list.is_undef()) {
    return std::move(Value());
  }

  List *list = arg_list.value.list;

  if (list->begin() != list->end()) {
    return std::move(Value(*(list->begin())));
  } else {
    return std::move(Value());
  }
}

const Value builtins::boolean2int(const Value& arg) {
  if (arg.is_undef()) {
    return std::move(arg);
  }

  return std::move(Value((INT_T)arg.value.bval));
}

const Value builtins::int2boolean(const Value& arg) {
  if (arg.is_undef()) {
    return std::move(arg);
  }

  return std::move(Value((bool)arg.value.ival));
}

const Value builtins::enum2int(const Value& arg) {
  if (arg.is_undef()) {
    return std::move(arg);
  }

  return std::move(Value((INT_T)arg.value.enum_val->id));
}

const Value builtins::asint(const Value& arg) {
  if (arg.is_undef()) {
    return std::move(arg);
  }

  switch (arg.type) {
    case TypeType::INT:
      return std::move(Value(arg.value.ival));
    case TypeType::FLOAT:
      return std::move(Value((INT_T)arg.value.fval));
    case TypeType::RATIONAL:
      return std::move(Value((INT_T)(arg.value.rat->numerator / arg.value.rat->denominator)));
    default: assert(0);
  }
}

const Value builtins::asfloat(const Value& arg) {
  if (arg.is_undef()) {
    return std::move(arg);
  }

  switch (arg.type) {
    case TypeType::INT:
      return std::move(Value((FLOAT_T) arg.value.ival));
    case TypeType::FLOAT:
      return std::move(Value(arg.value.fval));
    case TypeType::RATIONAL:
      return std::move(Value(((FLOAT_T)arg.value.rat->numerator) / arg.value.rat->denominator));
    default: assert(0);
  }
}

void get_numerator_denominator(double x, int64_t *num, int64_t *denom) {
  // thanks to
  // http://stackoverflow.com/a/96035/781502
  uint64_t m[2][2];
  double startx = x;
  int64_t maxden = 10000000000;
  int64_t ai;

  /* initialize matrix */
  m[0][0] = m[1][1] = 1;
  m[0][1] = m[1][0] = 0;

  /* loop finding terms until denom gets too big */
  while (m[1][0] *  ( ai = (int64_t)x ) + m[1][1] <= maxden) {
      long t;
      t = m[0][0] * ai + m[0][1];
      m[0][1] = m[0][0];
      m[0][0] = t;
      t = m[1][0] * ai + m[1][1];
      m[1][1] = m[1][0];
      m[1][0] = t;
      if(x==(double)ai) break;     // AF: division by zero
      x = 1/(x - (double) ai);
      if(x>(double)0x7FFFFFFF) break;  // AF: representation failure
  }

  /* now remaining x is between 0 and 1/ai */
  /* approx as either 0 or 1/m where m is max that will fit in maxden */
  /* first try zero */

  double error1 = startx - ((double) m[0][0] / (double) m[1][0]);

  *num = m[0][0];
  *denom =  m[1][0];

  /* now try other possibility */
  ai = (maxden - m[1][1]) / m[1][0];
  m[0][0] = m[0][0] * ai + m[0][1];
  m[1][0] = m[1][0] * ai + m[1][1];
  double error2 = startx - ((double) m[0][0] / (double) m[1][0]);

  if (abs(error1) > abs(error2)) {
    *num = m[0][0];
    *denom =  m[1][0];
  }
}

const Value builtins::asrational(const Value& arg) {
  if (arg.is_undef()) {
    return std::move(arg);
  }

  rational_t *result = (rational_t*) pp_mem_alloc(
      &(ExecutionContext::value_stack), sizeof(rational_t)
  );
  switch (arg.type) {
    case TypeType::INT:
      result->numerator = arg.value.ival;
      result->denominator = 1;
      return std::move(Value(result));
    case TypeType::FLOAT:
      get_numerator_denominator(arg.value.fval, &result->numerator, &result->denominator);
      return std::move(Value(result));
    case TypeType::RATIONAL:
      return std::move(Value(arg.value.rat));
    default: assert(0);
  }
}

const Value builtins::symbolic(const Value& arg) {
  if (arg.is_symbolic() && !arg.value.sym->list) {
    return std::move(Value(true));
  } else {
    return std::move(Value(false));
  }
}

namespace builtins {
namespace shared {
  #include "shared_glue.h"

  IGNORE_VARIADIC_WARNINGS
  #pragma GCC diagnostic ignored "-Wmissing-field-initializers"
  #pragma GCC diagnostic ignored "-Wunused-parameter"

  // the CASM runtime heavily depens on macros, whatever you think of it ...
  // here we need to provide all definitions ...
  #define TRUE                    1
  #define FALSE                   0
  #define ARG(TYPE, NAME)             TYPE* NAME
  #define SARG(VAR) #VAR              " {0x%lx,%u}"
  #define PARG(TYPE, VAR)             (uint64_t)VAR->value, VAR->defined
  #define CASM_RT(FORMAT, ARGS...)        /* printf-able */
  #define CASM_INFO(FORMAT, ARGS...)      /* printf-able */

  // create concrete variants of the shareds
  #define CASM_CALL_SHARED(NAME, VALUE, ARGS...)  NAME(VALUE, ##ARGS)
  #define DEFINE_CASM_SHARED(NAME, VALUE, ARGS...) void NAME(VALUE, ##ARGS)
  #include "libcasmrt/pp_casm_shared.h"

  namespace symbolic {
    // create symbolic variants of shareds
    namespace BV {
      // mock BV namespace as expected by the pp_casm_shared builtins
      struct helper_t {
        bool next() { return true; }
      };
      static helper_t symbolic_nopointer;
      helper_t *symbolic_ = &symbolic_nopointer;
    }

    #undef CASM_CALL_SHARED
    #undef DEFINE_CASM_SHARED
    #define SYMBOLIC
    #define CASM_CALL_SHARED(NAME, VALUE, ARGS...)  symbolic_##NAME(VALUE, ##ARGS)
    #define DEFINE_CASM_SHARED(NAME, VALUE, ARGS...) void symbolic_##NAME(VALUE, ##ARGS)
    #include "libcasmrt/pp_casm_shared.h"
  }

  #pragma GCC diagnostic warning "-Wmissing-field-initializers"
  #pragma GCC diagnostic warning "-Wunused-parameter"
  REENABLE_VARIADIC_WARNINGS

  const Value dispatch(BuiltinAtom::Id builtin_id,
                       const std::vector<Value>& arguments, ExecutionContext& ctxt) {
    const char *sym_name;
    Int ret;
    Int arg0;
    Int arg1;
    Int arg2;
    Int arg3;
    Int arg4;
    switch (builtin_id) {
      SHARED_DISPATCH
      default: assert(0);
    }

    if (ret.defined == TRUE) {
      return std::move(Value((INT_T)ret.value));
    } else if (ctxt.symbolic && ret.sym) {
      Value v(new symbol_t(::symbolic::next_symbol_id()));
      ::symbolic::dump_builtin(ctxt.trace, sym_name, arguments, v);
      return std::move(v);
    } else {
      return std::move(Value());
    }
  }
}
}
<|endoftext|>


<commit_before>//===-- asan_suppressions.cc ----------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is a part of AddressSanitizer, an address sanity checker.
//
// Issue suppression and suppression-related functions.
//===----------------------------------------------------------------------===//

#include "asan_suppressions.h"

#include "asan_stack.h"
#include "sanitizer_common/sanitizer_placement_new.h"
#include "sanitizer_common/sanitizer_suppressions.h"
#include "sanitizer_common/sanitizer_symbolizer.h"

namespace __asan {

ALIGNED(64) static char suppression_placeholder[sizeof(SuppressionContext)];
static SuppressionContext *suppression_ctx = nullptr;
static const char kInterceptorName[] = "interceptor_name";
static const char kInterceptorViaFunction[] = "interceptor_via_fun";
static const char kInterceptorViaLibrary[] = "interceptor_via_lib";
static const char kODRViolation[] = "odr_violation";
static const char *kSuppressionTypes[] = {
    kInterceptorName, kInterceptorViaFunction, kInterceptorViaLibrary,
    kODRViolation};

extern "C" {
#if SANITIZER_SUPPORTS_WEAK_HOOKS
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
const char *__asan_default_suppressions();
#else
// No week hooks, provide empty implementation.
const char *__asan_default_suppressions() { return ""; }
#endif  // SANITIZER_SUPPORTS_WEAK_HOOKS
}  // extern "C"

void InitializeSuppressions() {
  CHECK_EQ(nullptr, suppression_ctx);
  suppression_ctx = new (suppression_placeholder)  // NOLINT
      SuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes));
  suppression_ctx->ParseFromFile(flags()->suppressions);
  if (&__asan_default_suppressions)
    suppression_ctx->Parse(__asan_default_suppressions());
}

bool IsInterceptorSuppressed(const char *interceptor_name) {
  CHECK(suppression_ctx);
  Suppression *s;
  // Match "interceptor_name" suppressions.
  return suppression_ctx->Match(interceptor_name, kInterceptorName, &s);
}

bool HaveStackTraceBasedSuppressions() {
  CHECK(suppression_ctx);
  return suppression_ctx->HasSuppressionType(kInterceptorViaFunction) ||
         suppression_ctx->HasSuppressionType(kInterceptorViaLibrary);
}

bool IsODRViolationSuppressed(const char *global_var_name) {
  CHECK(suppression_ctx);
  Suppression *s;
  // Match "odr_violation" suppressions.
  return suppression_ctx->Match(global_var_name, kODRViolation, &s);
}

bool IsStackTraceSuppressed(const StackTrace *stack) {
  if (!HaveStackTraceBasedSuppressions())
    return false;

  CHECK(suppression_ctx);
  Symbolizer *symbolizer = Symbolizer::GetOrInit();
  Suppression *s;
  for (uptr i = 0; i < stack->size && stack->trace[i]; i++) {
    uptr addr = stack->trace[i];

    if (suppression_ctx->HasSuppressionType(kInterceptorViaLibrary)) {
      const char *module_name;
      uptr module_offset;
      // Match "interceptor_via_lib" suppressions.
      if (symbolizer->GetModuleNameAndOffsetForPC(addr, &module_name,
                                                  &module_offset) &&
          suppression_ctx->Match(module_name, kInterceptorViaLibrary, &s)) {
        return true;
      }
    }

    if (suppression_ctx->HasSuppressionType(kInterceptorViaFunction)) {
      SymbolizedStack *frames = symbolizer->SymbolizePC(addr);
      for (SymbolizedStack *cur = frames; cur; cur = cur->next) {
        const char *function_name = cur->info.function;
        if (!function_name) {
          continue;
        }
        // Match "interceptor_via_fun" suppressions.
        if (suppression_ctx->Match(function_name, kInterceptorViaFunction,
                                   &s)) {
          frames->ClearAll();
          return true;
        }
      }
      frames->ClearAll();
    }
  }
  return false;
}

} // namespace __asan
<commit_msg>[asan] attempting to fix the windows build <commit_after>//===-- asan_suppressions.cc ----------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is a part of AddressSanitizer, an address sanity checker.
//
// Issue suppression and suppression-related functions.
//===----------------------------------------------------------------------===//

#include "asan_suppressions.h"

#include "asan_stack.h"
#include "sanitizer_common/sanitizer_placement_new.h"
#include "sanitizer_common/sanitizer_suppressions.h"
#include "sanitizer_common/sanitizer_symbolizer.h"

namespace __asan {

ALIGNED(64) static char suppression_placeholder[sizeof(SuppressionContext)];
static SuppressionContext *suppression_ctx = nullptr;
static const char kInterceptorName[] = "interceptor_name";
static const char kInterceptorViaFunction[] = "interceptor_via_fun";
static const char kInterceptorViaLibrary[] = "interceptor_via_lib";
static const char kODRViolation[] = "odr_violation";
static const char *kSuppressionTypes[] = {
    kInterceptorName, kInterceptorViaFunction, kInterceptorViaLibrary,
    kODRViolation};

#if SANITIZER_SUPPORTS_WEAK_HOOKS
extern "C" {
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
const char *__asan_default_suppressions();
}  // extern "C"
#endif  // SANITIZER_SUPPORTS_WEAK_HOOKS

void InitializeSuppressions() {
  CHECK_EQ(nullptr, suppression_ctx);
  suppression_ctx = new (suppression_placeholder)  // NOLINT
      SuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes));
  suppression_ctx->ParseFromFile(flags()->suppressions);
#if SANITIZER_SUPPORTS_WEAK_HOOKS
  if (&__asan_default_suppressions)
    suppression_ctx->Parse(__asan_default_suppressions());
#endif  // SANITIZER_SUPPORTS_WEAK_HOOKS
}

bool IsInterceptorSuppressed(const char *interceptor_name) {
  CHECK(suppression_ctx);
  Suppression *s;
  // Match "interceptor_name" suppressions.
  return suppression_ctx->Match(interceptor_name, kInterceptorName, &s);
}

bool HaveStackTraceBasedSuppressions() {
  CHECK(suppression_ctx);
  return suppression_ctx->HasSuppressionType(kInterceptorViaFunction) ||
         suppression_ctx->HasSuppressionType(kInterceptorViaLibrary);
}

bool IsODRViolationSuppressed(const char *global_var_name) {
  CHECK(suppression_ctx);
  Suppression *s;
  // Match "odr_violation" suppressions.
  return suppression_ctx->Match(global_var_name, kODRViolation, &s);
}

bool IsStackTraceSuppressed(const StackTrace *stack) {
  if (!HaveStackTraceBasedSuppressions())
    return false;

  CHECK(suppression_ctx);
  Symbolizer *symbolizer = Symbolizer::GetOrInit();
  Suppression *s;
  for (uptr i = 0; i < stack->size && stack->trace[i]; i++) {
    uptr addr = stack->trace[i];

    if (suppression_ctx->HasSuppressionType(kInterceptorViaLibrary)) {
      const char *module_name;
      uptr module_offset;
      // Match "interceptor_via_lib" suppressions.
      if (symbolizer->GetModuleNameAndOffsetForPC(addr, &module_name,
                                                  &module_offset) &&
          suppression_ctx->Match(module_name, kInterceptorViaLibrary, &s)) {
        return true;
      }
    }

    if (suppression_ctx->HasSuppressionType(kInterceptorViaFunction)) {
      SymbolizedStack *frames = symbolizer->SymbolizePC(addr);
      for (SymbolizedStack *cur = frames; cur; cur = cur->next) {
        const char *function_name = cur->info.function;
        if (!function_name) {
          continue;
        }
        // Match "interceptor_via_fun" suppressions.
        if (suppression_ctx->Match(function_name, kInterceptorViaFunction,
                                   &s)) {
          frames->ClearAll();
          return true;
        }
      }
      frames->ClearAll();
    }
  }
  return false;
}

} // namespace __asan
<|endoftext|>


<commit_before>// Copyright (c) 2007, 2008 libmv authors.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.

#include <cassert>
#include <vector>

#include "libmv/numeric/numeric.h"
#include "libmv/correspondence/klt.h"
#include "libmv/image/image.h"
#include "libmv/image/image_io.h"
#include "libmv/image/convolve.h"
#include "libmv/image/sample.h"

using std::vector;

namespace libmv {

static void FindLocalMaxima(const FloatImage &trackness,
                            float min_trackness,
                            KLTContext::FeatureList *features) {
  for (int i = 1; i < trackness.Height()-1; ++i) {
    for (int j = 1; j < trackness.Width()-1; ++j) {
      if (   trackness(i,j) >= min_trackness
          && trackness(i,j) >= trackness(i-1, j-1)
          && trackness(i,j) >= trackness(i-1, j  )
          && trackness(i,j) >= trackness(i-1, j+1)
          && trackness(i,j) >= trackness(i  , j-1)
          && trackness(i,j) >= trackness(i  , j+1)
          && trackness(i,j) >= trackness(i+1, j-1)
          && trackness(i,j) >= trackness(i+1, j  )
          && trackness(i,j) >= trackness(i+1, j+1)) {
        KLTPointFeature *p = new KLTPointFeature;
        p->position(1) = i;
        p->position(0) = j;
        p->trackness = trackness(i,j);
        features->push_back(p);
      }
    }
  }
}

// Compute the gradient matrix noted by Z in Good Features to Track.
//
//   Z = [gxx gxy; gxy gyy]
//
// This function computes the matrix for every pixel.
static void ComputeGradientMatrix(const Array3Df &image_and_gradients,
                                       int window_size,
                                       Array3Df *gradient_matrix) {
  Array3Df gradients;
  gradients.ResizeLike(image_and_gradients);
  for (int j = 0; j < image_and_gradients.Height(); ++j) {
    for (int i = 0; i < image_and_gradients.Width(); ++i) {
      float gx = image_and_gradients(j, i, 1);
      float gy = image_and_gradients(j, i, 2);
      gradients(j, i, 0) = gx * gx;
      gradients(j, i, 1) = gx * gy;
      gradients(j, i, 2) = gy * gy;
    }
  }
  // Sum the gradient matrix over tracking window for each pixel.
  BoxFilter(gradients, window_size, gradient_matrix);
}

// Given the three distinct elements of the symmetric 2x2 matrix
//
//                     [gxx gxy]
//                     [gxy gyy],
//
// return the minimum eigenvalue of the matrix.
// Borrowed from Stan Birchfield's KLT implementation.
static float MinEigenValue(float gxx, float gxy, float gyy) {
  return (gxx + gyy - sqrt((gxx - gyy) * (gxx - gyy) + 4 * gxy * gxy)) / 2.0f;
}

// Compute trackness of every pixel given the gradient matrix.
// This is done as described in the Good Features to Track paper.
static void ComputeTrackness(const Array3Df gradient_matrix,
                             Array3Df *trackness_pointer,
                             double *trackness_mean) {
  Array3Df &trackness = *trackness_pointer;
  trackness.Resize(gradient_matrix.Height(), gradient_matrix.Width());
  *trackness_mean = 0;
  for (int i = 0; i < trackness.Height(); ++i) {
    for (int j = 0; j < trackness.Width(); ++j) {
      double t = MinEigenValue(gradient_matrix(i, j, 0),
                               gradient_matrix(i, j, 1),
                               gradient_matrix(i, j, 2));
      trackness(i, j) = t;
      *trackness_mean += t;
    }
  }
  *trackness_mean /= trackness.Size();
}

static double dist2(const Vec2f &x, const Vec2f &y) {
  double a = x(0) - y(0);
  double b = x(1) - y(1);
  return a * a + b * b;
}

// TODO(keir): Use Stan's neat trick of using a 'punch-out' array to detect
// too-closes features. This is O(n^2)!
static void RemoveTooCloseFeatures(KLTContext::FeatureList *features,
                                   double mindist2) {

  KLTContext::FeatureList::iterator i = features->begin();
  while (i != features->end()) {
    bool i_deleted = false;
    KLTContext::FeatureList::iterator j = i;
    ++j;
    while (j != features->end() && !i_deleted) {
      if (dist2((*i)->position, (*j)->position) < mindist2) {
        KLTContext::FeatureList::iterator to_delete;
        if ((*i)->trackness < (*j)->trackness) {
          to_delete = i;
          ++i;
          i_deleted = true;
        } else {
          to_delete = j;
          ++j;
        }
        delete *to_delete;
        features->erase(to_delete);
      } else {
        ++j;
      }
    }
    if (!i_deleted) {
      ++i;
    }
  }
}

void KLTContext::DetectGoodFeatures(const Array3Df &image_and_gradients,
                                    FeatureList *features) {
  Array3Df gradient_matrix;
  ComputeGradientMatrix(image_and_gradients, WindowSize(), &gradient_matrix);

  Array3Df trackness;
  double trackness_mean;
  ComputeTrackness(gradient_matrix, &trackness, &trackness_mean);
  min_trackness_ = trackness_mean;

  FindLocalMaxima(trackness, min_trackness_, features);

  RemoveTooCloseFeatures(features, min_feature_dist_ * min_feature_dist_);
}

// TODO(keir): Restore or delete these functions...
void KLTContext::TrackFeatures(ImagePyramid *pyramid1,
                               const FeatureList &features1,
                               ImagePyramid *pyramid2,
                               FeatureList *features2_pointer) {
  FeatureList &features2 = *features2_pointer;

  features2.clear();
  for (FeatureList::const_iterator i = features1.begin();
       i != features1.end(); ++i) {
    KLTPointFeature *tracked_feature = new KLTPointFeature;
    TrackFeature(pyramid1, **i, pyramid2, tracked_feature);
    features2.push_back(tracked_feature);
  }
}

void KLTContext::TrackFeature(ImagePyramid *pyramid1,
                              const KLTPointFeature &feature1,
                              ImagePyramid *pyramid2,
                              KLTPointFeature *feature2_pointer) {
  const int highest_level = pyramid1->NumLevels() - 1;

  Vec2 position1, position2;
  position2(0) = feature1.position(0) / pow(2., highest_level + 1);
  position2(1) = feature1.position(1) / pow(2., highest_level + 1);

  for (int i = highest_level; i >= 0; --i) {
    position1(0) = feature1.position(0) / pow(2., i);
    position1(1) = feature1.position(1) / pow(2., i);
    position2(0) *= 2;
    position2(1) *= 2;

    TrackFeatureOneLevel(pyramid1->Level(i),
                         position1,
                         pyramid2->Level(i),
                         &position2);
  }
  feature2_pointer->position = position2;
}

// Compute the gradient matrix noted by Z and the error vector e.
// See Good Features to Track.
static void ComputeTrackingEquation(const Array3Df &image_and_gradient1,
                                    const Array3Df &image_and_gradient2,
                                    const Vec2 &position1,
                                    const Vec2 &position2,
                                    int half_width,
                                    float *gxx,
                                    float *gxy,
                                    float *gyy,
                                    float *ex,
                                    float *ey) {
  *gxx = 0;
  *gxy = 0;
  *gyy = 0;
  *ex = 0;
  *ey = 0;
  for (int i = -half_width; i <= half_width; ++i) {
    for (int j = -half_width; j <= half_width; ++j) {
      float x1 = position1(0) + j;
      float y1 = position1(1) + i;
      float x2 = position2(0) + j;
      float y2 = position2(1) + i;
      // TODO(pau): should do boundary checking outside this loop, and call here
      // a sampler that does not boundary checking.
      float I = SampleLinear(image_and_gradient1, y1, x1, 0);
      float J = SampleLinear(image_and_gradient2, y2, x2, 0);
      float gx = SampleLinear(image_and_gradient2, y2, x2, 1);
      float gy = SampleLinear(image_and_gradient2, y2, x2, 2);
      *gxx += gx * gx;
      *gxy += gx * gy;
      *gyy += gy * gy;
      *ex += (I - J) * gx;
      *ey += (I - J) * gy;
    }
  }
}

// Solve the tracking equation
//
//   [gxx gxy] [dx] = [ex]
//   [gxy gyy] [dy] = [ey]
//
// for dx and dy.  Borrowed from Stan Birchfield's KLT implementation.
static bool SolveTrackingEquation(float gxx, float gxy, float gyy,
                                  float ex, float ey,
                                  float min_determinant,
                                  float *dx, float *dy) {
  float det = gxx * gyy - gxy * gxy;
//  printf("det=%f, min_det=%f, gxx=%f, gxy=%f, gyy=%f\n", det, min_determinant,
//      gxx, gxy, gyy);
  if (det < min_determinant) {
    *dx = 0;
    *dy = 0;
    return false;
  }
  *dx = (gyy * ex - gxy * ey) / det;
  *dy = (gxx * ey - gxy * ex) / det;
  return true;
}

void KLTContext::TrackFeatureOneLevel(const Array3Df &image_and_gradient1,
                                      const Vec2 &position1,
                                      const Array3Df &image_and_gradient2,
                                      Vec2 *position2_pointer) {
  Vec2 &position2 = *position2_pointer;

  for (int i = 0; i < max_iterations_; ++i) {
    // Compute gradient matrix and error vector.
    float gxx, gxy, gyy, ex, ey;
    ComputeTrackingEquation(image_and_gradient1, image_and_gradient2,
                            position1, position2,
                            HalfWindowSize(),
                            &gxx, &gxy, &gyy, &ex, &ey);
    // Solve the linear system for deltad.
    float dx, dy;
    if (!SolveTrackingEquation(gxx, gxy, gyy, ex, ey, min_determinant_,
                               &dx, &dy)) {
      // TODO(keir): drop feature.
//      printf("dropped!\n");
    }

    // Update feature2 position.
    position2(0) += dx;
    position2(1) += dy;

    // TODO(keir): Handle other tracking failure conditions and pass the
    // reasons out to the caller. For example, for pyramid tracking a failure
    // at a coarse level suggests trying again at a finer level.
    if (Square(dx) + Square(dy) < min_update_distance2_) {
//      printf("distance too small: %f, %f\n", dx, dy);
      break;
    }
//    printf("dx=%f, dy=%f\n", dx, dy);
  }
}

void KLTContext::DrawFeatureList(const FeatureList &features,
                                 const Vec3 &color,
                                 FloatImage *image) const {
  for (FeatureList::const_iterator i = features.begin();
       i != features.end(); ++i) {
    DrawFeature(**i, color, image);
  }
}

void KLTContext::DrawFeature(const KLTPointFeature &feature,
                             const Vec3 &color,
                             FloatImage *image) const {
  assert(image->Depth() == 3);

  const int cross_width = 5;
  int x = lround(feature.position(0));
  int y = lround(feature.position(1));
  if (!image->Contains(y,x)) {
    return;
  }

  // Draw vertical line.
  for (int i = max(0, y - cross_width);
       i < min(image->Height(), y + cross_width + 1); ++i) {
    for (int k = 0; k < 3; ++k) {
      (*image)(i, x, k) = color(k);
    }
  }
  // Draw horizontal line.
  for (int j = max(0, x - cross_width);
       j < min(image->Width(), x + cross_width + 1); ++j) {
    for (int k = 0; k < 3; ++k) {
      (*image)(y, j, k) = color(k);
    }
  }
}

}  // namespace libmv
<commit_msg>Add debug printing to KLT.<commit_after>// Copyright (c) 2007, 2008 libmv authors.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.

#include <cassert>
#include <vector>

#include "libmv/numeric/numeric.h"
#include "libmv/correspondence/klt.h"
#include "libmv/image/image.h"
#include "libmv/image/image_io.h"
#include "libmv/image/convolve.h"
#include "libmv/image/sample.h"

using std::vector;

namespace libmv {

static void FindLocalMaxima(const FloatImage &trackness,
                            float min_trackness,
                            KLTContext::FeatureList *features) {
  for (int i = 1; i < trackness.Height()-1; ++i) {
    for (int j = 1; j < trackness.Width()-1; ++j) {
      if (   trackness(i,j) >= min_trackness
          && trackness(i,j) >= trackness(i-1, j-1)
          && trackness(i,j) >= trackness(i-1, j  )
          && trackness(i,j) >= trackness(i-1, j+1)
          && trackness(i,j) >= trackness(i  , j-1)
          && trackness(i,j) >= trackness(i  , j+1)
          && trackness(i,j) >= trackness(i+1, j-1)
          && trackness(i,j) >= trackness(i+1, j  )
          && trackness(i,j) >= trackness(i+1, j+1)) {
        KLTPointFeature *p = new KLTPointFeature;
        p->position(1) = i;
        p->position(0) = j;
        p->trackness = trackness(i,j);
        features->push_back(p);
      }
    }
  }
}

// Compute the gradient matrix noted by Z in Good Features to Track.
//
//   Z = [gxx gxy; gxy gyy]
//
// This function computes the matrix for every pixel.
static void ComputeGradientMatrix(const Array3Df &image_and_gradients,
                                       int window_size,
                                       Array3Df *gradient_matrix) {
  Array3Df gradients;
  gradients.ResizeLike(image_and_gradients);
  for (int j = 0; j < image_and_gradients.Height(); ++j) {
    for (int i = 0; i < image_and_gradients.Width(); ++i) {
      float gx = image_and_gradients(j, i, 1);
      float gy = image_and_gradients(j, i, 2);
      gradients(j, i, 0) = gx * gx;
      gradients(j, i, 1) = gx * gy;
      gradients(j, i, 2) = gy * gy;
    }
  }
  // Sum the gradient matrix over tracking window for each pixel.
  BoxFilter(gradients, window_size, gradient_matrix);
}

// Given the three distinct elements of the symmetric 2x2 matrix
//
//                     [gxx gxy]
//                     [gxy gyy],
//
// return the minimum eigenvalue of the matrix.
// Borrowed from Stan Birchfield's KLT implementation.
static float MinEigenValue(float gxx, float gxy, float gyy) {
  return (gxx + gyy - sqrt((gxx - gyy) * (gxx - gyy) + 4 * gxy * gxy)) / 2.0f;
}

// Compute trackness of every pixel given the gradient matrix.
// This is done as described in the Good Features to Track paper.
static void ComputeTrackness(const Array3Df gradient_matrix,
                             Array3Df *trackness_pointer,
                             double *trackness_mean) {
  Array3Df &trackness = *trackness_pointer;
  trackness.Resize(gradient_matrix.Height(), gradient_matrix.Width());
  *trackness_mean = 0;
  for (int i = 0; i < trackness.Height(); ++i) {
    for (int j = 0; j < trackness.Width(); ++j) {
      double t = MinEigenValue(gradient_matrix(i, j, 0),
                               gradient_matrix(i, j, 1),
                               gradient_matrix(i, j, 2));
      trackness(i, j) = t;
      *trackness_mean += t;
    }
  }
  *trackness_mean /= trackness.Size();
}

static double dist2(const Vec2f &x, const Vec2f &y) {
  double a = x(0) - y(0);
  double b = x(1) - y(1);
  return a * a + b * b;
}

// TODO(keir): Use Stan's neat trick of using a 'punch-out' array to detect
// too-closes features. This is O(n^2)!
static void RemoveTooCloseFeatures(KLTContext::FeatureList *features,
                                   double mindist2) {

  KLTContext::FeatureList::iterator i = features->begin();
  while (i != features->end()) {
    bool i_deleted = false;
    KLTContext::FeatureList::iterator j = i;
    ++j;
    while (j != features->end() && !i_deleted) {
      if (dist2((*i)->position, (*j)->position) < mindist2) {
        KLTContext::FeatureList::iterator to_delete;
        if ((*i)->trackness < (*j)->trackness) {
          to_delete = i;
          ++i;
          i_deleted = true;
        } else {
          to_delete = j;
          ++j;
        }
        delete *to_delete;
        features->erase(to_delete);
      } else {
        ++j;
      }
    }
    if (!i_deleted) {
      ++i;
    }
  }
}

void KLTContext::DetectGoodFeatures(const Array3Df &image_and_gradients,
                                    FeatureList *features) {
  Array3Df gradient_matrix;
  ComputeGradientMatrix(image_and_gradients, WindowSize(), &gradient_matrix);

  Array3Df trackness;
  double trackness_mean;
  ComputeTrackness(gradient_matrix, &trackness, &trackness_mean);
  min_trackness_ = trackness_mean;

  FindLocalMaxima(trackness, min_trackness_, features);

  RemoveTooCloseFeatures(features, min_feature_dist_ * min_feature_dist_);
}

// TODO(keir): Restore or delete these functions...
void KLTContext::TrackFeatures(ImagePyramid *pyramid1,
                               const FeatureList &features1,
                               ImagePyramid *pyramid2,
                               FeatureList *features2_pointer) {
  FeatureList &features2 = *features2_pointer;

  features2.clear();
  for (FeatureList::const_iterator i = features1.begin();
       i != features1.end(); ++i) {
    KLTPointFeature *tracked_feature = new KLTPointFeature;
    TrackFeature(pyramid1, **i, pyramid2, tracked_feature);
    features2.push_back(tracked_feature);
  }
}

void KLTContext::TrackFeature(ImagePyramid *pyramid1,
                              const KLTPointFeature &feature1,
                              ImagePyramid *pyramid2,
                              KLTPointFeature *feature2_pointer) {
  const int highest_level = pyramid1->NumLevels() - 1;

  Vec2 position1, position2;
  position2(0) = feature1.position(0) / pow(2., highest_level + 1);
  position2(1) = feature1.position(1) / pow(2., highest_level + 1);

  for (int i = highest_level; i >= 0; --i) {
    position1(0) = feature1.position(0) / pow(2., i);
    position1(1) = feature1.position(1) / pow(2., i);
    position2(0) *= 2;
    position2(1) *= 2;

    TrackFeatureOneLevel(pyramid1->Level(i),
                         position1,
                         pyramid2->Level(i),
                         &position2);
  }
  feature2_pointer->position = position2;
}

// Compute the gradient matrix noted by Z and the error vector e.
// See Good Features to Track.
static void ComputeTrackingEquation(const Array3Df &image_and_gradient1,
                                    const Array3Df &image_and_gradient2,
                                    const Vec2 &position1,
                                    const Vec2 &position2,
                                    int half_width,
                                    float *gxx,
                                    float *gxy,
                                    float *gyy,
                                    float *ex,
                                    float *ey) {
  *gxx = 0;
  *gxy = 0;
  *gyy = 0;
  *ex = 0;
  *ey = 0;
  for (int i = -half_width; i <= half_width; ++i) {
    for (int j = -half_width; j <= half_width; ++j) {
      float x1 = position1(0) + j;
      float y1 = position1(1) + i;
      float x2 = position2(0) + j;
      float y2 = position2(1) + i;
      // TODO(pau): should do boundary checking outside this loop, and call here
      // a sampler that does not boundary checking.
      float I = SampleLinear(image_and_gradient1, y1, x1, 0);
      float J = SampleLinear(image_and_gradient2, y2, x2, 0);
      float gx = SampleLinear(image_and_gradient2, y2, x2, 1);
      float gy = SampleLinear(image_and_gradient2, y2, x2, 2);
      *gxx += gx * gx;
      *gxy += gx * gy;
      *gyy += gy * gy;
      *ex += (I - J) * gx;
      *ey += (I - J) * gy;
    }
  }
}

// Solve the tracking equation
//
//   [gxx gxy] [dx] = [ex]
//   [gxy gyy] [dy] = [ey]
//
// for dx and dy.  Borrowed from Stan Birchfield's KLT implementation.
static bool SolveTrackingEquation(float gxx, float gxy, float gyy,
                                  float ex, float ey,
                                  float min_determinant,
                                  float *dx, float *dy) {
  float det = gxx * gyy - gxy * gxy;
//  printf("det=%f, min_det=%f, gxx=%f, gxy=%f, gyy=%f\n", det, min_determinant,
//      gxx, gxy, gyy);
  if (det < min_determinant) {
    *dx = 0;
    *dy = 0;
    return false;
  }
  *dx = (gyy * ex - gxy * ey) / det;
  *dy = (gxx * ey - gxy * ex) / det;
  return true;
}

void KLTContext::TrackFeatureOneLevel(const Array3Df &image_and_gradient1,
                                      const Vec2 &position1,
                                      const Array3Df &image_and_gradient2,
                                      Vec2 *position2_pointer) {
  Vec2 &position2 = *position2_pointer;

  int i;
  float dx=0, dy=0;
  max_iterations_ = 30;
  printf("disps = array([\n");
  for (i = 0; i < max_iterations_; ++i) {
    // Compute gradient matrix and error vector.
    float gxx, gxy, gyy, ex, ey;
    ComputeTrackingEquation(image_and_gradient1, image_and_gradient2,
                            position1, position2,
                            HalfWindowSize(),
                            &gxx, &gxy, &gyy, &ex, &ey);
    // Solve the linear system for deltad.
    if (!SolveTrackingEquation(gxx, gxy, gyy, ex, ey, min_determinant_,
                               &dx, &dy)) {
      // TODO(keir): drop feature.
      printf("dropped!\n");
    }

    // shrink the update
    dx *= 0.5;
    dy *= 0.5;

    // Update feature2 position.
    position2(0) += dx;
    position2(1) += dy;

    printf("  [%10f, %10f, %10f, %10f],\n", dx, dy, position2(0), position2(1));

    // TODO(keir): Handle other tracking failure conditions and pass the
    // reasons out to the caller. For example, for pyramid tracking a failure
    // at a coarse level suggests trying again at a finer level.
    if (Square(dx) + Square(dy) < min_update_distance2_) {
      printf("# distance too small: %f, %f\n", dx, dy);
      break;
    }
//    printf("dx=%f, dy=%f\n", dx, dy);
  }
  printf("])\n");
  if (i == max_iterations_) {
    printf("hit max iters. dx=%f, dy=%f\n", dx, dy);
  }
}

void KLTContext::DrawFeatureList(const FeatureList &features,
                                 const Vec3 &color,
                                 FloatImage *image) const {
  for (FeatureList::const_iterator i = features.begin();
       i != features.end(); ++i) {
    DrawFeature(**i, color, image);
  }
}

void KLTContext::DrawFeature(const KLTPointFeature &feature,
                             const Vec3 &color,
                             FloatImage *image) const {
  assert(image->Depth() == 3);

  const int cross_width = 5;
  int x = lround(feature.position(0));
  int y = lround(feature.position(1));
  if (!image->Contains(y,x)) {
    return;
  }

  // Draw vertical line.
  for (int i = max(0, y - cross_width);
       i < min(image->Height(), y + cross_width + 1); ++i) {
    for (int k = 0; k < 3; ++k) {
      (*image)(i, x, k) = color(k);
    }
  }
  // Draw horizontal line.
  for (int j = max(0, x - cross_width);
       j < min(image->Width(), x + cross_width + 1); ++j) {
    for (int k = 0; k < 3; ++k) {
      (*image)(y, j, k) = color(k);
    }
  }
}

}  // namespace libmv
<|endoftext|>