Goose  Diff

Differences From Artifact [7bf294508a]:

  • File bs/analyze/value.cpp — part of check-in [b6b76a4e03] at 2019-09-25 19:16:09 on branch trunk — Implemented a first batch of llr instruction to z3 expression conversions. (user: achavasse size: 5630)

To Artifact [b822f3d82d]:

  • File bs/analyze/value.cpp — part of check-in [7f14d60722] at 2019-09-26 00:27:15 on branch trunk — Static analysis: check that function verification statements are satisfiable and emit relevant error messages if they aren't. (user: achavasse size: 6454)

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
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





+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+













+
+
+
+
+
+











+
-
+
+
+
+
+
+
+
+
+
+
+









-
-
-
-
-
-







#include "analyze.h"
#include "builtins/builtins.h"

namespace goose::analyze
{
    optional< z3::expr > BuildZ3ValFromConstant( const Value& val )
    {
        auto& c = GetZ3Context();

        // TODO: what about very large int types? Can z3 represent them?

        if( auto b = FromValue< bool >( val ) )
            return c.bool_val( *b );
        else if( auto intVal = FromValue< APSInt >( val ) )
             return c.int_val( intVal->getExtValue() );

        return nullopt;
    }

    optional< z3::expr > BuildZ3ConstantFromType( const Term& type, const string& name )
    {
        auto& c = GetZ3Context();

        // TODO: what about very large int types? Can z3 represent them?

        if( type == GetValueType< bool >() )
            return c.bool_const( name.c_str() );
        else if( FromValue< builtins::IntegerType >( *ValueFromIRExpr( type ) ) )
             return c.int_const( name.c_str() );

        return nullopt;
    }

    template< typename I, typename F >
    optional< z3::expr > BuildZ3BinExpr( const I& instr, F&& func )
    {
        auto lhs = BuildZ3ExprFromValue( instr.lhs() );
        if( !lhs )
            return nullopt;

        auto rhs = BuildZ3ExprFromValue( instr.rhs() );
        if( !rhs )
            return nullopt;

        return func( *lhs, *rhs );
    }

    template< typename T >
    optional< z3::expr > BuildZ3Op( const T& instr )
    {
        return nullopt;
    }

    // TODO: inline cfg. We'll need those functions to take some context with a z3 solver and an optional precondition (indicating which basic block we're in)
    // so that they can push assertions directly from the inline CFG (this will have to recurse into the code that builds assertions from a cfg, which doesn't even exist yet)

    // TODO: Call. Lots of work to do there: it needs to extract the function's assertions, map args to function param ids, and replace GetVars to thos ids with the corresponding
    // expressions.

    // TODO: Create temporary. Need to keep track of which z3 expressions are assigned to what temporaries, much like in codegen.

    // TODO: GetTemporary.

    // TODO: AllocVar. Generate a z3 constant with fresh name and store it as the var's initial content.
    // TODO: GetVar. Retrieve the latest z3 expression stored in that var, in the same way that we track allocas in codegen.

    optional< z3::expr > BuildZ3Op( const GetVar& instr )
    {
        // TODO: we should actually retrieve the last expression stored in that var, SSA style,
        // and have the AllocVar func generate it a name to be stored as the initial content.
        // When this is done we can remove the type from llr::GetVar.
        stringstream sstr;
        sstr << '$' << instr.cfgId() << '_' << instr.index();
        return BuildZ3ConstantFromType( instr.type(), sstr.str() );
    }

    // TODO: SetVar. Store a new z3 expression into that var.

    // 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.

    // TODO: bitwise operators. They need to work on bitvecs, so we'll need a param indicating that we want to
    // build bitvecs rather than ints, and use it when building the sub expression of something that needs bitvecs.

    template< typename T >
    optional< z3::expr > BuildZ3Op( const T& instr )
    {
        return nullopt;
    }

    // TODO: Not. We don't have a dedicated opcode in llr for it bc llvm didn't need it,
    // but we'll need it so add it (and lower it to xor with complement for llvm in codegen)

    optional< z3::expr > BuildZ3Op( const And& instr )
    {
        // TODO this works only for bools, have to use & for bitvecs
        return BuildZ3BinExpr( instr, []( auto&& lhs, auto&& rhs ) { return lhs && rhs; } );
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
166
167
168
169
170
171
172
















173
174
175
176
177
178

179
180
181
182
183







-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-






-
+




    {
        return visit( [&]( auto&& e )
        {
            return BuildZ3Op( e );
        }, instr.content() );
    }

    optional< z3::expr > BuildZ3ExprFromConstant( const Value& val )
    {
        auto& c = GetZ3Context();

        // TODO: what about very large int types? Can z3 represent them?

        if( auto b = FromValue< bool >( val ) )
            return c.bool_val( *b );
        else if( auto intVal = FromValue< APSInt >( val ) )
             return c.int_val( intVal->getExtValue() );
        else if( auto strVal = FromValue< string >( val ) )
            return c.string_val( *strVal );

        return nullopt;
    }

    optional< z3::expr > BuildZ3ExprFromValue( const Value& val )
    {
        if( val.isPoison() )
            return nullopt;

        if( val.isConstant() )
            return BuildZ3ExprFromConstant( val );
            return BuildZ3ValFromConstant( val );

        return BuildZ3Op( *val.llr() );
    }
}