Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | Refactored the code builder: it is now carried around as a Value, and accessed through a bunch of extension points, so we can have different builders (and even user defined ones) later to make classes etc. |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA3-256: |
1ad61a27179e88785c36e73529f99fcb |
| User & Date: | zlodo 2021-11-11 20:05:58.905 |
Context
|
2021-11-11
| ||
| 20:19 | Removed a file that was not properly deleted in the previous commit check-in: b808c4a5f5 user: zlodo tags: trunk | |
| 20:05 | Refactored the code builder: it is now carried around as a Value, and accessed through a bunch of extension points, so we can have different builders (and even user defined ones) later to make classes etc. check-in: 1ad61a2717 user: zlodo tags: trunk | |
| 01:00 |
| |
Changes
Added bs/builtins/builders/codebuilder.cpp.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
#include "builtins.h"
using namespace goose;
using namespace goose::sema;
using namespace goose::builtins;
bool CodeBuilder::destroyAndPopCurrentLifetimeScopeValues( const Context& c )
{
auto it = m_liveValuesList.begin();
while( it != m_liveValuesList.end() )
{
if( it->m_lifeTimeScopeLevel < m_lifeTimeScopeLevels )
break;
if( !destroyLiveValue( c, it->m_value ) )
{
m_liveValuesList.clear();
if( cfg() )
cfg()->poison();
return false;
}
it = m_liveValuesList.erase( it );
}
return true;
}
bool CodeBuilder::destroyAllLiveValues( const Context& c )
{
for( auto it = m_liveValuesList.begin(); it != m_liveValuesList.end(); ++it )
{
if( !destroyLiveValue( c, it->m_value ) )
{
m_liveValuesList.clear();
if( cfg() )
cfg()->poison();
return false;
}
}
return true;
}
bool CodeBuilder::destroyAllLiveValuesFromBreakScope( const Context& c, uint32_t breakScopeLevel )
{
for( auto it = m_liveValuesList.begin(); it != m_liveValuesList.end(); ++it )
{
if( it->m_breakableScopeLevel < breakScopeLevel )
return true;
if( !destroyLiveValue( c, it->m_value ) )
{
m_liveValuesList.clear();
if( cfg() )
cfg()->poison();
return false;
}
}
return true;
}
bool CodeBuilder::destroyAllLiveValuesFromContinueScope( const Context& c, uint32_t continueScopeLevel )
{
for( auto it = m_liveValuesList.begin(); it != m_liveValuesList.end(); ++it )
{
if( it->m_continuableScopeLevel < continueScopeLevel )
return true;
if( !destroyLiveValue( c, it->m_value ) )
{
m_liveValuesList.clear();
if( cfg() )
cfg()->poison();
return false;
}
}
return true;
}
bool CodeBuilder::destroyLiveValue( const Context& c, const Value& v )
{
if( v.isPoison() )
return false;
DiagnosticsContext dc( v.locationId(), "When invoking DestroyValue." );
auto result = InvokeOverloadSet( c, c.env()->extDestroyValue(),
MakeTuple( v ) );
if( result.isPoison() )
return false;
if( !result.isConstant() )
cfg()->currentBB()->emplace_back( *result.cir() );
return true;
}
void CodeBuilder::extendValueLifetime( uint32_t index )
{
// Find the live value.
auto it = find_if( m_liveValuesList.begin(), m_liveValuesList.end(),
[&]( auto&& lv )
{
return lv.m_index == index;
} );
if( it == m_liveValuesList.end() )
return;
--it->m_lifeTimeScopeLevel;
// Look for the last value that belongs to the parent lifetime scope, if any.
auto last = find_if( it, m_liveValuesList.end(),
[&]( auto&& lv )
{
return lv.m_lifeTimeScopeLevel < it->m_lifeTimeScopeLevel;
} );
// Reinsert the value just after the last value of the parent scope (the one we
// just found), like it would be if it was inserted in that lifetime scope in the first
// place.
auto lvToExtend = move( *it );
m_liveValuesList.erase( it );
m_liveValuesList.emplace( last, move( lvToExtend ) );
}
|
Added bs/builtins/builders/codebuilder.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
#ifndef GOOSE_BUILTINS_BUILDER_CODEBUILDER_H
#define GOOSE_BUILTINS_BUILDER_CODEBUILDER_H
namespace goose::builtins
{
class CodeBuilder
{
public:
template< typename C >
CodeBuilder( C&& cfg ) :
m_cfg( forward< C >( cfg ) )
{}
const auto& cfg() const { return m_cfg; }
void poison()
{
if( m_cfg )
m_cfg->poison();
}
void pushLifeTimeScope() { ++m_lifeTimeScopeLevels; }
void popLifeTimeScope() { --m_lifeTimeScopeLevels; }
void pushBreakableScope() { ++m_breakableScopeLevels; }
void popBreakableScope() { --m_breakableScopeLevels; }
void pushContinuableScope() { ++m_continuableScopeLevels; }
void popContinuableScope() { --m_continuableScopeLevels; }
uint32_t lifeTimeScopeLevels() const { return m_lifeTimeScopeLevels; }
uint32_t breakableScopeLevels() const { return m_breakableScopeLevels; }
uint32_t continuableScopeLevels() const { return m_continuableScopeLevels; }
template< typename T >
void pushLiveValue( T&& v, uint32_t index )
{
m_liveValuesList.emplace_front(
forward< T >( v ), index,
m_lifeTimeScopeLevels,
m_breakableScopeLevels,
m_continuableScopeLevels
);
}
// Extend the life duration of a live value to the current lifetime scope.
void extendValueLifetime( uint32_t index );
// Invoke the destroy extension point for every live variable from the current
// lifetime scope, and pops off the stack. To be called when exiting a lifetime scope.
// Returns false if something goes wrong, in which case the cfg will also be marked
// as poisoned.
// Note: it is called automatically by LifetimeScopeGuard.
bool destroyAndPopCurrentLifetimeScopeValues( const Context& c );
// Invoke the destroy extension point for every live variable, but leave them on the stack.
// To be called before emitting a return terminator.
bool destroyAllLiveValues( const Context& c );
// Invoke the destroy extension point for every live variable that belong in the specified
// break scope and every child scope, but leave them on the stack.
// To be called before emitting a break terminator.
bool destroyAllLiveValuesFromBreakScope( const Context& c, uint32_t breakScopeLevel );
// Invoke the destroy extension point for every live variable that belong in the specified
// continue scope and every child scope, but leave them on the stack.
// To be called before emitting a continue terminator.
bool destroyAllLiveValuesFromContinueScope( const Context& c, uint32_t continueScopeLevel );
private:
// Destruction
bool destroyLiveValue( const Context& c, const Value& v );
ptr< cir::CFG > m_cfg;
// The number of nested lifetime scopes.
uint32_t m_lifeTimeScopeLevels = 0;
// The number of nested breakable scopes.
uint32_t m_breakableScopeLevels = 0;
// The number of nested continuable scopes.
uint32_t m_continuableScopeLevels = 0;
// The live values stack, used to track when
// to destroy values (such as local variables going out of scope)
struct LiveValue
{
LiveValue() {}
template< typename T >
LiveValue( T&& v, uint32_t index, uint32_t lt, uint32_t b, uint32_t c ) :
m_value( forward< T >( v ) ),
m_index( index ),
m_lifeTimeScopeLevel( lt ),
m_breakableScopeLevel( b ),
m_continuableScopeLevel( c )
{}
Value m_value;
uint32_t m_index = 0;
// We keep track of those to determine which values to
// destroy when exiting a scope, emitting a break terminator,
// and emitting a continue terminator, respectively.
uint32_t m_lifeTimeScopeLevel = 0;
uint32_t m_breakableScopeLevel = 0;
uint32_t m_continuableScopeLevel = 0;
};
list< LiveValue > m_liveValuesList;
};
}
#endif
|
Added bs/builtins/builders/interfaces.cpp.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
#include "builtins/builtins.h"
#include "parse/parse.h"
using namespace goose::parse;
using namespace goose::cir;
namespace goose::builtins
{
void SetupBuilderInterfaces( Env& e )
{
RegisterBuiltinFunc< Eager< void > ( TypeWrapper< ptr< CodeBuilder > > ) >( e, e.extPoisonBuilder(),
[]( const TypeWrapper< ptr< CodeBuilder > >& cb )
{
cb->poison();
} );
RegisterBuiltinFunc< Eager< bool > ( TypeWrapper< ptr< CodeBuilder > > ) >( e, e.extBuilderAllowsVarDecl(),
[]( const TypeWrapper< ptr< CodeBuilder > >& cb )
{
return true;
} );
RegisterBuiltinFunc< Eager< TypeWrapper< ptr< cir::CFG > > > ( TypeWrapper< ptr< CodeBuilder > > ) >( e, e.extGetCFG(),
[]( const TypeWrapper< ptr< CodeBuilder > >& cb )
{
return cb->cfg();
} );
RegisterBuiltinFunc< Eager< uint32_t > ( TypeWrapper< ptr< CodeBuilder > > ) >( e, e.extGetBreakableScopeLevels(),
[]( const TypeWrapper< ptr< CodeBuilder > >& cb )
{
return cb->breakableScopeLevels();
} );
RegisterBuiltinFunc< Eager< uint32_t > ( TypeWrapper< ptr< CodeBuilder > > ) >( e, e.extGetContinuableScopeLevels(),
[]( const TypeWrapper< ptr< CodeBuilder > >& cb )
{
return cb->continuableScopeLevels();
} );
RegisterBuiltinFunc< Eager< void > ( TypeWrapper< ptr< CodeBuilder > > ) >( e, e.extPushLifetimeScope(),
[]( const TypeWrapper< ptr< CodeBuilder > >& cb )
{
cb->pushLifeTimeScope();
} );
RegisterBuiltinFunc< Eager< void > ( TypeWrapper< ptr< CodeBuilder > > ) >( e, e.extPopLifetimeScope(),
[]( const TypeWrapper< ptr< CodeBuilder > >& cb )
{
cb->popLifeTimeScope();
} );
RegisterBuiltinFunc< Eager< void > ( TypeWrapper< ptr< CodeBuilder > > ) >( e, e.extPushBreakableScope(),
[]( const TypeWrapper< ptr< CodeBuilder > >& cb )
{
cb->pushBreakableScope();
} );
RegisterBuiltinFunc< Eager< void > ( TypeWrapper< ptr< CodeBuilder > > ) >( e, e.extPopBreakableScope(),
[]( const TypeWrapper< ptr< CodeBuilder > >& cb )
{
cb->popBreakableScope();
} );
RegisterBuiltinFunc< Eager< void > ( TypeWrapper< ptr< CodeBuilder > > ) >( e, e.extPushContinuableScope(),
[]( const TypeWrapper< ptr< CodeBuilder > >& cb )
{
cb->pushContinuableScope();
} );
RegisterBuiltinFunc< Eager< void > ( TypeWrapper< ptr< CodeBuilder > > ) >( e, e.extPopContinuableScope(),
[]( const TypeWrapper< ptr< CodeBuilder > >& cb )
{
cb->popContinuableScope();
} );
RegisterBuiltinFunc< Intrinsic< void ( TypeWrapper< ptr< CodeBuilder > >, Value, uint32_t ) > >( e, e.extPushLiveValue(),
[]( auto&& c, const Value& cbv, const Value& v, const Value& index )
{
auto cb = *FromValue< TypeWrapper< ptr< CodeBuilder > > >( cbv );
cb->pushLiveValue( v, *FromValue< uint32_t >( index ) );
} );
RegisterBuiltinFunc< Eager< void > ( TypeWrapper< ptr< CodeBuilder > >, uint32_t ) >( e, e.extExtendValueLifetime(),
[]( const TypeWrapper< ptr< CodeBuilder > >& cb, uint32_t index )
{
cb->extendValueLifetime( index );
} );
RegisterBuiltinFunc< Intrinsic< bool ( TypeWrapper< ptr< CodeBuilder > > ) > >( e, e.extDestroyAndPopCurrentLifetimeScopeValues(),
[]( auto&& c, const Value& cbv )
{
auto cb = *FromValue< TypeWrapper< ptr< CodeBuilder > > >( cbv );
return ToValue( cb->destroyAndPopCurrentLifetimeScopeValues( c ) );
} );
RegisterBuiltinFunc< Intrinsic< bool ( TypeWrapper< ptr< CodeBuilder > > ) > >( e, e.extDestroyAllLiveValues(),
[]( auto&& c, const Value& cbv )
{
auto cb = *FromValue< TypeWrapper< ptr< CodeBuilder > > >( cbv );
return ToValue( cb->destroyAllLiveValues( c ) );
} );
RegisterBuiltinFunc< Intrinsic< bool ( TypeWrapper< ptr< CodeBuilder > >, uint32_t ) > >( e, e.extDestroyAllLiveValuesFromBreakScope(),
[]( auto&& c, const Value& cbv, const Value& index )
{
auto cb = *FromValue< TypeWrapper< ptr< CodeBuilder > > >( cbv );
return ToValue( cb->destroyAllLiveValuesFromBreakScope( c, *FromValue< uint32_t >( index ) ) );
} );
RegisterBuiltinFunc< Intrinsic< bool ( TypeWrapper< ptr< CodeBuilder > >, uint32_t ) > >( e, e.extDestroyAllLiveValuesFromContinueScope(),
[]( auto&& c, const Value& cbv, const Value& index )
{
auto cb = *FromValue< TypeWrapper< ptr< CodeBuilder > > >( cbv );
return ToValue( cb->destroyAllLiveValuesFromContinueScope( c, *FromValue< uint32_t >( index ) ) );
} );
}
}
|
Changes to bs/builtins/builtins.cpp.
| ︙ | ︙ | |||
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
e.extLowerConstantForRuntime() = CreateOverloadSet( e, "_LowerConstantForRuntime"_sid );
e.extLowerTypeForVerification() = CreateOverloadSet( e, "_LowerTypeForVerification"_sid );
e.extLowerConstantForVerification() = CreateOverloadSet( e, "_LowerConstantForVerification"_sid );
e.extConvertFuncParam() = CreateOverloadSet( e, "_ConvertFuncParam"_sid );
e.extConvertFuncArg() = CreateOverloadSet( e, "_ConvertFuncArg"_sid );
SetupBuiltinTypes( e );
SetupBuiltinOperators( e );
SetupBuiltinStatements( e );
}
const Term& RootG0Identity()
{
static auto identity = VEC( TSID( g0 ) );
return identity;
}
| > > > > > > > > > > > > > > > > > > > > > > > > | 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
e.extLowerConstantForRuntime() = CreateOverloadSet( e, "_LowerConstantForRuntime"_sid );
e.extLowerTypeForVerification() = CreateOverloadSet( e, "_LowerTypeForVerification"_sid );
e.extLowerConstantForVerification() = CreateOverloadSet( e, "_LowerConstantForVerification"_sid );
e.extConvertFuncParam() = CreateOverloadSet( e, "_ConvertFuncParam"_sid );
e.extConvertFuncArg() = CreateOverloadSet( e, "_ConvertFuncArg"_sid );
e.extPoisonBuilder() = CreateOverloadSet( e, "_PoisonBuilder"_sid );
e.extBuilderAllowsVarDecl() = CreateOverloadSet( e, "_BuilderAllowsVarDecl"_sid );
e.extGetCFG() = CreateOverloadSet( e, "_GetCFG"_sid );
e.extGetBreakableScopeLevels() = CreateOverloadSet( e, "_GetBreakableScopeLevels"_sid );
e.extGetContinuableScopeLevels() = CreateOverloadSet( e, "_GetContinuableScopeLevels"_sid );
e.extPushLifetimeScope() = CreateOverloadSet( e, "_PushLifetimeScope"_sid );
e.extPopLifetimeScope() = CreateOverloadSet( e, "_PopLifetimeScope"_sid );
e.extPushBreakableScope() = CreateOverloadSet( e, "_PushBreakableScope"_sid );
e.extPopBreakableScope() = CreateOverloadSet( e, "_PopBreakableScope"_sid );
e.extPushContinuableScope() = CreateOverloadSet( e, "_PushContinuableScope"_sid );
e.extPopContinuableScope() = CreateOverloadSet( e, "_PopContinuableScope"_sid );
e.extPushLiveValue() = CreateOverloadSet( e, "_PushLiveValue"_sid );
e.extExtendValueLifetime() = CreateOverloadSet( e, "_ExtendValueLifetime"_sid );
e.extDestroyAndPopCurrentLifetimeScopeValues() = CreateOverloadSet( e, "_DestroyAndPopCurrentLifetimeScopeValues"_sid );
e.extDestroyAllLiveValues() = CreateOverloadSet( e, "_DestroyAllLiveValues"_sid );
e.extDestroyAllLiveValuesFromBreakScope() = CreateOverloadSet( e, "_DestroyAllLiveValuesFromBreakScope"_sid );
e.extDestroyAllLiveValuesFromContinueScope() = CreateOverloadSet( e, "_DestroyAllLiveValuesFromContinueScope"_sid );
SetupBuiltinTypes( e );
SetupBuiltinOperators( e );
SetupBuiltinStatements( e );
SetupBuilderInterfaces( e );
}
const Term& RootG0Identity()
{
static auto identity = VEC( TSID( g0 ) );
return identity;
}
|
| ︙ | ︙ |
Changes to bs/builtins/builtins.h.
| ︙ | ︙ | |||
13 14 15 16 17 18 19 20 21 22 |
using namespace diagnostics;
extern const Term& RootG0Identity();
}
#include "codegen/codegen.h"
#include "types/types.h"
#include "operators/operators.h"
#include "statements/statements.h"
| > > | | | | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
using namespace diagnostics;
extern const Term& RootG0Identity();
}
#include "codegen/codegen.h"
#include "helpers.h"
#include "builders/codebuilder.h"
#include "types/types.h"
#include "operators/operators.h"
#include "statements/statements.h"
#include "exprhelpers.h"
namespace goose::builtins
{
extern void SetupBuilderInterfaces( Env& e );
extern void SetupBuiltins( Env& e );
}
#endif
|
Added bs/builtins/exprhelpers.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
#ifndef GOOSE_BUILTINS_EXPRHELPERS_H
#define GOOSE_BUILTINS_EXPRHELPERS_H
#include "parse/parse.h"
namespace goose::builtins::exprhelpers
{
template< typename V >
Value Not( V&& val )
{
return BuildComputedValue( GetValueType< bool >(),
cir::Not( forward< V >( val ) ) ).setLocationId( val.locationId() );
}
template< typename L, typename R >
Value Or( L&& lhs, R&& rhs )
{
auto locId = max( lhs.locationId(), rhs.locationId() );
return BuildComputedValue( GetValueType< bool >(),
cir::Or( forward< L >( lhs ), forward< R >( rhs ) ) ).setLocationId( locId );
}
template< typename L, typename R >
Value And( L&& lhs, R&& rhs )
{
auto locId = max( lhs.locationId(), rhs.locationId() );
return BuildComputedValue( GetValueType< bool >(),
cir::And( forward< L >( lhs ), forward< R >( rhs ) ) ).setLocationId( locId );
}
template< typename L, typename R >
Value Eq( L&& lhs, R&& rhs )
{
auto locId = max( lhs.locationId(), rhs.locationId() );
return BuildComputedValue( GetValueType< bool >(),
cir::Eq( forward< L >( lhs ), forward< R >( rhs ) ) ).setLocationId( locId );
}
template< typename L, typename R >
Value Neq( L&& lhs, R&& rhs )
{
auto locId = max( lhs.locationId(), rhs.locationId() );
return BuildComputedValue( GetValueType< bool >(),
cir::Neq( forward< L >( lhs ), forward< R >( rhs ) ) ).setLocationId( locId );
}
template< typename L, typename R >
Value UGT( L&& lhs, R&& rhs )
{
auto locId = max( lhs.locationId(), rhs.locationId() );
return BuildComputedValue( GetValueType< bool >(),
cir::UGT( forward< L >( lhs ), forward< R >( rhs ) ) ).setLocationId( locId );
}
template< typename L, typename R >
Value UGE( L&& lhs, R&& rhs )
{
auto locId = max( lhs.locationId(), rhs.locationId() );
return BuildComputedValue( GetValueType< bool >(),
cir::UGE( forward< L >( lhs ), forward< R >( rhs ) ) ).setLocationId( locId );
}
template< typename L, typename R >
Value ULT( L&& lhs, R&& rhs )
{
auto locId = max( lhs.locationId(), rhs.locationId() );
return BuildComputedValue( GetValueType< bool >(),
cir::ULT( forward< L >( lhs ), forward< R >( rhs ) ) ).setLocationId( locId );
}
template< typename L, typename R >
Value ULE( L&& lhs, R&& rhs )
{
auto locId = max( lhs.locationId(), rhs.locationId() );
return BuildComputedValue( GetValueType< bool >(),
cir::ULE( forward< L >( lhs ), forward< R >( rhs ) ) ).setLocationId( locId );
}
template< typename L, typename R >
Value SGT( L&& lhs, R&& rhs )
{
auto locId = max( lhs.locationId(), rhs.locationId() );
return BuildComputedValue( GetValueType< bool >(),
cir::SGT( forward< L >( lhs ), forward< R >( rhs ) ) ).setLocationId( locId );
}
template< typename L, typename R >
Value SGE( L&& lhs, R&& rhs )
{
auto locId = max( lhs.locationId(), rhs.locationId() );
return BuildComputedValue( GetValueType< bool >(),
cir::SGE( forward< L >( lhs ), forward< R >( rhs ) ) ).setLocationId( locId );
}
template< typename L, typename R >
Value SLT( L&& lhs, R&& rhs )
{
auto locId = max( lhs.locationId(), rhs.locationId() );
return BuildComputedValue( GetValueType< bool >(),
cir::SLT( forward< L >( lhs ), forward< R >( rhs ) ) ).setLocationId( locId );
}
template< typename L, typename R >
Value SLE( L&& lhs, R&& rhs )
{
auto locId = max( lhs.locationId(), rhs.locationId() );
return BuildComputedValue( GetValueType< bool >(),
cir::SLE( forward< L >( lhs ), forward< R >( rhs ) ) ).setLocationId( locId );
}
}
#endif
|
Changes to bs/builtins/helpers.cpp.
1 | #include "builtins/builtins.h" | < | | > | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
#include "builtins/builtins.h"
using namespace goose::parse;
namespace goose::builtins
{
void RegisterRule( sema::Env& env, StringId name, parse::Rule&& rule )
{
parse::RegisterRule( env, AppendToVectorTerm( RootG0Identity(), TERM( name ) ), move( rule ) );
}
ptr< cir::BasicBlock > ParseSubStatement( Parser& p, uint32_t precedence )
{
auto next = p.resolver()->lookAheadUnresolved();
if( !next )
return nullptr;
auto np = p.makeNestedParser();
auto cfg = GetCFG( np.context() );
if( !cfg )
return nullptr;
auto bb = cfg->createBB();
cfg->setCurrentBB( bb );
auto decomp = Decompose( next->first, Val< Delimiter >() );
if( !decomp || *decomp != Delimiter::OpenBrace )
{
// This is not a braced statement: create a new identity and visibility rules
// so that anything defined by the statement isn't visible outside of it.
// If it is a braced statement, the block will be parsed as a nested brace block
|
| ︙ | ︙ | |||
69 70 71 72 73 74 75 |
return false;
vec.emplace_back( *val );
}
return true;
}
| | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 |
return false;
vec.emplace_back( *val );
}
return true;
}
void PoisonBuilder( const Context& c )
{
DiagnosticsContext dc( 0, "When invoking _PoisonBuilder." );
InvokeOverloadSet( c, c.env()->extPoisonBuilder(),
MakeTuple( c.builder() ) );
}
bool BuilderAllowsVarDecl( const Context& c )
{
DiagnosticsContext dc( 0, "When invoking _BuilderAllowsVarDecl." );
auto result = InvokeOverloadSet( c, c.env()->extBuilderAllowsVarDecl(),
MakeTuple( c.builder() ) );
if( result.isPoison() )
return {};
auto success = FromValue< bool >( result );
if( !success )
return {};
return *success;
}
ptr< cir::CFG > GetCFG( const Context& c )
{
DiagnosticsContext dc( 0, "When invoking _GetCFG." );
auto result = InvokeOverloadSet( c, c.env()->extGetCFG(),
MakeTuple( c.builder() ) );
if( result.isPoison() )
return {};
auto cfg = FromValue< TypeWrapper< ptr< cir::CFG > > >( result );
if( !cfg )
return {};
return *cfg;
}
uint32_t GetBreakableScopeLevels( const Context& c )
{
DiagnosticsContext dc( 0, "When invoking _GetBreakableScopeLevels." );
auto result = InvokeOverloadSet( c, c.env()->extGetBreakableScopeLevels(),
MakeTuple( c.builder() ) );
if( result.isPoison() )
return {};
auto levels = FromValue< uint32_t >( result );
if( !levels )
return {};
return *levels;
}
uint32_t GetContinuableScopeLevels( const Context& c )
{
DiagnosticsContext dc( 0, "When invoking _GetContinuableScopeLevels." );
auto result = InvokeOverloadSet( c, c.env()->extGetContinuableScopeLevels(),
MakeTuple( c.builder() ) );
if( result.isPoison() )
return {};
auto levels = FromValue< uint32_t >( result );
if( !levels )
return {};
return *levels;
}
void PushLifetimeScope( const Context& c )
{
DiagnosticsContext dc( 0, "When invoking _PushLifetimeScope." );
InvokeOverloadSet( c, c.env()->extPushLifetimeScope(),
MakeTuple( c.builder() ) );
}
void PopLifetimeScope( const Context& c )
{
DiagnosticsContext dc( 0, "When invoking _PopLifetimeScope." );
InvokeOverloadSet( c, c.env()->extPopLifetimeScope(),
MakeTuple( c.builder() ) );
}
void PushBreakableScope( const Context& c )
{
DiagnosticsContext dc( 0, "When invoking _PushBreakableScope." );
InvokeOverloadSet( c, c.env()->extPushBreakableScope(),
MakeTuple( c.builder() ) );
}
void PopBreakableScope( const Context& c )
{
DiagnosticsContext dc( 0, "When invoking _PopBreakableScope." );
InvokeOverloadSet( c, c.env()->extPopBreakableScope(),
MakeTuple( c.builder() ) );
}
void PushContinuableScope( const Context& c )
{
DiagnosticsContext dc( 0, "When invoking _PushContinuableScope." );
InvokeOverloadSet( c, c.env()->extPushContinuableScope(),
MakeTuple( c.builder() ) );
}
void PopContinuableScope( const Context& c )
{
DiagnosticsContext dc( 0, "When invoking _PopContinuableScope." );
InvokeOverloadSet( c, c.env()->extPopContinuableScope(),
MakeTuple( c.builder() ) );
}
void PushLiveValue( const Context& c, const Value& val, uint32_t index )
{
DiagnosticsContext dc( val.locationId(), "When invoking _PushLiveValue." );
InvokeOverloadSet( c, c.env()->extPushLiveValue(),
MakeTuple( c.builder(), val, ToValue( index ) ) );
}
void ExtendValueLifetime( const Context& c, uint32_t index )
{
DiagnosticsContext dc( 0, "When invoking _ExtendValueLifetime." );
InvokeOverloadSet( c, c.env()->extExtendValueLifetime(),
MakeTuple( c.builder(), ToValue( index ) ) );
}
bool DestroyAndPopCurrentLifetimeScopeValues( const Context& c )
{
DiagnosticsContext dc( 0, "When invoking _DestroyAndPopCurrentLifetimeScopeValues." );
auto result = InvokeOverloadSet( c, c.env()->extDestroyAndPopCurrentLifetimeScopeValues(),
MakeTuple( c.builder() ) );
if( result.isPoison() )
return {};
auto success = FromValue< bool >( result );
if( !success )
return {};
return *success;
}
bool DestroyAllLiveValues( const Context& c )
{
DiagnosticsContext dc( 0, "When invoking _DestroyAllLiveValues." );
auto result = InvokeOverloadSet( c, c.env()->extDestroyAllLiveValues(),
MakeTuple( c.builder() ) );
if( result.isPoison() )
return {};
auto success = FromValue< bool >( result );
if( !success )
return {};
return *success;
}
bool DestroyAllLiveValuesFromBreakScope( const Context& c, uint32_t breakScopeLevel )
{
DiagnosticsContext dc( 0, "When invoking _DestroyAllLiveValuesFromBreakScope." );
auto result = InvokeOverloadSet( c, c.env()->extDestroyAllLiveValuesFromBreakScope(),
MakeTuple( c.builder(), ToValue( breakScopeLevel ) ) );
if( result.isPoison() )
return {};
auto success = FromValue< bool >( result );
if( !success )
return {};
return *success;
}
bool DestroyAllLiveValuesFromContinueScope( const Context& c, uint32_t continueScopeLevel )
{
DiagnosticsContext dc( 0, "When invoking _DestroyAllLiveValuesFromContinueScope." );
auto result = InvokeOverloadSet( c, c.env()->extDestroyAllLiveValuesFromContinueScope(),
MakeTuple( c.builder(), ToValue( continueScopeLevel ) ) );
if( result.isPoison() )
return {};
auto success = FromValue< bool >( result );
if( !success )
return {};
return *success;
}
}
|
Changes to bs/builtins/helpers.h.
1 2 3 | #ifndef GOOSE_BUILTINS_HELPERS_H #define GOOSE_BUILTINS_HELPERS_H | | > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
#ifndef GOOSE_BUILTINS_HELPERS_H
#define GOOSE_BUILTINS_HELPERS_H
namespace goose::parse
{
class Parser;
class Rule;
}
namespace goose::builtins
{
extern const Term& EmptyPredicates();
template< typename T >
void DefineConstant( sema::Env& env, StringId name, T&& val )
{
env.storeValue( AppendToVectorTerm( RootG0Identity(), TERM( name ) ), ANYTERM( _ ), forward< T >( val ) );
}
extern void RegisterRule( sema::Env& env, StringId name, parse::Rule&& rule );
|
| ︙ | ︙ | |||
55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
auto MkStdRTType( I&& identity, L&& llvmType )
{
return VEC( forward< I >( identity ), EmptyPredicates(), forward< L >( llvmType ) );
}
extern bool ParseExpressionList( parse::Parser& p, uint32_t precedence, ValueVec& vec );
struct CTTypePattern
{
static const Term& GetPattern()
{
static auto pat = ValueToEIR( Value( TypeType(), VEC( TSID( ct_type ), REPEAT( HOLE( "_"_sid ) ) ) ) );
return pat;
}
| > > > > > > > > > > > > > > > > > > > > > > > | 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
auto MkStdRTType( I&& identity, L&& llvmType )
{
return VEC( forward< I >( identity ), EmptyPredicates(), forward< L >( llvmType ) );
}
extern bool ParseExpressionList( parse::Parser& p, uint32_t precedence, ValueVec& vec );
extern void PoisonBuilder( const Context& c );
extern bool BuilderAllowsVarDecl( const Context& c );
extern ptr< cir::CFG > GetCFG( const Context& c );
extern uint32_t GetBreakableScopeLevels( const Context& c );
extern uint32_t GetContinuableScopeLevels( const Context& c );
extern void PushLifetimeScope( const Context& c );
extern void PopLifetimeScope( const Context& c );
extern void PushBreakableScope( const Context& c );
extern void PopBreakableScope( const Context& c );
extern void PushContinuableScope( const Context& c );
extern void PopContinuableScope( const Context& c );
extern void PushLiveValue( const Context& c, const Value& val, uint32_t index );
extern void ExtendValueLifetime( const Context& c, uint32_t index );
extern bool DestroyAndPopCurrentLifetimeScopeValues( const Context& c );
extern bool DestroyAllLiveValues( const Context& c );
extern bool DestroyAllLiveValuesFromBreakScope( const Context& c, uint32_t breakScopeLevel );
extern bool DestroyAllLiveValuesFromContinueScope( const Context& c, uint32_t continueScopeLevel );
struct CTTypePattern
{
static const Term& GetPattern()
{
static auto pat = ValueToEIR( Value( TypeType(), VEC( TSID( ct_type ), REPEAT( HOLE( "_"_sid ) ) ) ) );
return pat;
}
|
| ︙ | ︙ |
Changes to bs/builtins/meson.build.
| ︙ | ︙ | |||
98 99 100 101 102 103 104 105 106 107 108 |
'statements/return.cpp',
'statements/if.cpp',
'statements/hif.cpp',
'statements/while.cpp',
'statements/break.cpp',
'statements/continue.cpp',
'statements/verification.cpp',
include_directories: bsinc,
dependencies: [fmt_dep, tracy_dep]
)
| > > > | 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
'statements/return.cpp',
'statements/if.cpp',
'statements/hif.cpp',
'statements/while.cpp',
'statements/break.cpp',
'statements/continue.cpp',
'statements/verification.cpp',
'builders/codebuilder.cpp',
'builders/interfaces.cpp',
include_directories: bsinc,
dependencies: [fmt_dep, tracy_dep]
)
|
Changes to bs/builtins/operators/arith.cpp.
| ︙ | ︙ | |||
83 84 85 86 87 88 89 |
BuildParseRule( e, "/"_sid,
LeftAssInfixOp( "operator_divide"_sid, precedence::MulDivOp,
BuildGenericTupleOperator(),
ForType< BigInt, SDiv >(),
ForType< CustomPattern< IntegerType, IntegerType::PatternSigned > >(
[]( auto&& c, auto&& lhs, auto&& rhs ) -> Value
{
| | < | | < | | 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
BuildParseRule( e, "/"_sid,
LeftAssInfixOp( "operator_divide"_sid, precedence::MulDivOp,
BuildGenericTupleOperator(),
ForType< BigInt, SDiv >(),
ForType< CustomPattern< IntegerType, IntegerType::PatternSigned > >(
[]( auto&& c, auto&& lhs, auto&& rhs ) -> Value
{
using namespace goose::builtins::exprhelpers;
auto cfg = GetCFG( c );
assert( cfg );
// Build a zero constant of the same type as the denominator
// to construct the assertion expression.
auto zeroValue = Value( rhs.type(), APSInt::get( 0 ) );
auto cond = Neq( rhs, zeroValue );
DiagnosticsManager::GetInstance().defineCustomDiagnostic(
cond.locationId(), "assert"_sid, "the divisor may be 0." );
cfg->currentBB()->emplace_back(
cir::Assert( move( cond ) )
);
return BuildComputedValue( lhs.type(),
SDiv( lhs, rhs ) );
} ),
ForType< CustomPattern< IntegerType, IntegerType::PatternUnsigned > >(
[]( auto&& c, auto&& lhs, auto&& rhs ) -> Value
{
using namespace goose::builtins::exprhelpers;
auto cfg = GetCFG( c );
assert( cfg );
// Build a zero constant of the same type as the denominator
// to construct the assertion expression.
auto zeroValue = Value( rhs.type(), APSInt::get( 0 ) );
auto cond = Neq( rhs, zeroValue );
|
| ︙ | ︙ | |||
138 139 140 141 142 143 144 |
BuildParseRule( e, "%"_sid,
LeftAssInfixOp( "operator_modulo"_sid, precedence::MulDivOp,
BuildGenericTupleOperator(),
ForType< BigInt, SRem >(),
ForType< CustomPattern< IntegerType, IntegerType::PatternSigned > >(
[]( auto&& c, auto&& lhs, auto&& rhs ) -> Value
{
| | < | | < | | 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 |
BuildParseRule( e, "%"_sid,
LeftAssInfixOp( "operator_modulo"_sid, precedence::MulDivOp,
BuildGenericTupleOperator(),
ForType< BigInt, SRem >(),
ForType< CustomPattern< IntegerType, IntegerType::PatternSigned > >(
[]( auto&& c, auto&& lhs, auto&& rhs ) -> Value
{
using namespace goose::builtins::exprhelpers;
auto cfg = GetCFG( c );
assert( cfg );
// Build a zero constant of the same type as the denominator
// to construct the assertion expression.
auto zeroValue = Value( rhs.type(), APSInt::get( 0 ) );
auto cond = Neq( rhs, zeroValue );
DiagnosticsManager::GetInstance().defineCustomDiagnostic(
cond.locationId(), "assert"_sid, "the divisor may be 0." );
cfg->currentBB()->emplace_back(
cir::Assert( move( cond ) )
);
return BuildComputedValue( lhs.type(),
SRem( lhs, rhs ) );
} ),
ForType< CustomPattern< IntegerType, IntegerType::PatternUnsigned > >(
[]( auto&& c, auto&& lhs, auto&& rhs ) -> Value
{
using namespace goose::builtins::exprhelpers;
auto cfg = GetCFG( c );
assert( cfg );
// Build a zero constant of the same type as the denominator
// to construct the assertion expression.
auto zeroValue = Value( rhs.type(), APSInt::get( 0 ) );
auto cond = Neq( rhs, zeroValue );
|
| ︙ | ︙ |
Changes to bs/builtins/operators/assignment.cpp.
| ︙ | ︙ | |||
21 22 23 24 25 26 27 |
G_VAL_ASSERT( lhs, !lhs.isConstant() );
auto refType = *FromValue< ReferenceType >( *EIRToValue( lhs.type() ) );
if( !ParseTypePredicates( c, *EIRToValue( refType.type() ) ) )
return PoisonValue();
| | | | | | | 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
G_VAL_ASSERT( lhs, !lhs.isConstant() );
auto refType = *FromValue< ReferenceType >( *EIRToValue( lhs.type() ) );
if( !ParseTypePredicates( c, *EIRToValue( refType.type() ) ) )
return PoisonValue();
auto cfg = GetCFG( c );
if( !cfg )
{
DiagnosticsManager::GetInstance().emitSyntaxErrorMessage( 0, "assignments are not allowed here." );
return PoisonValue();
}
if( auto bb = cfg->currentBB() )
bb->emplace_back( Store( lhs.cir(), refType.type(), rhs, lhs.locationId() ) );
// Return the ref to support chained assignments, like in c++.
return Value( lhs );
};
// Generic function to assign a value to a decl (local variable declaration)
auto DeclAssignment = []( auto&& c, auto&& lhs, auto&& rhs ) -> Value
{
if( !BuilderAllowsVarDecl( c ) )
{
DiagnosticsManager::GetInstance().emitSyntaxErrorMessage( 0, "variable declarations are not allowed here." );
return PoisonValue();
}
auto decl = *FromValue< Decl >( lhs );
return DeclareLocalVar( c, decl.type(), decl.name(), rhs, lhs.locationId() );
};
// Generic function to assign a value to a template named decl (local variable declaration with local type inference)
auto TNamedDeclAssignment = []( auto&& c, auto&& lhs, auto&& rhs ) -> Value
{
if( !BuilderAllowsVarDecl( c ) )
{
DiagnosticsManager::GetInstance().emitSyntaxErrorMessage( 0, "variable declarations are not allowed here." );
return PoisonValue();
}
auto tndecl = *FromValue< TNamedDecl >( lhs );
return DeclareLocalVarWithTypeInference( c, tndecl.type(), tndecl.name(), rhs, lhs.locationId() );
|
| ︙ | ︙ |
Changes to bs/builtins/operators/dollar.cpp.
1 2 | #include "builtins/builtins.h" #include "precedence.h" | < | 1 2 3 4 5 6 7 8 9 | #include "builtins/builtins.h" #include "precedence.h" using namespace goose; using namespace goose::eir; using namespace goose::parse; using namespace goose::builtins; // Dollar is a low level operator: it doesn't expect a value rhs operand, |
| ︙ | ︙ |
Changes to bs/builtins/operators/dot.cpp.
| ︙ | ︙ | |||
18 19 20 21 22 23 24 |
// returns a reference to the specified member.
ForTypes< CustomPattern< Value, ReferenceType::PatternAnyOf< TuplePattern > >,
CustomPattern< IntegerType, IntegerType::PatternUnsigned32 > >(
[]( auto&& c, auto&& lhs, auto&& rhs ) -> Value
{
G_VAL_ASSERT( lhs, !lhs.isConstant() );
| < < < < | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
// returns a reference to the specified member.
ForTypes< CustomPattern< Value, ReferenceType::PatternAnyOf< TuplePattern > >,
CustomPattern< IntegerType, IntegerType::PatternUnsigned32 > >(
[]( auto&& c, auto&& lhs, auto&& rhs ) -> Value
{
G_VAL_ASSERT( lhs, !lhs.isConstant() );
if( !rhs.isConstant() )
{
DiagnosticsManager::GetInstance().emitErrorMessage( rhs.locationId(),
"the right operand for the dot operator needs to be a constant." );
return PoisonValue();
}
|
| ︙ | ︙ |
Changes to bs/builtins/operators/helpers.h.
1 2 3 | #ifndef GOOSE_BUILTINS_OPERATORS_HELPERS_H #define GOOSE_BUILTINS_OPERATORS_HELPERS_H | < < | 1 2 3 4 5 6 7 8 9 10 |
#ifndef GOOSE_BUILTINS_OPERATORS_HELPERS_H
#define GOOSE_BUILTINS_OPERATORS_HELPERS_H
namespace goose::builtins
{
using namespace goose::parse;
template< typename... R >
void BuildParseRule( sema::Env& env, StringId name, R&&... ruleBuilders )
{
|
| ︙ | ︙ |
Changes to bs/builtins/operators/logic.cpp.
| ︙ | ︙ | |||
89 90 91 92 93 94 95 |
return forward< L >( lhs );
return forward< R >( rhs );
}
// When building verification clauses we have no code builder and no cfg,
// and we just want to generate a plain or operation.
| > | < < < | 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
return forward< L >( lhs );
return forward< R >( rhs );
}
// When building verification clauses we have no code builder and no cfg,
// and we just want to generate a plain or operation.
auto cfg = GetCFG( c );
if( !cfg )
return BuildComputedValue( GetValueType< bool >(), Or( lhs, rhs ) );
// Build the control flow for shortcut evaluation.
const auto& predBB = cfg->currentBB();
auto pRhsBB = cfg->createBB();
auto pSuccBB = cfg->createBB();
// If the lhs is true, skip to the end directly.
// Otherwise, jump to the BB that computes rhs.
|
| ︙ | ︙ | |||
164 165 166 167 168 169 170 |
return forward< R >( rhs );
return forward< L >( lhs );
}
// When building verification clauses we have bo code builder and no cfg,
// and we just want to generate a plain and operation.
| > | < < < | 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 |
return forward< R >( rhs );
return forward< L >( lhs );
}
// When building verification clauses we have bo code builder and no cfg,
// and we just want to generate a plain and operation.
auto cfg = GetCFG( c );
if( !cfg )
return BuildComputedValue( GetValueType< bool >(), And( lhs, rhs ) );
// Build the control flow for shortcut evaluation.
const auto& predBB = cfg->currentBB();
auto pRhsBB = cfg->createBB();
auto pSuccBB = cfg->createBB();
// If the lhs is false, skip to the end directly.
// Otherwise, jump to the BB that computes rhs.
|
| ︙ | ︙ | |||
224 225 226 227 228 229 230 |
} ),
// runtime integer left shift.
ForTypes< CustomPattern< IntegerType, IntegerType::Pattern >,
CustomPattern< IntegerType, IntegerType::PatternUnsigned > >(
[]( auto&& c, auto&& lhs, auto&& rhs ) -> Value
{
| | < | | 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 |
} ),
// runtime integer left shift.
ForTypes< CustomPattern< IntegerType, IntegerType::Pattern >,
CustomPattern< IntegerType, IntegerType::PatternUnsigned > >(
[]( auto&& c, auto&& lhs, auto&& rhs ) -> Value
{
using namespace goose::builtins::exprhelpers;
auto cfg = GetCFG( c );
assert( cfg );
// Shifting for a number of bits equal or larger than the bitsize
// of lhs is an undefined behavior, so we require verification that
// it won't happen.
// Extract the integer type of lhs to retreieve its bit size.
auto lhsType = *FromValue< IntegerType >( *EIRToValue( lhs.type() ) );
|
| ︙ | ︙ | |||
270 271 272 273 274 275 276 |
// runtime signed integer right shift, defined to work for any two integers of same
// bit size.
ForTypes< CustomPattern< IntegerType, IntegerType::PatternSigned >,
CustomPattern< IntegerType, IntegerType::PatternUnsigned > >(
[]( auto&& c, auto&& lhs, auto&& rhs ) -> Value
{
| | < | | 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 |
// runtime signed integer right shift, defined to work for any two integers of same
// bit size.
ForTypes< CustomPattern< IntegerType, IntegerType::PatternSigned >,
CustomPattern< IntegerType, IntegerType::PatternUnsigned > >(
[]( auto&& c, auto&& lhs, auto&& rhs ) -> Value
{
using namespace goose::builtins::exprhelpers;
auto cfg = GetCFG( c );
assert( cfg );
// Shifting for a number of bits equal or larger than the bitsize
// of lhs is an undefined behavior, so we require verification that
// it won't happen.
// Extract the integer type of lhs to retreieve its bit size.
auto lhsType = *FromValue< IntegerType >( *EIRToValue( lhs.type() ) );
|
| ︙ | ︙ | |||
301 302 303 304 305 306 307 |
} ),
// runtime unsigned integer right shift, defined to work for any two integers of same
// bit size.
ForType< CustomPattern< IntegerType, IntegerType::PatternUnsigned > >(
[]( auto&& c, auto&& lhs, auto&& rhs ) -> Value
{
| | < | | 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 |
} ),
// runtime unsigned integer right shift, defined to work for any two integers of same
// bit size.
ForType< CustomPattern< IntegerType, IntegerType::PatternUnsigned > >(
[]( auto&& c, auto&& lhs, auto&& rhs ) -> Value
{
using namespace goose::builtins::exprhelpers;
auto cfg = GetCFG( c );
assert( cfg );
// Shifting for a number of bits equal or larger than the bitsize
// of lhs is an undefined behavior, so we require verification that
// it won't happen.
// Extract the integer type of lhs to retreieve its bit size.
auto lhsType = *FromValue< IntegerType >( *EIRToValue( lhs.type() ) );
|
| ︙ | ︙ |
Changes to bs/builtins/operators/semicolon.cpp.
1 2 | #include "builtins/builtins.h" #include "precedence.h" | < | 1 2 3 4 5 6 7 8 9 |
#include "builtins/builtins.h"
#include "precedence.h"
using namespace goose;
using namespace goose::eir;
using namespace goose::parse;
namespace
{
|
| ︙ | ︙ |
Changes to bs/builtins/operators/tuple.h.
1 2 3 | #ifndef GOOSE_BUILTINS_OPERATORS_TUPLE_H #define GOOSE_BUILTINS_OPERATORS_TUPLE_H | < < | 1 2 3 4 5 6 7 8 9 10 |
#ifndef GOOSE_BUILTINS_OPERATORS_TUPLE_H
#define GOOSE_BUILTINS_OPERATORS_TUPLE_H
namespace goose::builtins
{
using namespace goose::parse;
static inline auto BuildGenericTupleOperator()
{
return []< typename tag >( auto&& e, auto&& pOvlSet, tag t )
|
| ︙ | ︙ |
Changes to bs/builtins/operators/where.cpp.
1 2 | #include "builtins/builtins.h" #include "precedence.h" | < | 1 2 3 4 5 6 7 8 9 | #include "builtins/builtins.h" #include "precedence.h" using namespace goose; using namespace goose::eir; using namespace goose::parse; using namespace goose::builtins; namespace goose::builtins |
| ︙ | ︙ |
Changes to bs/builtins/statements/break.cpp.
1 2 3 | #include "builtins/builtins.h" #include "parse/parse.h" #include "precedence.h" | < | > | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
#include "builtins/builtins.h"
#include "parse/parse.h"
#include "precedence.h"
using namespace goose;
using namespace goose::eir;
using namespace goose::parse;
namespace goose::builtins
{
void SetupBreakStmt( Env& e )
{
auto handleBreak = []( Parser& p, LocationId locationId, uint32_t prec )
{
auto& dm = DiagnosticsManager::GetInstance();
auto level = GetBreakableScopeLevels( p.context() );
if( p.isInParenExpr() || !level )
{
dm.emitSyntaxErrorMessage( locationId, "the break statement is not allowed here.", 0 );
return false;
}
auto cfg = GetCFG( p.context() );
if( !cfg->currentBB() || cfg->currentBB()->terminator() )
{
DiagnosticsManager::GetInstance().emitSyntaxErrorMessage(
locationId, "unreachable code.", 0 );
PoisonBuilder( p.context() );
return true;
}
// Emit cleanups for all live variables in the scopes that we are breaking through.
DestroyAllLiveValuesFromBreakScope( p.context(), level );
cfg->currentBB()->setTerminator( cir::Break( level ) );
return true;
};
RegisterRule( e, "break"_sid, Rule( handleBreak ) );
}
}
|
Changes to bs/builtins/statements/continue.cpp.
1 2 3 | #include "builtins/builtins.h" #include "parse/parse.h" #include "precedence.h" | < | > | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
#include "builtins/builtins.h"
#include "parse/parse.h"
#include "precedence.h"
using namespace goose;
using namespace goose::eir;
using namespace goose::parse;
namespace goose::builtins
{
void SetupContinueStmt( Env& e )
{
auto handleContinue = []( Parser& p, LocationId locationId, uint32_t prec )
{
auto& dm = DiagnosticsManager::GetInstance();
auto level = GetContinuableScopeLevels( p.context() );
if( p.isInParenExpr() || !level )
{
dm.emitSyntaxErrorMessage( locationId, "the continue statement is not allowed here.", 0 );
return false;
}
auto cfg = GetCFG( p.context() );
if( !cfg->currentBB() || cfg->currentBB()->terminator() )
{
DiagnosticsManager::GetInstance().emitSyntaxErrorMessage(
locationId, "unreachable code.", 0 );
PoisonBuilder( p.context() );
return true;
}
// Emit cleanups for all live variables in the scopes that we are continuing through.
DestroyAllLiveValuesFromContinueScope( p.context(), level );
cfg->currentBB()->setTerminator( cir::Continue( level ) );
return true;
};
RegisterRule( e, "continue"_sid, Rule( handleContinue ) );
}
}
|
Changes to bs/builtins/statements/hif.cpp.
1 2 3 | #include "builtins/builtins.h" #include "parse/parse.h" #include "precedence.h" | < | 1 2 3 4 5 6 7 8 9 10 |
#include "builtins/builtins.h"
#include "parse/parse.h"
#include "precedence.h"
using namespace goose;
using namespace goose::eir;
using namespace goose::parse;
namespace goose::builtins
{
|
| ︙ | ︙ |
Changes to bs/builtins/statements/if.cpp.
1 2 3 | #include "builtins/builtins.h" #include "parse/parse.h" #include "precedence.h" | < | | < | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
#include "builtins/builtins.h"
#include "parse/parse.h"
#include "precedence.h"
using namespace goose;
using namespace goose::eir;
using namespace goose::parse;
namespace goose::builtins
{
void SetupIfStmt( Env& e )
{
auto handleIf = []( Parser& p, LocationId locationId, uint32_t prec )
{
auto& dm = DiagnosticsManager::GetInstance();
auto cfg = GetCFG( p.context() );
if( p.isInParenExpr() || !cfg )
{
dm.emitSyntaxErrorMessage( locationId, "the if statement is not allowed here.", 0 );
return false;
}
auto pPrecBB = cfg->currentBB();
if( !pPrecBB || pPrecBB->terminator() )
{
DiagnosticsManager::GetInstance().emitSyntaxErrorMessage(
locationId, "unreachable code.", 0 );
PoisonBuilder( p.context() );
}
// Create a scope for the entire if, so that any var declared
// inside of the condition is alive and visible throughout the if.
Scope s( p );
auto np = p.makeNestedParser();
|
| ︙ | ︙ | |||
67 68 69 70 71 72 73 |
break;
}
return false;
}
if( get< Value >( converted ).isPoison() )
| | | 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
break;
}
return false;
}
if( get< Value >( converted ).isPoison() )
PoisonBuilder( p.context() );
// The condition may have emitted additional basic blocks, so get the current block again.
pPrecBB = cfg->currentBB();
auto pThenBB = ParseSubStatement( p, precedence::IfStmt );
if( !pThenBB )
{
|
| ︙ | ︙ | |||
112 113 114 115 116 117 118 |
ptr< cir::BasicBlock > pSuccBB;
// If both the then and the else blocks successors exist and are terminated,
// we don't need a successor block.
if( !pElseBB || ( pThenSuccBB && !pThenSuccBB->terminator() )
|| ( pElseSuccBB && !pElseSuccBB->terminator() ) )
| | | 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
ptr< cir::BasicBlock > pSuccBB;
// If both the then and the else blocks successors exist and are terminated,
// we don't need a successor block.
if( !pElseBB || ( pThenSuccBB && !pThenSuccBB->terminator() )
|| ( pElseSuccBB && !pElseSuccBB->terminator() ) )
pSuccBB = cfg->createBB();
pPrecBB->setTerminator( cir::CondBranch(
get< Value >( converted ),
pThenBB,
pElseBB ? pElseBB : pSuccBB ) );
if( pThenSuccBB && !pThenSuccBB->terminator() )
|
| ︙ | ︙ |
Changes to bs/builtins/statements/return.cpp.
1 2 3 | #include "builtins/builtins.h" #include "parse/parse.h" #include "precedence.h" | < | | | | | | | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
#include "builtins/builtins.h"
#include "parse/parse.h"
#include "precedence.h"
using namespace goose;
using namespace goose::eir;
using namespace goose::parse;
namespace goose::builtins
{
void SetupReturnStmt( Env& e )
{
auto handleReturn = []( Parser& p, LocationId locationId, uint32_t prec )
{
auto& dm = DiagnosticsManager::GetInstance();
auto cfg = GetCFG( p.context() );
if( p.isInParenExpr() || !cfg )
{
dm.emitSyntaxErrorMessage( locationId, "the return statement is not allowed here.", 0 );
return false;
}
if( !cfg->currentBB() || cfg->currentBB()->terminator() )
{
DiagnosticsManager::GetInstance().emitSyntaxErrorMessage(
locationId, "unreachable code.", 0 );
PoisonBuilder( p.context() );
}
p.flushValue();
// Emit cleanups (destructor calls) for all currently live values in the function.
DestroyAllLiveValues( p.context() );
const auto& context = p.context();
if( context.returnType() == GetValueType< void >() )
{
cfg->emitTerminator( p.resolver()->currentLocation(), cir::Ret() );
return true;
}
auto np = p.makeNestedParser();
if( !np.parseExpression( precedence::ReturnStmt + 1 ) )
{
dm.emitSyntaxErrorMessage( locationId, "expected an expression following the return statement.", 0 );
cfg->emitTerminator( p.resolver()->currentLocation(), cir::Ret( PoisonValue() ) );
return false;
}
auto retVal = np.popValue();
if( !retVal )
{
dm.emitSyntaxErrorMessage( locationId, "expected an expression following the return statement.", 0 );
cfg->emitTerminator( p.resolver()->currentLocation(), cir::Ret( PoisonValue() ) );
return false;
}
auto converted = ConvertValueToType( context, *retVal, *context.returnType() );
if( holds_alternative< ValUnifyError >( converted ) )
{
switch( get< ValUnifyError >( converted ) )
{
case ValUnifyError::NoSolution:
dm.emitErrorMessage( retVal->locationId(), "return value type mismatch." );
break;
case ValUnifyError::Ambiguous:
dm.emitErrorMessage( retVal->locationId(), "ambiguous return value conversion." );
break;
}
// Emit a terminator with a poison value to avoid the function compilation
// code to complain about a missing return.
cfg->emitTerminator( p.resolver()->currentLocation(), cir::Ret( PoisonValue() ) );
PoisonBuilder( p.context() );
return true;
}
cfg->emitTerminator( p.resolver()->currentLocation(), cir::Ret( get< Value >( converted ) ) );
return true;
};
RegisterRule( e, "return"_sid, Rule( handleReturn ) );
}
}
|
Changes to bs/builtins/statements/using.cpp.
1 2 3 | #include "builtins/builtins.h" #include "parse/parse.h" #include "precedence.h" | < | 1 2 3 4 5 6 7 8 9 10 |
#include "builtins/builtins.h"
#include "parse/parse.h"
#include "precedence.h"
using namespace goose;
using namespace goose::eir;
using namespace goose::parse;
namespace goose::builtins
{
|
| ︙ | ︙ |
Changes to bs/builtins/statements/verification.cpp.
1 2 | #include "builtins/builtins.h" #include "precedence.h" | < | 1 2 3 4 5 6 7 8 9 | #include "builtins/builtins.h" #include "precedence.h" using namespace goose; using namespace goose::eir; using namespace goose::parse; using namespace goose::builtins; namespace |
| ︙ | ︙ |
Changes to bs/builtins/statements/while.cpp.
1 2 3 | #include "builtins/builtins.h" #include "parse/parse.h" #include "precedence.h" | < | | < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
#include "builtins/builtins.h"
#include "parse/parse.h"
#include "precedence.h"
using namespace goose;
using namespace goose::eir;
using namespace goose::parse;
namespace goose::builtins
{
void SetupWhileStmt( Env& e )
{
auto handleWhile = []( Parser& p, LocationId locationId, uint32_t prec )
{
auto& dm = DiagnosticsManager::GetInstance();
auto cfg = GetCFG( p.context() );
if( p.isInParenExpr() || !cfg )
{
dm.emitSyntaxErrorMessage( locationId, "the while statement is not allowed here.", 0 );
return false;
}
auto pPrecBB = cfg->currentBB();
if( !pPrecBB || pPrecBB->terminator() )
{
DiagnosticsManager::GetInstance().emitSyntaxErrorMessage(
locationId, "unreachable code.", 0 );
cfg->poison();
|
| ︙ | ︙ | |||
67 68 69 70 71 72 73 |
break;
}
return false;
}
if( get< Value >( converted ).isPoison() )
| | | | | 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
break;
}
return false;
}
if( get< Value >( converted ).isPoison() )
PoisonBuilder( p.context() );
// The condition may have emitted additional basic blocks, so get the current block again.
pPrecBB = cfg->currentBB();
auto pHeaderBB = cfg->createBB();
// Set the loop header's location to a span including the while keyword and the condition
pHeaderBB->setLocationId( Location::CreateSpanningLocation( locationId, condVal->locationId() ) );
BreakableScopeGuard bsg( p.context() );
ContinuableScopeGuard csg( p.context() );
auto pBodyBB = ParseSubStatement( p, precedence::IfStmt );
if( !pBodyBB )
{
dm.emitSyntaxErrorMessage( p.resolver()->currentLocation(), "expected a statement after the while condition.", 0 );
return false;
}
|
| ︙ | ︙ | |||
102 103 104 105 106 107 108 |
}
// Jump unconditionally from the pred block to the loop header.
pPrecBB->setTerminator( cir::Branch( pHeaderBB ) );
auto pSuccBB = cfg->createBB();
| | | | 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
}
// Jump unconditionally from the pred block to the loop header.
pPrecBB->setTerminator( cir::Branch( pHeaderBB ) );
auto pSuccBB = cfg->createBB();
auto breakLevel = GetBreakableScopeLevels( p.context() );
auto continueLevel = GetContinuableScopeLevels( p.context() );
// Go through all basic blocks, find all break and continue terminators
// for our scope level and replace them with branches respectively to
// the successor BB or to the loop header BB.
cfg->forEachBB( [&]( auto&& bb )
{
const auto& t = bb->terminator();
|
| ︙ | ︙ |
Changes to bs/builtins/types/basic.cpp.
1 | #include "builtins/builtins.h" | < | 1 2 3 4 5 6 7 8 |
#include "builtins/builtins.h"
using namespace goose;
using namespace goose::sema;
using namespace goose::builtins;
namespace goose::builtins
{
|
| ︙ | ︙ |
Changes to bs/builtins/types/drop.cpp.
| ︙ | ︙ | |||
10 11 12 13 14 15 16 |
{
// Default implementation of DropValue().
// Constant values are discarded, and the cir of computed values
// is appended to the current BB of the current parser.
RegisterBuiltinFunc< Intrinsic< void ( Value ) > >( e, e.extDropValue(),
[]( const Context& c, const Value& v )
{
| | > > > > | | | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
{
// Default implementation of DropValue().
// Constant values are discarded, and the cir of computed values
// is appended to the current BB of the current parser.
RegisterBuiltinFunc< Intrinsic< void ( Value ) > >( e, e.extDropValue(),
[]( const Context& c, const Value& v )
{
if( v.isConstant() )
return;
// Reference use a load instruction to store their address,
// so don't emit them. There is never any point in emitting
// a load whose result isn't used anyway.
if( holds_alternative< Load >( v.cir()->content() ) )
return;
auto cfg = GetCFG( c );
if( !cfg )
return;
auto bb = cfg->currentBB();
bb->emplace_back( move( *v.cir() ) );
} );
using AnyDeclType = CustomPattern< Decl, Decl::Pattern >;
// DropValue for Decls: declare a local variable with default initialization.
// TODO: if the invocation to InitializeValue fails, we should have a way to
// replace the generic "function arguments mismatch" error message with something
// more specific such as "can't default-initialize a variable of type XXX"
RegisterBuiltinFunc< Intrinsic< void ( AnyDeclType ) > >( e, e.extDropValue(),
[]( const Context& c, const Value& v )
{
if( !GetCFG( c ) )
{
DiagnosticsManager::GetInstance().emitSyntaxErrorMessage( 0, "variable declarations are not allowed here." );
return PoisonValue();
}
auto decl = *FromValue< Decl >( v );
return DeclareLocalVar( c, decl.type(), decl.name(), nullopt, v.locationId() );
|
| ︙ | ︙ |
Changes to bs/builtins/types/func/compile.cpp.
1 2 3 4 | #include "builtins/builtins.h" #include "lex/lex.h" #include "parse/parse.h" #include "verify/verify.h" | < | 1 2 3 4 5 6 7 8 9 10 11 |
#include "builtins/builtins.h"
#include "lex/lex.h"
#include "parse/parse.h"
#include "verify/verify.h"
using namespace goose::builtins;
using namespace goose::parse;
namespace goose::builtins
{
Value CompileFunc( const Context& c, const Value& f )
|
| ︙ | ︙ | |||
149 150 151 152 153 154 155 |
f.type().intrinsic() ? GetValueType< TypeWrapper< Value > >() : f.type().returnType() );
auto cfg = make_shared< cir::CFG >( VecSize( f.type().params() ) );
cfg->createBB();
cfg->setCurrentBB( cfg->entryBB() );
auto cb = make_shared< CodeBuilder >( cfg );
| | | 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 |
f.type().intrinsic() ? GetValueType< TypeWrapper< Value > >() : f.type().returnType() );
auto cfg = make_shared< cir::CFG >( VecSize( f.type().params() ) );
cfg->createBB();
cfg->setCurrentBB( cfg->entryBB() );
auto cb = make_shared< CodeBuilder >( cfg );
localContext.setBuilder( ToValue( TypeWrapper< ptr< CodeBuilder > >( cb ) ) );
// Create the local variable bindings to access the function params
// from inside the body, as well as the signature.
uint32_t varId = 0;
// For intrinsic functions, expose the context, which was
// pushed as en extra, implicit first arg
|
| ︙ | ︙ | |||
224 225 226 227 228 229 230 |
// TODO: at some point we'll want to check for reachability in the static verifier,
// and either emit the implicit return or declare the code unreachable depending on the result.
// The reachability analysis will have to be done before contract validation, as the
// calls to DestroyValue() may also have requirements to enforce, so we'll need to emit
// the eventual implicit return first.
p.flushValue();
cb->destroyAllLiveValues( localContext );
| | | 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 |
// TODO: at some point we'll want to check for reachability in the static verifier,
// and either emit the implicit return or declare the code unreachable depending on the result.
// The reachability analysis will have to be done before contract validation, as the
// calls to DestroyValue() may also have requirements to enforce, so we'll need to emit
// the eventual implicit return first.
p.flushValue();
cb->destroyAllLiveValues( localContext );
cfg->emitTerminator( r->currentLocation(), cir::Ret() );
}
pFuncCIR->body() = cfg;
verify::Func fv( localContext, f );
return fv.verify();
}
}
|
Changes to bs/builtins/types/func/func.cpp.
1 2 3 4 | #include "builtins/builtins.h" #include "lex/lex.h" #include "parse/parse.h" #include "verify/verify.h" | < | 1 2 3 4 5 6 7 8 9 10 11 |
#include "builtins/builtins.h"
#include "lex/lex.h"
#include "parse/parse.h"
#include "verify/verify.h"
using namespace goose::builtins;
using namespace goose::parse;
namespace goose::builtins
{
const Term& FuncPattern::GetPattern()
|
| ︙ | ︙ |
Changes to bs/builtins/types/func/invoke.cpp.
| ︙ | ︙ | |||
85 86 87 88 89 90 91 |
auto argList = BuildArgListForCall( c, ft, typeCheckedArgs );
if( !argList )
return PoisonValue();
auto result = BuildComputedValue( typeCheckedRType, cir::Call( preparedCallee, move( *argList ) ) );
// If the result is non-void, register it for destruction.
| | | | | 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
auto argList = BuildArgListForCall( c, ft, typeCheckedArgs );
if( !argList )
return PoisonValue();
auto result = BuildComputedValue( typeCheckedRType, cir::Call( preparedCallee, move( *argList ) ) );
// If the result is non-void, register it for destruction.
if( result.type() != GetValueType< void >() )
{
if( auto cfg = GetCFG( c ) )
PushLiveValue( c, result, cfg->getNewTemporaryIndex() );
}
return result;
}
optional< Term > getSignature( const Value& callee ) const final
{
|
| ︙ | ︙ |
Changes to bs/builtins/types/localvar/drop.cpp.
| ︙ | ︙ | |||
24 25 26 27 28 29 30 |
auto identity = AppendToVectorTerm( c.identity(), lv.name() );
c.env()->storeValue( identity, ANYTERM( _ ),
ValueToEIR( v ) );
// Extend the variable's lifetime, so that it won't be destroyed as the statement's lifetime scope ends,
// but instead when its parent lifetime scope ends.
| < | | 24 25 26 27 28 29 30 31 32 33 34 |
auto identity = AppendToVectorTerm( c.identity(), lv.name() );
c.env()->storeValue( identity, ANYTERM( _ ),
ValueToEIR( v ) );
// Extend the variable's lifetime, so that it won't be destroyed as the statement's lifetime scope ends,
// but instead when its parent lifetime scope ends.
ExtendValueLifetime( c, lv.index() );
} );
}
}
|
Changes to bs/builtins/types/localvar/localvar.cpp.
| ︙ | ︙ | |||
17 18 19 20 21 22 23 |
{
static auto pattern = GetValueType< LocalVar >( HOLE( "T"_sid ) );
return pattern;
}
Value DeclareLocalVar( const Context& c, const Term& type, StringId name, const optional< Value >& initializer, LocationId locId )
{
| | | | | 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
{
static auto pattern = GetValueType< LocalVar >( HOLE( "T"_sid ) );
return pattern;
}
Value DeclareLocalVar( const Context& c, const Term& type, StringId name, const optional< Value >& initializer, LocationId locId )
{
auto cfg = GetCFG( c );
if( !cfg )
return PoisonValue();
auto index = cfg->getNewTemporaryIndex();
auto bb = cfg->currentBB();
if( !bb )
return PoisonValue();
|
| ︙ | ︙ | |||
69 70 71 72 73 74 75 |
auto locVar = ToValue( lv );
auto identity = AppendToVectorTerm( c.identity(), name );
c.env()->storeValue( identity, ANYTERM( _ ),
ValueToEIR( locVar ) );
| | | | | | 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
auto locVar = ToValue( lv );
auto identity = AppendToVectorTerm( c.identity(), name );
c.env()->storeValue( identity, ANYTERM( _ ),
ValueToEIR( locVar ) );
PushLiveValue( c, locVar, lv.index() );
return locVar;
}
Value DeclareLocalVarWithTypeInference( Context& c, const Term& typeTExpr, StringId name, const Value& initVal, LocationId locId )
{
auto cfg = GetCFG( c );
if( !cfg )
return PoisonValue();
auto bb = cfg->currentBB();
if( !bb )
return PoisonValue();
// To infer the type and obtain a suitable initialization function, we typecheck
// ( $$T, _ ( MutRef[$$T], initValType ) initFunc )
|
| ︙ | ︙ | |||
204 205 206 207 208 209 210 |
if( name != ""_sid )
{
auto identity = AppendToVectorTerm( c.identity(), name );
c.env()->storeValue( identity, ANYTERM( _ ),
ValueToEIR( locVar ) );
}
| | | 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 |
if( name != ""_sid )
{
auto identity = AppendToVectorTerm( c.identity(), name );
c.env()->storeValue( identity, ANYTERM( _ ),
ValueToEIR( locVar ) );
}
PushLiveValue( c, locVar, lv.index() );
return locVar;
}
}
namespace goose::eir
{
const Term& Bridge< LocalVarType >::Type()
|
| ︙ | ︙ |
Changes to bs/builtins/types/overloadset/helpers.cpp.
| ︙ | ︙ | |||
58 59 60 61 62 63 64 |
}
Value InvokeOverloadSet( const Context& c, const ptr< OverloadSet >& pOvlSet, Value args )
{
assert( pOvlSet );
Context localC( c.env(), c.identity(), GetValueType< uint32_t >() );
| | | 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
}
Value InvokeOverloadSet( const Context& c, const ptr< OverloadSet >& pOvlSet, Value args )
{
assert( pOvlSet );
Context localC( c.env(), c.identity(), GetValueType< uint32_t >() );
localC.setBuilder( c.builder() );
execute::VM vm;
if( !args.isConstant() && cir::CanValueBeEagerlyEvaluated( args ) )
args = execute::Evaluate( args, vm );
if( args.isPoison() )
return PoisonValue();
|
| ︙ | ︙ |
Changes to bs/builtins/types/predicates/predicates.cpp.
1 2 3 | #include "builtins/builtins.h" #include "lex/lex.h" #include "parse/parse.h" | < | 1 2 3 4 5 6 7 8 9 10 |
#include "builtins/builtins.h"
#include "lex/lex.h"
#include "parse/parse.h"
using namespace goose::parse;
namespace goose::builtins
{
const Term& EmptyPredicates()
{
|
| ︙ | ︙ |
Changes to bs/builtins/types/pretty.cpp.
1 | #include "builtins/builtins.h" | < | 1 2 3 4 5 6 7 8 |
#include "builtins/builtins.h"
using namespace goose;
using namespace goose::sema;
using namespace goose::builtins;
namespace goose::builtins
{
|
| ︙ | ︙ |
Changes to bs/builtins/types/reference/parse.cpp.
1 2 3 | #include "builtins/builtins.h" #include "parse/parse.h" #include "precedence.h" | < | 1 2 3 4 5 6 7 8 9 10 | #include "builtins/builtins.h" #include "parse/parse.h" #include "precedence.h" using namespace goose; using namespace goose::eir; using namespace goose::parse; using namespace goose::builtins; namespace |
| ︙ | ︙ |
Changes to bs/builtins/types/reference/typecheck.cpp.
| ︙ | ︙ | |||
27 28 29 30 31 32 33 |
// TypeCheck the param with the ref's content
co_yield TypeCheck( lhs, content, tcc );
}
TCGen TypeCheckingBuildTempRef( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc )
{
| < < < < < < | 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
// TypeCheck the param with the ref's content
co_yield TypeCheck( lhs, content, tcc );
}
TCGen TypeCheckingBuildTempRef( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc )
{
auto lRefType = *FromValue< ReferenceType >( *EIRToValue( ValuePatternFromEIR( lhs )->type() ) );
if( lRefType.behavior() == MutAccessLevel() )
co_return;
auto lhsPat = ValueToEIR( ValuePattern( TSID( param ), lRefType.type(), HOLE( "_"_sid ) ) );
|
| ︙ | ︙ | |||
60 61 62 63 64 65 66 |
auto&& [arg, rhs] = *result;
auto val = *EIRToValue( arg );
ReferenceType rt( val.type(), TempAccessLevel() );
auto rhsVal = *EIRToValue( rhs );
| > > > > > | | 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
auto&& [arg, rhs] = *result;
auto val = *EIRToValue( arg );
ReferenceType rt( val.type(), TempAccessLevel() );
auto rhsVal = *EIRToValue( rhs );
auto cfg = GetCFG( tcc.context() );
if( !cfg )
return nullopt;
// TODO create an ext point for this
auto tempIndex = cfg->getNewTemporaryIndex();
return ValueToEIR( BuildComputedValue( ValueToEIR( ToValue( rt ) ), TempAddr( tempIndex, rhsVal ) )
.setLocationId( rhsVal.locationId() ) );
} );
// Override the weight because we don't want
// this solution to count more than directly using
// the value without wrapping it into a tempref
|
| ︙ | ︙ |
Changes to bs/builtins/types/runtime/array.cpp.
1 | #include "builtins/builtins.h" | < | 1 2 3 4 5 6 7 8 |
#include "builtins/builtins.h"
using namespace goose;
using namespace goose::builtins;
namespace goose::builtins
{
void SetupRuntimeArrayType( Env& e )
|
| ︙ | ︙ |
Changes to bs/builtins/types/runtime/basic.cpp.
1 2 | #include "builtins/builtins.h" #include "codegen/codegen.h" | < | 1 2 3 4 5 6 7 8 9 |
#include "builtins/builtins.h"
#include "codegen/codegen.h"
using namespace goose;
using namespace goose::builtins;
using namespace goose::codegen;
namespace goose::builtins
{
|
| ︙ | ︙ |
Changes to bs/builtins/types/runtime/pointer.cpp.
1 | #include "builtins/builtins.h" | < | 1 2 3 4 5 6 7 8 |
#include "builtins/builtins.h"
using namespace goose;
using namespace goose::builtins;
namespace goose::builtins
{
void SetupRuntimePointerType( Env& e )
|
| ︙ | ︙ |
Changes to bs/builtins/types/runtime/record.cpp.
1 2 | #include "builtins/builtins.h" #include "codegen/codegen.h" | < | 1 2 3 4 5 6 7 8 9 |
#include "builtins/builtins.h"
#include "codegen/codegen.h"
using namespace goose;
using namespace goose::builtins;
using namespace goose::codegen;
namespace goose::builtins
{
|
| ︙ | ︙ |
Changes to bs/builtins/types/runtime/typecheck.cpp.
1 | #include "builtins/builtins.h" | < | 1 2 3 4 5 6 7 8 |
#include "builtins/builtins.h"
using namespace goose;
using namespace goose::eir;
namespace goose::builtins
{
void SetupRuntimeTypesChecking( Env& e )
|
| ︙ | ︙ |
Changes to bs/builtins/types/template/pretty.cpp.
1 | #include "builtins/builtins.h" | < | 1 2 3 4 5 6 7 8 |
#include "builtins/builtins.h"
using namespace goose;
using namespace goose::sema;
using namespace goose::builtins;
namespace goose::builtins
{
|
| ︙ | ︙ |
Changes to bs/builtins/types/tuple/typecheck.cpp.
| ︙ | ︙ | |||
96 97 98 99 100 101 102 |
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
{
auto ltup = ValuePatternFromEIR( lhs );
auto rtup = EIRToValue( rhs );
| | > > > > > | | 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
{
auto ltup = ValuePatternFromEIR( lhs );
auto rtup = EIRToValue( rhs );
if( !ltup || !rtup )
co_return;
auto cfg = GetCFG( tcc.context() );
if( !cfg )
co_return;
auto tupType = *EIRToValue( ltup->type() );
assert( TupleTypeSize( tupType ) == TupleTypeSize( *EIRToValue( rtup->type() ) ) );
// TODO create an ext point for this instead of going directly thru cfg
auto tempIndex = cfg->getNewTemporaryIndex();
auto rtupref = BuildComputedValue( ValueToEIR( ToValue( ReferenceType{ rtup->type(), ConstAccessLevel() } ) ),
cir::TempAddr( tempIndex, *rtup ) );
co_yield TypeCheckComputedTuple( tcc, tupType, *rtup, rtupref, 0, EmptyTuple() );
} );
|
| ︙ | ︙ |
Changes to bs/builtins/types/types.cpp.
| ︙ | ︙ | |||
83 84 85 86 87 88 89 |
auto result = InvokeOverloadSet( c,
c.env()->extIsType(),
MakeTuple( v ) );
if( result.isPoison() )
{
| | < | < | < | < | 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
auto result = InvokeOverloadSet( c,
c.env()->extIsType(),
MakeTuple( v ) );
if( result.isPoison() )
{
PoisonBuilder( c );
return false;
}
auto boolRes = FromValue< bool >( result );
if( !boolRes )
{
DiagnosticsManager::GetInstance().emitErrorMessage( v.locationId(),
"the IsType extension point returned a non boolean value." );
PoisonBuilder( c );
return false;
}
return *boolRes;
}
Value ToType( const Context& c, const Value& v )
{
auto result = InvokeOverloadSet( c,
c.env()->extToType(),
MakeTuple( v ) );
if( result.isPoison() )
{
PoisonBuilder( c );
return PoisonType();
}
if( !result.isType() )
{
DiagnosticsManager::GetInstance().emitErrorMessage( v.locationId(),
"the ToType extension point returned a non type value." );
PoisonBuilder( c );
return PoisonType();
}
return result;
}
}
|
Changes to bs/builtins/types/wrapper.h.
| ︙ | ︙ | |||
174 175 176 177 178 179 180 181 182 183 184 185 186 187 |
};
template<>
struct TypeWrapperTraits< ptr< sema::Context > >
{
static auto typeId() { return "Context"_sid; }
};
template<>
struct TypeWrapperTraits< ptr< CodeBuilder > >
{
static auto typeId() { return "CodeBuilder"_sid; }
};
| > > > > > > | 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 |
};
template<>
struct TypeWrapperTraits< ptr< sema::Context > >
{
static auto typeId() { return "Context"_sid; }
};
template<>
struct TypeWrapperTraits< ptr< cir::CFG > >
{
static auto typeId() { return "CFG"_sid; }
};
template<>
struct TypeWrapperTraits< ptr< CodeBuilder > >
{
static auto typeId() { return "CodeBuilder"_sid; }
};
|
| ︙ | ︙ |
Changes to bs/cir/call.cpp.
| ︙ | ︙ | |||
39 40 41 42 43 44 45 |
// executing it in the first place in most cases.
return !pFunc || pFunc->canBeExecuted();
}
bool Call::canBeEagerlyEvaluated() const
{
// Functions with void return type are assumed to have side effects
| | > | | 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
// executing it in the first place in most cases.
return !pFunc || pFunc->canBeExecuted();
}
bool Call::canBeEagerlyEvaluated() const
{
// Functions with void return type are assumed to have side effects
// and therefore that they should never be eagerly evaluated,
// It's not like they would need to be anyway.
// An exception is builtin functions that have been explicitely marked to be eagerly evaluated.
if( GetFuncRType( m_func ) == GetValueType< void >() )
return IsEagerBuiltinFunc( m_func );
if( IsNonEagerBuiltinFunc( m_func ) )
return false;
if( IsExternalFunc( m_func ) )
return false;
|
| ︙ | ︙ |
Changes to bs/cir/cfg.h.
| ︙ | ︙ | |||
20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
const auto& currentBB() const { return m_currentBB; }
template< typename T >
void setCurrentBB( T&& pBB )
{
m_currentBB = forward< T >( pBB );
}
void addEdge( uint32_t srcIndex, uint32_t destIndex );
const auto& edges() const { return m_edges; }
template< typename V >
void setIdoms( V&& idoms )
{
| > > > > > > > > > > > > > | 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
const auto& currentBB() const { return m_currentBB; }
template< typename T >
void setCurrentBB( T&& pBB )
{
m_currentBB = forward< T >( pBB );
}
template< typename T >
void emitTerminator( eir::LocationId locId, T&& terminator )
{
if( !currentBB() || currentBB()->terminator() )
{
DiagnosticsManager::GetInstance().emitSyntaxErrorMessage(
locId, "unreachable code.", 0 );
return;
}
currentBB()->setTerminator( forward< T >( terminator ) );
}
void addEdge( uint32_t srcIndex, uint32_t destIndex );
const auto& edges() const { return m_edges; }
template< typename V >
void setIdoms( V&& idoms )
{
|
| ︙ | ︙ |
Changes to bs/cir/cir.h.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
#ifndef GOOSE_CIR_H
#define GOOSE_CIR_H
#include "util/util.h"
#include "eir/eir.h"
namespace goose::cir
{
using namespace util;
static constexpr uint32_t InvalidVarId = numeric_limits< uint32_t >::max();
class CFG;
}
#include "helpers.h"
| > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
#ifndef GOOSE_CIR_H
#define GOOSE_CIR_H
#include "util/util.h"
#include "eir/eir.h"
#include "diagnostics/diagnostics.h"
namespace goose::cir
{
using namespace util;
using namespace diagnostics;
static constexpr uint32_t InvalidVarId = numeric_limits< uint32_t >::max();
class CFG;
}
#include "helpers.h"
|
| ︙ | ︙ |
Changes to bs/compile/compiler.cpp.
1 2 | #include "compiler.h" #include "builtins/builtins.h" | < | 1 2 3 4 5 6 7 8 9 | #include "compiler.h" #include "builtins/builtins.h" #include "g0api/g0api.h" #include "sema/sema.h" #include "verify/verify.h" #include "execute/execute.h" #include "diagnostics/diagnostics.h" #include "llvm/InitializePasses.h" |
| ︙ | ︙ | |||
124 125 126 127 128 129 130 |
VerbosityContext vc( Verbosity::Normal, true );
auto cfg = make_shared< cir::CFG >( 0 );
cfg->createBB();
cfg->setCurrentBB( cfg->entryBB() );
auto cb = make_shared< CodeBuilder >( cfg );
| | | 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
VerbosityContext vc( Verbosity::Normal, true );
auto cfg = make_shared< cir::CFG >( 0 );
cfg->createBB();
cfg->setCurrentBB( cfg->entryBB() );
auto cb = make_shared< CodeBuilder >( cfg );
c.setBuilder( ToValue( TypeWrapper< ptr< CodeBuilder > >( cb ) ) );
auto r = make_shared< parse::Resolver >(
make_shared< lex::Lexer >( sourcefile, filename ), c );
parse::Parser p( r );
p.parseSequence();
|
| ︙ | ︙ | |||
147 148 149 150 151 152 153 |
if( cfg->currentBB() && !cfg->currentBB()->terminator() )
{
p.flushValue();
cb->destroyAllLiveValues( c );
if( returnType == GetValueType< void >() )
| | | 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
if( cfg->currentBB() && !cfg->currentBB()->terminator() )
{
p.flushValue();
cb->destroyAllLiveValues( c );
if( returnType == GetValueType< void >() )
cfg->emitTerminator( r->currentLocation(), cir::Ret() );
else if( !defRetVal )
{
dm.emitSyntaxErrorMessage( r->currentLocation(), "missing return statement." );
return nullptr;
}
else
{
|
| ︙ | ︙ | |||
172 173 174 175 176 177 178 |
dm.emitErrorMessage( defRetVal->locationId(), "ambiguous default return value conversion." );
break;
}
return nullptr;
}
| | | 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 |
dm.emitErrorMessage( defRetVal->locationId(), "ambiguous default return value conversion." );
break;
}
return nullptr;
}
cfg->emitTerminator( r->currentLocation(), cir::Ret( get< Value >( converted ) ) );
}
}
verify::Func fv( c, cfg, returnType );
if( !fv.verify() )
return nullptr;
return cfg;
}
}
|
Changes to bs/execute/termaddr.cpp.
1 2 | #include "execute.h" #include "builtins/builtins.h" | < | 1 2 3 4 5 6 7 8 9 |
#include "execute.h"
#include "builtins/builtins.h"
using namespace goose;
using namespace goose::execute;
using namespace goose::builtins;
const Term& Bridge< eir::Term* >::Type()
{
|
| ︙ | ︙ |
Changes to bs/execute/vm.cpp.
1 2 3 4 5 6 7 | #include "execute.h" #include "builtins/builtins.h" using namespace goose; using namespace goose::execute; using namespace goose::builtins; | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#include "execute.h"
#include "builtins/builtins.h"
using namespace goose;
using namespace goose::execute;
using namespace goose::builtins;
uint32_t VM::ms_remainingBranchInstExecutions = 1 << 24;
optional< Value > VM::execute( CFG& cfg )
{
return execute( cfg.entryBB() );
}
optional< Value > VM::execute( ptr< BasicBlock > bb )
|
| ︙ | ︙ | |||
42 43 44 45 46 47 48 |
}
optional< Value > VM::execute( const cir::Call& call )
{
if( !( ms_remainingBranchInstExecutions ) )
{
DiagnosticsManager::GetInstance().emitErrorMessage( 0,
| | | | | 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
}
optional< Value > VM::execute( const cir::Call& call )
{
if( !( ms_remainingBranchInstExecutions ) )
{
DiagnosticsManager::GetInstance().emitErrorMessage( 0,
"execute: compilation time execution budget exceeded." );
return PoisonValue();
}
--ms_remainingBranchInstExecutions;
if( call.func().isPoison() )
DiagnosticsManager::GetInstance().setCurrentVerbosityLevel( Verbosity::Silent );
auto func = Evaluate( call.func(), *this );
if( func.isPoison() )
return PoisonValue();
if( !func.isConstant() )
{
DiagnosticsManager::GetInstance().emitErrorMessage( 0,
"execute: function evaluation failed." );
return PoisonValue();
}
if( IsExternalFunc( func ) )
{
DiagnosticsManager::GetInstance().emitErrorMessage( 0,
"execute: can't call external functions." );
return PoisonValue();
}
bool poisoned = false;
const auto& vec = *get< pvec >( call.args() );
if( IsBuiltinFunc( func ) )
|
| ︙ | ︙ | |||
318 319 320 321 322 323 324 |
}
ptr< BasicBlock > VM::executeTerminator( const cir::Branch& b )
{
if( !( ms_remainingBranchInstExecutions ) )
{
DiagnosticsManager::GetInstance().emitErrorMessage( 0,
| | | | | 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 |
}
ptr< BasicBlock > VM::executeTerminator( const cir::Branch& b )
{
if( !( ms_remainingBranchInstExecutions ) )
{
DiagnosticsManager::GetInstance().emitErrorMessage( 0,
"execute: compilation time execution budget exceeded." );
m_retVal = PoisonValue();
return nullptr;
}
--ms_remainingBranchInstExecutions;
return b.dest().lock();
}
ptr< BasicBlock > VM::executeTerminator( const cir::CondBranch& cb )
{
if( !( ms_remainingBranchInstExecutions ) )
{
DiagnosticsManager::GetInstance().emitErrorMessage( 0,
"execute: compilation time execution budget exceeded." );
m_retVal = PoisonValue();
return nullptr;
}
--ms_remainingBranchInstExecutions;
auto cond = Evaluate( cb.cond(), *this );
if( cond.isPoison() )
return nullptr;
if( !cond.isConstant() )
{
DiagnosticsManager::GetInstance().emitErrorMessage( cb.cond().locationId(),
"execute: branch condition evaluation failed." );
m_retVal = PoisonValue();
return nullptr;
}
if( *FromValue< bool >( cond ) )
return cb.trueDest().lock();
|
| ︙ | ︙ |
Changes to bs/g0api/compiler.cpp.
1 2 3 4 5 | #include "g0api/g0api.h" #include "parse/parse.h" #include "verify/verify.h" #include "execute/execute.h" #include "compile/compiler.h" | < | 1 2 3 4 5 6 7 8 9 10 11 12 |
#include "g0api/g0api.h"
#include "parse/parse.h"
#include "verify/verify.h"
#include "execute/execute.h"
#include "compile/compiler.h"
using namespace goose;
using namespace goose::compile;
namespace goose::g0api
{
void SetupApiCompiler( Env& e )
|
| ︙ | ︙ |
Changes to bs/g0api/extensibility/cir.cpp.
1 2 3 | #include "g0api/g0api.h" #include "eir/eir.h" #include "parse/parse.h" | < | 1 2 3 4 5 6 7 8 9 10 |
#include "g0api/g0api.h"
#include "eir/eir.h"
#include "parse/parse.h"
using namespace goose;
using namespace goose::parse;
using namespace goose::g0api;
namespace
{
|
| ︙ | ︙ |
Changes to bs/g0api/extensibility/diagnostics.cpp.
1 2 3 | #include "g0api/g0api.h" #include "eir/eir.h" #include "parse/parse.h" | < | 1 2 3 4 5 6 7 8 9 10 |
#include "g0api/g0api.h"
#include "eir/eir.h"
#include "parse/parse.h"
using namespace goose;
using namespace goose::parse;
using namespace goose::g0api;
namespace goose::g0api
{
|
| ︙ | ︙ |
Changes to bs/g0api/extensibility/eir.cpp.
1 2 3 | #include "g0api/g0api.h" #include "eir/eir.h" #include "parse/parse.h" | < | 1 2 3 4 5 6 7 8 9 10 |
#include "g0api/g0api.h"
#include "eir/eir.h"
#include "parse/parse.h"
using namespace goose;
using namespace goose::parse;
using namespace goose::g0api;
namespace
{
|
| ︙ | ︙ |
Changes to bs/g0api/extensibility/env.cpp.
1 2 3 | #include "g0api/g0api.h" #include "eir/eir.h" #include "parse/parse.h" | < | 1 2 3 4 5 6 7 8 9 10 |
#include "g0api/g0api.h"
#include "eir/eir.h"
#include "parse/parse.h"
using namespace goose;
using namespace goose::parse;
using namespace goose::g0api;
namespace goose::g0api
{
|
| ︙ | ︙ |
Changes to bs/g0api/extensibility/value.cpp.
1 2 3 | #include "g0api/g0api.h" #include "eir/eir.h" #include "parse/parse.h" | < | 1 2 3 4 5 6 7 8 9 10 |
#include "g0api/g0api.h"
#include "eir/eir.h"
#include "parse/parse.h"
using namespace goose;
using namespace goose::parse;
using namespace goose::g0api;
namespace goose::g0api
{
|
| ︙ | ︙ |
Changes to bs/g0api/types.cpp.
1 2 | #include "g0api/g0api.h" #include "eir/eir.h" | < | 1 2 3 4 5 6 7 8 9 |
#include "g0api/g0api.h"
#include "eir/eir.h"
using namespace goose;
using namespace goose::g0api;
namespace
{
template< typename T >
|
| ︙ | ︙ | |||
84 85 86 87 88 89 90 |
SetupWrapperForType< ptr< Terminator > >( e, "Terminator"_sid, pEquals, pNotEquals );
////////////////////////////
// Context
////////////////////////////
SetupWrapperForType< ptr< Context > >( e, "Context"_sid, pEquals, pNotEquals );
| | | | < < < < < < < < < < < < < < < < < < | < < < < | | 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
SetupWrapperForType< ptr< Terminator > >( e, "Terminator"_sid, pEquals, pNotEquals );
////////////////////////////
// Context
////////////////////////////
SetupWrapperForType< ptr< Context > >( e, "Context"_sid, pEquals, pNotEquals );
RegisterBuiltinFunc< bool ( TypeWrapper< ptr< Context > >, TermRef< TypeWrapper< ptr< CFG > > > ) >( e, "ContextGetCFG"_sid,
[]( const TypeWrapper< ptr< Context > >& c, TermRef< TypeWrapper< ptr< CFG > > >& out )
{
auto cfg = GetCFG( *c.get() );
if( !cfg )
return false;
out = cfg;
return true;
} );
////////////////////////////
// ReferenceType
////////////////////////////
SetupWrapperForType< ptr< ReferenceType > >( e, "RefTypeDesc"_sid, pEquals, pNotEquals );
|
| ︙ | ︙ |
Changes to bs/g0api/types.h.
| ︙ | ︙ | |||
58 59 60 61 62 63 64 |
template<>
struct TypeWrapperTraits< ptr< TypePredicates > >
{
static auto typeId() { return "TypePredicates"_sid; }
};
| < < < < < < | 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
template<>
struct TypeWrapperTraits< ptr< TypePredicates > >
{
static auto typeId() { return "TypePredicates"_sid; }
};
template<>
struct TypeWrapperTraits< ptr< cir::BasicBlock > >
{
static auto typeId() { return "BasicBlock"_sid; }
};
template<>
|
| ︙ | ︙ |
Changes to bs/parse/blocks.cpp.
| ︙ | ︙ | |||
230 231 232 233 234 235 236 |
{
// Create a nested verbosity context to restrict the scope of
// error silencing caused by syntax errors to the block.
VerbosityContext vc( Verbosity::Normal );
m_resolver->consume();
| < | < | < | | 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 |
{
// Create a nested verbosity context to restrict the scope of
// error silencing caused by syntax errors to the block.
VerbosityContext vc( Verbosity::Normal );
m_resolver->consume();
LifetimeScopeGuard lsg( context() );
auto p = makeNestedParser( Delimiter::OpenBrace );
p.parseSequence();
auto next = m_resolver->consumeUnresolved();
if( !next )
{
DiagnosticsManager::GetInstance().emitSyntaxErrorMessage(
resolver()->currentLocation(), "'}' expected.", 0 );
PoisonBuilder( context() );
return true;
}
auto decomp = Decompose( next->first, Val< Delimiter >() );
if( !decomp || *decomp != Delimiter::CloseBrace )
{
DiagnosticsManager::GetInstance().emitSyntaxErrorMessage(
next->second, "'}' expected.", 0 );
PoisonBuilder( context() );
return true;
}
return true;
}
bool Parser::parseNestedBraceBlock()
|
| ︙ | ︙ |
Changes to bs/parse/parser.cpp.
| ︙ | ︙ | |||
20 21 22 23 24 25 26 |
// Parse a sequence of expression. Each expression is
// a statement.
void Parser::parseSequence()
{
for(;;)
{
| | | 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
// Parse a sequence of expression. Each expression is
// a statement.
void Parser::parseSequence()
{
for(;;)
{
LifetimeScopeGuard lsg( context() );
{
// Each statement gets its own visibility scope,
// so that vars defined inside of the statement are only
// visible from within it.
// However, they also have a lifetime scope, which
// is separate because we need to flush the value
|
| ︙ | ︙ | |||
74 75 76 77 78 79 80 |
if( !parseInfix( next->first, *prec ) )
break;
}
}
void Parser::flushValue()
{
| | | | 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
if( !parseInfix( next->first, *prec ) )
break;
}
}
void Parser::flushValue()
{
auto cfg = GetCFG( context() );
if( m_lastValue && cfg && ( !cfg->currentBB() || cfg->currentBB()->terminator() ) )
{
DiagnosticsManager::GetInstance().emitSyntaxErrorMessage(
m_lastValue->locationId(), "unreachable code.", 0 );
}
// Flush the pending value, by invoking the DropValue
// extension point, where an overload will decide
|
| ︙ | ︙ |
Changes to bs/parse/parser.inl.
1 2 3 4 5 6 7 8 9 10 11 |
#ifndef GOOSE_PARSE_PARSER_INL
#define GOOSE_PARSE_PARSER_INL
namespace goose::parse
{
template< typename V >
void Parser::pushValue( V&& val )
{
if( val.isPoison() )
{
DiagnosticsManager::GetInstance().setCurrentVerbosityLevel( Verbosity::Silent );
| | < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
#ifndef GOOSE_PARSE_PARSER_INL
#define GOOSE_PARSE_PARSER_INL
namespace goose::parse
{
template< typename V >
void Parser::pushValue( V&& val )
{
if( val.isPoison() )
{
DiagnosticsManager::GetInstance().setCurrentVerbosityLevel( Verbosity::Silent );
builtins::PoisonBuilder( context() );
}
flushValue();
if( val.isConstant() || !cir::CanValueBeEagerlyEvaluated( val ) )
{
m_lastValue = forward< V >( val );
|
| ︙ | ︙ |
Changes to bs/parse/scope.cpp.
1 2 3 4 5 6 7 8 9 10 11 12 |
#include "parse.h"
using namespace goose;
using namespace goose::parse;
using namespace goose::builtins;
VisibilityScope::VisibilityScope( Parser& p ) :
m_identityGuard( p )
{
auto parentBaseIdentity = p.context().identity();
parentBaseIdentity = TakeVectorTerm( parentBaseIdentity, VecSize( parentBaseIdentity ) - 1 );
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
#include "parse.h"
using namespace goose;
using namespace goose::parse;
using namespace goose::builtins;
LifetimeScopeGuard::LifetimeScopeGuard( const sema::Context& c ) :
m_context( c )
{
PushLifetimeScope( m_context );
}
LifetimeScopeGuard::~LifetimeScopeGuard()
{
PopLifetimeScope( m_context );
}
BreakableScopeGuard::BreakableScopeGuard( const sema::Context& c ) :
m_context( c )
{
PushBreakableScope( m_context );
}
BreakableScopeGuard::~BreakableScopeGuard()
{
PopBreakableScope( m_context );
}
ContinuableScopeGuard::ContinuableScopeGuard( const sema::Context& c ) :
m_context( c )
{
PushContinuableScope( m_context );
}
ContinuableScopeGuard::~ContinuableScopeGuard()
{
PopContinuableScope( m_context );
}
VisibilityScope::VisibilityScope( Parser& p ) :
m_identityGuard( p )
{
auto parentBaseIdentity = p.context().identity();
parentBaseIdentity = TakeVectorTerm( parentBaseIdentity, VecSize( parentBaseIdentity ) - 1 );
|
| ︙ | ︙ |
Changes to bs/parse/scope.h.
1 2 3 4 5 6 7 8 9 10 11 12 |
#ifndef GOOSE_PARSE_SCOPE_H
#define GOOSE_PARSE_SCOPE_H
namespace goose::parse
{
// Helper object that creates a nested visibility scope.
class VisibilityScope
{
public:
VisibilityScope( Parser& p );
private:
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
#ifndef GOOSE_PARSE_SCOPE_H
#define GOOSE_PARSE_SCOPE_H
namespace goose::parse
{
class LifetimeScopeGuard
{
public:
LifetimeScopeGuard( const sema::Context& c );
~LifetimeScopeGuard();
private:
const sema::Context& m_context;
};
class BreakableScopeGuard
{
public:
BreakableScopeGuard( const sema::Context& c );
~BreakableScopeGuard();
private:
const sema::Context& m_context;
};
class ContinuableScopeGuard
{
public:
ContinuableScopeGuard( const sema::Context& c );
~ContinuableScopeGuard();
private:
const sema::Context& m_context;
};
// Helper object that creates a nested visibility scope.
class VisibilityScope
{
public:
VisibilityScope( Parser& p );
private:
|
| ︙ | ︙ | |||
20 21 22 23 24 25 26 |
public:
Scope( Parser& p ) :
VisibilityScope( p ),
m_lifeTimeScopeGuard( p.context() )
{}
private:
| | | 50 51 52 53 54 55 56 57 58 59 60 61 |
public:
Scope( Parser& p ) :
VisibilityScope( p ),
m_lifeTimeScopeGuard( p.context() )
{}
private:
LifetimeScopeGuard m_lifeTimeScopeGuard;
};
}
#endif
|
Changes to bs/sema/context.h.
1 2 3 4 5 6 |
#ifndef GOOSE_SEMA_CONTEXT_H
#define GOOSE_SEMA_CONTEXT_H
namespace goose::sema
{
class Env;
| < | | > > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
#ifndef GOOSE_SEMA_CONTEXT_H
#define GOOSE_SEMA_CONTEXT_H
namespace goose::sema
{
class Env;
class Context
{
public:
template< typename E, typename I >
Context( E&& pEnv, I&& identity ) :
m_pEnv( forward< E >( pEnv ) ),
m_identity( forward< I >( identity ) )
{}
template< typename E, typename I, typename R >
Context( E&& pEnv, I&& identity, R&& returnType ) :
m_pEnv( forward< E >( pEnv ) ),
m_identity( forward< I >( identity ) ),
m_returnType( forward< R >( returnType ) )
{}
template< typename B >
void setBuilder( B&& b )
{
m_builder = forward< B >( b );
}
const auto& env() const { return m_pEnv; }
const auto& identity() const { return m_identity; }
const auto& returnType() const { return m_returnType; }
const auto& builder() const { return m_builder; }
template< typename T >
T builder() const { return FromValue< T >( m_builder ); }
void setEnv( const ptr< Env >& pEnv )
{
m_pEnv = pEnv;
}
void setIdentity( const Term& identity )
{
m_identity = identity;
}
private:
ptr< Env > m_pEnv;
Term m_identity;
optional< Term > m_returnType;
Value m_builder;
};
}
#endif
|
Changes to bs/sema/env.h.
| ︙ | ︙ | |||
75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
auto& extConvertFuncParam() { return m_extConvertFuncParam; }
const auto& extConvertFuncParam() const { return m_extConvertFuncParam; }
auto& extConvertFuncArg() { return m_extConvertFuncArg; }
const auto& extConvertFuncArg() const { return m_extConvertFuncArg; }
template< typename... T >
auto createCIRFunc( T&&... args )
{
ms_cirFuncs.emplace_back( make_shared< cir::Func >( forward< T >( args )... ) );
return ms_cirFuncs.back();
}
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
auto& extConvertFuncParam() { return m_extConvertFuncParam; }
const auto& extConvertFuncParam() const { return m_extConvertFuncParam; }
auto& extConvertFuncArg() { return m_extConvertFuncArg; }
const auto& extConvertFuncArg() const { return m_extConvertFuncArg; }
auto& extPoisonBuilder() { return m_extPoisonBuilder; }
const auto& extPoisonBuilder() const { return m_extPoisonBuilder; }
auto& extBuilderAllowsVarDecl() { return m_extBuilderAllowsVarDecl; }
const auto& extBuilderAllowsVarDecl() const { return m_extBuilderAllowsVarDecl; }
auto& extGetCFG() { return m_extGetCFG; }
const auto& extGetCFG() const { return m_extGetCFG; }
auto& extGetBreakableScopeLevels() { return m_extGetBreakableScopeLevels; }
const auto& extGetBreakableScopeLevels() const { return m_extGetBreakableScopeLevels; }
auto& extGetContinuableScopeLevels() { return m_extGetContinuableScopeLevels; }
const auto& extGetContinuableScopeLevels() const { return m_extGetContinuableScopeLevels; }
auto& extPushLifetimeScope() { return m_extPushLifetimeScope; }
const auto& extPushLifetimeScope() const { return m_extPushLifetimeScope; }
auto& extPopLifetimeScope() { return m_extPopLifetimeScope; }
const auto& extPopLifetimeScope() const { return m_extPopLifetimeScope; }
auto& extPushBreakableScope() { return m_extPushBreakableScope; }
const auto& extPushBreakableScope() const { return m_extPushBreakableScope; }
auto& extPopBreakableScope() { return m_extPopBreakableScope; }
const auto& extPopBreakableScope() const { return m_extPopBreakableScope; }
auto& extPushContinuableScope() { return m_extPushContinuableScope; }
const auto& extPushContinuableScope() const { return m_extPushContinuableScope; }
auto& extPopContinuableScope() { return m_extPopContinuableScope; }
const auto& extPopContinuableScope() const { return m_extPopContinuableScope; }
auto& extPushLiveValue() { return m_extPushLiveValue; }
const auto& extPushLiveValue() const { return m_extPushLiveValue; }
auto& extExtendValueLifetime() { return m_extExtendValueLifetime; }
const auto& extExtendValueLifetime() const { return m_extExtendValueLifetime; }
auto& extDestroyAndPopCurrentLifetimeScopeValues() { return m_extDestroyAndPopCurrentLifetimeScopeValues; }
const auto& extDestroyAndPopCurrentLifetimeScopeValues() const { return m_extDestroyAndPopCurrentLifetimeScopeValues; }
auto& extDestroyAllLiveValues() { return m_extDestroyAllLiveValues; }
const auto& extDestroyAllLiveValues() const { return m_extDestroyAllLiveValues; }
auto& extDestroyAllLiveValuesFromBreakScope() { return m_extDestroyAllLiveValuesFromBreakScope; }
const auto& extDestroyAllLiveValuesFromBreakScope() const { return m_extDestroyAllLiveValuesFromBreakScope; }
auto& extDestroyAllLiveValuesFromContinueScope() { return m_extDestroyAllLiveValuesFromContinueScope; }
const auto& extDestroyAllLiveValuesFromContinueScope() const { return m_extDestroyAllLiveValuesFromContinueScope; }
template< typename... T >
auto createCIRFunc( T&&... args )
{
ms_cirFuncs.emplace_back( make_shared< cir::Func >( forward< T >( args )... ) );
return ms_cirFuncs.back();
}
|
| ︙ | ︙ | |||
103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
ptr< OverloadSet > m_extLowerConstantForRuntime;
ptr< OverloadSet > m_extLowerTypeForVerification;
ptr< OverloadSet > m_extLowerConstantForVerification;
ptr< OverloadSet > m_extConvertFuncParam;
ptr< OverloadSet > m_extConvertFuncArg;
uint64_t m_valueStoreVersion = 0;
ptr< CTMemoryManager > m_memManager;
// CIR funcs form a cyclic graph, since functions can
// be recursive or mutually recursive.
// Since they end up being stored in cir::Call in the form of values,
| > > > > > > > > > > > > > > > > > > > > > > > | 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 |
ptr< OverloadSet > m_extLowerConstantForRuntime;
ptr< OverloadSet > m_extLowerTypeForVerification;
ptr< OverloadSet > m_extLowerConstantForVerification;
ptr< OverloadSet > m_extConvertFuncParam;
ptr< OverloadSet > m_extConvertFuncArg;
ptr< OverloadSet > m_extPoisonBuilder;
ptr< OverloadSet > m_extBuilderAllowsVarDecl;
ptr< OverloadSet > m_extGetCFG;
ptr< OverloadSet > m_extGetBreakableScopeLevels;
ptr< OverloadSet > m_extGetContinuableScopeLevels;
ptr< OverloadSet > m_extPushLifetimeScope;
ptr< OverloadSet > m_extPopLifetimeScope;
ptr< OverloadSet > m_extPushBreakableScope;
ptr< OverloadSet > m_extPopBreakableScope;
ptr< OverloadSet > m_extPushContinuableScope;
ptr< OverloadSet > m_extPopContinuableScope;
ptr< OverloadSet > m_extPushLiveValue;
ptr< OverloadSet > m_extExtendValueLifetime;
ptr< OverloadSet > m_extDestroyAndPopCurrentLifetimeScopeValues;
ptr< OverloadSet > m_extDestroyAllLiveValues;
ptr< OverloadSet > m_extDestroyAllLiveValuesFromBreakScope;
ptr< OverloadSet > m_extDestroyAllLiveValuesFromContinueScope;
uint64_t m_valueStoreVersion = 0;
ptr< CTMemoryManager > m_memManager;
// CIR funcs form a cyclic graph, since functions can
// be recursive or mutually recursive.
// Since they end up being stored in cir::Call in the form of values,
|
| ︙ | ︙ |
Changes to bs/sema/meson.build.
| ︙ | ︙ | |||
16 17 18 19 20 21 22 |
'inv-ruleset.cpp',
'invocation.cpp',
'tpl-ruleset.cpp',
'template.cpp',
'overloadset.cpp',
| < | 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
'inv-ruleset.cpp',
'invocation.cpp',
'tpl-ruleset.cpp',
'template.cpp',
'overloadset.cpp',
'lower.cpp',
include_directories: bsinc,
dependencies: [fmt_dep, tracy_dep]
)
|
| ︙ | ︙ |
Changes to bs/sema/sema.h.
| ︙ | ︙ | |||
40 41 42 43 44 45 46 | #include "inv-ruleset.h" #include "invocation.h" #include "tpl-ruleset.h" #include "template.h" #include "overloadset.h" | < | 40 41 42 43 44 45 46 47 48 49 50 51 | #include "inv-ruleset.h" #include "invocation.h" #include "tpl-ruleset.h" #include "template.h" #include "overloadset.h" #include "tctrie.inl" #include "tctrie-typecheck.inl" #endif |
Changes to bs/verify/helpers.inl.
1 2 3 | #ifndef GOOSE_HELPERS_INL #define GOOSE_HELPERS_INL | < < | 1 2 3 4 5 6 7 8 9 10 |
#ifndef GOOSE_HELPERS_INL
#define GOOSE_HELPERS_INL
namespace goose::verify
{
template< typename F >
void ForEachPredicate( Builder& b, const Term& t, const z3::expr& valExpr, F&& func )
{
auto type = *EIRToValue( t );
|
| ︙ | ︙ |
Changes to lib/prelude/ref_verification.g0.
| ︙ | ︙ | |||
39 40 41 42 43 44 45 |
Value rhsExpr
if p2ok
rhsExpr = BuildConjunction( pred2 )
else
rhsExpr = WrapValue( true )
| < < < < | | 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
Value rhsExpr
if p2ok
rhsExpr = BuildConjunction( pred2 )
else
rhsExpr = WrapValue( true )
CFG cfg
if !ContextGetCFG( c, cfg )
return
BasicBlock bb
if !GetCFGCurrentBasicBlock( cfg, bb )
return
var cond = MkValue( ValueToEIR( WrapValue( bool ) ), MkInstr( InstrOpCodeEq, lhsExpr, rhsExpr ) )
|
| ︙ | ︙ | |||
70 71 72 73 74 75 76 |
void EmitPredicatesCheck( Context c, Value arg, Value refType )
{
TypePredicates pred
if !GetTypePredicates( c, refType, pred )
return
| < < < < | | 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
void EmitPredicatesCheck( Context c, Value arg, Value refType )
{
TypePredicates pred
if !GetTypePredicates( c, refType, pred )
return
CFG cfg
if !ContextGetCFG( c, cfg )
return
BasicBlock bb
if !GetCFGCurrentBasicBlock( cfg, bb )
return
RefTypeDesc rt
|
| ︙ | ︙ |