<commit_before>//---------------------------------------------------------------------------//
/*
  Copyright (c) 2012, Stuart R. Slattery
  All rights reserved.

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions are
  met:

  *: Redistributions of source code must retain the above copyright
  notice, this list of conditions and the following disclaimer.

  *: Redistributions in binary form must reproduce the above copyright
  notice, this list of conditions and the following disclaimer in the
  documentation and/or other materials provided with the distribution.

  *: Neither the name of the University of Wisconsin - Madison nor the
  names of its contributors may be used to endorse or promote products
  derived from this software without specific prior written permission.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
//---------------------------------------------------------------------------//
/*!
 * \brief DTK_ConsistentInterpolationOperator.cpp
 * \author Stuart R. Slattery
 * \brief Consistent interpolation operator.
 */
//---------------------------------------------------------------------------//

#include <algorithm>
#include <unordered_map>

#include "DTK_BasicEntityPredicates.hpp"
#include "DTK_ConsistentInterpolationOperator.hpp"
#include "DTK_DBC.hpp"
#include "DTK_ParallelSearch.hpp"
#include "DTK_PredicateComposition.hpp"

#include <Teuchos_OrdinalTraits.hpp>

#include <Tpetra_Distributor.hpp>
#include <Tpetra_Map.hpp>

namespace DataTransferKit
{
//---------------------------------------------------------------------------//
// Constructor.
ConsistentInterpolationOperator::ConsistentInterpolationOperator(
    const Teuchos::RCP<const TpetraMap> &domain_map,
    const Teuchos::RCP<const TpetraMap> &range_map,
    const Teuchos::ParameterList &parameters )
    : Base( domain_map, range_map )
    , d_range_entity_dim( 0 )
    , d_keep_missed_sol( false )
    , d_missed_range_entity_ids( 0 )
{
    // Get the topological dimension of the range entities.
    Teuchos::ParameterList map_list =
        parameters.sublist( "Consistent Interpolation" );
    if ( map_list.isParameter( "Range Entity Dimension" ) )
    {
        d_range_entity_dim = map_list.get<int>( "Range Entity Dimension" );
    }

    // Get the search list.
    d_search_list = parameters.sublist( "Search" );

    // If we want to keep the range data when we miss entities instead of
    // zeros, turn this on.
    if ( map_list.isParameter( "Keep Missed Range Data" ) )
    {
        d_keep_missed_sol = map_list.get<bool>( "Keep Missed Range Data" );
        if ( d_keep_missed_sol )
        {
            d_search_list.set( "Track Missed Range Entities", true );
        }
    }
}

//---------------------------------------------------------------------------//
// Setup the map operator.
void ConsistentInterpolationOperator::setupImpl(
    const Teuchos::RCP<FunctionSpace> &domain_space,
    const Teuchos::RCP<FunctionSpace> &range_space )
{
    DTK_REQUIRE( Teuchos::nonnull( domain_space ) );
    DTK_REQUIRE( Teuchos::nonnull( range_space ) );

    // Extract the Support maps.
    const Teuchos::RCP<const typename Base::TpetraMap> domain_map =
        this->getDomainMap();
    const Teuchos::RCP<const typename Base::TpetraMap> range_map =
        this->getRangeMap();

    // Get the parallel communicator.
    Teuchos::RCP<const Teuchos::Comm<int>> comm = domain_map->getComm();

    // Determine if we have range and domain data on this process.
    bool nonnull_domain = Teuchos::nonnull( domain_space->entitySet() );
    bool nonnull_range = Teuchos::nonnull( range_space->entitySet() );

    // Get the physical dimension.
    int physical_dimension = 0;
    if ( nonnull_domain )
    {
        physical_dimension = domain_space->entitySet()->physicalDimension();
    }
    else if ( nonnull_range )
    {
        physical_dimension = range_space->entitySet()->physicalDimension();
    }

    // Get an iterator over the domain entities.
    EntityIterator domain_iterator;
    if ( nonnull_domain )
    {
        LocalEntityPredicate local_predicate(
            domain_space->entitySet()->communicator()->getRank() );
        PredicateFunction domain_predicate = PredicateComposition::And(
            domain_space->selectFunction(), local_predicate.getFunction() );
        domain_iterator = domain_space->entitySet()->entityIterator(
            domain_space->entitySet()->physicalDimension(), domain_predicate );
    }

    // Build a parallel search over the domain.
    ParallelSearch psearch( comm, physical_dimension, domain_iterator,
                            domain_space->localMap(), d_search_list );

    // Get an iterator over the range entities.
    EntityIterator range_iterator;
    if ( nonnull_range )
    {
        LocalEntityPredicate local_predicate(
            range_space->entitySet()->communicator()->getRank() );
        PredicateFunction range_predicate = PredicateComposition::And(
            range_space->selectFunction(), local_predicate.getFunction() );
        range_iterator = range_space->entitySet()->entityIterator(
            d_range_entity_dim, range_predicate );
    }

    // Search the domain with the range.
    psearch.search( range_iterator, range_space->localMap(), d_search_list );

    // If we are keeping track of range entities that were not mapped, extract
    // them.
    d_missed_range_entity_ids =
        Teuchos::Array<EntityId>( psearch.getMissedRangeEntityIds() );

    // Determine the Support ids for the range entities found in the local
    // domain
    // on this process and the number of domain entities they were found in
    // globally for averaging.
    std::unordered_map<EntityId, GO> range_support_id_map;
    Teuchos::RCP<Tpetra::Vector<double, int, SupportId, Node>> scale_vector =
        Tpetra::createVector<double, int, SupportId, Node>( range_map );
    {
        // Extract the set of local range entities that were found in domain
        // entities.
        Teuchos::Array<int> export_ranks;
        Teuchos::Array<GO> export_data;
        Teuchos::Array<EntityId> domain_ids;
        Teuchos::Array<EntityId>::const_iterator domain_id_it;
        Teuchos::Array<GO> range_support_ids;
        EntityIterator range_it;
        EntityIterator range_begin = range_iterator.begin();
        EntityIterator range_end = range_iterator.end();
        for ( range_it = range_begin; range_it != range_end; ++range_it )
        {
            // Get the support id for the range entity.
            range_space->shapeFunction()->entitySupportIds( *range_it,
                                                            range_support_ids );
            DTK_CHECK( 1 == range_support_ids.size() );

            // Get the domain entities in which the range entity was found.
            psearch.getDomainEntitiesFromRange( range_it->id(), domain_ids );

            // Add a scale factor for this range entity to the scaling vector.
            DTK_CHECK( range_map->isNodeGlobalElement( range_support_ids[0] ) );
            scale_vector->replaceGlobalValue( range_support_ids[0],
                                              1.0 / domain_ids.size() );

            // For each supporting domain entity, pair the range entity id and
            // its support id.
            for ( domain_id_it = domain_ids.begin();
                  domain_id_it != domain_ids.end(); ++domain_id_it )
            {
                export_ranks.push_back(
                    psearch.domainEntityOwnerRank( *domain_id_it ) );

                export_data.push_back( range_support_ids[0] );
                export_data.push_back( Teuchos::as<GO>( range_it->id() ) );
            }
        }

        // Communicate the range entity Support data back to the domain parallel
        // decomposition.
        Tpetra::Distributor range_to_domain_dist( comm );
        int num_import = range_to_domain_dist.createFromSends( export_ranks() );
        Teuchos::Array<GO> import_data( 2 * num_import );
        Teuchos::ArrayView<const GO> export_data_view = export_data();
        range_to_domain_dist.doPostsAndWaits( export_data_view, 2,
                                              import_data() );

        // Map the range entities to their support ids.
        for ( int i = 0; i < num_import; ++i )
        {
            range_support_id_map.emplace(
                Teuchos::as<EntityId>( import_data[2 * i + 1] ),
                import_data[2 * i] );
        }
    }

    // Allocate the coupling matrix.
    d_coupling_matrix = Tpetra::createCrsMatrix<double, LO, GO>( range_map );

    // Construct the entries of the coupling matrix.
    Teuchos::Array<EntityId> range_entity_ids;
    Teuchos::Array<EntityId>::const_iterator range_entity_id_it;
    Teuchos::ArrayView<const double> range_parametric_coords;
    Teuchos::Array<double> domain_shape_values;
    Teuchos::Array<double>::iterator domain_shape_it;
    Teuchos::Array<GO> domain_support_ids;
    EntityIterator domain_it;
    EntityIterator domain_begin = domain_iterator.begin();
    EntityIterator domain_end = domain_iterator.end();
    for ( domain_it = domain_begin; domain_it != domain_end; ++domain_it )
    {
        // Get the domain Support ids supporting the domain entity.
        domain_space->shapeFunction()->entitySupportIds( *domain_it,
                                                         domain_support_ids );

        // Get the range entities that mapped into this domain entity.
        psearch.getRangeEntitiesFromDomain( domain_it->id(), range_entity_ids );

        // Sum into the global coupling matrix row for each domain.
        for ( range_entity_id_it = range_entity_ids.begin();
              range_entity_id_it != range_entity_ids.end();
              ++range_entity_id_it )
        {
            // Get the parametric coordinates of the range entity in the
            // domain entity.
            psearch.rangeParametricCoordinatesInDomain(
                domain_it->id(), *range_entity_id_it, range_parametric_coords );

            // Evaluate the shape function at the coordinates.
            domain_space->shapeFunction()->evaluateValue(
                *domain_it, range_parametric_coords, domain_shape_values );
            DTK_CHECK( domain_shape_values.size() ==
                       domain_support_ids.size() );

            // Consistent interpolation requires one support location per
            // range entity. Load the row for this range support location into
            // the matrix.
            DTK_CHECK( range_support_id_map.count( *range_entity_id_it ) );
            d_coupling_matrix->insertGlobalValues(
                range_support_id_map.find( *range_entity_id_it )->second,
                domain_support_ids(), domain_shape_values() );
        }
    }

    // Finalize the coupling matrix.
    d_coupling_matrix->fillComplete( domain_map, range_map );

    // Left-scale the matrix with the number of domain entities in which each
    // range entity was found.
    d_coupling_matrix->leftScale( *scale_vector );

    // If we want to keep the range data when we miss points, create the
    // scaling vector.
    if ( d_keep_missed_sol )
    {
        d_keep_range_vec =
            Tpetra::createVector<double, LO, GO, Node>( range_map );
        for ( auto &m : d_missed_range_entity_ids )
        {
            d_keep_range_vec->replaceGlobalValue( m, 1.0 );
        }
    }
}

//---------------------------------------------------------------------------//
// Apply the operator.
void ConsistentInterpolationOperator::applyImpl( const TpetraMultiVector &X,
                                                 TpetraMultiVector &Y,
                                                 Teuchos::ETransp mode,
                                                 double alpha,
                                                 double beta ) const
{
    // If we want to keep the range data when we miss points, make a work vec
    // and get the parts we will zero out. Beta must be zero or the interface
    // is violated.
    Teuchos::RCP<Tpetra::Vector<Scalar, LO, GO, Node>> work_vec;
    if ( d_keep_missed_sol )
    {
        DTK_REQUIRE( 0.0 == beta );
        DTK_REQUIRE( Teuchos::nonnull( d_keep_range_vec ) );
        work_vec =
            Tpetra::createVector<double, LO, GO, Node>( this->getRangeMap() );
        work_vec->elementWiseMultiply( 1.0, *d_keep_range_vec, Y, 0.0 );
    }

    // Apply the coupling matrix.
    d_coupling_matrix->apply( X, Y, mode, alpha, beta );

    // If we want to keep the range data when we miss points, add back in the
    // components that got zeroed out.
    if ( d_keep_missed_sol )
    {
        Y.update( 1.0, *work_vec, 1.0 );
    }
}

//---------------------------------------------------------------------------//
// Transpose apply option.
bool ConsistentInterpolationOperator::hasTransposeApplyImpl() const
{
    return true;
}

//---------------------------------------------------------------------------//
// Return the ids of the range entities that were not mapped during the last
// setup phase (i.e. those that are guaranteed to not receive data from the
// transfer).
Teuchos::ArrayView<const EntityId>
ConsistentInterpolationOperator::getMissedRangeEntityIds() const
{
    return d_missed_range_entity_ids();
}

//---------------------------------------------------------------------------//

} // end namespace DataTransferKit

