Goose  Artifact [a6b1a5f414]

Artifact a6b1a5f4143f6cd67d29f5cf66a41390df83168f0c9aa18ed328c9fbcb1d0f36:

  • File bs/cir/helpers.h — part of check-in [0db147f117] at 2024-09-15 20:24:31 on branch cir-ssa-refactor — Add clang format settings, reformat everything (user: achavasse size: 3635)

#ifndef GOOSE_CIR_HELPERS_H
#define GOOSE_CIR_HELPERS_H

namespace goose::cir
{
    extern bool IsValueConstantOrExecutable( const eir::Value& val );
    extern bool CanValueBeEagerlyEvaluated( const eir::Value& val );

    extern bool DoesInstrSeqHaveSideEffects( const InstrSeq& is );

    template< typename T > class TempStorage
    {
      public:
        TempStorage( size_t size = 0 ) :
            m_storage( size )
        {
        }

        template< typename TT > T& set( uint32_t index, TT&& x )
        {
            if( IsUid( index ) )
            {
                auto [it, _] = m_uidStorage.emplace( index, forward< TT >( x ) );
                return it->second;
            }

            if( index >= m_storage.size() )
                m_storage.resize( index + 1 );
            m_storage[index] = forward< TT >( x );
            return m_storage[index];
        }

        const T* get( uint32_t index ) const
        {
            if( IsUid( index ) )
            {
                auto it = m_uidStorage.find( index );
                if( it == m_uidStorage.end() )
                    return nullptr;
                return &it->second;
            }

            if( index < m_storage.size() )
                return &m_storage[index];

            return nullptr;
        }

        T* get( uint32_t index )
        {
            if( IsUid( index ) )
                return nullptr;

            if( index < m_storage.size() )
                return &m_storage[index];

            return nullptr;
        }

      private:
        llvm::SmallVector< T, 16 > m_storage;
        unordered_map< uint32_t, T > m_uidStorage;
    };

    // We need to lower types before consuming them from the CIR. Ideally we'd do this while
    // building the CIR but as things are now it would involve enormous refactoring to store lowered
    // types in a bunch of high level objects, and all the code to round trip them to EIR would have
    // to deal with them, while also making sure they aren't actually participating in pattern
    // matching. A significant redesign will probably allow for an elegant solution, but that's for
    // the rewrite. In the mean time we use this ugly helper that lowers the type when reading it
    // from the CIR, if not previously done. Since it needs the context we have to store the current
    // context as a static member. This will have to do for the BS compiler...
    class LowerableType
    {
      public:
        template< typename T >
        LowerableType( T&& type ) :
            m_type( forward< T >( type ) )
        {
        }

        const auto& type() const { return m_type; }

        const eir::Term& get() const;

        auto operator<( const LowerableType& other ) const { return m_type < other.m_type; }

        auto operator==( const LowerableType& other ) const { return m_type == other.m_type; }

      private:
        eir::Term m_type;
        mutable optional< eir::Term > m_loweredType;
    };

    // Same as above for values
    class LowerableValue
    {
      public:
        template< typename T >
        LowerableValue( T&& val ) :
            m_val( forward< T >( val ) )
        {
        }

        const auto& val() const { return m_val; }

        const eir::Value& get() const;
        eir::Value& modify();

        auto operator<( const LowerableValue& other ) const { return m_val < other.m_val; }

        auto operator==( const LowerableValue& other ) const { return m_val == other.m_val; }

      private:
        eir::Value m_val;
        mutable optional< eir::Value > m_loweredVal;
    };
} // namespace goose::cir

#endif