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