//---------------------------------------------------------------------------//
// end DTK_ConsistentInterpolationOperator.cpp
//---------------------------------------------------------------------------//
<commit_msg>Do not divide by zero.<commit_after>//---------------------------------------------------------------------------//
/*
  Copyright (c) 2012, Stuart R. Slattery
  All rights reserved.

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions are
  met:

  *: Redistributions of source code must retain the above copyright
  notice, this list of conditions and the following disclaimer.

  *: Redistributions in binary form must reproduce the above copyright
  notice, this list of conditions and the following disclaimer in the
  documentation and/or other materials provided with the distribution.

  *: Neither the name of the University of Wisconsin - Madison nor the
  names of its contributors may be used to endorse or promote products
  derived from this software without specific prior written permission.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
//---------------------------------------------------------------------------//
/*!
 * \brief DTK_ConsistentInterpolationOperator.cpp
 * \author Stuart R. Slattery
 * \brief Consistent interpolation operator.
 */
//---------------------------------------------------------------------------//

#include <algorithm>
#include <unordered_map>

#include "DTK_BasicEntityPredicates.hpp"
#include "DTK_ConsistentInterpolationOperator.hpp"
#include "DTK_DBC.hpp"
#include "DTK_ParallelSearch.hpp"
#include "DTK_PredicateComposition.hpp"

#include <Teuchos_OrdinalTraits.hpp>

#include <Tpetra_Distributor.hpp>
#include <Tpetra_Map.hpp>

namespace DataTransferKit
{
//---------------------------------------------------------------------------//
// Constructor.
ConsistentInterpolationOperator::ConsistentInterpolationOperator(
    const Teuchos::RCP<const TpetraMap> &domain_map,
    const Teuchos::RCP<const TpetraMap> &range_map,
    const Teuchos::ParameterList &parameters )
    : Base( domain_map, range_map )
    , d_range_entity_dim( 0 )
    , d_keep_missed_sol( false )
    , d_missed_range_entity_ids( 0 )
{
    // Get the topological dimension of the range entities.
    Teuchos::ParameterList map_list =
        parameters.sublist( "Consistent Interpolation" );
    if ( map_list.isParameter( "Range Entity Dimension" ) )
    {
        d_range_entity_dim = map_list.get<int>( "Range Entity Dimension" );
    }

    // Get the search list.
    d_search_list = parameters.sublist( "Search" );

    // If we want to keep the range data when we miss entities instead of
    // zeros, turn this on.
    if ( map_list.isParameter( "Keep Missed Range Data" ) )
    {
        d_keep_missed_sol = map_list.get<bool>( "Keep Missed Range Data" );
        if ( d_keep_missed_sol )
        {
            d_search_list.set( "Track Missed Range Entities", true );
        }
    }
}

//---------------------------------------------------------------------------//
// Setup the map operator.
void ConsistentInterpolationOperator::setupImpl(
    const Teuchos::RCP<FunctionSpace> &domain_space,
    const Teuchos::RCP<FunctionSpace> &range_space )
{
    DTK_REQUIRE( Teuchos::nonnull( domain_space ) );
    DTK_REQUIRE( Teuchos::nonnull( range_space ) );

    // Extract the Support maps.
    const Teuchos::RCP<const typename Base::TpetraMap> domain_map =
        this->getDomainMap();
    const Teuchos::RCP<const typename Base::TpetraMap> range_map =
        this->getRangeMap();

    // Get the parallel communicator.
    Teuchos::RCP<const Teuchos::Comm<int>> comm = domain_map->getComm();

    // Determine if we have range and domain data on this process.
    bool nonnull_domain = Teuchos::nonnull( domain_space->entitySet() );
    bool nonnull_range = Teuchos::nonnull( range_space->entitySet() );

    // Get the physical dimension.
    int physical_dimension = 0;
    if ( nonnull_domain )
    {
        physical_dimension = domain_space->entitySet()->physicalDimension();
    }
    else if ( nonnull_range )
    {
        physical_dimension = range_space->entitySet()->physicalDimension();
    }

    // Get an iterator over the domain entities.
    EntityIterator domain_iterator;
    if ( nonnull_domain )
    {
        LocalEntityPredicate local_predicate(
            domain_space->entitySet()->communicator()->getRank() );
        PredicateFunction domain_predicate = PredicateComposition::And(
            domain_space->selectFunction(), local_predicate.getFunction() );
        domain_iterator = domain_space->entitySet()->entityIterator(
            domain_space->entitySet()->physicalDimension(), domain_predicate );
    }

    // Build a parallel search over the domain.
    ParallelSearch psearch( comm, physical_dimension, domain_iterator,
                            domain_space->localMap(), d_search_list );

    // Get an iterator over the range entities.
    EntityIterator range_iterator;
    if ( nonnull_range )
    {
        LocalEntityPredicate local_predicate(
            range_space->entitySet()->communicator()->getRank() );
        PredicateFunction range_predicate = PredicateComposition::And(
            range_space->selectFunction(), local_predicate.getFunction() );
        range_iterator = range_space->entitySet()->entityIterator(
            d_range_entity_dim, range_predicate );
    }

    // Search the domain with the range.
    psearch.search( range_iterator, range_space->localMap(), d_search_list );

    // If we are keeping track of range entities that were not mapped, extract
    // them.
    d_missed_range_entity_ids =
        Teuchos::Array<EntityId>( psearch.getMissedRangeEntityIds() );

    // Determine the Support ids for the range entities found in the local
    // domain
    // on this process and the number of domain entities they were found in
    // globally for averaging.
    std::unordered_map<EntityId, GO> range_support_id_map;
    Teuchos::RCP<Tpetra::Vector<double, int, SupportId, Node>> scale_vector =
        Tpetra::createVector<double, int, SupportId, Node>( range_map );
    {
        // Extract the set of local range entities that were found in domain
        // entities.
        Teuchos::Array<int> export_ranks;
        Teuchos::Array<GO> export_data;
        Teuchos::Array<EntityId> domain_ids;
        Teuchos::Array<EntityId>::const_iterator domain_id_it;
        Teuchos::Array<GO> range_support_ids;
        EntityIterator range_it;
        EntityIterator range_begin = range_iterator.begin();
        EntityIterator range_end = range_iterator.end();
        for ( range_it = range_begin; range_it != range_end; ++range_it )
        {
            // Get the support id for the range entity.
            range_space->shapeFunction()->entitySupportIds( *range_it,
                                                            range_support_ids );
            DTK_CHECK( 1 == range_support_ids.size() );

            // Get the domain entities in which the range entity was found.
            psearch.getDomainEntitiesFromRange( range_it->id(), domain_ids );

            // Add a scale factor for this range entity to the scaling vector.
            DTK_CHECK( range_map->isNodeGlobalElement( range_support_ids[0] ) );
            const double scale_factor =
                ( domain_ids.size() != 0 ) ? 1.0 / domain_ids.size() : 1.;
            scale_vector->replaceGlobalValue( range_support_ids[0],
                                              scale_factor );

            // For each supporting domain entity, pair the range entity id and
            // its support id.
            for ( domain_id_it = domain_ids.begin();
                  domain_id_it != domain_ids.end(); ++domain_id_it )
            {
                export_ranks.push_back(
                    psearch.domainEntityOwnerRank( *domain_id_it ) );

                export_data.push_back( range_support_ids[0] );
                export_data.push_back( Teuchos::as<GO>( range_it->id() ) );
            }
        }

        // Communicate the range entity Support data back to the domain parallel
        // decomposition.
        Tpetra::Distributor range_to_domain_dist( comm );
        int num_import = range_to_domain_dist.createFromSends( export_ranks() );
        Teuchos::Array<GO> import_data( 2 * num_import );
        Teuchos::ArrayView<const GO> export_data_view = export_data();
        range_to_domain_dist.doPostsAndWaits( export_data_view, 2,
                                              import_data() );

        // Map the range entities to their support ids.
        for ( int i = 0; i < num_import; ++i )
        {
            range_support_id_map.emplace(
                Teuchos::as<EntityId>( import_data[2 * i + 1] ),
                import_data[2 * i] );
        }
    }

    // Allocate the coupling matrix.
    d_coupling_matrix = Tpetra::createCrsMatrix<double, LO, GO>( range_map );

    // Construct the entries of the coupling matrix.
    Teuchos::Array<EntityId> range_entity_ids;
    Teuchos::Array<EntityId>::const_iterator range_entity_id_it;
    Teuchos::ArrayView<const double> range_parametric_coords;
    Teuchos::Array<double> domain_shape_values;
    Teuchos::Array<double>::iterator domain_shape_it;
    Teuchos::Array<GO> domain_support_ids;
    EntityIterator domain_it;
    EntityIterator domain_begin = domain_iterator.begin();
    EntityIterator domain_end = domain_iterator.end();
    for ( domain_it = domain_begin; domain_it != domain_end; ++domain_it )
    {
        // Get the domain Support ids supporting the domain entity.
        domain_space->shapeFunction()->entitySupportIds( *domain_it,
                                                         domain_support_ids );

        // Get the range entities that mapped into this domain entity.
        psearch.getRangeEntitiesFromDomain( domain_it->id(), range_entity_ids );

        // Sum into the global coupling matrix row for each domain.
        for ( range_entity_id_it = range_entity_ids.begin();
              range_entity_id_it != range_entity_ids.end();
              ++range_entity_id_it )
        {
            // Get the parametric coordinates of the range entity in the
            // domain entity.
            psearch.rangeParametricCoordinatesInDomain(
                domain_it->id(), *range_entity_id_it, range_parametric_coords );

            // Evaluate the shape function at the coordinates.
            domain_space->shapeFunction()->evaluateValue(
                *domain_it, range_parametric_coords, domain_shape_values );
            DTK_CHECK( domain_shape_values.size() ==
                       domain_support_ids.size() );

            // Consistent interpolation requires one support location per
            // range entity. Load the row for this range support location into
            // the matrix.
            DTK_CHECK( range_support_id_map.count( *range_entity_id_it ) );
            d_coupling_matrix->insertGlobalValues(
                range_support_id_map.find( *range_entity_id_it )->second,
                domain_support_ids(), domain_shape_values() );
        }
    }

    // Finalize the coupling matrix.
    d_coupling_matrix->fillComplete( domain_map, range_map );

    // Left-scale the matrix with the number of domain entities in which each
    // range entity was found.
    d_coupling_matrix->leftScale( *scale_vector );

    // If we want to keep the range data when we miss points, create the
    // scaling vector.
    if ( d_keep_missed_sol )
    {
        d_keep_range_vec =
            Tpetra::createVector<double, LO, GO, Node>( range_map );
        for ( auto &m : d_missed_range_entity_ids )
        {
            d_keep_range_vec->replaceGlobalValue( m, 1.0 );
        }
    }
}

//---------------------------------------------------------------------------//
// Apply the operator.
void ConsistentInterpolationOperator::applyImpl( const TpetraMultiVector &X,
                                                 TpetraMultiVector &Y,
                                                 Teuchos::ETransp mode,
                                                 double alpha,
                                                 double beta ) const
{
    // If we want to keep the range data when we miss points, make a work vec
    // and get the parts we will zero out. Beta must be zero or the interface
    // is violated.
    Teuchos::RCP<Tpetra::Vector<Scalar, LO, GO, Node>> work_vec;
    if ( d_keep_missed_sol )
    {
        DTK_REQUIRE( 0.0 == beta );
        DTK_REQUIRE( Teuchos::nonnull( d_keep_range_vec ) );
        work_vec =
            Tpetra::createVector<double, LO, GO, Node>( this->getRangeMap() );
        work_vec->elementWiseMultiply( 1.0, *d_keep_range_vec, Y, 0.0 );
    }

    // Apply the coupling matrix.
    d_coupling_matrix->apply( X, Y, mode, alpha, beta );

    // If we want to keep the range data when we miss points, add back in the
    // components that got zeroed out.
    if ( d_keep_missed_sol )
    {
        Y.update( 1.0, *work_vec, 1.0 );
    }
}

//---------------------------------------------------------------------------//
// Transpose apply option.
bool ConsistentInterpolationOperator::hasTransposeApplyImpl() const
{
    return true;
}

//---------------------------------------------------------------------------//
// Return the ids of the range entities that were not mapped during the last
// setup phase (i.e. those that are guaranteed to not receive data from the
// transfer).
Teuchos::ArrayView<const EntityId>
ConsistentInterpolationOperator::getMissedRangeEntityIds() const
{
    return d_missed_range_entity_ids();
}

//---------------------------------------------------------------------------//

} // end namespace DataTransferKit

