Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | cfg: now that we got rid of this crazy system where CFGs could "call" other CFGs that weren't really functions, removed that clumsy cfg index that was needed to identify temporaries everywhere. |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA3-256: |
238df77134c7da91c6509b44b2ab9b47 |
| User & Date: | achavasse 2019-11-19 00:04:49.108 |
Context
|
2019-11-19
| ||
| 20:20 | cfg: fix the way the variable ids modified by each loop are stored to avoid duplicate entries. check-in: 1c3ff200aa user: achavasse tags: trunk | |
| 00:04 | cfg: now that we got rid of this crazy system where CFGs could "call" other CFGs that weren't really functions, removed that clumsy cfg index that was needed to identify temporaries everywhere. check-in: 238df77134 user: achavasse tags: trunk | |
|
2019-11-18
| ||
| 22:42 | Removed the "inline CFG" llr instruction and related support code. check-in: 5329f83e33 user: achavasse tags: trunk | |
Changes
Changes to bs/builtins/extpoints.cpp.
| ︙ | ︙ | |||
128 129 130 131 132 133 134 |
// or partial specialization of this, since it will have to emit specialized
// binary runtime code.
RegisterBuiltinFunc< Intrinsic< Value ( LocVarOfTypeT, ValueOfTypeT ) > >( e, e.extInitializeLocalVar(),
[]( const Value& lv, const Value& initVal )
{
auto locVar = *FromValue< LocalVar >( lv );
return BuildComputedValue( GetValueType< void >(),
| | | | | | | 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 |
// or partial specialization of this, since it will have to emit specialized
// binary runtime code.
RegisterBuiltinFunc< Intrinsic< Value ( LocVarOfTypeT, ValueOfTypeT ) > >( e, e.extInitializeLocalVar(),
[]( const Value& lv, const Value& initVal )
{
auto locVar = *FromValue< LocalVar >( lv );
return BuildComputedValue( GetValueType< void >(),
SetVar( initVal, locVar.index() ) );
} );
// Initialization for integer vars
RegisterBuiltinFunc< Intrinsic< Value ( IntegerLocVarType, IntegerType ) > >( e, e.extInitializeLocalVar(),
[]( const Value& lv, const Value& initVal )
{
auto locVar = *FromValue< LocalVar >( lv );
return BuildComputedValue( GetValueType< void >(),
SetVar( initVal, locVar.index() ) );
} );
// Default initialization for integer vars
RegisterBuiltinFunc< Intrinsic< Value ( IntegerLocVarType ) > >( e, e.extInitializeLocalVar(),
[]( const Value& lv )
{
auto locVar = *FromValue< LocalVar >( lv );
auto opTypeVal = *ValueFromIRExpr( locVar.type() );
auto opType = *FromValue< IntegerType >( opTypeVal );
auto initVal = Value( locVar.type(),
APSInt( opType.m_numBits, !opType.m_signed ) );
return BuildComputedValue( GetValueType< void >(),
SetVar( move( initVal ), locVar.index() ) );
} );
// Default initialization for ct_int vars
RegisterBuiltinFunc< Intrinsic< Value ( CTIntLocVarType ) > >( e, e.extInitializeLocalVar(),
[]( const Value& lv )
{
auto locVar = *FromValue< LocalVar >( lv );
return BuildComputedValue( GetValueType< void >(),
SetVar( ToValue( BigInt() ), locVar.index() ) );
} );
// Default initialization for ct_string vars
RegisterBuiltinFunc< Intrinsic< Value ( CTStringLocVarType ) > >( e, e.extInitializeLocalVar(),
[]( const Value& lv )
{
auto locVar = *FromValue< LocalVar >( lv );
return BuildComputedValue( GetValueType< void >(),
SetVar( ToValue( ""s ), locVar.index() ) );
} );
}
}
|
Changes to bs/builtins/operators/assignment.cpp.
| ︙ | ︙ | |||
19 20 21 22 23 24 25 |
auto BuiltinTypeAssignment = []( auto&& lhs, auto&& rhs ) -> Value
{
auto locvar = *FromValue< LocalVar >( lhs );
auto& p = *Parser::GetCurrentParser();
auto bb = p.cfg()->currentBB();
if( bb )
| | | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
auto BuiltinTypeAssignment = []( auto&& lhs, auto&& rhs ) -> Value
{
auto locvar = *FromValue< LocalVar >( lhs );
auto& p = *Parser::GetCurrentParser();
auto bb = p.cfg()->currentBB();
if( bb )
bb->emplace_back( SetVar( rhs, locvar.index() ) );
// TODO: we don't support chained assignments for now. Probably later when we have
// references.
return Value( GetValueType< void >(), 0U );
};
BuildParseRule( e, "="_sid,
|
| ︙ | ︙ |
Changes to bs/builtins/operators/logic.cpp.
| ︙ | ︙ | |||
103 104 105 106 107 108 109 |
auto pSuccBB = cfg->createBB();
// If the lhs is true, skip to the end directly.
// Otherwise, jump to the BB that computes rhs.
predBB->setTerminator( CondBranch( lhs, pSuccBB, pRhsBB ) );
auto rhsIndex = cfg->getNewTemporaryIndex();
| | | | | | | 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 |
auto pSuccBB = cfg->createBB();
// If the lhs is true, skip to the end directly.
// Otherwise, jump to the BB that computes rhs.
predBB->setTerminator( CondBranch( lhs, pSuccBB, pRhsBB ) );
auto rhsIndex = cfg->getNewTemporaryIndex();
pRhsBB->emplace_back( CreateTemporary( rhsIndex, rhs ) );
pRhsBB->setTerminator( Branch( pSuccBB ) );
auto resultIndex = cfg->getNewTemporaryIndex();
// Build the Phi instruction that will collect the final result.
auto phi = Phi( *ValueFromIRExpr( GetValueType< bool >() ), 2,
resultIndex );
// If coming directly from the lhs BB, we know the result is true.
phi.setIncoming( predBB, ToValue( true ) );
// Otherwise, the result is whatever was computed by the rhs block.
phi.setIncoming( pRhsBB, BuildComputedValue( GetValueType< bool >(),
GetTemporary( GetValueType< bool >(), rhsIndex ) ) );
pSuccBB->emplace_back( move( phi ) );
cfg->setCurrentBB( pSuccBB );
// Build the result val which pulls the temporary created above.
return BuildComputedValue( GetValueType< bool >(),
GetTemporary( GetValueType< bool >(), resultIndex ) );
} )
)
);
BuildParseRule( e, "&"_sid,
LeftAssInfixOp( "operator_and"_sid, precedence::AndOp,
BuildGenericTupleOperator(),
|
| ︙ | ︙ | |||
175 176 177 178 179 180 181 |
auto pSuccBB = cfg->createBB();
// If the lhs is false, skip to the end directly.
// Otherwise, jump to the BB that computes rhs.
predBB->setTerminator( CondBranch( lhs, pRhsBB, pSuccBB ) );
auto rhsIndex = cfg->getNewTemporaryIndex();
| | | | | | | 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 |
auto pSuccBB = cfg->createBB();
// If the lhs is false, skip to the end directly.
// Otherwise, jump to the BB that computes rhs.
predBB->setTerminator( CondBranch( lhs, pRhsBB, pSuccBB ) );
auto rhsIndex = cfg->getNewTemporaryIndex();
pRhsBB->emplace_back( CreateTemporary( rhsIndex, rhs ) );
pRhsBB->setTerminator( Branch( pSuccBB ) );
auto resultIndex = cfg->getNewTemporaryIndex();
// Build the Phi instruction that will collect the final result.
auto phi = Phi( *ValueFromIRExpr( GetValueType< bool >() ), 2,
resultIndex );
// If coming directly from the lhs BB, we know the result is true.
phi.setIncoming( predBB, ToValue( false ) );
// Otherwise, the result is whatever was computed by the rhs block.
phi.setIncoming( pRhsBB, BuildComputedValue( GetValueType< bool >(),
GetTemporary( GetValueType< bool >(), rhsIndex ) ) );
pSuccBB->emplace_back( move( phi ) );
cfg->setCurrentBB( pSuccBB );
// Build the result val which pulls the temporary created above.
return BuildComputedValue( GetValueType< bool >(),
GetTemporary( GetValueType< bool >(), resultIndex ) );
} )
)
);
BuildParseRule( e, "<<"_sid,
LeftAssInfixOp( "operator_shift_left"_sid, precedence::BitShiftOp,
BuildGenericTupleOperator(),
|
| ︙ | ︙ |
Changes to bs/builtins/types/func/build.cpp.
| ︙ | ︙ | |||
22 23 24 25 26 27 28 |
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( _ ),
| | | 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
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(), llr::GetVar( move( decl.type() ), varId++ ) ) ) );
}
else if( param.isConstant() )
tv->append( ParamPatFromTerm( ValueToIRExpr( param ) ) );
return true;
} );
|
| ︙ | ︙ | |||
99 100 101 102 103 104 105 |
// the param needs to be visible regardless of which domain we are compiling
// the function in.
auto paramIdentity = AppendToVectorTerm(
InjectDomainIntoIdentity( identity, ANYTERM( _ ) ),
TERM( decl.name() ) );
c.env()->storeValue( paramIdentity, ANYTERM( _ ),
| | | 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
// the param needs to be visible regardless of which domain we are compiling
// the function in.
auto paramIdentity = AppendToVectorTerm(
InjectDomainIntoIdentity( identity, ANYTERM( _ ) ),
TERM( decl.name() ) );
c.env()->storeValue( paramIdentity, ANYTERM( _ ),
ValueToIRExpr( BuildComputedValue( decl.type(), llr::GetVar( decl.type(), varId++ ) ) ) );
return true;
} );
out_bodyContext = Context( c.env(), identity, funcType.returnType() );
auto pFuncLLR = c.env()->createLLRFunc( identity );
|
| ︙ | ︙ |
Changes to bs/builtins/types/func/func.cpp.
| ︙ | ︙ | |||
286 287 288 289 290 291 292 |
return false;
Context localContext( c.env(), pFuncLLR->identity(), f.type().returnType() );
auto tokProvider = lex::MakeVectorAdapter( *static_pointer_cast< vector< TermLoc > >( f.tokens() ) );
auto r = make_shared< parse::Resolver >( tokProvider, localContext );
Parser p( r );
| | | 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 |
return false;
Context localContext( c.env(), pFuncLLR->identity(), f.type().returnType() );
auto tokProvider = lex::MakeVectorAdapter( *static_pointer_cast< vector< TermLoc > >( f.tokens() ) );
auto r = make_shared< parse::Resolver >( tokProvider, localContext );
Parser p( r );
auto cfg = make_shared< llr::CFG >( VecSize( f.type().params() ) );
cfg->createBB();
p.setCFG( cfg );
p.cfg()->setCurrentBB( cfg->entryBB() );
bool success = p.parseBraceBlock();
p.flushValue();
|
| ︙ | ︙ |
Changes to bs/builtins/types/localvar/localvar.cpp.
| ︙ | ︙ | |||
17 18 19 20 21 22 23 |
{
static auto pattern = GetValueType< LocalVar >( MkHole( "T"_sid ) );
return pattern;
}
Value DeclareLocalVar( Parser& p, const Term& type, StringId name, const optional< Value >& initializer )
{
| < | | | 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
{
static auto pattern = GetValueType< LocalVar >( MkHole( "T"_sid ) );
return pattern;
}
Value DeclareLocalVar( Parser& p, const Term& type, StringId name, const optional< Value >& initializer )
{
auto index = p.cfg()->getNewTemporaryIndex();
LocalVar lv( name, type, p.resolver()->context().env()->NewUniqueId(), index );
auto bb = p.cfg()->currentBB();
if( !bb )
return PoisonValue();
auto typeVal = *ValueFromIRExpr( type );
bb->emplace_back( AllocVar( typeVal, index ) );
if( initializer )
{
DiagnosticsContext dc( 0, "When invoking InitializeLocalVar." );
p.pushValue( InvokeOverloadSet( p.resolver()->context(),
p.resolver()->context().env()->extInitializeLocalVar(),
|
| ︙ | ︙ | |||
165 166 167 168 169 170 171 |
SubTerm() // initializer
)
);
auto&& [type, initializer] = *callDecomp;
auto initializerVal = *ValueFromIRExpr( initializer );
| < | | | 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 |
SubTerm() // initializer
)
);
auto&& [type, initializer] = *callDecomp;
auto initializerVal = *ValueFromIRExpr( initializer );
auto index = p.cfg()->getNewTemporaryIndex();
// 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 LowerType on it during codegen,
// it will have a meaningful location for the error message to attach itself on.
uint32_t typeLoc = ValueFromIRExpr( typeTExpr )->locationId();
LocalVar lv( name, type, p.resolver()->context().env()->NewUniqueId(), index );
bb->emplace_back( AllocVar( ValueFromIRExpr( lv.type() )->setLocationId( typeLoc ), index ) );
p.pushValue( ResolveInvocation( c, GetInvocationRule( *c.env(), initializerVal ), initializerVal,
MakeTuple( ToValue( lv ), initVal ) ) );
auto locVar = ToValue( lv );
if( name != ""_sid )
|
| ︙ | ︙ | |||
236 237 238 239 240 241 242 |
Term Bridge< LocalVar >::Type( const Term& type )
{
return ValueToIRExpr( ToValue< LocalVarType >( type ) );
}
Value Bridge< LocalVar >::ToValue( const LocalVar& lv )
{
| | < | | | 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 |
Term Bridge< LocalVar >::Type( const Term& type )
{
return ValueToIRExpr( ToValue< LocalVarType >( type ) );
}
Value Bridge< LocalVar >::ToValue( const LocalVar& lv )
{
return Value( Type( lv.type() ), VEC( TERM( lv.name() ), TERM( lv.uniqueId() ), TERM( lv.index() ) ) );
}
optional< LocalVar > Bridge< LocalVar >::FromValue( const Value& v )
{
if( !v.isConstant() )
return nullopt;
auto t = FromValue< LocalVarType >( *ValueFromIRExpr( v.type() ) );
if( !t )
return nullopt;
auto result = Decompose( v.val(),
Vec(
Val< StringId >(),
Val< uint32_t >(),
Val< uint32_t >()
)
);
if( !result )
return nullopt;
auto&& [name,uniqueId,index] = *result;
return LocalVar( name, move( t->type() ), uniqueId, index );
}
}
|
Changes to bs/builtins/types/localvar/localvar.h.
| ︙ | ︙ | |||
27 28 29 30 31 32 33 |
Term m_type;
};
class LocalVar
{
public:
template< typename T >
| | < < | 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 |
Term m_type;
};
class LocalVar
{
public:
template< typename T >
LocalVar( StringId name, T&& type, uint32_t uniqueId, uint32_t index ) :
m_name( name ),
m_type( forward< T >( type ) ),
m_uniqueId( uniqueId ),
m_index( index )
{}
auto name() const { return m_name; }
auto uniqueId() const { return m_uniqueId; }
const auto& type() const { return m_type; }
auto& type() { return m_type; }
const auto& index() const { return m_index; }
struct PatternAny
{
static const Term& GetPattern();
static optional< Term > GetDomain() { return sema::DomainAny(); }
};
|
| ︙ | ︙ | |||
81 82 83 84 85 86 87 |
static auto GetDomain() { return PP::GetDomain(); }
};
private:
StringId m_name;
Term m_type;
uint32_t m_uniqueId = 0;
| < | 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
static auto GetDomain() { return PP::GetDomain(); }
};
private:
StringId m_name;
Term m_type;
uint32_t m_uniqueId = 0;
uint32_t m_index = 0;
};
}
namespace goose::ir
{
template<>
|
| ︙ | ︙ |
Changes to bs/builtins/types/localvar/unify.cpp.
| ︙ | ︙ | |||
24 25 26 27 28 29 30 |
[]( const Term& lhs, const Term& rhs, UnificationContext& c ) -> UniGen
{
auto locvar = FromValue< LocalVar >( *ValueFromIRExpr( rhs ) );
if( !locvar )
co_return;
auto varcontent = ValueToIRExpr( BuildComputedValue( locvar->type(),
| | | 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
[]( const Term& lhs, const Term& rhs, UnificationContext& c ) -> UniGen
{
auto locvar = FromValue< LocalVar >( *ValueFromIRExpr( rhs ) );
if( !locvar )
co_return;
auto varcontent = ValueToIRExpr( BuildComputedValue( locvar->type(),
GetVar( locvar->type(), locvar->index() ) ) );
// Unify the param with the var's content
co_yield Unify( lhs, varcontent, c );
} );
// LocalVar unification against another LocalVar: unify their types.
e.unificationRuleSet()->addSymRule(
|
| ︙ | ︙ |
Changes to bs/codegen/func.cpp.
| ︙ | ︙ | |||
65 66 67 68 69 70 71 |
{
inf.lastEmittedAlloca = m_llvmBuilder.CreateAlloca( arg.getType() );
args.push_back( inf.lastEmittedAlloca );
}
size_t i = 0;
for( auto&& arg : pllvmFunc->args() )
| > | > > | < | 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
{
inf.lastEmittedAlloca = m_llvmBuilder.CreateAlloca( arg.getType() );
args.push_back( inf.lastEmittedAlloca );
}
size_t i = 0;
for( auto&& arg : pllvmFunc->args() )
{
m_llvmBuilder.CreateStore( &arg, args[i] );
inf.temporaries->set( i, args[i] );
++i;
}
if( !buildCFG( inf, pllvmFunc, func.llr()->body() ) )
return nullptr;
llvm::verifyFunction( *pllvmFunc );
return pllvmFunc;
}
|
| ︙ | ︙ |
Changes to bs/codegen/instructions.cpp.
| ︙ | ︙ | |||
90 91 92 93 94 95 96 |
}
return m_llvmBuilder.CreateCall( llvmCallee, args );
}
llvm::Value* Module::buildInstruction( Infos& inf, const llr::CreateTemporary& ct )
{
| | | | | | | | | 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 |
}
return m_llvmBuilder.CreateCall( llvmCallee, args );
}
llvm::Value* Module::buildInstruction( Infos& inf, const llr::CreateTemporary& ct )
{
return createTemporary( inf, ct.index(), buildValue( inf, ct.value() ) );
}
llvm::Value* Module::buildInstruction( Infos& inf, const llr::GetTemporary& gt )
{
auto* ppVal = inf.temporaries->get( gt.index() );
assert( ppVal );
if( !ppVal )
return nullptr;
return *ppVal;
}
llvm::Value* Module::createTemporary( Infos& inf, uint32_t index, llvm::Value* pValue ) const
{
inf.temporaries->set( index, pValue );
return pValue;
}
llvm::Value* Module::buildInstruction( Infos& inf, const llr::AllocVar& av )
{
auto type = LowerType( inf.context, av.type() );
if( !type )
return nullptr;
llvm::IRBuilderBase::InsertPointGuard g( m_llvmBuilder );
if( inf.lastEmittedAlloca && inf.lastEmittedAlloca->getNextNode() )
m_llvmBuilder.SetInsertPoint( inf.lastEmittedAlloca->getNextNode() );
else
m_llvmBuilder.SetInsertPoint( inf.allocaBasicBlock, inf.allocaBasicBlock->begin() );
inf.lastEmittedAlloca = m_llvmBuilder.CreateAlloca( GetLLVMType( *type ) );
createTemporary( inf, av.index(), inf.lastEmittedAlloca );
return inf.lastEmittedAlloca;
}
llvm::Value* Module::buildInstruction( Infos& inf, const llr::GetVar& gv )
{
return m_llvmBuilder.CreateLoad( *inf.temporaries->get( gv.index() ) );
}
llvm::Value* Module::buildInstruction( Infos& inf, const llr::SetVar& sv )
{
auto val = buildValue( inf, sv.value() );
if( !val )
return nullptr;
return m_llvmBuilder.CreateStore( val, *inf.temporaries->get( sv.index() ) );
}
llvm::Value* Module::buildInstruction( Infos& inf, const llr::Phi& p )
{
auto type = LowerType( inf.context, p.type() );
if( !type )
return nullptr;
|
| ︙ | ︙ | |||
178 179 180 181 182 183 184 |
return true;
} );
}
if( !pPHI )
return nullptr;
| | | 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 |
return true;
} );
}
if( !pPHI )
return nullptr;
return createTemporary( inf, p.destIndex(), pPHI );
}
llvm::Value* Module::buildInstruction( Infos& inf, const llr::LoadConstStr& lcs )
{
llvm::GlobalVariable* pGlob = nullptr;
auto* arType = llvm::ArrayType::get( llvm::IntegerType::getInt8Ty( GetLLVMContext() ),
|
| ︙ | ︙ |
Changes to bs/codegen/module.h.
| ︙ | ︙ | |||
99 100 101 102 103 104 105 |
template< typename T >
bool buildTerminator( Infos& inf, const T& t )
{
return false;
}
| | | 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
template< typename T >
bool buildTerminator( Infos& inf, const T& t )
{
return false;
}
llvm::Value* createTemporary( Infos& inf, uint32_t index, llvm::Value* pValue ) const;
llvm::Module m_llvmModule;
llvm::IRBuilder<> m_llvmBuilder;
llvm::TargetMachine* m_targetMachine = nullptr;
unordered_map< string, llvm::GlobalVariable* > m_strings;
};
|
| ︙ | ︙ |
Changes to bs/compile/compiler.cpp.
| ︙ | ︙ | |||
100 101 102 103 104 105 106 |
DiagnosticsContext dc( 0, true );
VerbosityContext vc( Verbosity::Normal, true );
auto r = make_shared< parse::Resolver >(
make_shared< lex::Lexer >( sourcefile, filename ), c );
parse::Parser p( r );
| | | 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
DiagnosticsContext dc( 0, true );
VerbosityContext vc( Verbosity::Normal, true );
auto r = make_shared< parse::Resolver >(
make_shared< lex::Lexer >( sourcefile, filename ), c );
parse::Parser p( r );
auto cfg = make_shared< llr::CFG >( 0 );
cfg->createBB();
p.setCFG( cfg );
p.cfg()->setCurrentBB( cfg->entryBB() );
p.parseSequence();
if( cfg->isPoisoned() )
|
| ︙ | ︙ |
Changes to bs/execute/frame.h.
1 2 3 4 5 6 7 8 9 |
#ifndef GOOSE_EXECUTE_FRAME_H
#define GOOSE_EXECUTE_FRAME_H
namespace goose::execute
{
class Frame
{
public:
template< typename V >
| < < < < < < | | | | | 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_EXECUTE_FRAME_H
#define GOOSE_EXECUTE_FRAME_H
namespace goose::execute
{
class Frame
{
public:
template< typename V >
void setTemporary( uint32_t index, V&& val )
{
m_temporaries.set( index, forward< V >( val ) );
}
const auto* getTemporary( uint32_t index ) const
{
return m_temporaries.get( index );
}
const auto& retVal() const { return m_retVal; }
void setRetVal( const Value& val ) { m_retVal = val; }
private:
TempStorage< optional< Value > > m_temporaries;
|
| ︙ | ︙ |
Changes to bs/execute/vm.cpp.
| ︙ | ︙ | |||
108 109 110 111 112 113 114 |
if( !pFunc || !pFunc->isValid() )
return PoisonValue();
Frame f;
llvm::SmallVector< optional< Value >, 8 > args;
| | | < < | | | | | | 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 |
if( !pFunc || !pFunc->isValid() )
return PoisonValue();
Frame f;
llvm::SmallVector< optional< Value >, 8 > args;
uint32_t argIndex = 0;
for( auto&& a : vec.terms() )
{
auto val = ValueFromIRExpr( a );
assert( val );
auto newVal = Evaluate( *val, *this );
if( newVal.isPoison() )
return PoisonValue();
if( !newVal.isConstant() )
{
DiagnosticsManager::GetInstance().emitErrorMessage( 0,
"Execute: args evaluation failed." );
return PoisonValue();
}
f.setTemporary( argIndex++, move( newVal ) );
}
swap( m_frame, f );
auto result = execute( *pFunc->body() );
swap( m_frame, f );
return result;
}
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 )
{
m_frame.setTemporary( ct.index(), Evaluate( ct.value(), *this ) );
return nullopt;
}
optional< Value > VM::execute( const llr::GetTemporary& gt )
{
const auto* pVal = m_frame.getTemporary( gt.index() );
assert( pVal );
if( !pVal )
return PoisonValue();
return *pVal;
}
optional< Value > VM::execute( const llr::GetVar& gv )
{
const auto* pVal = m_frame.getTemporary( gv.index() );
if( !pVal )
return PoisonValue();
return *pVal;
}
optional< Value > VM::execute( const llr::SetVar& sv )
{
auto result = Evaluate( sv.value(), *this );
if( !result.isConstant() )
result = PoisonValue();
m_frame.setTemporary( sv.index(), result );
return nullopt;
}
optional< Value > VM::execute( const llr::Phi& p )
{
p.forAllIncomings( [&]( auto&& bb, auto&& val )
{
if( bb == m_pPreviousBB )
{
m_frame.setTemporary( p.destIndex(), Evaluate( val, *this ) );
return false;
}
return true;
} );
return PoisonValue();
|
| ︙ | ︙ |
Changes to bs/llr/allocvar.h.
1 2 3 4 5 6 7 8 9 |
#ifndef GOOSE_LLR_ALLOCVAR_H
#define GOOSE_LLR_ALLOCVAR_H
namespace goose::llr
{
class AllocVar
{
public:
template< typename T >
| | < < < | 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 |
#ifndef GOOSE_LLR_ALLOCVAR_H
#define GOOSE_LLR_ALLOCVAR_H
namespace goose::llr
{
class AllocVar
{
public:
template< typename T >
AllocVar( T&& type, uint32_t index ) :
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;
}
private:
ir::Value m_type;
uint32_t m_index = 0;
};
}
#endif
|
Changes to bs/llr/cfg.h.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#ifndef GOOSE_LLR_CFG_H
#define GOOSE_LLR_CFG_H
namespace goose::llr
{
class BasicBlock;
class CFG : public enable_shared_from_this< CFG >
{
public:
bool isPoisoned() const { return m_poisoned; }
void poison() { m_poisoned = true; }
const auto& entryBB() const { return m_basicBlocks.front(); }
const auto& lastBB() const { return m_basicBlocks.back(); }
const auto& currentBB() const { return m_currentBB; }
| > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
#ifndef GOOSE_LLR_CFG_H
#define GOOSE_LLR_CFG_H
namespace goose::llr
{
class BasicBlock;
class CFG : public enable_shared_from_this< CFG >
{
public:
CFG( uint32_t numParams ) :
m_temporariesCount( numParams )
{}
bool isPoisoned() const { return m_poisoned; }
void poison() { m_poisoned = true; }
const auto& entryBB() const { return m_basicBlocks.front(); }
const auto& lastBB() const { return m_basicBlocks.back(); }
const auto& currentBB() const { return m_currentBB; }
|
| ︙ | ︙ | |||
41 42 43 44 45 46 47 |
// calling ComputeDominators().
optional< uint32_t > getDominatorDistance( uint32_t bbIndex1, uint32_t bbIndex2 ) const;
const auto& getBB( uint32_t index ) const { return m_basicBlocks[index - 1]; }
auto count() const { return m_basicBlocks.size(); }
| < < < | | | | | 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 |
// calling ComputeDominators().
optional< uint32_t > getDominatorDistance( uint32_t bbIndex1, uint32_t bbIndex2 ) const;
const auto& getBB( uint32_t index ) const { return m_basicBlocks[index - 1]; }
auto count() const { return m_basicBlocks.size(); }
const ptr< llr::BasicBlock >& createBB();
auto getNewTemporaryIndex() { return m_temporariesCount++; }
// Clear the llvm basic block pointers from the entire cfg.
void unbindFromLLVM();
bool canBeExecuted() const;
bool canBeEagerlyEvaluated() const;
template< typename F >
void forEachBB( F&& func )
{
for( auto&& bb : m_basicBlocks )
func( bb );
}
void setVariableModifiedByLoop( uint32_t loopId, const ir::Term& type, uint32_t varId )
{
m_loopModifiedVariables.emplace( loopId, make_tuple( type, varId ) );
}
template< typename F >
void forEachVariableModifiedInLoop( uint32_t loopId, F&& func ) const
{
auto&& [begin, end] = m_loopModifiedVariables.equal_range( loopId );
for( auto it = begin; it != end; ++it )
func( get< 0 >( it->second ), get< 1 >( it->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 the indices of all the variables modified
// during that loop.
// May be be empty if it has not (yet) been computed.
unordered_multimap< uint32_t, tuple< ir::Term, uint32_t > >
m_loopModifiedVariables;
// The number of temporary indices used by this CFG.
uint32_t m_temporariesCount = 0;
uint32_t m_loopCount = 0;
|
| ︙ | ︙ |
Changes to bs/llr/cfgviz.cpp.
| ︙ | ︙ | |||
83 84 85 86 87 88 89 |
} );
auto id = builder.getNodeId( &instr.value() );
GraphVizBuilder::Row row( builder );
GraphVizBuilder::Cell cell( builder );
GraphVizBuilder::Color col( builder, GraphVizBuilder::GetNodeColor( id ) );
| | | | | | | 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
} );
auto id = builder.getNodeId( &instr.value() );
GraphVizBuilder::Row row( builder );
GraphVizBuilder::Cell cell( builder );
GraphVizBuilder::Color col( builder, GraphVizBuilder::GetNodeColor( id ) );
builder.output() << "CreateTemporary " << instr.index() << ", " << id;
builder.addEdge( builder.currentNodeId(), id );
}
void CfgViz( GraphVizBuilder& builder, const GetTemporary& instr )
{
GraphVizBuilder::Row row( builder );
GraphVizBuilder::Cell cell( builder );
GraphVizBuilder::Color col( builder );
builder.output() << "GetTemporary " << instr.index();
}
void CfgViz( GraphVizBuilder& builder, const AllocVar& instr )
{
GraphVizBuilder::Row row( builder );
GraphVizBuilder::Cell cell( builder );
GraphVizBuilder::Color col( builder );
builder.output() << "AllocVar " << instr.index();
}
void CfgViz( GraphVizBuilder& builder, const GetVar& instr )
{
GraphVizBuilder::Row row( builder );
GraphVizBuilder::Cell cell( builder );
GraphVizBuilder::Color col( builder );
builder.output() << "GetVar " << instr.index();
}
void CfgViz( GraphVizBuilder& builder, const SetVar& instr )
{
GraphVizBuilder::Row row( builder );
GraphVizBuilder::Cell cell( builder );
GraphVizBuilder::Color col( builder );
builder.output() << "SetVar " << instr.index();
}
void CfgViz( GraphVizBuilder& builder, const Phi& instr )
{
{
GraphVizBuilder::Row row( builder );
GraphVizBuilder::Cell cell( builder );
|
| ︙ | ︙ |
Changes to bs/llr/createtemporary.h.
1 2 3 4 5 6 7 8 9 |
#ifndef GOOSE_LLR_CREATETEMPORARY_H
#define GOOSE_LLR_CREATETEMPORARY_H
namespace goose::llr
{
class CreateTemporary
{
public:
template< typename V >
| | < < < | 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 |
#ifndef GOOSE_LLR_CREATETEMPORARY_H
#define GOOSE_LLR_CREATETEMPORARY_H
namespace goose::llr
{
class CreateTemporary
{
public:
template< typename V >
CreateTemporary( uint32_t index, V&& val ) :
m_index( index ),
m_value( forward< V >( val ) )
{}
const auto& index() const { return m_index; }
const auto& value() const { return m_value; }
bool canBeExecuted() const
{
return IsValueConstantOrExecutable( m_value );
}
bool canBeEagerlyEvaluated() const
{
return CanValueBeEagerlyEvaluated( m_value );
}
private:
uint32_t m_index = 0;
ir::Value m_value;
};
}
#endif
|
Changes to bs/llr/gettemporary.h.
1 2 3 4 5 6 7 8 9 |
#ifndef GOOSE_LLR_GETTEMPORARY_H
#define GOOSE_LLR_GETTEMPORARY_H
namespace goose::llr
{
class GetTemporary
{
public:
template< typename T >
| | < < < | 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 |
#ifndef GOOSE_LLR_GETTEMPORARY_H
#define GOOSE_LLR_GETTEMPORARY_H
namespace goose::llr
{
class GetTemporary
{
public:
template< typename T >
GetTemporary( T&& type, uint32_t index ) :
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;
}
private:
ir::Term m_type;
uint32_t m_index = 0;
};
}
#endif
|
Changes to bs/llr/getvar.h.
| ︙ | ︙ | |||
8 9 10 11 12 13 14 |
// executed eagerly (that is, not from within a function while that function
// is being compiled).
// So we do need to have both.
class GetVar
{
public:
template< typename T >
| | < < < | 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 |
// executed eagerly (that is, not from within a function while that function
// is being compiled).
// So we do need to have both.
class GetVar
{
public:
template< typename T >
GetVar( T&& type, uint32_t index ) :
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;
}
private:
ir::Term m_type;
uint32_t m_index = 0;
};
}
#endif
|
Changes to bs/llr/helpers.h.
| ︙ | ︙ | |||
16 17 18 19 20 21 22 |
}
template< typename T >
class TempStorage
{
public:
template< typename TT >
| | | < < < < | | < < < < < < < | | < < < | | | < < < | | < | 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 |
}
template< typename T >
class TempStorage
{
public:
template< typename TT >
auto& set( uint32_t index, TT&& x )
{
auto [it, inserted] = m_storage.try_emplace( index );
it->second = forward< TT >( x );
return it->second;
}
const T* get( uint32_t index ) const
{
auto it = m_storage.find( index );
if( it == m_storage.end() )
return nullptr;
return &it->second;
}
T* get( uint32_t index )
{
auto it = m_storage.find( index );
if( it == m_storage.end() )
return nullptr;
return &it->second;
}
private:
unordered_map< uint32_t, T > m_storage;
};
}
#endif
|
Changes to bs/llr/loopvars.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 |
#include "llr.h"
namespace goose::llr
{
void MarkVarChangedByLoop( const ptr< CFG >& cfg, uint32_t loopId, const ir::Term& type, uint32_t varId )
{
cfg->setVariableModifiedByLoop( loopId, type, varId );
const auto& pHeader = cfg->getBB( loopId );
if( pHeader->loopId() )
MarkVarChangedByLoop( cfg, pHeader->loopId(), type, varId );
}
void ComputeLoopModifiedVars( const ptr< CFG >& cfg )
{
cfg->forEachBB( [&]( auto&& bb )
{
for( auto&& instr : *bb )
{
if( auto sv = get_if< SetVar >( &instr.content() ) )
{
const auto& type = sv->value().type();
if( bb->isLoopHeader() )
MarkVarChangedByLoop( cfg, bb->index(), type, sv->index() );
else if( bb->loopId() )
MarkVarChangedByLoop( cfg, bb->loopId(), type, sv->index() );
}
}
} );
}
}
|
Changes to bs/llr/phi.h.
1 2 3 4 5 6 7 8 9 10 11 |
#ifndef GOOSE_LLR_PHI_H
#define GOOSE_LLR_PHI_H
namespace goose::llr
{
class BasicBlock;
class Phi
{
public:
template< typename T >
| | < < | 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 |
#ifndef GOOSE_LLR_PHI_H
#define GOOSE_LLR_PHI_H
namespace goose::llr
{
class BasicBlock;
class Phi
{
public:
template< typename T >
Phi( T&& type, uint32_t numIncomings, uint32_t destIndex ) :
m_type( forward< T >( type ) ),
m_destIndex( destIndex )
{
m_incomings.reserve( numIncomings );
}
const auto& type() const { return m_type; }
const auto& destIndex() const { return m_destIndex; }
void setIncoming( const ptr< BasicBlock >& bb, const ir::Value& val )
{
m_incomings.emplace_back( bb, val );
}
|
| ︙ | ︙ | |||
46 47 48 49 50 51 52 |
bool canBeEagerlyEvaluated() const
{
return true;
}
private:
ir::Value m_type;
| < | 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
bool canBeEagerlyEvaluated() const
{
return true;
}
private:
ir::Value m_type;
uint32_t m_destIndex = 0;
using incInfo = pair< wptr< BasicBlock >, ir::Value >;
llvm::SmallVector< incInfo, 2 > m_incomings;
};
}
#endif
|
Changes to bs/llr/setvar.h.
1 2 3 4 5 6 7 8 9 |
#ifndef GOOSE_LLR_SETVAR_H
#define GOOSE_LLR_SETVAR_H
namespace goose::llr
{
class SetVar
{
public:
template< typename T >
| | < < < | 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 |
#ifndef GOOSE_LLR_SETVAR_H
#define GOOSE_LLR_SETVAR_H
namespace goose::llr
{
class SetVar
{
public:
template< typename T >
SetVar( T&& val, uint32_t index ) :
m_value( forward< T >( val ) ),
m_index( index )
{}
const auto& value() const { return m_value; }
const auto& index() const { return m_index; }
bool canBeExecuted() const
{
return true;
}
bool canBeEagerlyEvaluated() const
{
return false;
}
private:
ir::Value m_value;
uint32_t m_index = 0;
};
}
#endif
|
Changes to bs/llr/tests/dom-1.cpp.
| ︙ | ︙ | |||
8 9 10 11 12 13 14 |
using namespace goose::ir;
using namespace goose::llr;
SCENARIO( "Dominators test 1", "[llr-dom-1]" )
{
WHEN( "Computing the dominators of an arbitrary CFG" )
{
| | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
using namespace goose::ir;
using namespace goose::llr;
SCENARIO( "Dominators test 1", "[llr-dom-1]" )
{
WHEN( "Computing the dominators of an arbitrary CFG" )
{
auto cfg = make_shared< CFG >( 0 );
auto bb1 = cfg->createBB();
auto bb2 = cfg->createBB();
auto bb3 = cfg->createBB();
auto bb4 = cfg->createBB();
auto bb5 = cfg->createBB();
auto bb6 = cfg->createBB();
|
| ︙ | ︙ |
Changes to bs/llr/tests/dom-2.cpp.
| ︙ | ︙ | |||
8 9 10 11 12 13 14 |
using namespace goose::ir;
using namespace goose::llr;
SCENARIO( "Dominators test 1", "[llr-dom-1]" )
{
WHEN( "Computing the dominators of an arbitrary CFG" )
{
| | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
using namespace goose::ir;
using namespace goose::llr;
SCENARIO( "Dominators test 1", "[llr-dom-1]" )
{
WHEN( "Computing the dominators of an arbitrary CFG" )
{
auto cfg = make_shared< CFG >( 0 );
auto bb1 = cfg->createBB();
auto bb2 = cfg->createBB();
auto bb3 = cfg->createBB();
auto bb4 = cfg->createBB();
auto bb5 = cfg->createBB();
auto bb6 = cfg->createBB();
|
| ︙ | ︙ |
Changes to bs/verify/builder.cpp.
| ︙ | ︙ | |||
43 44 45 46 47 48 49 |
cout << "check_unsat " << ( *m_currentPredicate && !e ) << endl;
}
m_checkFailed = m_checkFailed || !result;
return result;
}
| | | | | | | | | | | | | | | | | 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 |
cout << "check_unsat " << ( *m_currentPredicate && !e ) << endl;
}
m_checkFailed = m_checkFailed || !result;
return result;
}
const z3::expr* Builder::getVarForBasicBlock( uint32_t bbIndex, uint32_t index ) const
{
const auto* vs = m_varStorage.get( index );
if( !vs )
return nullptr;
if( vs->size() <= bbIndex )
return nullptr;
const auto& optExpr = (*vs)[ bbIndex ];
if( !optExpr )
return nullptr;
return &*optExpr;
}
const z3::expr& Builder::setVarForBasicBlock( uint32_t bbIndex, uint32_t index, z3::expr&& e )
{
auto* vs = m_varStorage.get( index );
if( !vs )
{
VarState newVS;
newVS.resize( bbIndex + 1 );
vs = &m_varStorage.set( index, move( newVS ) );
}
else if( vs->size() <= bbIndex )
vs->resize( bbIndex + 1 );
(*vs)[ bbIndex ] = move( e );
return *(*vs)[ bbIndex ];
}
const z3::expr* Builder::retrieveVar( uint32_t index, const Term& type, uint32_t bbIndex )
{
if( bbIndex == m_currentBBIndex )
return nullptr;
if( bbIndex == ~0 )
bbIndex = m_currentBBIndex;
const auto* expr = getVarForBasicBlock( bbIndex, index );
if( expr )
return expr;
if( !m_cfg )
return nullptr;
auto newVar = BuildZ3ConstantFromType( type, format( "v{}", m_nextUniqueId++ ) );
if( !newVar )
return nullptr;
auto& c = GetZ3Context();
// Model the ssa phi operation by creating a series of equality assertions, each implied by
// one of the possible incoming edge condition for the current basic block.
if( m_remapper )
{
m_remapper->forEachIncomingEdge( bbIndex, [&]( auto&& predIndex, auto&& expr )
{
if( const auto* predVar = retrieveVar( index, type, predIndex ) )
add( z3::implies( c.bool_const( format( "e{}_{}", predIndex, bbIndex ).c_str() ), *newVar == *predVar ) );
} );
}
return &setVarForBasicBlock( bbIndex, index, move( *newVar ) );
}
void Builder::setVar( uint32_t index, const Value& val )
{
if( !m_cfg )
return;
auto newVar = BuildZ3ConstantFromType( val.type(), format( "v{}", m_nextUniqueId++ ) );
if( !newVar )
return;
if( auto expr = BuildZ3ExprFromValue( *this, val ) )
assume( *newVar == *expr );
setVarForBasicBlock( m_currentBBIndex, index, move( *newVar ) );
}
void Builder::setVar( uint32_t index, z3::expr&& expr )
{
setVarForBasicBlock( m_currentBBIndex, index, move( expr ) );
}
void Builder::havocVar( uint32_t bbIndex, const Term& type, uint32_t index )
{
if( !m_cfg )
return;
auto newVar = BuildZ3ConstantFromType( type, format( "v{}", m_nextUniqueId++ ) );
if( !newVar )
return;
setVarForBasicBlock( bbIndex, index, move( *newVar ) );
}
const z3::expr* Builder::retrievePlaceholder( const StringId& sid ) const
{
auto it = m_placeholders.find( sid );
if( it == m_placeholders.end() )
return nullptr;
|
| ︙ | ︙ |
Changes to bs/verify/builder.h.
| ︙ | ︙ | |||
40 41 42 43 44 45 46 |
m_currentPredicate = predicate;
}
void add( const z3::expr& e );
void assume( const z3::expr& e );
bool checkAssertion( const z3::expr& e, uint32_t locationId );
| | | | | | | | 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 |
m_currentPredicate = predicate;
}
void add( const z3::expr& e );
void assume( const z3::expr& e );
bool checkAssertion( const z3::expr& e, uint32_t locationId );
const z3::expr* retrieveVar( uint32_t index, const Term& type, uint32_t bbIndex = ~0 );
void setVar( uint32_t index, const Value& val );
void setVar( uint32_t index, z3::expr&& expr );
// Havoc (make undefined) a variable for a given basic block.
void havocVar( uint32_t bbIndex, const Term& type, uint32_t index );
const z3::expr* retrievePlaceholder( const StringId& sid ) const;
void setPlaceholder( const StringId& sid, const z3::expr& expr );
uint32_t newUniqueId() { return m_nextUniqueId++; }
bool hasCheckFailed() const { return m_checkFailed; }
template< typename F >
void setAssertionHandler( F&& handler )
{
m_assertionHandler = forward< F >( handler );
}
private:
const z3::expr* getVarForBasicBlock( uint32_t bbIndex, uint32_t index ) const;
const z3::expr& setVarForBasicBlock( uint32_t bbIndex, uint32_t index, z3::expr&& e );
z3::solver* m_solver = nullptr;
Remapper* m_remapper = nullptr;
ptr< llr::CFG > m_cfg;
uint32_t m_currentBBIndex = 1;
|
| ︙ | ︙ |
Changes to bs/verify/call.cpp.
| ︙ | ︙ | |||
20 21 22 23 24 25 26 |
// Create a temporary builder to construct the z3 expressions out of the
// function's pre-conditions and postconditions, configured
// to perform the necessary replacements for arguments and for the
// return value placeholder.
Builder cb( *b.solver(), b.remapper() );
| | | | 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 |
// Create a temporary builder to construct the z3 expressions out of the
// function's pre-conditions and postconditions, configured
// to perform the necessary replacements for arguments and for the
// return value placeholder.
Builder cb( *b.solver(), b.remapper() );
// Inject the arguments in the context.
// They will be picked up by getVars instructions when refered to
// by the verification conditions.
uint32_t index = 0;
ForEachInVectorTerm( instr.args(), [&]( auto&& t )
{
auto arg = *ValueFromIRExpr( t );
if( auto expr = BuildZ3ExprFromValue( b, arg ) )
cb.setVar( index++, move( *expr ) );
return true;
} );
// Setup the return value placeholder
if( retExpr )
cb.setPlaceholder( "@"_sid, *retExpr );
|
| ︙ | ︙ |
Changes to bs/verify/loop.cpp.
| ︙ | ︙ | |||
55 56 57 58 59 60 61 |
} );
// Havoc all the variables modified during the current loop and emit
// the first unrolling for the induction case.
m_remapper.nextLoopIteration();
uint32_t firstInductionIterationHeaderIndex = m_remapper.remapBBId( bb );
| | | | 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
} );
// Havoc all the variables modified during the current loop and emit
// the first unrolling for the induction case.
m_remapper.nextLoopIteration();
uint32_t firstInductionIterationHeaderIndex = m_remapper.remapBBId( bb );
m_cfg->forEachVariableModifiedInLoop( bb.index(), [&]( auto&& type, uint32_t varId )
{
m_builder.havocVar( firstInductionIterationHeaderIndex, type, varId );
} );
buildZ3Expressions( bb, &parentWorkQueue );
// Emit the rest of the induction case.
uint32_t i = 1;
while( i < k )
|
| ︙ | ︙ |
Changes to bs/verify/value.cpp.
| ︙ | ︙ | |||
62 63 64 65 66 67 68 |
}
// Implemented in call.cpp
extern optional< z3::expr > BuildZ3Op( Builder& b, const Call& instr );
optional< z3::expr > BuildZ3Op( Builder& b, const CreateTemporary& instr )
{
| | | | | | | | 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 |
}
// Implemented in call.cpp
extern optional< z3::expr > BuildZ3Op( Builder& b, const Call& instr );
optional< z3::expr > BuildZ3Op( Builder& b, const CreateTemporary& instr )
{
b.setVar( instr.index(), instr.value() );
return nullopt;
}
optional< z3::expr > BuildZ3Op( Builder& b, const GetTemporary& instr )
{
const auto* expr = b.retrieveVar( instr.index(), instr.type() );
if( expr )
return *expr;
return BuildZ3ConstantFromType( instr.type(), format( "v{}", instr.index() ) );
}
optional< z3::expr > BuildZ3Op( Builder& b, const GetVar& instr )
{
const auto* expr = b.retrieveVar( instr.index(), instr.type() );
if( expr )
return *expr;
return BuildZ3ConstantFromType( instr.type(), format( "v{}", instr.index() ) );
}
optional< z3::expr > BuildZ3Op( Builder& b, const SetVar& instr )
{
b.setVar( instr.index(), instr.value() );
return nullopt;
}
// TODO: Phi. Construct an expression combining all of the incoming z3 expressions from all the possible incoming blocks.
// TODO: LoadConstStr. Build a z3 str value.
|
| ︙ | ︙ |