Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | Fixed passing tuple by value to functions, which involved properly handling type checking of constant tuples containing computed data and some codegen bugs |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA3-256: |
9b8306c3afc8a7f062d7f9c85d488b78 |
| User & Date: | zlodo 2023-01-05 19:44:44.691 |
Context
|
2023-01-06
| ||
| 19:13 | Remove redundant calls to the ToType extension point when compiling function bodies check-in: 78a358141d user: zlodo tags: trunk | |
|
2023-01-05
| ||
| 19:44 | Fixed passing tuple by value to functions, which involved properly handling type checking of constant tuples containing computed data and some codegen bugs check-in: 9b8306c3af user: zlodo tags: trunk | |
|
2022-11-21
| ||
| 18:59 |
| |
Changes
Changes to bs/builtins/operators/assignment.cpp.
| ︙ | ︙ | |||
152 153 154 155 156 157 158 |
{
DiagnosticsManager::GetInstance().emitErrorMessage( 0, "incompatible tuple sizes." );
return PoisonValue();
}
// Store the source tuple as a temporary, otherwise we're going to recompute rhs
// for each member assigned (which is bad)
| | | 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
{
DiagnosticsManager::GetInstance().emitErrorMessage( 0, "incompatible tuple sizes." );
return PoisonValue();
}
// Store the source tuple as a temporary, otherwise we're going to recompute rhs
// for each member assigned (which is bad)
auto rhsIndex = util::GenerateNewUID();
cfg->currentBB()->append( rhs, CreateTemporary( rhsIndex, rhs.locationId() ) );
auto srcTup = BuildComputedValue( rhs.type(), GetTemporary( rhs.type(), rhsIndex, rhs.locationId() ) );
// Load the values from the rhs tuple into temporary vars.
vector< Value > tempVars;
tempVars.reserve( tupSize );
|
| ︙ | ︙ |
Changes to bs/builtins/operators/logic.cpp.
| ︙ | ︙ | |||
147 148 149 150 151 152 153 |
auto pSuccBB = cfg->createBB();
// If the lhs is true, skip to the end directly.
// Otherwise, jump to the BB that computes rhs.
predBB->append( lhs );
predBB->setTerminator( CondBranch( pSuccBB, pRhsBB ) );
| | | | 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 |
auto pSuccBB = cfg->createBB();
// If the lhs is true, skip to the end directly.
// Otherwise, jump to the BB that computes rhs.
predBB->append( lhs );
predBB->setTerminator( CondBranch( pSuccBB, pRhsBB ) );
auto rhsIndex = util::GenerateNewUID();
pRhsBB->append( rhs, CreateTemporary( rhsIndex, c.locationId() ) );
pRhsBB->setTerminator( Branch( pSuccBB ) );
auto resultIndex = util::GenerateNewUID();
// Build the Phi instruction that will collect the final result.
auto phi = Phi( *EIRToValue( GetValueType< bool >() ), 2,
resultIndex, c.locationId() );
// If coming directly from the lhs BB, we know the result is true.
phi.setIncoming( predBB, ToValue( true ) );
|
| ︙ | ︙ | |||
247 248 249 250 251 252 253 |
auto pSuccBB = cfg->createBB();
// If the lhs is false, skip to the end directly.
// Otherwise, jump to the BB that computes rhs.
predBB->append( lhs );
predBB->setTerminator( CondBranch( pRhsBB, pSuccBB ) );
| | | | 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 |
auto pSuccBB = cfg->createBB();
// If the lhs is false, skip to the end directly.
// Otherwise, jump to the BB that computes rhs.
predBB->append( lhs );
predBB->setTerminator( CondBranch( pRhsBB, pSuccBB ) );
auto rhsIndex = util::GenerateNewUID();
pRhsBB->append( rhs, CreateTemporary( rhsIndex, c.locationId() ) );
pRhsBB->setTerminator( Branch( pSuccBB ) );
auto resultIndex = util::GenerateNewUID();
// Build the Phi instruction that will collect the final result.
auto phi = Phi( *EIRToValue( GetValueType< bool >() ), 2,
resultIndex, c.locationId() );
// If coming directly from the lhs BB, we know the result is false.
phi.setIncoming( predBB, ToValue( false ) );
|
| ︙ | ︙ |
Changes to bs/builtins/types/func/build.cpp.
| ︙ | ︙ | |||
42 43 44 45 46 47 48 |
// 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( _ ),
ValueToEIR( BuildComputedValue( decl.type(),
| | | | 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 |
// 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( _ ),
ValueToEIR( BuildComputedValue( decl.type(),
cir::VarAddr( varId++, param.locationId() ),
cir::Load( decl.type(), param.locationId() ) ) ) );
}
else if( param.isConstant() )
tv->append( ValueToEIR( param ) );
return true;
} );
if( failed )
return nullopt;
// If the return type is non-void, expose @result under the verification identity as a computed value whose type
// is the function's return type, and the value is a placeholder cir instruction. This will allow verification
// expressions to refer to the current function's return value as a value of the correct type.
auto rtTerm = ValueToEIR( ToType( c, returnType ) );
if( rtTerm != GetValueType< void >() )
{
auto name = "@result"_sid;
auto retValVerificationIdentity = AppendToVectorTerm( verificationIdentity, TERM( name ) );
c.env()->storeValue( retValVerificationIdentity, ANYTERM( _ ),
ValueToEIR( BuildComputedValue( rtTerm, cir::Placeholder( rtTerm, name, returnType.locationId() ) ) ) );
|
| ︙ | ︙ |
Changes to bs/builtins/types/func/compile.cpp.
| ︙ | ︙ | |||
153 154 155 156 157 158 159 |
if( IsOpenTuple( declType ) )
{
auto packId = varId;
auto pack = EmptyClosedTuple();
ForEachInTuple( declType, [&]( auto&& type )
{
| | | > | | > > > > > > > | 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 |
if( IsOpenTuple( declType ) )
{
auto packId = varId;
auto pack = EmptyClosedTuple();
ForEachInTuple( declType, [&]( auto&& type )
{
auto t = ValueToEIR( ToType( c, type ) );
auto val = BuildComputedValue( t,
cir::VarAddr( varId++, type.locationId() ),
cir::Load( t, type.locationId() ) );
pack = AppendToTuple( pack, val );
return true;
} );
c.env()->storeValue( paramIdentity, ANYTERM( _ ),
ValueToEIR( pack ) );
cb->declareValue( pack, packId );
}
else
{
// Create a locvar to hold the param.
Term type;
if( f.type().kind() == FuncType::Kind::Intrinsic )
type = GetValueType< TypeWrapper< Value > >();
else
// TODO: we are calling the ToType extension point to convert a param that was already converted
// when building the function type! We can probably manage to reuse the already converted type
// and avoid this redundant call to ToType which is expensive
type = ValueToEIR( ToType( c, *EIRToValue( decl.type() ) ) );
LocalVar lv( decl.name(), move( type ), varId++ );
auto locVar = ToValue( lv ).setLocationId( param.locationId() );
c.env()->storeValue( paramIdentity, ANYTERM( _ ),
ValueToEIR( locVar ) );
cb->declareValue( locVar, lv.index() );
}
|
| ︙ | ︙ | |||
222 223 224 225 226 227 228 229 230 231 232 233 |
// 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::RetVoid( r->currentLocation() ) );
}
pFuncCIR->body() = cfg;
verify::Func fv( localContext, f );
return fv.verify();
}
}
| > | 230 231 232 233 234 235 236 237 238 239 240 241 242 |
// 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::RetVoid( r->currentLocation() ) );
}
ReindexVars( cfg );
pFuncCIR->body() = cfg;
verify::Func fv( localContext, f );
return fv.verify();
}
}
|
Changes to bs/builtins/types/func/functype.cpp.
| ︙ | ︙ | |||
92 93 94 95 96 97 98 |
{
auto av = make_shared< Vector >();
av->reserve( VecSize( ft.params() ) );
bool failed = false;
ForEachInVectorTerms( ft.params(), unifiedArgs, [&]( auto&& p, auto&& a )
{
| | | 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
{
auto av = make_shared< Vector >();
av->reserve( VecSize( ft.params() ) );
bool failed = false;
ForEachInVectorTerms( ft.params(), unifiedArgs, [&]( auto&& p, auto&& a )
{
auto vp = EIRToValuePattern( p );
if( vp->val() == HOLE( "_"_sid ) )
{
auto arg = *EIRToValue( a );
auto convertedArg = InvokeOverloadSet( c, c.env()->extConvertFuncArg(),
MakeClosedTuple( arg, *EIRToValue( vp->type() ) ) );
if( convertedArg.isPoison() )
{
|
| ︙ | ︙ | |||
128 129 130 131 132 133 134 |
auto pCBWrapper = ToValue( TypeWrapper< ptr< Context > >( make_shared< Context >( c ) ) );
av->append( ValueToEIR( pCBWrapper ) );
bool failed = false;
ForEachInVectorTerms( ft.params(), typeCheckedArgs, [&]( auto&& p, auto&& a )
{
| | | 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
auto pCBWrapper = ToValue( TypeWrapper< ptr< Context > >( make_shared< Context >( c ) ) );
av->append( ValueToEIR( pCBWrapper ) );
bool failed = false;
ForEachInVectorTerms( ft.params(), typeCheckedArgs, [&]( auto&& p, auto&& a )
{
auto vp = EIRToValuePattern( p );
if( vp->val() == HOLE( "_"_sid ) )
{
auto wrappedArg = ToValue( TypeWrapper< Value >( *EIRToValue( a ) ) );
av->append( ValueToEIR( wrappedArg ) );
}
return true;
|
| ︙ | ︙ |
Changes to bs/builtins/types/func/invocation/func.cpp.
| ︙ | ︙ | |||
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
auto result = BuildComputedValue( typeCheckedRType, argsInstrSeq, preparedCallee,
cir::Call( argCount, loc ) );
if( result.type() != GetValueType< void >() && !IsExternalFunc( callee ) )
{
if( cir::CanValueBeEagerlyEvaluated( result ) )
{
if( !verify::VerifyInstrSeq( c, *result.cir() ) )
return PoisonValue();
execute::VM vm;
result = execute::Evaluate( result, vm );
}
// Register the result for destruction.
if( auto cfg = GetCFG( c ) )
| > > > > > > > > > > > > | | 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 |
auto result = BuildComputedValue( typeCheckedRType, argsInstrSeq, preparedCallee,
cir::Call( argCount, loc ) );
if( result.type() != GetValueType< void >() && !IsExternalFunc( callee ) )
{
if( cir::CanValueBeEagerlyEvaluated( result ) )
{
// Backup the value's instr seq: we need to reindex it to verify it,
// but if the evaluation into a constant doesn't pan out, we need to restore
// it so that any contained var uid gets reindexed as part of the whole cfg
// later.
auto savedInstrSeq = result.cir();
result.setCIR( make_shared< cir::InstrSeq >( *savedInstrSeq ) );
ReindexVars( *result.cir() );
if( !verify::VerifyInstrSeq( c, *result.cir() ) )
return PoisonValue();
execute::VM vm;
result = execute::Evaluate( result, vm );
if( !result.isConstant() )
result.setCIR( move( savedInstrSeq ) );
}
// Register the result for destruction.
if( auto cfg = GetCFG( c ) )
DeclareValue( c, result, util::GenerateNewUID() );
}
return result;
}
Value prepareFunc( const Context& c, LocationId funcValLocation, const Value& callee, const Term& typeCheckedCallPat, TypeCheckingContext& tcc ) const final
{
|
| ︙ | ︙ |
Changes to bs/builtins/types/func/invocation/intrinsic.cpp.
| ︙ | ︙ | |||
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
auto ft = *FromValue< FuncType >( *EIRToValue( preparedCallee.type() ) );
// Intrinsic call: we insert the context wrapper as first param,
// wrap all args with TypeWrapper< Value >, and execute the function directly.
auto argList = BuildArgListForIntrinsicCall( c, ft, typeCheckedArgs );
if( !argList )
return PoisonValue();
auto argsInstrSeq = BuildArgsInstrSeq( *argList );
auto argCount = VecSize( *argList );
execute::VM vm;
cir::InstrSeq is;
AppendToInstrSeq( is, argsInstrSeq, preparedCallee, cir::Call( argCount, loc ) );
if( !vm.execute( is ) )
return PoisonValue();
if( ft.returnType() == GetValueType< void >() )
return Value( GetValueType< void >(), 0U );
auto result = vm.pop();
if( !result )
| > > > | 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
auto ft = *FromValue< FuncType >( *EIRToValue( preparedCallee.type() ) );
// Intrinsic call: we insert the context wrapper as first param,
// wrap all args with TypeWrapper< Value >, and execute the function directly.
auto argList = BuildArgListForIntrinsicCall( c, ft, typeCheckedArgs );
if( !argList )
return PoisonValue();
auto argsInstrSeq = BuildArgsInstrSeq( *argList );
auto argCount = VecSize( *argList );
execute::VM vm;
cir::InstrSeq is;
AppendToInstrSeq( is, argsInstrSeq, preparedCallee, cir::Call( argCount, loc ) );
ReindexVars( is );
if( !vm.execute( is ) )
return PoisonValue();
if( ft.returnType() == GetValueType< void >() )
return Value( GetValueType< void >(), 0U );
auto result = vm.pop();
if( !result )
|
| ︙ | ︙ |
Changes to bs/builtins/types/func/lower.cpp.
| ︙ | ︙ | |||
28 29 30 31 32 33 34 |
ForEachInVectorTerm( ft.params(), [&]( auto&& p )
{
// Params are not stored explicitely, but as patterns
// for expediency (where the value is either a hole or an actual
// value depending on whether this is a specialization param),
// which is useful in most places except here as we need to extract
// back the type from the pattern (and skip specialization params).
| | | 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
ForEachInVectorTerm( ft.params(), [&]( auto&& p )
{
// Params are not stored explicitely, but as patterns
// for expediency (where the value is either a hole or an actual
// value depending on whether this is a specialization param),
// which is useful in most places except here as we need to extract
// back the type from the pattern (and skip specialization params).
auto vp = EIRToValuePattern( p );
if( !vp )
{
success = false;
return false;
}
if( vp->val() == HOLE( "_"_sid ) )
|
| ︙ | ︙ |
Changes to bs/builtins/types/func/typecheck.cpp.
| ︙ | ︙ | |||
20 21 22 23 24 25 26 |
ValueToEIR( ValuePattern(
ANYTERM( _ ),
ANYTERM( _ ),
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
{
| | | | | | 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 |
ValueToEIR( ValuePattern(
ANYTERM( _ ),
ANYTERM( _ ),
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
{
auto lhsVal = *EIRToValuePattern( lhs );
lhsVal.sort() = HOLE( "_"_sid );
co_yield TypeCheck( ValueToEIR( lhsVal ), rhs, tcc );
} );
// Constant param rule
e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,
ValueToEIR( ValuePattern(
TSID( constant ),
ANYTERM( _ ),
ANYTERM( _ ) ) ),
ValueToEIR( ValuePattern(
TSID( constant ),
ANYTERM( _ ),
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
{
auto lhsVal = *EIRToValuePattern( lhs );
auto rhsVal = *EIRToValuePattern( rhs );
// Check the types
for( auto&& [ut,tcc] : TypeCheck( lhsVal.type(), rhsVal.type(), tcc ) )
{
// Check the contents
for( auto&& [uv,tcc] : TypeCheck( lhsVal.val(), rhsVal.val(), tcc ) )
{
ValuePattern result( TSID( constant ), move( ut ), move( uv ), rhsVal.locationId() );
co_yield { ValueToEIR( move( result ) ), tcc };
}
}
} );
// func type param / func arg
e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,
|
| ︙ | ︙ |
Changes to bs/builtins/types/localvar/localvar.cpp.
| ︙ | ︙ | |||
21 22 23 24 25 26 27 |
Value DeclareLocalVar( const Context& c, const Term& type, StringId name, const optional< Value >& initializer, LocationId locId )
{
auto cfg = GetCFG( c );
if( !cfg )
return PoisonValue();
| | | 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
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 = util::GenerateNewUID();
auto bb = cfg->currentBB();
if( !bb )
return PoisonValue();
Value typeVal = *EIRToValue( type );
if( !typeVal.isType() )
|
| ︙ | ︙ | |||
174 175 176 177 178 179 180 |
);
auto&& [type, initializer] = *callDecomp;
if( !ParseTypePredicates( c, *EIRToValue( type ) ) )
return PoisonValue();
| | | 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 |
);
auto&& [type, initializer] = *callDecomp;
if( !ParseTypePredicates( c, *EIRToValue( type ) ) )
return PoisonValue();
auto index = util::GenerateNewUID();
// Retrieve the texpr's location and set it on the inferred type. This way if an
// error occurs later with it, for instance when calling LowerTypeForRuntime on it during codegen,
// it will have a meaningful location for the error message to attach itself on.
auto typeLoc = EIRToValue( typeTExpr )->locationId();
LocalVar lv( name, type, index );
|
| ︙ | ︙ |
Changes to bs/builtins/types/localvar/typecheck.cpp.
| ︙ | ︙ | |||
18 19 20 21 22 23 24 |
ValueToEIR( ValuePattern(
ANYTERM( _ ),
localVarPattern,
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
{
| | | | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
ValueToEIR( ValuePattern(
ANYTERM( _ ),
localVarPattern,
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
{
auto lvarType = *FromValue< LocalVarType >( *EIRToValue( EIRToValuePattern( lhs )->type() ) );
auto rhsVal = *EIRToValuePattern( rhs );
auto rvarType = *FromValue< LocalVarType >( *EIRToValue( rhsVal.type() ) );
for( auto&& [s, tcc] : Unify( lvarType.type(), rvarType.type(), tcc ) )
{
co_yield { ValueToEIR( Value( ValueToEIR( ToValue( LocalVarType( s ) ) ),
rhsVal.val() ).setLocationId( rhsVal.locationId() ) ), tcc };
}
|
| ︙ | ︙ |
Changes to bs/builtins/types/param.h.
| ︙ | ︙ | |||
16 17 18 19 20 21 22 |
template< typename T >
auto ParamPat( T&& type )
{
// If the type is a tuple of type, convert it to the type of a tuple.
// (the type of a tuple is just a list of values, so just extract the value part of the tuple)
if( auto typeVal = EIRToValue( type ); typeVal && IsTuple( *typeVal ) )
| | | 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
template< typename T >
auto ParamPat( T&& type )
{
// If the type is a tuple of type, convert it to the type of a tuple.
// (the type of a tuple is just a list of values, so just extract the value part of the tuple)
if( auto typeVal = EIRToValue( type ); typeVal && IsTuple( *typeVal ) )
return ValueToEIR( ValuePattern( TSID( param ), ValueToEIR( TupleOfTypesToTupleType( *typeVal ) ), HOLE( "_"_sid ) ) );
return ValueToEIR( ValuePattern( TSID( param ), forward< T >( type ), HOLE( "_"_sid ) ) );
}
// This special param pattern forces the argument to be passed as is without any typechecking.
struct ForwarderPattern
{
|
| ︙ | ︙ |
Changes to bs/builtins/types/pretty.cpp.
| ︙ | ︙ | |||
58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
ANYTERM( _ ) ) ),
[&]( auto&& out, auto&& t )
{
auto decl = *FromValue< Decl >( *EIRToValue( t ) );
out << "decl(" << decl.type() << ", " << decl.name() << ")";
return true;
} );
pp.addRule( GetValueType< bool >(), [&]( auto&& out, auto&& t ) { out << "bool"; return true; } );
pp.addRule( MkStdType( TSID( rt_type ), TSID( bool ) ), [&]( auto&& out, auto&& t ) { out << "bool"; return true; } );
pp.addRule( GetValueType< string >(), [&]( auto&& out, auto&& t ) { out << "ct_string"; return true; } );
pp.addRule( MkStdType( TSID( ct_type ), TSID( ct_string ) ), [&]( auto&& out, auto&& t ) { out << "ct_string"; return true; } );
| > > > > > > > > > > > > > | 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 |
ANYTERM( _ ) ) ),
[&]( auto&& out, auto&& t )
{
auto decl = *FromValue< Decl >( *EIRToValue( t ) );
out << "decl(" << decl.type() << ", " << decl.name() << ")";
return true;
} );
pp.addRule( ValueToEIR( ValuePattern( TSID( param ), ANYTERM(_), ANYTERM(_) ) ),
[&]( auto&& out, auto&& t )
{
auto v = *EIRToValuePattern( t );
auto ty = EIRToValue( v.type() );
out << "param[ ";
pp.print( out, ty ? ty->val() : v.type() );
out << " ]{ ";
pp.print( out, v.val() );
out << " }";
return true;
} );
pp.addRule( GetValueType< bool >(), [&]( auto&& out, auto&& t ) { out << "bool"; return true; } );
pp.addRule( MkStdType( TSID( rt_type ), TSID( bool ) ), [&]( auto&& out, auto&& t ) { out << "bool"; return true; } );
pp.addRule( GetValueType< string >(), [&]( auto&& out, auto&& t ) { out << "ct_string"; return true; } );
pp.addRule( MkStdType( TSID( ct_type ), TSID( ct_string ) ), [&]( auto&& out, auto&& t ) { out << "ct_string"; return true; } );
|
| ︙ | ︙ |
Changes to bs/builtins/types/reference/reference.cpp.
| ︙ | ︙ | |||
51 52 53 54 55 56 57 |
return pattern;
}
// Returns an instruction that computes the address of whatever's contained in the locvar.
cir::Instruction GetAddrFromLocalVar( const LocalVar& lv )
{
// TODO LOC: may need loc in LocalVar
| | | | 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
return pattern;
}
// Returns an instruction that computes the address of whatever's contained in the locvar.
cir::Instruction GetAddrFromLocalVar( const LocalVar& lv )
{
// TODO LOC: may need loc in LocalVar
return cir::VarAddr( lv.index(), {} );
}
Value BuildLocalVarMutRef( const LocalVar& lv )
{
// TODO LOC: may need loc in LocalVar
auto rt = ValueToEIR( ToValue( ReferenceType{ lv.type(), MutAccessSpecifer() } ) );
return BuildComputedValue( move( rt ), cir::VarAddr( lv.index(), {} ) );
}
const Term& MutAccessSpecifer()
{
static auto al = ValueToEIR( ToValue( AccessSpecifier( "mut"_sid ) ) );
return al;
}
|
| ︙ | ︙ |
Changes to bs/builtins/types/reference/typecheck.cpp.
| ︙ | ︙ | |||
25 26 27 28 29 30 31 |
// 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 )
{
| | | 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
// 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( EIRToValuePattern( lhs )->type() ) );
if( lRefType.behavior() == MutAccessSpecifer() )
co_return;
auto lhsPat = ValueToEIR( ValuePattern( TSID( param ), lRefType.type(), HOLE( "_"_sid ) ) );
for( auto&& [s,tcc] : TypeCheck( lhsPat, rhs, tcc ) )
|
| ︙ | ︙ | |||
58 59 60 61 62 63 64 |
auto cfg = GetCFG( tcc.context() );
if( !cfg )
return nullopt;
// TODO create an ext point for this
auto loc = rhsVal.locationId();
| | | 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
auto cfg = GetCFG( tcc.context() );
if( !cfg )
return nullopt;
// TODO create an ext point for this
auto loc = rhsVal.locationId();
auto tempIndex = util::GenerateNewUID();
return ValueToEIR( BuildComputedValue( ValueToEIR( ToValue( rt ) ), rhsVal,
TempAddr( tempIndex, loc ) ).setLocationId( loc ) );
} );
// Override the weight because we don't want
// this solution to count more than directly using
// the value without wrapping it into a tempref
|
| ︙ | ︙ | |||
105 106 107 108 109 110 111 |
ValueToEIR( ValuePattern(
ANYTERM( _ ),
refTypePattern,
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
{
| | | | 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
ValueToEIR( ValuePattern(
ANYTERM( _ ),
refTypePattern,
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
{
auto lRefType = *FromValue< ReferenceType >( *EIRToValue( EIRToValuePattern( lhs )->type() ) );
auto rhsVal = *EIRToValuePattern( rhs );
auto rRefType = *FromValue< ReferenceType >( *EIRToValue( rhsVal.type() ) );
// Type check the behaviors
for( auto&& [b, tcc] : TypeCheck( lRefType.behavior(), rRefType.behavior(), tcc ) )
{
// Check the types
for( auto&& [t, tcc] : TypeCheck( lRefType.type(), rRefType.type(), tcc ) )
|
| ︙ | ︙ | |||
226 227 228 229 230 231 232 |
ValueToEIR( ValuePattern(
ANYTERM( _ ),
localVarPattern,
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
{
| | | 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 |
ValueToEIR( ValuePattern(
ANYTERM( _ ),
localVarPattern,
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
{
auto ltype = EIRToValuePattern( lhs )->type();
auto lvval = *EIRToValue( rhs );
auto locvar = FromValue< LocalVar >( lvval );
if( !locvar )
co_return;
auto ref = ValueToEIR( ToValue( BuildLocalVarMutRef( *locvar ) )
|
| ︙ | ︙ | |||
252 253 254 255 256 257 258 |
ValueToEIR( ValuePattern(
ANYTERM( _ ),
refRefTypePattern,
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
{
| | | 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 |
ValueToEIR( ValuePattern(
ANYTERM( _ ),
refRefTypePattern,
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
{
auto ltype = EIRToValuePattern( lhs )->type();
auto rrefVal = *EIRToValue( rhs );
auto rrType = FromValue< ReferenceType >( *EIRToValue( rrefVal.type() ) );
if( !rrType )
co_return;
auto loc = rrefVal.locationId();
|
| ︙ | ︙ |
Changes to bs/builtins/types/runtime/typecheck.cpp.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#include "builtins/builtins.h"
using namespace goose;
using namespace goose::eir;
namespace goose::builtins
{
void SetupRuntimeTypesChecking( Env& e )
{
auto rtIntTypePattern = Value( TypeType(), MkStdType( TSID( rt_type ), TSID( integer ),
VEC( ANYTERM( _ ), ANYTERM( _ ) ) ) );
// Conversion rule for ct_int to runtime int:
// we verify that the ct_int fits in the bitsize/signage
| > > > > > > > > > > > > | 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 |
#include "builtins/builtins.h"
using namespace goose;
using namespace goose::eir;
namespace goose::builtins
{
// TODO: converting a computed ct_int to a rt int is legit in compile time code.
// Consider this:
// var someTuple = (123,456)
// void someCompileTimeFunc( ( uint(32), uint(32) tup )
// Can't perform a compile time to someCompileTimeFunc with someTuple as the later contains computed ct_ints
// So we need to allow this conversion, but only at compile time. Perhaps emit the conversion as a call to a compile time conversion
// func, which therefore would fail when compiling because the ct_int wouldn't be able to be lowered to a runtime type?
// (we'd also need to emit asserton checks for the ct_int bounds)
// Probably something to do in the prelude.
void SetupRuntimeTypesChecking( Env& e )
{
auto rtIntTypePattern = Value( TypeType(), MkStdType( TSID( rt_type ), TSID( integer ),
VEC( ANYTERM( _ ), ANYTERM( _ ) ) ) );
// Conversion rule for ct_int to runtime int:
// we verify that the ct_int fits in the bitsize/signage
|
| ︙ | ︙ | |||
32 33 34 35 36 37 38 |
// It means that we are unifying a function parameter against any ct_int value,
// which we can't (because we have to know the value to safely convert it),
// so we reject it.
auto rhsVal = *EIRToValue( rhs );
if( !rhsVal.isConstant() )
co_return;
| | | 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
// It means that we are unifying a function parameter against any ct_int value,
// which we can't (because we have to know the value to safely convert it),
// so we reject it.
auto rhsVal = *EIRToValue( rhs );
if( !rhsVal.isConstant() )
co_return;
auto lhsVal = EIRToValuePattern( lhs );
if( !lhsVal )
co_return;
auto s = HalfUnify( lhsVal->type(), tcc );
if( !s )
co_return;
|
| ︙ | ︙ | |||
117 118 119 120 121 122 123 |
ValueToEIR( ValuePattern(
ANYTERM( _ ),
GetValueType< NullPointer >(),
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& c ) -> TCGen
{
| | | 129 130 131 132 133 134 135 136 137 138 139 140 |
ValueToEIR( ValuePattern(
ANYTERM( _ ),
GetValueType< NullPointer >(),
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& c ) -> TCGen
{
auto lVal = *EIRToValuePattern( lhs );
co_yield { ValueToEIR( Value( lVal.type(), 0U ) ), c };
} );
}
}
|
Changes to bs/builtins/types/template/rules/tuple.cpp.
| ︙ | ︙ | |||
48 49 50 51 52 53 54 |
}
else
v->append( t );
return true;
} );
| | | | 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 |
}
else
v->append( t );
return true;
} );
return ValueToEIR( ValuePattern( TSID( constant ), ValueToEIR( MkTupleType( TSID( closed ), HOLE( "_"_sid ) ) ), v ) );
}
Generator< Value > buildParamDecls( const Context& c, const Term& param, TermGen& args ) const final
{
co_yield *EIRToValue( *args.consume() );
}
void setup( const Context& c, TypeCheckingContext& tcc, const Term& t ) const final
{
auto tup = *EIRToValue( t );
ForEachTermInTuple( tup, [&]( auto&& t )
{
TemplateSetup( c, tcc, t );
return true;
} );
}
uint64_t hashTypePredicates( const Context& c, const TypeCheckingContext& tcc, const Term& t ) const final
{
auto tup = EIRToValuePattern( t );
auto vec = get< pvec >( tup->val() );
assert( vec );
auto g = ContainerTypePredicatesHashGenerator( c, tcc, vec->terms() );
return llvm::hash_combine_range( g.begin(), g.end() );
}
|
| ︙ | ︙ | |||
97 98 99 100 101 102 103 |
}
else
v->append( t );
return true;
} );
| | | 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
}
else
v->append( t );
return true;
} );
return ValueToEIR( ValuePattern( TSID( constant ), ValueToEIR( MkTupleType( TSID( closed ), HOLE( "_"_sid ) ) ), v ) );
}
bool isPackExpr( const Context& c, const Term& val ) const final
{
return false;
}
};
|
| ︙ | ︙ |
Changes to bs/builtins/types/template/rules/tvectype.cpp.
1 2 3 4 5 6 7 8 |
#include "builtins/builtins.h"
namespace goose::builtins
{
class TVecTypeTemplateRule : public TemplateRule
{
bool prepare( TemplateContext& c, const Term& t ) const final
{
| | | | | | | | | | 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 |
#include "builtins/builtins.h"
namespace goose::builtins
{
class TVecTypeTemplateRule : public TemplateRule
{
bool prepare( TemplateContext& c, const Term& t ) const final
{
auto tvecType = EIRToValuePattern( t );
auto tvec = TVecFromEIR( tvecType->val() );
assert( tvec );
for( auto&& x : tvec->content()->terms() )
{
// TVec is a way to substitute a Vec for a TVec when building a type representation
// to easily make TExpr versions of complex types without having to handle them specifically.
// However, it's still a fixed structuring element, we don't want to allow packs in there.
if( IsTemplatePackExpr( c.semaContext(), x ) )
{
DiagnosticsManager::GetInstance().emitErrorMessage( EIRToValue( x )->locationId(),
"pack expressions aren't allowed here." );
return false;
}
if( !PrepareTemplate( c, x ) )
return false;
}
return true;
}
optional< Term > buildSignature( const TemplateContext& c, const Term& t ) const final
{
auto tvecType = EIRToValuePattern( t );
auto tvec = TVecFromEIR( tvecType->val() );
assert( tvec );
auto v = make_shared< Vector >();
v->reserve( tvec->content()->terms().size() );
for( auto&& x : tvec->content()->terms() )
{
if( auto s = BuildTemplateSignature( c, x ) )
v->append( move( *s ) );
else
v->append( x );
}
return ValueToEIR( ValuePattern( TSID( constant ), TypeType(), v ) );
}
Generator< Value > buildParamDecls( const Context& c, const Term& param, TermGen& args ) const final
{
co_yield *EIRToValue( *args.consume() );
}
void setup( const Context& c, TypeCheckingContext& tcc, const Term& t ) const final
{
auto tvecType = EIRToValuePattern( t );
auto tvec = TVecFromEIR( tvecType->val() );
assert( tvec );
for( auto&& x : tvec->content()->terms() )
TemplateSetup( c, tcc, x );
}
uint64_t hashTypePredicates( const Context& c, const TypeCheckingContext& tcc, const Term& t ) const final
{
auto tvecType = EIRToValuePattern( t );
auto tvec = TVecFromEIR( tvecType->val() );
assert( tvec );
auto g = ContainerTypePredicatesHashGenerator( c, tcc, tvec->content()->terms() );
return llvm::hash_combine_range( g.begin(), g.end() );
}
optional< Term > buildArgPattern( const Context& c, const Term& t ) const final
{
auto tvecType = EIRToValuePattern( t );
auto tvec = TVecFromEIR( tvecType->val() );
assert( tvec );
auto v = make_shared< Vector >();
v->reserve( tvec->content()->terms().size() );
for( auto&& x : tvec->content()->terms() )
{
auto s = BuildTemplateArgPattern( c, x );
if( s )
v->append( move( *s ) );
else
v->append( x );
}
return ValueToEIR( ValuePattern( TSID( constant ), TypeType(), v ) );
}
bool isPackExpr( const Context& c, const Term& val ) const final
{
return false;
}
};
|
| ︙ | ︙ |
Changes to bs/builtins/types/tuple/tuple.cpp.
| ︙ | ︙ | |||
81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
ConcatenateVectorTerms( ltup.val(), rtup.val() ) );
if( ltup.isPoison() || rtup.isPoison() )
result.setPoison();
return result;
}
bool IsTuple( const Value& t )
{
auto typeVal = EIRToValue( t.type() );
if( !typeVal || !typeVal->isConstant() )
return false;
| > > > > > > > > > > > > > > > > | 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 |
ConcatenateVectorTerms( ltup.val(), rtup.val() ) );
if( ltup.isPoison() || rtup.isPoison() )
result.setPoison();
return result;
}
Value VectorToTuple( const Term& state, const pvec& vec )
{
auto types = make_shared< Vector >();
types->reserve( vec->terms().size() );
for( auto&& t : vec->terms() )
{
auto val = EIRToValue( t );
assert( val );
types->append( val->type() );
}
return Value(
ValueToEIR( MkTupleType( state, TERM( move( types ) ) ) ), vec );
}
bool IsTuple( const Value& t )
{
auto typeVal = EIRToValue( t.type() );
if( !typeVal || !typeVal->isConstant() )
return false;
|
| ︙ | ︙ |
Changes to bs/builtins/types/tuple/tuple.h.
| ︙ | ︙ | |||
13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
extern const Value& EmptyClosedTuple();
extern Value AppendToTuple( const Value& tup, const Value& val );
extern Value AppendToTuple( const Value& tup, const ValuePattern& valPat );
extern Value PrependToTuple( const Value& val, const Value& tup );
extern Value ConcatenateTuples( const Value& ltup, const Value& rtup );
template< typename... V >
Value MakeClosedTuple( V&&... values );
template< typename... V >
Value MakeOpenTuple( V&&... values );
| > > | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
extern const Value& EmptyClosedTuple();
extern Value AppendToTuple( const Value& tup, const Value& val );
extern Value AppendToTuple( const Value& tup, const ValuePattern& valPat );
extern Value PrependToTuple( const Value& val, const Value& tup );
extern Value ConcatenateTuples( const Value& ltup, const Value& rtup );
extern Value VectorToTuple( const Term& state, const pvec& vec );
template< typename... V >
Value MakeClosedTuple( V&&... values );
template< typename... V >
Value MakeOpenTuple( V&&... values );
|
| ︙ | ︙ |
Changes to bs/builtins/types/tuple/typecheck.cpp.
1 2 3 4 5 6 7 |
#include "builtins/builtins.h"
using namespace goose;
using namespace goose::eir;
namespace goose::builtins
{
| > | | | < < | > > | | > | > > > > > > | | > > | > | > > > | > | | > > > > > > > > > > | > | > > > > > > > > > | > | | > > | > | | | | < > < | < > | | > | < > | > | > > > | | < < < | > > > | | 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 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 |
#include "builtins/builtins.h"
using namespace goose;
using namespace goose::eir;
using namespace goose::cir;
namespace goose::builtins
{
Value BuildComputedTuple( const pvec& elems, bool closed, LocationId locationId )
{
auto types = make_shared< Vector >();
types->reserve( elems->terms().size() );
auto tupTempUID = util::GenerateNewUID();
InstrSeq is;
uint32_t elemIndex = 0;
for( auto&& t : elems->terms() )
{
auto val = EIRToValue( t );
assert( val );
types->append( val->type() );
AppendToInstrSeq( is,
VarAddr( tupTempUID, locationId ),
Select( elemIndex++, val->locationId() ),
*val,
Store( move( val->type() ), val->locationId(), locationId )
);
}
auto tupType = MkTupleType( closed ? TSID( closed ) : TSID( open ), TERM( move( types ) ) );
auto tupTypeTerm = ValueToEIR( tupType );
auto tupIS = make_shared< InstrSeq >();
AppendToInstrSeq( *tupIS, AllocVar( move( tupType ), tupTempUID, locationId ) );
AppendToInstrSeq( *tupIS, move( is ) );
AppendToInstrSeq( *tupIS, GetTemporary( tupTypeTerm, tupTempUID, locationId ) );
return Value( move( tupTypeTerm ), move( tupIS ) );
}
TCGen TypeCheckTuple( const TypeCheckingContext& tcc, const Value& tupType, pvec args, uint32_t index, bool isComputed, const pvec& out, bool closed, LocationId loc )
{
auto param = ParamPat( GetTupleTypeElement( tupType, index ) );
auto tupSize = args->terms().size();
for( auto&& [s,tcc] : TypeCheck( param, args->terms()[index], tcc ) )
{
if( !EIRToValue( s )->isConstant() )
isComputed = true;
auto newOut = make_shared< Vector >( Vector::MakeAppend( *out, move( s ) ) );
if( index == ( tupSize - 1 ) )
{
if( isComputed )
co_yield { ValueToEIR( BuildComputedTuple( newOut, closed, loc ) ), tcc };
else
co_yield { ValueToEIR( VectorToTuple( closed ? TSID( closed ) : TSID( open ), newOut ).setLocationId( loc ) ), tcc };
}
else
co_yield TypeCheckTuple( tcc, tupType, args, index + 1, isComputed, newOut, closed, loc );
}
}
TCGen TypeCheckConstantTuple( const TypeCheckingContext& tcc, const Value& tupType, const Value& tupArg, const pvec& out, bool closed )
{
auto argVec = get< pvec >( tupArg.val() );
co_yield TypeCheckTuple( tcc, tupType, argVec, 0, false, out, closed, tupArg.locationId() );
}
TCGen TypeCheckComputedTuple( const TypeCheckingContext& tcc, const Value& tupType, const Value& tupArg, const Value& tupArgRef, const pvec& out, bool closed )
{
G_VAL_ASSERT( tupArgRef, !tupArgRef.isConstant() );
auto argRefs = make_shared< Vector >();
argRefs->reserve( TupleSize( tupArg ) );
uint32_t index = 0;
ForEachInTupleType( *EIRToValue( tupArg.type() ), [&]( auto&& type )
{
ReferenceType rt( type, ConstAccessSpecifer() );
auto argRef = ValueToEIR( BuildComputedValue( ValueToEIR( ToValue( rt ) ),
tupArgRef, cir::Select( index++, tupArg.locationId() ) ) );
argRefs->append( move( argRef ) );
return true;
} );
co_yield TypeCheckTuple( tcc, tupType, argRefs, 0, true, out, closed, tupArg.locationId() );
}
void SetupTupleTypeChecking( Env& e )
{
e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,
ValueToEIR( ValuePattern(
ANYTERM( _ ),
ValueToEIR( MkTupleType( ANYTERM( S ), VECOFLENGTH( L ) ) ),
ANYTERM( _ ) ) ),
ValueToEIR( ValuePattern(
TSID( constant ),
ValueToEIR( MkTupleType( ANYTERM( S ), VECOFLENGTH( L ) ) ),
VECOFLENGTH( L ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
{
auto ltup = EIRToValuePattern( lhs );
auto rtup = EIRToValue( rhs );
if( !ltup || !rtup )
co_return;
auto tupType = *EIRToValue( ltup->type() );
auto out = make_shared< Vector >();
out->reserve( TupleSize( *rtup ) );
co_yield TypeCheckConstantTuple( tcc, tupType, *rtup, out, !IsOpenTuple( *rtup ) );
} );
e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,
ValueToEIR( ValuePattern(
ANYTERM( _ ),
ValueToEIR( MkTupleType( ANYTERM( S ), VECOFLENGTH( L ) ) ),
ANYTERM( _ ) ) ),
ValueToEIR( ValuePattern(
TSID( computed ),
ValueToEIR( MkTupleType( ANYTERM( S ), VECOFLENGTH( L ) ) ),
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
{
auto ltup = EIRToValuePattern( lhs );
auto rtup = EIRToValue( rhs );
if( !ltup || !rtup )
co_return;
auto cfg = GetCFG( tcc.context() );
if( !cfg )
co_return;
auto tupType = *EIRToValue( ltup->type() );
auto tempIndex = util::GenerateNewUID();
auto rtupref = BuildComputedValue( ValueToEIR( ToValue( ReferenceType{ rtup->type(), ConstAccessSpecifer() } ) ),
*rtup, cir::TempAddr( tempIndex, rtup->locationId() ) );
auto out = make_shared< Vector >();
out->reserve( TupleSize( *rtup ) );
co_yield TypeCheckComputedTuple( tcc, tupType, *rtup, rtupref, out, !IsOpenTuple( *rtup ) );
} );
// 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,
ValueToEIR( ValuePattern(
|
| ︙ | ︙ |
Changes to bs/builtins/types/types.cpp.
| ︙ | ︙ | |||
105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
}
return *boolRes;
}
Value ToType( const Context& c, const Value& v )
{
auto result = InvokeOverloadSet( c,
c.env()->extToType(),
MakeClosedTuple( v ) );
if( result.isPoison() )
{
PoisonBuilder( c );
| > > > | 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
}
return *boolRes;
}
Value ToType( const Context& c, const Value& v )
{
if( v.isType() )
return v;
auto result = InvokeOverloadSet( c,
c.env()->extToType(),
MakeClosedTuple( v ) );
if( result.isPoison() )
{
PoisonBuilder( c );
|
| ︙ | ︙ |
Changes to bs/cir/allocvar.h.
| ︙ | ︙ | |||
11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
BaseInstr( loc ),
m_type( forward< T >( type ) ),
m_index( index )
{}
const auto& type() const { return m_type; }
const auto& index() const { return m_index; }
bool canBeExecuted() const { return true; }
bool canBeEagerlyEvaluated() const { return false; }
bool haveSideEffects() const { return true; }
bool operator<( const AllocVar& rhs ) const
{
| > | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
BaseInstr( loc ),
m_type( forward< T >( type ) ),
m_index( index )
{}
const auto& type() const { return m_type; }
const auto& index() const { return m_index; }
void setIndex( uint32_t index ) { m_index = index; }
bool canBeExecuted() const { return true; }
bool canBeEagerlyEvaluated() const { return false; }
bool haveSideEffects() const { return true; }
bool operator<( const AllocVar& rhs ) const
{
|
| ︙ | ︙ |
Changes to bs/cir/basicblock.h.
| ︙ | ︙ | |||
48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
auto* llvmBB() { return m_llvmBB; }
void setLLVMBB( llvm::BasicBlock* pBB ) { m_llvmBB = pBB; }
auto empty() const { return m_instructions.empty(); }
const auto& instructions() const { return m_instructions; }
using RunnableInstructions = llvm::SmallVector< Instruction, 16 >;
const RunnableInstructions* runnableInstructions() const
{
if( m_dirty )
{
m_dirty = false;
| > | 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
auto* llvmBB() { return m_llvmBB; }
void setLLVMBB( llvm::BasicBlock* pBB ) { m_llvmBB = pBB; }
auto empty() const { return m_instructions.empty(); }
const auto& instructions() const { return m_instructions; }
auto& instructions() { return m_instructions; }
using RunnableInstructions = llvm::SmallVector< Instruction, 16 >;
const RunnableInstructions* runnableInstructions() const
{
if( m_dirty )
{
m_dirty = false;
|
| ︙ | ︙ | |||
81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
m_dirty = true;
}
template< typename T >
void setTerminator( T&& terminator );
const auto& terminator() const { return m_terminator; }
bool canBeExecuted() const
{
return m_canBeExecuted
&& ( !m_terminator || m_terminator->canBeExecuted() );
}
| > > | 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
m_dirty = true;
}
template< typename T >
void setTerminator( T&& terminator );
const auto& terminator() const { return m_terminator; }
void dirty() { m_dirty = true; }
bool canBeExecuted() const
{
return m_canBeExecuted
&& ( !m_terminator || m_terminator->canBeExecuted() );
}
|
| ︙ | ︙ |
Changes to bs/cir/cfg.h.
| ︙ | ︙ | |||
72 73 74 75 76 77 78 |
const auto& getBB( uint32_t index ) const { return m_basicBlocks[index - 1]; }
auto count() const { return m_basicBlocks.size(); }
const ptr< BasicBlock >& createBB();
| < > | 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
const auto& getBB( uint32_t index ) const { return m_basicBlocks[index - 1]; }
auto count() const { return m_basicBlocks.size(); }
const ptr< BasicBlock >& createBB();
auto temporariesCount() const { return m_temporariesCount; }
void setTemporariesCount( uint32_t count ) { m_temporariesCount = count; }
// Clear the llvm basic block pointers from the entire cfg.
void unbindFromLLVM();
bool canBeExecuted() const;
bool canBeEagerlyEvaluated() const;
|
| ︙ | ︙ | |||
166 167 168 169 170 171 172 173 174 175 |
extern void ComputeDominators( const ptr< CFG >& cfg );
// Detect loops and store loop informations into the CFG.
extern void IdentifyLoops( const ptr< CFG >& cfg );
// Find which loop modifies which variable.
extern void IdentifyLoopModifiedAddrs( const ptr< CFG >& cfg );
}
#endif
| > > > > > | 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 |
extern void ComputeDominators( const ptr< CFG >& cfg );
// Detect loops and store loop informations into the CFG.
extern void IdentifyLoops( const ptr< CFG >& cfg );
// Find which loop modifies which variable.
extern void IdentifyLoopModifiedAddrs( const ptr< CFG >& cfg );
// While we generate CIR instructions, we use a simple global unique id for each different temporary.
// This pass renumbers them and counts them, so that CIR consumers can simply store them in arrays.
extern void ReindexVars( const ptr< CFG >& cfg );
extern void ReindexVars( InstrSeq& is );
}
#endif
|
Changes to bs/cir/createtemporary.h.
| ︙ | ︙ | |||
8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
public:
CreateTemporary( uint32_t index, LocationId loc ) :
BaseInstr( loc ),
m_index( index )
{}
const auto& index() const { return m_index; }
bool canBeExecuted() const { return true; }
bool canBeEagerlyEvaluated() const { return true; }
bool haveSideEffects() const { return true; }
bool operator<( const CreateTemporary& rhs ) const
{
| > | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
public:
CreateTemporary( uint32_t index, LocationId loc ) :
BaseInstr( loc ),
m_index( index )
{}
const auto& index() const { return m_index; }
void setIndex( uint32_t index ) { m_index = index; }
bool canBeExecuted() const { return true; }
bool canBeEagerlyEvaluated() const { return true; }
bool haveSideEffects() const { return true; }
bool operator<( const CreateTemporary& rhs ) const
{
|
| ︙ | ︙ |
Changes to bs/cir/gettemporary.h.
| ︙ | ︙ | |||
11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
BaseInstr( loc ),
m_type( forward< T >( type ) ),
m_index( index )
{}
const auto& type() const { return m_type; }
const auto& index() const { return m_index; }
bool canBeExecuted() const { return true; }
bool canBeEagerlyEvaluated() const { return true; }
bool haveSideEffects() const { return false; }
bool operator<( const GetTemporary& rhs ) const
{
| > | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
BaseInstr( loc ),
m_type( forward< T >( type ) ),
m_index( index )
{}
const auto& type() const { return m_type; }
const auto& index() const { return m_index; }
void setIndex( uint32_t index ) { m_index = index; }
bool canBeExecuted() const { return true; }
bool canBeEagerlyEvaluated() const { return true; }
bool haveSideEffects() const { return false; }
bool operator<( const GetTemporary& rhs ) const
{
|
| ︙ | ︙ |
Changes to bs/cir/hash.cpp.
| ︙ | ︙ | |||
21 22 23 24 25 26 27 |
size_t hash< goose::cir::Constant >::operator()( const goose::cir::Constant& x ) const
{
return goose::util::ComputeHash( x.value() );
}
size_t hash< goose::cir::VarAddr >::operator()( const goose::cir::VarAddr& x ) const
{
| | | 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
size_t hash< goose::cir::Constant >::operator()( const goose::cir::Constant& x ) const
{
return goose::util::ComputeHash( x.value() );
}
size_t hash< goose::cir::VarAddr >::operator()( const goose::cir::VarAddr& x ) const
{
return goose::util::ComputeHash( x.varIndex() );
}
size_t hash< goose::cir::TempAddr >::operator()( const goose::cir::TempAddr& x ) const
{
return goose::util::ComputeHash( x.tempIndex() );
}
|
| ︙ | ︙ |
Changes to bs/cir/helpers.h.
| ︙ | ︙ | |||
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 |
TempStorage( size_t size ) :
m_storage( size )
{}
template< typename TT >
T& set( uint32_t index, TT&& x )
{
if( index >= m_storage.size() )
m_storage.resize( index + 1 );
m_storage[index] = forward< TT >( x );
return m_storage[index];
}
const T* get( uint32_t index ) const
{
if( index < m_storage.size() )
return &m_storage[index];
return nullptr;
}
T* get( uint32_t index )
{
if( index < m_storage.size() )
return &m_storage[index];
return nullptr;
}
private:
llvm::SmallVector< T, 16 > m_storage;
| > > > > > > | 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 |
TempStorage( size_t size ) :
m_storage( size )
{}
template< typename TT >
T& set( uint32_t index, TT&& x )
{
assert( !IsUid( index ) );
if( index >= m_storage.size() )
m_storage.resize( index + 1 );
m_storage[index] = forward< TT >( x );
return m_storage[index];
}
const T* get( uint32_t index ) const
{
assert( !IsUid( index ) );
if( index < m_storage.size() )
return &m_storage[index];
return nullptr;
}
T* get( uint32_t index )
{
assert( !IsUid( index ) );
if( index < m_storage.size() )
return &m_storage[index];
return nullptr;
}
private:
llvm::SmallVector< T, 16 > m_storage;
|
| ︙ | ︙ |
Changes to bs/cir/instruction.h.
| ︙ | ︙ | |||
225 226 227 228 229 230 231 232 233 234 235 236 237 238 |
GhostCall,
PHOverrideSet,
PHOverrideClear,
Placeholder
>;
const auto& content() const { return m_content; }
bool canBeExecuted() const;
bool canBeEagerlyEvaluated() const;
bool haveSideEffects() const;
friend ostream& operator<<( ostream& out, const Instruction& inst );
| > | 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 |
GhostCall,
PHOverrideSet,
PHOverrideClear,
Placeholder
>;
const auto& content() const { return m_content; }
auto& content() { return m_content; }
bool canBeExecuted() const;
bool canBeEagerlyEvaluated() const;
bool haveSideEffects() const;
friend ostream& operator<<( ostream& out, const Instruction& inst );
|
| ︙ | ︙ |
Changes to bs/cir/meson.build.
1 2 3 4 5 6 7 8 9 10 11 12 |
goose_cir = library( 'goose-cir',
'cfg.cpp',
'dominators.cpp',
'loops.cpp',
'loopaddrs.cpp',
'instruction.cpp',
'terminator.cpp',
'func.cpp',
'helpers.cpp',
'verifinstrfilter.cpp',
'hash.cpp',
'decorator.cpp',
| > | 1 2 3 4 5 6 7 8 9 10 11 12 13 |
goose_cir = library( 'goose-cir',
'cfg.cpp',
'dominators.cpp',
'loops.cpp',
'loopaddrs.cpp',
'reindexvars.cpp',
'instruction.cpp',
'terminator.cpp',
'func.cpp',
'helpers.cpp',
'verifinstrfilter.cpp',
'hash.cpp',
'decorator.cpp',
|
| ︙ | ︙ |
Changes to bs/cir/phi.h.
| ︙ | ︙ | |||
16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
{
m_incomings.reserve( numIncomings );
}
const auto& type() const { return m_type; }
uint32_t numIncomings() const { return m_incomings.size(); }
const auto& destIndex() const { return m_destIndex; }
void setIncoming( const ptr< BasicBlock >& bb, const eir::Value& val )
{
m_incomings.emplace_back( bb, val );
}
template< typename F >
| > | 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
{
m_incomings.reserve( numIncomings );
}
const auto& type() const { return m_type; }
uint32_t numIncomings() const { return m_incomings.size(); }
const auto& destIndex() const { return m_destIndex; }
void setDestIndex( uint32_t index ) { m_destIndex = index; }
void setIncoming( const ptr< BasicBlock >& bb, const eir::Value& val )
{
m_incomings.emplace_back( bb, val );
}
template< typename F >
|
| ︙ | ︙ |
Added bs/cir/reindexvars.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 |
#include "cir.h"
namespace goose::cir
{
// While we generate CIR instructions, we use a simple global unique id for each different var and temporary.
// This pass renumbers them and counts them, so that CIR consumers can simply store them in arrays.
template< typename F >
void ReindexVars( InstrSeq& is, F& getOrCreateIndex )
{
for( auto& x : is )
{
visit( [&]< typename T >( T& instr )
{
if constexpr( is_same_v< T, CreateTemporary > )
{
instr.setIndex( getOrCreateIndex( instr.index() ) );
}
else if constexpr( is_same_v< T, GetTemporary > )
{
instr.setIndex( getOrCreateIndex( instr.index() ) );
}
else if constexpr( is_same_v< T, TempAddr > )
{
instr.setTempIndex( getOrCreateIndex( instr.tempIndex() ) );
}
else if constexpr( is_same_v< T, AllocVar > )
{
instr.setIndex( getOrCreateIndex( instr.index() ) );
}
else if constexpr( is_same_v< T, VarAddr > )
{
instr.setVarIndex( getOrCreateIndex( instr.varIndex() ) );
}
else if constexpr( is_same_v< T, Phi > )
{
instr.setDestIndex( getOrCreateIndex( instr.destIndex() ) );
instr.forAllIncomings( [&]( auto&&, auto&& val )
{
if( val.isConstant() )
return true;
ReindexVars( *val.cir(), getOrCreateIndex );
return true;
} );
}
}, x.content() );
}
}
void ReindexVars( const ptr< CFG >& cfg )
{
unordered_map< uint32_t, uint32_t > uidToIndex;
uint32_t count = cfg->temporariesCount();
auto getOrCreateIndex = [&]( uint32_t uid )
{
// The indices of function parameters are directly set as indices,
// not UIDs, and we don't want to modify them as they are assumed to
// start at 0 in the param order.
if( !IsUid( uid ) )
return uid;
auto it = uidToIndex.find( uid );
if( it == uidToIndex.end() )
{
auto&& [newIt,_] = uidToIndex.emplace( uid, count++ );
it = newIt;
}
return it->second;
};
cfg->forEachBB( [&]( auto&& bb )
{
ReindexVars( bb->instructions(), getOrCreateIndex );
bb->dirty();
} );
cfg->setTemporariesCount( count );
}
void ReindexVars( InstrSeq& is )
{
unordered_map< uint32_t, uint32_t > uidToIndex;
uint32_t count = 0;
auto getOrCreateIndex = [&]( uint32_t uid )
{
// The indices of function parameters are directly set as indices,
// not UIDs, and we don't want to modify them as they are assumed to
// start at 0 in the param order.
if( !IsUid( uid ) )
return uid;
auto it = uidToIndex.find( uid );
if( it == uidToIndex.end() )
{
auto&& [newIt,_] = uidToIndex.emplace( uid, count++ );
it = newIt;
}
return it->second;
};
ReindexVars( is, getOrCreateIndex );
}
}
|
Changes to bs/cir/tempaddr.h.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#ifndef GOOSE_CIR_TEMPADDR_H
#define GOOSE_CIR_TEMPADDR_H
namespace goose::cir
{
class TempAddr : public BaseInstr< 1, true >
{
public:
TempAddr( uint32_t i, LocationId loc ) :
BaseInstr( loc ),
m_tempIndex( i )
{}
| | < | < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
#ifndef GOOSE_CIR_TEMPADDR_H
#define GOOSE_CIR_TEMPADDR_H
namespace goose::cir
{
class TempAddr : public BaseInstr< 1, true >
{
public:
TempAddr( uint32_t i, LocationId loc ) :
BaseInstr( loc ),
m_tempIndex( i )
{}
uint32_t tempIndex() const{ return m_tempIndex; }
void setTempIndex( uint32_t index ) { m_tempIndex = index; }
bool canBeExecuted() const { return true; }
bool canBeEagerlyEvaluated() const { return false; }
bool haveSideEffects() const { return false; }
bool operator<( const TempAddr& rhs ) const
{
|
| ︙ | ︙ |
Changes to bs/cir/varaddr.h.
1 2 3 4 5 6 7 8 |
#ifndef GOOSE_CIR_VARADDR_H
#define GOOSE_CIR_VARADDR_H
namespace goose::cir
{
class VarAddr : public BaseInstr< 0, true >
{
public:
| < | < < < | < | < < | < < | < | 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 |
#ifndef GOOSE_CIR_VARADDR_H
#define GOOSE_CIR_VARADDR_H
namespace goose::cir
{
class VarAddr : public BaseInstr< 0, true >
{
public:
VarAddr( uint32_t varIndex, LocationId loc ) :
BaseInstr( loc ),
m_varIndex( varIndex )
{}
uint32_t varIndex() const { return m_varIndex; }
void setVarIndex( uint32_t index ) { m_varIndex = index; }
bool canBeExecuted() const { return true; }
bool canBeEagerlyEvaluated() const { return false; }
bool haveSideEffects() const { return false; }
bool operator<( const VarAddr& rhs ) const
{
return m_varIndex < rhs.m_varIndex;
}
friend ostream& operator<<( ostream& out, const VarAddr& ins )
{
return out << "VARADDR(" << ins.m_varIndex << ')';
}
private:
uint32_t m_varIndex = 0;
};
}
#endif
|
Changes to bs/codegen/address.cpp.
| ︙ | ︙ | |||
35 36 37 38 39 40 41 |
{
auto initVal = st.stack.pop( m_llvmBuilder );
if( !initVal )
return false;
auto* ppVal = st.temporaries->get( ta.tempIndex() );
| | | 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
{
auto initVal = st.stack.pop( m_llvmBuilder );
if( !initVal )
return false;
auto* ppVal = st.temporaries->get( ta.tempIndex() );
if( !ppVal || !*ppVal )
{
st.temporaries->set( ta.tempIndex(), *initVal );
ppVal = st.temporaries->get( ta.tempIndex() );
}
if( llvm::isa< llvm::AllocaInst >( **ppVal ) )
{
|
| ︙ | ︙ |
Changes to bs/codegen/stack.h.
| ︙ | ︙ | |||
24 25 26 27 28 29 30 |
return get< codegen::Address >( result );
}
else if constexpr( is_same_v< T, llvm::Value* > )
{
if( holds_alternative< codegen::Address >( result ) )
return AddressToGEP( builder, get< codegen::Address >( result ) );
else
| | | | 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
return get< codegen::Address >( result );
}
else if constexpr( is_same_v< T, llvm::Value* > )
{
if( holds_alternative< codegen::Address >( result ) )
return AddressToGEP( builder, get< codegen::Address >( result ) );
else
return InsertLoadIfNeeded( builder, get< llvm::Value* >( result ) );
}
else if( holds_alternative< llvm::Value* >( result ) )
return llvm::dyn_cast_or_null< remove_pointer_t< T > >( InsertLoadIfNeeded( builder, get< llvm::Value* >( result ) ) );
return nullopt;
}
optional< Slot > pop()
{
if( m_stack.empty() )
|
| ︙ | ︙ | |||
49 50 51 52 53 54 55 56 57 58 59 60 |
template< typename T >
void push( T&& v )
{
m_stack.push( forward< T >( v ) );
}
private:
stack< Slot > m_stack;
};
}
#endif
| > > > > > > > | 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
template< typename T >
void push( T&& v )
{
m_stack.push( forward< T >( v ) );
}
private:
static llvm::Value* InsertLoadIfNeeded( llvm::IRBuilder<>& builder, llvm::Value* lv )
{
if( llvm::isa< llvm::AllocaInst >( lv ) )
return builder.CreateLoad( llvm::cast< llvm::AllocaInst >( lv )->getAllocatedType(), lv );
return lv;
}
stack< Slot > m_stack;
};
}
#endif
|
Changes to bs/compile/compiler.cpp.
| ︙ | ︙ | |||
175 176 177 178 179 180 181 182 183 184 185 186 187 188 |
return nullptr;
}
cfg->currentBB()->append( get< Value >( converted ) );
cfg->emitTerminator( r->currentLocation(), cir::Ret( r->currentLocation() ) );
}
}
verify::Func fv( c, cfg, returnType );
if( !fv.verify() )
return nullptr;
return cfg;
}
| > > | 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 |
return nullptr;
}
cfg->currentBB()->append( get< Value >( converted ) );
cfg->emitTerminator( r->currentLocation(), cir::Ret( r->currentLocation() ) );
}
}
ReindexVars( cfg );
verify::Func fv( c, cfg, returnType );
if( !fv.verify() )
return nullptr;
return cfg;
}
|
| ︙ | ︙ |
Changes to bs/eir/value.cpp.
| ︙ | ︙ | |||
111 112 113 114 115 116 117 |
}
Term ValueToEIR( const ValuePattern& v )
{
return VEC( TSID( value ), v.sort(), v.type(), v.val(), v.locationId() );
}
| | | 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
}
Term ValueToEIR( const ValuePattern& v )
{
return VEC( TSID( value ), v.sort(), v.type(), v.val(), v.locationId() );
}
optional< ValuePattern > EIRToValuePattern( const Term& t )
{
auto result = Decompose( t,
Vec(
Lit( "value"_sid ),
SubTerm(),
SubTerm(),
SubTerm(),
|
| ︙ | ︙ |
Changes to bs/eir/value.h.
| ︙ | ︙ | |||
14 15 16 17 18 19 20 |
extern const Term& TypeType();
extern Term ValueToEIR( const Value& v );
extern optional< Value > EIRToValue( const Term& t );
extern Term ValueToEIR( const ValuePattern& v );
| | | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
extern const Term& TypeType();
extern Term ValueToEIR( const Value& v );
extern optional< Value > EIRToValue( const Term& t );
extern Term ValueToEIR( const ValuePattern& v );
extern optional< ValuePattern > EIRToValuePattern( const Term& t );
class Value
{
public:
Value() = default;
template< typename T, typename VL >
|
| ︙ | ︙ | |||
38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
ptr< cir::InstrSeq > cir() const
{
const auto* ppCir = get_if< ptr< cir::InstrSeq > >( &m_valOrCIR );
if( !ppCir )
return nullptr;
return *ppCir;
}
auto locationId() const { return m_locationId; }
auto&& setLocationId( LocationId id )
{
if( !m_locationId.isPoison() )
m_locationId = id;
return *this;
| > > > > > > | 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
ptr< cir::InstrSeq > cir() const
{
const auto* ppCir = get_if< ptr< cir::InstrSeq > >( &m_valOrCIR );
if( !ppCir )
return nullptr;
return *ppCir;
}
template< typename T >
void setCIR( T&& pInstrSeq )
{
m_valOrCIR = forward< T >( pInstrSeq );
}
auto locationId() const { return m_locationId; }
auto&& setLocationId( LocationId id )
{
if( !m_locationId.isPoison() )
m_locationId = id;
return *this;
|
| ︙ | ︙ | |||
88 89 90 91 92 93 94 |
class ValuePattern
{
public:
template< typename S, typename T, typename V >
ValuePattern( S&& sort, T&& type, V&& v, LocationId locationId = LocationId() ) :
m_sort( forward< T >( sort ) ),
| < < < < < < < < | 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
class ValuePattern
{
public:
template< typename S, typename T, typename V >
ValuePattern( S&& sort, T&& type, V&& v, LocationId locationId = LocationId() ) :
m_sort( forward< T >( sort ) ),
m_type( forward< T >( type ) ),
m_val( forward< V >( v ) ),
m_locationId( locationId )
{}
auto locationId() const { return m_locationId; }
auto&& setLocationId( LocationId id )
|
| ︙ | ︙ |
Changes to bs/execute/vm.cpp.
| ︙ | ︙ | |||
212 213 214 215 216 217 218 |
{
push( cst.value() );
return true;
}
bool VM::execute( const cir::VarAddr& va )
{
| | | | 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 |
{
push( cst.value() );
return true;
}
bool VM::execute( const cir::VarAddr& va )
{
auto stackIndex = m_currentFrameStart + ( va.varIndex() & 0x7fffffff );
if( stackIndex >= m_stack.size() )
return false;
if( !m_stack[stackIndex] )
return false;
push( ToValue( m_stack[stackIndex].get() ) );
return true;
}
bool VM::execute( const cir::TempAddr& ta )
{
auto initVal = pop();
if( !initVal )
return false;
auto stackIndex = m_currentFrameStart + ( ta.tempIndex() & 0x7fffffff );
if( stackIndex >= m_stack.size() )
return false;
if( !m_stack[stackIndex] )
m_stack[stackIndex] = make_shared< Term >( ValueToEIR( Evaluate( *initVal, *this ) ) );
|
| ︙ | ︙ | |||
277 278 279 280 281 282 283 |
bool VM::execute( const cir::CreateTemporary& ct )
{
auto val = pop();
if( !val )
return false;
| | | > | > > | | 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 |
bool VM::execute( const cir::CreateTemporary& ct )
{
auto val = pop();
if( !val )
return false;
auto stackIndex = m_currentFrameStart + ( ct.index() & 0x7fffffff );
if( m_stack.size() <= stackIndex )
m_stack.resize( stackIndex + 1 );
m_stack[stackIndex] = make_shared< Term >( ValueToEIR( Evaluate( *val, *this ) ) );
return true;
}
bool VM::execute( const cir::GetTemporary& gt )
{
auto stackIndex = ( gt.index() & 0x7fffffff ) + m_currentFrameStart;
if( stackIndex >= m_stack.size() )
return false;
assert( m_stack[stackIndex] );
auto val = EIRToValue( *m_stack[stackIndex] );
assert( val );
push( *val );
return true;
}
bool VM::execute( const cir::AllocVar& av )
{
auto stackIndex = m_currentFrameStart + ( av.index() & 0x7fffffff );
if( m_stack.size() <= stackIndex )
m_stack.resize( stackIndex + 1 );
m_stack[stackIndex] = BuildUninitializedValue( av.type() );
return true;
}
|
| ︙ | ︙ | |||
383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 |
if( opval.isPoison() )
return false;
if( !opval.isConstant() )
return false;
auto boolVal = FromValue< bool >( opval );
if( !boolVal )
return false;
push( ToValue( !*boolVal ) );
return true;
}
ptr< BasicBlock > VM::executeTerminator( const cir::Terminator& terminator )
{
| > > > > | 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 |
if( opval.isPoison() )
return false;
if( !opval.isConstant() )
return false;
auto boolVal = FromValue< bool >( opval );
if( !boolVal )
{
G_TRACE_VAL( *operand );
G_TRACE_VAL( opval );
return false;
}
push( ToValue( !*boolVal ) );
return true;
}
ptr< BasicBlock > VM::executeTerminator( const cir::Terminator& terminator )
{
|
| ︙ | ︙ |
Changes to bs/g0api/extensibility/cir.cpp.
| ︙ | ︙ | |||
207 208 209 210 211 212 213 |
} );
// MkInstr and UnpackInstr overloads
auto MkInstr = CreateOverloadSet( e, "MkInstr"_sid );
auto UnpackInstr = CreateOverloadSet( e, "UnpackInstr"_sid );
RegisterInstrOverloads< Call, InstrOpCode::Call >( e, MkInstr, UnpackInstr, &Call::numArgs, &Call::locationId );
| | | 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 |
} );
// MkInstr and UnpackInstr overloads
auto MkInstr = CreateOverloadSet( e, "MkInstr"_sid );
auto UnpackInstr = CreateOverloadSet( e, "UnpackInstr"_sid );
RegisterInstrOverloads< Call, InstrOpCode::Call >( e, MkInstr, UnpackInstr, &Call::numArgs, &Call::locationId );
RegisterInstrOverloads< VarAddr, InstrOpCode::VarAddr >( e, MkInstr, UnpackInstr, &VarAddr::varIndex, &VarAddr::locationId );
RegisterInstrOverloads< TempAddr, InstrOpCode::TempAddr >( e, MkInstr, UnpackInstr, &TempAddr::tempIndex, &TempAddr::locationId );
RegisterInstrOverloads< Select, InstrOpCode::Select >( e, MkInstr, UnpackInstr, &Select::memberIndex, &Select::locationId );
RegisterInstrOverloads< CreateTemporary, InstrOpCode::CreateTemporary >( e, MkInstr, UnpackInstr, &CreateTemporary::index, &CreateTemporary::locationId );
RegisterInstrOverloads< GetTemporary, InstrOpCode::GetTemporary >( e, MkInstr, UnpackInstr, &GetTemporary::type, &GetTemporary::index, &GetTemporary::locationId );
RegisterInstrOverloads< AllocVar, InstrOpCode::AllocVar >( e, MkInstr, UnpackInstr, &AllocVar::type, &AllocVar::index, &AllocVar::locationId );
RegisterInstrOverloads< Load, InstrOpCode::Load >( e, MkInstr, UnpackInstr, &Load::type, &Load::locationId );
RegisterInstrOverloads< Store, InstrOpCode::Store >( e, MkInstr, UnpackInstr, &Store::type, &Store::srcLocId, &Store::destLocId );
|
| ︙ | ︙ | |||
432 433 434 435 436 437 438 |
( e, "CFGCreateBasicBlock"_sid,
[]( const auto& pCFG ) -> TypeWrapper< ptr< BasicBlock > >
{
auto& cfg = *pCFG.get();
return cfg.createBB();
} );
| | | | < | | 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 |
( e, "CFGCreateBasicBlock"_sid,
[]( const auto& pCFG ) -> TypeWrapper< ptr< BasicBlock > >
{
auto& cfg = *pCFG.get();
return cfg.createBB();
} );
RegisterBuiltinFunc< uint32_t () >
( e, "GenerateNewUID"_sid,
[]()
{
return util::GenerateNewUID();
} );
////////////////////////////
// Decorator
////////////////////////////
RegisterBuiltinFunc< void ( TypeWrapper< ptr< Decorator > >, TypeWrapper< ptr< Instruction > > ) >
( e, "DecoratorAddPrologueInstr"_sid,
|
| ︙ | ︙ |
Changes to bs/parse/resolver.cpp.
1 2 3 4 5 6 7 8 |
#include "parse.h"
using namespace goose;
using namespace goose::parse;
void Resolver::init()
{
m_context.onContextRestoredSignal().subscribe( [&]
| | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
#include "parse.h"
using namespace goose;
using namespace goose::parse;
void Resolver::init()
{
m_context.onContextRestoredSignal().subscribe( [&]
{
clearLookAheadCache();
} );
}
bool Resolver::eos() const
{
clearCacheIfNeeded();
return m_tokProvider->eos() && m_lookAheadCache.empty();
}
|
| ︙ | ︙ |
Changes to bs/sema/typecheck.cpp.
| ︙ | ︙ | |||
68 69 70 71 72 73 74 |
auto expr = VEC( lhs, rhs );
for( auto&& [s, rule] : Match( expr, rules ) )
{
if( rule.exclusive )
{
if( exclusiveRule )
| | | 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
auto expr = VEC( lhs, rhs );
for( auto&& [s, rule] : Match( expr, rules ) )
{
if( rule.exclusive )
{
if( exclusiveRule )
G_VAL_ERROR( *EIRToValuePattern( rhs ), "ambiguous exclusive type checking rule" );
exclusiveRule = &rule;
}
else if( !exclusiveRule )
candidates.push( { s.score(), &rule } );
}
|
| ︙ | ︙ | |||
137 138 139 140 141 142 143 |
if( c.score < bestScore )
break;
auto gen = c.rule->func( lhs, rhs, tcc );
if( gen.begin() != gen.end() )
{
#ifdef TCRULES_DEBUG
| | | | 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
if( c.score < bestScore )
break;
auto gen = c.rule->func( lhs, rhs, tcc );
if( gen.begin() != gen.end() )
{
#ifdef TCRULES_DEBUG
G_VAL_ERROR( *EIRToValuePattern( rhs ), format( "ambiguous type checking rule: {}:{} and {}:{} both match",
bestInfos->pFilename, bestInfos->line, c.rule->infos.pFilename, c.rule->infos.line ) );
#else
G_VAL_ERROR( *EIRToValuePattern( rhs ), "ambiguous type checking rule" );
#endif
}
candidates.pop();
}
#ifdef TC_LOG_RULES
|
| ︙ | ︙ |
Changes to bs/sema/uni-holes.cpp.
| ︙ | ︙ | |||
397 398 399 400 401 402 403 |
ANYTERM( _ ),
ForwardingHolePattern(),
ANYTERM( _ ) ) ),
ANYTERM( _ ),
[]( const Term& lhs, const Term& rhs, TypeCheckingContext tcc ) -> TCGen
{
| | | 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 |
ANYTERM( _ ),
ForwardingHolePattern(),
ANYTERM( _ ) ) ),
ANYTERM( _ ),
[]( const Term& lhs, const Term& rhs, TypeCheckingContext tcc ) -> TCGen
{
auto lVal = *EIRToValuePattern( lhs );
auto h = *ForwardingHoleFromIRExpr( lVal.type() );
if( h.name() == "_"_sid )
co_yield UniAnonHoleAny( lVal.type(), rhs, tcc );
else
co_yield UniHoleAny( lVal.type(), rhs, tcc );
}, true
|
| ︙ | ︙ |
Changes to bs/util/meson.build.
1 2 3 4 5 6 7 8 |
goose_util = library( 'goose-util',
'stringid.cpp',
'bigint.cpp',
'graphviz.cpp',
include_directories: bsinc,
dependencies: [fmt_dep, mimalloc_dep, tracy_dep]
)
| > | 1 2 3 4 5 6 7 8 9 |
goose_util = library( 'goose-util',
'util.cpp',
'stringid.cpp',
'bigint.cpp',
'graphviz.cpp',
include_directories: bsinc,
dependencies: [fmt_dep, mimalloc_dep, tracy_dep]
)
|
| ︙ | ︙ |
Added bs/util/util.cpp.
> > > > > > > | 1 2 3 4 5 6 7 |
#include "util.h"
uint32_t goose::util::GenerateNewUID()
{
static uint32_t nextUid = 0x80000000;
return nextUid++;
}
|
Changes to bs/util/util.h.
| ︙ | ︙ | |||
229 230 231 232 233 234 235 236 237 238 |
{
m_observers.emplace_back( forward< F >( observer ) );
}
private:
vector< function< void( T... ) > > m_observers;
};
}
#endif
| > > > > > | 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 |
{
m_observers.emplace_back( forward< F >( observer ) );
}
private:
vector< function< void( T... ) > > m_observers;
};
// Simple uid generator
extern uint32_t GenerateNewUID();
static inline bool IsUid( uint32_t x ) { return x & 0x80000000; }
}
#endif
|
Changes to bs/verify/call.cpp.
| ︙ | ︙ | |||
69 70 71 72 73 74 75 |
)
);
if( !result )
return true;
auto&& [type, val, locId] = *result;
| | | 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
)
);
if( !result )
return true;
auto&& [type, val, locId] = *result;
auto paramVal = BuildComputedValue( type, VarAddr( varId++, locId ), Load( type, locId ) );
auto zv = BuildZ3ExprFromValue( cb, paramVal );
ForEachPredicate( cb, type, zv.expr, [&]( auto&& z3expr, auto locId )
{
DiagnosticsContext dc( fVal->locationId(), "At this call." );
b.checkAssertion( z3expr, locId );
} );
|
| ︙ | ︙ |
Changes to bs/verify/func.cpp.
| ︙ | ︙ | |||
68 69 70 71 72 73 74 |
)
);
if( !result )
return true;
auto&& [type, val, locId] = *result;
| | | 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
)
);
if( !result )
return true;
auto&& [type, val, locId] = *result;
auto paramVal = BuildComputedValue( type, VarAddr( varId, locId ), Load( type, locId ) )
.setLocationId( locId );
// Initialize every parameter containing variable with a freshly named constant of the right type.
auto paramInit = BuildZ3ConstantFromType( m_builder, type, format( "p{}", varId ) );
m_builder.setVar( varId, move( paramInit ) );
++varId;
|
| ︙ | ︙ |
Added tests/g0/function/e-template-tuple-vararg-2.g0.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
#Include( "tests/g0/helpers.g0" )
bool testVarArgFunc1( ( $T... ) gg )
{
if !check( GetTupleSize( $T ) == 3, "vararg test 1" )
return false
if !check( GetTupleSize( gg ) == 3, "vararg test 2" )
return false
if !check( $T.0 == ct_string, "vararg test 3" )
return false
if !check( $T.1 == bool, "vararg test 4" )
return false
if !check( $T.2 == ct_int, "vararg test 5" )
return false
if !check( gg.0 == "blah", "vararg test 6" )
return false
if !check( gg.1 == false, "vararg test 7" )
return false
if !check( gg.2 == 219, "vararg test 8" )
return false
return true
}
var gg = ( "blah", false, 219 )
if !testVarArgFunc1( gg )
return 1
|
Added tests/g0/function/e-template-vararg-2.g0.
> > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#Include( "tests/g0/helpers.g0" )
bool foo( ( ct_string, bool, ct_int ) tup )
{
if tup.0 == "blah" & tup.1 == false & tup.2 == 219
return true
return false
}
bool testVarArgFunc2( $T... gg )
{
return foo( gg );
}
if !testVarArgFunc2( "blah", false, 219 )
return 1
|
Changes to tests/g0/function/meson.build.
1 2 3 4 5 6 7 8 |
e_tests = [
'e-overloading',
'e-templates',
'e-func',
'e-higher-func',
'e-higher-template',
'e-higher-poly',
'e-template-vararg',
| > | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
e_tests = [
'e-overloading',
'e-templates',
'e-func',
'e-higher-func',
'e-higher-template',
'e-higher-poly',
'e-template-vararg',
'e-template-vararg-2',
'e-template-tuple-vararg',
'e-template-tuple-vararg-2'
]
c_fail_tests = [
'c-fail-calling-compiletime-func',
'c-fail-func-type-mismatch',
]
|
| ︙ | ︙ |
Changes to tests/g0/tuple/ce-tuple.g0.
| ︙ | ︙ | |||
49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
return 1
tup2.0, tup2.2, tup2.3 = tup2.3, tup2.0, tup2.2
if !check( tup2.0 == 420 & tup2.1 & tup2.2 == 219 & tup2.3 == 654654, "tuple test 4" )
return 1
using fflush = ExternalFunction( uint(32) ( pointer(void) stream ), "fflush" )
#if IsCompiling
{
fflush( nullptr )
}
#else
| > > > > > > > > > > > > | 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 |
return 1
tup2.0, tup2.2, tup2.3 = tup2.3, tup2.0, tup2.2
if !check( tup2.0 == 420 & tup2.1 & tup2.2 == 219 & tup2.3 == 654654, "tuple test 4" )
return 1
// Passing a tuple by value
uint(32), uint(32) baz( ( uint(32), bool, uint(32), uint(32) ) tup )
{
return tup.0, tup.2
}
( uint(32), bool, uint(32), uint(32) ) tup3 = ( 123, false, 456, 789 )
var a, var b = baz( tup3 )
if !check( a == 123 & b == 456, "tuple test 5" )
return 1
using fflush = ExternalFunction( uint(32) ( pointer(void) stream ), "fflush" )
#if IsCompiling
{
fflush( nullptr )
}
#else
|
| ︙ | ︙ |
Changes to tests/g0/tuple/ce-tuple.txt.
1 2 3 4 | tuple test 1: OK tuple test 2: OK tuple test 3: OK tuple test 4: OK | > | 1 2 3 4 5 | tuple test 1: OK tuple test 2: OK tuple test 3: OK tuple test 4: OK tuple test 5: OK |
Changes to tests/g0/verification/z3gen/e-z3gen-test-2.txt.
1 2 3 4 | === Begin function verification trace === (=> b1 (= v0_1_0 p0)) (=> b1 (= v1_1_1 p1)) assume (distinct v0_1_0 v1_1_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 46 47 | === Begin function verification trace === (=> b1 (= v0_1_0 p0)) (=> b1 (= v1_1_1 p1)) assume (distinct v0_1_0 v1_1_1) (=> b1 (= v2_1_3 u2)) (=> b1 (= v2_1_4 v0_1_0)) (=> b1 (= v3_1_6 u5)) (=> b1 (= v3_1_7 v1_1_1)) (=> b1 (= v4_1_9 u8)) (=> b1 (= v4_1_10 v2_1_4)) (=> b1 (= v5_1_12 u11)) (=> b1 (= v5_1_13 v3_1_7)) (= e1_2 (and b1 (< v4_1_10 v5_1_13))) (= b2 e1_2) (=> b2 (= v6_2_15 u14)) (=> e1_2 (= v5_2_16 v5_1_13)) (=> b2 (= v5_2_17 v5_2_16)) (=> b2 (= v6_2_18 v5_2_17)) (=> b2 (= v7_2_20 u19)) (=> e1_2 (= v4_2_21 v4_1_10)) (=> b2 (= v4_2_22 v4_2_21)) (=> b2 (= v7_2_23 v4_2_22)) (=> b2 (= v4_2_24 v6_2_18)) (=> b2 (= v5_2_25 v7_2_23)) (= e1_3 (and b1 (not (< v4_1_10 v5_1_13)))) (= e2_3 (and b2 b2)) (= b3 (or e1_3 e2_3)) (= e3_4 (and b3 b3)) (= b4 e3_4) (=> e1_3 (= v4_3_26 v4_1_10)) (=> e2_3 (= v4_3_26 v4_2_24)) (=> b3 (= v4_3_27 v4_3_26)) (=> e3_4 (= v4_4_28 v4_3_27)) (=> b4 (= v4_4_29 v4_4_28)) (=> e1_3 (= v5_3_30 v5_1_13)) (=> e2_3 (= v5_3_30 v5_2_25)) (=> b3 (= v5_3_31 v5_3_30)) (=> e3_4 (= v5_4_32 v5_3_31)) (=> b4 (= v5_4_33 v5_4_32)) check_unsat (and b4 (not (> v4_4_29 v5_4_33))) (= e4_5 (and b4 b4)) (= b5 e4_5) === End function verification trace === === Begin function verification trace === (=> b1 (= v1_1_0 1)) (=> b1 (= v0_1_1 2)) |
| ︙ | ︙ |
Changes to tests/g0/verification/z3gen/e-z3gen-test-3.txt.
1 2 3 4 | === Begin function verification trace === (=> b1 (= v0_1_0 p0)) (=> b1 (= v1_1_1 p1)) assume (distinct v0_1_0 v1_1_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 | === Begin function verification trace === (=> b1 (= v0_1_0 p0)) (=> b1 (= v1_1_1 p1)) assume (distinct v0_1_0 v1_1_1) (=> b1 (= v2_1_3 u2)) (=> b1 (= v2_1_4 v0_1_0)) (=> b1 (= v3_1_6 u5)) (=> b1 (= v3_1_7 v1_1_1)) (=> b1 (= v4_1_9 u8)) (=> b1 (= v4_1_10 v2_1_4)) (=> b1 (= v5_1_12 u11)) (=> b1 (= v5_1_13 v3_1_7)) (= e1_2 (and b1 (< v4_1_10 v5_1_13))) (= b2 e1_2) (=> b2 (= v6_2_15 u14)) (=> e1_2 (= v5_2_16 v5_1_13)) (=> b2 (= v5_2_17 v5_2_16)) (=> b2 (= v6_2_18 v5_2_17)) (=> b2 (= v7_2_20 u19)) (=> e1_2 (= v4_2_21 v4_1_10)) (=> b2 (= v4_2_22 v4_2_21)) (=> b2 (= v7_2_23 v4_2_22)) (=> b2 (= v4_2_24 v6_2_18)) (=> b2 (= v5_2_25 v7_2_23)) (= e1_3 (and b1 (not (< v4_1_10 v5_1_13)))) (= e2_3 (and b2 b2)) (= b3 (or e1_3 e2_3)) (=> e1_3 (= v4_3_26 v4_1_10)) (=> e2_3 (= v4_3_26 v4_2_24)) (=> b3 (= v4_3_27 v4_3_26)) (=> e1_3 (= v5_3_28 v5_1_13)) (=> e2_3 (= v5_3_28 v5_2_25)) (=> b3 (= v5_3_29 v5_3_28)) check_unsat (and b3 (not (> (- v4_3_27 v5_3_29) 0))) === End function verification trace === === Checking instr seq === (=> b1 (= v1_1_1 1)) (=> b1 (= v0_1_2 2)) check_unsat (not (distinct v0_1_2 v1_1_1)) assume (> r0 0) |
| ︙ | ︙ |
Changes to tests/g0/verification/z3gen/e-z3gen-test-4.txt.
1 2 3 4 | === Begin function verification trace === (=> b1 (= v0_1_0 p0)) (=> b1 (= v1_1_1 p1)) assume (distinct v0_1_0 v1_1_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 | === Begin function verification trace === (=> b1 (= v0_1_0 p0)) (=> b1 (= v1_1_1 p1)) assume (distinct v0_1_0 v1_1_1) (=> b1 (= v2_1_3 u2)) (=> b1 (= v2_1_4 v0_1_0)) (=> b1 (= v3_1_6 u5)) (=> b1 (= v3_1_7 v1_1_1)) (=> b1 (= v4_1_9 u8)) (=> b1 (= v4_1_10 v2_1_4)) (=> b1 (= v5_1_12 u11)) (=> b1 (= v5_1_13 v3_1_7)) (= e1_2 (and b1 (< v4_1_10 v5_1_13))) (= b2 e1_2) (=> b2 (= v6_2_15 u14)) (=> e1_2 (= v5_2_16 v5_1_13)) (=> b2 (= v5_2_17 v5_2_16)) (=> b2 (= v6_2_18 v5_2_17)) (=> b2 (= v7_2_20 u19)) (=> e1_2 (= v4_2_21 v4_1_10)) (=> b2 (= v4_2_22 v4_2_21)) (=> b2 (= v7_2_23 v4_2_22)) (=> b2 (= v4_2_24 v6_2_18)) (=> b2 (= v5_2_25 v7_2_23)) (= e1_3 (and b1 (not (< v4_1_10 v5_1_13)))) (= e2_3 (and b2 b2)) (= b3 (or e1_3 e2_3)) (=> e1_3 (= v4_3_26 v4_1_10)) (=> e2_3 (= v4_3_26 v4_2_24)) (=> b3 (= v4_3_27 v4_3_26)) (=> e1_3 (= v5_3_28 v5_1_13)) (=> e2_3 (= v5_3_28 v5_2_25)) (=> b3 (= v5_3_29 v5_3_28)) check_unsat (and b3 (not (> (- v4_3_27 v5_3_29) 0))) === End function verification trace === === Begin function verification trace === (=> b1 (= v0_1_0 p0)) assume (distinct v0_1_0 0) (=> b1 (= v1_1_2 (* 2 v0_1_0))) (=> b1 (= v0_1_3 v0_1_0)) |
| ︙ | ︙ |
Changes to tests/g0/verification/z3gen/e-z3gen-test-5.txt.
1 2 3 4 5 6 7 8 9 | === Begin function verification trace === (=> b1 (= v0_1_0 p0)) (=> b1 (= v1_1_1 p1)) assume (distinct v0_1_0 v1_1_1) (=> b1 (= v2_1_4 (tupsort0 u2 u3))) (=> b1 (= v2_1_5 (tupsort0 v0_1_0 (tupsort0_1 v2_1_4)))) (=> b1 (= v2_1_6 (tupsort0 (tupsort0_0 v2_1_5) v1_1_1))) (= e1_2 (and b1 (< (tupsort0_0 v2_1_6) (tupsort0_1 v2_1_6)))) (= b2 e1_2) | | | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | === Begin function verification trace === (=> b1 (= v0_1_0 p0)) (=> b1 (= v1_1_1 p1)) assume (distinct v0_1_0 v1_1_1) (=> b1 (= v2_1_4 (tupsort0 u2 u3))) (=> b1 (= v2_1_5 (tupsort0 v0_1_0 (tupsort0_1 v2_1_4)))) (=> b1 (= v2_1_6 (tupsort0 (tupsort0_0 v2_1_5) v1_1_1))) (= e1_2 (and b1 (< (tupsort0_0 v2_1_6) (tupsort0_1 v2_1_6)))) (= b2 e1_2) (=> b2 (= v3_2_8 u7)) (=> e1_2 (= v2_2_9 v2_1_6)) (=> b2 (= v2_2_10 v2_2_9)) (=> b2 (= v3_2_11 (tupsort0_1 v2_2_10))) (=> b2 (= v4_2_13 u12)) (=> b2 (= v4_2_14 (tupsort0_0 v2_2_10))) (=> b2 (= v2_2_15 (tupsort0 v3_2_11 (tupsort0_1 v2_2_10)))) (=> b2 (= v2_2_16 (tupsort0 (tupsort0_0 v2_2_15) v4_2_14))) (let ((a!1 (and b1 (not (< (tupsort0_0 v2_1_6) (tupsort0_1 v2_1_6)))))) (= e1_3 a!1)) (= e2_3 (and b2 b2)) (= b3 (or e1_3 e2_3)) (= e3_4 (and b3 b3)) (= b4 e3_4) (=> e1_3 (= v2_3_17 v2_1_6)) |
| ︙ | ︙ |