//---------------------------------------------------------------------------//
// end DTK_ConsistentInterpolationOperator.cpp
//---------------------------------------------------------------------------//
<|endoftext|>


<commit_before>#ifndef STAN__MATH__MATRIX__EXP_HPP
#define STAN__MATH__MATRIX__EXP_HPP

#include <stan/math/matrix/Eigen.hpp>

namespace stan {
  namespace math {

    /**
     * Return the element-wise exponentiation of the matrix or vector.
     *
     * @param m The matrix or vector.
     * @return ret(i,j) = exp(m(i,j))
     */
    template<typename T, int Rows, int Cols>
    inline Eigen::Matrix<T,Rows,Cols> exp(const Eigen::Matrix<T,Rows,Cols>& m) {
      return m.array().exp().matrix();
    }

  }
}
#endif
<commit_msg>Fix stan::math::exp behaviour for NaN (for matrices of doubles)<commit_after>#ifndef STAN__MATH__MATRIX__EXP_HPP
#define STAN__MATH__MATRIX__EXP_HPP

#include <stan/math/matrix/Eigen.hpp>

namespace stan {
  namespace math {

    /**
     * Return the element-wise exponentiation of the matrix or vector.
     *
     * @param m The matrix or vector.
     * @return ret(i,j) = exp(m(i,j))
     */
    template<typename T, int Rows, int Cols>
    inline Eigen::Matrix<T,Rows,Cols> exp(Eigen::Matrix<T,Rows,Cols> mat) {
      T * mat_ = mat.data();
      for (int i = 0, size_ = mat.size(); i < size_; i++)
        mat_[i] = std::exp(mat_[i]);
      return mat;
    }

  }
}
#endif
<|endoftext|>


<commit_before>#ifndef STAN__MATH__MATRIX__EXP_HPP
#define STAN__MATH__MATRIX__EXP_HPP

#include <stan/math/matrix/Eigen.hpp>

namespace stan {
  namespace math {

    /**
     * Return the element-wise exponentiation of the matrix or vector.
     *
     * @param m The matrix or vector.
     * @return ret(i,j) = exp(m(i,j))
     */
    template<typename T, int Rows, int Cols>
    inline Eigen::Matrix<T,Rows,Cols> exp(Eigen::Matrix<T,Rows,Cols> mat) {
      for (T * it = mat.data(), * end_ = it + mat.size(); it != end_; it++)
        *it = exp(*it);
      return mat;
    }

  }
}
#endif
<commit_msg>stan::math::exp(Eigen::Matrix) will have an specialized version for double that will check for nan inputs<commit_after>#ifndef STAN__MATH__MATRIX__EXP_HPP
#define STAN__MATH__MATRIX__EXP_HPP

#include <stan/math/matrix/Eigen.hpp>
#include <boost/math/special_functions/fpclassify.hpp>

namespace stan {
  namespace math {

    /**
     * Return the element-wise exponentiation of the matrix or vector.
     *
     * @param m The matrix or vector.
     * @return ret(i,j) = exp(m(i,j))
     */
    template<typename T, int Rows, int Cols>
    inline Eigen::Matrix<T,Rows,Cols> exp(const Eigen::Matrix<T,Rows,Cols> & m) {
      return m.array().exp().matrix();
    }

    template<int Rows, int Cols>
    inline Eigen::Matrix<double,Rows,Cols> exp(const Eigen::Matrix<double,Rows,Cols> & m) {
      for (const double * it = m.data(), * end_ = it + m.size(); it != end_; it++)
        if (boost::math::isnan(*it)) {
          Eigen::Matrix<double,Rows,Cols> mat = m;
          for (double * it = mat.data(), * end_ = it + mat.size(); it != end_; it++)
            *it = std::exp(*it);
          return mat;
        }
      return m.array().exp().matrix();
    }

  }
}
#endif
<|endoftext|>


<commit_before>#pragma once

#include "common/Emotemap.hpp"
#include "messages/Image.hpp"
#include "messages/Link.hpp"
#include "messages/MessageColor.hpp"
#include "singletons/Fonts.hpp"

#include <QRect>
#include <QString>
#include <QTime>
#include <boost/noncopyable.hpp>

#include <cstdint>
#include <memory>

namespace chatterino {
class Channel;
struct EmoteData;
struct MessageLayoutContainer;

class MessageElement : boost::noncopyable
{
public:
    enum Flags : uint32_t {
        None = 0,
        Misc = (1 << 0),
        Text = (1 << 1),

        Username = (1 << 2),
        Timestamp = (1 << 3),

        TwitchEmoteImage = (1 << 4),
        TwitchEmoteText = (1 << 5),
        TwitchEmote = TwitchEmoteImage | TwitchEmoteText,
        BttvEmoteImage = (1 << 6),
        BttvEmoteText = (1 << 7),
        BttvEmote = BttvEmoteImage | BttvEmoteText,
        FfzEmoteImage = (1 << 10),
        FfzEmoteText = (1 << 11),
        FfzEmote = FfzEmoteImage | FfzEmoteText,
        EmoteImages = TwitchEmoteImage | BttvEmoteImage | FfzEmoteImage,

        BitsStatic = (1 << 12),
        BitsAnimated = (1 << 13),

        // Slot 1: Twitch
        // - Staff badge
        // - Admin badge
        // - Global Moderator badge
        BadgeGlobalAuthority = (1 << 14),

        // Slot 2: Twitch
        // - Moderator badge
        // - Broadcaster badge
        BadgeChannelAuthority = (1 << 15),

        // Slot 3: Twitch
        // - Subscription badges
        BadgeSubscription = (1 << 16),

        // Slot 4: Twitch
        // - Turbo badge
        // - Prime badge
        // - Bit badges
        // - Game badges
        BadgeVanity = (1 << 17),

        // Slot 5: Chatterino
        // - Chatterino developer badge
        // - Chatterino donator badge
        // - Chatterino top donator badge
        BadgeChatterino = (1 << 18),

        // Rest of slots: ffz custom badge? bttv custom badge? mywaifu (puke) custom badge?

        Badges = BadgeGlobalAuthority | BadgeChannelAuthority | BadgeSubscription | BadgeVanity |
                 BadgeChatterino,

        ChannelName = (1 << 19),

        BitsAmount = (1 << 20),

        ModeratorTools = (1 << 21),

        EmojiImage = (1 << 23),
        EmojiText = (1 << 24),
        EmojiAll = EmojiImage | EmojiText,

        AlwaysShow = (1 << 25),

        // used in the ChannelView class to make the collapse buttons visible if needed
        Collapsed = (1 << 26),

        Default = Timestamp | Badges | Username | BitsStatic | FfzEmoteImage | BttvEmoteImage |
                  TwitchEmoteImage | BitsAmount | Text | AlwaysShow,
    };

    enum UpdateFlags : char {
        Update_Text,
        Update_Emotes,
        Update_Images,
        Update_All = Update_Text | Update_Emotes | Update_Images
    };

    virtual ~MessageElement();

    MessageElement *setLink(const Link &link);
    MessageElement *setTooltip(const QString &tooltip);
    MessageElement *setTrailingSpace(bool value);
    const QString &getTooltip() const;
    const Link &getLink() const;
    bool hasTrailingSpace() const;
    Flags getFlags() const;

    virtual void addToContainer(MessageLayoutContainer &container, MessageElement::Flags flags) = 0;

protected:
    MessageElement(Flags flags);
    bool trailingSpace = true;

private:
    Link link;
    QString tooltip;
    Flags flags;
};

// contains a simple image
class ImageElement : public MessageElement
{
    Image *image;

public:
    ImageElement(Image *image, MessageElement::Flags flags);

    void addToContainer(MessageLayoutContainer &container, MessageElement::Flags flags) override;
};

// contains a text, it will split it into words
class TextElement : public MessageElement
{
    MessageColor color;
    FontStyle style;

    struct Word {
        QString text;
        int width = -1;
    };
    std::vector<Word> words;

public:
    TextElement(const QString &text, MessageElement::Flags flags,
                const MessageColor &color = MessageColor::Text,
                FontStyle style = FontStyle::ChatMedium);
    ~TextElement() override = default;

    void addToContainer(MessageLayoutContainer &container, MessageElement::Flags flags) override;
};

// contains emote data and will pick the emote based on :
//   a) are images for the emote type enabled
//   b) which size it wants
class EmoteElement : public MessageElement
{
    std::unique_ptr<TextElement> textElement;

public:
    EmoteElement(const EmoteData &data, MessageElement::Flags flags);
    ~EmoteElement() override = default;

    void addToContainer(MessageLayoutContainer &container, MessageElement::Flags flags) override;

    const EmoteData data;
};

// contains a text, formated depending on the preferences
class TimestampElement : public MessageElement
{
    QTime time;
    std::unique_ptr<TextElement> element;
    QString format;

public:
    TimestampElement(QTime time = QTime::currentTime());
    ~TimestampElement() override = default;

    void addToContainer(MessageLayoutContainer &container, MessageElement::Flags flags) override;

    TextElement *formatTime(const QTime &time);
};

// adds all the custom moderation buttons, adds a variable amount of items depending on settings
// fourtf: implement
class TwitchModerationElement : public MessageElement
{
public:
    TwitchModerationElement();

    void addToContainer(MessageLayoutContainer &container, MessageElement::Flags flags) override;
};

}  // namespace chatterino
<commit_msg>Changed some stuff<commit_after>#pragma once

#include "common/Emotemap.hpp"
#include "messages/Image.hpp"
#include "messages/Link.hpp"
#include "messages/MessageColor.hpp"
#include "singletons/Fonts.hpp"

#include <QRect>
#include <QString>
#include <QTime>
#include <boost/noncopyable.hpp>

#include <cstdint>
#include <memory>

