Goose  Artifact [010901731b]

Artifact 010901731b69fa5d62ebdea21e7d7c97b37cd8c667462e090b9cbc4f97495ef9:

  • File bs/cir/helpers.h — part of check-in [597d732090] at 2023-12-01 19:18:25 on branch cir-not-stack-language — CIR: add operands and result indices to instructions (user: zlodo size: 6583)

#ifndef GOOSE_CIR_HELPERS_H
#define GOOSE_CIR_HELPERS_H

namespace goose::cir
{
    class Instruction;
    using InstrSeq = list< Instruction >;

    extern bool IsValueConstantOrExecutable( const eir::Value& val );
    extern bool CanValueBeEagerlyEvaluated( const eir::Value& val );

    extern bool DoesInstrSeqHaveSideEffects( const InstrSeq& is );

    extern void AppendInstrSeq( InstrSeq& is, InstrSeq&& isToAppend );
    extern void AppendInstrSeq( InstrSeq& is, const InstrSeq& isToAppend );

    extern void AppendValue( InstrSeq& is, Value&& v );
    extern void AppendValue( InstrSeq& is, const Value& v );

    template< typename I >
    void AppendToInstrSeq( InstrSeq& is, I&& instr )
    {
        using II = remove_cvref_t< I >;

        if constexpr( is_same_v< II, InstrSeq > )
        {
            AppendInstrSeq( is, forward< I >( instr ) );
        }
        else if constexpr( is_same_v< II, Value > )
        {
            AppendValue( is, forward< I >( instr ) );
        }
        else
        {
            is.emplace_back( Instruction( forward< I >( instr ) ) );
        }
    }

    static inline void AppendToInstrSeq( InstrSeq& is, const ptr< InstrSeq >& instr )
    {
        AppendToInstrSeq( is, *instr );
    }

    static inline void AppendToInstrSeq( InstrSeq& is, ptr< InstrSeq >&& instr )
    {
        AppendToInstrSeq( is, move( *instr ) );
    }

    template< typename HI, typename... TI >
    void AppendToInstrSeq( InstrSeq& is, HI&& headInstr, TI&&... tailInstrs )
    {
        AppendToInstrSeq( is, forward< HI >( headInstr ) );
        AppendToInstrSeq( is, forward< TI >( tailInstrs )... );
    }

    template< typename T, typename... I >
    auto BuildComputedValue( T&& type, I&&... instrs )
    {
        auto is = make_shared< InstrSeq >();
        AppendToInstrSeq( *is, forward< I >( instrs )... );

        return eir::Value( forward< T >( type ), move( is ) );
    }

    struct OperandIndex
    {
        uint32_t index = 0;
    };

    template< bool enable >
    struct InstrResult
    {
        OperandIndex index;
    };

    template<>
    struct InstrResult< false >
    {};

    template< size_t operandCount, bool haveResult >
    class BaseInstr
    {
        public:
            BaseInstr( LocationId loc ) :
                m_loc( loc )
            {}

            uint32_t operandIndex( uint32_t operand ) const
            {
                assert( operand < operandcount );
                return m_operandIndices[operand].index;
            }

            void setOperandIndex( uint32_t operand, uint32_t index )
            {
                assert( operand < operandcount );
                m_operandIndices[operand].index = index;
            }

            int32_t resultIndex() const
            {
                if constexpr( haveResult )
                {
                    return m_result.index.index;    // Looks like shit but whatever
                }
                else
                {
                    assert( false );
                    return 0;
                }
            }

            void setResultIndex( uint32_t index )
            {
                if constexpr( haveResult )
                {
                    return m_result.index.index = index;    // Even worse lol
                }
                else
                {
                    assert( false );
                }
            }

            void setLocationId( LocationId loc ) { m_loc = loc; }
            auto locationId() const { return m_loc; }

            static constexpr size_t OperandCount = operandCount;
            static constexpr bool HaveResult = haveResult;

        private:
            array< OperandIndex, operandCount > m_operandIndices;
            InstrResult< haveResult > m_result;
            LocationId m_loc;
    };

    template< size_t minOperandCount, bool haveResult >
    class BaseInstrWithOperandList : public BaseInstr< minOperandCount, haveResult >
    {
        using super = BaseInstr< minOperandCount, haveResult >;

        public:
            BaseInstrWithOperandList( uint32_t extraOperandsCount, LocationId loc ) :
                super( loc ),
                m_operandList( extraOperandsCount )
            {}

            uint32_t operandIndex( uint32_t operand ) const
            {
                if( operand < minOperandCount )
                    return super::operandIndex( operand );
                operand -= minOperandCount;
                assert( operand < m_operandList.size() );
                return m_operandList[operand].index;
            }

            void setOperandIndex( uint32_t operand, uint32_t index )
            {
                if( operand < minOperandCount )
                    super::setOperandIndex( operand, index );
                operand -= minOperandCount;
                assert( operand < m_operandList.size() );
                m_operandList[operand].index = index;
            }

        private:
            llvm::SmallVector< OperandIndex, 4 > m_operandList;
    };

    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;
    };
}

#endif