#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