Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | FuncValidator: more work on the implementation. |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA3-256: |
98a85945f6fe4a920a83d743037b0eba |
| User & Date: | achavasse 2019-10-02 20:09:26.523 |
Context
|
2019-10-02
| ||
| 22:11 | z3 builder: instead of directly adding negated assertions to the solver, gather them into a conjunction and add that. check-in: 2734029a31 user: achavasse tags: trunk | |
| 20:09 | FuncValidator: more work on the implementation. check-in: 98a85945f6 user: achavasse tags: trunk | |
| 19:30 | Implemented a helper class allowing to wrap each z3 expression with a predicate indicating that the execution flow went through a certain basic block. check-in: 1d340c945f user: achavasse tags: trunk | |
Changes
Changes to bs/analyze/analyze.h.
| ︙ | ︙ | |||
9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
using namespace ir;
using namespace llr;
class Builder;
extern z3::context& GetZ3Context();
extern optional< z3::expr > BuildZ3ExprFromValue( Builder& b, const Value& val );
}
#include "builder.h"
#include "verifstmtvalidator.h"
#include "funcvalidator.h"
#endif
| > | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
using namespace ir;
using namespace llr;
class Builder;
extern z3::context& GetZ3Context();
extern optional< z3::expr > BuildZ3ExprFromValue( Builder& b, const Value& val );
extern optional< z3::expr > BuildZ3Op( Builder& b, const llr::Instruction& instr );
}
#include "builder.h"
#include "verifstmtvalidator.h"
#include "funcvalidator.h"
#endif
|
Changes to bs/analyze/builder.cpp.
| ︙ | ︙ | |||
14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
}
m_solver.add( z3::implies( *m_currentPredicate, e ) );
}
void Builder::addAssertion( const z3::expr e )
{
if( !m_currentPredicate )
{
m_solver.add( !e );
return;
}
m_solver.add( z3::implies( *m_currentPredicate, !e ) );
| > > | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
}
m_solver.add( z3::implies( *m_currentPredicate, e ) );
}
void Builder::addAssertion( const z3::expr e )
{
m_haveAnyAssertion = true;
if( !m_currentPredicate )
{
m_solver.add( !e );
return;
}
m_solver.add( z3::implies( *m_currentPredicate, !e ) );
|
| ︙ | ︙ |
Changes to bs/analyze/builder.h.
| ︙ | ︙ | |||
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
Builder( z3::solver& solver ) :
m_solver( solver )
{}
void addAssumption( const z3::expr e );
void addAssertion( const z3::expr e );
private:
z3::solver& m_solver;
// All emitted assumptions and assertions are wrapped
// with implication from this predicate.
// This is used to model the control flow, where each
// basic block gets a predicate that indicates that
// the execution flow is going through that block.
optional< z3::expr > m_currentPredicate;
};
}
#endif
| > > > > > > | 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 |
Builder( z3::solver& solver ) :
m_solver( solver )
{}
void addAssumption( const z3::expr e );
void addAssertion( const z3::expr e );
bool haveAnyAssertion() const { return m_haveAnyAssertion; }
private:
z3::solver& m_solver;
// All emitted assumptions and assertions are wrapped
// with implication from this predicate.
// This is used to model the control flow, where each
// basic block gets a predicate that indicates that
// the execution flow is going through that block.
optional< z3::expr > m_currentPredicate;
// Check if we actually emitted any assertion. If we didn't,
// then we have no condition to prove, so just skip the checking.
bool m_haveAnyAssertion = false;
};
}
#endif
|
Changes to bs/analyze/funcvalidator.cpp.
1 2 3 4 5 6 7 8 9 |
#include "analyze.h"
#include "builtins/builtins.h"
#include "diagnostics/diagnostics.h"
using namespace goose::analyze;
using namespace goose::diagnostics;
FuncValidator::FuncValidator( const builtins::Func& func ) :
m_solver( GetZ3Context() ),
| | > > > > | 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 |
#include "analyze.h"
#include "builtins/builtins.h"
#include "diagnostics/diagnostics.h"
using namespace goose::analyze;
using namespace goose::diagnostics;
FuncValidator::FuncValidator( const builtins::Func& func ) :
m_solver( GetZ3Context() ),
m_builder( m_solver ),
m_func( func )
{
buildZ3Formula( func );
}
bool FuncValidator::validate()
{
if( !m_builder.haveAnyAssertion() )
return true;
switch( m_solver.check() )
{
case z3::check_result::unsat:
// We are using the solver to try and find a counter example,
// so if it's unsat, it's good.
return true;
|
| ︙ | ︙ | |||
52 53 54 55 56 57 58 |
return true;
} );
const auto& llr = func.llr();
const auto& cfg = llr->body();
| | > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
return true;
} );
const auto& llr = func.llr();
const auto& cfg = llr->body();
// For now, we assume that the BBs are already ordered so that each BB's dominating BB precedes it,
// which should be the case due to the way if, while and shortcut eval operators are implemented.
cfg->ForEachBB( [&]( auto&& bb )
{
buildFormulasForBB( bb );
} );
}
void FuncValidator::buildFormulasForBB( const ptr< llr::BasicBlock >& bb )
{
// TODO: setup the predicate for this basic block
for( auto&& x : *bb )
BuildZ3Op( m_builder, x );
handleTerminator( *bb->terminator() );
}
void FuncValidator::handleTerminator( const llr::Terminator& t )
{
return visit( [&]( auto&& t )
{
return handleTerminator( t );
}, t.content() );
}
void FuncValidator::handleTerminator( const llr::Ret& t )
{
// Emit the "ensures" expressions as assertions.
const auto& reqs = m_func.type().verifInfos()->postAssertion();
ForEachInVectorTerm( reqs, [&]( auto&& t )
{
// Don't do any error handling here, it should already have been taken care of
// by VerifStmtValidator.
if( auto z3expr = BuildZ3ExprFromValue( m_builder, *ValueFromIRExpr( t ) ) )
m_builder.addAssertion( *z3expr );
return true;
} );
}
void FuncValidator::handleTerminator( const llr::Branch& t )
{
// TODO - set the predicate of the target BB to be the same as the current BB's
}
void FuncValidator::handleTerminator( const llr::CondBranch& t )
{
// TODO - set the predicate of the true BB to a z3expr generated from the condition,
// and the predicate for the false BB to its negation
}
|
Changes to bs/analyze/funcvalidator.h.
| ︙ | ︙ | |||
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
FuncValidator( const builtins::Func& func );
bool validate();
private:
void buildZ3Formula( const builtins::Func& func );
void buildFormulasForBB( const ptr< llr::BasicBlock >& bb );
z3::solver m_solver;
Builder m_builder;
// For now we don't attempt to handle loops. We only keep track
// of which basic blocks we already converted to formulas to avoid
// doing them again.
unordered_set< uint32_t > m_convertedBBIndices;
};
}
| > > > > > > > > > > > > | 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 |
FuncValidator( const builtins::Func& func );
bool validate();
private:
void buildZ3Formula( const builtins::Func& func );
void buildFormulasForBB( const ptr< llr::BasicBlock >& bb );
void handleTerminator( const llr::Terminator& t );
template< typename T >
void handleTerminator( const T& t )
{}
void handleTerminator( const llr::Ret& t );
void handleTerminator( const llr::Branch& t );
void handleTerminator( const llr::CondBranch& t );
z3::solver m_solver;
Builder m_builder;
const builtins::Func& m_func;
// For now we don't attempt to handle loops. We only keep track
// of which basic blocks we already converted to formulas to avoid
// doing them again.
unordered_set< uint32_t > m_convertedBBIndices;
};
}
|
| ︙ | ︙ |
Changes to bs/analyze/meson.build.
1 2 3 4 5 6 7 8 9 |
goose_analyze = library( 'goose-analyze',
'analyze.cpp',
'value.cpp',
'verifstmtvalidator.cpp',
'funcvalidator.cpp',
include_directories: bsinc,
dependencies: [fmt_dep, z3_dep]
)
| > | 1 2 3 4 5 6 7 8 9 10 |
goose_analyze = library( 'goose-analyze',
'analyze.cpp',
'value.cpp',
'builder.cpp',
'verifstmtvalidator.cpp',
'funcvalidator.cpp',
include_directories: bsinc,
dependencies: [fmt_dep, z3_dep]
)
|
Changes to bs/builtins/types/func/func.cpp.
| ︙ | ︙ | |||
332 333 334 335 336 337 338 |
// calls to DestroyValue() may also have requirements to enforce, so we'll need to emit
// the eventual implicit return first.
p.destroyAllLiveValues();
p.emitTerminator( llr::Ret() );
}
pFuncLLR->body() = cfg;
| > > | | 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 |
// calls to DestroyValue() may also have requirements to enforce, so we'll need to emit
// the eventual implicit return first.
p.destroyAllLiveValues();
p.emitTerminator( llr::Ret() );
}
pFuncLLR->body() = cfg;
analyze::FuncValidator fv( f );
return fv.validate();
}
Term BuildArgListForCall( const FuncType& ft, const Term& unifiedArgs )
{
auto av = make_shared< Vector >();
av->reserve( VecSize( ft.params() ) );
|
| ︙ | ︙ |