namespace chatterino {
class Channel;
struct EmoteData;
struct MessageLayoutContainer;

class MessageElement : boost::noncopyable
{
public:
    enum Flags : uint32_t {
        None = 0,
        Misc = (1 << 0),
        Text = (1 << 1),

        Username = (1 << 2),
        Timestamp = (1 << 3),

        TwitchEmoteImage = (1 << 4),
        TwitchEmoteText = (1 << 5),
        TwitchEmote = TwitchEmoteImage | TwitchEmoteText,
        BttvEmoteImage = (1 << 6),
        BttvEmoteText = (1 << 7),
        BttvEmote = BttvEmoteImage | BttvEmoteText,
        FfzEmoteImage = (1 << 10),
        FfzEmoteText = (1 << 11),
        FfzEmote = FfzEmoteImage | FfzEmoteText,
        EmoteImages = TwitchEmoteImage | BttvEmoteImage | FfzEmoteImage,

        BitsStatic = (1 << 12),
        BitsAnimated = (1 << 13),

        // Slot 1: Twitch
        // - Staff badge
        // - Admin badge
        // - Global Moderator badge
        BadgeGlobalAuthority = (1 << 14),

        // Slot 2: Twitch
        // - Moderator badge
        // - Broadcaster badge
        BadgeChannelAuthority = (1 << 15),

        // Slot 3: Twitch
        // - Subscription badges
        BadgeSubscription = (1 << 16),

        // Slot 4: Twitch
        // - Turbo badge
        // - Prime badge
        // - Bit badges
        // - Game badges
        BadgeVanity = (1 << 17),

        // Slot 5: Chatterino
        // - Chatterino developer badge
        // - Chatterino donator badge
        // - Chatterino top donator badge
        BadgeChatterino = (1 << 18),

        // Rest of slots: ffz custom badge? bttv custom badge? mywaifu (puke) custom badge?

        Badges = BadgeGlobalAuthority | BadgeChannelAuthority | BadgeSubscription | BadgeVanity |
                 BadgeChatterino,

        ChannelName = (1 << 19),

        BitsAmount = (1 << 20),

        ModeratorTools = (1 << 21),

        EmojiImage = (1 << 23),
        EmojiText = (1 << 24),
        EmojiAll = EmojiImage | EmojiText,

        AlwaysShow = (1 << 25),

        // used in the ChannelView class to make the collapse buttons visible if needed
        Collapsed = (1 << 26),

        Default = Timestamp | Badges | Username | BitsStatic | FfzEmoteImage | BttvEmoteImage |
                  TwitchEmoteImage | BitsAmount | Text | AlwaysShow,
    };

    enum UpdateFlags : char {
        Update_Text,
        Update_Emotes,
        Update_Images,
        Update_All = Update_Text | Update_Emotes | Update_Images
    };

    virtual ~MessageElement();

    MessageElement *setLink(const Link &link);
    MessageElement *setTooltip(const QString &tooltip);
    MessageElement *setTrailingSpace(bool value);
    const QString &getTooltip() const;
    const Link &getLink() const;
    bool hasTrailingSpace() const;
    Flags getFlags() const;

    virtual void addToContainer(MessageLayoutContainer &container, MessageElement::Flags flags) = 0;

protected:
    MessageElement(Flags flags);
    bool trailingSpace = true;

private:
    Link link;
    QString tooltip;
    Flags flags;
};

// contains a simple image
class ImageElement : public MessageElement
{
    Image *image;

public:
    ImageElement(Image *image, MessageElement::Flags flags);

    void addToContainer(MessageLayoutContainer &container, MessageElement::Flags flags) override;
};

// contains a text, it will split it into words
class TextElement : public MessageElement
{
    MessageColor color;
    FontStyle style;

    struct Word {
        QString text;
        int width = -1;
    };
    std::vector<Word> words;

public:
    TextElement(const QString &text, MessageElement::Flags flags,
                const MessageColor &color = MessageColor::Text,
                FontStyle style = FontStyle::ChatMedium);
    ~TextElement() override = default;

    void addToContainer(MessageLayoutContainer &container, MessageElement::Flags flags) override;
};

// contains emote data and will pick the emote based on :
//   a) are images for the emote type enabled
//   b) which size it wants
class EmoteElement : public MessageElement
{
    std::unique_ptr<TextElement> textElement;

public:
    EmoteElement(const EmoteData &data, MessageElement::Flags flags);
    ~EmoteElement() override = default;

    void addToContainer(MessageLayoutContainer &container, MessageElement::Flags flags) override;

    const EmoteData data;
};

// contains a text, formated depending on the preferences
class TimestampElement : public MessageElement
{
public:
    TimestampElement(QTime time_ = QTime::currentTime());
    ~TimestampElement() override = default;

    void addToContainer(MessageLayoutContainer &container, MessageElement::Flags flags) override;

    TextElement *formatTime(const QTime &time_);

private:
    QTime time_;
    std::unique_ptr<TextElement> element_;
    QString format_;
};

// adds all the custom moderation buttons, adds a variable amount of items depending on settings
// fourtf: implement
class TwitchModerationElement : public MessageElement
{
public:
    TwitchModerationElement();

    void addToContainer(MessageLayoutContainer &container, MessageElement::Flags flags) override;
};

}  // namespace chatterino
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2008 James Molloy, Jörg Pfähler, Matthew Iselin
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <Log.h>
#include <vfs/VFS.h>
#include <vfs/Directory.h>
#include "../../subsys/posix/PosixSubsystem.h"
#include <machine/Device.h>
#include <machine/Disk.h>
#include <Module.h>
#include <processor/Processor.h>
#include <linker/Elf.h>
#include <process/Thread.h>
#include <process/Process.h>
#include <process/Scheduler.h>
#include <processor/PhysicalMemoryManager.h>
#include <processor/VirtualAddressSpace.h>
#include <machine/Machine.h>
#include <linker/DynamicLinker.h>
#include <panic.h>
#include <utilities/assert.h>

#include <kernel/core/BootIO.h>

#include <network-stack/NetworkStack.h>
#include <network-stack/RoutingTable.h>
#include <network-stack/UdpLogger.h>

#include <users/UserManager.h>

#include <utilities/TimeoutGuard.h>

#include <config/ConfigurationManager.h>
#include <config/MemoryBackend.h>

#include <machine/DeviceHashTree.h>
#include <lodisk/LoDisk.h>

#include <machine/InputManager.h>

extern void pedigree_init_sigret();
extern void pedigree_init_pthreads();

extern BootIO bootIO;

void init_stage2();

static bool bRootMounted = false;
static bool probeDisk(Disk *pDisk)
{
    String alias; // Null - gets assigned by the filesystem.
    if (VFS::instance().mount(pDisk, alias))
    {
        // For mount message
        bool didMountAsRoot = false;

        // Search for the root specifier, if we haven't already mounted root
        if (!bRootMounted)
        {
            NormalStaticString s;
            s += alias;
            s += "»/.pedigree-root";

            File* f = VFS::instance().find(String(static_cast<const char*>(s)));
            if (f && !bRootMounted)
            {
                NOTICE("Mounted " << alias << " successfully as root.");
                VFS::instance().addAlias(alias, String("root"));
                bRootMounted = didMountAsRoot = true;
            }
        }

        if(!didMountAsRoot)
        {
            NOTICE("Mounted " << alias << ".");
        }
        return false;
    }
    return false;
}

static bool findDisks(Device *pDev)
{
    for (unsigned int i = 0; i < pDev->getNumChildren(); i++)
    {
        Device *pChild = pDev->getChild(i);
        if (pChild->getNumChildren() == 0 && /* Only check leaf nodes. */
                pChild->getType() == Device::Disk)
        {
            if ( probeDisk(dynamic_cast<Disk*> (pChild)) ) return true;
        }
        else
        {
            // Recurse.
            if (findDisks(pChild)) return true;
        }
    }
    return false;
}

static void init()
{
    static HugeStaticString str;

    // Mount all available filesystems.
    if (!findDisks(&Device::root()))
    {
//     FATAL("No disks found!");
    }

//    if (VFS::instance().find(String("raw»/")) == 0)
//    {
//        FATAL("No raw partition!");
//    }

    // Are we running a live CD?
    /// \todo Use the configuration manager to determine if we're running a live CD or
    ///       not, to avoid the potential for conflicts here.
    if(VFS::instance().find(String("root»/livedisk.img")))
    {
        FileDisk *pRamDisk = new FileDisk(String("root»/livedisk.img"), FileDisk::RamOnly);
        if(pRamDisk && pRamDisk->initialise())
        {
            pRamDisk->setParent(&Device::root());
            Device::root().addChild(pRamDisk);

            // Mount it in the VFS
            VFS::instance().removeAlias(String("root"));
            bRootMounted = false;
            findDisks(pRamDisk);
        }
        else
            delete pRamDisk;
    }

    // Is there a root disk mounted?
    if(VFS::instance().find(String("root»/.pedigree-root")) == 0)
    {
        FATAL("No root disk (missing .pedigree-root?)");
    }

    // Fill out the device hash table
    DeviceHashTree::instance().fill(&Device::root());

#if 0
    // Testing froggey's Bochs patch for magic watchpoints... -Matt
    volatile uint32_t abc = 0;
    NOTICE("Address of abc = " << reinterpret_cast<uintptr_t>(&abc) << "...");
    asm volatile("xchg %%cx,%%cx" :: "a" (&abc));
    abc = 0xdeadbeef;
    abc = 0xdeadbe;
    abc = 0xdead;
    abc = 0xde;
    abc = 0xd;
    abc = 0;
    FATAL("Test complete: " << abc << ".");
#endif

    // Initialise user/group configuration.
    UserManager::instance().initialise();

    // Build routing tables - try to find a default configuration that can
    // connect to the outside world
    IpAddress empty;
    bool bRouteFound = false;
    for (size_t i = 0; i < NetworkStack::instance().getNumDevices(); i++)
    {
        /// \todo Perhaps try and ping a remote host?
        Network* card = NetworkStack::instance().getDevice(i);
        StationInfo info = card->getStationInfo();

        // If the device has a gateway, set it as the default and continue
        if (info.gateway != empty)
        {
            if(!bRouteFound)
            {
                RoutingTable::instance().Add(RoutingTable::Named, empty, empty, String("default"), card);
                bRouteFound = true;
            }

            // Additionally route the complement of its subnet to the gateway
            RoutingTable::instance().Add(RoutingTable::DestSubnetComplement,
                                         info.ipv4,
                                         info.subnetMask,
                                         info.gateway,
                                         String(""),
                                         card);

            // And the actual subnet that the card is on needs to route to... the card.
            RoutingTable::instance().Add(RoutingTable::DestSubnet,
                                         info.ipv4,
                                         info.subnetMask,
                                         empty,
                                         String(""),
                                         card);
        }

        // If this isn't already the loopback device, redirect our own IP to 127.0.0.1
        if(info.ipv4.getIp() != Network::convertToIpv4(127, 0, 0, 1))
            RoutingTable::instance().Add(RoutingTable::DestIpSub, info.ipv4, Network::convertToIpv4(127, 0, 0, 1), String(""), NetworkStack::instance().getLoopback());
        else
            RoutingTable::instance().Add(RoutingTable::DestIp, info.ipv4, empty, String(""), card);
    }

    // Otherwise, just assume the default is interface zero
    if (!bRouteFound)
        RoutingTable::instance().Add(RoutingTable::Named, empty, empty, String("default"), NetworkStack::instance().getDevice(0));

#if 0
    // Routes installed, start the UDP logger
    UdpLogger *logger = new UdpLogger();
    logger->initialise(IpAddress(Network::convertToIpv4(192, 168, 0, 1)));

    Log::instance().installCallback(logger);
#endif

    str += "Loading init program (root»/applications/TUI)\n";
    bootIO.write(str, BootIO::White, BootIO::Black);
    str.clear();

#ifdef THREADS
    // At this point we're uninterruptible, as we're forking.
    Spinlock lock;
    lock.acquire();

    // Create a new process for the init process.
    Process *pProcess = new Process(Processor::information().getCurrentThread()->getParent());
    pProcess->setUser(UserManager::instance().getUser(0));
    pProcess->setGroup(UserManager::instance().getUser(0)->getDefaultGroup());

    pProcess->description().clear();
    pProcess->description().append("init");

    pProcess->setCwd(VFS::instance().find(String("root»/")));
    pProcess->setCtty(0);

    PosixSubsystem *pSubsystem = new PosixSubsystem;
    pProcess->setSubsystem(pSubsystem);

    new Thread(pProcess, reinterpret_cast<Thread::ThreadStartFunc>(&init_stage2), 0x0 /* parameter */);

    lock.release();
#else
    #warning the init module is almost useless without threads.
#endif
}
static void destroy()
{
}

