#ifndef GOOSE_CODEGEN_STACK_H
#define GOOSE_CODEGEN_STACK_H
namespace goose::codegen
{
class Stack
{
public:
using Slot = variant< llvm::Value*, codegen::Address >;
template< typename T = llvm::Value* >
optional< T > pop( llvm::IRBuilder<>& builder )
{
if( m_stack.empty() )
return nullopt;
auto result = m_stack.top();
m_stack.pop();
if constexpr( is_same_v< T, codegen::Address > )
{
if( !holds_alternative< codegen::Address >( result ) )
return nullopt;
return get< codegen::Address >( result );
}
else if constexpr( is_same_v< T, llvm::Value* > )
{
if( holds_alternative< codegen::Address >( result ) )
return AddressToGEP( builder, get< codegen::Address >( result ) );
else
return InsertLoadIfNeeded( builder, get< llvm::Value* >( result ) );
}
else if( holds_alternative< llvm::Value* >( result ) )
return llvm::dyn_cast_or_null< remove_pointer_t< T > >( InsertLoadIfNeeded( builder, get< llvm::Value* >( result ) ) );
return nullopt;
}
optional< Slot > pop()
{
if( m_stack.empty() )
return nullopt;
auto result = m_stack.top();
m_stack.pop();
return result;
}
template< typename T >
void push( T&& v )
{
m_stack.push( forward< T >( v ) );
}
private:
static llvm::Value* InsertLoadIfNeeded( llvm::IRBuilder<>& builder, llvm::Value* lv )
{
if( llvm::isa< llvm::AllocaInst >( lv ) )
return builder.CreateLoad( llvm::cast< llvm::AllocaInst >( lv )->getAllocatedType(), lv );
return lv;
}
stack< Slot > m_stack;
};
}
#endif