Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | References refactor: references are now values all the way to the llr, where a new "CalcAddress" instruction represents a conversion from a logical address (location + path) into an actual runtime or compilation time address. This is in preparation to allow references to be stored in variables or passed as parameters. (It just took 4.5 months to finish this... Refactoring just sucks) |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA3-256: |
8ddd71f9b2af916c582a4c15856171c7 |
| User & Date: | achavasse 2020-12-18 01:29:15.640 |
| Original Comment: | References refactor: references are now values all the way to the llr, where a new "CalcAddress" instruction represents a conversion from a logical address (location + path) into an actual runtimle or compilation time address. This is in preparation to allow references to be stored in variables or passed as parameters. (It just took 4.5 months to finish this... Refactoring just sucks) |
Context
|
2020-12-26
| ||
| 14:59 | Build fix check-in: c8058eaaf9 user: achavasse tags: trunk | |
|
2020-12-18
| ||
| 01:29 | References refactor: references are now values all the way to the llr, where a new "CalcAddress" instruction represents a conversion from a logical address (location + path) into an actual runtime or compilation time address. This is in preparation to allow references to be stored in variables or passed as parameters. (It just took 4.5 months to finish this... Refactoring just sucks) check-in: 8ddd71f9b2 user: achavasse tags: trunk | |
|
2020-08-02
| ||
| 19:26 | Execute: use a proper call stack so that we'll be able later on to reference values living on the caller's stack to be able to pass references around at compilation time. check-in: 151e3b4d8c user: achavasse tags: trunk | |
Changes
Changes to bs/builtins/operators/assignment.cpp.
| ︙ | ︙ | |||
27 28 29 30 31 32 33 |
if( !cb )
{
DiagnosticsManager::GetInstance().emitSyntaxErrorMessage( 0, "assignments are not allowed here." );
return PoisonValue();
}
if( auto bb = cb->cfg()->currentBB() )
| | | 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
if( !cb )
{
DiagnosticsManager::GetInstance().emitSyntaxErrorMessage( 0, "assignments are not allowed here." );
return PoisonValue();
}
if( auto bb = cb->cfg()->currentBB() )
bb->emplace_back( Store( lhs, rhs ) );
// Return the ref to support chained assignments, like in c++.
return Value( lhs );
};
BuildParseRule( e, "="_sid,
RightAssInfixOp( "operator_assign"_sid, precedence::AssignmentOp,
|
| ︙ | ︙ |
Changes to bs/builtins/operators/dot.cpp.
| ︙ | ︙ | |||
42 43 44 45 46 47 48 |
return PoisonValue();
}
auto tempIndex = cfg->getNewTemporaryIndex();
auto loc = Location::CreateSpanningLocation( lhs.locationId(), rhs.locationId() );
ReferenceType rt( GetTupleElementType( lhs, index ), TSID( temp ) );
| | < | < | 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
return PoisonValue();
}
auto tempIndex = cfg->getNewTemporaryIndex();
auto loc = Location::CreateSpanningLocation( lhs.locationId(), rhs.locationId() );
ReferenceType rt( GetTupleElementType( lhs, index ), TSID( temp ) );
auto addr = Reference( rt, TemporaryBaseAddr( tempIndex, lhs ) );
addr.appendToPath( index );
return ToValue( addr );
} ),
// dot operator for a non-temporary tuple (contained in a local var):
// returns a mutable reference to the specified member.
ForTypes< CustomPattern< LocalVar, LocalVar::Pattern< TuplePattern > >,
CustomPattern< IntegerType, IntegerType::PatternUnsigned32 > >(
[]( auto&& c, auto&& lhs, auto&& rhs ) -> Value
|
| ︙ | ︙ | |||
77 78 79 80 81 82 83 |
"the index is out of range." );
return PoisonValue();
}
auto loc = Location::CreateSpanningLocation( lhs.locationId(), rhs.locationId() );
ReferenceType rt( GetTupleTypeElement( tupType, index ), TSID( mut ) );
| | < | < | 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
"the index is out of range." );
return PoisonValue();
}
auto loc = Location::CreateSpanningLocation( lhs.locationId(), rhs.locationId() );
ReferenceType rt( GetTupleTypeElement( tupType, index ), TSID( mut ) );
auto addr = Reference( rt, VarBaseAddr( lv.index() ) );
addr.appendToPath( index );
return ToValue( addr );
} )
)
);
}
}
|
Changes to bs/builtins/types/func/build.cpp.
| ︙ | ︙ | |||
18 19 20 21 22 23 24 25 26 |
auto decl = *FromValue< Decl >( param );
tv->append( ParamPat( decl.type() ) );
// Bind a stand-in value with the parameters name to be used inside of verification expressions.
auto paramVerificationIdentity = AppendToVectorTerm( verificationIdentity,
TERM( decl.name() ) );
c.env()->storeValue( paramVerificationIdentity, ANYTERM( _ ),
ValueToIRExpr( BuildComputedValue( decl.type(),
| > > | | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
auto decl = *FromValue< Decl >( param );
tv->append( ParamPat( decl.type() ) );
// Bind a stand-in value with the parameters name to be used inside of verification expressions.
auto paramVerificationIdentity = AppendToVectorTerm( verificationIdentity,
TERM( decl.name() ) );
Reference argRef( ReferenceType{ decl.type(), TSID( const ) }, llr::VarBaseAddr( varId++ ) );
c.env()->storeValue( paramVerificationIdentity, ANYTERM( _ ),
ValueToIRExpr( BuildComputedValue( decl.type(),
llr::Load( ToValue( argRef ), decl.type() ) ) ) );
}
else if( param.isConstant() )
tv->append( ValueToIRExpr( param ) );
return true;
} );
|
| ︙ | ︙ |
Changes to bs/builtins/types/func/compile.cpp.
| ︙ | ︙ | |||
19 20 21 22 23 24 25 |
auto func = FromValue< Func >( f );
assert( func );
if( func->isExternal() )
return f;
if( ParseFuncBody( c, *func ) )
| | | | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
auto func = FromValue< Func >( f );
assert( func );
if( func->isExternal() )
return f;
if( ParseFuncBody( c, *func ) )
return f;
return PoisonValue();
}
bool ParseFuncConstraints( const Context& c, const FuncType& funcType )
{
auto& fvi = *funcType.verifInfos();
if( !fvi.preCondToks() && !fvi.postCondToks() )
|
| ︙ | ︙ |
Changes to bs/builtins/types/init.cpp.
| ︙ | ︙ | |||
28 29 30 31 32 33 34 |
{
auto ref = *FromValue< Reference >( r );
if( !ParseTypePredicates( c, c.identity(), *ValueFromIRExpr( ref.type().type() ) ) )
return PoisonValue();
return BuildComputedValue( GetValueType< void >(),
| | | | | 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 |
{
auto ref = *FromValue< Reference >( r );
if( !ParseTypePredicates( c, c.identity(), *ValueFromIRExpr( ref.type().type() ) ) )
return PoisonValue();
return BuildComputedValue( GetValueType< void >(),
Store( r, initVal ) );
} );
// Default initialization for ct_int vars
RegisterBuiltinFunc< Intrinsic< Value ( CTIntMutRefType ) > >( e, e.extInitialize(),
[]( auto&& c, const Value& r )
{
auto ref = *FromValue< Reference >( r );
if( !ParseTypePredicates( c, c.identity(), *ValueFromIRExpr( ref.type().type() ) ) )
return PoisonValue();
return BuildComputedValue( GetValueType< void >(),
Store( r, ToValue( BigInt() ) ) );
} );
// Default initialization for ct_string vars
RegisterBuiltinFunc< Intrinsic< Value ( CTStringMutRefType ) > >( e, e.extInitialize(),
[]( auto&& c, const Value& r )
{
auto ref = *FromValue< Reference >( r );
if( !ParseTypePredicates( c, c.identity(), *ValueFromIRExpr( ref.type().type() ) ) )
return PoisonValue();
return BuildComputedValue( GetValueType< void >(),
Store( r, ToValue( ""s ) ) );
} );
}
}
|
Changes to bs/builtins/types/localvar/invoke.cpp.
| ︙ | ︙ | |||
8 9 10 11 12 13 14 |
{
public:
bool canBeInvoked( const Context& c, const Value& callee ) const final
{
auto lv = *FromValue< LocalVar >( callee );
auto val = BuildComputedValue( lv.type(),
| | | | 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 |
{
public:
bool canBeInvoked( const Context& c, const Value& callee ) const final
{
auto lv = *FromValue< LocalVar >( callee );
auto val = BuildComputedValue( lv.type(),
llr::Load( ToValue( BuildLocalVarConstRef( lv ) ), lv.type() ) );
return sema::CanBeInvoked( c, val );
}
Value resolveInvocation( const Context& c, uint32_t locationId, const Value& callee, const Term& args ) const final
{
auto lv = *FromValue< LocalVar >( callee );
auto val = BuildComputedValue( lv.type(),
llr::Load( ToValue( BuildLocalVarConstRef( lv ) ), lv.type() ) );
return sema::GetInvocationRule( *c.env(), val )->resolveInvocation( c, locationId, val, args );
}
};
void SetupLocalVarInvocationRule( Env& e )
{
|
| ︙ | ︙ |
Changes to bs/builtins/types/localvar/localvar.cpp.
| ︙ | ︙ | |||
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 |
// it will have a meaningful location for the error message to attach itself on.
uint32_t typeLoc = ValueFromIRExpr( typeTExpr )->locationId();
LocalVar lv( name, type, index );
bb->emplace_back( AllocVar( ValueFromIRExpr( lv.type() )->setLocationId( typeLoc ), index ) );
DiagnosticsContext dc( 0, "When invoking Initialize." );
auto initResult = ResolveInvocation( c, GetInvocationRule( *c.env(), initializerVal ), initializerVal,
MakeTuple( ToValue( lv ), initVal ) );
if( !initResult.isPoison() )
{
DiagnosticsContext dc2( initResult.locationId(), "When invoking DropValue." );
InvokeOverloadSet( c, c.env()->extDropValue(),
MakeTuple( move( initResult ) ) );
}
| > > > > > > > | 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 |
// it will have a meaningful location for the error message to attach itself on.
uint32_t typeLoc = ValueFromIRExpr( typeTExpr )->locationId();
LocalVar lv( name, type, index );
bb->emplace_back( AllocVar( ValueFromIRExpr( lv.type() )->setLocationId( typeLoc ), index ) );
DiagnosticsContext dc( 0, "When invoking Initialize." );
auto initResult = ResolveInvocation( c, GetInvocationRule( *c.env(), initializerVal ), initializerVal,
MakeTuple( ToValue( lv ), initVal ) );
if( !initResult.isConstant() && llr::CanValueBeEagerlyEvaluated( initResult ) )
{
execute::VM vm;
initResult = execute::Evaluate( initResult, vm );
}
if( !initResult.isPoison() )
{
DiagnosticsContext dc2( initResult.locationId(), "When invoking DropValue." );
InvokeOverloadSet( c, c.env()->extDropValue(),
MakeTuple( move( initResult ) ) );
}
|
| ︙ | ︙ |
Changes to bs/builtins/types/localvar/localvar.h.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#ifndef GOOSE_BUILTINS_TYPES_LOCALVAR_H
#define GOOSE_BUILTINS_TYPES_LOCALVAR_H
namespace goose::parse
{
class Parser;
}
namespace goose::builtins
{
extern void SetupLocalVarInvocationRule( Env& e );
extern void SetupLocalVarTypeChecking( Env& e );
extern void SetupLocalVarInitialize( Env& e );
extern void SetupLocalVarDropValue( Env& e );
Value DeclareLocalVar( const Context& c, const Term& type, StringId name, const optional< Value >& initializer );
Value DeclareLocalVarWithTypeInference( Context& c, const Term& typeTExpr, StringId name, const Value& initVal );
| > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
#ifndef GOOSE_BUILTINS_TYPES_LOCALVAR_H
#define GOOSE_BUILTINS_TYPES_LOCALVAR_H
namespace goose::parse
{
class Parser;
}
namespace goose::builtins
{
class LocalVar;
extern void SetupLocalVarInvocationRule( Env& e );
extern void SetupLocalVarTypeChecking( Env& e );
extern void SetupLocalVarInitialize( Env& e );
extern void SetupLocalVarDropValue( Env& e );
Value DeclareLocalVar( const Context& c, const Term& type, StringId name, const optional< Value >& initializer );
Value DeclareLocalVarWithTypeInference( Context& c, const Term& typeTExpr, StringId name, const Value& initVal );
|
| ︙ | ︙ |
Changes to bs/builtins/types/reference/reference.cpp.
| ︙ | ︙ | |||
33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
}
const Term& Reference::PatternAnyMutableOfTypeT::GetPattern()
{
static auto pattern = GetValueType< Reference >( HOLE( "T"_sid ), TSID( mut ) );
return pattern;
}
}
namespace goose::ir
{
const Term& Bridge< ReferenceType >::Type()
{
return TypeType();
| > > > > > > > > > > | 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
}
const Term& Reference::PatternAnyMutableOfTypeT::GetPattern()
{
static auto pattern = GetValueType< Reference >( HOLE( "T"_sid ), TSID( mut ) );
return pattern;
}
Reference BuildLocalVarConstRef( const LocalVar& lv )
{
return { ReferenceType{ lv.type(), TSID( const ) }, llr::VarBaseAddr( lv.index() ) };
}
Reference BuildLocalVarMutRef( const LocalVar& lv )
{
return { ReferenceType{ lv.type(), TSID( mut ) }, llr::VarBaseAddr( lv.index() ) };
}
}
namespace goose::ir
{
const Term& Bridge< ReferenceType >::Type()
{
return TypeType();
|
| ︙ | ︙ | |||
64 65 66 67 68 69 70 |
if( !result )
return nullopt;
auto&& [bhv, type] = *result;
return ReferenceType( move( type ), move( bhv ) );
}
| | | | < | | > > > > | | 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 |
if( !result )
return nullopt;
auto&& [bhv, type] = *result;
return ReferenceType( move( type ), move( bhv ) );
}
Term Bridge< builtins::Reference >::Type( const Term& type, const Term& bhv )
{
return ValueToIRExpr( ::ToValue( ReferenceType( type, bhv ) ) );
}
Value Bridge< builtins::Reference >::ToValue( const builtins::Reference& ref )
{
return BuildComputedValue( ValueToIRExpr( ::ToValue( ref.type() ) ), llr::CalcAddress{ ref.address() } );
}
optional< builtins::Reference > Bridge< builtins::Reference >::FromValue( const Value& v )
{
if( v.isConstant() )
return nullopt;
auto llrRef = get_if< llr::CalcAddress >( &v.llr()->content() );
if( !llrRef )
return nullopt;
auto t = FromValue< ReferenceType >( *ValueFromIRExpr( v.type() ) );
if( !t )
return nullopt;
return builtins::Reference( move( *t ), get< llr::CalcAddress >( v.llr()->content() ) );
}
}
|
Changes to bs/builtins/types/reference/reference.h.
| ︙ | ︙ | |||
36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
Reference( T&& type, A&& addr ) :
m_type( forward< T >( type ) ),
m_addr( forward< A >( addr ) )
{}
const auto& type() const { return m_type; }
const auto& address() const { return m_addr; }
struct PatternAny
{
static const Term& GetPattern();
};
struct PatternAnyMutable
| > > > > > | 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
Reference( T&& type, A&& addr ) :
m_type( forward< T >( type ) ),
m_addr( forward< A >( addr ) )
{}
const auto& type() const { return m_type; }
const auto& address() const { return m_addr; }
void appendToPath( uint32_t index )
{
m_addr.appendToPath( index );
}
struct PatternAny
{
static const Term& GetPattern();
};
struct PatternAnyMutable
|
| ︙ | ︙ | |||
94 95 96 97 98 99 100 |
static auto pattern = GetValueType< Reference >( PP::GetPattern(), TSID( const ) );
return pattern;
}
};
private:
ReferenceType m_type;
| | > > > | 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
static auto pattern = GetValueType< Reference >( PP::GetPattern(), TSID( const ) );
return pattern;
}
};
private:
ReferenceType m_type;
llr::CalcAddress m_addr;
};
extern Reference BuildLocalVarConstRef( const LocalVar& lv );
extern Reference BuildLocalVarMutRef( const LocalVar& lv );
}
namespace goose::ir
{
template<>
struct Bridge< builtins::ReferenceType >
{
|
| ︙ | ︙ |
Changes to bs/builtins/types/reference/typecheck.cpp.
| ︙ | ︙ | |||
16 17 18 19 20 21 22 |
auto refTypePatternConstant = ValueToIRExpr(
Value( GetValueType< ReferenceType >(), TVEC( TSID( reference ), TSID( const ), ANYTERM( _ ) ) ) );
auto refTypePatternMutable = ValueToIRExpr(
Value( GetValueType< ReferenceType >(), TVEC( TSID( reference ), TSID( mut ), ANYTERM( _ ) ) ) );
auto refTypePatternTemporary = ValueToIRExpr(
| | | 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
auto refTypePatternConstant = ValueToIRExpr(
Value( GetValueType< ReferenceType >(), TVEC( TSID( reference ), TSID( const ), ANYTERM( _ ) ) ) );
auto refTypePatternMutable = ValueToIRExpr(
Value( GetValueType< ReferenceType >(), TVEC( TSID( reference ), TSID( mut ), ANYTERM( _ ) ) ) );
auto refTypePatternTemporary = ValueToIRExpr(
Value( GetValueType< ReferenceType >(), TVEC( TSID( reference ), TSID( temp ), ANYTERM( _ ) ) ) );
// Reference type checking rule.
e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,
ParamPat( refTypePattern ),
ValueToIRExpr( ValuePattern(
|
| ︙ | ︙ | |||
100 101 102 103 104 105 106 |
{
auto refval = *ValueFromIRExpr( rhs );
auto ref = FromValue< Reference >( refval );
if( !ref )
co_return;
auto content = ValueToIRExpr( BuildComputedValue( ref->type().type(),
| | | 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
{
auto refval = *ValueFromIRExpr( rhs );
auto ref = FromValue< Reference >( refval );
if( !ref )
co_return;
auto content = ValueToIRExpr( BuildComputedValue( ref->type().type(),
llr::Load( refval, ref->type().type() ) )
.setLocationId( refval.locationId() ) );
// TypeCheck the param with the ref's content
co_yield TypeCheck( lhs, content, tcc );
} );
// LocalVar type checking against a param (implicit referencing):
|
| ︙ | ︙ | |||
131 132 133 134 135 136 137 |
auto ltype = ValuePatternFromIRExpr( lhs )->type();
auto lvval = *ValueFromIRExpr( rhs );
auto locvar = FromValue< LocalVar >( lvval );
if( !locvar )
co_return;
| < < | < | | < < < < < < < < < < | 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
auto ltype = ValuePatternFromIRExpr( lhs )->type();
auto lvval = *ValueFromIRExpr( rhs );
auto locvar = FromValue< LocalVar >( lvval );
if( !locvar )
co_return;
auto ref = ValueToIRExpr( ToValue( BuildLocalVarMutRef( *locvar ) )
.setLocationId( lvval.locationId() ) );
co_yield TypeCheck( lhs, ref, tcc );
} );
// Implicit referencing of non-variables: build a tempref
e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,
ValueToIRExpr( ValuePattern(
ANYTERM( _ ),
|
| ︙ | ︙ | |||
207 208 209 210 211 212 213 |
auto&& [ref, rhs] = *result;
auto rhsVal = *ValueFromIRExpr( rhs );
auto refPat = *ValuePatternFromIRExpr( ref );
auto rt = *FromValue< ReferenceType >( *ValueFromIRExpr( refPat.type() ) );
| | < < | 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 |
auto&& [ref, rhs] = *result;
auto rhsVal = *ValueFromIRExpr( rhs );
auto refPat = *ValuePatternFromIRExpr( ref );
auto rt = *FromValue< ReferenceType >( *ValueFromIRExpr( refPat.type() ) );
return ValueToIRExpr( ToValue( Reference{ move( rt ), TemporaryBaseAddr( tempIndex, rhsVal ) } ) );
} );
co_yield { move( wrapped ), tcc };
}
}
} );
}
}
|
Changes to bs/builtins/types/runtime/basic.cpp.
| ︙ | ︙ | |||
227 228 229 230 231 232 233 234 235 236 |
Value Bridge< uint64_t >::ToValue( uint64_t x )
{
return ir::ToValue( APSInt::getUnsigned( x ) );
}
optional< uint64_t > Bridge< uint64_t >::FromValue( const Value& v )
{
return FromValue< APSInt >( v )->getLimitedValue();
}
}
| > > | 227 228 229 230 231 232 233 234 235 236 237 238 |
Value Bridge< uint64_t >::ToValue( uint64_t x )
{
return ir::ToValue( APSInt::getUnsigned( x ) );
}
optional< uint64_t > Bridge< uint64_t >::FromValue( const Value& v )
{
if( !v.isConstant() )
return nullopt;
return FromValue< APSInt >( v )->getLimitedValue();
}
}
|
Changes to bs/builtins/types/runtime/init.cpp.
| ︙ | ︙ | |||
13 14 15 16 17 18 19 |
using IntegerType = CustomPattern< IntegerType, IntegerType::Pattern >;
// Initialization for integer vars
RegisterBuiltinFunc< Intrinsic< Value ( IntegerMutRefType, IntegerType ) > >( e, e.extInitialize(),
[]( auto&& c, const Value& r, const Value& initVal )
{
| < | | | 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 |
using IntegerType = CustomPattern< IntegerType, IntegerType::Pattern >;
// Initialization for integer vars
RegisterBuiltinFunc< Intrinsic< Value ( IntegerMutRefType, IntegerType ) > >( e, e.extInitialize(),
[]( auto&& c, const Value& r, const Value& initVal )
{
return BuildComputedValue( GetValueType< void >(),
Store( r, initVal ) );
} );
// Default initialization for integer vars
RegisterBuiltinFunc< Intrinsic< Value ( IntegerMutRefType ) > >( e, e.extInitialize(),
[]( auto&& c, const Value& r )
{
auto ref = *FromValue< Reference >( r );
auto opTypeVal = *ValueFromIRExpr( ref.type().type() );
auto opType = *FromValue< IntegerType >( opTypeVal );
auto initVal = Value( ref.type().type(),
APSInt( opType.m_numBits, !opType.m_signed ) );
return BuildComputedValue( GetValueType< void >(),
Store( r, initVal ) );
} );
}
}
|
Changes to bs/builtins/types/tuple/init.cpp.
| ︙ | ︙ | |||
25 26 27 28 29 30 31 |
// Create a mutable reference to the element to initialize
ReferenceType rt( t, TSID( mut ) );
auto addr = lref.address();
addr.appendToPath( index );
auto elemRef = BuildComputedValue( ValueToIRExpr( ToValue( rt ) ),
| < | | 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
// Create a mutable reference to the element to initialize
ReferenceType rt( t, TSID( mut ) );
auto addr = lref.address();
addr.appendToPath( index );
auto elemRef = BuildComputedValue( ValueToIRExpr( ToValue( rt ) ),
move( addr ) ).setLocationId( elemType.locationId() );
auto elemInit = *ValueFromIRExpr( GetTupleElement( initTup, index++ ) );
DiagnosticsContext dc( elemType.locationId(), "When invoking Initialize." );
auto init = InvokeOverloadSet( c, c.env()->extInitialize(),
MakeTuple( elemRef, move( elemInit ) ) );
|
| ︙ | ︙ | |||
62 63 64 65 66 67 68 |
ForEachInTupleType( tupType, [&]( auto&& t )
{
auto elemType = *ValueFromIRExpr( t );
// Create a mutable reference to the element to initialize
ReferenceType rt( t, TSID( mut ) );
auto addr = ref.address();
| | | | 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
ForEachInTupleType( tupType, [&]( auto&& t )
{
auto elemType = *ValueFromIRExpr( t );
// Create a mutable reference to the element to initialize
ReferenceType rt( t, TSID( mut ) );
auto addr = ref.address();
addr.path().back() = index++;
auto elemRef = BuildComputedValue( ValueToIRExpr( ToValue( rt ) ),
Load( ToValue( ref ), rt.type() ) )
.setLocationId( elemType.locationId() );
DiagnosticsContext dc( elemType.locationId(), "When invoking Initialize." );
auto init = InvokeOverloadSet( c, c.env()->extInitialize(),
MakeTuple( elemRef ) );
DiagnosticsContext dc2( elemType.locationId(), "When invoking DropValue." );
|
| ︙ | ︙ |
Changes to bs/builtins/types/tuple/typecheck.cpp.
| ︙ | ︙ | |||
23 24 25 26 27 28 29 |
if( index == ( tupSize - 1 ) )
co_yield { ValueToIRExpr( newOut ), tcc };
else
co_yield TypeCheckConstantTuple( tcc, tupType, tupArg, index + 1, newOut );
}
}
| | | | 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 |
if( index == ( tupSize - 1 ) )
co_yield { ValueToIRExpr( newOut ), tcc };
else
co_yield TypeCheckConstantTuple( tcc, tupType, tupArg, index + 1, newOut );
}
}
TCGen TypeCheckComputedTuple( const TypeCheckingContext& tcc, const Value& tupType, const Value& tupArg, const llr::CalcAddress& tupAddr, uint32_t index, const Value& out )
{
auto param = ParamPat( GetTupleTypeElement( tupType, index ) );
auto argType = GetTupleElementType( tupArg, index );
ReferenceType rt( argType, TSID( const ) );
auto argAddr = tupAddr;
argAddr.appendToPath( index );
auto argRef = ValueToIRExpr( BuildComputedValue( ValueToIRExpr( ToValue( rt ) ),
move( argAddr ) ) );
auto tupSize = TupleTypeSize( tupType );
for( auto&& [s,tcc] : TypeCheck( param, argRef, tcc ) )
{
auto val = ValuePatternFromIRExpr( s );
assert( val );
|
| ︙ | ︙ | |||
102 103 104 105 106 107 108 |
if( !ltup || !rtup || !tcc.context().codeBuilder() )
co_return;
auto tupType = *ValueFromIRExpr( ltup->type() );
assert( TupleTypeSize( tupType ) == TupleTypeSize( *ValueFromIRExpr( rtup->type() ) ) );
auto tempIndex = tcc.context().codeBuilder()->cfg()->getNewTemporaryIndex();
| | | 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
if( !ltup || !rtup || !tcc.context().codeBuilder() )
co_return;
auto tupType = *ValueFromIRExpr( ltup->type() );
assert( TupleTypeSize( tupType ) == TupleTypeSize( *ValueFromIRExpr( rtup->type() ) ) );
auto tempIndex = tcc.context().codeBuilder()->cfg()->getNewTemporaryIndex();
llr::CalcAddress addr( llr::TemporaryBaseAddr( tempIndex, *rtup ) );
co_yield TypeCheckComputedTuple( tcc, tupType, *rtup, addr, 0, EmptyTuple() );
} );
// Single element tuple unwrapping rules: if we encounter such a tuple, attempt to typecheck
// its contained value with whatever's on the other side.
e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,
|
| ︙ | ︙ |
Changes to bs/codegen/address.cpp.
1 2 3 4 5 6 7 | #include "codegen.h" #include "builtins/builtins.h" using namespace goose; using namespace goose::codegen; using namespace goose::builtins; | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#include "codegen.h"
#include "builtins/builtins.h"
using namespace goose;
using namespace goose::codegen;
using namespace goose::builtins;
llvm::Value* Module::buildInstruction( Infos& inf, const CalcAddress& addr )
{
auto* baseAddrVal = buildAddress( inf, addr.baseAddr() );
if( !baseAddrVal )
return nullptr;
if( addr.path().empty() )
return baseAddrVal;
|
| ︙ | ︙ | |||
27 28 29 30 31 32 33 |
{
return visit( [&]( auto&& ba )
{
return buildAddress( inf, ba );
}, baseAddr );
}
| | | 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
{
return visit( [&]( auto&& ba )
{
return buildAddress( inf, ba );
}, baseAddr );
}
llvm::Value* Module::buildAddress( Infos& inf, const TemporaryBaseAddr& ta )
{
auto* ppVal = inf.temporaries->get( ta.index );
if( !ppVal )
{
auto* pValue = buildValue( inf, ta.m_initValue );
if( !pValue )
|
| ︙ | ︙ | |||
50 51 52 53 54 55 56 |
auto* pAlloca = buildAlloca( inf, ( *ppVal )->getType() );
auto* pStore = m_llvmBuilder.CreateStore( *ppVal, pAlloca );
inf.temporaries->set( ta.index, pAlloca );
return pAlloca;
}
| | | 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
auto* pAlloca = buildAlloca( inf, ( *ppVal )->getType() );
auto* pStore = m_llvmBuilder.CreateStore( *ppVal, pAlloca );
inf.temporaries->set( ta.index, pAlloca );
return pAlloca;
}
llvm::Value* Module::buildAddress( Infos& inf, const VarBaseAddr& va )
{
auto* ppVal = inf.temporaries->get( va.index );
assert( ppVal );
if( !ppVal )
return nullptr;
return *ppVal;
}
|
Changes to bs/codegen/instructions.cpp.
| ︙ | ︙ | |||
112 113 114 115 116 117 118 |
auto type = LowerTypeForRuntime( inf.context, *ValueFromIRExpr( load.type() ) );
if( !type )
return nullptr;
auto* llvmType = GetLLVMType( *type );
assert( llvmType );
| | | | 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 |
auto type = LowerTypeForRuntime( inf.context, *ValueFromIRExpr( load.type() ) );
if( !type )
return nullptr;
auto* llvmType = GetLLVMType( *type );
assert( llvmType );
auto* ptrVal = buildValue(inf, load.addr() );// buildAddress( inf, load.addr() );
return m_llvmBuilder.CreateLoad( llvmType, ptrVal );
}
llvm::Value* Module::buildInstruction( Infos& inf, const llr::Store& store )
{
auto* pValue = buildValue( inf, store.val() );
if( !pValue )
return nullptr;
auto* ptrVal = buildValue(inf, store.addr() );
if( llvm::isa< llvm::ConstantAggregate >( pValue ) )
{
stringstream name;
name << ".constaggr" << hex << m_nextAggregateID++;
auto pGlob = new llvm::GlobalVariable( m_llvmModule,
|
| ︙ | ︙ |
Changes to bs/codegen/module.h.
| ︙ | ︙ | |||
50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
llvm::BasicBlock* buildBasicBlock( Infos& inf, const ptr< llr::BasicBlock >& pBB );
llvm::Value* buildValue( Infos& inf, const Value& val );
llvm::Constant* buildConstant( Infos& inf, const Value& val );
llvm::Value* buildInstruction( Infos& inf, const llr::Instruction& instr );
llvm::Value* buildInstruction( Infos& inf, const llr::Call& call );
llvm::Value* buildInstruction( Infos& inf, const llr::CreateTemporary& ct );
llvm::Value* buildInstruction( Infos& inf, const llr::GetTemporary& gt );
llvm::Value* buildInstruction( Infos& inf, const llr::AllocVar& av );
llvm::Value* buildInstruction( Infos& inf, const llr::Load& load );
llvm::Value* buildInstruction( Infos& inf, const llr::Store& store );
llvm::Value* buildInstruction( Infos& inf, const llr::Phi& p );
llvm::Value* buildInstruction( Infos& inf, const llr::LoadConstStr& lcs );
| > | 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
llvm::BasicBlock* buildBasicBlock( Infos& inf, const ptr< llr::BasicBlock >& pBB );
llvm::Value* buildValue( Infos& inf, const Value& val );
llvm::Constant* buildConstant( Infos& inf, const Value& val );
llvm::Value* buildInstruction( Infos& inf, const llr::Instruction& instr );
llvm::Value* buildInstruction( Infos& inf, const llr::Call& call );
llvm::Value* buildInstruction( Infos& inf, const llr::CalcAddress& ct );
llvm::Value* buildInstruction( Infos& inf, const llr::CreateTemporary& ct );
llvm::Value* buildInstruction( Infos& inf, const llr::GetTemporary& gt );
llvm::Value* buildInstruction( Infos& inf, const llr::AllocVar& av );
llvm::Value* buildInstruction( Infos& inf, const llr::Load& load );
llvm::Value* buildInstruction( Infos& inf, const llr::Store& store );
llvm::Value* buildInstruction( Infos& inf, const llr::Phi& p );
llvm::Value* buildInstruction( Infos& inf, const llr::LoadConstStr& lcs );
|
| ︙ | ︙ | |||
99 100 101 102 103 104 105 |
template< typename T >
bool buildTerminator( Infos& inf, const T& t )
{
return false;
}
| < | | | 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
template< typename T >
bool buildTerminator( Infos& inf, const T& t )
{
return false;
}
llvm::Value* buildAddress( Infos& inf, const BaseAddress& baseAddr );
llvm::Value* buildAddress( Infos& inf, const TemporaryBaseAddr& ta );
llvm::Value* buildAddress( Infos& inf, const VarBaseAddr& va );
llvm::Value* buildAlloca( Infos& inf, llvm::Type* type );
llvm::Value* createTemporary( Infos& inf, uint32_t index, llvm::Value* pValue ) const;
llvm::Module m_llvmModule;
llvm::DataLayout m_dataLayout;
llvm::IRBuilder<> m_llvmBuilder;
|
| ︙ | ︙ |
Changes to bs/compile/compiler.cpp.
| ︙ | ︙ | |||
59 60 61 62 63 64 65 |
{
auto result = LoadAndExecuteFile( m_pEnv, filename, builtins::RootIdentity(), GetValueType< uint32_t >(), ToValue< uint32_t >( 1 ) );
if( DiagnosticsManager::GetInstance().errorsWereEmitted() )
return 1;
if( !result )
| > > > | > | 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
{
auto result = LoadAndExecuteFile( m_pEnv, filename, builtins::RootIdentity(), GetValueType< uint32_t >(), ToValue< uint32_t >( 1 ) );
if( DiagnosticsManager::GetInstance().errorsWereEmitted() )
return 1;
if( !result )
{
DiagnosticsManager::GetInstance().emitErrorMessage( 0,
format( "{}: coult not be executed.", filename ) );
return 1;
}
if( result->isPoison() )
return 1;
return *FromValue< uint32_t >( *result );
}
|
| ︙ | ︙ |
Changes to bs/execute/binaryops.inl.
1 2 3 4 5 6 |
#ifndef GOOSE_EXECUTE_BINARYOPS_INL
#define GOOSE_EXECUTE_BINARYOPS_INL
namespace goose::execute
{
template< typename F >
| | | > > | > > | 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 |
#ifndef GOOSE_EXECUTE_BINARYOPS_INL
#define GOOSE_EXECUTE_BINARYOPS_INL
namespace goose::execute
{
template< typename F >
optional< Value > VM::executeEqualityBinOp( const llr::BinaryOp& bo, F&& func )
{
if( bo.lhs().isPoison() || bo.rhs().isPoison() )
return PoisonValue();
assert( bo.lhs().type() == bo.rhs().type() );
if( bo.lhs().type() != bo.rhs().type() )
return PoisonValue();
auto lval = Evaluate( bo.lhs(), *this );
if( lval.isPoison() )
return PoisonValue();
if( !lval.isConstant() )
return nullopt;
auto rval = Evaluate( bo.rhs(), *this );
if( rval.isPoison() )
return PoisonValue();
if( !rval.isConstant() )
return nullopt;
if( auto lbool = FromValue< bool >( lval ) )
return ToValue( func( *lbool, *FromValue< bool >( rval ) ) );
if( auto lint = FromValue< APSInt >( lval ) )
{
auto rint = *FromValue< APSInt >( rval );
|
| ︙ | ︙ | |||
49 50 51 52 53 54 55 |
}
assert( false );
return PoisonValue();
}
template< typename F >
| | | > > | > > | 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 |
}
assert( false );
return PoisonValue();
}
template< typename F >
optional< Value > VM::executeLogicBinOp( const llr::BinaryOp& bo, F&& func )
{
if( bo.lhs().isPoison() || bo.rhs().isPoison() )
return PoisonValue();
assert( bo.lhs().type() == bo.rhs().type() );
if( bo.lhs().type() != bo.rhs().type() )
return PoisonValue();
auto lval = Evaluate( bo.lhs(), *this );
if( lval.isPoison() )
return PoisonValue();
if( !lval.isConstant() )
return nullopt;
auto rval = Evaluate( bo.rhs(), *this );
if( rval.isPoison() )
return PoisonValue();
if( !rval.isConstant() )
return nullopt;
if( auto lbool = FromValue< bool >( lval ) )
return ToValue( func( *lbool, *FromValue< bool >( rval ) ) );
if( auto lint = FromValue< APSInt >( lval ) )
{
auto rint = *FromValue< APSInt >( rval );
|
| ︙ | ︙ | |||
86 87 88 89 90 91 92 |
}
assert( false );
return PoisonValue();
}
template< typename F >
| | | > > | > > | | > > | > > | 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 |
}
assert( false );
return PoisonValue();
}
template< typename F >
optional< Value > VM::executeBinOp( const llr::BinaryOp& bo, F&& func )
{
if( bo.lhs().isPoison() || bo.rhs().isPoison() )
return PoisonValue();
assert( bo.lhs().type() == bo.rhs().type() );
if( bo.lhs().type() != bo.rhs().type() )
return PoisonValue();
auto lval = Evaluate( bo.lhs(), *this );
if( lval.isPoison() )
return PoisonValue();
if( !lval.isConstant() )
return nullopt;
auto rval = Evaluate( bo.rhs(), *this );
if( rval.isPoison() )
return PoisonValue();
if( !rval.isConstant() )
return nullopt;
if( auto lint = FromValue< APSInt >( lval ) )
{
auto rint = *FromValue< APSInt >( rval );
return ToValue( func( *lint, move( rint ) ) );
}
if( auto lint = FromValue< BigInt >( lval ) )
{
const auto& rint = *FromValue< BigInt >( rval );
return ToValue( func( *lint, rint ) );
}
assert( false );
return PoisonValue();
}
template< typename F >
optional< Value > VM::executeShiftBinOp( const llr::BinaryOp& bo, F&& func )
{
if( bo.lhs().isPoison() || bo.rhs().isPoison() )
return PoisonValue();
auto lval = Evaluate( bo.lhs(), *this );
if( lval.isPoison() )
return PoisonValue();
if( !lval.isConstant() )
return nullopt;
auto rval = Evaluate( bo.rhs(), *this );
if( rval.isPoison() )
return PoisonValue();
if( !rval.isConstant() )
return nullopt;
if( auto lint = FromValue< APSInt >( lval ) )
{
auto rint = *FromValue< APSInt >( rval );
return ToValue( APSInt( func( *lint, move( rint ) ), lint->isUnsigned() ) );
}
|
| ︙ | ︙ |
Changes to bs/execute/vm.cpp.
| ︙ | ︙ | |||
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
assert( val );
auto newVal = Evaluate( *val, *this );
if( newVal.isPoison() )
poisoned = true;
if( !newVal.isConstant() )
return ValueToIRExpr( PoisonValue() );
return ValueToIRExpr( newVal );
} );
if( poisoned )
return PoisonValue();
| > > > | 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
assert( val );
auto newVal = Evaluate( *val, *this );
if( newVal.isPoison() )
poisoned = true;
if( !newVal.isConstant() )
{
poisoned = true;
return ValueToIRExpr( PoisonValue() );
}
return ValueToIRExpr( newVal );
} );
if( poisoned )
return PoisonValue();
|
| ︙ | ︙ | |||
139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
}
optional< Value > VM::ExecuteBuiltinFuncCall( const Value& func, const Term& args )
{
const auto& f = GetBuiltinFuncWrapper( func );
return f( args );
}
optional< Value > VM::execute( const llr::CreateTemporary& ct )
{
auto stackIndex = m_currentFrameStart + ct.index();
if( m_stack.size() <= stackIndex )
m_stack.resize( stackIndex + 1, TSID( UNINITIALIZED ) );
| > > > > > > > > > | 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
}
optional< Value > VM::ExecuteBuiltinFuncCall( const Value& func, const Term& args )
{
const auto& f = GetBuiltinFuncWrapper( func );
return f( args );
}
optional< Value > VM::execute( const llr::CalcAddress& ref )
{
auto* pAddr = calcAddress( ref );
if( !pAddr )
return nullopt;
return ToValue( reinterpret_cast< uintptr_t >( pAddr ) );
}
optional< Value > VM::execute( const llr::CreateTemporary& ct )
{
auto stackIndex = m_currentFrameStart + ct.index();
if( m_stack.size() <= stackIndex )
m_stack.resize( stackIndex + 1, TSID( UNINITIALIZED ) );
|
| ︙ | ︙ | |||
172 173 174 175 176 177 178 |
m_stack[stackIndex] = BuildUninitializedValue( av.type() );
return nullopt;
}
optional< Value > VM::execute( const llr::Load& l )
{
| | | > | | > > | 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 |
m_stack[stackIndex] = BuildUninitializedValue( av.type() );
return nullopt;
}
optional< Value > VM::execute( const llr::Load& l )
{
auto addrInt = FromValue< uintptr_t >( Evaluate( l.addr(), *this ) );
if( !addrInt )
return nullopt;
auto addr = reinterpret_cast< const Term* >( *addrInt );
return ValueFromIRExpr( *addr );
}
optional< Value > VM::execute( const llr::Store& s )
{
auto addrInt = FromValue< uintptr_t >( Evaluate( s.addr(), *this ) );
if( !addrInt )
return nullopt;
auto addr = reinterpret_cast< Term* >( *addrInt );
auto result = Evaluate( s.val(), *this );
if( !result.isConstant() )
return PoisonValue();
*addr = ValueToIRExpr( result );
return nullopt;
|
| ︙ | ︙ | |||
219 220 221 222 223 224 225 |
optional< Value > VM::execute( const llr::Not& uo )
{
if( uo.operand().isPoison() )
return PoisonValue();
auto opval = Evaluate( uo.operand(), *this );
| | > > | 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 |
optional< Value > VM::execute( const llr::Not& uo )
{
if( uo.operand().isPoison() )
return PoisonValue();
auto opval = Evaluate( uo.operand(), *this );
if( opval.isPoison() )
return PoisonValue();
if( !opval.isConstant() )
return nullopt;
auto boolVal = FromValue< bool >( opval );
if( !boolVal )
return PoisonValue();
return ToValue( !*boolVal );
}
|
| ︙ | ︙ | |||
289 290 291 292 293 294 295 |
if( *FromValue< bool >( cond ) )
return cb.trueDest().lock();
return cb.falseDest().lock();
}
| | | 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 |
if( *FromValue< bool >( cond ) )
return cb.trueDest().lock();
return cb.falseDest().lock();
}
Term* VM::calcAddress( const CalcAddress& addr )
{
auto* pTerm = calcAddress( addr.baseAddr() );
if( !pTerm )
return nullptr;
for( auto&& index : addr.path() )
{
|
| ︙ | ︙ | |||
321 322 323 324 325 326 327 |
{
return visit( [&]( auto&& ba )
{
return calcAddress( ba );
}, baseAddr );
}
| | | | 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 |
{
return visit( [&]( auto&& ba )
{
return calcAddress( ba );
}, baseAddr );
}
Term* VM::calcAddress( const llr::TemporaryBaseAddr& ta )
{
auto stackIndex = m_currentFrameStart + ta.index;
if( m_stack.size() <= stackIndex )
m_stack.resize( stackIndex + 1, TSID( UNINITIALIZED ) );
if( stackIndex >= m_stack.size() )
return nullptr;
if( m_stack[stackIndex] == TSID( UNINITIALIZED ) )
m_stack[stackIndex] = ValueToIRExpr( Evaluate( ta.m_initValue, *this ) );
return &m_stack[stackIndex];
}
Term* VM::calcAddress( const llr::VarBaseAddr& va )
{
auto stackIndex = m_currentFrameStart + va.index;
if( stackIndex >= m_stack.size() )
return nullptr;
return &m_stack[stackIndex];
}
|
| ︙ | ︙ |
Changes to bs/execute/vm.h.
| ︙ | ︙ | |||
14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
}
optional< Value > execute( CFG& cfg );
optional< Value > execute( ptr< BasicBlock > bb );
optional< Value > execute( const llr::Instruction& instr );
optional< Value > execute( const llr::Call& call );
optional< Value > execute( const llr::CreateTemporary& ct );
optional< Value > execute( const llr::GetTemporary& gt );
optional< Value > execute( const llr::AllocVar& av );
optional< Value > execute( const llr::Load& l );
optional< Value > execute( const llr::Store& s );
optional< Value > execute( const llr::Phi& p );
| > | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
}
optional< Value > execute( CFG& cfg );
optional< Value > execute( ptr< BasicBlock > bb );
optional< Value > execute( const llr::Instruction& instr );
optional< Value > execute( const llr::Call& call );
optional< Value > execute( const llr::CalcAddress& ref );
optional< Value > execute( const llr::CreateTemporary& ct );
optional< Value > execute( const llr::GetTemporary& gt );
optional< Value > execute( const llr::AllocVar& av );
optional< Value > execute( const llr::Load& l );
optional< Value > execute( const llr::Store& s );
optional< Value > execute( const llr::Phi& p );
|
| ︙ | ︙ | |||
70 71 72 73 74 75 76 |
}
private:
static optional< Value > ExecuteBuiltinFuncCall( const Value& func, const Term& args );
static Term BuildUninitializedValue( const Value& type );
template< typename F >
| | | | | | | | | 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 |
}
private:
static optional< Value > ExecuteBuiltinFuncCall( const Value& func, const Term& args );
static Term BuildUninitializedValue( const Value& type );
template< typename F >
optional< Value > executeEqualityBinOp( const llr::BinaryOp& bo, F&& func );
template< typename F >
optional< Value > executeLogicBinOp( const llr::BinaryOp& bo, F&& func );
template< typename F >
optional< Value > executeBinOp( const llr::BinaryOp& bo, F&& func );
template< typename F >
optional< Value > executeShiftBinOp( const llr::BinaryOp& bo, F&& func );
Term* calcAddress( const CalcAddress& addr );
Term* calcAddress( const BaseAddress& baseAddr );
Term* calcAddress( const TemporaryBaseAddr& va );
Term* calcAddress( const VarBaseAddr& va );
llvm::SmallVector< Term, 8 > m_stack;
optional< Value > m_retVal;
size_t m_currentFrameStart = 0;
// Used to interpret Phi instructions.
ptr< BasicBlock > m_pPreviousBB;
|
| ︙ | ︙ |
Name change from bs/llr/address.h to bs/llr/calcaddr.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 |
#ifndef GOOSE_LLR_CALCADDR_H
#define GOOSE_LLR_CALCADDR_H
namespace goose::llr
{
struct TemporaryBaseAddr
{
template< typename T >
TemporaryBaseAddr( uint32_t i, T&& init ) :
m_initValue( forward< T >( init ) ),
index( i )
{}
auto operator<=>( const TemporaryBaseAddr& rhs ) const
{
return index <=> rhs.index;
}
ir::Value m_initValue;
uint32_t index = 0;
};
struct VarBaseAddr
{
VarBaseAddr( uint32_t i ) : index( i ) {}
auto operator<=>( const VarBaseAddr& ) const = default;
uint32_t index = 0;
};
// TODO: at some point we'll want to be able to use an integer Value as the base address.
using BaseAddress = variant
<
TemporaryBaseAddr,
VarBaseAddr
>;
static inline strong_ordering operator<=>( const BaseAddress& lhs, const BaseAddress& rhs )
{
return visit( [&]< typename L, typename R >( const L& l, const R& r )
{
if constexpr( is_same_v< L, R > )
|
| ︙ | ︙ | |||
63 64 65 66 67 68 69 |
if( auto cmp = lhs[i] <=> rhs[i]; cmp != 0 )
return cmp;
}
return strong_ordering::equal;
}
| < < | > > > | | | > > > > > | > > > > > > > > < < < < < | 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 |
if( auto cmp = lhs[i] <=> rhs[i]; cmp != 0 )
return cmp;
}
return strong_ordering::equal;
}
class CalcAddress
{
public:
CalcAddress( BaseAddress&& baseAddr ) :
m_baseAddr( move( baseAddr ) )
{}
CalcAddress( const BaseAddress& baseAddr ) :
m_baseAddr( baseAddr )
{}
const auto& baseAddr() const
{
return m_baseAddr;
}
void appendToPath( uint32_t index )
{
m_path.push_back( index );
}
const auto& path() const
{
return m_path;
}
auto& path()
{
return m_path;
}
auto operator<=>( const CalcAddress& ) const = default;
bool canBeExecuted() const { return true; }
bool canBeEagerlyEvaluated() const { return false; }
bool isTempRef() const
{
return holds_alternative< TemporaryBaseAddr >( baseAddr() );
}
private:
BaseAddress m_baseAddr;
// Indices of tuple or array elements to follow to reach into nested
// values, interpreted depending on the types encountered. This is similar
// in spirit to the indices passed to llvm's GEP instruction.
AddressPath m_path;
};
}
#endif
|
Changes to bs/llr/cfg.h.
| ︙ | ︙ | |||
62 63 64 65 66 67 68 |
template< typename F >
void forEachBB( F&& func )
{
for( auto&& bb : m_basicBlocks )
func( bb );
}
| | | | | | 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 |
template< typename F >
void forEachBB( F&& func )
{
for( auto&& bb : m_basicBlocks )
func( bb );
}
void setAddressModifiedByLoop( uint32_t loopId, const ir::Term& type, const CalcAddress& addr )
{
m_loopModifiedAddresses.emplace( make_pair( loopId, addr ), type );
}
template< typename F >
void forEachAddressModifiedInLoop( uint32_t loopId, F&& func ) const
{
auto begin = m_loopModifiedAddresses.lower_bound( { loopId, CalcAddress( 0U ) } );
auto end = m_loopModifiedAddresses.upper_bound( { loopId, CalcAddress( ~0U ) } );
for( auto it = begin; it != end; ++it )
func( it->second, it->first.second );
}
private:
vector< ptr< BasicBlock > > m_basicBlocks;
ptr< BasicBlock > m_currentBB;
// All the edges of the CFG in SrcBBIndex, DestBBIndex form
unordered_multimap< uint32_t, uint32_t > m_edges;
// For each BB, store the index of its immediate dominator.
// May be be empty if it has not (yet) been computed.
vector< uint32_t > m_idoms;
// For each loop, store all of the adresses modified
// during that loop.
// May be be empty if it has not (yet) been computed.
multimap< pair< uint32_t, CalcAddress >, ir::Term > m_loopModifiedAddresses;
// The number of temporary indices used by this CFG.
uint32_t m_temporariesCount = 0;
uint32_t m_loopCount = 0;
bool m_poisoned = false;
|
| ︙ | ︙ |
Changes to bs/llr/cfgviz.cpp.
| ︙ | ︙ | |||
70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
GraphVizBuilder::Row row( builder );
GraphVizBuilder::Cell cell( builder );
GraphVizBuilder::Color col( builder );
// TODO also visualize the func and the args
builder.output() << "Call";
}
void CfgViz( GraphVizBuilder& builder, const CreateTemporary& instr )
{
builder.queueWork( [&]
{
CfgViz( builder, instr.value() );
} );
| > > > > > > > > > | 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
GraphVizBuilder::Row row( builder );
GraphVizBuilder::Cell cell( builder );
GraphVizBuilder::Color col( builder );
// TODO also visualize the func and the args
builder.output() << "Call";
}
void CfgViz( GraphVizBuilder& builder, const Reference& instr )
{
GraphVizBuilder::Row row( builder );
GraphVizBuilder::Cell cell( builder );
GraphVizBuilder::Color col( builder );
builder.output() << "Reference";
}
void CfgViz( GraphVizBuilder& builder, const CreateTemporary& instr )
{
builder.queueWork( [&]
{
CfgViz( builder, instr.value() );
} );
|
| ︙ | ︙ |
Changes to bs/llr/cfgviz.h.
| ︙ | ︙ | |||
15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
extern void CfgViz( GraphVizBuilder& builder, const ptr< BasicBlock >& bb );
extern void CfgViz( GraphVizBuilder& builder, const ir::Value& val );
extern void CfgViz( GraphVizBuilder& builder, const Instruction& instr );
extern void CfgViz( GraphVizBuilder& builder, const Terminator& t );
extern void CfgViz( GraphVizBuilder& builder, const Call& instr );
extern void CfgViz( GraphVizBuilder& builder, const CreateTemporary& instr );
extern void CfgViz( GraphVizBuilder& builder, const GetTemporary& instr );
extern void CfgViz( GraphVizBuilder& builder, const AllocVar& instr );
extern void CfgViz( GraphVizBuilder& builder, const Load& instr );
extern void CfgViz( GraphVizBuilder& builder, const Store& instr );
extern void CfgViz( GraphVizBuilder& builder, const Phi& instr );
extern void CfgViz( GraphVizBuilder& builder, const LoadConstStr& instr );
| > | 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
extern void CfgViz( GraphVizBuilder& builder, const ptr< BasicBlock >& bb );
extern void CfgViz( GraphVizBuilder& builder, const ir::Value& val );
extern void CfgViz( GraphVizBuilder& builder, const Instruction& instr );
extern void CfgViz( GraphVizBuilder& builder, const Terminator& t );
extern void CfgViz( GraphVizBuilder& builder, const Call& instr );
extern void CfgViz( GraphVizBuilder& builder, const CalcAddress& instr );
extern void CfgViz( GraphVizBuilder& builder, const CreateTemporary& instr );
extern void CfgViz( GraphVizBuilder& builder, const GetTemporary& instr );
extern void CfgViz( GraphVizBuilder& builder, const AllocVar& instr );
extern void CfgViz( GraphVizBuilder& builder, const Load& instr );
extern void CfgViz( GraphVizBuilder& builder, const Store& instr );
extern void CfgViz( GraphVizBuilder& builder, const Phi& instr );
extern void CfgViz( GraphVizBuilder& builder, const LoadConstStr& instr );
|
| ︙ | ︙ |
Changes to bs/llr/helpers.cpp.
| ︙ | ︙ | |||
13 14 15 16 17 18 19 20 |
bool CanValueBeEagerlyEvaluated( const ir::Value& val )
{
if( val.isConstant() )
return true;
return val.llr()->canBeEagerlyEvaluated();
}
}
| > > > > > > > > > | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
bool CanValueBeEagerlyEvaluated( const ir::Value& val )
{
if( val.isConstant() )
return true;
return val.llr()->canBeEagerlyEvaluated();
}
bool IsCompileTimeTempRef( const ir::Value& val )
{
if( !val.isConstant() )
return false;
const auto* pRefInst = get_if< CalcAddress >( &val.llr()->content() );
return pRefInst && pRefInst->isTempRef();
}
}
|
Changes to bs/llr/helpers.h.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
#ifndef GOOSE_LLR_HELPERS_H
#define GOOSE_LLR_HELPERS_H
namespace goose::llr
{
class Instruction;
bool IsValueConstantOrExecutable( const ir::Value& val );
bool CanValueBeEagerlyEvaluated( const ir::Value& val );
template< typename T, typename I >
auto BuildComputedValue( T&& type, I&& instr )
{
return ir::Value( forward< T >( type ),
make_shared< Instruction >( forward< I >( instr ) ) );
}
| > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#ifndef GOOSE_LLR_HELPERS_H
#define GOOSE_LLR_HELPERS_H
namespace goose::llr
{
class Instruction;
bool IsValueConstantOrExecutable( const ir::Value& val );
bool CanValueBeEagerlyEvaluated( const ir::Value& val );
bool IsCompileTimeTempRef( const ir::Value& val );
template< typename T, typename I >
auto BuildComputedValue( T&& type, I&& instr )
{
return ir::Value( forward< T >( type ),
make_shared< Instruction >( forward< I >( instr ) ) );
}
|
| ︙ | ︙ |
Changes to bs/llr/instruction.h.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
#ifndef GOOSE_LLR_INSTRUCTION_H
#define GOOSE_LLR_INSTRUCTION_H
namespace goose::llr
{
class CFG;
class Instruction
{
public:
Instruction( Call&& c ) :
m_content( move( c ) )
{}
Instruction( CreateTemporary&& ct ) :
m_content( move( ct ) )
{}
Instruction( GetTemporary&& gt ) :
m_content( move( gt ) )
| > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
#ifndef GOOSE_LLR_INSTRUCTION_H
#define GOOSE_LLR_INSTRUCTION_H
namespace goose::llr
{
class CFG;
class Instruction
{
public:
Instruction( Call&& c ) :
m_content( move( c ) )
{}
Instruction( CalcAddress&& cad ) :
m_content( move( cad ) )
{}
Instruction( CreateTemporary&& ct ) :
m_content( move( ct ) )
{}
Instruction( GetTemporary&& gt ) :
m_content( move( gt ) )
|
| ︙ | ︙ | |||
143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
Instruction( Placeholder&& x ) :
m_content( move( x ) )
{}
using Content = variant
<
Call,
CreateTemporary,
GetTemporary,
AllocVar,
Load,
Store,
Phi,
LoadConstStr,
| > > > | 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 |
Instruction( Placeholder&& x ) :
m_content( move( x ) )
{}
using Content = variant
<
Call,
CalcAddress,
CreateTemporary,
GetTemporary,
AllocVar,
Load,
Store,
Phi,
LoadConstStr,
|
| ︙ | ︙ |
Changes to bs/llr/llr.h.
| ︙ | ︙ | |||
11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
static constexpr uint32_t InvalidVarId = numeric_limits< uint32_t >::max();
class CFG;
}
#include "helpers.h"
#include "address.h"
#include "call.h"
#include "loadconst.h"
#include "createtemporary.h"
#include "gettemporary.h"
#include "allocvar.h"
#include "load.h"
#include "store.h"
| > | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
static constexpr uint32_t InvalidVarId = numeric_limits< uint32_t >::max();
class CFG;
}
#include "helpers.h"
#include "address.h"
#include "calcaddr.h"
#include "call.h"
#include "loadconst.h"
#include "createtemporary.h"
#include "gettemporary.h"
#include "allocvar.h"
#include "load.h"
#include "store.h"
|
| ︙ | ︙ |
Changes to bs/llr/load.h.
| ︙ | ︙ | |||
14 15 16 17 18 19 20 |
const auto& addr() const { return m_addr; }
const auto& type() const { return m_type; }
bool canBeExecuted() const { return true; }
bool canBeEagerlyEvaluated() const
{
| | | | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
const auto& addr() const { return m_addr; }
const auto& type() const { return m_type; }
bool canBeExecuted() const { return true; }
bool canBeEagerlyEvaluated() const
{
return IsCompileTimeTempRef( m_addr );
}
private:
ir::Value m_addr;
ir::Term m_type;
};
}
#endif
|
Changes to bs/llr/loopaddrs.cpp.
1 2 3 4 |
#include "llr.h"
namespace goose::llr
{
| | | > > > > > > > > > > > | | 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 "llr.h"
namespace goose::llr
{
void MarkAddrChangedByLoop( const ptr< CFG >& cfg, uint32_t loopId, const ir::Term& type, const CalcAddress& addr )
{
cfg->setAddressModifiedByLoop( loopId, type, addr );
const auto& pHeader = cfg->getBB( loopId );
if( pHeader->loopId() )
MarkAddrChangedByLoop( cfg, pHeader->loopId(), type, addr );
}
void ComputeLoopModifiedAddrs( const ptr< CFG >& cfg )
{
cfg->forEachBB( [&]( auto&& bb )
{
for( auto&& instr : *bb )
{
auto st = get_if< Store >( &instr.content() );
if( !st )
continue;
auto llr = st->addr().llr();
if( !llr )
continue;
auto ref = get_if< CalcAddress >( &llr->content() );
if( !ref )
continue;
MarkAddrChangedByLoop( cfg, bb->index(), st->val().type(), *ref );
}
} );
}
}
|
Changes to bs/llr/store.h.
| ︙ | ︙ | |||
18 19 20 21 22 23 24 |
bool canBeExecuted() const
{
return IsValueConstantOrExecutable( m_val );
}
bool canBeEagerlyEvaluated() const
{
| | | | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
bool canBeExecuted() const
{
return IsValueConstantOrExecutable( m_val );
}
bool canBeEagerlyEvaluated() const
{
return IsCompileTimeTempRef( m_addr )
&& CanValueBeEagerlyEvaluated( m_val );
}
private:
ir::Value m_addr;
ir::Value m_val;
};
}
#endif
|
Changes to bs/sema/invocation.cpp.
| ︙ | ︙ | |||
51 52 53 54 55 56 57 |
auto loc = Location::CreateSpanningLocation( callee.locationId(), args.locationId() );
if( loc == ~0 )
DiagnosticsManager::GetInstance().setCurrentVerbosityLevel( Verbosity::Silent );
auto result = pInvRule->resolveInvocation( c, loc, callee, args.val() ).setLocationId( loc );
// If the result is non-void, register it for destruction.
| < < < | 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
auto loc = Location::CreateSpanningLocation( callee.locationId(), args.locationId() );
if( loc == ~0 )
DiagnosticsManager::GetInstance().setCurrentVerbosityLevel( Verbosity::Silent );
auto result = pInvRule->resolveInvocation( c, loc, callee, args.val() ).setLocationId( loc );
// If the result is non-void, register it for destruction.
if( c.codeBuilder() && result.type() != GetValueType< void >() )
{
if( auto cfg = c.codeBuilder()->cfg() )
c.codeBuilder()->pushLiveValue( result, cfg->getNewTemporaryIndex() );
}
return result;
|
| ︙ | ︙ |
Changes to bs/sema/typecheck.cpp.
| ︙ | ︙ | |||
70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
// Let's not really worry about how to properly report this for now.
if( ambiguous )
throw runtime_error( "ambiguous type checking rule" );
if( !bestRule )
co_return;
co_yield bestRule->func( lhs, rhs, context );
}
TCGen Unify( const Term& lhs, const Term& rhs, const TypeCheckingContext& context )
{
const auto& rules = context.rules()->uniRules();
| > > > > > > | 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
// Let's not really worry about how to properly report this for now.
if( ambiguous )
throw runtime_error( "ambiguous type checking rule" );
if( !bestRule )
co_return;
#ifdef TCRULES_DEBUG
cout << "calling typecheck rule " << bestRule->infos.pFilename << ':' << bestRule->infos.line << endl;
cout << " lhs " << lhs << endl;
cout << " rhs " << rhs << endl;
#endif
co_yield bestRule->func( lhs, rhs, context );
}
TCGen Unify( const Term& lhs, const Term& rhs, const TypeCheckingContext& context )
{
const auto& rules = context.rules()->uniRules();
|
| ︙ | ︙ |
Changes to bs/verify/call.cpp.
| ︙ | ︙ | |||
55 56 57 58 59 60 61 |
)
);
if( !result )
return true;
auto&& [type, val, locId] = *result;
| | | 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
)
);
if( !result )
return true;
auto&& [type, val, locId] = *result;
auto paramVal = BuildComputedValue( type, CalcAddress( llr::VarBaseAddr( varId++ ) ) );
if( auto zv = BuildZ3ExprFromValue( cb, paramVal ) )
{
ForEachPredicate( cb, type, zv->expr, [&]( auto&& z3expr, auto locId )
{
DiagnosticsContext dc( instr.func().locationId(), "At this call." );
b.checkAssertion( z3expr, locId );
|
| ︙ | ︙ |
Changes to bs/verify/comptime.cpp.
| ︙ | ︙ | |||
8 9 10 11 12 13 14 |
{
bool VerifyCompTimeExpr( Builder& b, const Call& instr );
template< typename T >
bool VerifyCompTimeExpr( Builder& b, const T& instr )
{
assert( false );
| < | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
{
bool VerifyCompTimeExpr( Builder& b, const Call& instr );
template< typename T >
bool VerifyCompTimeExpr( Builder& b, const T& instr )
{
assert( false );
}
bool VerifyCompTimeExpr( const sema::Context& c, const Value& val )
{
if( val.isConstant() || val.isPoison() )
return true;
|
| ︙ | ︙ | |||
141 142 143 144 145 146 147 |
)
);
if( !result )
return true;
auto&& [type, val, locId] = *result;
| > | | 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
)
);
if( !result )
return true;
auto&& [type, val, locId] = *result;
builtins::Reference argRef( builtins::ReferenceType{ type, TSID( const ) }, llr::VarBaseAddr( varId++ ) );
auto paramVal = BuildComputedValue( type, llr::Load( ToValue( argRef ), type ) );
if( auto zv = BuildZ3ExprFromValue( b, paramVal ) )
{
ForEachPredicate( b, type, zv->expr, [&]( auto&& z3expr, auto locId )
{
DiagnosticsContext dc( instr.func().locationId(), "At this compilation-time call." );
b.checkAssertion( z3expr, locId );
|
| ︙ | ︙ |
Changes to bs/verify/func.cpp.
| ︙ | ︙ | |||
67 68 69 70 71 72 73 |
)
);
if( !result )
return true;
auto&& [type, val, locId] = *result;
| > | | 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
)
);
if( !result )
return true;
auto&& [type, val, locId] = *result;
builtins::Reference argRef( builtins::ReferenceType{ type, TSID( const ) }, llr::VarBaseAddr( varId ) );
auto paramVal = BuildComputedValue( type, llr::Load( ToValue( argRef ), type ) );
// Initialize every parameter containing variable with an freshly named constant of the right type.
if( auto paramInit = BuildZ3ConstantFromType( m_builder, type, format( "p{}", varId ) ) )
m_builder.setVar( varId, move( *paramInit ) );
++varId;
|
| ︙ | ︙ | |||
106 107 108 109 110 111 112 |
bool result = buildZ3Expressions( *m_cfg->entryBB(), nullptr );
if( ms_TraceMode )
cout << "=== End function verification trace ===\n\n";
return result;
}
| | | 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
bool result = buildZ3Expressions( *m_cfg->entryBB(), nullptr );
if( ms_TraceMode )
cout << "=== End function verification trace ===\n\n";
return result;
}
catch( const z3::exception& e )
{
cerr << "Func: z3 exception: " << e << endl;
// rethrow so we get a stack trace dump to know where the error happened
throw;
}
}
|
| ︙ | ︙ |
Changes to bs/verify/storage.cpp.
1 2 3 4 5 6 7 8 |
#include "verify.h"
#include "builtins/builtins.h"
using namespace goose;
using namespace goose::builtins;
namespace goose::verify
{
| | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
#include "verify.h"
#include "builtins/builtins.h"
using namespace goose;
using namespace goose::builtins;
namespace goose::verify
{
optional< Z3Val > LoadFromAddress( Builder& b, const CalcAddress& addr )
{
auto val = LoadFromAddress( b, addr.baseAddr() );
if( !val )
return nullopt;
for( auto&& index : addr.path() )
{
|
| ︙ | ︙ | |||
32 33 34 35 36 37 38 |
{
return visit( [&]( auto&& ba )
{
return LoadFromAddress( b, ba );
}, baseAddr );
}
| | | | 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
{
return visit( [&]( auto&& ba )
{
return LoadFromAddress( b, ba );
}, baseAddr );
}
optional< Z3Val > LoadFromAddress( Builder& b, const llr::TemporaryBaseAddr& ta )
{
auto zv = b.retrieveVar( ta.index );
if( zv )
return zv;
return b.setVar( ta.index, ta.m_initValue );
}
optional< Z3Val > LoadFromAddress( Builder& b, const llr::VarBaseAddr& va )
{
return b.retrieveVar( va.index );
}
optional< z3::expr > ModifyAggregate( Builder& b, const Z3Val& aggregate, const AddressPath& path, uint32_t index, Z3Val&& valToStore )
{
auto tinfo = TypeCache::GetInstance()->getTypeInfo( b.context(), ValueToIRExpr( aggregate.type ) );
|
| ︙ | ︙ | |||
91 92 93 94 95 96 97 |
else
args.push_back( move( elemExpr ) );
}
return tinfo->ctor( args );
}
| | | 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
else
args.push_back( move( elemExpr ) );
}
return tinfo->ctor( args );
}
void StoreToAddress( Builder& b, const CalcAddress& addr, Z3Val&& valToStore )
{
if( addr.path().empty() )
{
StoreToAddress( b, addr.baseAddr(), move( valToStore ) );
return;
}
|
| ︙ | ︙ | |||
119 120 121 122 123 124 125 |
{
return visit( [&]( auto&& ba )
{
return StoreToAddress( b, ba, move( val ) );
}, baseAddr );
}
| | | | | 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 |
{
return visit( [&]( auto&& ba )
{
return StoreToAddress( b, ba, move( val ) );
}, baseAddr );
}
void StoreToAddress( Builder& b, const llr::TemporaryBaseAddr& ta, Z3Val&& val )
{
b.setVar( ta.index, move( val ) );
}
void StoreToAddress( Builder& b, const llr::VarBaseAddr& va, Z3Val&& val )
{
b.setVar( va.index, move( val ) );
}
void HavocAddress( Builder& b, uint32_t bbIndex, const Term& type, const CalcAddress& addr )
{
auto valToStore = BuildZ3ConstantFromType( b, type, format( "v{}", b.newUniqueId() ) );
if( !valToStore )
return;
StoreToAddress( b, addr, move( *valToStore ) );
}
}
|
Changes to bs/verify/storage.h.
1 2 3 4 5 |
#ifndef GOOSE_VERIFY_STORAGE_H
#define GOOSE_VERIFY_STORAGE_H
namespace goose::verify
{
| | | | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
#ifndef GOOSE_VERIFY_STORAGE_H
#define GOOSE_VERIFY_STORAGE_H
namespace goose::verify
{
extern optional< Z3Val > LoadFromAddress( Builder& b, const llr::CalcAddress& addr );
extern optional< Z3Val > LoadFromAddress( Builder& b, const BaseAddress& baseAddr );
extern optional< Z3Val > LoadFromAddress( Builder& b, const llr::TemporaryBaseAddr& ta );
extern optional< Z3Val > LoadFromAddress( Builder& b, const llr::VarBaseAddr& va );
extern void StoreToAddress( Builder& b, const llr::CalcAddress& addr, Z3Val&& val );
extern void StoreToAddress( Builder& b, const BaseAddress& baseAddr, Z3Val&& val );
extern void StoreToAddress( Builder& b, const llr::TemporaryBaseAddr& ta, Z3Val&& val );
extern void StoreToAddress( Builder& b, const llr::VarBaseAddr& va, Z3Val&& val );
extern void HavocAddress( Builder& b, uint32_t bbIndex, const Term& type, const llr::CalcAddress& addr );
}
#endif
|
Changes to bs/verify/value.cpp.
| ︙ | ︙ | |||
150 151 152 153 154 155 156 |
optional< Z3Val > BuildZ3Op( Builder& b, const T& instr )
{
return nullopt;
}
optional< Z3Val > BuildZ3Op( Builder& b, const Load& instr )
{
| | | | 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 |
optional< Z3Val > BuildZ3Op( Builder& b, const T& instr )
{
return nullopt;
}
optional< Z3Val > BuildZ3Op( Builder& b, const Load& instr )
{
return LoadFromAddress( b, FromValue< builtins::Reference >( instr.addr() )->address() );
}
optional< Z3Val > BuildZ3Op( Builder& b, const Store& instr )
{
if( auto zv = BuildZ3ExprFromValue( b, instr.val() ) )
StoreToAddress( b, FromValue< builtins::Reference >( instr.addr() )->address(), move( *zv ) );
return nullopt;
}
// Implemented in call.cpp
extern optional< Z3Val > BuildZ3Op( Builder& b, const Call& instr );
optional< Z3Val > BuildZ3Op( Builder& b, const CreateTemporary& instr )
|
| ︙ | ︙ |
Changes to tests/noprelude/verify/z3out-test-4.txt.
| ︙ | ︙ | |||
51 52 53 54 55 56 57 | (= b1 true) check_unsat (not (distinct v80 v81)) assume (> r79 0) check_unsat (not (distinct r79 0)) === End function verification trace === === Checking compilation-time call === | | | | 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | (= b1 true) check_unsat (not (distinct v80 v81)) assume (> r79 0) check_unsat (not (distinct r79 0)) === End function verification trace === === Checking compilation-time call === assume (= v84 5) check_unsat (not (distinct v84 0)) === Begin function verification trace === (= b1 true) === End function verification trace === |