extern void system_reset();

void init_stage2()
{
    // Load initial program.
    File* initProg = VFS::instance().find(String("root»/applications/TUI"));
    if (!initProg)
    {
        NOTICE("INIT: FileNotFound!!");
        initProg = VFS::instance().find(String("root»/applications/tui"));
        if (!initProg)
        {
            FATAL("Unable to load init program!");
            return;
        }
    }
    NOTICE("INIT: File found: " << reinterpret_cast<uintptr_t>(initProg));
    String fname = initProg->getName();
    NOTICE("INIT: name: " << fname);
    // That will have forked - we don't want to fork, so clear out all the chaff in the new address space that's not
    // in the kernel address space so we have a clean slate.
    Process *pProcess = Processor::information().getCurrentThread()->getParent();
    pProcess->getAddressSpace()->revertToKernelAddressSpace();

    DynamicLinker *pLinker = new DynamicLinker();
    pProcess->setLinker(pLinker);

    if (!pLinker->loadProgram(initProg))
    {
        FATAL("Init program failed to load!");
    }

    for (int j = 0; j < 0x20000; j += 0x1000)
    {
        physical_uintptr_t phys = PhysicalMemoryManager::instance().allocatePage();
        bool b = Processor::information().getVirtualAddressSpace().map(phys, reinterpret_cast<void*> (j+0x20000000), VirtualAddressSpace::Write);
        if (!b)
            WARNING("map() failed in init");
    }

    // Initialise the sigret and pthreads shizzle.
    pedigree_init_sigret();

    pedigree_init_pthreads();

#if 0
    system_reset();
#else
    // Alrighty - lets create a new thread for this program - -8 as PPC assumes the previous stack frame is available...
    new Thread(pProcess, reinterpret_cast<Thread::ThreadStartFunc>(pLinker->getProgramElf()->getEntryPoint()), 0x0 /* parameter */,  reinterpret_cast<void*>(0x20020000-8) /* Stack */);
#endif
}

#ifdef X86_COMMON
#define __MOD_DEPS "vfs", "ext2", "fat", "posix", "partition", "TUI", "linker", "network-stack", "vbe", "users", "pedigree-c"
#elif PPC_COMMON
#define __MOD_DEPS "vfs", "ext2", "fat", "posix", "partition", "TUI", "linker", "network-stack", "users", "pedigree-c"
#elif ARM_COMMON
#define __MOD_DEPS "vfs", "ext2", "fat", "posix", "partition", "linker", "network-stack", "users", "pedigree-c"
#endif
MODULE_INFO("init", &init, &destroy, __MOD_DEPS);
<commit_msg>init module now waits until the TUI thread is running before exiting its entry point.<commit_after>/*
 * Copyright (c) 2008 James Molloy, Jörg Pfähler, Matthew Iselin
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <Log.h>
#include <vfs/VFS.h>
#include <vfs/Directory.h>
#include "../../subsys/posix/PosixSubsystem.h"
#include <machine/Device.h>
#include <machine/Disk.h>
#include <Module.h>
#include <processor/Processor.h>
#include <linker/Elf.h>
#include <process/Thread.h>
#include <process/Process.h>
#include <process/Scheduler.h>
#include <processor/PhysicalMemoryManager.h>
#include <processor/VirtualAddressSpace.h>
#include <machine/Machine.h>
#include <linker/DynamicLinker.h>
#include <panic.h>
#include <utilities/assert.h>

#include <kernel/core/BootIO.h>

#include <network-stack/NetworkStack.h>
#include <network-stack/RoutingTable.h>
#include <network-stack/UdpLogger.h>

#include <users/UserManager.h>

#include <utilities/TimeoutGuard.h>

#include <config/ConfigurationManager.h>
#include <config/MemoryBackend.h>

#include <machine/DeviceHashTree.h>
#include <lodisk/LoDisk.h>

#include <machine/InputManager.h>

extern void pedigree_init_sigret();
extern void pedigree_init_pthreads();

extern BootIO bootIO;

void init_stage2();

static bool bRootMounted = false;
static bool probeDisk(Disk *pDisk)
{
    String alias; // Null - gets assigned by the filesystem.
    if (VFS::instance().mount(pDisk, alias))
    {
        // For mount message
        bool didMountAsRoot = false;

        // Search for the root specifier, if we haven't already mounted root
        if (!bRootMounted)
        {
            NormalStaticString s;
            s += alias;
            s += "»/.pedigree-root";

            File* f = VFS::instance().find(String(static_cast<const char*>(s)));
            if (f && !bRootMounted)
            {
                NOTICE("Mounted " << alias << " successfully as root.");
                VFS::instance().addAlias(alias, String("root"));
                bRootMounted = didMountAsRoot = true;
            }
        }

        if(!didMountAsRoot)
        {
            NOTICE("Mounted " << alias << ".");
        }
        return false;
    }
    return false;
}

static bool findDisks(Device *pDev)
{
    for (unsigned int i = 0; i < pDev->getNumChildren(); i++)
    {
        Device *pChild = pDev->getChild(i);
        if (pChild->getNumChildren() == 0 && /* Only check leaf nodes. */
                pChild->getType() == Device::Disk)
        {
            if ( probeDisk(dynamic_cast<Disk*> (pChild)) ) return true;
        }
        else
        {
            // Recurse.
            if (findDisks(pChild)) return true;
        }
    }
    return false;
}

/// This ensures that the init module entry function will not exit until the init
/// program entry point thread is running.
Mutex g_InitProgramLoaded(true);

static void init()
{
    static HugeStaticString str;

    // Mount all available filesystems.
    if (!findDisks(&Device::root()))
    {
//     FATAL("No disks found!");
    }

//    if (VFS::instance().find(String("raw»/")) == 0)
//    {
//        FATAL("No raw partition!");
//    }

    // Are we running a live CD?
    /// \todo Use the configuration manager to determine if we're running a live CD or
    ///       not, to avoid the potential for conflicts here.
    if(VFS::instance().find(String("root»/livedisk.img")))
    {
        FileDisk *pRamDisk = new FileDisk(String("root»/livedisk.img"), FileDisk::RamOnly);
        if(pRamDisk && pRamDisk->initialise())
        {
            pRamDisk->setParent(&Device::root());
            Device::root().addChild(pRamDisk);

            // Mount it in the VFS
            VFS::instance().removeAlias(String("root"));
            bRootMounted = false;
            findDisks(pRamDisk);
        }
        else
            delete pRamDisk;
    }

    // Is there a root disk mounted?
    if(VFS::instance().find(String("root»/.pedigree-root")) == 0)
    {
        FATAL("No root disk (missing .pedigree-root?)");
    }

    // Fill out the device hash table
    DeviceHashTree::instance().fill(&Device::root());

#if 0
    // Testing froggey's Bochs patch for magic watchpoints... -Matt
    volatile uint32_t abc = 0;
    NOTICE("Address of abc = " << reinterpret_cast<uintptr_t>(&abc) << "...");
    asm volatile("xchg %%cx,%%cx" :: "a" (&abc));
    abc = 0xdeadbeef;
    abc = 0xdeadbe;
    abc = 0xdead;
    abc = 0xde;
    abc = 0xd;
    abc = 0;
    FATAL("Test complete: " << abc << ".");
#endif

    // Initialise user/group configuration.
    UserManager::instance().initialise();

    // Build routing tables - try to find a default configuration that can
    // connect to the outside world
    IpAddress empty;
    bool bRouteFound = false;
    for (size_t i = 0; i < NetworkStack::instance().getNumDevices(); i++)
    {
        /// \todo Perhaps try and ping a remote host?
        Network* card = NetworkStack::instance().getDevice(i);
        StationInfo info = card->getStationInfo();

        // If the device has a gateway, set it as the default and continue
        if (info.gateway != empty)
        {
            if(!bRouteFound)
            {
                RoutingTable::instance().Add(RoutingTable::Named, empty, empty, String("default"), card);
                bRouteFound = true;
            }

            // Additionally route the complement of its subnet to the gateway
            RoutingTable::instance().Add(RoutingTable::DestSubnetComplement,
                                         info.ipv4,
                                         info.subnetMask,
                                         info.gateway,
                                         String(""),
                                         card);

            // And the actual subnet that the card is on needs to route to... the card.
            RoutingTable::instance().Add(RoutingTable::DestSubnet,
                                         info.ipv4,
                                         info.subnetMask,
                                         empty,
                                         String(""),
                                         card);
        }

        // If this isn't already the loopback device, redirect our own IP to 127.0.0.1
        if(info.ipv4.getIp() != Network::convertToIpv4(127, 0, 0, 1))
            RoutingTable::instance().Add(RoutingTable::DestIpSub, info.ipv4, Network::convertToIpv4(127, 0, 0, 1), String(""), NetworkStack::instance().getLoopback());
        else
            RoutingTable::instance().Add(RoutingTable::DestIp, info.ipv4, empty, String(""), card);
    }

    // Otherwise, just assume the default is interface zero
    if (!bRouteFound)
        RoutingTable::instance().Add(RoutingTable::Named, empty, empty, String("default"), NetworkStack::instance().getDevice(0));

#if 0
    // Routes installed, start the UDP logger
    UdpLogger *logger = new UdpLogger();
    logger->initialise(IpAddress(Network::convertToIpv4(192, 168, 0, 1)));

    Log::instance().installCallback(logger);
#endif

    str += "Loading init program (root»/applications/TUI)\n";
    bootIO.write(str, BootIO::White, BootIO::Black);
    str.clear();

#ifdef THREADS
    // At this point we're uninterruptible, as we're forking.
    Spinlock lock;
    lock.acquire();

    // Create a new process for the init process.
    Process *pProcess = new Process(Processor::information().getCurrentThread()->getParent());
    pProcess->setUser(UserManager::instance().getUser(0));
    pProcess->setGroup(UserManager::instance().getUser(0)->getDefaultGroup());

    pProcess->description().clear();
    pProcess->description().append("init");

    pProcess->setCwd(VFS::instance().find(String("root»/")));
    pProcess->setCtty(0);

    PosixSubsystem *pSubsystem = new PosixSubsystem;
    pProcess->setSubsystem(pSubsystem);

    new Thread(pProcess, reinterpret_cast<Thread::ThreadStartFunc>(&init_stage2), 0x0 /* parameter */);

    lock.release();

    // Wait for the program to load
    g_InitProgramLoaded.acquire();
#else
    #warning the init module is almost useless without threads.
#endif
}
static void destroy()
{
}

extern void system_reset();

void init_stage2()
{
    // Load initial program.
    File* initProg = VFS::instance().find(String("root»/applications/TUI"));
    if (!initProg)
    {
        NOTICE("INIT: FileNotFound!!");
        initProg = VFS::instance().find(String("root»/applications/tui"));
        if (!initProg)
        {
            FATAL("Unable to load init program!");
            return;
        }
    }
    NOTICE("INIT: File found");
    String fname = initProg->getName();
    NOTICE("INIT: name: " << fname);
    // That will have forked - we don't want to fork, so clear out all the chaff
    // in the new address space that's not in the kernel address space so we
    // have a clean slate.
    Process *pProcess = Processor::information().getCurrentThread()->getParent();
    pProcess->getAddressSpace()->revertToKernelAddressSpace();

    DynamicLinker *pLinker = new DynamicLinker();
    pProcess->setLinker(pLinker);

    if (!pLinker->loadProgram(initProg))
    {
        FATAL("Init program failed to load!");
    }

    for (int j = 0; j < 0x20000; j += 0x1000)
    {
        physical_uintptr_t phys = PhysicalMemoryManager::instance().allocatePage();
        bool b = Processor::information().getVirtualAddressSpace().map(phys, reinterpret_cast<void*> (j+0x20000000), VirtualAddressSpace::Write);
        if (!b)
            WARNING("map() failed in init");
    }

    // Initialise the sigret and pthreads shizzle.
    pedigree_init_sigret();

    pedigree_init_pthreads();

#if 0
    system_reset();
#else
    // Alrighty - lets create a new thread for this program - -8 as PPC assumes the previous stack frame is available...
    new Thread(pProcess, reinterpret_cast<Thread::ThreadStartFunc>(pLinker->getProgramElf()->getEntryPoint()), 0x0 /* parameter */,  reinterpret_cast<void*>(0x20020000-8) /* Stack */);

    g_InitProgramLoaded.release();
#endif
}

#ifdef X86_COMMON
#define __MOD_DEPS "vfs", "ext2", "fat", "posix", "partition", "TUI", "linker", "network-stack", "vbe", "users", "pedigree-c"
#elif PPC_COMMON
#define __MOD_DEPS "vfs", "ext2", "fat", "posix", "partition", "TUI", "linker", "network-stack", "users", "pedigree-c"
#elif ARM_COMMON
#define __MOD_DEPS "vfs", "ext2", "fat", "posix", "partition", "linker", "network-stack", "users", "pedigree-c"
#endif
MODULE_INFO("init", &init, &destroy, __MOD_DEPS);
<|endoftext|>


<commit_before>/*
    Copyright 2008 Brain Research Institute, Melbourne, Australia

    Written by J-Donald Tournier, 27/06/08.

    This file is part of MRtrix.

    MRtrix is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    MRtrix is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with MRtrix.  If not, see <http://www.gnu.org/licenses/>.

*/

#include <gsl/gsl_version.h>

#include "mrtrix.h"

namespace MR
{

  /************************************************************************
   *                     MRtrix version information                      *
   ************************************************************************/

  const size_t mrtrix_major_version = MRTRIX_MAJOR_VERSION;
  const size_t mrtrix_minor_version = MRTRIX_MINOR_VERSION;
  const size_t mrtrix_micro_version = MRTRIX_MICRO_VERSION;

  /************************************************************************
   *                       Miscellaneous functions                        *
   ************************************************************************/

  std::vector<float> parse_floats (const std::string& spec)
  {
    std::vector<float> V;

    if (!spec.size()) throw Exception ("floating-point sequence specifier is empty");
    std::string::size_type start = 0, end;
    try {
      do {
        end = spec.find_first_of (',', start);
        std::string sub (spec.substr (start, end-start));
        float num = sub == "nan" ? NAN : to<float> (spec.substr (start, end-start));
        V.push_back (num);
        start = end+1;
      }
      while (end < spec.size());
    }
    catch (Exception& E) {
      throw Exception (E, "can't parse floating-point sequence specifier \"" + spec + "\"");
    }

    return (V);
  }

  std::vector<int> parse_ints (const std::string& spec, int last)
  {
    std::vector<int> V;
    if (!spec.size()) throw Exception ("integer sequence specifier is empty");
    std::string::size_type start = 0, end;
    int num[3];
    int i = 0;
    try {
      do {
        end = spec.find_first_of (",:", start);
        std::string token (strip (spec.substr (start, end-start)));
        lowercase (token);
        if (token == "end") {
          if (last == std::numeric_limits<int>::max())
            throw Exception ("value of \"end\" is not known in number sequence \"" + spec + "\"");
          num[i] = last;
        }
        else num[i] = to<int> (spec.substr (start, end-start));

        char last_char = end < spec.size() ? spec[end] : '\0';
        if (last_char == ':') {
          i++;
          if (i > 2) throw Exception ("invalid number range in number sequence \"" + spec + "\"");
        }
        else {
          if (i) {
            int inc, last;
            if (i == 2) {
              inc = num[1];
              last = num[2];
            }
            else {
              inc = 1;
              last = num[1];
            }
            if (inc * (last - num[0]) < 0) inc = -inc;
            for (; (inc > 0 ? num[0] <= last : num[0] >= last) ; num[0] += inc) V.push_back (num[0]);
          }
          else V.push_back (num[0]);
          i = 0;
        }

        start = end+1;
      }
      while (end < spec.size());
    }
    catch (Exception& E) {
      throw Exception (E, "can't parse integer sequence specifier \"" + spec + "\"");
    }

    return (V);
  }

  std::vector<std::string> split (const std::string& string, const char* delimiters, bool ignore_empty_fields, size_t num)
  {
    std::vector<std::string> V;
    std::string::size_type start = 0, end;
    try {
      do {
        end = string.find_first_of (delimiters, start);
        V.push_back (string.substr (start, end-start));
        start = ignore_empty_fields ? string.find_first_not_of (delimiters, end+1) : end+1;
        if (V.size()+1 >= num) {
          V.push_back (string.substr (start));
          break;
        }
      }
      while (end < std::string::npos && V.size() < num);
      // should this change to:
      //} while (start < std::string::npos && V.size() < num);
    }
    catch (...)  {
      throw Exception ("can't split string \"" + string + "\"");
    }
    return V;
  }

}
<commit_msg>fix MR::split(std::string&) function to handle missing entries, etc.<commit_after>/*
    Copyright 2008 Brain Research Institute, Melbourne, Australia

    Written by J-Donald Tournier, 27/06/08.

    This file is part of MRtrix.

    MRtrix is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    MRtrix is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with MRtrix.  If not, see <http://www.gnu.org/licenses/>.

*/

#include <gsl/gsl_version.h>

#include "mrtrix.h"

namespace MR
{

  /************************************************************************
   *                     MRtrix version information                      *
   ************************************************************************/

  const size_t mrtrix_major_version = MRTRIX_MAJOR_VERSION;
  const size_t mrtrix_minor_version = MRTRIX_MINOR_VERSION;
  const size_t mrtrix_micro_version = MRTRIX_MICRO_VERSION;

  /************************************************************************
   *                       Miscellaneous functions                        *
   ************************************************************************/

  std::vector<float> parse_floats (const std::string& spec)
  {
    std::vector<float> V;

    if (!spec.size()) throw Exception ("floating-point sequence specifier is empty");
    std::string::size_type start = 0, end;
    try {
      do {
        end = spec.find_first_of (',', start);
        std::string sub (spec.substr (start, end-start));
        float num = sub == "nan" ? NAN : to<float> (spec.substr (start, end-start));
        V.push_back (num);
        start = end+1;
      }
      while (end < spec.size());
    }
    catch (Exception& E) {
      throw Exception (E, "can't parse floating-point sequence specifier \"" + spec + "\"");
    }

    return (V);
  }

  std::vector<int> parse_ints (const std::string& spec, int last)
  {
    std::vector<int> V;
    if (!spec.size()) throw Exception ("integer sequence specifier is empty");
    std::string::size_type start = 0, end;
    int num[3];
    int i = 0;
    try {
      do {
        end = spec.find_first_of (",:", start);
        std::string token (strip (spec.substr (start, end-start)));
        lowercase (token);
        if (token == "end") {
          if (last == std::numeric_limits<int>::max())
            throw Exception ("value of \"end\" is not known in number sequence \"" + spec + "\"");
          num[i] = last;
        }
        else num[i] = to<int> (spec.substr (start, end-start));

        char last_char = end < spec.size() ? spec[end] : '\0';
        if (last_char == ':') {
          i++;
          if (i > 2) throw Exception ("invalid number range in number sequence \"" + spec + "\"");
        }
        else {
          if (i) {
            int inc, last;
            if (i == 2) {
              inc = num[1];
              last = num[2];
            }
            else {
              inc = 1;
              last = num[1];
            }
            if (inc * (last - num[0]) < 0) inc = -inc;
            for (; (inc > 0 ? num[0] <= last : num[0] >= last) ; num[0] += inc) V.push_back (num[0]);
          }
          else V.push_back (num[0]);
          i = 0;
        }

        start = end+1;
      }
      while (end < spec.size());
    }
    catch (Exception& E) {
      throw Exception (E, "can't parse integer sequence specifier \"" + spec + "\"");
    }

    return (V);
  }

  std::vector<std::string> split (const std::string& string, const char* delimiters, bool ignore_empty_fields, size_t num)
  {
    std::vector<std::string> V;
    std::string::size_type start = 0, end;
    try {
      do {
        end = string.find_first_of (delimiters, start);
        V.push_back (string.substr (start, end-start));
        if (end >= string.size()) break;
        start = ignore_empty_fields ? string.find_first_not_of (delimiters, end+1) : end+1;
        if (start > string.size()) break;
        if (V.size()+1 >= num) {
          V.push_back (string.substr (start));
          break;
        }
      } while (true);
    }
    catch (...)  {
      throw Exception ("can't split string \"" + string + "\"");
    }
    return V;
  }

}
<|endoftext|>


<commit_before>// ----------------------------------------------------------------------------
// Copyright 2017 Nervana Systems Inc.
// 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
// ----------------------------------------------------------------------------

#include <iostream>

#include <clang/Basic/DiagnosticOptions.h>
#include <clang/Basic/TargetInfo.h>
#include <clang/CodeGen/CodeGenAction.h>
#include <clang/CodeGen/ObjectFilePCHContainerOperations.h>
#include <clang/Driver/DriverDiagnostic.h>
#include <clang/Driver/Options.h>
#include <clang/Frontend/CompilerInstance.h>
#include <clang/Frontend/CompilerInstance.h>
#include <clang/Frontend/CompilerInvocation.h>
#include <clang/Frontend/FrontendActions.h>
#include <clang/Frontend/FrontendDiagnostic.h>
#include <clang/Frontend/TextDiagnosticBuffer.h>
#include <clang/Frontend/TextDiagnosticPrinter.h>
#include <clang/Frontend/TextDiagnosticPrinter.h>
#include <clang/Frontend/Utils.h>
#include <clang/FrontendTool/Utils.h>
#include <clang/Lex/Preprocessor.h>
#include <clang/Lex/PreprocessorOptions.h>
#include <llvm/ADT/Statistic.h>
#include <llvm/LinkAllPasses.h>
#include <llvm/Option/Arg.h>
#include <llvm/Option/ArgList.h>
#include <llvm/Option/OptTable.h>
#include <llvm/Support/ErrorHandling.h>
#include <llvm/Support/ManagedStatic.h>
#include <llvm/Support/Signals.h>
#include <llvm/Support/TargetSelect.h>
#include <llvm/Support/TargetSelect.h>
#include <llvm/Support/Timer.h>
#include <llvm/Support/raw_ostream.h>

#include "ngraph/codegen/compiler.hpp"
#include "ngraph/file_util.hpp"
#include "ngraph/log.hpp"
#include "ngraph/util.hpp"

// TODO: Fix leaks

// #define USE_CACHE

using namespace clang;
using namespace llvm;
using namespace llvm::opt;
using namespace std;

using namespace ngraph::codegen;

static HeaderCache s_header_cache;
static StaticCompiler s_static_compiler;
static std::mutex m_mutex;

Compiler::Compiler()
{
}

Compiler::~Compiler()
{
}

void Compiler::set_precompiled_header_source(const std::string& source)
{
    s_static_compiler.set_precompiled_header_source(source);
}

void Compiler::add_header_search_path(const std::string& path)
{
    s_static_compiler.add_header_search_path(path);
}

std::unique_ptr<llvm::Module> Compiler::compile(const std::string& source)
{
    lock_guard<mutex> lock(m_mutex);
    return s_static_compiler.compile(compiler_action, source);
}

static std::string GetExecutablePath(const char* Argv0)
{
    // This just needs to be some symbol in the binary; C++ doesn't
    // allow taking the address of ::main however.
    void* MainAddr = reinterpret_cast<void*>(GetExecutablePath);
    return llvm::sys::fs::getMainExecutable(Argv0, MainAddr);
}

StaticCompiler::StaticCompiler()
    : m_precompiled_header_valid(false)
    , m_debuginfo_enabled(false)
    , m_source_name("code.cpp")
{
#if NGCPU_DEBUGINFO
    m_debuginfo_enabled = true;
#endif

    InitializeNativeTarget();
    LLVMInitializeNativeAsmPrinter();
    LLVMInitializeNativeAsmParser();

    // Prepare compilation arguments
    vector<const char*> args;
    args.push_back(m_source_name.c_str());

    // Prepare DiagnosticEngine
    IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
    TextDiagnosticPrinter* textDiagPrinter = new clang::TextDiagnosticPrinter(errs(), &*DiagOpts);
    IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
    DiagnosticsEngine DiagEngine(DiagID, &*DiagOpts, textDiagPrinter);

    // Create and initialize CompilerInstance
    m_compiler = std::unique_ptr<CompilerInstance>(new CompilerInstance());
    m_compiler->createDiagnostics();

    // Initialize CompilerInvocation
    CompilerInvocation::CreateFromArgs(
        m_compiler->getInvocation(), &args[0], &args[0] + args.size(), DiagEngine);

    // Infer the builtin include path if unspecified.
    if (m_compiler->getHeaderSearchOpts().UseBuiltinIncludes &&
        m_compiler->getHeaderSearchOpts().ResourceDir.empty())
    {
        void* MainAddr = reinterpret_cast<void*>(GetExecutablePath);
        auto path = CompilerInvocation::GetResourcesPath(args[0], MainAddr);
        m_compiler->getHeaderSearchOpts().ResourceDir = path;
    }

    if (s_header_cache.is_valid() == false)
    {
        // Add base toolchain-supplied header paths
        // Ideally one would use the Linux toolchain definition in clang/lib/Driver/ToolChains.h
        // But that's a private header and isn't part of the public libclang API
        // Instead of re-implementing all of that functionality in a custom toolchain
        // just hardcode the paths relevant to frequently used build/test machines for now
        add_header_search_path(CLANG_BUILTIN_HEADERS_PATH);
        add_header_search_path("/usr/include/x86_64-linux-gnu");
        add_header_search_path("/usr/include");

        // Search for headers in
        //    /usr/include/x86_64-linux-gnu/c++/N.N
        //    /usr/include/c++/N.N
        // and add them to the header search path

        file_util::iterate_files("/usr/include/x86_64-linux-gnu/c++/",
                                 [&](const std::string& file, bool is_dir) {
                                     if (is_dir)
                                     {
                                         string dir_name = file_util::get_file_name(file);
                                         if (is_version_number(dir_name))
                                         {
                                             add_header_search_path(file);
                                         }
                                     }
                                 });

        file_util::iterate_files("/usr/include/c++/", [&](const std::string& file, bool is_dir) {
            if (is_dir)
            {
                string dir_name = file_util::get_file_name(file);
                if (is_version_number(dir_name))
                {
                    add_header_search_path(file);
                }
            }
        });

        add_header_search_path(EIGEN_HEADERS_PATH);
        add_header_search_path(NGRAPH_HEADERS_PATH);
#ifdef USE_CACHE
        s_header_cache.set_valid();
#endif
    }

#ifdef USE_CACHE
    use_cached_files(m_compiler);
#endif

    // Language options
    // These are the C++ features needed to compile ngraph headers
    // and any dependencies like Eigen
    auto LO = m_compiler->getInvocation().getLangOpts();
    LO->CPlusPlus = 1;
    LO->CPlusPlus11 = 1;
    LO->Bool = 1;
    LO->Exceptions = 1;
    LO->CXXExceptions = 1;
    LO->WChar = 1;
    LO->RTTI = 1;
    // Enable OpenMP for Eigen
    LO->OpenMP = 1;
    LO->OpenMPUseTLS = 1;

    // CodeGen options
    auto& CGO = m_compiler->getInvocation().getCodeGenOpts();
    CGO.OptimizationLevel = 3;
    CGO.RelocationModel = "static";
    CGO.ThreadModel = "posix";
    CGO.FloatABI = "hard";
    CGO.OmitLeafFramePointer = 1;
    CGO.VectorizeLoop = 1;
    CGO.VectorizeSLP = 1;
    CGO.CXAAtExit = 1;

    if (m_debuginfo_enabled)
    {
        CGO.setDebugInfo(codegenoptions::FullDebugInfo);
    }

    // Enable various target features
    // Most of these are for Eigen
    auto& TO = m_compiler->getInvocation().getTargetOpts();
    // TODO: This needs to be configurable and selected carefully
    TO.CPU = "broadwell";
    TO.FeaturesAsWritten.emplace_back("+sse");
    TO.FeaturesAsWritten.emplace_back("+sse2");
    TO.FeaturesAsWritten.emplace_back("+sse3");
    TO.FeaturesAsWritten.emplace_back("+ssse3");
    TO.FeaturesAsWritten.emplace_back("+sse4.1");
    TO.FeaturesAsWritten.emplace_back("+sse4.2");
    TO.FeaturesAsWritten.emplace_back("+avx");
    TO.FeaturesAsWritten.emplace_back("+avx2");
    TO.FeaturesAsWritten.emplace_back("+fma");
}

StaticCompiler::~StaticCompiler()
{
}

bool StaticCompiler::is_version_number(const string& path)
{
    bool rc = true;
    vector<string> tokens = ngraph::split(path, '.');
    for (string s : tokens)
    {
        for (char c : s)
        {
            if (!isdigit(c))
            {
                rc = false;
            }
        }
    }
    return rc;
}

void StaticCompiler::add_header_search_path(const string& path)
{
    if (!contains(m_extra_search_path_list, path))
    {
        m_extra_search_path_list.push_back(path);
        HeaderSearchOptions& hso = m_compiler->getInvocation().getHeaderSearchOpts();
#ifdef USE_CACHE
        static vector<string> valid_ext = {".h", ".hpp", ".tcc", ""};
        string mapped_path = file_util::path_join("/$BUILTIN", path);
        mapped_path = path;
        s_header_cache.add_path(mapped_path);
        auto func = [&](const std::string& file, bool is_dir) {
            if (!is_dir)
            {
                string ext = file_util::get_file_ext(file);
                if (contains(valid_ext, ext))
                {
                    // This is a header file
                    string relative_name = file.substr(path.size() + 1);
                    string mapped_name = file_util::path_join(mapped_path, relative_name);

                    ErrorOr<unique_ptr<MemoryBuffer>> code = MemoryBuffer::getFile(file);
                    if (error_code ec = code.getError())
                    {
                        // throw up
                        throw runtime_error("could not find file '" + file + "'");
                    }

                    s_header_cache.add_file(mapped_name, code.get());
                }
            }
        };
        file_util::iterate_files(path, func, true);
#else
        hso.AddPath(path, clang::frontend::System, false, false);
#endif
    }
}

void StaticCompiler::use_cached_files()
{
    HeaderSearchOptions& hso = m_compiler->getInvocation().getHeaderSearchOpts();
    for (const string& path : s_header_cache.get_include_paths())
    {
        hso.AddPath(path, clang::frontend::System, false, false);
    }
    for (auto& header : s_header_cache.get_header_map())
    {
        m_compiler->getPreprocessorOpts().addRemappedFile(header.first, header.second.get());
    }
}

std::unique_ptr<llvm::Module>
    StaticCompiler::compile(std::unique_ptr<clang::CodeGenAction>& compiler_action,
                            const string& source)
{
    if (!m_precompiled_header_valid && m_precomiled_header_source.empty() == false)
    {
        generate_pch(m_precomiled_header_source);
    }
    if (m_precompiled_header_valid)
    {
        // Preprocessor options
        auto& PPO = m_compiler->getInvocation().getPreprocessorOpts();
        PPO.ImplicitPCHInclude = m_pch_path;
        PPO.DisablePCHValidation = 0;
    }

    // Map code filename to a memoryBuffer
    StringRef source_ref(source);
    unique_ptr<MemoryBuffer> buffer = MemoryBuffer::getMemBufferCopy(source_ref);
    m_compiler->getInvocation().getPreprocessorOpts().addRemappedFile(m_source_name, buffer.get());

    // Create and execute action
    compiler_action.reset(new EmitCodeGenOnlyAction());
    std::unique_ptr<llvm::Module> rc;
    if (m_compiler->ExecuteAction(*compiler_action) == true)
    {
        rc = compiler_action->takeModule();
    }

    buffer.release();

    m_compiler->getInvocation().getPreprocessorOpts().clearRemappedFiles();

    return rc;
}

void StaticCompiler::generate_pch(const string& source)
{
    m_pch_path = file_util::tmp_filename();
    m_compiler->getFrontendOpts().OutputFile = m_pch_path;

    // Map code filename to a memoryBuffer
    StringRef source_ref(source);
    unique_ptr<MemoryBuffer> buffer = MemoryBuffer::getMemBufferCopy(source_ref);
    m_compiler->getInvocation().getPreprocessorOpts().addRemappedFile(m_source_name, buffer.get());

    // Create and execute action
    clang::GeneratePCHAction* compilerAction = new clang::GeneratePCHAction();
    if (m_compiler->ExecuteAction(*compilerAction) == true)
    {
        m_precompiled_header_valid = true;
    }

    buffer.release();

    m_compiler->getInvocation().getPreprocessorOpts().clearRemappedFiles();
    delete compilerAction;
}
<commit_msg>Kill duplicate imports (#308)<commit_after>// ----------------------------------------------------------------------------
// Copyright 2017 Nervana Systems Inc.
// 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
// ----------------------------------------------------------------------------

#include <iostream>

#include <clang/Basic/DiagnosticOptions.h>
#include <clang/Basic/TargetInfo.h>
#include <clang/CodeGen/CodeGenAction.h>
#include <clang/CodeGen/ObjectFilePCHContainerOperations.h>
#include <clang/Driver/DriverDiagnostic.h>
#include <clang/Driver/Options.h>
#include <clang/Frontend/CompilerInstance.h>
#include <clang/Frontend/CompilerInvocation.h>
#include <clang/Frontend/FrontendActions.h>
#include <clang/Frontend/FrontendDiagnostic.h>
#include <clang/Frontend/TextDiagnosticBuffer.h>
#include <clang/Frontend/TextDiagnosticPrinter.h>
#include <clang/Frontend/Utils.h>
#include <clang/FrontendTool/Utils.h>
#include <clang/Lex/Preprocessor.h>
#include <clang/Lex/PreprocessorOptions.h>
#include <llvm/ADT/Statistic.h>
#include <llvm/LinkAllPasses.h>
#include <llvm/Option/Arg.h>
#include <llvm/Option/ArgList.h>
#include <llvm/Option/OptTable.h>
#include <llvm/Support/ErrorHandling.h>
#include <llvm/Support/ManagedStatic.h>
#include <llvm/Support/Signals.h>
#include <llvm/Support/TargetSelect.h>
#include <llvm/Support/Timer.h>
#include <llvm/Support/raw_ostream.h>

#include "ngraph/codegen/compiler.hpp"
#include "ngraph/file_util.hpp"
#include "ngraph/log.hpp"
#include "ngraph/util.hpp"

// TODO: Fix leaks

// #define USE_CACHE

using namespace clang;
using namespace llvm;
using namespace llvm::opt;
using namespace std;

using namespace ngraph::codegen;

static HeaderCache s_header_cache;
static StaticCompiler s_static_compiler;
static std::mutex m_mutex;

Compiler::Compiler()
{
}

Compiler::~Compiler()
{
}

void Compiler::set_precompiled_header_source(const std::string& source)
{
    s_static_compiler.set_precompiled_header_source(source);
}

void Compiler::add_header_search_path(const std::string& path)
{
    s_static_compiler.add_header_search_path(path);
}

std::unique_ptr<llvm::Module> Compiler::compile(const std::string& source)
{
    lock_guard<mutex> lock(m_mutex);
    return s_static_compiler.compile(compiler_action, source);
}

static std::string GetExecutablePath(const char* Argv0)
{
    // This just needs to be some symbol in the binary; C++ doesn't
    // allow taking the address of ::main however.
    void* MainAddr = reinterpret_cast<void*>(GetExecutablePath);
    return llvm::sys::fs::getMainExecutable(Argv0, MainAddr);
}

StaticCompiler::StaticCompiler()
    : m_precompiled_header_valid(false)
    , m_debuginfo_enabled(false)
    , m_source_name("code.cpp")
{
#if NGCPU_DEBUGINFO
    m_debuginfo_enabled = true;
#endif

    InitializeNativeTarget();
    LLVMInitializeNativeAsmPrinter();
    LLVMInitializeNativeAsmParser();

    // Prepare compilation arguments
    vector<const char*> args;
    args.push_back(m_source_name.c_str());

    // Prepare DiagnosticEngine
    IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
    TextDiagnosticPrinter* textDiagPrinter = new clang::TextDiagnosticPrinter(errs(), &*DiagOpts);
    IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
    DiagnosticsEngine DiagEngine(DiagID, &*DiagOpts, textDiagPrinter);

    // Create and initialize CompilerInstance
    m_compiler = std::unique_ptr<CompilerInstance>(new CompilerInstance());
    m_compiler->createDiagnostics();

    // Initialize CompilerInvocation
    CompilerInvocation::CreateFromArgs(
        m_compiler->getInvocation(), &args[0], &args[0] + args.size(), DiagEngine);

    // Infer the builtin include path if unspecified.
    if (m_compiler->getHeaderSearchOpts().UseBuiltinIncludes &&
        m_compiler->getHeaderSearchOpts().ResourceDir.empty())
    {
        void* MainAddr = reinterpret_cast<void*>(GetExecutablePath);
        auto path = CompilerInvocation::GetResourcesPath(args[0], MainAddr);
        m_compiler->getHeaderSearchOpts().ResourceDir = path;
    }

    if (s_header_cache.is_valid() == false)
    {
        // Add base toolchain-supplied header paths
        // Ideally one would use the Linux toolchain definition in clang/lib/Driver/ToolChains.h
        // But that's a private header and isn't part of the public libclang API
        // Instead of re-implementing all of that functionality in a custom toolchain
        // just hardcode the paths relevant to frequently used build/test machines for now
        add_header_search_path(CLANG_BUILTIN_HEADERS_PATH);
        add_header_search_path("/usr/include/x86_64-linux-gnu");
        add_header_search_path("/usr/include");

        // Search for headers in
        //    /usr/include/x86_64-linux-gnu/c++/N.N
        //    /usr/include/c++/N.N
        // and add them to the header search path

        file_util::iterate_files("/usr/include/x86_64-linux-gnu/c++/",
                                 [&](const std::string& file, bool is_dir) {
                                     if (is_dir)
                                     {
                                         string dir_name = file_util::get_file_name(file);
                                         if (is_version_number(dir_name))
                                         {
                                             add_header_search_path(file);
                                         }
                                     }
                                 });

        file_util::iterate_files("/usr/include/c++/", [&](const std::string& file, bool is_dir) {
            if (is_dir)
            {
                string dir_name = file_util::get_file_name(file);
                if (is_version_number(dir_name))
                {
                    add_header_search_path(file);
                }
            }
        });

        add_header_search_path(EIGEN_HEADERS_PATH);
        add_header_search_path(NGRAPH_HEADERS_PATH);
#ifdef USE_CACHE
        s_header_cache.set_valid();
#endif
    }

#ifdef USE_CACHE
    use_cached_files(m_compiler);
#endif

    // Language options
    // These are the C++ features needed to compile ngraph headers
    // and any dependencies like Eigen
    auto LO = m_compiler->getInvocation().getLangOpts();
    LO->CPlusPlus = 1;
    LO->CPlusPlus11 = 1;
    LO->Bool = 1;
    LO->Exceptions = 1;
    LO->CXXExceptions = 1;
    LO->WChar = 1;
    LO->RTTI = 1;
    // Enable OpenMP for Eigen
    LO->OpenMP = 1;
    LO->OpenMPUseTLS = 1;

    // CodeGen options
    auto& CGO = m_compiler->getInvocation().getCodeGenOpts();
    CGO.OptimizationLevel = 3;
    CGO.RelocationModel = "static";
    CGO.ThreadModel = "posix";
    CGO.FloatABI = "hard";
    CGO.OmitLeafFramePointer = 1;
    CGO.VectorizeLoop = 1;
    CGO.VectorizeSLP = 1;
    CGO.CXAAtExit = 1;

    if (m_debuginfo_enabled)
    {
        CGO.setDebugInfo(codegenoptions::FullDebugInfo);
    }

    // Enable various target features
    // Most of these are for Eigen
    auto& TO = m_compiler->getInvocation().getTargetOpts();
    // TODO: This needs to be configurable and selected carefully
    TO.CPU = "broadwell";
    TO.FeaturesAsWritten.emplace_back("+sse");
    TO.FeaturesAsWritten.emplace_back("+sse2");
    TO.FeaturesAsWritten.emplace_back("+sse3");
    TO.FeaturesAsWritten.emplace_back("+ssse3");
    TO.FeaturesAsWritten.emplace_back("+sse4.1");
    TO.FeaturesAsWritten.emplace_back("+sse4.2");
    TO.FeaturesAsWritten.emplace_back("+avx");
    TO.FeaturesAsWritten.emplace_back("+avx2");
    TO.FeaturesAsWritten.emplace_back("+fma");
}

StaticCompiler::~StaticCompiler()
{
}

bool StaticCompiler::is_version_number(const string& path)
{
    bool rc = true;
    vector<string> tokens = ngraph::split(path, '.');
    for (string s : tokens)
    {
        for (char c : s)
        {
            if (!isdigit(c))
            {
                rc = false;
            }
        }
    }
    return rc;
}

void StaticCompiler::add_header_search_path(const string& path)
{
    if (!contains(m_extra_search_path_list, path))
    {
        m_extra_search_path_list.push_back(path);
        HeaderSearchOptions& hso = m_compiler->getInvocation().getHeaderSearchOpts();
#ifdef USE_CACHE
        static vector<string> valid_ext = {".h", ".hpp", ".tcc", ""};
        string mapped_path = file_util::path_join("/$BUILTIN", path);
        mapped_path = path;
        s_header_cache.add_path(mapped_path);
        auto func = [&](const std::string& file, bool is_dir) {
            if (!is_dir)
            {
                string ext = file_util::get_file_ext(file);
                if (contains(valid_ext, ext))
                {
                    // This is a header file
                    string relative_name = file.substr(path.size() + 1);
                    string mapped_name = file_util::path_join(mapped_path, relative_name);

                    ErrorOr<unique_ptr<MemoryBuffer>> code = MemoryBuffer::getFile(file);
                    if (error_code ec = code.getError())
                    {
                        // throw up
                        throw runtime_error("could not find file '" + file + "'");
                    }

                    s_header_cache.add_file(mapped_name, code.get());
                }
            }
        };
        file_util::iterate_files(path, func, true);
#else
        hso.AddPath(path, clang::frontend::System, false, false);
#endif
    }
}

void StaticCompiler::use_cached_files()
{
    HeaderSearchOptions& hso = m_compiler->getInvocation().getHeaderSearchOpts();
    for (const string& path : s_header_cache.get_include_paths())
    {
        hso.AddPath(path, clang::frontend::System, false, false);
    }
    for (auto& header : s_header_cache.get_header_map())
    {
        m_compiler->getPreprocessorOpts().addRemappedFile(header.first, header.second.get());
    }
}

std::unique_ptr<llvm::Module>
    StaticCompiler::compile(std::unique_ptr<clang::CodeGenAction>& compiler_action,
                            const string& source)
{
    if (!m_precompiled_header_valid && m_precomiled_header_source.empty() == false)
    {
        generate_pch(m_precomiled_header_source);
    }
    if (m_precompiled_header_valid)
    {
        // Preprocessor options
        auto& PPO = m_compiler->getInvocation().getPreprocessorOpts();
        PPO.ImplicitPCHInclude = m_pch_path;
        PPO.DisablePCHValidation = 0;
    }

    // Map code filename to a memoryBuffer
    StringRef source_ref(source);
    unique_ptr<MemoryBuffer> buffer = MemoryBuffer::getMemBufferCopy(source_ref);
    m_compiler->getInvocation().getPreprocessorOpts().addRemappedFile(m_source_name, buffer.get());

    // Create and execute action
    compiler_action.reset(new EmitCodeGenOnlyAction());
    std::unique_ptr<llvm::Module> rc;
    if (m_compiler->ExecuteAction(*compiler_action) == true)
    {
        rc = compiler_action->takeModule();
    }

    buffer.release();

    m_compiler->getInvocation().getPreprocessorOpts().clearRemappedFiles();

    return rc;
}

void StaticCompiler::generate_pch(const string& source)
{
    m_pch_path = file_util::tmp_filename();
    m_compiler->getFrontendOpts().OutputFile = m_pch_path;

    // Map code filename to a memoryBuffer
    StringRef source_ref(source);
    unique_ptr<MemoryBuffer> buffer = MemoryBuffer::getMemBufferCopy(source_ref);
    m_compiler->getInvocation().getPreprocessorOpts().addRemappedFile(m_source_name, buffer.get());

    // Create and execute action
    clang::GeneratePCHAction* compilerAction = new clang::GeneratePCHAction();
    if (m_compiler->ExecuteAction(*compilerAction) == true)
    {
        m_precompiled_header_valid = true;
    }

    buffer.release();

    m_compiler->getInvocation().getPreprocessorOpts().clearRemappedFiles();
    delete compilerAction;
}
<|endoftext|>