Goose  Check-in [7d2def7b75]

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Renamed "ir" to "eir" (expression intermediate representation) and "llr" to "cir" (code intermediate representation) for clarity.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 7d2def7b7561cbe9e14dfef5f2a89fe59e1175c34e0288cc9ee8750054f04ba8
User & Date: achavasse 2020-12-27 14:40:24.320
Context
2021-01-02
18:00
Some more renaming. check-in: 0345b9f807 user: achavasse tags: trunk
2020-12-27
14:40
Renamed "ir" to "eir" (expression intermediate representation) and "llr" to "cir" (code intermediate representation) for clarity. check-in: 7d2def7b75 user: achavasse tags: trunk
2020-12-26
14:59
Build fix check-in: c8058eaaf9 user: achavasse tags: trunk
Changes
Unified Diff Ignore Whitespace Patch
Changes to bs/builtins/api/codegen/func.cpp.
1
2
3
4
5
6
7
8
9
#include "builtins/builtins.h"
#include "ir/ir.h"

using namespace goose;

namespace goose::builtins
{
    void SetupApiCGFunc( Env& e )
    {

|







1
2
3
4
5
6
7
8
9
#include "builtins/builtins.h"
#include "eir/eir.h"

using namespace goose;

namespace goose::builtins
{
    void SetupApiCGFunc( Env& e )
    {
Changes to bs/builtins/api/codegen/linker.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include "builtins/builtins.h"
#include "ir/ir.h"
#include "lld/Common/Driver.h"
#include "llvm/Support/raw_os_ostream.h"

using namespace goose;
using namespace goose::ir;
using namespace goose::builtins;

namespace
{
    bool BuildArgArrayFromTuple( const Value& tup, vector< string >& array )
    {
        if( !IsTuple( tup ) )

|




|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include "builtins/builtins.h"
#include "eir/eir.h"
#include "lld/Common/Driver.h"
#include "llvm/Support/raw_os_ostream.h"

using namespace goose;
using namespace goose::eir;
using namespace goose::builtins;

namespace
{
    bool BuildArgArrayFromTuple( const Value& tup, vector< string >& array )
    {
        if( !IsTuple( tup ) )
Changes to bs/builtins/api/codegen/mangle.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
#include "builtins/builtins.h"
#include "ir/ir.h"

using namespace goose;

namespace goose::builtins
{
    void SetupApiCGMangle( Env& e )
    {
        RegisterBuiltinFunc< string ( Value ) >( e, "CGMangle"_sid,
            []( const Value& v ) -> string
            {
                auto func = FromValue< Func >( v );
                if( !func )
                    return "";

                if( !func->llr() )
                    return "";

                auto result = codegen::Mangle( func->llr()->identity() );
                if( !result )
                    return "";

                return *result;
            } );
    }
}

|














|


|







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 "builtins/builtins.h"
#include "eir/eir.h"

using namespace goose;

namespace goose::builtins
{
    void SetupApiCGMangle( Env& e )
    {
        RegisterBuiltinFunc< string ( Value ) >( e, "CGMangle"_sid,
            []( const Value& v ) -> string
            {
                auto func = FromValue< Func >( v );
                if( !func )
                    return "";

                if( !func->cir() )
                    return "";

                auto result = codegen::Mangle( func->cir()->identity() );
                if( !result )
                    return "";

                return *result;
            } );
    }
}
Changes to bs/builtins/api/codegen/module.cpp.
1
2
3
4
5
6
7
8
9
#include "builtins/builtins.h"
#include "ir/ir.h"

namespace goose::builtins
{
    void SetupApiCGModule( Env& e )
    {
        RegisterBuiltinFunc< ptr< codegen::Module > ( string ) >( e, "CGModuleCreate"_sid,
            []( const string& name )

|







1
2
3
4
5
6
7
8
9
#include "builtins/builtins.h"
#include "eir/eir.h"

namespace goose::builtins
{
    void SetupApiCGModule( Env& e )
    {
        RegisterBuiltinFunc< ptr< codegen::Module > ( string ) >( e, "CGModuleCreate"_sid,
            []( const string& name )
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
            []( const ptr< codegen::Module >& module, const string& filename )
            {
                return module->emitToFile( filename, llvm::CGFT_ObjectFile );
            } );
    }
}

namespace goose::ir
{
    const Term& Bridge< ptr< codegen::Module > >::Type()
    {
        static auto type = ValueToIRExpr( Value( TypeType(), VEC( TSID( ct_type ), TSID( cg_module ) ) ) );
        return type;
    }








|







41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
            []( const ptr< codegen::Module >& module, const string& filename )
            {
                return module->emitToFile( filename, llvm::CGFT_ObjectFile );
            } );
    }
}

namespace goose::eir
{
    const Term& Bridge< ptr< codegen::Module > >::Type()
    {
        static auto type = ValueToIRExpr( Value( TypeType(), VEC( TSID( ct_type ), TSID( cg_module ) ) ) );
        return type;
    }

Changes to bs/builtins/api/codegen/module.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#ifndef GOOSE_BUILTINS_API_CODEGEN_MODULE_H
#define GOOSE_BUILTINS_API_CODEGEN_MODULE_H

namespace goose::builtins
{
    extern void SetupApiCGModule( Env& e );
}

namespace goose::ir
{
    template<>
    struct Bridge< ptr< codegen::Module > >
    {
        static const Term& Type();
        static Value ToValue( const ptr< codegen::Module >& os );
        static optional< ptr< codegen::Module > > FromValue( const Value& v );








|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#ifndef GOOSE_BUILTINS_API_CODEGEN_MODULE_H
#define GOOSE_BUILTINS_API_CODEGEN_MODULE_H

namespace goose::builtins
{
    extern void SetupApiCGModule( Env& e );
}

namespace goose::eir
{
    template<>
    struct Bridge< ptr< codegen::Module > >
    {
        static const Term& Type();
        static Value ToValue( const ptr< codegen::Module >& os );
        static optional< ptr< codegen::Module > > FromValue( const Value& v );
Changes to bs/builtins/api/compiler.cpp.
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217

                auto funcIdentity = AppendToVectorTerm( builtins::RootIdentity(),
                    TERM( StringId( Env::NewUniqueId() ) ) );

                c.env()->addVisibilityRule( builtins::RootIdentity(), funcIdentity );

                auto func = BuildFunc( localC, ftype, funcIdentity, params, nullptr, c );
                const auto& pFuncLLR = func.llr();

                auto cfg = Compiler::LoadAndParseFile( pEnv.lock(), filename, funcIdentity,
                    ftype.returnType(), defReturnValue );

                if( !cfg )
                    return PoisonValue();

                if( cfg->isPoisoned() )
                    return PoisonValue();

                pFuncLLR->body() = cfg;
                return ToValue( func );
            } );
    }
}







|










|




195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217

                auto funcIdentity = AppendToVectorTerm( builtins::RootIdentity(),
                    TERM( StringId( Env::NewUniqueId() ) ) );

                c.env()->addVisibilityRule( builtins::RootIdentity(), funcIdentity );

                auto func = BuildFunc( localC, ftype, funcIdentity, params, nullptr, c );
                const auto& pFuncCIR = func.cir();

                auto cfg = Compiler::LoadAndParseFile( pEnv.lock(), filename, funcIdentity,
                    ftype.returnType(), defReturnValue );

                if( !cfg )
                    return PoisonValue();

                if( cfg->isPoisoned() )
                    return PoisonValue();

                pFuncCIR->body() = cfg;
                return ToValue( func );
            } );
    }
}
Changes to bs/builtins/api/extensibility/codebuilder.cpp.
1
2
3
4
5
6
7
8
9
10
11
#include "builtins/builtins.h"
#include "ir/ir.h"

namespace goose::ir
{
    const Term& Bridge< ptr< sema::CodeBuilder > >::Type()
    {
        static auto type = ValueToIRExpr( Value( TypeType(), VEC( TSID( ct_type ), TSID( ext_codebuilder ) ) ) );
        return type;
    }


|

|







1
2
3
4
5
6
7
8
9
10
11
#include "builtins/builtins.h"
#include "eir/eir.h"

namespace goose::eir
{
    const Term& Bridge< ptr< sema::CodeBuilder > >::Type()
    {
        static auto type = ValueToIRExpr( Value( TypeType(), VEC( TSID( ct_type ), TSID( ext_codebuilder ) ) ) );
        return type;
    }

Changes to bs/builtins/api/extensibility/codebuilder.h.
1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_BUILTINS_API_EXTENSIBILITY_CODEBUILDER_H
#define GOOSE_BUILTINS_API_EXTENSIBILITY_CODEBUILDER_H

namespace goose::ir
{
    template<>
    struct Bridge< ptr< sema::CodeBuilder > >
    {
        static const Term& Type();
        static Value ToValue( const ptr< sema::CodeBuilder >& cb );
        static optional< ptr< sema::CodeBuilder > > FromValue( const Value& v );



|







1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_BUILTINS_API_EXTENSIBILITY_CODEBUILDER_H
#define GOOSE_BUILTINS_API_EXTENSIBILITY_CODEBUILDER_H

namespace goose::eir
{
    template<>
    struct Bridge< ptr< sema::CodeBuilder > >
    {
        static const Term& Type();
        static Value ToValue( const ptr< sema::CodeBuilder >& cb );
        static optional< ptr< sema::CodeBuilder > > FromValue( const Value& v );
Changes to bs/builtins/api/extensibility/termwrapper.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
#include "builtins/builtins.h"
#include "ir/ir.h"

using namespace goose::builtins;

namespace goose::ir
{
    const Term& Bridge< TermWrapper >::Type()
    {
        static auto type = ValueToIRExpr( Value( TypeType(), VEC( TSID( ct_type ), TSID( ext_termwrapper ) ) ) );
        return type;
    }


|



|







1
2
3
4
5
6
7
8
9
10
11
12
13
#include "builtins/builtins.h"
#include "eir/eir.h"

using namespace goose::builtins;

namespace goose::eir
{
    const Term& Bridge< TermWrapper >::Type()
    {
        static auto type = ValueToIRExpr( Value( TypeType(), VEC( TSID( ct_type ), TSID( ext_termwrapper ) ) ) );
        return type;
    }

Changes to bs/builtins/api/extensibility/termwrapper.h.
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
            }

        private:
            Term m_term;
    };
}

namespace goose::ir
{
    template<>
    struct Bridge< builtins::TermWrapper >
    {
        static const Term& Type();
        static Value ToValue( const builtins::TermWrapper& tw );
        static optional< Term > FromValue( const Value& v );







|







22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
            }

        private:
            Term m_term;
    };
}

namespace goose::eir
{
    template<>
    struct Bridge< builtins::TermWrapper >
    {
        static const Term& Type();
        static Value ToValue( const builtins::TermWrapper& tw );
        static optional< Term > FromValue( const Value& v );
Changes to bs/builtins/api/extensibility/valuewrapper.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
#include "builtins/builtins.h"
#include "ir/ir.h"

using namespace goose::builtins;

namespace goose::ir
{
    const Term& Bridge< ValueWrapper >::Type()
    {
        static auto type = ValueToIRExpr( Value( TypeType(), VEC( TSID( ct_type ), TSID( ext_valuewrapper ) ) ) );
        return type;
    }


|



|







1
2
3
4
5
6
7
8
9
10
11
12
13
#include "builtins/builtins.h"
#include "eir/eir.h"

using namespace goose::builtins;

namespace goose::eir
{
    const Term& Bridge< ValueWrapper >::Type()
    {
        static auto type = ValueToIRExpr( Value( TypeType(), VEC( TSID( ct_type ), TSID( ext_valuewrapper ) ) ) );
        return type;
    }

Changes to bs/builtins/api/extensibility/valuewrapper.h.
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
            }

        private:
            Value m_value;
    };
}

namespace goose::ir
{
    template<>
    struct Bridge< builtins::ValueWrapper >
    {
        static const Term& Type();
        static Value ToValue( const builtins::ValueWrapper& vw );
        static optional< Value > FromValue( const Value& v );







|







22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
            }

        private:
            Value m_value;
    };
}

namespace goose::eir
{
    template<>
    struct Bridge< builtins::ValueWrapper >
    {
        static const Term& Type();
        static Value ToValue( const builtins::ValueWrapper& vw );
        static optional< Value > FromValue( const Value& v );
Changes to bs/builtins/api/support/cast.cpp.
1
2
3
4
5
6
7
8
9
#include "builtins/builtins.h"
#include "ir/ir.h"

using namespace goose;

namespace goose::builtins
{
    void SetupApiCastFuncs( Env& e )
    {

|







1
2
3
4
5
6
7
8
9
#include "builtins/builtins.h"
#include "eir/eir.h"

using namespace goose;

namespace goose::builtins
{
    void SetupApiCastFuncs( Env& e )
    {
Changes to bs/builtins/api/support/verification.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include "builtins/builtins.h"
#include "ir/ir.h"
#include "parse/parse.h"

using namespace goose;
using namespace goose::parse;

namespace goose::builtins
{
    void SetupApiVerificationFuncs( Env& e )
    {
        RegisterBuiltinFunc< Intrinsic< Value ( bool ) > >( e, "assert"_sid,
            []( const Context& c, const Value& cond )
            {
                return BuildComputedValue( GetValueType< void >(),
                    llr::Assert( cond ) );
            } );
    }
}

|













|



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include "builtins/builtins.h"
#include "eir/eir.h"
#include "parse/parse.h"

using namespace goose;
using namespace goose::parse;

namespace goose::builtins
{
    void SetupApiVerificationFuncs( Env& e )
    {
        RegisterBuiltinFunc< Intrinsic< Value ( bool ) > >( e, "assert"_sid,
            []( const Context& c, const Value& cond )
            {
                return BuildComputedValue( GetValueType< void >(),
                    cir::Assert( cond ) );
            } );
    }
}
Changes to bs/builtins/builtins.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#ifndef GOOSE_BUILTINS_H
#define GOOSE_BUILTINS_H

#include "ir/ir.h"
#include "llr/llr.h"
#include "sema/sema.h"
#include "diagnostics/diagnostics.h"

namespace goose::builtins
{
    using namespace ir;
    using namespace sema;
    using namespace diagnostics;

    extern const Term& RootIdentity();
}

#include "codegen/codegen.h"



|
|





|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#ifndef GOOSE_BUILTINS_H
#define GOOSE_BUILTINS_H

#include "eir/eir.h"
#include "cir/cir.h"
#include "sema/sema.h"
#include "diagnostics/diagnostics.h"

namespace goose::builtins
{
    using namespace eir;
    using namespace sema;
    using namespace diagnostics;

    extern const Term& RootIdentity();
}

#include "codegen/codegen.h"
Changes to bs/builtins/exprbuilder.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
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
#ifndef GOOSE_BUILTINS_EXPRBUILDER_H
#define GOOSE_BUILTINS_EXPRBUILDER_H

#include "parse/parse.h"

namespace goose::builtins::exprbuilder
{
    template< typename V >
    Value Not( V&& val )
    {
        return BuildComputedValue( GetValueType< bool >(),
            llr::Not( forward< V >( val ) ) ).setLocationId( val.locationId() );
    }

    template< typename L, typename R >
    Value Or( L&& lhs, R&& rhs )
    {
        auto locId = max( lhs.locationId(), rhs.locationId() );
        return BuildComputedValue( GetValueType< bool >(),
            llr::Or( forward< L >( lhs ), forward< R >( rhs ) ) );
    }

    template< typename L, typename R >
    Value And( L&& lhs, R&& rhs )
    {
        auto locId = max( lhs.locationId(), rhs.locationId() );
        return BuildComputedValue( GetValueType< bool >(),
            llr::And( forward< L >( lhs ), forward< R >( rhs ) ) ).setLocationId( locId );
    }

    template< typename L, typename R >
    Value Eq( L&& lhs, R&& rhs )
    {
        auto locId = max( lhs.locationId(), rhs.locationId() );
        return BuildComputedValue( GetValueType< bool >(),
            llr::Eq( forward< L >( lhs ), forward< R >( rhs ) ) ).setLocationId( locId );
    }

    template< typename L, typename R >
    Value Neq( L&& lhs, R&& rhs )
    {
        auto locId = max( lhs.locationId(), rhs.locationId() );
        return BuildComputedValue( GetValueType< bool >(),
            llr::Neq( forward< L >( lhs ), forward< R >( rhs ) ) ).setLocationId( locId );
    }

    template< typename L, typename R >
    Value UGT( L&& lhs, R&& rhs )
    {
        auto locId = max( lhs.locationId(), rhs.locationId() );
        return BuildComputedValue( GetValueType< bool >(),
            llr::UGT( forward< L >( lhs ), forward< R >( rhs ) ) ).setLocationId( locId );
    }

    template< typename L, typename R >
    Value UGE( L&& lhs, R&& rhs )
    {
        auto locId = max( lhs.locationId(), rhs.locationId() );
        return BuildComputedValue( GetValueType< bool >(),
            llr::UGE( forward< L >( lhs ), forward< R >( rhs ) ) ).setLocationId( locId );
    }

    template< typename L, typename R >
    Value ULT( L&& lhs, R&& rhs )
    {
        auto locId = max( lhs.locationId(), rhs.locationId() );
        return BuildComputedValue( GetValueType< bool >(),
            llr::ULT( forward< L >( lhs ), forward< R >( rhs ) ) ).setLocationId( locId );
    }

    template< typename L, typename R >
    Value ULE( L&& lhs, R&& rhs )
    {
        auto locId = max( lhs.locationId(), rhs.locationId() );
        return BuildComputedValue( GetValueType< bool >(),
            llr::ULE( forward< L >( lhs ), forward< R >( rhs ) ) ).setLocationId( locId );
    }

    template< typename L, typename R >
    Value SGT( L&& lhs, R&& rhs )
    {
        auto locId = max( lhs.locationId(), rhs.locationId() );
        return BuildComputedValue( GetValueType< bool >(),
            llr::SGT( forward< L >( lhs ), forward< R >( rhs ) ) ).setLocationId( locId );
    }

    template< typename L, typename R >
    Value SGE( L&& lhs, R&& rhs )
    {
        auto locId = max( lhs.locationId(), rhs.locationId() );
        return BuildComputedValue( GetValueType< bool >(),
            llr::SGE( forward< L >( lhs ), forward< R >( rhs ) ) ).setLocationId( locId );
    }

    template< typename L, typename R >
    Value SLT( L&& lhs, R&& rhs )
    {
        auto locId = max( lhs.locationId(), rhs.locationId() );
        return BuildComputedValue( GetValueType< bool >(),
            llr::SLT( forward< L >( lhs ), forward< R >( rhs ) ) ).setLocationId( locId );
    }

    template< typename L, typename R >
    Value SLE( L&& lhs, R&& rhs )
    {
        auto locId = max( lhs.locationId(), rhs.locationId() );
        return BuildComputedValue( GetValueType< bool >(),
            llr::SLE( forward< L >( lhs ), forward< R >( rhs ) ) );
    }
}

#endif











|







|







|







|







|







|







|







|







|







|







|







|







|




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
#ifndef GOOSE_BUILTINS_EXPRBUILDER_H
#define GOOSE_BUILTINS_EXPRBUILDER_H

#include "parse/parse.h"

namespace goose::builtins::exprbuilder
{
    template< typename V >
    Value Not( V&& val )
    {
        return BuildComputedValue( GetValueType< bool >(),
            cir::Not( forward< V >( val ) ) ).setLocationId( val.locationId() );
    }

    template< typename L, typename R >
    Value Or( L&& lhs, R&& rhs )
    {
        auto locId = max( lhs.locationId(), rhs.locationId() );
        return BuildComputedValue( GetValueType< bool >(),
            cir::Or( forward< L >( lhs ), forward< R >( rhs ) ) );
    }

    template< typename L, typename R >
    Value And( L&& lhs, R&& rhs )
    {
        auto locId = max( lhs.locationId(), rhs.locationId() );
        return BuildComputedValue( GetValueType< bool >(),
            cir::And( forward< L >( lhs ), forward< R >( rhs ) ) ).setLocationId( locId );
    }

    template< typename L, typename R >
    Value Eq( L&& lhs, R&& rhs )
    {
        auto locId = max( lhs.locationId(), rhs.locationId() );
        return BuildComputedValue( GetValueType< bool >(),
            cir::Eq( forward< L >( lhs ), forward< R >( rhs ) ) ).setLocationId( locId );
    }

    template< typename L, typename R >
    Value Neq( L&& lhs, R&& rhs )
    {
        auto locId = max( lhs.locationId(), rhs.locationId() );
        return BuildComputedValue( GetValueType< bool >(),
            cir::Neq( forward< L >( lhs ), forward< R >( rhs ) ) ).setLocationId( locId );
    }

    template< typename L, typename R >
    Value UGT( L&& lhs, R&& rhs )
    {
        auto locId = max( lhs.locationId(), rhs.locationId() );
        return BuildComputedValue( GetValueType< bool >(),
            cir::UGT( forward< L >( lhs ), forward< R >( rhs ) ) ).setLocationId( locId );
    }

    template< typename L, typename R >
    Value UGE( L&& lhs, R&& rhs )
    {
        auto locId = max( lhs.locationId(), rhs.locationId() );
        return BuildComputedValue( GetValueType< bool >(),
            cir::UGE( forward< L >( lhs ), forward< R >( rhs ) ) ).setLocationId( locId );
    }

    template< typename L, typename R >
    Value ULT( L&& lhs, R&& rhs )
    {
        auto locId = max( lhs.locationId(), rhs.locationId() );
        return BuildComputedValue( GetValueType< bool >(),
            cir::ULT( forward< L >( lhs ), forward< R >( rhs ) ) ).setLocationId( locId );
    }

    template< typename L, typename R >
    Value ULE( L&& lhs, R&& rhs )
    {
        auto locId = max( lhs.locationId(), rhs.locationId() );
        return BuildComputedValue( GetValueType< bool >(),
            cir::ULE( forward< L >( lhs ), forward< R >( rhs ) ) ).setLocationId( locId );
    }

    template< typename L, typename R >
    Value SGT( L&& lhs, R&& rhs )
    {
        auto locId = max( lhs.locationId(), rhs.locationId() );
        return BuildComputedValue( GetValueType< bool >(),
            cir::SGT( forward< L >( lhs ), forward< R >( rhs ) ) ).setLocationId( locId );
    }

    template< typename L, typename R >
    Value SGE( L&& lhs, R&& rhs )
    {
        auto locId = max( lhs.locationId(), rhs.locationId() );
        return BuildComputedValue( GetValueType< bool >(),
            cir::SGE( forward< L >( lhs ), forward< R >( rhs ) ) ).setLocationId( locId );
    }

    template< typename L, typename R >
    Value SLT( L&& lhs, R&& rhs )
    {
        auto locId = max( lhs.locationId(), rhs.locationId() );
        return BuildComputedValue( GetValueType< bool >(),
            cir::SLT( forward< L >( lhs ), forward< R >( rhs ) ) ).setLocationId( locId );
    }

    template< typename L, typename R >
    Value SLE( L&& lhs, R&& rhs )
    {
        auto locId = max( lhs.locationId(), rhs.locationId() );
        return BuildComputedValue( GetValueType< bool >(),
            cir::SLE( forward< L >( lhs ), forward< R >( rhs ) ) );
    }
}

#endif
Changes to bs/builtins/helpers.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include "builtins/builtins.h"
#include "builtins/helpers.h"

using namespace goose::parse;

namespace goose::builtins
{
    void RegisterRule( sema::Env& env, const StringId& name, parse::Rule&& rule )
    {
        parse::RegisterRule( env, AppendToVectorTerm( RootIdentity(), TERM( name ) ), move( rule ) );
    }

    ptr< llr::BasicBlock > ParseSubStatement( Parser& p, uint32_t precedence )
    {
        auto next = p.resolver()->lookAheadUnresolved();
        if( !next )
            return nullptr;

        auto np = p.makeNestedParser();













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include "builtins/builtins.h"
#include "builtins/helpers.h"

using namespace goose::parse;

namespace goose::builtins
{
    void RegisterRule( sema::Env& env, const StringId& name, parse::Rule&& rule )
    {
        parse::RegisterRule( env, AppendToVectorTerm( RootIdentity(), TERM( name ) ), move( rule ) );
    }

    ptr< cir::BasicBlock > ParseSubStatement( Parser& p, uint32_t precedence )
    {
        auto next = p.resolver()->lookAheadUnresolved();
        if( !next )
            return nullptr;

        auto np = p.makeNestedParser();

Changes to bs/builtins/helpers.h.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
    extern void RegisterRule( sema::Env& env, const StringId& name, parse::Rule&& rule );

    // Utility function used to parse flow control statements, such as if and loops.
    // This parses a sub statement, which can be enclosed in a brace block or not.
    // It will get its own scope, with visibility rules setup to see the current
    // scope.
    // It returns a pointer to the final basic block generated by the statement.
    ptr< llr::BasicBlock > ParseSubStatement( parse::Parser& p, uint32_t precedence );

    enum class ValUnifyError
    {
        NoSolution,
        Ambiguous
    };








|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
    extern void RegisterRule( sema::Env& env, const StringId& name, parse::Rule&& rule );

    // Utility function used to parse flow control statements, such as if and loops.
    // This parses a sub statement, which can be enclosed in a brace block or not.
    // It will get its own scope, with visibility rules setup to see the current
    // scope.
    // It returns a pointer to the final basic block generated by the statement.
    ptr< cir::BasicBlock > ParseSubStatement( parse::Parser& p, uint32_t precedence );

    enum class ValUnifyError
    {
        NoSolution,
        Ambiguous
    };

Changes to bs/builtins/operators/arith.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include "builtins/builtins.h"
#include "precedence.h"
#include "helpers.h"
#include "tuple.h"

using namespace goose;
using namespace goose::ir;
using namespace goose::llr;
using namespace goose::parse;

namespace goose::builtins
{
    void SetupArithOps( Env& e )
    {
        BuildParseRule( e, "+"_sid,






|
|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include "builtins/builtins.h"
#include "precedence.h"
#include "helpers.h"
#include "tuple.h"

using namespace goose;
using namespace goose::eir;
using namespace goose::cir;
using namespace goose::parse;

namespace goose::builtins
{
    void SetupArithOps( Env& e )
    {
        BuildParseRule( e, "+"_sid,
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
                    auto zeroValue = Value( rhs.type(), APSInt::get( 0 ) );
                    auto cond = Neq( rhs, zeroValue );

                    DiagnosticsManager::GetInstance().defineCustomDiagnostic(
                        cond.locationId(), "assert"_sid, "the divisor may be 0." );

                    cfg->currentBB()->emplace_back(
                        llr::Assert( move( cond ) )
                    );

                    return BuildComputedValue( lhs.type(),
                        SDiv( lhs, rhs ) );
                } ),
                ForType< CustomPattern< IntegerType, IntegerType::PatternUnsigned > >(
                []( auto&& c, auto&& lhs, auto&& rhs ) -> Value







|







98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
                    auto zeroValue = Value( rhs.type(), APSInt::get( 0 ) );
                    auto cond = Neq( rhs, zeroValue );

                    DiagnosticsManager::GetInstance().defineCustomDiagnostic(
                        cond.locationId(), "assert"_sid, "the divisor may be 0." );

                    cfg->currentBB()->emplace_back(
                        cir::Assert( move( cond ) )
                    );

                    return BuildComputedValue( lhs.type(),
                        SDiv( lhs, rhs ) );
                } ),
                ForType< CustomPattern< IntegerType, IntegerType::PatternUnsigned > >(
                []( auto&& c, auto&& lhs, auto&& rhs ) -> Value
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
                    auto zeroValue = Value( rhs.type(), APSInt::get( 0 ) );
                    auto cond = Neq( rhs, zeroValue );

                    DiagnosticsManager::GetInstance().defineCustomDiagnostic(
                        cond.locationId(), "assert"_sid, "the divisor may be 0." );

                    cfg->currentBB()->emplace_back(
                        llr::Assert( move( cond ) )
                    );

                    return BuildComputedValue( lhs.type(),
                        UDiv( lhs, rhs ) );
                } )
            )
        );







|







122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
                    auto zeroValue = Value( rhs.type(), APSInt::get( 0 ) );
                    auto cond = Neq( rhs, zeroValue );

                    DiagnosticsManager::GetInstance().defineCustomDiagnostic(
                        cond.locationId(), "assert"_sid, "the divisor may be 0." );

                    cfg->currentBB()->emplace_back(
                        cir::Assert( move( cond ) )
                    );

                    return BuildComputedValue( lhs.type(),
                        UDiv( lhs, rhs ) );
                } )
            )
        );
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
                    auto zeroValue = Value( rhs.type(), APSInt::get( 0 ) );
                    auto cond = Neq( rhs, zeroValue );

                    DiagnosticsManager::GetInstance().defineCustomDiagnostic(
                        cond.locationId(), "assert"_sid, "the divisor may be 0." );

                    cfg->currentBB()->emplace_back(
                        llr::Assert( move( cond ) )
                    );

                    return BuildComputedValue( lhs.type(),
                        SRem( lhs, rhs ) );
                } ),
                ForType< CustomPattern< IntegerType, IntegerType::PatternUnsigned > >(
                []( auto&& c, auto&& lhs, auto&& rhs ) -> Value







|







153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
                    auto zeroValue = Value( rhs.type(), APSInt::get( 0 ) );
                    auto cond = Neq( rhs, zeroValue );

                    DiagnosticsManager::GetInstance().defineCustomDiagnostic(
                        cond.locationId(), "assert"_sid, "the divisor may be 0." );

                    cfg->currentBB()->emplace_back(
                        cir::Assert( move( cond ) )
                    );

                    return BuildComputedValue( lhs.type(),
                        SRem( lhs, rhs ) );
                } ),
                ForType< CustomPattern< IntegerType, IntegerType::PatternUnsigned > >(
                []( auto&& c, auto&& lhs, auto&& rhs ) -> Value
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
                    auto zeroValue = Value( rhs.type(), APSInt::get( 0 ) );
                    auto cond = Neq( rhs, zeroValue );

                    DiagnosticsManager::GetInstance().defineCustomDiagnostic(
                        cond.locationId(), "assert"_sid, "the divisor may be 0." );

                    cfg->currentBB()->emplace_back(
                        llr::Assert( move( cond ) )
                    );

                    return BuildComputedValue( lhs.type(),
                        URem( lhs, rhs ) );
                } )
            )
        );
    }
}







|









177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
                    auto zeroValue = Value( rhs.type(), APSInt::get( 0 ) );
                    auto cond = Neq( rhs, zeroValue );

                    DiagnosticsManager::GetInstance().defineCustomDiagnostic(
                        cond.locationId(), "assert"_sid, "the divisor may be 0." );

                    cfg->currentBB()->emplace_back(
                        cir::Assert( move( cond ) )
                    );

                    return BuildComputedValue( lhs.type(),
                        URem( lhs, rhs ) );
                } )
            )
        );
    }
}
Changes to bs/builtins/operators/assignment.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include "builtins/builtins.h"
#include "precedence.h"
#include "helpers.h"
#include "tuple.h"

using namespace goose;
using namespace goose::ir;
using namespace goose::llr;
using namespace goose::parse;

namespace goose::builtins
{
    void SetupAssignmentOps( Env& e )
    {
        auto assOp = GetOrCreateOverloadSet( e, "operator_assign"_sid );






|
|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include "builtins/builtins.h"
#include "precedence.h"
#include "helpers.h"
#include "tuple.h"

using namespace goose;
using namespace goose::eir;
using namespace goose::cir;
using namespace goose::parse;

namespace goose::builtins
{
    void SetupAssignmentOps( Env& e )
    {
        auto assOp = GetOrCreateOverloadSet( e, "operator_assign"_sid );
Changes to bs/builtins/operators/comma.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
#include "builtins/builtins.h"
#include "precedence.h"
#include "helpers.h"

using namespace goose;
using namespace goose::ir;
using namespace goose::parse;

namespace goose::builtins
{
    void SetupCommaOp( Env& e )
    {
        using LocVarOfAnyType =





|







1
2
3
4
5
6
7
8
9
10
11
12
13
#include "builtins/builtins.h"
#include "precedence.h"
#include "helpers.h"

using namespace goose;
using namespace goose::eir;
using namespace goose::parse;

namespace goose::builtins
{
    void SetupCommaOp( Env& e )
    {
        using LocVarOfAnyType =
Changes to bs/builtins/operators/comparison.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include "builtins/builtins.h"
#include "precedence.h"
#include "helpers.h"
#include "tuple.h"

using namespace goose;
using namespace goose::ir;
using namespace goose::llr;
using namespace goose::parse;

// TODO: tuple comparisons. Bit of a pita to implement and cba right now. Maybe something to implement in the lib.

namespace goose::builtins
{
    void SetupComparisonOps( Env& e )






|
|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include "builtins/builtins.h"
#include "precedence.h"
#include "helpers.h"
#include "tuple.h"

using namespace goose;
using namespace goose::eir;
using namespace goose::cir;
using namespace goose::parse;

// TODO: tuple comparisons. Bit of a pita to implement and cba right now. Maybe something to implement in the lib.

namespace goose::builtins
{
    void SetupComparisonOps( Env& e )
Changes to bs/builtins/operators/compoundass.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
#include "builtins/builtins.h"
#include "precedence.h"
#include "helpers.h"
using namespace goose;
using namespace goose::ir;
using namespace goose::llr;
using namespace goose::parse;

namespace goose::builtins
{
    // Helper to build a compound assignment operator
    template< typename L, typename R >
    auto MakeCompoundAssOpFunc( Env& e, StringId opName )




|
|







1
2
3
4
5
6
7
8
9
10
11
12
13
#include "builtins/builtins.h"
#include "precedence.h"
#include "helpers.h"
using namespace goose;
using namespace goose::eir;
using namespace goose::cir;
using namespace goose::parse;

namespace goose::builtins
{
    // Helper to build a compound assignment operator
    template< typename L, typename R >
    auto MakeCompoundAssOpFunc( Env& e, StringId opName )
Changes to bs/builtins/operators/dollar.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include "builtins/builtins.h"
#include "precedence.h"
#include "builtins/helpers.h"

using namespace goose;
using namespace goose::ir;
using namespace goose::parse;
using namespace goose::builtins;

// Dollar is a low level operator: it doesn't expect a value rhs operand,
// but just an identifier ir instruction.
// So we can't use the convenient operator wrapper rule.
//
// Also, it works both as a prefix operator to construct a TVar,
// and as an infix operator (with a decl or TEXpr as the left value) to
// construct a Decl of the form "<type> $FOO" or a TDecl of the form
// "<TExpr> $FOO" (for instance $T $FOO)
namespace





|




|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include "builtins/builtins.h"
#include "precedence.h"
#include "builtins/helpers.h"

using namespace goose;
using namespace goose::eir;
using namespace goose::parse;
using namespace goose::builtins;

// Dollar is a low level operator: it doesn't expect a value rhs operand,
// but just an identifier eir instruction.
// So we can't use the convenient operator wrapper rule.
//
// Also, it works both as a prefix operator to construct a TVar,
// and as an infix operator (with a decl or TEXpr as the left value) to
// construct a Decl of the form "<type> $FOO" or a TDecl of the form
// "<TExpr> $FOO" (for instance $T $FOO)
namespace
Changes to bs/builtins/operators/dot.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include "builtins/builtins.h"
#include "precedence.h"
#include "helpers.h"
#include "tuple.h"

using namespace goose;
using namespace goose::ir;
using namespace goose::llr;
using namespace goose::parse;

namespace goose::builtins
{
    void SetupDotOp( Env& e )
    {
        BuildParseRule( e, "."_sid,






|
|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include "builtins/builtins.h"
#include "precedence.h"
#include "helpers.h"
#include "tuple.h"

using namespace goose;
using namespace goose::eir;
using namespace goose::cir;
using namespace goose::parse;

namespace goose::builtins
{
    void SetupDotOp( Env& e )
    {
        BuildParseRule( e, "."_sid,
Changes to bs/builtins/operators/logic.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
#include "builtins/builtins.h"
#include "precedence.h"
#include "helpers.h"
#include "tuple.h"

using namespace goose;
using namespace goose::ir;
using namespace goose::llr;
using namespace goose::parse;

namespace goose::builtins
{
    void SetupLogicOps( Env& e )
    {
        BuildParseRule( e, "!"_sid,
            PrefixOp( "operator_logical_not"_sid, precedence::UnaryOps,
                BuildGenericTupleOperator(),

                ForType< bool >( []( auto&& c, auto&& operand ) -> Value
                {
                    return BuildComputedValue( GetValueType< bool >(),
                        llr::Not( operand ) );
                } )
            )
        );

        BuildParseRule( e, "~"_sid,
            PrefixOp( "operator_bitwise_not"_sid, precedence::UnaryOps,
                BuildGenericTupleOperator(),






|
|













|







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
#include "builtins/builtins.h"
#include "precedence.h"
#include "helpers.h"
#include "tuple.h"

using namespace goose;
using namespace goose::eir;
using namespace goose::cir;
using namespace goose::parse;

namespace goose::builtins
{
    void SetupLogicOps( Env& e )
    {
        BuildParseRule( e, "!"_sid,
            PrefixOp( "operator_logical_not"_sid, precedence::UnaryOps,
                BuildGenericTupleOperator(),

                ForType< bool >( []( auto&& c, auto&& operand ) -> Value
                {
                    return BuildComputedValue( GetValueType< bool >(),
                        cir::Not( operand ) );
                } )
            )
        );

        BuildParseRule( e, "~"_sid,
            PrefixOp( "operator_bitwise_not"_sid, precedence::UnaryOps,
                BuildGenericTupleOperator(),
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257

                    auto cond = ULT( rhs, bitSizeValue );

                    DiagnosticsManager::GetInstance().defineCustomDiagnostic(
                        cond.locationId(), "assert"_sid, "the shift amount may be equal or greater than the bitsize." );

                    cfg->currentBB()->emplace_back(
                        llr::Assert( move( cond ) )
                    );

                    return BuildComputedValue( lhs.type(),
                        Shl( lhs, rhs ) );
                } )
            )
        );







|







243
244
245
246
247
248
249
250
251
252
253
254
255
256
257

                    auto cond = ULT( rhs, bitSizeValue );

                    DiagnosticsManager::GetInstance().defineCustomDiagnostic(
                        cond.locationId(), "assert"_sid, "the shift amount may be equal or greater than the bitsize." );

                    cfg->currentBB()->emplace_back(
                        cir::Assert( move( cond ) )
                    );

                    return BuildComputedValue( lhs.type(),
                        Shl( lhs, rhs ) );
                } )
            )
        );
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303

                    auto cond = ULT( rhs, bitSizeValue );

                    DiagnosticsManager::GetInstance().defineCustomDiagnostic(
                        cond.locationId(), "assert"_sid, "the shift amount may be equal or greater than the bitsize." );

                    cfg->currentBB()->emplace_back(
                        llr::Assert( move( cond ) )
                    );

                    return BuildComputedValue( lhs.type(),
                        AShr( lhs, rhs ) );
                } ),

                // runtime unsigned integer right shift, defined to work for any two integers of same







|







289
290
291
292
293
294
295
296
297
298
299
300
301
302
303

                    auto cond = ULT( rhs, bitSizeValue );

                    DiagnosticsManager::GetInstance().defineCustomDiagnostic(
                        cond.locationId(), "assert"_sid, "the shift amount may be equal or greater than the bitsize." );

                    cfg->currentBB()->emplace_back(
                        cir::Assert( move( cond ) )
                    );

                    return BuildComputedValue( lhs.type(),
                        AShr( lhs, rhs ) );
                } ),

                // runtime unsigned integer right shift, defined to work for any two integers of same
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336

                    auto cond = ULT( rhs, bitSizeValue );

                    DiagnosticsManager::GetInstance().defineCustomDiagnostic(
                        cond.locationId(), "assert"_sid, "the shift amount may be equal or greater than the bitsize." );

                    cfg->currentBB()->emplace_back(
                        llr::Assert( move( cond ) )
                    );

                    return BuildComputedValue( lhs.type(),
                        LShr( lhs, rhs ) );
                } )
            )
        );
    }
}







|









320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336

                    auto cond = ULT( rhs, bitSizeValue );

                    DiagnosticsManager::GetInstance().defineCustomDiagnostic(
                        cond.locationId(), "assert"_sid, "the shift amount may be equal or greater than the bitsize." );

                    cfg->currentBB()->emplace_back(
                        cir::Assert( move( cond ) )
                    );

                    return BuildComputedValue( lhs.type(),
                        LShr( lhs, rhs ) );
                } )
            )
        );
    }
}
Changes to bs/builtins/operators/semicolon.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
#include "builtins/builtins.h"
#include "precedence.h"
#include "builtins/helpers.h"

using namespace goose;
using namespace goose::ir;
using namespace goose::parse;

namespace
{
    bool parseSemicolon( Parser& p, uint32_t locationId, uint32_t prec )
    {
        return p.parseExpression( prec );





|







1
2
3
4
5
6
7
8
9
10
11
12
13
#include "builtins/builtins.h"
#include "precedence.h"
#include "builtins/helpers.h"

using namespace goose;
using namespace goose::eir;
using namespace goose::parse;

namespace
{
    bool parseSemicolon( Parser& p, uint32_t locationId, uint32_t prec )
    {
        return p.parseExpression( prec );
Changes to bs/builtins/operators/where.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
#include "builtins/builtins.h"
#include "precedence.h"
#include "builtins/helpers.h"

using namespace goose;
using namespace goose::ir;
using namespace goose::parse;
using namespace goose::builtins;

namespace goose::builtins
{
    void SetupWhereOp( Env& e )
    {





|







1
2
3
4
5
6
7
8
9
10
11
12
13
#include "builtins/builtins.h"
#include "precedence.h"
#include "builtins/helpers.h"

using namespace goose;
using namespace goose::eir;
using namespace goose::parse;
using namespace goose::builtins;

namespace goose::builtins
{
    void SetupWhereOp( Env& e )
    {
Changes to bs/builtins/statements/break.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include "builtins/builtins.h"
#include "parse/parse.h"
#include "precedence.h"
#include "builtins/helpers.h"

using namespace goose;
using namespace goose::ir;
using namespace goose::parse;

namespace goose::builtins
{
    void SetupBreakStmt( Env& e )
    {
        auto handleBreak = []( Parser& p, uint32_t locationId, uint32_t prec )






|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include "builtins/builtins.h"
#include "parse/parse.h"
#include "precedence.h"
#include "builtins/helpers.h"

using namespace goose;
using namespace goose::eir;
using namespace goose::parse;

namespace goose::builtins
{
    void SetupBreakStmt( Env& e )
    {
        auto handleBreak = []( Parser& p, uint32_t locationId, uint32_t prec )
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
                cb->poison();
                return true;
            }

            // Emit cleanups for all live variables in the scopes that we are breaking through.
            cb->destroyAllLiveValuesFromBreakScope( p.context(), cb->breakableScopeLevels() );

            cfg->currentBB()->setTerminator( llr::Break( cb->breakableScopeLevels() ) );
            return true;
        };

        Rule r( handleBreak );
        auto ruleVal = ToValue( move( r ) );
        auto ruleTerm = ValueToIRExpr( ruleVal );
        e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( break ) ), ANYTERM( _ ), ruleTerm );
    }
}







|









31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
                cb->poison();
                return true;
            }

            // Emit cleanups for all live variables in the scopes that we are breaking through.
            cb->destroyAllLiveValuesFromBreakScope( p.context(), cb->breakableScopeLevels() );

            cfg->currentBB()->setTerminator( cir::Break( cb->breakableScopeLevels() ) );
            return true;
        };

        Rule r( handleBreak );
        auto ruleVal = ToValue( move( r ) );
        auto ruleTerm = ValueToIRExpr( ruleVal );
        e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( break ) ), ANYTERM( _ ), ruleTerm );
    }
}
Changes to bs/builtins/statements/continue.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include "builtins/builtins.h"
#include "parse/parse.h"
#include "precedence.h"
#include "builtins/helpers.h"

using namespace goose;
using namespace goose::ir;
using namespace goose::parse;

namespace goose::builtins
{
    void SetupContinueStmt( Env& e )
    {
        auto handleContinue = []( Parser& p, uint32_t locationId, uint32_t prec )






|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include "builtins/builtins.h"
#include "parse/parse.h"
#include "precedence.h"
#include "builtins/helpers.h"

using namespace goose;
using namespace goose::eir;
using namespace goose::parse;

namespace goose::builtins
{
    void SetupContinueStmt( Env& e )
    {
        auto handleContinue = []( Parser& p, uint32_t locationId, uint32_t prec )
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
                cb->poison();
                return true;
            }

            // Emit cleanups for all live variables in the scopes that we are continuing through.
            cb->destroyAllLiveValuesFromBreakScope( p.context(), cb->continuableScopeLevels() );

            cfg->currentBB()->setTerminator( llr::Continue( cb->continuableScopeLevels() ) );
            return true;
        };

        Rule r( handleContinue );
        auto ruleVal = ToValue( move( r ) );
        auto ruleTerm = ValueToIRExpr( ruleVal );
        e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( continue ) ), ANYTERM( _ ), ruleTerm );
    }
}







|









31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
                cb->poison();
                return true;
            }

            // Emit cleanups for all live variables in the scopes that we are continuing through.
            cb->destroyAllLiveValuesFromBreakScope( p.context(), cb->continuableScopeLevels() );

            cfg->currentBB()->setTerminator( cir::Continue( cb->continuableScopeLevels() ) );
            return true;
        };

        Rule r( handleContinue );
        auto ruleVal = ToValue( move( r ) );
        auto ruleTerm = ValueToIRExpr( ruleVal );
        e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( continue ) ), ANYTERM( _ ), ruleTerm );
    }
}
Changes to bs/builtins/statements/hif.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include "builtins/builtins.h"
#include "parse/parse.h"
#include "precedence.h"
#include "builtins/helpers.h"

using namespace goose;
using namespace goose::ir;
using namespace goose::parse;

namespace goose::builtins
{
    void SetupHIfStmt( Env& e )
    {
        auto handleHIf = []( Parser& p, uint32_t locationId, uint32_t prec )






|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include "builtins/builtins.h"
#include "parse/parse.h"
#include "precedence.h"
#include "builtins/helpers.h"

using namespace goose;
using namespace goose::eir;
using namespace goose::parse;

namespace goose::builtins
{
    void SetupHIfStmt( Env& e )
    {
        auto handleHIf = []( Parser& p, uint32_t locationId, uint32_t prec )
Changes to bs/builtins/statements/if.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include "builtins/builtins.h"
#include "parse/parse.h"
#include "precedence.h"
#include "builtins/helpers.h"

using namespace goose;
using namespace goose::ir;
using namespace goose::parse;

namespace goose::builtins
{
    void SetupIfStmt( Env& e )
    {
        auto handleIf = []( Parser& p, uint32_t locationId, uint32_t prec )






|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include "builtins/builtins.h"
#include "parse/parse.h"
#include "precedence.h"
#include "builtins/helpers.h"

using namespace goose;
using namespace goose::eir;
using namespace goose::parse;

namespace goose::builtins
{
    void SetupIfStmt( Env& e )
    {
        auto handleIf = []( Parser& p, uint32_t locationId, uint32_t prec )
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
                dm.emitSyntaxErrorMessage( p.resolver()->currentLocation(), "expected a statement after the if condition.", 0 );
                return false;
            }

            // Retrieve the successor block of the then branch, if any
            auto pThenSuccBB = cfg->currentBB();

            ptr< llr::BasicBlock > pElseBB, pElseSuccBB;

            auto next = p.resolver()->lookAheadUnresolved();
            if( next )
            {
                const auto* nextSid = get_if< StringId >( &next->first );
                if( nextSid && *nextSid == "else"_sid )
                {







|







82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
                dm.emitSyntaxErrorMessage( p.resolver()->currentLocation(), "expected a statement after the if condition.", 0 );
                return false;
            }

            // Retrieve the successor block of the then branch, if any
            auto pThenSuccBB = cfg->currentBB();

            ptr< cir::BasicBlock > pElseBB, pElseSuccBB;

            auto next = p.resolver()->lookAheadUnresolved();
            if( next )
            {
                const auto* nextSid = get_if< StringId >( &next->first );
                if( nextSid && *nextSid == "else"_sid )
                {
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
                    pElseSuccBB = cfg->currentBB();
                }
            }

            if( !pPrecBB )
                return true;

            ptr< llr::BasicBlock > pSuccBB;

            // If both the then and the else blocks successors exist and are terminated,
            // we don't need a successor block.
            if( !pElseBB || ( pThenSuccBB && !pThenSuccBB->terminator() )
                || ( pElseSuccBB && !pElseSuccBB->terminator() ) )
                pSuccBB = cb->cfg()->createBB();

            pPrecBB->setTerminator( llr::CondBranch(
                get< Value >( converted ),
                pThenBB,
                pElseBB ? pElseBB : pSuccBB ) );

            if( pThenSuccBB && !pThenSuccBB->terminator() )
                pThenSuccBB->setTerminator( llr::Branch( pSuccBB ) );

            if( pElseSuccBB && !pElseSuccBB->terminator() )
                pElseSuccBB->setTerminator( llr::Branch( pSuccBB ) );

            // Intentionally set the current BB to null if no
            // successor block was created: it means all our code paths
            // are already terminated and there is no point in emitting any more
            // instructions.
            cfg->setCurrentBB( pSuccBB );
            return true;







|







|





|


|







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
                    pElseSuccBB = cfg->currentBB();
                }
            }

            if( !pPrecBB )
                return true;

            ptr< cir::BasicBlock > pSuccBB;

            // If both the then and the else blocks successors exist and are terminated,
            // we don't need a successor block.
            if( !pElseBB || ( pThenSuccBB && !pThenSuccBB->terminator() )
                || ( pElseSuccBB && !pElseSuccBB->terminator() ) )
                pSuccBB = cb->cfg()->createBB();

            pPrecBB->setTerminator( cir::CondBranch(
                get< Value >( converted ),
                pThenBB,
                pElseBB ? pElseBB : pSuccBB ) );

            if( pThenSuccBB && !pThenSuccBB->terminator() )
                pThenSuccBB->setTerminator( cir::Branch( pSuccBB ) );

            if( pElseSuccBB && !pElseSuccBB->terminator() )
                pElseSuccBB->setTerminator( cir::Branch( pSuccBB ) );

            // Intentionally set the current BB to null if no
            // successor block was created: it means all our code paths
            // are already terminated and there is no point in emitting any more
            // instructions.
            cfg->setCurrentBB( pSuccBB );
            return true;
Changes to bs/builtins/statements/return.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include "builtins/builtins.h"
#include "parse/parse.h"
#include "precedence.h"
#include "builtins/helpers.h"

using namespace goose;
using namespace goose::ir;
using namespace goose::parse;

namespace goose::builtins
{
    void SetupReturnStmt( Env& e )
    {
        auto handleReturn = []( Parser& p, uint32_t locationId, uint32_t prec )






|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include "builtins/builtins.h"
#include "parse/parse.h"
#include "precedence.h"
#include "builtins/helpers.h"

using namespace goose;
using namespace goose::eir;
using namespace goose::parse;

namespace goose::builtins
{
    void SetupReturnStmt( Env& e )
    {
        auto handleReturn = []( Parser& p, uint32_t locationId, uint32_t prec )
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
            // Emit cleanups (destructor calls) for all currently live values in the function.
            cb->destroyAllLiveValues( p.context() );

            const auto& context = p.context();

            if( context.returnType() == GetValueType< void >() )
            {
                cb->emitTerminator( p.resolver()->currentLocation(), llr::Ret() );
                return true;
            }

            auto np = p.makeNestedParser();
            if( !np.parseExpression( precedence::ReturnStmt + 1 ) )
            {
                dm.emitSyntaxErrorMessage( locationId, "expected an expression following the return statement.", 0 );
                cb->emitTerminator( p.resolver()->currentLocation(), llr::Ret( PoisonValue() ) );
                return false;
            }

            auto retVal = np.popValue();
            if( !retVal )
            {
                dm.emitSyntaxErrorMessage( locationId, "expected an expression following the return statement.", 0 );
                cb->emitTerminator( p.resolver()->currentLocation(), llr::Ret( PoisonValue() ) );
                return false;
            }

            auto converted = ConvertValueToType( context, *retVal, *context.returnType() );
            if( holds_alternative< ValUnifyError >( converted ) )
            {
                switch( get< ValUnifyError >( converted ) )
                {
                    case ValUnifyError::NoSolution:
                        dm.emitErrorMessage( retVal->locationId(), "return value type mismatch." );
                        break;

                    case ValUnifyError::Ambiguous:
                        dm.emitErrorMessage( retVal->locationId(), "ambiguous return value conversion." );
                        break;
                }

                // Emit a terminator with a poison value to avoid the function compilation
                // code to complain about a missing return.
                cb->emitTerminator( p.resolver()->currentLocation(), llr::Ret( PoisonValue() ) );
                cb->poison();
                return true;
            }

            cb->emitTerminator( p.resolver()->currentLocation(), llr::Ret( get< Value >( converted ) ) );
            return true;
        };

        Rule r( handleReturn );
        auto ruleVal = ToValue( move( r ) );
        auto ruleTerm = ValueToIRExpr( ruleVal );
        e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( return ) ), ANYTERM( _ ), ruleTerm );
    }
}







|







|







|



















|




|









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
            // Emit cleanups (destructor calls) for all currently live values in the function.
            cb->destroyAllLiveValues( p.context() );

            const auto& context = p.context();

            if( context.returnType() == GetValueType< void >() )
            {
                cb->emitTerminator( p.resolver()->currentLocation(), cir::Ret() );
                return true;
            }

            auto np = p.makeNestedParser();
            if( !np.parseExpression( precedence::ReturnStmt + 1 ) )
            {
                dm.emitSyntaxErrorMessage( locationId, "expected an expression following the return statement.", 0 );
                cb->emitTerminator( p.resolver()->currentLocation(), cir::Ret( PoisonValue() ) );
                return false;
            }

            auto retVal = np.popValue();
            if( !retVal )
            {
                dm.emitSyntaxErrorMessage( locationId, "expected an expression following the return statement.", 0 );
                cb->emitTerminator( p.resolver()->currentLocation(), cir::Ret( PoisonValue() ) );
                return false;
            }

            auto converted = ConvertValueToType( context, *retVal, *context.returnType() );
            if( holds_alternative< ValUnifyError >( converted ) )
            {
                switch( get< ValUnifyError >( converted ) )
                {
                    case ValUnifyError::NoSolution:
                        dm.emitErrorMessage( retVal->locationId(), "return value type mismatch." );
                        break;

                    case ValUnifyError::Ambiguous:
                        dm.emitErrorMessage( retVal->locationId(), "ambiguous return value conversion." );
                        break;
                }

                // Emit a terminator with a poison value to avoid the function compilation
                // code to complain about a missing return.
                cb->emitTerminator( p.resolver()->currentLocation(), cir::Ret( PoisonValue() ) );
                cb->poison();
                return true;
            }

            cb->emitTerminator( p.resolver()->currentLocation(), cir::Ret( get< Value >( converted ) ) );
            return true;
        };

        Rule r( handleReturn );
        auto ruleVal = ToValue( move( r ) );
        auto ruleTerm = ValueToIRExpr( ruleVal );
        e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( return ) ), ANYTERM( _ ), ruleTerm );
    }
}
Changes to bs/builtins/statements/using.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
#include "builtins/builtins.h"
#include "parse/parse.h"
#include "precedence.h"

using namespace goose;
using namespace goose::ir;
using namespace goose::parse;

namespace goose::builtins
{
    void SetupUsingStmt( Env& e )
    {
        auto handleUsing = []( Parser& p, uint32_t locationId, uint32_t prec )





|







1
2
3
4
5
6
7
8
9
10
11
12
13
#include "builtins/builtins.h"
#include "parse/parse.h"
#include "precedence.h"

using namespace goose;
using namespace goose::eir;
using namespace goose::parse;

namespace goose::builtins
{
    void SetupUsingStmt( Env& e )
    {
        auto handleUsing = []( Parser& p, uint32_t locationId, uint32_t prec )
Changes to bs/builtins/statements/verification.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
#include "builtins/builtins.h"
#include "precedence.h"
#include "builtins/helpers.h"

using namespace goose;
using namespace goose::ir;
using namespace goose::parse;
using namespace goose::builtins;

namespace
{
    optional< uint32_t > VerifStmtPrecedence( const Parser& p )
    {





|







1
2
3
4
5
6
7
8
9
10
11
12
13
#include "builtins/builtins.h"
#include "precedence.h"
#include "builtins/helpers.h"

using namespace goose;
using namespace goose::eir;
using namespace goose::parse;
using namespace goose::builtins;

namespace
{
    optional< uint32_t > VerifStmtPrecedence( const Parser& p )
    {
Changes to bs/builtins/statements/while.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include "builtins/builtins.h"
#include "parse/parse.h"
#include "precedence.h"
#include "builtins/helpers.h"

using namespace goose;
using namespace goose::ir;
using namespace goose::parse;

namespace goose::builtins
{
    void SetupWhileStmt( Env& e )
    {
        auto handleWhile = []( Parser& p, uint32_t locationId, uint32_t prec )






|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include "builtins/builtins.h"
#include "parse/parse.h"
#include "precedence.h"
#include "builtins/helpers.h"

using namespace goose;
using namespace goose::eir;
using namespace goose::parse;

namespace goose::builtins
{
    void SetupWhileStmt( Env& e )
    {
        auto handleWhile = []( Parser& p, uint32_t locationId, uint32_t prec )
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
            if( !pPrecBB )
                return true;

            // Retrieve the final block of the loop body, if any
            if( auto pBodySuccBB = cfg->currentBB(); pBodySuccBB && !pBodySuccBB->terminator() )
            {
                // Jump from the end of the body BB back to the loop header
                pBodySuccBB->setTerminator( llr::Branch( pHeaderBB ) );
            }

            // Jump unconditionally from the pred block to the loop header.
            pPrecBB->setTerminator( llr::Branch( pHeaderBB ) );

            auto pSuccBB = cfg->createBB();

            auto breakLevel = cb->breakableScopeLevels();
            auto continueLevel = cb->continuableScopeLevels();

            // Go through all basic blocks, find all break and continue terminators
            // for our scope level and replace them with branches respectively to
            // the successor BB or to the loop header BB.
            cfg->forEachBB( [&]( auto&& bb )
            {
                const auto& t = bb->terminator();
                if( !t )
                    return;

                if( const auto* pBreak = get_if< llr::Break >( &t->content() ) )
                {
                    if( pBreak->level() == breakLevel )
                        bb->setTerminator( llr::Branch( pSuccBB ) );
                    return;
                }

                if( const auto* pCont = get_if< llr::Continue >( &t->content() ) )
                {
                    if( pCont->level() == continueLevel )
                        bb->setTerminator( llr::Branch( pHeaderBB ) );
                    return;
                }
            } );

            // Emit the conditional branch that will either run an iteration of the loop or exit to the succ bb.
            pHeaderBB->setTerminator( llr::CondBranch(
                get< Value >( converted ),
                pBodyBB, pSuccBB ) );

            cfg->setCurrentBB( pSuccBB );
            return true;
        };

        Rule r( handleWhile );
        auto ruleVal = ToValue( move( r ) );
        auto ruleTerm = ValueToIRExpr( ruleVal );
        e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( while ) ), ANYTERM( _ ), ruleTerm );
    }
}







|



|















|


|



|


|





|













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
            if( !pPrecBB )
                return true;

            // Retrieve the final block of the loop body, if any
            if( auto pBodySuccBB = cfg->currentBB(); pBodySuccBB && !pBodySuccBB->terminator() )
            {
                // Jump from the end of the body BB back to the loop header
                pBodySuccBB->setTerminator( cir::Branch( pHeaderBB ) );
            }

            // Jump unconditionally from the pred block to the loop header.
            pPrecBB->setTerminator( cir::Branch( pHeaderBB ) );

            auto pSuccBB = cfg->createBB();

            auto breakLevel = cb->breakableScopeLevels();
            auto continueLevel = cb->continuableScopeLevels();

            // Go through all basic blocks, find all break and continue terminators
            // for our scope level and replace them with branches respectively to
            // the successor BB or to the loop header BB.
            cfg->forEachBB( [&]( auto&& bb )
            {
                const auto& t = bb->terminator();
                if( !t )
                    return;

                if( const auto* pBreak = get_if< cir::Break >( &t->content() ) )
                {
                    if( pBreak->level() == breakLevel )
                        bb->setTerminator( cir::Branch( pSuccBB ) );
                    return;
                }

                if( const auto* pCont = get_if< cir::Continue >( &t->content() ) )
                {
                    if( pCont->level() == continueLevel )
                        bb->setTerminator( cir::Branch( pHeaderBB ) );
                    return;
                }
            } );

            // Emit the conditional branch that will either run an iteration of the loop or exit to the succ bb.
            pHeaderBB->setTerminator( cir::CondBranch(
                get< Value >( converted ),
                pBodyBB, pSuccBB ) );

            cfg->setCurrentBB( pSuccBB );
            return true;
        };

        Rule r( handleWhile );
        auto ruleVal = ToValue( move( r ) );
        auto ruleTerm = ValueToIRExpr( ruleVal );
        e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( while ) ), ANYTERM( _ ), ruleTerm );
    }
}
Changes to bs/builtins/types/basic.cpp.
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
    const Term& ValuePatternT::GetPattern()
    {
        static auto pattern = HOLE( "T"_sid );
        return pattern;
    }
}

namespace goose::ir
{
    // void
    const Term& Bridge< void >::Type()
    {
        static auto type = ValueToIRExpr( Value( TypeType(), TSID( void ) ) );
        return type;
    }







|







28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
    const Term& ValuePatternT::GetPattern()
    {
        static auto pattern = HOLE( "T"_sid );
        return pattern;
    }
}

namespace goose::eir
{
    // void
    const Term& Bridge< void >::Type()
    {
        static auto type = ValueToIRExpr( Value( TypeType(), TSID( void ) ) );
        return type;
    }
Changes to bs/builtins/types/basic.h.
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
        }
    };

    template< typename T >
    using ValueTypeOf = CustomPattern< Value, PatternValueTypeOf< T > >;
}

namespace goose::ir
{
    template<>
    struct Bridge< void >
    {
        static const Term& Type();
    };








|







20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
        }
    };

    template< typename T >
    using ValueTypeOf = CustomPattern< Value, PatternValueTypeOf< T > >;
}

namespace goose::eir
{
    template<>
    struct Bridge< void >
    {
        static const Term& Type();
    };

Changes to bs/builtins/types/constrainedfunc/constrainedfunc.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include "builtins/builtins.h"

using namespace goose::builtins;

bool goose::builtins::IsConstrainedFunc( const Value& tcc )
{
    return tcc.type() == GetValueType< ConstrainedFunc >();
}

namespace goose::ir
{
    const Term& Bridge< builtins::ConstrainedFunc >::Type()
    {
        static auto type = ValueToIRExpr( Value( TypeType(), VEC( TSID( ct_type ), TSID( constrainedfunc ) ) ) );
        return type;
    }










|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include "builtins/builtins.h"

using namespace goose::builtins;

bool goose::builtins::IsConstrainedFunc( const Value& tcc )
{
    return tcc.type() == GetValueType< ConstrainedFunc >();
}

namespace goose::eir
{
    const Term& Bridge< builtins::ConstrainedFunc >::Type()
    {
        static auto type = ValueToIRExpr( Value( TypeType(), VEC( TSID( ct_type ), TSID( constrainedfunc ) ) ) );
        return type;
    }

Changes to bs/builtins/types/constrainedfunc/constrainedfunc.h.
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
            ptr< InvocationRule >   m_pInvRule;
            Value                   m_func;
    };

    extern bool IsConstrainedFunc( const Value& tcc );
}

namespace goose::ir
{
    template<>
    struct Bridge< builtins::ConstrainedFunc >
    {
        static const Term& Type();
        static Value ToValue( const builtins::ConstrainedFunc& cf );
        static optional< builtins::ConstrainedFunc > FromValue( const Value& v );







|







25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
            ptr< InvocationRule >   m_pInvRule;
            Value                   m_func;
    };

    extern bool IsConstrainedFunc( const Value& tcc );
}

namespace goose::eir
{
    template<>
    struct Bridge< builtins::ConstrainedFunc >
    {
        static const Term& Type();
        static Value ToValue( const builtins::ConstrainedFunc& cf );
        static optional< builtins::ConstrainedFunc > FromValue( const Value& v );
Changes to bs/builtins/types/constrainedfunc/typecheck.cpp.
1
2
3
4
5
6
7
8
9
10
11
#include "builtins/builtins.h"

using namespace goose;
using namespace goose::ir;

namespace goose::builtins
{
    void SetupConstrainedFuncTypeChecking( Env& e )
    {
        auto funcTypePat = ValueToIRExpr( Value( TypeType(), VEC( TSID( func ),
            ANYTERM( _ ), ANYTERM( _ ) ) ) );



|







1
2
3
4
5
6
7
8
9
10
11
#include "builtins/builtins.h"

using namespace goose;
using namespace goose::eir;

namespace goose::builtins
{
    void SetupConstrainedFuncTypeChecking( Env& e )
    {
        auto funcTypePat = ValueToIRExpr( Value( TypeType(), VEC( TSID( func ),
            ANYTERM( _ ), ANYTERM( _ ) ) ) );
Changes to bs/builtins/types/decl.cpp.
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
        static auto pattern = ValueToIRExpr(
            Value( TypeType(), VEC( TSID( decl ), HOLE( "_"_sid ) ) ) );

        return pattern;
    }
}

namespace goose::ir
{
    Term Bridge< Decl >::Type( const Term& declType )
    {
        return ValueToIRExpr( Value( TypeType(), VEC( TSID( decl ), declType ) ) );
    }

    Value Bridge< Decl >::ToValue( const Decl& d )







|







22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
        static auto pattern = ValueToIRExpr(
            Value( TypeType(), VEC( TSID( decl ), HOLE( "_"_sid ) ) ) );

        return pattern;
    }
}

namespace goose::eir
{
    Term Bridge< Decl >::Type( const Term& declType )
    {
        return ValueToIRExpr( Value( TypeType(), VEC( TSID( decl ), declType ) ) );
    }

    Value Bridge< Decl >::ToValue( const Decl& d )
Changes to bs/builtins/types/decl.h.
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
            Term m_type;
            StringId m_name;
    };

    extern bool IsDecl( const Value& d );
}

namespace goose::ir
{
    template<>
    struct Bridge< builtins::Decl >
    {
        static Term Type( const Term& declType );
        static Value ToValue( const builtins::Decl& d );
        static optional< builtins::Decl > FromValue( const Value& v );







|







24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
            Term m_type;
            StringId m_name;
    };

    extern bool IsDecl( const Value& d );
}

namespace goose::eir
{
    template<>
    struct Bridge< builtins::Decl >
    {
        static Term Type( const Term& declType );
        static Value ToValue( const builtins::Decl& d );
        static optional< builtins::Decl > FromValue( const Value& v );
Changes to bs/builtins/types/destroy.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
#include "builtins/builtins.h"
#include "parse/parse.h"

using namespace goose::parse;
using namespace goose::llr;

namespace goose::builtins
{
    void SetupDestroyValue( Env& e )
    {
        // Default implementation of DestroyValue().
        // Does nothing.




|







1
2
3
4
5
6
7
8
9
10
11
12
#include "builtins/builtins.h"
#include "parse/parse.h"

using namespace goose::parse;
using namespace goose::cir;

namespace goose::builtins
{
    void SetupDestroyValue( Env& e )
    {
        // Default implementation of DestroyValue().
        // Does nothing.
Changes to bs/builtins/types/drop.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
#include "builtins/builtins.h"
#include "parse/parse.h"

using namespace goose::parse;
using namespace goose::llr;

namespace goose::builtins
{
    void SetupDropValue( Env& e )
    {
        // Default implementation of DropValue().
        // Constant values are discarded, and the llr of computed values
        // is appended to the current BB of the current parser.
        RegisterBuiltinFunc< Intrinsic< void ( Value ) > >( e, e.extDropValue(),
            []( const Context& c, const Value& v )
            {
                if( v.isConstant() || !c.codeBuilder() )
                    return;

                // Reference use a load instruction to store their address,
                // so don't emit them. There is never any point in emitting
                // a load whose result isn't used anyway.
                if( holds_alternative< Load >( v.llr()->content() ) )
                    return;

                auto bb = c.codeBuilder()->cfg()->currentBB();
                bb->emplace_back( move( *v.llr() ) );
            } );

        using AnyDeclType = CustomPattern< Decl, Decl::Pattern >;

        // DropValue for Decls: declare a local variable with default initialization.
        // TODO: if the invocation to InitializeValue fails, we should have a way to
        // replace the generic "function arguments mismatch" error message with something




|






|










|



|







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 "builtins/builtins.h"
#include "parse/parse.h"

using namespace goose::parse;
using namespace goose::cir;

namespace goose::builtins
{
    void SetupDropValue( Env& e )
    {
        // Default implementation of DropValue().
        // Constant values are discarded, and the cir of computed values
        // is appended to the current BB of the current parser.
        RegisterBuiltinFunc< Intrinsic< void ( Value ) > >( e, e.extDropValue(),
            []( const Context& c, const Value& v )
            {
                if( v.isConstant() || !c.codeBuilder() )
                    return;

                // Reference use a load instruction to store their address,
                // so don't emit them. There is never any point in emitting
                // a load whose result isn't used anyway.
                if( holds_alternative< Load >( v.cir()->content() ) )
                    return;

                auto bb = c.codeBuilder()->cfg()->currentBB();
                bb->emplace_back( move( *v.cir() ) );
            } );

        using AnyDeclType = CustomPattern< Decl, Decl::Pattern >;

        // DropValue for Decls: declare a local variable with default initialization.
        // TODO: if the invocation to InitializeValue fails, we should have a way to
        // replace the generic "function arguments mismatch" error message with something
Changes to bs/builtins/types/func/bfunc.h.
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80

    // Same as above, but takes a type pattern provider.
    template< typename PP >
    struct TypePatternParam
    {};
}

namespace goose::ir
{
    template< typename R, typename... T >
    struct Bridge< R ( T... ) >
    {
        using functype = function< R ( T... ) >;

        static const Term& Type( const ptr< builtins::FuncVerificationInfos >& fvi = nullptr );







|







66
67
68
69
70
71
72
73
74
75
76
77
78
79
80

    // Same as above, but takes a type pattern provider.
    template< typename PP >
    struct TypePatternParam
    {};
}

namespace goose::eir
{
    template< typename R, typename... T >
    struct Bridge< R ( T... ) >
    {
        using functype = function< R ( T... ) >;

        static const Term& Type( const ptr< builtins::FuncVerificationInfos >& fvi = nullptr );
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
        {
            return GetValueType< T >();
        }

        template< typename TT >
        static auto ToValue( TT&& val )
        {
            return ir::ToValue( forward< TT >( val ) );
        }

        static auto FromValue( const Value& v )
        {
            return ir::FromValue< T >( v );
        }
    };
}

#endif







|




|





93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
        {
            return GetValueType< T >();
        }

        template< typename TT >
        static auto ToValue( TT&& val )
        {
            return eir::ToValue( forward< TT >( val ) );
        }

        static auto FromValue( const Value& v )
        {
            return eir::FromValue< T >( v );
        }
    };
}

#endif
Changes to bs/builtins/types/func/bfunc.inl.
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
        if( !pOvlSet->add( env, ToValue< FT >( forward< F >( func ), fvi ), GetFuncInvocationRule() ) )
            throw logic_error( "panic: duplicate overload registered for builtin func." );

        return fvi;
    }
}

namespace goose::ir
{
    template< typename T >
    struct BuildBuiltinFuncParamPat
    {
        static const auto& GetParamPattern()
        {
            static auto pat = builtins::ParamPat( GetValueType< T >() );







|







37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
        if( !pOvlSet->add( env, ToValue< FT >( forward< F >( func ), fvi ), GetFuncInvocationRule() ) )
            throw logic_error( "panic: duplicate overload registered for builtin func." );

        return fvi;
    }
}

namespace goose::eir
{
    template< typename T >
    struct BuildBuiltinFuncParamPat
    {
        static const auto& GetParamPattern()
        {
            static auto pat = builtins::ParamPat( GetValueType< T >() );
145
146
147
148
149
150
151
152
153
154
155
156
157

            if constexpr( is_void_v< builtins::remove_eager_t< R > > )
            {
                apply( func, *params );
                return Value( GetValueType< void >(), 0U );
            }
            else
                return ir::ToValue( apply( func, *params ) );
        };
    }
}

#endif







|





145
146
147
148
149
150
151
152
153
154
155
156
157

            if constexpr( is_void_v< builtins::remove_eager_t< R > > )
            {
                apply( func, *params );
                return Value( GetValueType< void >(), 0U );
            }
            else
                return eir::ToValue( apply( func, *params ) );
        };
    }
}

#endif
Changes to bs/builtins/types/func/build.cpp.
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
                auto decl = *FromValue< Decl >( param );
                tv->append( ParamPat( decl.type() ) );

                // Bind a stand-in value with the parameters name to be used inside of verification expressions.
                auto paramVerificationIdentity = AppendToVectorTerm( verificationIdentity,
                    TERM( decl.name() ) );

                Reference argRef( ReferenceType{ decl.type(), TSID( const ) }, llr::VarBaseAddr( varId++ ) );

                c.env()->storeValue( paramVerificationIdentity, ANYTERM( _ ),
                    ValueToIRExpr( BuildComputedValue( decl.type(),
                    llr::Load( ToValue( argRef ), decl.type() ) ) ) );
            }
            else if( param.isConstant() )
                tv->append( ValueToIRExpr( param ) );

            return true;
        } );

        // 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 llr instruction. This will allow verification
        // expressions to refer to the current function's return value as a value of the correct type.
        auto rtTerm = ValueToIRExpr( returnType );
        if( rtTerm != GetValueType< void >() )
        {
            auto name = "@result"_sid;
            auto retValVerificationIdentity = AppendToVectorTerm( verificationIdentity, TERM( name ) );

            c.env()->storeValue( retValVerificationIdentity, ANYTERM( _ ),
                ValueToIRExpr( BuildComputedValue( rtTerm, llr::Placeholder( rtTerm, name ) ) ) );
        }

        auto pVerifInfos = make_shared< FuncVerificationInfos >( move( verificationIdentity ) );
        return FuncType( ValueToIRExpr( returnType ), tv, move( pVerifInfos ) );
    }

    Func BuildExternalFunc( FuncType funcType, const string& symbol, bool varArg )







|



|








|








|







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
                auto decl = *FromValue< Decl >( param );
                tv->append( ParamPat( decl.type() ) );

                // Bind a stand-in value with the parameters name to be used inside of verification expressions.
                auto paramVerificationIdentity = AppendToVectorTerm( verificationIdentity,
                    TERM( decl.name() ) );

                Reference argRef( ReferenceType{ decl.type(), TSID( const ) }, cir::VarBaseAddr( varId++ ) );

                c.env()->storeValue( paramVerificationIdentity, ANYTERM( _ ),
                    ValueToIRExpr( BuildComputedValue( decl.type(),
                    cir::Load( ToValue( argRef ), decl.type() ) ) ) );
            }
            else if( param.isConstant() )
                tv->append( ValueToIRExpr( param ) );

            return true;
        } );

        // 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 = ValueToIRExpr( returnType );
        if( rtTerm != GetValueType< void >() )
        {
            auto name = "@result"_sid;
            auto retValVerificationIdentity = AppendToVectorTerm( verificationIdentity, TERM( name ) );

            c.env()->storeValue( retValVerificationIdentity, ANYTERM( _ ),
                ValueToIRExpr( BuildComputedValue( rtTerm, cir::Placeholder( rtTerm, name ) ) ) );
        }

        auto pVerifInfos = make_shared< FuncVerificationInfos >( move( verificationIdentity ) );
        return FuncType( ValueToIRExpr( returnType ), tv, move( pVerifInfos ) );
    }

    Func BuildExternalFunc( FuncType funcType, const string& symbol, bool varArg )
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
        auto funcTypeTerm = ValueToIRExpr( ToValue( funcType ) );
        auto identity = VEC( funcIdentity, funcTypeTerm );

        assert( c.identity() != identity );
        c.env()->addVisibilityRule( c.identity(), identity );

        out_bodyContext = Context( c.env(), identity, funcType.returnType() );
        auto pFuncLLR = c.env()->createLLRFunc( identity );

        return Func( funcType, unparsedBody, get< pvec >( paramsDecl.val() ), pFuncLLR.get() );
    }

    Term BuildCallPatternFromFuncType( const Value& funcType )
    {
        auto ftype = *FromValue< FuncType >( funcType );

        auto apv = make_shared< Vector >();







|

|







75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
        auto funcTypeTerm = ValueToIRExpr( ToValue( funcType ) );
        auto identity = VEC( funcIdentity, funcTypeTerm );

        assert( c.identity() != identity );
        c.env()->addVisibilityRule( c.identity(), identity );

        out_bodyContext = Context( c.env(), identity, funcType.returnType() );
        auto pFuncCIR = c.env()->createCIRFunc( identity );

        return Func( funcType, unparsedBody, get< pvec >( paramsDecl.val() ), pFuncCIR.get() );
    }

    Term BuildCallPatternFromFuncType( const Value& funcType )
    {
        auto ftype = *FromValue< FuncType >( funcType );

        auto apv = make_shared< Vector >();
Changes to bs/builtins/types/func/compile.cpp.
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
167
168
169
    }

    bool ParseFuncBody( const Context& c, const Func& f )
    {
        if( !ParseFuncConstraints( c, f.type() ) )
            return false;

        const auto& pFuncLLR = f.llr();

        // If the function was already marked as invalid, don't bother trying to compile it again.
        if( !pFuncLLR->isValid() )
            return false;

        // Perform lazy parsing on param types' predicates
        bool predsOk = true;

        ForEachInVectorTerm( f.type().params(), [&]( auto&& param )
        {
            auto result = Decompose( param,
                Vec(
                    Lit( "value"_sid ),
                    SubTerm(),
                    SubTerm(),
                    SubTerm(),
                    Val< LocationId >()
                )
            );
            assert( result );

            auto&& [sort, type, val, locId] = *result;

            if( !ParseTypePredicates( c, pFuncLLR->identity(), *ValueFromIRExpr( type ) ) )
                predsOk = false;

            return true;
        } );

        if( !predsOk )
            return false;

        // Perform lazy parsing on return type predicates
        if( !ParseTypePredicates( c, pFuncLLR->identity(), *ValueFromIRExpr( f.type().returnType() ) ) )
            return false;

        // If the function already have a llr body, nothing to do.
        if( pFuncLLR->body() )
            return true;

        if( !f.tokens() )
            return false;

        Context localContext( c.env(), pFuncLLR->identity(), f.type().returnType() );

        auto cfg = make_shared< llr::CFG >( VecSize( f.type().params() ) );
        cfg->createBB();
        cfg->setCurrentBB( cfg->entryBB() );

        auto cb = make_shared< CodeBuilder >( cfg );
        localContext.setBuilder( cb );

        // Create the local variable bindings to access the function params
        // from inside the body, as well as the signature.
        uint32_t varId = 0;
        for( auto&& t : f.paramsDecl()->terms() )
        {
            auto param = *ValueFromIRExpr( t );

            if( !IsDecl( param ) )
                continue;

            auto decl = *FromValue< Decl >( param );

            auto paramIdentity = AppendToVectorTerm(
                pFuncLLR->identity(),// ANYTERM( _ ),
                TERM( decl.name() ) );

            // Create a locvar to hold the param.
            LocalVar lv( decl.name(), decl.type(), varId++ );
            auto locVar = ToValue( lv ).setLocationId( param.locationId() );

            c.env()->storeValue( paramIdentity, ANYTERM( _ ),







|


|




















|









|


|
|





|

|



















|







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
167
168
169
    }

    bool ParseFuncBody( const Context& c, const Func& f )
    {
        if( !ParseFuncConstraints( c, f.type() ) )
            return false;

        const auto& pFuncCIR = f.cir();

        // If the function was already marked as invalid, don't bother trying to compile it again.
        if( !pFuncCIR->isValid() )
            return false;

        // Perform lazy parsing on param types' predicates
        bool predsOk = true;

        ForEachInVectorTerm( f.type().params(), [&]( auto&& param )
        {
            auto result = Decompose( param,
                Vec(
                    Lit( "value"_sid ),
                    SubTerm(),
                    SubTerm(),
                    SubTerm(),
                    Val< LocationId >()
                )
            );
            assert( result );

            auto&& [sort, type, val, locId] = *result;

            if( !ParseTypePredicates( c, pFuncCIR->identity(), *ValueFromIRExpr( type ) ) )
                predsOk = false;

            return true;
        } );

        if( !predsOk )
            return false;

        // Perform lazy parsing on return type predicates
        if( !ParseTypePredicates( c, pFuncCIR->identity(), *ValueFromIRExpr( f.type().returnType() ) ) )
            return false;

        // If the function already have a cir body, nothing to do.
        if( pFuncCIR->body() )
            return true;

        if( !f.tokens() )
            return false;

        Context localContext( c.env(), pFuncCIR->identity(), f.type().returnType() );

        auto cfg = make_shared< cir::CFG >( VecSize( f.type().params() ) );
        cfg->createBB();
        cfg->setCurrentBB( cfg->entryBB() );

        auto cb = make_shared< CodeBuilder >( cfg );
        localContext.setBuilder( cb );

        // Create the local variable bindings to access the function params
        // from inside the body, as well as the signature.
        uint32_t varId = 0;
        for( auto&& t : f.paramsDecl()->terms() )
        {
            auto param = *ValueFromIRExpr( t );

            if( !IsDecl( param ) )
                continue;

            auto decl = *FromValue< Decl >( param );

            auto paramIdentity = AppendToVectorTerm(
                pFuncCIR->identity(),// ANYTERM( _ ),
                TERM( decl.name() ) );

            // Create a locvar to hold the param.
            LocalVar lv( decl.name(), decl.type(), varId++ );
            auto locVar = ToValue( lv ).setLocationId( param.locationId() );

            c.env()->storeValue( paramIdentity, ANYTERM( _ ),
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
211
212
213
214
215
216
217
218
219
220
221
222

        if( !success || cfg->isPoisoned() )
        {
            // Fail silently here, because it may be a case of trying
            // to execute an invocation at compile time before falling
            // back to code generation.
            // It's up to our caller to catch the error here, if any.
            pFuncLLR->setInvalid();
            return false;
        }

        if( cfg->currentBB() && !cfg->currentBB()->terminator() )
        {
            if( localContext.returnType() != GetValueType< void >() )
            {
                pFuncLLR->setInvalid();

                // TODO: this location sucks, we might need to store the last parsed location
                // inside each BB to improve that
                DiagnosticsManager::GetInstance().emitErrorMessage( r->currentLocation(),
                    "missing return statement in a function with non-void return type." );
                return false;
            }

            // Implicit return at the end of a void function:
            // Emit the cleanups, and the terminator.
            // TODO: at some point we'll want to check for reachability in the static verifier,
            // and either emit the implicit return or declare the code unreachable depending on the result.
            // The reachability analysis will have to be done before contract validation, as the
            // 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 );
            cb->emitTerminator( r->currentLocation(), llr::Ret() );
        }

        pFuncLLR->body() = cfg;

        verify::Func fv( localContext, f );
        return fv.verify();
    }
}







|







|

















|


|





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
211
212
213
214
215
216
217
218
219
220
221
222

        if( !success || cfg->isPoisoned() )
        {
            // Fail silently here, because it may be a case of trying
            // to execute an invocation at compile time before falling
            // back to code generation.
            // It's up to our caller to catch the error here, if any.
            pFuncCIR->setInvalid();
            return false;
        }

        if( cfg->currentBB() && !cfg->currentBB()->terminator() )
        {
            if( localContext.returnType() != GetValueType< void >() )
            {
                pFuncCIR->setInvalid();

                // TODO: this location sucks, we might need to store the last parsed location
                // inside each BB to improve that
                DiagnosticsManager::GetInstance().emitErrorMessage( r->currentLocation(),
                    "missing return statement in a function with non-void return type." );
                return false;
            }

            // Implicit return at the end of a void function:
            // Emit the cleanups, and the terminator.
            // TODO: at some point we'll want to check for reachability in the static verifier,
            // and either emit the implicit return or declare the code unreachable depending on the result.
            // The reachability analysis will have to be done before contract validation, as the
            // 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 );
            cb->emitTerminator( r->currentLocation(), cir::Ret() );
        }

        pFuncCIR->body() = cfg;

        verify::Func fv( localContext, f );
        return fv.verify();
    }
}
Changes to bs/builtins/types/func/func.cpp.
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
        );
        assert( typeDecomp );
        auto&& [kind, rtype, ptypes, vinf, varArg] = *typeDecomp;

        return rtype;
    }

    const llr::Func* GetFuncLLR( const Value& f )
    {
        if( !f.isConstant() )
            return nullptr;

        auto func = FromValue< Func >( f );
        assert( func );
        return func->llr();
    }

    ParamListKind CheckParamListKind( const Value& tup )
    {
        if( !IsTuple( tup ) )
            return ParamListKind::Invalid;








|






|







90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
        );
        assert( typeDecomp );
        auto&& [kind, rtype, ptypes, vinf, varArg] = *typeDecomp;

        return rtype;
    }

    const cir::Func* GetFuncCIR( const Value& f )
    {
        if( !f.isConstant() )
            return nullptr;

        auto func = FromValue< Func >( f );
        assert( func );
        return func->cir();
    }

    ParamListKind CheckParamListKind( const Value& tup )
    {
        if( !IsTuple( tup ) )
            return ParamListKind::Invalid;

141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
            return true;
        } );

        return av;
    }
}

namespace goose::ir
{
    const Term& Bridge< FuncType >::Type()
    {
        return TypeType();
    }

    Value Bridge< FuncType >::ToValue( const FuncType& ft )







|







141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
            return true;
        } );

        return av;
    }
}

namespace goose::eir
{
    const Term& Bridge< FuncType >::Type()
    {
        return TypeType();
    }

    Value Bridge< FuncType >::ToValue( const FuncType& ft )
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
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

    Value Bridge< Func >::ToValue( const builtins::Func& func )
    {
        if( func.isExternal() )
            return Value( Type( func ), TERM( *func.symbol() ) );

        return Value( Type( func ), VEC(
            TERM( func.tokens() ), TERM( func.paramsDecl() ), TERM( func.llr() ) ) );
    }

    optional< Func > Bridge< Func >::FromValue( const Value& v )
    {
        if( !v.isConstant() || v.isPoison() )
            return nullopt;

        auto funcTypeVal = ValueFromIRExpr( v.type() );
        if( !funcTypeVal )
            return nullopt;

        auto funcType = ::FromValue< FuncType >( *funcTypeVal );
        if( !funcType )
            return nullopt;

        auto result = Decompose( v.val(),
            Vec(
                Val< ptr< void > >(),   // body toks
                Val< pvec >(),          // param decls
                Val< void* >()          // llr
            )
        );

        if( result )
        {
            auto&& [toks,paramDecls,llr] = *result;
            return Func( move( *funcType ), toks, paramDecls, static_cast< llr::Func* >( llr ) );
        }

        // Try to decode it as an external func
        auto result2 = Decompose( v.val(),
            Val< string >()
        );

        if( !result2 )
            return nullopt;

        return Func( move( *funcType ), *result2 );
    }
}







|



















|





|
|













189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
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

    Value Bridge< Func >::ToValue( const builtins::Func& func )
    {
        if( func.isExternal() )
            return Value( Type( func ), TERM( *func.symbol() ) );

        return Value( Type( func ), VEC(
            TERM( func.tokens() ), TERM( func.paramsDecl() ), TERM( func.cir() ) ) );
    }

    optional< Func > Bridge< Func >::FromValue( const Value& v )
    {
        if( !v.isConstant() || v.isPoison() )
            return nullopt;

        auto funcTypeVal = ValueFromIRExpr( v.type() );
        if( !funcTypeVal )
            return nullopt;

        auto funcType = ::FromValue< FuncType >( *funcTypeVal );
        if( !funcType )
            return nullopt;

        auto result = Decompose( v.val(),
            Vec(
                Val< ptr< void > >(),   // body toks
                Val< pvec >(),          // param decls
                Val< void* >()          // cir
            )
        );

        if( result )
        {
            auto&& [toks,paramDecls,cir] = *result;
            return Func( move( *funcType ), toks, paramDecls, static_cast< cir::Func* >( cir ) );
        }

        // Try to decode it as an external func
        auto result2 = Decompose( v.val(),
            Val< string >()
        );

        if( !result2 )
            return nullopt;

        return Func( move( *funcType ), *result2 );
    }
}
Changes to bs/builtins/types/func/func.h.
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
        Template,
        Invalid
    };

    extern Term GetFuncSig( const Value& func );
    extern Term GetFuncSigFromType( const Value& funcType );
    extern Term GetFuncRType( const Value& func );
    extern const llr::Func* GetFuncLLR( const Value& func );

    // Given a tuple, determines whether it is a valid param list, and of which kind.
    extern ParamListKind CheckParamListKind( const Value& tup );

    template< typename F >
    void ForEachDeclInTuple( const Value& tup, F&& func );








|







22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
        Template,
        Invalid
    };

    extern Term GetFuncSig( const Value& func );
    extern Term GetFuncSigFromType( const Value& funcType );
    extern Term GetFuncRType( const Value& func );
    extern const cir::Func* GetFuncCIR( const Value& func );

    // Given a tuple, determines whether it is a valid param list, and of which kind.
    extern ParamListKind CheckParamListKind( const Value& tup );

    template< typename F >
    void ForEachDeclInTuple( const Value& tup, F&& func );

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
    extern bool IsExternalFunc( const Value& f );
    extern bool IsFuncType( const Value& t );

    class Func
    {
        public:
            template< typename T, typename B, typename P >
            Func( T&& funcType, B&& toks, P&& paramsDecls, llr::Func* llr ) :
                m_type( forward< T >( funcType ) ),
                m_tokens( forward< B >( toks ) ),
                m_paramsDecl( forward< P >( paramsDecls ) ),
                m_llr( llr )
            {}

            template< typename T, typename B, typename P >
            Func( T&& funcType, B&& toks, P&& paramsDecls ) :
                m_type( forward< T >( funcType ) ),
                m_tokens( forward< B >( toks ) ),
                m_paramsDecl( forward< P >( paramsDecls ) )
            {}

            template< typename T >
            Func( T&& funcType, const string& symbol ) :
                m_type( forward< T >( funcType ) ),
                m_symbol( symbol )
            {}

            bool isExternal() const { return m_symbol.has_value(); }

            const auto& type() const { return m_type; }
            const auto& tokens() const { return m_tokens; }
            const auto& paramsDecl() const { return m_paramsDecl; }
            const auto& llr() const { return m_llr; }
            const auto& symbol() const { return m_symbol; }

            void setLLR( llr::Func* llr )
            {
                m_llr = llr;
            }

        private:
            FuncType m_type;

            ptr< void > m_tokens;  // the unparsed body

            pvec m_paramsDecl;
            llr::Func* m_llr = nullptr;

            // The function's symbol, if this is an external function.
            optional< string > m_symbol;
    };

    extern Value CompileFunc( const Context& c, const Value& f );
    extern bool ParseFuncConstraints( const Context& c, const FuncType& funcType );
    extern bool ParseFuncBody( const Context& c, const Value& f );
    extern bool ParseFuncBody( const Context& c, const Func& f );

    // The args for a function may include constants that are specialization args.
    // When building a call instruction, we need to strip those out and keep only
    // the args that actually exist at runtime / execution time.
    extern Term BuildArgListForCall( const FuncType& ft, const Term& unifiedArgs );
}

namespace goose::ir
{
    template<>
    struct Bridge< builtins::FuncType >
    {
        static const Term& Type();
        static Value ToValue( const builtins::FuncType& ft );
        static optional< builtins::FuncType > FromValue( const Value& v );







|



|




















|


|

|








|
















|







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
    extern bool IsExternalFunc( const Value& f );
    extern bool IsFuncType( const Value& t );

    class Func
    {
        public:
            template< typename T, typename B, typename P >
            Func( T&& funcType, B&& toks, P&& paramsDecls, cir::Func* cir ) :
                m_type( forward< T >( funcType ) ),
                m_tokens( forward< B >( toks ) ),
                m_paramsDecl( forward< P >( paramsDecls ) ),
                m_cir( cir )
            {}

            template< typename T, typename B, typename P >
            Func( T&& funcType, B&& toks, P&& paramsDecls ) :
                m_type( forward< T >( funcType ) ),
                m_tokens( forward< B >( toks ) ),
                m_paramsDecl( forward< P >( paramsDecls ) )
            {}

            template< typename T >
            Func( T&& funcType, const string& symbol ) :
                m_type( forward< T >( funcType ) ),
                m_symbol( symbol )
            {}

            bool isExternal() const { return m_symbol.has_value(); }

            const auto& type() const { return m_type; }
            const auto& tokens() const { return m_tokens; }
            const auto& paramsDecl() const { return m_paramsDecl; }
            const auto& cir() const { return m_cir; }
            const auto& symbol() const { return m_symbol; }

            void setCIR( cir::Func* cir )
            {
                m_cir = cir;
            }

        private:
            FuncType m_type;

            ptr< void > m_tokens;  // the unparsed body

            pvec m_paramsDecl;
            cir::Func* m_cir = nullptr;

            // The function's symbol, if this is an external function.
            optional< string > m_symbol;
    };

    extern Value CompileFunc( const Context& c, const Value& f );
    extern bool ParseFuncConstraints( const Context& c, const FuncType& funcType );
    extern bool ParseFuncBody( const Context& c, const Value& f );
    extern bool ParseFuncBody( const Context& c, const Func& f );

    // The args for a function may include constants that are specialization args.
    // When building a call instruction, we need to strip those out and keep only
    // the args that actually exist at runtime / execution time.
    extern Term BuildArgListForCall( const FuncType& ft, const Term& unifiedArgs );
}

namespace goose::eir
{
    template<>
    struct Bridge< builtins::FuncType >
    {
        static const Term& Type();
        static Value ToValue( const builtins::FuncType& ft );
        static optional< builtins::FuncType > FromValue( const Value& v );
Changes to bs/builtins/types/func/invoke.cpp.
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
                );

                auto&& [unifiedArgs, unifiedRType] = *callDecomp;

                newCallee.setLocationId( loc );

                if( IsBuiltinFunc( newCallee ) )
                    return BuildComputedValue( unifiedRType, llr::Call( newCallee, unifiedArgs ) );

                if( IsIntrinsicFunc( newCallee ) )
                    return GetBuiltinIntrinsicFuncWrapper( newCallee )( c, unifiedArgs );

                auto ft = *FromValue< FuncType >( *ValueFromIRExpr( newCallee.type() ) );
                auto argList = BuildArgListForCall( ft, unifiedArgs );

                return BuildComputedValue( unifiedRType, llr::Call( newCallee, argList ) );
            }

            optional< Term > getSignature( const Value& callee ) const final
            {
                return GetFuncSig( callee );
            }








|







|







53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
                );

                auto&& [unifiedArgs, unifiedRType] = *callDecomp;

                newCallee.setLocationId( loc );

                if( IsBuiltinFunc( newCallee ) )
                    return BuildComputedValue( unifiedRType, cir::Call( newCallee, unifiedArgs ) );

                if( IsIntrinsicFunc( newCallee ) )
                    return GetBuiltinIntrinsicFuncWrapper( newCallee )( c, unifiedArgs );

                auto ft = *FromValue< FuncType >( *ValueFromIRExpr( newCallee.type() ) );
                auto argList = BuildArgListForCall( ft, unifiedArgs );

                return BuildComputedValue( unifiedRType, cir::Call( newCallee, argList ) );
            }

            optional< Term > getSignature( const Value& callee ) const final
            {
                return GetFuncSig( callee );
            }

Changes to bs/builtins/types/func/lower.cpp.
1
2
3
4
5
6
7
8
9
10
11
#include "builtins/builtins.h"

using namespace goose;
using namespace goose::ir;
using namespace goose::builtins;

namespace goose::builtins
{
    optional< FuncType > LowerFunctionTypeForRuntime( const Context& c, const FuncType& ft )
    {
        // If the passed function already have an associated llvm type,



|







1
2
3
4
5
6
7
8
9
10
11
#include "builtins/builtins.h"

using namespace goose;
using namespace goose::eir;
using namespace goose::builtins;

namespace goose::builtins
{
    optional< FuncType > LowerFunctionTypeForRuntime( const Context& c, const FuncType& ft )
    {
        // If the passed function already have an associated llvm type,
Changes to bs/builtins/types/func/typecheck.cpp.
1
2
3
4
5
6
7
8
9
10
11
#include "builtins/builtins.h"

using namespace goose;
using namespace goose::ir;

namespace goose::builtins
{
    void SetupFunctionTypeChecking( Env& e )
    {
        // Default param rule: we basically treat it like a regular value.
        // Things that need a more specific rule for params can override this with



|







1
2
3
4
5
6
7
8
9
10
11
#include "builtins/builtins.h"

using namespace goose;
using namespace goose::eir;

namespace goose::builtins
{
    void SetupFunctionTypeChecking( Env& e )
    {
        // Default param rule: we basically treat it like a regular value.
        // Things that need a more specific rule for params can override this with
Changes to bs/builtins/types/init.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
#include "builtins/builtins.h"
#include "parse/parse.h"

using namespace goose::parse;
using namespace goose::llr;

namespace goose::builtins
{
    void SetupInitialize( Env& e )
    {
        using ValueOfTypeT = CustomPattern< Value, ValuePatternT >;





|







1
2
3
4
5
6
7
8
9
10
11
12
#include "builtins/builtins.h"
#include "parse/parse.h"

using namespace goose::parse;
using namespace goose::cir;

namespace goose::builtins
{
    void SetupInitialize( Env& e )
    {
        using ValueOfTypeT = CustomPattern< Value, ValuePatternT >;

Changes to bs/builtins/types/intrinsic/intrinsic.h.
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
    struct VerificationIntrinsic
    {};

    using BuiltinIntrinsicFuncWrapper = function< Value ( const Context& c, const Term& argVec ) >;
    extern const BuiltinIntrinsicFuncWrapper& GetBuiltinIntrinsicFuncWrapper( const Value& func );
}

namespace goose::ir
{
    template< typename R, typename... T >
    struct Bridge< builtins::Intrinsic< R ( T... ) > >
    {
        using functype = function< R ( T... ) >;

        static const Term& Type( const ptr< builtins::FuncVerificationInfos >& fvi = nullptr );







|







16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
    struct VerificationIntrinsic
    {};

    using BuiltinIntrinsicFuncWrapper = function< Value ( const Context& c, const Term& argVec ) >;
    extern const BuiltinIntrinsicFuncWrapper& GetBuiltinIntrinsicFuncWrapper( const Value& func );
}

namespace goose::eir
{
    template< typename R, typename... T >
    struct Bridge< builtins::Intrinsic< R ( T... ) > >
    {
        using functype = function< R ( T... ) >;

        static const Term& Type( const ptr< builtins::FuncVerificationInfos >& fvi = nullptr );
Changes to bs/builtins/types/intrinsic/intrinsic.inl.
1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_BUILTINS_TYPES_INTRINSIC_INL
#define GOOSE_BUILTINS_TYPES_INTRINSIC_INL

namespace goose::ir
{
    template< typename R, typename... T >
    const Term& Bridge< builtins::Intrinsic< R ( T... ) > >::Type( const ptr< builtins::FuncVerificationInfos >& fvi )
    {
        static auto type = ValueToIRExpr( Value( TypeType(), VEC( TSID( func ), TSID( intrinsic ),
            GetValueType< Value >(),
            sema::Quote( BuildBuiltinFuncParamTypeList< T... >() ),



|







1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_BUILTINS_TYPES_INTRINSIC_INL
#define GOOSE_BUILTINS_TYPES_INTRINSIC_INL

namespace goose::eir
{
    template< typename R, typename... T >
    const Term& Bridge< builtins::Intrinsic< R ( T... ) > >::Type( const ptr< builtins::FuncVerificationInfos >& fvi )
    {
        static auto type = ValueToIRExpr( Value( TypeType(), VEC( TSID( func ), TSID( intrinsic ),
            GetValueType< Value >(),
            sema::Quote( BuildBuiltinFuncParamTypeList< T... >() ),
Changes to bs/builtins/types/localvar/drop.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
#include "builtins/builtins.h"
#include "parse/parse.h"

using namespace goose::parse;
using namespace goose::llr;

namespace goose::builtins
{
    void SetupLocalVarDropValue( Env& e )
    {
        using AnyLocVarType = CustomPattern< LocalVar, LocalVar::PatternAny >;





|







1
2
3
4
5
6
7
8
9
10
11
12
#include "builtins/builtins.h"
#include "parse/parse.h"

using namespace goose::parse;
using namespace goose::cir;

namespace goose::builtins
{
    void SetupLocalVarDropValue( Env& e )
    {
        using AnyLocVarType = CustomPattern< LocalVar, LocalVar::PatternAny >;

Changes to bs/builtins/types/localvar/invoke.cpp.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
    {
        public:
            bool canBeInvoked( const Context& c, const Value& callee ) const final
            {
                auto lv = *FromValue< LocalVar >( callee );

                auto val = BuildComputedValue( lv.type(),
                    llr::Load( ToValue( BuildLocalVarConstRef( lv ) ), lv.type() ) );

                return sema::CanBeInvoked( c, val );
            }

            Value resolveInvocation( const Context& c, uint32_t locationId, const Value& callee, const Term& args ) const final
            {
                auto lv = *FromValue< LocalVar >( callee );

                auto val = BuildComputedValue( lv.type(),
                    llr::Load( ToValue( BuildLocalVarConstRef( lv ) ), lv.type() ) );

                return sema::GetInvocationRule( *c.env(), val )->resolveInvocation( c, locationId, val, args );
            }
    };

    void SetupLocalVarInvocationRule( Env& e )
    {







|









|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
    {
        public:
            bool canBeInvoked( const Context& c, const Value& callee ) const final
            {
                auto lv = *FromValue< LocalVar >( callee );

                auto val = BuildComputedValue( lv.type(),
                    cir::Load( ToValue( BuildLocalVarConstRef( lv ) ), lv.type() ) );

                return sema::CanBeInvoked( c, val );
            }

            Value resolveInvocation( const Context& c, uint32_t locationId, const Value& callee, const Term& args ) const final
            {
                auto lv = *FromValue< LocalVar >( callee );

                auto val = BuildComputedValue( lv.type(),
                    cir::Load( ToValue( BuildLocalVarConstRef( lv ) ), lv.type() ) );

                return sema::GetInvocationRule( *c.env(), val )->resolveInvocation( c, locationId, val, args );
            }
    };

    void SetupLocalVarInvocationRule( Env& e )
    {
Changes to bs/builtins/types/localvar/localvar.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
#include "builtins/builtins.h"
#include "parse/parse.h"

using namespace goose::builtins;
using namespace goose::llr;
using namespace goose::parse;

namespace goose::builtins
{
    const Term& LocalVar::PatternAny::GetPattern()
    {
        static auto pattern = GetValueType< LocalVar >( HOLE( "_"_sid ) );




|







1
2
3
4
5
6
7
8
9
10
11
12
#include "builtins/builtins.h"
#include "parse/parse.h"

using namespace goose::builtins;
using namespace goose::cir;
using namespace goose::parse;

namespace goose::builtins
{
    const Term& LocalVar::PatternAny::GetPattern()
    {
        static auto pattern = GetValueType< LocalVar >( HOLE( "_"_sid ) );
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
        bb->emplace_back( AllocVar( ValueFromIRExpr( lv.type() )->setLocationId( typeLoc ), index ) );

        DiagnosticsContext dc( 0, "When invoking Initialize." );

        auto initResult = ResolveInvocation( c, GetInvocationRule( *c.env(), initializerVal ), initializerVal,
            MakeTuple( ToValue( lv ), initVal ) );

        if( !initResult.isConstant() && llr::CanValueBeEagerlyEvaluated( initResult ) )
        {
            execute::VM vm;
            initResult = execute::Evaluate( initResult, vm );
        }

        if( !initResult.isPoison() )
        {







|







179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
        bb->emplace_back( AllocVar( ValueFromIRExpr( lv.type() )->setLocationId( typeLoc ), index ) );

        DiagnosticsContext dc( 0, "When invoking Initialize." );

        auto initResult = ResolveInvocation( c, GetInvocationRule( *c.env(), initializerVal ), initializerVal,
            MakeTuple( ToValue( lv ), initVal ) );

        if( !initResult.isConstant() && cir::CanValueBeEagerlyEvaluated( initResult ) )
        {
            execute::VM vm;
            initResult = execute::Evaluate( initResult, vm );
        }

        if( !initResult.isPoison() )
        {
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
        }

        cb->pushLiveValue( locVar, lv.index() );
        return locVar;
    }
}

namespace goose::ir
{
    const Term& Bridge< LocalVarType >::Type()
    {
        return TypeType();
    }

    Value Bridge< LocalVarType >::ToValue( const LocalVarType& t )







|







206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
        }

        cb->pushLiveValue( locVar, lv.index() );
        return locVar;
    }
}

namespace goose::eir
{
    const Term& Bridge< LocalVarType >::Type()
    {
        return TypeType();
    }

    Value Bridge< LocalVarType >::ToValue( const LocalVarType& t )
Changes to bs/builtins/types/localvar/localvar.h.
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
        private:
            StringId m_name;
            Term m_type;
            uint32_t m_index = 0;
    };
}

namespace goose::ir
{
    template<>
    struct Bridge< builtins::LocalVarType >
    {
        static const Term& Type();
        static Value ToValue( const builtins::LocalVarType& t );
        static Value ToValue( const Term& type );







|







80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
        private:
            StringId m_name;
            Term m_type;
            uint32_t m_index = 0;
    };
}

namespace goose::eir
{
    template<>
    struct Bridge< builtins::LocalVarType >
    {
        static const Term& Type();
        static Value ToValue( const builtins::LocalVarType& t );
        static Value ToValue( const Term& type );
Changes to bs/builtins/types/localvar/typecheck.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
#include "builtins/builtins.h"

using namespace goose;
using namespace goose::ir;
using namespace goose::llr;

namespace goose::builtins
{
    void SetupLocalVarTypeChecking( Env& e )
    {
        auto localVarPattern = GetValueType< LocalVar >( ANYTERM( _ ) );




|
|







1
2
3
4
5
6
7
8
9
10
11
12
#include "builtins/builtins.h"

using namespace goose;
using namespace goose::eir;
using namespace goose::cir;

namespace goose::builtins
{
    void SetupLocalVarTypeChecking( Env& e )
    {
        auto localVarPattern = GetValueType< LocalVar >( ANYTERM( _ ) );

Changes to bs/builtins/types/lower.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
#include "builtins/builtins.h"
#include "parse/parse.h"

using namespace goose::parse;
using namespace goose::llr;

namespace goose::builtins
{
    void SetupLower( Env& e )
    {
        // Default implementation of LowerTypeForVerification():
        // Do nothing.




|







1
2
3
4
5
6
7
8
9
10
11
12
#include "builtins/builtins.h"
#include "parse/parse.h"

using namespace goose::parse;
using namespace goose::cir;

namespace goose::builtins
{
    void SetupLower( Env& e )
    {
        // Default implementation of LowerTypeForVerification():
        // Do nothing.
Changes to bs/builtins/types/overloadset/helpers.cpp.
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
        assert( pOvlSet );

        Context localC( c.env(), c.identity(), GetValueType< uint32_t >() );
        localC.setBuilder( c.codeBuilder() );

        execute::VM vm;

        if( !args.isConstant() && llr::CanValueBeEagerlyEvaluated( args ) )
            args = execute::Evaluate( args, vm );
        if( args.isPoison() )
            return PoisonValue();

        auto val = ResolveInvocation( localC, GetOverloadSetInvocationRule(), ToValue( pOvlSet ), args );

        if( val.isConstant() || !llr::CanValueBeEagerlyEvaluated( val ) )
            return val;

        return execute::Evaluate( val, vm );
    }
}







|






|





62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
        assert( pOvlSet );

        Context localC( c.env(), c.identity(), GetValueType< uint32_t >() );
        localC.setBuilder( c.codeBuilder() );

        execute::VM vm;

        if( !args.isConstant() && cir::CanValueBeEagerlyEvaluated( args ) )
            args = execute::Evaluate( args, vm );
        if( args.isPoison() )
            return PoisonValue();

        auto val = ResolveInvocation( localC, GetOverloadSetInvocationRule(), ToValue( pOvlSet ), args );

        if( val.isConstant() || !cir::CanValueBeEagerlyEvaluated( val ) )
            return val;

        return execute::Evaluate( val, vm );
    }
}
Changes to bs/builtins/types/overloadset/overloadset.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include "builtins/builtins.h"

using namespace goose::builtins;

bool goose::builtins::IsOverloadSet( const Value& os )
{
    return os.type() == GetValueType< ptr< OverloadSet > >();
}

namespace goose::ir
{
    const Term& Bridge< ptr< builtins::OverloadSet > >::Type()
    {
        static auto type = ValueToIRExpr( Value( TypeType(), VEC( TSID( ct_type ), TSID( overloadset ) ) ) );
        return type;
    }










|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include "builtins/builtins.h"

using namespace goose::builtins;

bool goose::builtins::IsOverloadSet( const Value& os )
{
    return os.type() == GetValueType< ptr< OverloadSet > >();
}

namespace goose::eir
{
    const Term& Bridge< ptr< builtins::OverloadSet > >::Type()
    {
        static auto type = ValueToIRExpr( Value( TypeType(), VEC( TSID( ct_type ), TSID( overloadset ) ) ) );
        return type;
    }

Changes to bs/builtins/types/overloadset/overloadset.h.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
    extern ptr< InvocationRule >& GetOverloadSetInvocationRule();
    extern void SetupOverloadSetInvocationRule( Env& e );
    extern void SetupOverloadSetTypeChecking( Env& e );

    extern bool IsOverloadSet( const Value& os );
}

namespace goose::ir
{
    template<>
    struct Bridge< ptr< builtins::OverloadSet > >
    {
        static const Term& Type();
        static Value ToValue( const ptr< builtins::OverloadSet >& os );
        static optional< ptr< builtins::OverloadSet > > FromValue( const Value& v );







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
    extern ptr< InvocationRule >& GetOverloadSetInvocationRule();
    extern void SetupOverloadSetInvocationRule( Env& e );
    extern void SetupOverloadSetTypeChecking( Env& e );

    extern bool IsOverloadSet( const Value& os );
}

namespace goose::eir
{
    template<>
    struct Bridge< ptr< builtins::OverloadSet > >
    {
        static const Term& Type();
        static Value ToValue( const ptr< builtins::OverloadSet >& os );
        static optional< ptr< builtins::OverloadSet > > FromValue( const Value& v );
Changes to bs/builtins/types/overloadset/typecheck.cpp.
1
2
3
4
5
6
7
8
9
10
11
#include "builtins/builtins.h"

using namespace goose;
using namespace goose::ir;

namespace goose::builtins
{
    void SetupOverloadSetTypeChecking( Env& e )
    {
        auto funcTypePat = ValueToIRExpr( Value( TypeType(), VEC( TSID( func ),
            ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( VA ) ) ) );



|







1
2
3
4
5
6
7
8
9
10
11
#include "builtins/builtins.h"

using namespace goose;
using namespace goose::eir;

namespace goose::builtins
{
    void SetupOverloadSetTypeChecking( Env& e )
    {
        auto funcTypePat = ValueToIRExpr( Value( TypeType(), VEC( TSID( func ),
            ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( VA ) ) ) );
Changes to bs/builtins/types/reference/parse.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
#include "builtins/builtins.h"
#include "parse/parse.h"
#include "precedence.h"

using namespace goose;
using namespace goose::ir;
using namespace goose::parse;

namespace goose::builtins
{
    void SetupRefTypeParsingRule( Env& e )
    {
        auto parseRefType = []( Parser& p, uint32_t locationId, uint32_t prec )





|







1
2
3
4
5
6
7
8
9
10
11
12
13
#include "builtins/builtins.h"
#include "parse/parse.h"
#include "precedence.h"

using namespace goose;
using namespace goose::eir;
using namespace goose::parse;

namespace goose::builtins
{
    void SetupRefTypeParsingRule( Env& e )
    {
        auto parseRefType = []( Parser& p, uint32_t locationId, uint32_t prec )
Changes to bs/builtins/types/reference/reference.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
#include "builtins/builtins.h"
#include "parse/parse.h"

using namespace goose::builtins;
using namespace goose::llr;
using namespace goose::parse;

namespace goose::builtins
{
    bool IsReferenceType( const Term& t )
    {
        auto result = Decompose( ValueFromIRExpr( t )->val(),




|







1
2
3
4
5
6
7
8
9
10
11
12
#include "builtins/builtins.h"
#include "parse/parse.h"

using namespace goose::builtins;
using namespace goose::cir;
using namespace goose::parse;

namespace goose::builtins
{
    bool IsReferenceType( const Term& t )
    {
        auto result = Decompose( ValueFromIRExpr( t )->val(),
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
    {
        static auto pattern = GetValueType< Reference >( HOLE( "T"_sid ), TSID( mut ) );
        return pattern;
    }

    Reference BuildLocalVarConstRef( const LocalVar& lv )
    {
        return { ReferenceType{ lv.type(), TSID( const ) }, llr::VarBaseAddr( lv.index() ) };
    }

    Reference BuildLocalVarMutRef( const LocalVar& lv )
    {
        return { ReferenceType{ lv.type(), TSID( mut ) }, llr::VarBaseAddr( lv.index() ) };
    }
}

namespace goose::ir
{
    const Term& Bridge< ReferenceType >::Type()
    {
        return TypeType();
    }

    Value Bridge< ReferenceType >::ToValue( const ReferenceType& t )







|




|



|







36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
    {
        static auto pattern = GetValueType< Reference >( HOLE( "T"_sid ), TSID( mut ) );
        return pattern;
    }

    Reference BuildLocalVarConstRef( const LocalVar& lv )
    {
        return { ReferenceType{ lv.type(), TSID( const ) }, cir::VarBaseAddr( lv.index() ) };
    }

    Reference BuildLocalVarMutRef( const LocalVar& lv )
    {
        return { ReferenceType{ lv.type(), TSID( mut ) }, cir::VarBaseAddr( lv.index() ) };
    }
}

namespace goose::eir
{
    const Term& Bridge< ReferenceType >::Type()
    {
        return TypeType();
    }

    Value Bridge< ReferenceType >::ToValue( const ReferenceType& t )
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
    Term Bridge< builtins::Reference >::Type( const Term& type, const Term& bhv )
    {
        return ValueToIRExpr( ::ToValue( ReferenceType( type, bhv ) ) );
    }

    Value Bridge< builtins::Reference >::ToValue( const builtins::Reference& ref )
    {
        return BuildComputedValue( ValueToIRExpr( ::ToValue( ref.type() ) ), llr::CalcAddress{ ref.address() } );
    }

    optional< builtins::Reference > Bridge< builtins::Reference >::FromValue( const Value& v )
    {
        if( v.isConstant() )
            return nullopt;

        auto llrRef = get_if< llr::CalcAddress >( &v.llr()->content() );
        if( !llrRef )
            return nullopt;

        auto t = FromValue< ReferenceType >( *ValueFromIRExpr( v.type() ) );
        if( !t )
            return nullopt;

        return builtins::Reference( move( *t ), get< llr::CalcAddress >( v.llr()->content() ) );
    }
}







|







|
|






|


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
    Term Bridge< builtins::Reference >::Type( const Term& type, const Term& bhv )
    {
        return ValueToIRExpr( ::ToValue( ReferenceType( type, bhv ) ) );
    }

    Value Bridge< builtins::Reference >::ToValue( const builtins::Reference& ref )
    {
        return BuildComputedValue( ValueToIRExpr( ::ToValue( ref.type() ) ), cir::CalcAddress{ ref.address() } );
    }

    optional< builtins::Reference > Bridge< builtins::Reference >::FromValue( const Value& v )
    {
        if( v.isConstant() )
            return nullopt;

        auto cirRef = get_if< cir::CalcAddress >( &v.cir()->content() );
        if( !cirRef )
            return nullopt;

        auto t = FromValue< ReferenceType >( *ValueFromIRExpr( v.type() ) );
        if( !t )
            return nullopt;

        return builtins::Reference( move( *t ), get< cir::CalcAddress >( v.cir()->content() ) );
    }
}
Changes to bs/builtins/types/reference/reference.h.
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
                    static auto pattern = GetValueType< Reference >( PP::GetPattern(), TSID( const ) );
                    return pattern;
                }
            };

        private:
            ReferenceType m_type;
            llr::CalcAddress m_addr;
    };

    extern Reference BuildLocalVarConstRef( const LocalVar& lv );
    extern Reference BuildLocalVarMutRef( const LocalVar& lv );
}

namespace goose::ir
{
    template<>
    struct Bridge< builtins::ReferenceType >
    {
        static const Term& Type();
        static Value ToValue( const builtins::ReferenceType& t );
        static optional< builtins::ReferenceType > FromValue( const Value& v );







|






|







99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
                    static auto pattern = GetValueType< Reference >( PP::GetPattern(), TSID( const ) );
                    return pattern;
                }
            };

        private:
            ReferenceType m_type;
            cir::CalcAddress m_addr;
    };

    extern Reference BuildLocalVarConstRef( const LocalVar& lv );
    extern Reference BuildLocalVarMutRef( const LocalVar& lv );
}

namespace goose::eir
{
    template<>
    struct Bridge< builtins::ReferenceType >
    {
        static const Term& Type();
        static Value ToValue( const builtins::ReferenceType& t );
        static optional< builtins::ReferenceType > FromValue( const Value& v );
Changes to bs/builtins/types/reference/typecheck.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
#include "builtins/builtins.h"

using namespace goose;
using namespace goose::ir;
using namespace goose::llr;

namespace goose::builtins
{
    void SetupReferenceTypeChecking( Env& e )
    {
        auto localVarPattern = GetValueType< LocalVar >( ANYTERM( _ ) );




|
|







1
2
3
4
5
6
7
8
9
10
11
12
#include "builtins/builtins.h"

using namespace goose;
using namespace goose::eir;
using namespace goose::cir;

namespace goose::builtins
{
    void SetupReferenceTypeChecking( Env& e )
    {
        auto localVarPattern = GetValueType< LocalVar >( ANYTERM( _ ) );

100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
            {
                auto refval = *ValueFromIRExpr( rhs );
                auto ref = FromValue< Reference >( refval );
                if( !ref )
                    co_return;

                auto content = ValueToIRExpr( BuildComputedValue( ref->type().type(),
                    llr::Load( refval, ref->type().type() ) )
                    .setLocationId( refval.locationId() ) );

                // TypeCheck the param with the ref's content
                co_yield TypeCheck( lhs, content, tcc );
            } );

        // LocalVar type checking against a param (implicit referencing):







|







100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
            {
                auto refval = *ValueFromIRExpr( rhs );
                auto ref = FromValue< Reference >( refval );
                if( !ref )
                    co_return;

                auto content = ValueToIRExpr( BuildComputedValue( ref->type().type(),
                    cir::Load( refval, ref->type().type() ) )
                    .setLocationId( refval.locationId() ) );

                // TypeCheck the param with the ref's content
                co_yield TypeCheck( lhs, content, tcc );
            } );

        // LocalVar type checking against a param (implicit referencing):
Changes to bs/builtins/types/runtime/array.cpp.
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

    llvm::Type* GetLLVMType( const ArrayType& a )
    {
        return llvm::ArrayType::get( GetLLVMType( *ValueFromIRExpr( a.m_containedType ) ), a.m_count );
    }
}

namespace goose::ir
{
    Value Bridge< ArrayType >::ToValue( const ArrayType& a )
    {
        return Value( Type(), MkStdRTType( TSID( array ),
            GetLLVMType( a ),
            TERM( a.m_count ), a.m_containedType ) );
    }







|







23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

    llvm::Type* GetLLVMType( const ArrayType& a )
    {
        return llvm::ArrayType::get( GetLLVMType( *ValueFromIRExpr( a.m_containedType ) ), a.m_count );
    }
}

namespace goose::eir
{
    Value Bridge< ArrayType >::ToValue( const ArrayType& a )
    {
        return Value( Type(), MkStdRTType( TSID( array ),
            GetLLVMType( a ),
            TERM( a.m_count ), a.m_containedType ) );
    }
Changes to bs/builtins/types/runtime/array.h.
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
        Term m_containedType;
        uint32_t m_count = 1;
    };

    extern llvm::Type* GetLLVMType( const ArrayType& a );
}

namespace goose::ir
{
    template<>
    struct Bridge< builtins::ArrayType >
    {
        static const Term& Type() { return TypeType(); }
        static Value ToValue( const builtins::ArrayType& a );
        static optional< builtins::ArrayType > FromValue( const Value& v );







|







16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
        Term m_containedType;
        uint32_t m_count = 1;
    };

    extern llvm::Type* GetLLVMType( const ArrayType& a );
}

namespace goose::eir
{
    template<>
    struct Bridge< builtins::ArrayType >
    {
        static const Term& Type() { return TypeType(); }
        static Value ToValue( const builtins::ArrayType& a );
        static optional< builtins::ArrayType > FromValue( const Value& v );
Changes to bs/builtins/types/runtime/basic.cpp.
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94

    llvm::Type* GetLLVMType( const IntegerType& t )
    {
        return llvm::IntegerType::get( GetLLVMContext(), t.m_numBits );
    }
}

namespace goose::ir
{
    //// Half
    Value Bridge< HalfFloatType >::ToValue( const HalfFloatType& t )
    {
        return Value( Type(), MkStdRTType( TSID( half ), GetLLVMType( t ) ) );
    }








|







80
81
82
83
84
85
86
87
88
89
90
91
92
93
94

    llvm::Type* GetLLVMType( const IntegerType& t )
    {
        return llvm::IntegerType::get( GetLLVMContext(), t.m_numBits );
    }
}

namespace goose::eir
{
    //// Half
    Value Bridge< HalfFloatType >::ToValue( const HalfFloatType& t )
    {
        return Value( Type(), MkStdRTType( TSID( half ), GetLLVMType( t ) ) );
    }

155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
        auto&& [predicates, llvmType, params] = *result;
        auto&& [numBits, signd] = params;
        return IntegerType( numBits, !!signd );
    }

    Term Bridge< APSInt >::Type( const APSInt& i )
    {
        return ValueToIRExpr( ir::ToValue(
            IntegerType( i.getBitWidth(), i.isSigned() ) ) );
    }

    Value Bridge< APSInt >::ToValue( const APSInt& i )
    {
        return Value( Type( i ), TERM( i ) );
    }







|







155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
        auto&& [predicates, llvmType, params] = *result;
        auto&& [numBits, signd] = params;
        return IntegerType( numBits, !!signd );
    }

    Term Bridge< APSInt >::Type( const APSInt& i )
    {
        return ValueToIRExpr( eir::ToValue(
            IntegerType( i.getBitWidth(), i.isSigned() ) ) );
    }

    Value Bridge< APSInt >::ToValue( const APSInt& i )
    {
        return Value( Type( i ), TERM( i ) );
    }
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
211
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

        return *result;
    }


    const Term& Bridge< uint8_t >::Type()
    {
        static auto type = ValueToIRExpr( ir::ToValue(
            IntegerType( 8, false ) ) );
        return type;
    }

    Value Bridge< uint8_t >::ToValue( uint8_t x )
    {
        return ir::ToValue( APSInt::getUnsigned( x ).trunc( 8 ) );
    }

    optional< uint8_t > Bridge< uint8_t >::FromValue( const Value& v )
    {
        return FromValue< APSInt >( v )->getLimitedValue();
    }


    const Term& Bridge< uint32_t >::Type()
    {
        static auto type = ValueToIRExpr( ir::ToValue(
            IntegerType( 32, false ) ) );
        return type;
    }

    Value Bridge< uint32_t >::ToValue( uint32_t x )
    {
        return ir::ToValue( APSInt::getUnsigned( x ).trunc( 32 ) );
    }

    optional< uint32_t > Bridge< uint32_t >::FromValue( const Value& v )
    {
        return FromValue< APSInt >( v )->getLimitedValue();
    }


    const Term& Bridge< uint64_t >::Type()
    {
        static auto type = ValueToIRExpr( ir::ToValue(
            IntegerType( 64, false ) ) );
        return type;
    }

    Value Bridge< uint64_t >::ToValue( uint64_t x )
    {
        return ir::ToValue( APSInt::getUnsigned( x ) );
    }

    optional< uint64_t > Bridge< uint64_t >::FromValue( const Value& v )
    {
        if( !v.isConstant() )
            return nullopt;
        return FromValue< APSInt >( v )->getLimitedValue();
    }
}







|






|










|






|










|






|









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

        return *result;
    }


    const Term& Bridge< uint8_t >::Type()
    {
        static auto type = ValueToIRExpr( eir::ToValue(
            IntegerType( 8, false ) ) );
        return type;
    }

    Value Bridge< uint8_t >::ToValue( uint8_t x )
    {
        return eir::ToValue( APSInt::getUnsigned( x ).trunc( 8 ) );
    }

    optional< uint8_t > Bridge< uint8_t >::FromValue( const Value& v )
    {
        return FromValue< APSInt >( v )->getLimitedValue();
    }


    const Term& Bridge< uint32_t >::Type()
    {
        static auto type = ValueToIRExpr( eir::ToValue(
            IntegerType( 32, false ) ) );
        return type;
    }

    Value Bridge< uint32_t >::ToValue( uint32_t x )
    {
        return eir::ToValue( APSInt::getUnsigned( x ).trunc( 32 ) );
    }

    optional< uint32_t > Bridge< uint32_t >::FromValue( const Value& v )
    {
        return FromValue< APSInt >( v )->getLimitedValue();
    }


    const Term& Bridge< uint64_t >::Type()
    {
        static auto type = ValueToIRExpr( eir::ToValue(
            IntegerType( 64, false ) ) );
        return type;
    }

    Value Bridge< uint64_t >::ToValue( uint64_t x )
    {
        return eir::ToValue( APSInt::getUnsigned( x ) );
    }

    optional< uint64_t > Bridge< uint64_t >::FromValue( const Value& v )
    {
        if( !v.isConstant() )
            return nullopt;
        return FromValue< APSInt >( v )->getLimitedValue();
    }
}
Changes to bs/builtins/types/runtime/basic.h.
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58

    extern llvm::Type* GetLLVMType( const HalfFloatType& t );
    extern llvm::Type* GetLLVMType( const FloatType& t );
    extern llvm::Type* GetLLVMType( const DoubleFloatType& t );
    extern llvm::Type* GetLLVMType( const IntegerType& t );
}

namespace goose::ir
{
    template<>
    struct Bridge< builtins::HalfFloatType >
    {
        static const Term& Type() { return TypeType(); }
        static Value ToValue( const builtins::HalfFloatType& i );
        static optional< builtins::HalfFloatType > FromValue( const Value& v );







|







44
45
46
47
48
49
50
51
52
53
54
55
56
57
58

    extern llvm::Type* GetLLVMType( const HalfFloatType& t );
    extern llvm::Type* GetLLVMType( const FloatType& t );
    extern llvm::Type* GetLLVMType( const DoubleFloatType& t );
    extern llvm::Type* GetLLVMType( const IntegerType& t );
}

namespace goose::eir
{
    template<>
    struct Bridge< builtins::HalfFloatType >
    {
        static const Term& Type() { return TypeType(); }
        static Value ToValue( const builtins::HalfFloatType& i );
        static optional< builtins::HalfFloatType > FromValue( const Value& v );
Changes to bs/builtins/types/runtime/init.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
#include "builtins/builtins.h"
#include "parse/parse.h"

using namespace goose::parse;
using namespace goose::llr;

namespace goose::builtins
{
    void SetupRuntimeBasicTypesInitialize( Env& e )
    {
        using IntegerMutRefType =
            CustomPattern< Reference, Reference::PatternMutable< IntegerType::Pattern > >;




|







1
2
3
4
5
6
7
8
9
10
11
12
#include "builtins/builtins.h"
#include "parse/parse.h"

using namespace goose::parse;
using namespace goose::cir;

namespace goose::builtins
{
    void SetupRuntimeBasicTypesInitialize( Env& e )
    {
        using IntegerMutRefType =
            CustomPattern< Reference, Reference::PatternMutable< IntegerType::Pattern > >;
Changes to bs/builtins/types/runtime/pointer.cpp.
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

    llvm::Type* GetLLVMType( const PointerType& p )
    {
        return llvm::PointerType::getUnqual( GetLLVMType( *ValueFromIRExpr( p.m_pointedType ) ) );
    }
}

namespace goose::ir
{
    Value Bridge< PointerType >::ToValue( const PointerType& p )
    {
        return Value( Type(), MkStdRTType( TSID( pointer ),
            GetLLVMType( p ),
            p.m_pointedType ) );
    }







|







28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

    llvm::Type* GetLLVMType( const PointerType& p )
    {
        return llvm::PointerType::getUnqual( GetLLVMType( *ValueFromIRExpr( p.m_pointedType ) ) );
    }
}

namespace goose::eir
{
    Value Bridge< PointerType >::ToValue( const PointerType& p )
    {
        return Value( Type(), MkStdRTType( TSID( pointer ),
            GetLLVMType( p ),
            p.m_pointedType ) );
    }
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
            return nullopt;

        return NullPointerType();
    }

    const Term& Bridge< NullPointer >::Type()
    {
        static auto type = ValueToIRExpr( ir::ToValue( NullPointerType() ) );
        return type;
    }

    const Value& Bridge< NullPointer >::ToValue( const NullPointer& np )
    {
        static auto val = Value( Type(), TSID( nullptr ) );
        return val;







|







75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
            return nullopt;

        return NullPointerType();
    }

    const Term& Bridge< NullPointer >::Type()
    {
        static auto type = ValueToIRExpr( eir::ToValue( NullPointerType() ) );
        return type;
    }

    const Value& Bridge< NullPointer >::ToValue( const NullPointer& np )
    {
        static auto val = Value( Type(), TSID( nullptr ) );
        return val;
Changes to bs/builtins/types/runtime/pointer.h.
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

    struct NullPointer
    {};

    extern llvm::Type* GetLLVMType( const PointerType& p );
}

namespace goose::ir
{
    template<>
    struct Bridge< builtins::PointerType >
    {
        static const Term& Type() { return TypeType(); }
        static Value ToValue( const builtins::PointerType& p );
        static optional< builtins::PointerType > FromValue( const Value& v );







|







20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

    struct NullPointer
    {};

    extern llvm::Type* GetLLVMType( const PointerType& p );
}

namespace goose::eir
{
    template<>
    struct Bridge< builtins::PointerType >
    {
        static const Term& Type() { return TypeType(); }
        static Value ToValue( const builtins::PointerType& p );
        static optional< builtins::PointerType > FromValue( const Value& v );
Changes to bs/builtins/types/runtime/record.cpp.
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
            elements.emplace_back( llvmType );
        }

        return llvm::StructType::get( GetLLVMContext(), elements, rt.m_packed );
    }
}

namespace goose::ir
{
    Value Bridge< RecordType >::ToValue( const RecordType& rt )
    {
        return Value( Type(), MkStdRTType( TSID( record ), GetLLVMType( rt ),
            TERM( rt.m_packed ? 1U : 0U ),
            TERM( rt.m_memberTypes ) ) );
    }







|







53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
            elements.emplace_back( llvmType );
        }

        return llvm::StructType::get( GetLLVMContext(), elements, rt.m_packed );
    }
}

namespace goose::eir
{
    Value Bridge< RecordType >::ToValue( const RecordType& rt )
    {
        return Value( Type(), MkStdRTType( TSID( record ), GetLLVMType( rt ),
            TERM( rt.m_packed ? 1U : 0U ),
            TERM( rt.m_memberTypes ) ) );
    }
Changes to bs/builtins/types/runtime/record.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#ifndef GOOSE_BUILTINS_TYPES_RUNTIME_RECORD_H
#define GOOSE_BUILTINS_TYPES_RUNTIME_RECORD_H

namespace goose::builtins
{
    extern void SetupRuntimeRecordType( Env& e );

    struct RecordType
    {
        RecordType( bool packed = false ) :
            m_memberTypes( make_shared< ir::Vector >() ),
            m_packed( packed )
        {}

        template< typename M >
        RecordType( M&& memberTypes, bool packed = false ) :
            m_memberTypes( forward< M >( memberTypes ) ),
            m_packed( packed )










|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#ifndef GOOSE_BUILTINS_TYPES_RUNTIME_RECORD_H
#define GOOSE_BUILTINS_TYPES_RUNTIME_RECORD_H

namespace goose::builtins
{
    extern void SetupRuntimeRecordType( Env& e );

    struct RecordType
    {
        RecordType( bool packed = false ) :
            m_memberTypes( make_shared< eir::Vector >() ),
            m_packed( packed )
        {}

        template< typename M >
        RecordType( M&& memberTypes, bool packed = false ) :
            m_memberTypes( forward< M >( memberTypes ) ),
            m_packed( packed )
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
        auto rt = ValueToIRExpr( ToValue( RecordType( forward< T >( types ), packed ) ) );
        return Value( move( rt ), forward< V >( vals ) );
    }

    extern llvm::Type* GetLLVMType( const RecordType& rt );
}

namespace goose::ir
{
    template<>
    struct Bridge< builtins::RecordType >
    {
        static const Term& Type() { return TypeType(); }
        static Value ToValue( const builtins::RecordType& rt );
        static optional< builtins::RecordType > FromValue( const Value& v );
    };
}

#endif







|











28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
        auto rt = ValueToIRExpr( ToValue( RecordType( forward< T >( types ), packed ) ) );
        return Value( move( rt ), forward< V >( vals ) );
    }

    extern llvm::Type* GetLLVMType( const RecordType& rt );
}

namespace goose::eir
{
    template<>
    struct Bridge< builtins::RecordType >
    {
        static const Term& Type() { return TypeType(); }
        static Value ToValue( const builtins::RecordType& rt );
        static optional< builtins::RecordType > FromValue( const Value& v );
    };
}

#endif
Changes to bs/builtins/types/runtime/typecheck.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
#include "builtins/builtins.h"
#include "builtins/helpers.h"

using namespace goose;
using namespace goose::ir;

namespace goose::builtins
{
    void SetupRuntimeTypesUnification( Env& e )
    {
        auto rtIntTypePattern = Value( TypeType(), MkStdType( TSID( integer ),
            VEC( ANYTERM( _ ), ANYTERM( _ ) ) ) );




|







1
2
3
4
5
6
7
8
9
10
11
12
#include "builtins/builtins.h"
#include "builtins/helpers.h"

using namespace goose;
using namespace goose::eir;

namespace goose::builtins
{
    void SetupRuntimeTypesUnification( Env& e )
    {
        auto rtIntTypePattern = Value( TypeType(), MkStdType( TSID( integer ),
            VEC( ANYTERM( _ ), ANYTERM( _ ) ) ) );
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
        []( const Term& lhs, const Term& rhs, const TypeCheckingContext& c ) -> TCGen
        {
            co_return;
        } );

        // ct_integer constant type checking against a IntegerType:
        // Check if the IntegerType is big enough for the constant,
        // and emit a LoadConstantInt llr instruction if so.
        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            ValueToIRExpr( ValuePattern(
                ANYTERM( _ ),
                ValueToIRExpr( rtIntTypePattern ),
                ANYTERM( _ ) ) ),








|







38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
        []( const Term& lhs, const Term& rhs, const TypeCheckingContext& c ) -> TCGen
        {
            co_return;
        } );

        // ct_integer constant type checking against a IntegerType:
        // Check if the IntegerType is big enough for the constant,
        // and emit a LoadConstantInt cir instruction if so.
        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            ValueToIRExpr( ValuePattern(
                ANYTERM( _ ),
                ValueToIRExpr( rtIntTypePattern ),
                ANYTERM( _ ) ) ),

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
            GetValueType< string >(),
        []( const Term& lhs, const Term& rhs, const TypeCheckingContext& c ) -> TCGen
        {
            co_yield HalfUnify( lhs, c );
        } );

        // ct_string constant type checking against a pointer to a integer( 8 ):
        // Emit a LoadConstantStr llr instruction.
        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            ValueToIRExpr( ValuePattern(
                ANYTERM( _ ),
                ValueToIRExpr( rtInt8PtrTypePattern ),
                ANYTERM( _ ) ) ),

            ValueToIRExpr( ValuePattern(
                ANYTERM( _ ),
                GetValueType< string >(),
                ANYTERM( _ ) ) ),

        []( const Term& lhs, const Term& rhs, const TypeCheckingContext& c ) -> TCGen
        {
            auto str = *FromValue< string >( *ValueFromIRExpr( rhs ) );
            auto lhsVal = *ValuePatternFromIRExpr( lhs );

            co_yield { ValueToIRExpr(
                BuildComputedValue( lhsVal.type(), llr::LoadConstStr( str ) ) ), c };
        } );

        auto ptrTypePattern = Value( TypeType(), MkStdType( TSID( pointer ),
            ANYTERM( _ ) ) );

        // nullptr constant type checking against a pointer of any type;
        // Yield a value of the given pointer type, with a 0 integer as its content.







|


















|







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
            GetValueType< string >(),
        []( const Term& lhs, const Term& rhs, const TypeCheckingContext& c ) -> TCGen
        {
            co_yield HalfUnify( lhs, c );
        } );

        // ct_string constant type checking against a pointer to a integer( 8 ):
        // Emit a LoadConstantStr cir instruction.
        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            ValueToIRExpr( ValuePattern(
                ANYTERM( _ ),
                ValueToIRExpr( rtInt8PtrTypePattern ),
                ANYTERM( _ ) ) ),

            ValueToIRExpr( ValuePattern(
                ANYTERM( _ ),
                GetValueType< string >(),
                ANYTERM( _ ) ) ),

        []( const Term& lhs, const Term& rhs, const TypeCheckingContext& c ) -> TCGen
        {
            auto str = *FromValue< string >( *ValueFromIRExpr( rhs ) );
            auto lhsVal = *ValuePatternFromIRExpr( lhs );

            co_yield { ValueToIRExpr(
                BuildComputedValue( lhsVal.type(), cir::LoadConstStr( str ) ) ), c };
        } );

        auto ptrTypePattern = Value( TypeType(), MkStdType( TSID( pointer ),
            ANYTERM( _ ) ) );

        // nullptr constant type checking against a pointer of any type;
        // Yield a value of the given pointer type, with a 0 integer as its content.
Changes to bs/builtins/types/template/tdecl.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include "builtins/builtins.h"

using namespace goose::builtins;

namespace goose::builtins
{
    bool IsTDecl( const Value& td )
    {
        return td.type() == GetValueType< TDecl >();
    }
}

namespace goose::ir
{
    const Term& Bridge< TDecl >::Type()
    {
        static auto type = ValueToIRExpr( Value( TypeType(), TSID( tdecl ) ) );
        return type;
    }













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include "builtins/builtins.h"

using namespace goose::builtins;

namespace goose::builtins
{
    bool IsTDecl( const Value& td )
    {
        return td.type() == GetValueType< TDecl >();
    }
}

namespace goose::eir
{
    const Term& Bridge< TDecl >::Type()
    {
        static auto type = ValueToIRExpr( Value( TypeType(), TSID( tdecl ) ) );
        return type;
    }

Changes to bs/builtins/types/template/tdecl.h.
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
            Term m_type;
            StringId m_name;
    };

    extern bool IsTDecl( const Value& td );
}

namespace goose::ir
{
    template<>
    struct Bridge< builtins::TDecl >
    {
        static const Term& Type();
        static Value ToValue( const builtins::TDecl& td );
        static optional< builtins::TDecl > FromValue( const Value& v );







|







23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
            Term m_type;
            StringId m_name;
    };

    extern bool IsTDecl( const Value& td );
}

namespace goose::eir
{
    template<>
    struct Bridge< builtins::TDecl >
    {
        static const Term& Type();
        static Value ToValue( const builtins::TDecl& td );
        static optional< builtins::TDecl > FromValue( const Value& v );
Changes to bs/builtins/types/template/tfunc.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include "builtins/builtins.h"
#include "lex/lex.h"
#include "parse/parse.h"

using namespace goose::builtins;
using namespace goose::parse;

namespace goose::ir
{
    Term Bridge< TFunc >::Type( const builtins::TFunc& tf )
    {
        return ValueToIRExpr( ::ToValue( tf.type() ) );
    }

    Value Bridge< TFunc >::ToValue( const TFunc& tf )







|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include "builtins/builtins.h"
#include "lex/lex.h"
#include "parse/parse.h"

using namespace goose::builtins;
using namespace goose::parse;

namespace goose::eir
{
    Term Bridge< TFunc >::Type( const builtins::TFunc& tf )
    {
        return ValueToIRExpr( ::ToValue( tf.type() ) );
    }

    Value Bridge< TFunc >::ToValue( const TFunc& tf )
Changes to bs/builtins/types/template/tfunc.h.
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
            Term        m_identity;
            ptr< void > m_toks;
    };

    extern Value InstantiateTFunc( const Context& c, const Value& callee, const Term& unifiedCallPat, const TypeCheckingContext& tcc );
}

namespace goose::ir
{
    template<>
    struct Bridge< builtins::TFunc >
    {
        static Term Type( const builtins::TFunc& tf );
        static Value ToValue( const builtins::TFunc& tf );
        static optional< builtins::TFunc > FromValue( const Value& v );







|







29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
            Term        m_identity;
            ptr< void > m_toks;
    };

    extern Value InstantiateTFunc( const Context& c, const Value& callee, const Term& unifiedCallPat, const TypeCheckingContext& tcc );
}

namespace goose::eir
{
    template<>
    struct Bridge< builtins::TFunc >
    {
        static Term Type( const builtins::TFunc& tf );
        static Value ToValue( const builtins::TFunc& tf );
        static optional< builtins::TFunc > FromValue( const Value& v );
Changes to bs/builtins/types/template/tfunctype.cpp.
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

    bool IsTFunc( const Value& t )
    {
        return IsTFuncType( *ValueFromIRExpr( t.type() ) );
    }
}

namespace goose::ir
{
    const Term& Bridge< TFuncType >::Type()
    {
        return TypeType();
    }

    Value Bridge< TFuncType >::ToValue( const TFuncType& tft )







|







25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

    bool IsTFunc( const Value& t )
    {
        return IsTFuncType( *ValueFromIRExpr( t.type() ) );
    }
}

namespace goose::eir
{
    const Term& Bridge< TFuncType >::Type()
    {
        return TypeType();
    }

    Value Bridge< TFuncType >::ToValue( const TFuncType& tft )
Changes to bs/builtins/types/template/tfunctype.h.
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
            ptr< vector< TermLoc > > m_postCondToks = make_shared< vector< TermLoc > >();
    };

    extern bool IsTFuncType( const Value& t );
    extern bool IsTFunc( const Value& t );
}

namespace goose::ir
{
    template<>
    struct Bridge< builtins::TFuncType >
    {
        static const Term& Type();
        static Value ToValue( const builtins::TFuncType& tft );
        static optional< builtins::TFuncType > FromValue( const Value& v );







|







39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
            ptr< vector< TermLoc > > m_postCondToks = make_shared< vector< TermLoc > >();
    };

    extern bool IsTFuncType( const Value& t );
    extern bool IsTFunc( const Value& t );
}

namespace goose::eir
{
    template<>
    struct Bridge< builtins::TFuncType >
    {
        static const Term& Type();
        static Value ToValue( const builtins::TFuncType& tft );
        static optional< builtins::TFuncType > FromValue( const Value& v );
Changes to bs/builtins/types/template/tnameddecl.cpp.
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
    const Term& TNamedDecl::Pattern::GetPattern()
    {
        static auto pattern = GetValueType< TNamedDecl >();
        return pattern;
    }
}

namespace goose::ir
{
    const Term& Bridge< TNamedDecl >::Type()
    {
        static auto type = ValueToIRExpr( Value( TypeType(), TSID( tnameddecl ) ) );
        return type;
    }








|







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
    const Term& TNamedDecl::Pattern::GetPattern()
    {
        static auto pattern = GetValueType< TNamedDecl >();
        return pattern;
    }
}

namespace goose::eir
{
    const Term& Bridge< TNamedDecl >::Type()
    {
        static auto type = ValueToIRExpr( Value( TypeType(), TSID( tnameddecl ) ) );
        return type;
    }

Changes to bs/builtins/types/template/tnameddecl.h.
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
            Term m_type;
            StringId m_name;
    };

    extern bool IsTNamedDecl( const Value& td );
}

namespace goose::ir
{
    template<>
    struct Bridge< builtins::TNamedDecl >
    {
        static const Term& Type();
        static Value ToValue( const builtins::TNamedDecl& td );
        static optional< builtins::TNamedDecl > FromValue( const Value& v );







|







24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
            Term m_type;
            StringId m_name;
    };

    extern bool IsTNamedDecl( const Value& td );
}

namespace goose::eir
{
    template<>
    struct Bridge< builtins::TNamedDecl >
    {
        static const Term& Type();
        static Value ToValue( const builtins::TNamedDecl& td );
        static optional< builtins::TNamedDecl > FromValue( const Value& v );
Changes to bs/builtins/types/template/tvar.cpp.
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

    bool IsTVar( const Value& tv )
    {
        return tv.type() == GetValueType< TVar >();
    }
}

namespace goose::ir
{
    const Term& Bridge< TVar >::Type()
    {
        static auto type = ValueToIRExpr( Value( TypeType(), VEC( TSID( texpr ), TSID( tvar ) ) ) );
        return type;
    }








|







37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

    bool IsTVar( const Value& tv )
    {
        return tv.type() == GetValueType< TVar >();
    }
}

namespace goose::eir
{
    const Term& Bridge< TVar >::Type()
    {
        static auto type = ValueToIRExpr( Value( TypeType(), VEC( TSID( texpr ), TSID( tvar ) ) ) );
        return type;
    }

Changes to bs/builtins/types/template/tvar.h.
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
    };

    extern bool IsTExpr( const optional< Value >& te );
    extern bool IsTExpr( const Value& te );
    extern bool IsTVar( const Value& tv );
}

namespace goose::ir
{
    template<>
    struct Bridge< builtins::TVar >
    {
        static const Term& Type();
        static Value ToValue( builtins::TVar&& tv );
        static optional< builtins::TVar > FromValue( const Value& v );







|







17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
    };

    extern bool IsTExpr( const optional< Value >& te );
    extern bool IsTExpr( const Value& te );
    extern bool IsTVar( const Value& tv );
}

namespace goose::eir
{
    template<>
    struct Bridge< builtins::TVar >
    {
        static const Term& Type();
        static Value ToValue( builtins::TVar&& tv );
        static optional< builtins::TVar > FromValue( const Value& v );
Changes to bs/builtins/types/template/tvec.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
#include "builtins/builtins.h"

using namespace goose::builtins;

namespace goose::ir
{
    const Term& Bridge< TVec >::Type()
    {
        static auto type = ValueToIRExpr( Value( TypeType(), VEC( TSID( texpr ), TSID( tvec ) ) ) );
        return type;
    }





|







1
2
3
4
5
6
7
8
9
10
11
12
#include "builtins/builtins.h"

using namespace goose::builtins;

namespace goose::eir
{
    const Term& Bridge< TVec >::Type()
    {
        static auto type = ValueToIRExpr( Value( TypeType(), VEC( TSID( texpr ), TSID( tvec ) ) ) );
        return type;
    }

Changes to bs/builtins/types/template/tvec.h.
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
        private:
            pvec m_content;
    };

    // Construct either a normal Vector term or a TVec.
    // If any of the provided term is a TExpr, construct a TVec.
    //
    // This is used to construct ir expressions for parametric types,
    // so that they are automatically turned into a suitable TExpr if
    // TExprs are passed as parameters.
    template< typename... T >
    extern Term BuildVecOrTVec( T&&... terms )
    {
        auto vec = Vector::Make( terms... );

        if( ( IsTExpr( ValueFromIRExpr( terms ) ) || ... ) )
            return ValueToIRExpr( ToValue( TVec( move( vec ) ) ) );

        return vec;
    }

    #define TVEC( ... ) BuildVecOrTVec( __VA_ARGS__ )
}

namespace goose::ir
{
    template<>
    struct Bridge< builtins::TVec >
    {
        static const Term& Type();
        static Value ToValue( const builtins::TVec& tv );
        static optional< builtins::TVec > FromValue( const Value& v );
    };
}

#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
42
43
44
45
46
47
48
49
50
51
        private:
            pvec m_content;
    };

    // Construct either a normal Vector term or a TVec.
    // If any of the provided term is a TExpr, construct a TVec.
    //
    // This is used to construct eir expressions for parametric types,
    // so that they are automatically turned into a suitable TExpr if
    // TExprs are passed as parameters.
    template< typename... T >
    extern Term BuildVecOrTVec( T&&... terms )
    {
        auto vec = Vector::Make( terms... );

        if( ( IsTExpr( ValueFromIRExpr( terms ) ) || ... ) )
            return ValueToIRExpr( ToValue( TVec( move( vec ) ) ) );

        return vec;
    }

    #define TVEC( ... ) BuildVecOrTVec( __VA_ARGS__ )
}

namespace goose::eir
{
    template<>
    struct Bridge< builtins::TVec >
    {
        static const Term& Type();
        static Value ToValue( const builtins::TVec& tv );
        static optional< builtins::TVec > FromValue( const Value& v );
    };
}

#endif
Changes to bs/builtins/types/template/typecheck.cpp.
1
2
3
4
5
6
7
8
9
10
11
#include "builtins/builtins.h"

using namespace goose;
using namespace goose::ir;

namespace goose::builtins
{
    void SetupTemplateFunctionTypeChecking( Env& e )
    {
        auto funcTypePat = ValueToIRExpr( Value( TypeType(), VEC( TSID( func ),
            ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( VA ) ) ) );



|







1
2
3
4
5
6
7
8
9
10
11
#include "builtins/builtins.h"

using namespace goose;
using namespace goose::eir;

namespace goose::builtins
{
    void SetupTemplateFunctionTypeChecking( Env& e )
    {
        auto funcTypePat = ValueToIRExpr( Value( TypeType(), VEC( TSID( func ),
            ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( VA ) ) ) );
Changes to bs/builtins/types/tuple/destroy.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
#include "builtins/builtins.h"
#include "parse/parse.h"

using namespace goose::parse;
using namespace goose::llr;

namespace goose::builtins
{
    void SetupTupleDestroyValue( Env& e )
    {
        // DestroyValue() for tuples: destroy every member value.
        RegisterBuiltinFunc< Intrinsic< void ( CustomPattern< Value, TuplePattern > ) > >( e, e.extDestroyValue(),




|







1
2
3
4
5
6
7
8
9
10
11
12
#include "builtins/builtins.h"
#include "parse/parse.h"

using namespace goose::parse;
using namespace goose::cir;

namespace goose::builtins
{
    void SetupTupleDestroyValue( Env& e )
    {
        // DestroyValue() for tuples: destroy every member value.
        RegisterBuiltinFunc< Intrinsic< void ( CustomPattern< Value, TuplePattern > ) > >( e, e.extDestroyValue(),
Changes to bs/builtins/types/tuple/drop.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
#include "builtins/builtins.h"
#include "parse/parse.h"

using namespace goose::parse;
using namespace goose::llr;

namespace goose::builtins
{
    void SetupTupleDropValue( Env& e )
    {
        // DropValue() for tuples: drop every member value.
        RegisterBuiltinFunc< Intrinsic< void ( CustomPattern< Value, TuplePattern > ) > >( e, e.extDropValue(),




|







1
2
3
4
5
6
7
8
9
10
11
12
#include "builtins/builtins.h"
#include "parse/parse.h"

using namespace goose::parse;
using namespace goose::cir;

namespace goose::builtins
{
    void SetupTupleDropValue( Env& e )
    {
        // DropValue() for tuples: drop every member value.
        RegisterBuiltinFunc< Intrinsic< void ( CustomPattern< Value, TuplePattern > ) > >( e, e.extDropValue(),
Changes to bs/builtins/types/tuple/init.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
#include "builtins/builtins.h"
#include "parse/parse.h"

using namespace goose::parse;
using namespace goose::llr;

namespace goose::builtins
{
    void InitTuple( const Context& c, const Value& tupRef, const Value& initTup )
    {
        auto lref = *FromValue< Reference >( tupRef );





|







1
2
3
4
5
6
7
8
9
10
11
12
#include "builtins/builtins.h"
#include "parse/parse.h"

using namespace goose::parse;
using namespace goose::cir;

namespace goose::builtins
{
    void InitTuple( const Context& c, const Value& tupRef, const Value& initTup )
    {
        auto lref = *FromValue< Reference >( tupRef );

Changes to bs/builtins/types/tuple/lower.cpp.
1
2
3
4
5
6
7
8
9
10
11
#include "builtins/builtins.h"

using namespace goose;
using namespace goose::ir;
using namespace goose::builtins;

namespace goose::builtins
{
    void SetupTupleLowering( Env& e )
    {
        RegisterBuiltinFunc< Intrinsic< Value ( TypePatternParam< TuplePattern > ) > >( e, e.extLowerTypeForRuntime(),



|







1
2
3
4
5
6
7
8
9
10
11
#include "builtins/builtins.h"

using namespace goose;
using namespace goose::eir;
using namespace goose::builtins;

namespace goose::builtins
{
    void SetupTupleLowering( Env& e )
    {
        RegisterBuiltinFunc< Intrinsic< Value ( TypePatternParam< TuplePattern > ) > >( e, e.extLowerTypeForRuntime(),
Changes to bs/builtins/types/tuple/tuple.cpp.
1
2
3
4
5
6
7
8
9
10
11
#include "builtins/builtins.h"

using namespace goose;
using namespace goose::ir;

namespace goose::builtins
{
    Value MkTupleType( const Term& state, const Term& types )
    {
        return Value( TypeType(), VEC( TSID( tuple ), state, types ) );
    }



|







1
2
3
4
5
6
7
8
9
10
11
#include "builtins/builtins.h"

using namespace goose;
using namespace goose::eir;

namespace goose::builtins
{
    Value MkTupleType( const Term& state, const Term& types )
    {
        return Value( TypeType(), VEC( TSID( tuple ), state, types ) );
    }
Changes to bs/builtins/types/tuple/tuple.h.
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87

    struct TuplePatternOfTypeT
    {
        static const Term& GetPattern();
    };
}

namespace goose::ir
{
    template< typename... T >
    struct Bridge< tuple< T... > >
    {
        static const Term& Type();
        static Value ToValue( const tuple< T... >& x );
        static optional< tuple< T... > > FromVectorTerm( const Term& v );







|







73
74
75
76
77
78
79
80
81
82
83
84
85
86
87

    struct TuplePatternOfTypeT
    {
        static const Term& GetPattern();
    };
}

namespace goose::eir
{
    template< typename... T >
    struct Bridge< tuple< T... > >
    {
        static const Term& Type();
        static Value ToValue( const tuple< T... >& x );
        static optional< tuple< T... > > FromVectorTerm( const Term& v );
Changes to bs/builtins/types/tuple/tuple.inl.
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
        return ForEachInVectorTerms( tup1.val(), tup2.val(), [&]( auto&& t1, auto&& t2 )
        {
            return func( *ValueFromIRExpr( t1 ), *ValueFromIRExpr( t2 ) );
        } );
    }
}

namespace goose::ir
{
    // Type
    static inline const Value& BuildTupleType( const Value& typeSoFar )
    {
        return typeSoFar;
    }








|







88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
        return ForEachInVectorTerms( tup1.val(), tup2.val(), [&]( auto&& t1, auto&& t2 )
        {
            return func( *ValueFromIRExpr( t1 ), *ValueFromIRExpr( t2 ) );
        } );
    }
}

namespace goose::eir
{
    // Type
    static inline const Value& BuildTupleType( const Value& typeSoFar )
    {
        return typeSoFar;
    }

Changes to bs/builtins/types/tuple/typecheck.cpp.
1
2
3
4
5
6
7
8
9
10
11
#include "builtins/builtins.h"

using namespace goose;
using namespace goose::ir;

namespace goose::builtins
{
    TCGen TypeCheckConstantTuple( const TypeCheckingContext& tcc, const Value& tupType, const Value& tupArg, uint32_t index, const Value& out )
    {
        auto param = ParamPat( GetTupleTypeElement( tupType, index ) );




|







1
2
3
4
5
6
7
8
9
10
11
#include "builtins/builtins.h"

using namespace goose;
using namespace goose::eir;

namespace goose::builtins
{
    TCGen TypeCheckConstantTuple( const TypeCheckingContext& tcc, const Value& tupType, const Value& tupArg, uint32_t index, const Value& out )
    {
        auto param = ParamPat( GetTupleTypeElement( tupType, index ) );

23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
            if( index == ( tupSize - 1 ) )
                co_yield { ValueToIRExpr( newOut ), tcc };
            else
                co_yield TypeCheckConstantTuple( tcc, tupType, tupArg, index + 1, newOut );
        }
    }

    TCGen TypeCheckComputedTuple( const TypeCheckingContext& tcc, const Value& tupType, const Value& tupArg, const llr::CalcAddress& tupAddr, uint32_t index, const Value& out )
    {
        auto param = ParamPat( GetTupleTypeElement( tupType, index ) );

        auto argType = GetTupleElementType( tupArg, index );
        ReferenceType rt( argType, TSID( const ) );
        auto argAddr = tupAddr;
        argAddr.appendToPath( index );







|







23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
            if( index == ( tupSize - 1 ) )
                co_yield { ValueToIRExpr( newOut ), tcc };
            else
                co_yield TypeCheckConstantTuple( tcc, tupType, tupArg, index + 1, newOut );
        }
    }

    TCGen TypeCheckComputedTuple( const TypeCheckingContext& tcc, const Value& tupType, const Value& tupArg, const cir::CalcAddress& tupAddr, uint32_t index, const Value& out )
    {
        auto param = ParamPat( GetTupleTypeElement( tupType, index ) );

        auto argType = GetTupleElementType( tupArg, index );
        ReferenceType rt( argType, TSID( const ) );
        auto argAddr = tupAddr;
        argAddr.appendToPath( index );
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
            if( !ltup || !rtup || !tcc.context().codeBuilder() )
                co_return;

            auto tupType = *ValueFromIRExpr( ltup->type() );
            assert( TupleTypeSize( tupType ) == TupleTypeSize( *ValueFromIRExpr( rtup->type() ) ) );

            auto tempIndex = tcc.context().codeBuilder()->cfg()->getNewTemporaryIndex();
            llr::CalcAddress addr( llr::TemporaryBaseAddr( tempIndex, *rtup ) );

            co_yield TypeCheckComputedTuple( tcc, tupType, *rtup, addr, 0, EmptyTuple() );
        } );

        // Single element tuple unwrapping rules: if we encounter such a tuple, attempt to typecheck
        // its contained value with whatever's on the other side.
        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,







|







102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
            if( !ltup || !rtup || !tcc.context().codeBuilder() )
                co_return;

            auto tupType = *ValueFromIRExpr( ltup->type() );
            assert( TupleTypeSize( tupType ) == TupleTypeSize( *ValueFromIRExpr( rtup->type() ) ) );

            auto tempIndex = tcc.context().codeBuilder()->cfg()->getNewTemporaryIndex();
            cir::CalcAddress addr( cir::TemporaryBaseAddr( tempIndex, *rtup ) );

            co_yield TypeCheckComputedTuple( tcc, tupType, *rtup, addr, 0, EmptyTuple() );
        } );

        // Single element tuple unwrapping rules: if we encounter such a tuple, attempt to typecheck
        // its contained value with whatever's on the other side.
        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,
Changes to bs/builtins/types/typepredicates.cpp.
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
        c.env()->addVisibilityRule( parentIdentity, predicatesIdentity );

        auto typeTerm = ValueToIRExpr( type );

        auto name = "@val"_sid;
        auto valuePlaceholderIdentity = AppendToVectorTerm( predicatesIdentity, TERM( name ) );
        c.env()->storeValue( valuePlaceholderIdentity, ANYTERM( _ ),
            ValueToIRExpr( BuildComputedValue( typeTerm, llr::Placeholder( typeTerm, name ) ) ) );

        Context localContext( c.env(), predicatesIdentity );

        for( auto&& toks : tp.m_unparsedPredicates )
        {
            auto tokProvider = lex::MakeVectorAdapter( toks );
            auto r = make_shared< parse::Resolver >( tokProvider, localContext );







|







62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
        c.env()->addVisibilityRule( parentIdentity, predicatesIdentity );

        auto typeTerm = ValueToIRExpr( type );

        auto name = "@val"_sid;
        auto valuePlaceholderIdentity = AppendToVectorTerm( predicatesIdentity, TERM( name ) );
        c.env()->storeValue( valuePlaceholderIdentity, ANYTERM( _ ),
            ValueToIRExpr( BuildComputedValue( typeTerm, cir::Placeholder( typeTerm, name ) ) ) );

        Context localContext( c.env(), predicatesIdentity );

        for( auto&& toks : tp.m_unparsedPredicates )
        {
            auto tokProvider = lex::MakeVectorAdapter( toks );
            auto r = make_shared< parse::Resolver >( tokProvider, localContext );
Name change from bs/llr/allocvar.h to bs/cir/allocvar.h.
1
2
3
4
5
6
7
8
9
10
11
#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 ) ),
|
|

|







1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_CIR_ALLOCVAR_H
#define GOOSE_CIR_ALLOCVAR_H

namespace goose::cir
{
    class AllocVar
    {
        public:
            template< typename T >
            AllocVar( T&& type, uint32_t index ) :
                m_type( forward< T >( type ) ),
22
23
24
25
26
27
28
29
30
31
32
33
34

            bool canBeEagerlyEvaluated() const
            {
                return false;
            }

        private:
            ir::Value m_type;
            uint32_t m_index = 0;
    };
}

#endif







|





22
23
24
25
26
27
28
29
30
31
32
33
34

            bool canBeEagerlyEvaluated() const
            {
                return false;
            }

        private:
            eir::Value m_type;
            uint32_t m_index = 0;
    };
}

#endif
Name change from bs/llr/arith.h to bs/cir/arith.h.
1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_LLR_ARITH_H
#define GOOSE_LLR_ARITH_H

namespace goose::llr
{
    class Add : public BinaryOp
    {
        public:
            template< typename L, typename R >
            Add( L&& lhs, R&& rhs ) : BinaryOp( forward< L >( lhs ), forward< R >( rhs ) ) {}
    };
|
|

|







1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_CIR_ARITH_H
#define GOOSE_CIR_ARITH_H

namespace goose::cir
{
    class Add : public BinaryOp
    {
        public:
            template< typename L, typename R >
            Add( L&& lhs, R&& rhs ) : BinaryOp( forward< L >( lhs ), forward< R >( rhs ) ) {}
    };
Name change from bs/llr/ass.h to bs/cir/ass.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#ifndef GOOSE_LLR_ASS_H
#define GOOSE_LLR_ASS_H

// This file is not called "assert.h" because that fucks the cassert header up
// when it tries to include assert.h.
// "ass" is both a good shortcut and an accurate description of the problem.

namespace goose::llr
{
    class Assert
    {
        public:
            template< typename V >
            Assert( V&& cond ) :
                m_cond( forward< V >( cond ) )
|
|





|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#ifndef GOOSE_CIR_ASS_H
#define GOOSE_CIR_ASS_H

// This file is not called "assert.h" because that fucks the cassert header up
// when it tries to include assert.h.
// "ass" is both a good shortcut and an accurate description of the problem.

namespace goose::cir
{
    class Assert
    {
        public:
            template< typename V >
            Assert( V&& cond ) :
                m_cond( forward< V >( cond ) )
24
25
26
27
28
29
30
31
32
33
34
35

            bool canBeEagerlyEvaluated() const
            {
                return false;
            }

        private:
            ir::Value m_cond;
    };
}

#endif







|




24
25
26
27
28
29
30
31
32
33
34
35

            bool canBeEagerlyEvaluated() const
            {
                return false;
            }

        private:
            eir::Value m_cond;
    };
}

#endif
Name change from bs/llr/basicblock.h to bs/cir/basicblock.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#ifndef GOOSE_LLR_BASICBLOCK_H
#define GOOSE_LLR_BASICBLOCK_H

namespace llvm
{
    class BasicBlock;
}

namespace goose::llr
{
    class BasicBlock
    {
        public:
            BasicBlock( const ptr< CFG >& owner, uint32_t index ) :
                m_owner( owner ),
                m_index( index )
|
|






|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#ifndef GOOSE_CIR_BASICBLOCK_H
#define GOOSE_CIR_BASICBLOCK_H

namespace llvm
{
    class BasicBlock;
}

namespace goose::cir
{
    class BasicBlock
    {
        public:
            BasicBlock( const ptr< CFG >& owner, uint32_t index ) :
                m_owner( owner ),
                m_index( index )
Name change from bs/llr/basicblock.inl to bs/cir/basicblock.inl.
1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_LLR_BASICBLOCK_INL
#define GOOSE_LLR_BASICBLOCK_INL

namespace goose::llr
{
    template< typename... T >
    void BasicBlock::emplace_back( T&&... args )
    {
        m_instructions.emplace_back( forward< T >( args )... );
        m_canBeExecuted = m_canBeExecuted && m_instructions.back().canBeExecuted();
        m_canBeEagerlyEvaluated = m_canBeEagerlyEvaluated && m_instructions.back().canBeEagerlyEvaluated();
|
|

|







1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_CIR_BASICBLOCK_INL
#define GOOSE_CIR_BASICBLOCK_INL

namespace goose::cir
{
    template< typename... T >
    void BasicBlock::emplace_back( T&&... args )
    {
        m_instructions.emplace_back( forward< T >( args )... );
        m_canBeExecuted = m_canBeExecuted && m_instructions.back().canBeExecuted();
        m_canBeEagerlyEvaluated = m_canBeEagerlyEvaluated && m_instructions.back().canBeEagerlyEvaluated();
Name change from bs/llr/binaryop.cpp to bs/cir/binaryop.cpp.
1
2
3
4
5
6
7
8
9
10
#include "llr.h"

namespace goose::llr
{
    bool BinaryOp::canBeExecuted() const
    {
        return IsValueConstantOrExecutable( m_lhs )
            && IsValueConstantOrExecutable( m_rhs );
    }

|

|







1
2
3
4
5
6
7
8
9
10
#include "cir.h"

namespace goose::cir
{
    bool BinaryOp::canBeExecuted() const
    {
        return IsValueConstantOrExecutable( m_lhs )
            && IsValueConstantOrExecutable( m_rhs );
    }

Name change from bs/llr/binaryop.h to bs/cir/binaryop.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#ifndef GOOSE_LLR_BINARYINSTR_H
#define GOOSE_LLR_BINARYINSTR_H

namespace goose::llr
{
    class BinaryOp
    {
        public:
            template< typename L, typename R >
            BinaryOp( L&& lhs, R&& rhs ) :
                m_lhs( forward< L >( lhs ) ),
                m_rhs( forward< R >( rhs ) )
            {}

            const auto& lhs() const { return m_lhs; }
            const auto& rhs() const { return m_rhs; }

            bool canBeExecuted() const;
            bool canBeEagerlyEvaluated() const;

        private:
            ir::Value m_lhs;
            ir::Value m_rhs;
    };

    class BinaryOpSameTypes : public BinaryOp
    {
        public:
            template< typename L, typename R >
            BinaryOpSameTypes( L&& l, R&& r ) :
|
|

|

















|
|







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
#ifndef GOOSE_CIR_BINARYINSTR_H
#define GOOSE_CIR_BINARYINSTR_H

namespace goose::cir
{
    class BinaryOp
    {
        public:
            template< typename L, typename R >
            BinaryOp( L&& lhs, R&& rhs ) :
                m_lhs( forward< L >( lhs ) ),
                m_rhs( forward< R >( rhs ) )
            {}

            const auto& lhs() const { return m_lhs; }
            const auto& rhs() const { return m_rhs; }

            bool canBeExecuted() const;
            bool canBeEagerlyEvaluated() const;

        private:
            eir::Value m_lhs;
            eir::Value m_rhs;
    };

    class BinaryOpSameTypes : public BinaryOp
    {
        public:
            template< typename L, typename R >
            BinaryOpSameTypes( L&& l, R&& r ) :
Name change from bs/llr/bitwise.h to bs/cir/bitwise.h.
1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_LLR_BITWISE_H
#define GOOSE_LLR_BITWISE_H

namespace goose::llr
{
    class And : public BinaryOp
    {
        public:
            template< typename L, typename R >
            And( L&& lhs, R&& rhs ) : BinaryOp( forward< L >( lhs ), forward< R >( rhs ) ) {}
    };
|
|

|







1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_CIR_BITWISE_H
#define GOOSE_CIR_BITWISE_H

namespace goose::cir
{
    class And : public BinaryOp
    {
        public:
            template< typename L, typename R >
            And( L&& lhs, R&& rhs ) : BinaryOp( forward< L >( lhs ), forward< R >( rhs ) ) {}
    };
Name change from bs/llr/branch.h to bs/cir/branch.h.
1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_LLR_BRANCH_H
#define GOOSE_LLR_BRANCH_H

namespace goose::llr
{
    class BasicBlock;

    class Branch
    {
        public:
            template< typename B >
|
|

|







1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_CIR_BRANCH_H
#define GOOSE_CIR_BRANCH_H

namespace goose::cir
{
    class BasicBlock;

    class Branch
    {
        public:
            template< typename B >
47
48
49
50
51
52
53
54
55
56
57
58
59
60
            {
                return CanValueBeEagerlyEvaluated( m_cond );
            }

            void addCFGEdges( const ptr< CFG >& cfg, uint32_t srcBBIndex );

        private:
            ir::Value m_cond;
            wptr< BasicBlock > m_trueDest;
            wptr< BasicBlock > m_falseDest;
    };
}

#endif







|






47
48
49
50
51
52
53
54
55
56
57
58
59
60
            {
                return CanValueBeEagerlyEvaluated( m_cond );
            }

            void addCFGEdges( const ptr< CFG >& cfg, uint32_t srcBBIndex );

        private:
            eir::Value m_cond;
            wptr< BasicBlock > m_trueDest;
            wptr< BasicBlock > m_falseDest;
    };
}

#endif
Name change from bs/llr/break.h to bs/cir/break.h.
1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_LLR_BREAK_H
#define GOOSE_LLR_BREAK_H

namespace goose::llr
{
    class Break
    {
        public:
            Break() {}

            Break( uint32_t level ) :
|
|

|







1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_CIR_BREAK_H
#define GOOSE_CIR_BREAK_H

namespace goose::cir
{
    class Break
    {
        public:
            Break() {}

            Break( uint32_t level ) :
Name change from bs/llr/calcaddr.h to bs/cir/calcaddr.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#ifndef GOOSE_LLR_CALCADDR_H
#define GOOSE_LLR_CALCADDR_H

namespace goose::llr
{
    struct TemporaryBaseAddr
    {
        template< typename T >
        TemporaryBaseAddr( uint32_t i, T&& init ) :
            m_initValue( forward< T >( init ) ),
            index( i )
        {}

        auto operator<=>( const TemporaryBaseAddr& rhs ) const
        {
            return index <=> rhs.index;
        }

        ir::Value m_initValue;
        uint32_t index = 0;
    };

    struct VarBaseAddr
    {
        VarBaseAddr( uint32_t i ) : index( i ) {}

|
|

|














|







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_CIR_CALCADDR_H
#define GOOSE_CIR_CALCADDR_H

namespace goose::cir
{
    struct TemporaryBaseAddr
    {
        template< typename T >
        TemporaryBaseAddr( uint32_t i, T&& init ) :
            m_initValue( forward< T >( init ) ),
            index( i )
        {}

        auto operator<=>( const TemporaryBaseAddr& rhs ) const
        {
            return index <=> rhs.index;
        }

        eir::Value m_initValue;
        uint32_t index = 0;
    };

    struct VarBaseAddr
    {
        VarBaseAddr( uint32_t i ) : index( i ) {}

Name change from bs/llr/call.cpp to bs/cir/call.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
#include "llr/llr.h"
#include "builtins/builtins.h"

using namespace goose::builtins;

namespace goose::llr
{
    bool Call::canBeExecuted() const
    {
        if( !IsValueConstantOrExecutable( m_func ) )
            return false;

        if( IsExternalFunc( m_func ) )
|




|







1
2
3
4
5
6
7
8
9
10
11
12
13
#include "cir/cir.h"
#include "builtins/builtins.h"

using namespace goose::builtins;

namespace goose::cir
{
    bool Call::canBeExecuted() const
    {
        if( !IsValueConstantOrExecutable( m_func ) )
            return false;

        if( IsExternalFunc( m_func ) )
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

        if( !argsCanBeExecuted )
            return false;

        if( IsBuiltinFunc( m_func ) )
            return true;

        const auto* pFunc = GetFuncLLR( m_func );

        // If the func is passed as a value, we might not have been able to evaluate
        // it yet, so we assume it's going to be executable. If it isn't, we'll fail
        // at execution time, which isn't a big deal - we should be able to avoid trying
        // executing it in the first place in most cases.
        return !pFunc || pFunc->canBeExecuted();
    }







|







27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

        if( !argsCanBeExecuted )
            return false;

        if( IsBuiltinFunc( m_func ) )
            return true;

        const auto* pFunc = GetFuncCIR( m_func );

        // If the func is passed as a value, we might not have been able to evaluate
        // it yet, so we assume it's going to be executable. If it isn't, we'll fail
        // at execution time, which isn't a big deal - we should be able to avoid trying
        // executing it in the first place in most cases.
        return !pFunc || pFunc->canBeExecuted();
    }
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82

        if( !argsAreConstant )
            return false;

        if( IsEagerBuiltinFunc( m_func ) )
            return true;

        const auto* pFuncLLR = GetFuncLLR( m_func );

        if( !pFuncLLR )
            return false;

        return pFuncLLR->canBeExecuted();
    }
}







|

|


|


68
69
70
71
72
73
74
75
76
77
78
79
80
81
82

        if( !argsAreConstant )
            return false;

        if( IsEagerBuiltinFunc( m_func ) )
            return true;

        const auto* pFuncCIR = GetFuncCIR( m_func );

        if( !pFuncCIR )
            return false;

        return pFuncCIR->canBeExecuted();
    }
}
Name change from bs/llr/call.h to bs/cir/call.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#ifndef GOOSE_LLR_CALL_H
#define GOOSE_LLR_CALL_H

namespace goose::llr
{
    class Call
    {
        public:
            template< typename F, typename A >
            Call( F&& func, A&& args ) :
                m_func( forward< F >( func ) ),
                m_args( forward< A >( args ) )
            {}

            const auto& func() const { return m_func; }
            const auto& args() const { return m_args; }

            bool canBeExecuted() const;
            bool canBeEagerlyEvaluated() const;

        private:
            ir::Value m_func;
            ir::Term m_args;
    };
}

#endif
|
|

|

















|
|




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
#ifndef GOOSE_CIR_CALL_H
#define GOOSE_CIR_CALL_H

namespace goose::cir
{
    class Call
    {
        public:
            template< typename F, typename A >
            Call( F&& func, A&& args ) :
                m_func( forward< F >( func ) ),
                m_args( forward< A >( args ) )
            {}

            const auto& func() const { return m_func; }
            const auto& args() const { return m_args; }

            bool canBeExecuted() const;
            bool canBeEagerlyEvaluated() const;

        private:
            eir::Value m_func;
            eir::Term m_args;
    };
}

#endif
Name change from bs/llr/cfg.cpp to bs/cir/cfg.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include "llr.h"

using namespace goose;
using namespace goose::llr;

const ptr< llr::BasicBlock >& CFG::createBB()
{
    m_basicBlocks.emplace_back( make_shared< llr::BasicBlock >( shared_from_this(), m_basicBlocks.size() + 1 ) );
    return m_basicBlocks.back();
}

void CFG::addEdge( uint32_t srcIndex, uint32_t destIndex )
{
    m_edges.emplace( srcIndex, destIndex );
}
|


|

|

|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include "cir.h"

using namespace goose;
using namespace goose::cir;

const ptr< cir::BasicBlock >& CFG::createBB()
{
    m_basicBlocks.emplace_back( make_shared< cir::BasicBlock >( shared_from_this(), m_basicBlocks.size() + 1 ) );
    return m_basicBlocks.back();
}

void CFG::addEdge( uint32_t srcIndex, uint32_t destIndex )
{
    m_edges.emplace( srcIndex, destIndex );
}
Name change from bs/llr/cfg.h to bs/cir/cfg.h.
1
2
3
4
5
6
7
8
9
10
11
#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 ) :
|
|

|







1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_CIR_CFG_H
#define GOOSE_CIR_CFG_H

namespace goose::cir
{
    class BasicBlock;

    class CFG : public enable_shared_from_this< CFG >
    {
        public:
            CFG( uint32_t numParams ) :
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
            // 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 setAddressModifiedByLoop( uint32_t loopId, const ir::Term& type, const CalcAddress& addr )
            {
                m_loopModifiedAddresses.emplace( make_pair( loopId, addr ), type );
            }

            template< typename F >
            void forEachAddressModifiedInLoop( uint32_t loopId, F&& func ) const
            {







|
















|







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
            // 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< cir::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 setAddressModifiedByLoop( uint32_t loopId, const eir::Term& type, const CalcAddress& addr )
            {
                m_loopModifiedAddresses.emplace( make_pair( loopId, addr ), type );
            }

            template< typename F >
            void forEachAddressModifiedInLoop( uint32_t loopId, F&& func ) const
            {
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
            // For each BB, store the index of its immediate dominator.
            // May be be empty if it has not (yet) been computed.
            vector< uint32_t > m_idoms;

            // For each loop, store all of the adresses modified
            // during that loop.
            // May be be empty if it has not (yet) been computed.
            multimap< pair< uint32_t, CalcAddress >, ir::Term > m_loopModifiedAddresses;

            // The number of temporary indices used by this CFG.
            uint32_t m_temporariesCount = 0;

            uint32_t m_loopCount = 0;

            bool m_poisoned = false;







|







91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
            // For each BB, store the index of its immediate dominator.
            // May be be empty if it has not (yet) been computed.
            vector< uint32_t > m_idoms;

            // For each loop, store all of the adresses modified
            // during that loop.
            // May be be empty if it has not (yet) been computed.
            multimap< pair< uint32_t, CalcAddress >, eir::Term > m_loopModifiedAddresses;

            // The number of temporary indices used by this CFG.
            uint32_t m_temporariesCount = 0;

            uint32_t m_loopCount = 0;

            bool m_poisoned = false;
Name change from bs/llr/cfgviz.cpp to bs/cir/cfgviz.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
#include "llr/llr.h"
#include "builtins/builtins.h"

using namespace goose::builtins;

namespace goose::llr
{
    void CfgViz( GraphVizBuilder& builder, const CFG& cfg )
    {
        CfgViz( builder, cfg.entryBB() );
    }

    void CfgViz( GraphVizBuilder& builder, const ptr< BasicBlock >& bb )
|




|







1
2
3
4
5
6
7
8
9
10
11
12
13
#include "cir/cir.h"
#include "builtins/builtins.h"

using namespace goose::builtins;

namespace goose::cir
{
    void CfgViz( GraphVizBuilder& builder, const CFG& cfg )
    {
        CfgViz( builder, cfg.entryBB() );
    }

    void CfgViz( GraphVizBuilder& builder, const ptr< BasicBlock >& bb )
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
        for( auto&& instr : *bb )
            CfgViz( builder, instr );

        if( bb->terminator() )
            CfgViz( builder, *bb->terminator() );
    }

    void CfgViz( GraphVizBuilder& builder, const ir::Value& val )
    {
        GraphVizBuilder::Node n( builder, &val, "Value" );

        if( val.isConstant() )
        {
            GraphVizBuilder::Row row( builder );
            GraphVizBuilder::Cell cell( builder );
            GraphVizBuilder::Color col( builder );
            builder.output() << val;
            return;
        }

        CfgViz( builder, *val.llr() );
    }

    void CfgViz( GraphVizBuilder& builder, const Instruction& instr )
    {
        visit( [&]( auto&& ins )
        {
            CfgViz( builder, ins );







|












|







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
        for( auto&& instr : *bb )
            CfgViz( builder, instr );

        if( bb->terminator() )
            CfgViz( builder, *bb->terminator() );
    }

    void CfgViz( GraphVizBuilder& builder, const eir::Value& val )
    {
        GraphVizBuilder::Node n( builder, &val, "Value" );

        if( val.isConstant() )
        {
            GraphVizBuilder::Row row( builder );
            GraphVizBuilder::Cell cell( builder );
            GraphVizBuilder::Color col( builder );
            builder.output() << val;
            return;
        }

        CfgViz( builder, *val.cir() );
    }

    void CfgViz( GraphVizBuilder& builder, const Instruction& instr )
    {
        visit( [&]( auto&& ins )
        {
            CfgViz( builder, ins );
Name change from bs/llr/cfgviz.h to bs/cir/cfgviz.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#ifndef GOOSE_LLR_CFGVIZ_H
#define GOOSE_LLR_CFGVIZ_H

namespace goose::llr
{
    template< typename T >
    void CfgViz( const char* pFilename, const T& x )
    {
        ofstream file( pFilename );
        GraphVizBuilder builder( file, true );
        CfgViz( builder, x );
    }

    extern void CfgViz( GraphVizBuilder& builder, const CFG& cfg );
    extern void CfgViz( GraphVizBuilder& builder, const ptr< BasicBlock >& bb );
    extern void CfgViz( GraphVizBuilder& builder, const ir::Value& val );

    extern void CfgViz( GraphVizBuilder& builder, const Instruction& instr );
    extern void CfgViz( GraphVizBuilder& builder, const Terminator& t );

    extern void CfgViz( GraphVizBuilder& builder, const Call& instr );
    extern void CfgViz( GraphVizBuilder& builder, const CalcAddress& instr );
    extern void CfgViz( GraphVizBuilder& builder, const CreateTemporary& instr );
|
|

|











|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#ifndef GOOSE_CIR_CFGVIZ_H
#define GOOSE_CIR_CFGVIZ_H

namespace goose::cir
{
    template< typename T >
    void CfgViz( const char* pFilename, const T& x )
    {
        ofstream file( pFilename );
        GraphVizBuilder builder( file, true );
        CfgViz( builder, x );
    }

    extern void CfgViz( GraphVizBuilder& builder, const CFG& cfg );
    extern void CfgViz( GraphVizBuilder& builder, const ptr< BasicBlock >& bb );
    extern void CfgViz( GraphVizBuilder& builder, const eir::Value& val );

    extern void CfgViz( GraphVizBuilder& builder, const Instruction& instr );
    extern void CfgViz( GraphVizBuilder& builder, const Terminator& t );

    extern void CfgViz( GraphVizBuilder& builder, const Call& instr );
    extern void CfgViz( GraphVizBuilder& builder, const CalcAddress& instr );
    extern void CfgViz( GraphVizBuilder& builder, const CreateTemporary& instr );
Name change from bs/llr/llr.h to bs/cir/cir.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#ifndef GOOSE_LLR_H
#define GOOSE_LLR_H

#include "util/util.h"
#include "ir/ir.h"

namespace goose::llr
{
    using namespace util;

    static constexpr uint32_t InvalidVarId = numeric_limits< uint32_t >::max();

    class CFG;
}
|
|


|

|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
#ifndef GOOSE_CIR_H
#define GOOSE_CIR_H

#include "util/util.h"
#include "eir/eir.h"

namespace goose::cir
{
    using namespace util;

    static constexpr uint32_t InvalidVarId = numeric_limits< uint32_t >::max();

    class CFG;
}
Name change from bs/llr/comparison.h to bs/cir/comparison.h.
1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_LLR_COMPARISON_H
#define GOOSE_LLR_COMPARISON_H

namespace goose::llr
{
    class Eq : public BinaryOpSameTypes
    {
        public:
            template< typename L, typename R >
            Eq( L&& lhs, R&& rhs ) : BinaryOpSameTypes( forward< L >( lhs ), forward< R >( rhs ) ) {}
    };
|
|

|







1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_CIR_COMPARISON_H
#define GOOSE_CIR_COMPARISON_H

namespace goose::cir
{
    class Eq : public BinaryOpSameTypes
    {
        public:
            template< typename L, typename R >
            Eq( L&& lhs, R&& rhs ) : BinaryOpSameTypes( forward< L >( lhs ), forward< R >( rhs ) ) {}
    };
Name change from bs/llr/continue.h to bs/cir/continue.h.
1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_LLR_CONTINUE_H
#define GOOSE_LLR_CONTINUE_H

namespace goose::llr
{
    class Continue
    {
        public:
            Continue() {}

            Continue( uint32_t level ) :
|
|

|







1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_CIR_CONTINUE_H
#define GOOSE_CIR_CONTINUE_H

namespace goose::cir
{
    class Continue
    {
        public:
            Continue() {}

            Continue( uint32_t level ) :
Name change from bs/llr/createtemporary.h to bs/cir/createtemporary.h.
1
2
3
4
5
6
7
8
9
10
11
#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 ),
|
|

|







1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_CIR_CREATETEMPORARY_H
#define GOOSE_CIR_CREATETEMPORARY_H

namespace goose::cir
{
    class CreateTemporary
    {
        public:
            template< typename V >
            CreateTemporary( uint32_t index, V&& val ) :
                m_index( index ),
23
24
25
26
27
28
29
30
31
32
33
34
            bool canBeEagerlyEvaluated() const
            {
                return CanValueBeEagerlyEvaluated( m_value );
            }

        private:
            uint32_t m_index = 0;
            ir::Value m_value;
    };
}

#endif







|




23
24
25
26
27
28
29
30
31
32
33
34
            bool canBeEagerlyEvaluated() const
            {
                return CanValueBeEagerlyEvaluated( m_value );
            }

        private:
            uint32_t m_index = 0;
            eir::Value m_value;
    };
}

#endif
Name change from bs/llr/dominators.cpp to bs/cir/dominators.cpp.
1
2
3
4
5
6
7
8
#include "llr.h"

using namespace goose;

// This is an almost verbatim transcription into C++ of the Lengauer-Tarjan algorithm,
// as listed in appendix B of the paper.
namespace
{
|







1
2
3
4
5
6
7
8
#include "cir.h"

using namespace goose;

// This is an almost verbatim transcription into C++ of the Lengauer-Tarjan algorithm,
// as listed in appendix B of the paper.
namespace
{
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
        {
            st.ancestor[s] = v;
            s = st.child[s];
        }
    }
}

namespace goose::llr
{
    void ComputeDominators( const ptr< CFG >& cfg )
    {
        // Check if this has already been computed.
        if( !cfg->idoms().empty() )
            return;








|







111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
        {
            st.ancestor[s] = v;
            s = st.child[s];
        }
    }
}

namespace goose::cir
{
    void ComputeDominators( const ptr< CFG >& cfg )
    {
        // Check if this has already been computed.
        if( !cfg->idoms().empty() )
            return;

Name change from bs/llr/func.cpp to bs/cir/func.cpp.
1
2
3
4
5
6
7
8
9
#include "llr/llr.h"

namespace goose::llr
{
    bool Func::canBeExecuted() const
    {
        return isValid() && m_body && m_body->canBeExecuted();
    }
}
|

|






1
2
3
4
5
6
7
8
9
#include "cir/cir.h"

namespace goose::cir
{
    bool Func::canBeExecuted() const
    {
        return isValid() && m_body && m_body->canBeExecuted();
    }
}
Name change from bs/llr/func.h to bs/cir/func.h.
1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_LLR_FUNC_H
#define GOOSE_LLR_FUNC_H

namespace goose::llr
{
    class Func
    {
        public:
            template< typename I >
            Func( I&& identity ) :
                m_identity( forward< I >( identity ) )
|
|

|







1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_CIR_FUNC_H
#define GOOSE_CIR_FUNC_H

namespace goose::cir
{
    class Func
    {
        public:
            template< typename I >
            Func( I&& identity ) :
                m_identity( forward< I >( identity ) )
23
24
25
26
27
28
29
30
31
32
33
34
35
36

            bool canBeExecuted() const;

            bool isValid() const { return m_valid; }
            void setInvalid() { m_valid = false; }

        private:
            ir::Term m_identity;
            ptr< CFG > m_body;
            bool m_valid = true;
    };
}

#endif







|






23
24
25
26
27
28
29
30
31
32
33
34
35
36

            bool canBeExecuted() const;

            bool isValid() const { return m_valid; }
            void setInvalid() { m_valid = false; }

        private:
            eir::Term m_identity;
            ptr< CFG > m_body;
            bool m_valid = true;
    };
}

#endif
Name change from bs/llr/gettemporary.h to bs/cir/gettemporary.h.
1
2
3
4
5
6
7
8
9
10
11
#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 ) ),
|
|

|







1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_CIR_GETTEMPORARY_H
#define GOOSE_CIR_GETTEMPORARY_H

namespace goose::cir
{
    class GetTemporary
    {
        public:
            template< typename T >
            GetTemporary( T&& type, uint32_t index ) :
                m_type( forward< T >( type ) ),
22
23
24
25
26
27
28
29
30
31
32
33
34

            bool canBeEagerlyEvaluated() const
            {
                return false;
            }

        private:
            ir::Term m_type;
            uint32_t m_index = 0;
    };
}

#endif







|





22
23
24
25
26
27
28
29
30
31
32
33
34

            bool canBeEagerlyEvaluated() const
            {
                return false;
            }

        private:
            eir::Term m_type;
            uint32_t m_index = 0;
    };
}

#endif
Name change from bs/llr/helpers.cpp to bs/cir/helpers.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
#include "llr/llr.h"

namespace goose::llr
{
    bool IsValueConstantOrExecutable( const ir::Value& val )
    {
        if( val.isConstant() )
            return true;

        return val.llr()->canBeExecuted();
    }

    bool CanValueBeEagerlyEvaluated( const ir::Value& val )
    {
        if( val.isConstant() )
            return true;

        return val.llr()->canBeEagerlyEvaluated();
    }

    bool IsCompileTimeTempRef( const ir::Value& val )
    {
        if( !val.isConstant() )
            return false;

        const auto* pRefInst = get_if< CalcAddress >( &val.llr()->content() );
        return pRefInst && pRefInst->isTempRef();
    }
}
|

|

|




|


|




|


|




|



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
#include "cir/cir.h"

namespace goose::cir
{
    bool IsValueConstantOrExecutable( const eir::Value& val )
    {
        if( val.isConstant() )
            return true;

        return val.cir()->canBeExecuted();
    }

    bool CanValueBeEagerlyEvaluated( const eir::Value& val )
    {
        if( val.isConstant() )
            return true;

        return val.cir()->canBeEagerlyEvaluated();
    }

    bool IsCompileTimeTempRef( const eir::Value& val )
    {
        if( !val.isConstant() )
            return false;

        const auto* pRefInst = get_if< CalcAddress >( &val.cir()->content() );
        return pRefInst && pRefInst->isTempRef();
    }
}
Name change from bs/llr/helpers.h to bs/cir/helpers.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#ifndef GOOSE_LLR_HELPERS_H
#define GOOSE_LLR_HELPERS_H

namespace goose::llr
{
    class Instruction;

    bool IsValueConstantOrExecutable( const ir::Value& val );
    bool CanValueBeEagerlyEvaluated( const ir::Value& val );
    bool IsCompileTimeTempRef( const ir::Value& val );

    template< typename T, typename I >
    auto BuildComputedValue( T&& type, I&& instr )
    {
        return ir::Value( forward< T >( type ),
            make_shared< Instruction >( forward< I >( instr ) ) );
    }

    template< typename T >
    class TempStorage
    {
        public:
|
|

|



|
|
|




|







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_HELPERS_H
#define GOOSE_CIR_HELPERS_H

namespace goose::cir
{
    class Instruction;

    bool IsValueConstantOrExecutable( const eir::Value& val );
    bool CanValueBeEagerlyEvaluated( const eir::Value& val );
    bool IsCompileTimeTempRef( const eir::Value& val );

    template< typename T, typename I >
    auto BuildComputedValue( T&& type, I&& instr )
    {
        return eir::Value( forward< T >( type ),
            make_shared< Instruction >( forward< I >( instr ) ) );
    }

    template< typename T >
    class TempStorage
    {
        public:
Name change from bs/llr/instruction.cpp to bs/cir/instruction.cpp.
1
2
3
4
5
6
7
8
9
10
#include "llr/llr.h"

namespace goose::llr
{
    bool Instruction::canBeExecuted() const
    {
        return visit( []< typename ET >( const ET& e )
        {
            if constexpr( is_same_v< ET, ptr< CFG > > )
                return e->canBeExecuted();
|

|







1
2
3
4
5
6
7
8
9
10
#include "cir/cir.h"

namespace goose::cir
{
    bool Instruction::canBeExecuted() const
    {
        return visit( []< typename ET >( const ET& e )
        {
            if constexpr( is_same_v< ET, ptr< CFG > > )
                return e->canBeExecuted();
Name change from bs/llr/instruction.h to bs/cir/instruction.h.
1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_LLR_INSTRUCTION_H
#define GOOSE_LLR_INSTRUCTION_H

namespace goose::llr
{
    class CFG;

    class Instruction
    {
        public:
            Instruction( Call&& c ) :
|
|

|







1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_CIR_INSTRUCTION_H
#define GOOSE_CIR_INSTRUCTION_H

namespace goose::cir
{
    class CFG;

    class Instruction
    {
        public:
            Instruction( Call&& c ) :
Name change from bs/llr/load.h to bs/cir/load.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#ifndef GOOSE_LLR_LOAD_H
#define GOOSE_LLR_LOAD_H

namespace goose::llr
{
    class Load
    {
        public:
            template< typename A, typename T >
            Load( A&& addr, T&& type ) :
                m_addr( forward< A >( addr ) ),
                m_type( forward< T >( type ) )
            {}

            const auto& addr() const { return m_addr; }
            const auto& type() const { return m_type; }

            bool canBeExecuted() const { return true; }
            bool canBeEagerlyEvaluated() const
            {
                return IsCompileTimeTempRef( m_addr );
            }

        private:
            ir::Value m_addr;
            ir::Term m_type;
    };
}

#endif
|
|

|




















|
|




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
#ifndef GOOSE_CIR_LOAD_H
#define GOOSE_CIR_LOAD_H

namespace goose::cir
{
    class Load
    {
        public:
            template< typename A, typename T >
            Load( A&& addr, T&& type ) :
                m_addr( forward< A >( addr ) ),
                m_type( forward< T >( type ) )
            {}

            const auto& addr() const { return m_addr; }
            const auto& type() const { return m_type; }

            bool canBeExecuted() const { return true; }
            bool canBeEagerlyEvaluated() const
            {
                return IsCompileTimeTempRef( m_addr );
            }

        private:
            eir::Value m_addr;
            eir::Term m_type;
    };
}

#endif
Name change from bs/llr/loadconst.h to bs/cir/loadconst.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#ifndef GOOSE_LLR_LOADCONST_H
#define GOOSE_LLR_LOADCONST_H

namespace llvm
{
    class IntegerType;
}

namespace goose::llr
{
    class LoadConstStr
    {
        public:
            LoadConstStr( const string& str ) :
                m_str( str )
            {}
|
|






|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#ifndef GOOSE_CIR_LOADCONST_H
#define GOOSE_CIR_LOADCONST_H

namespace llvm
{
    class IntegerType;
}

namespace goose::cir
{
    class LoadConstStr
    {
        public:
            LoadConstStr( const string& str ) :
                m_str( str )
            {}
Name change from bs/llr/logic.h to bs/cir/logic.h.
1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_LLR_LOGIC_H
#define GOOSE_LLR_LOGIC_H

namespace goose::llr
{
    class Not
    {
        public:
            template< typename T >
            Not( T&& operand ) :
                m_operand( forward< T >( operand ) )
|
|

|







1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_CIR_LOGIC_H
#define GOOSE_CIR_LOGIC_H

namespace goose::cir
{
    class Not
    {
        public:
            template< typename T >
            Not( T&& operand ) :
                m_operand( forward< T >( operand ) )
20
21
22
23
24
25
26
27
28
29
30
31

            bool canBeEagerlyEvaluated() const
            {
                return CanValueBeEagerlyEvaluated( m_operand );
            }

        private:
            ir::Value m_operand;
    };
}

#endif







|




20
21
22
23
24
25
26
27
28
29
30
31

            bool canBeEagerlyEvaluated() const
            {
                return CanValueBeEagerlyEvaluated( m_operand );
            }

        private:
            eir::Value m_operand;
    };
}

#endif
Name change from bs/llr/loopaddrs.cpp to bs/cir/loopaddrs.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
#include "llr.h"

namespace goose::llr
{
    void MarkAddrChangedByLoop( const ptr< CFG >& cfg, uint32_t loopId, const ir::Term& type, const CalcAddress& addr )
    {
        cfg->setAddressModifiedByLoop( loopId, type, addr );

        const auto& pHeader = cfg->getBB( loopId );

        if( pHeader->loopId() )
            MarkAddrChangedByLoop( cfg, pHeader->loopId(), type, addr );
    }

    void ComputeLoopModifiedAddrs( const ptr< CFG >& cfg )
    {
        cfg->forEachBB( [&]( auto&& bb )
        {
            for( auto&& instr : *bb )
            {
                auto st = get_if< Store >( &instr.content() );
                if( !st )
                    continue;

                auto llr = st->addr().llr();
                if( !llr )
                    continue;

                auto ref = get_if< CalcAddress >( &llr->content() );
                if( !ref )
                    continue;

                MarkAddrChangedByLoop( cfg, bb->index(), st->val().type(), *ref );
            }
        } );
    }
}
|

|

|



















|
|


|








1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include "cir.h"

namespace goose::cir
{
    void MarkAddrChangedByLoop( const ptr< CFG >& cfg, uint32_t loopId, const eir::Term& type, const CalcAddress& addr )
    {
        cfg->setAddressModifiedByLoop( loopId, type, addr );

        const auto& pHeader = cfg->getBB( loopId );

        if( pHeader->loopId() )
            MarkAddrChangedByLoop( cfg, pHeader->loopId(), type, addr );
    }

    void ComputeLoopModifiedAddrs( const ptr< CFG >& cfg )
    {
        cfg->forEachBB( [&]( auto&& bb )
        {
            for( auto&& instr : *bb )
            {
                auto st = get_if< Store >( &instr.content() );
                if( !st )
                    continue;

                auto cir = st->addr().cir();
                if( !cir )
                    continue;

                auto ref = get_if< CalcAddress >( &cir->content() );
                if( !ref )
                    continue;

                MarkAddrChangedByLoop( cfg, bb->index(), st->val().type(), *ref );
            }
        } );
    }
}
Name change from bs/llr/loops.cpp to bs/cir/loops.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
#include "llr.h"

// Note: we only handle reducible CFGs for now. The results are undefined (ie probably a clusterfuck) for
// irreducible CFGs. We'll have to handle irreducible CFGs when (if...) we implement goto.
namespace goose::llr
{
    void ComputeLoops( const ptr< CFG >& cfg, const ptr< BasicBlock >& bb );

    void MarkLoop( const ptr< CFG >& cfg, const ptr< BasicBlock >& bb, uint32_t loopHeaderId )
    {
        if( bb->index() == loopHeaderId )
            return;
|



|







1
2
3
4
5
6
7
8
9
10
11
12
#include "cir.h"

// Note: we only handle reducible CFGs for now. The results are undefined (ie probably a clusterfuck) for
// irreducible CFGs. We'll have to handle irreducible CFGs when (if...) we implement goto.
namespace goose::cir
{
    void ComputeLoops( const ptr< CFG >& cfg, const ptr< BasicBlock >& bb );

    void MarkLoop( const ptr< CFG >& cfg, const ptr< BasicBlock >& bb, uint32_t loopHeaderId )
    {
        if( bb->index() == loopHeaderId )
            return;
Name change from bs/llr/meson.build to bs/cir/meson.build.
1
2
3
4
5
6
7
8
goose_llr = library( 'goose-llr',
    'cfg.cpp',
    'dominators.cpp',
    'loops.cpp',
    'loopaddrs.cpp',
    'instruction.cpp',
    'binaryop.cpp',
    'terminator.cpp',
|







1
2
3
4
5
6
7
8
goose_cir = library( 'goose-cir',
    'cfg.cpp',
    'dominators.cpp',
    'loops.cpp',
    'loopaddrs.cpp',
    'instruction.cpp',
    'binaryop.cpp',
    'terminator.cpp',
Name change from bs/llr/phi.h to bs/cir/phi.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#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 );
            }

            uint32_t numIncomings() const { return m_incomings.size(); }

            template< typename F >
|
|

|

















|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#ifndef GOOSE_CIR_PHI_H
#define GOOSE_CIR_PHI_H

namespace goose::cir
{
    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 eir::Value& val )
            {
                m_incomings.emplace_back( bb, val );
            }

            uint32_t numIncomings() const { return m_incomings.size(); }

            template< typename F >
43
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







|


|






43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

            bool canBeEagerlyEvaluated() const
            {
                return true;
            }

        private:
            eir::Value m_type;
            uint32_t m_destIndex = 0;

            using incInfo = pair< wptr< BasicBlock >, eir::Value >;
            llvm::SmallVector< incInfo, 2 > m_incomings;

    };
}

#endif
Name change from bs/llr/placeholder.h to bs/cir/placeholder.h.
1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_LLR_PLACEHOLDER_H
#define GOOSE_LLR_PLACEHOLDER_H

namespace goose::llr
{
    // A placeholder value with a name, to be replacedd with something else.
    // Intended to represent the @ return value paceholder in functions'
    // post conditions.
    class Placeholder
    {
        public:
|
|

|







1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_CIR_PLACEHOLDER_H
#define GOOSE_CIR_PLACEHOLDER_H

namespace goose::cir
{
    // A placeholder value with a name, to be replacedd with something else.
    // Intended to represent the @ return value paceholder in functions'
    // post conditions.
    class Placeholder
    {
        public:
27
28
29
30
31
32
33
34
35
36
37
38
39

            bool canBeEagerlyEvaluated() const
            {
                return false;
            }

        private:
            ir::Term    m_type;
            StringId    m_name;
    };
}

#endif







|





27
28
29
30
31
32
33
34
35
36
37
38
39

            bool canBeEagerlyEvaluated() const
            {
                return false;
            }

        private:
            eir::Term    m_type;
            StringId    m_name;
    };
}

#endif
Name change from bs/llr/ret.h to bs/cir/ret.h.
1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_LLR_RET_H
#define GOOSE_LLR_RET_H

namespace goose::llr
{
    class Ret
    {
        public:
            Ret() {}

            template< typename V >
|
|

|







1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_CIR_RET_H
#define GOOSE_CIR_RET_H

namespace goose::cir
{
    class Ret
    {
        public:
            Ret() {}

            template< typename V >
24
25
26
27
28
29
30
31
32
33
34
35
            {
                return !m_value || CanValueBeEagerlyEvaluated( *m_value );
            }

            void addCFGEdges( const ptr< CFG >& cfg, uint32_t srcBBIndex )  {}

        private:
            optional< ir::Value > m_value;
    };
}

#endif







|




24
25
26
27
28
29
30
31
32
33
34
35
            {
                return !m_value || CanValueBeEagerlyEvaluated( *m_value );
            }

            void addCFGEdges( const ptr< CFG >& cfg, uint32_t srcBBIndex )  {}

        private:
            optional< eir::Value > m_value;
    };
}

#endif
Name change from bs/llr/store.h to bs/cir/store.h.
1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_LLR_STORE_H
#define GOOSE_LLR_STORE_H

namespace goose::llr
{
    class Store
    {
        public:
            template< typename A, typename V >
            Store( A&& addr, V&& val ) :
                m_addr( forward< A >( addr ) ),
|
|

|







1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_CIR_STORE_H
#define GOOSE_CIR_STORE_H

namespace goose::cir
{
    class Store
    {
        public:
            template< typename A, typename V >
            Store( A&& addr, V&& val ) :
                m_addr( forward< A >( addr ) ),
23
24
25
26
27
28
29
30
31
32
33
34
35
            bool canBeEagerlyEvaluated() const
            {
                return IsCompileTimeTempRef( m_addr )
                    && CanValueBeEagerlyEvaluated( m_val );
            }

        private:
            ir::Value m_addr;
            ir::Value m_val;
    };
}

#endif







|
|




23
24
25
26
27
28
29
30
31
32
33
34
35
            bool canBeEagerlyEvaluated() const
            {
                return IsCompileTimeTempRef( m_addr )
                    && CanValueBeEagerlyEvaluated( m_val );
            }

        private:
            eir::Value m_addr;
            eir::Value m_val;
    };
}

#endif
Name change from bs/llr/terminator.cpp to bs/cir/terminator.cpp.
1
2
3
4
5
6
7
8
9
10
#include "llr/llr.h"

namespace goose::llr
{
    bool Terminator::canBeExecuted() const
    {
        return visit( []( auto&& e )
        {
            return e.canBeExecuted();
        }, m_content );
|

|







1
2
3
4
5
6
7
8
9
10
#include "cir/cir.h"

namespace goose::cir
{
    bool Terminator::canBeExecuted() const
    {
        return visit( []( auto&& e )
        {
            return e.canBeExecuted();
        }, m_content );
Name change from bs/llr/terminator.h to bs/cir/terminator.h.
1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_LLR_TERMINATOR_H
#define GOOSE_LLR_TERMINATOR_H

namespace goose::llr
{
    class BasicBlock;

    class Terminator
    {
        public:
            Terminator() {}
|
|

|







1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_CIR_TERMINATOR_H
#define GOOSE_CIR_TERMINATOR_H

namespace goose::cir
{
    class BasicBlock;

    class Terminator
    {
        public:
            Terminator() {}
Name change from bs/llr/tests/dom-1.cpp to bs/cir/tests/dom-1.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <exception>
#define CATCH_CONFIG_MAIN
#include "catch2/catch.hpp"
#include "llr/llr.h"

using namespace std;
using namespace goose;
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();



|



|
|

|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <exception>
#define CATCH_CONFIG_MAIN
#include "catch2/catch.hpp"
#include "cir/cir.h"

using namespace std;
using namespace goose;
using namespace goose::eir;
using namespace goose::cir;

SCENARIO( "Dominators test 1", "[cir-dom-1]" )
{
    WHEN( "Computing the dominators of an arbitrary CFG" )
    {
        auto cfg = make_shared< CFG >( 0 );

        auto bb1 = cfg->createBB();
        auto bb2 = cfg->createBB();
Name change from bs/llr/tests/dom-2.cpp to bs/cir/tests/dom-2.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <exception>
#define CATCH_CONFIG_MAIN
#include "catch2/catch.hpp"
#include "llr/llr.h"

using namespace std;
using namespace goose;
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();



|



|
|

|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <exception>
#define CATCH_CONFIG_MAIN
#include "catch2/catch.hpp"
#include "cir/cir.h"

using namespace std;
using namespace goose;
using namespace goose::eir;
using namespace goose::cir;

SCENARIO( "Dominators test 1", "[cir-dom-1]" )
{
    WHEN( "Computing the dominators of an arbitrary CFG" )
    {
        auto cfg = make_shared< CFG >( 0 );

        auto bb1 = cfg->createBB();
        auto bb2 = cfg->createBB();
Name change from bs/llr/tests/meson.build to bs/cir/tests/meson.build.
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
tests = [
    'dom-1',
    'dom-2'
]

# We need to link thess low level test of the llr with the entire planet
# because my module dependencies are a clusterfuck.
foreach t : tests
    exe = executable( 'llr-' + t, t + '.cpp',
        link_with:
        [
            goose_util,
            goose_ir,
            goose_llr,
            goose_builtins,
            goose_sema,
            goose_lex,
            goose_parse,
            goose_diagnostics,
            goose_execute,
            goose_codegen,
            goose_verify,
            goose_compile
        ],
        include_directories: bsinc,
        dependencies: [catch2_dep, fmt_dep, llvm_dep, lld_deps]
    )
    test( 'llr-' + t, exe )
endforeach





|


|



|
|













|

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
tests = [
    'dom-1',
    'dom-2'
]

# We need to link thess low level test of the cir with the entire planet
# because my module dependencies are a clusterfuck.
foreach t : tests
    exe = executable( 'cir-' + t, t + '.cpp',
        link_with:
        [
            goose_util,
            goose_eir,
            goose_cir,
            goose_builtins,
            goose_sema,
            goose_lex,
            goose_parse,
            goose_diagnostics,
            goose_execute,
            goose_codegen,
            goose_verify,
            goose_compile
        ],
        include_directories: bsinc,
        dependencies: [catch2_dep, fmt_dep, llvm_dep, lld_deps]
    )
    test( 'cir-' + t, exe )
endforeach
Changes to bs/codegen/arithops.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
#include "codegen.h"
#include "builtins/builtins.h"

using namespace goose;
using namespace goose::codegen;
using namespace goose::builtins;

llvm::Value* Module::buildInstruction( Infos& inf, const llr::Add& bo )
{
    auto lhs = buildValue( inf, bo.lhs() );
    if( !lhs )
        return nullptr;

    auto rhs = buildValue( inf, bo.rhs() );
    if( !rhs )
        return nullptr;

    return m_llvmBuilder.CreateAdd( lhs, rhs );
}

llvm::Value* Module::buildInstruction( Infos& inf, const llr::Sub& bo )
{
    auto lhs = buildValue( inf, bo.lhs() );
    if( !lhs )
        return nullptr;

    auto rhs = buildValue( inf, bo.rhs() );
    if( !rhs )
        return nullptr;

    return m_llvmBuilder.CreateSub( lhs, rhs );
}

llvm::Value* Module::buildInstruction( Infos& inf, const llr::Mul& bo )
{
    auto lhs = buildValue( inf, bo.lhs() );
    if( !lhs )
        return nullptr;

    auto rhs = buildValue( inf, bo.rhs() );
    if( !rhs )
        return nullptr;

    return m_llvmBuilder.CreateMul( lhs, rhs );
}

llvm::Value* Module::buildInstruction( Infos& inf, const llr::UDiv& bo )
{
    auto lhs = buildValue( inf, bo.lhs() );
    if( !lhs )
        return nullptr;

    auto rhs = buildValue( inf, bo.rhs() );
    if( !rhs )
        return nullptr;

    return m_llvmBuilder.CreateUDiv( lhs, rhs );
}

llvm::Value* Module::buildInstruction( Infos& inf, const llr::SDiv& bo )
{
    auto lhs = buildValue( inf, bo.lhs() );
    if( !lhs )
        return nullptr;

    auto rhs = buildValue( inf, bo.rhs() );
    if( !rhs )
        return nullptr;

    return m_llvmBuilder.CreateSDiv( lhs, rhs );
}

llvm::Value* Module::buildInstruction( Infos& inf, const llr::URem& bo )
{
    auto lhs = buildValue( inf, bo.lhs() );
    if( !lhs )
        return nullptr;

    auto rhs = buildValue( inf, bo.rhs() );
    if( !rhs )
        return nullptr;

    return m_llvmBuilder.CreateURem( lhs, rhs );
}

llvm::Value* Module::buildInstruction( Infos& inf, const llr::SRem& bo )
{
    auto lhs = buildValue( inf, bo.lhs() );
    if( !lhs )
        return nullptr;

    auto rhs = buildValue( inf, bo.rhs() );
    if( !rhs )







|












|












|












|












|












|












|







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
#include "codegen.h"
#include "builtins/builtins.h"

using namespace goose;
using namespace goose::codegen;
using namespace goose::builtins;

llvm::Value* Module::buildInstruction( Infos& inf, const cir::Add& bo )
{
    auto lhs = buildValue( inf, bo.lhs() );
    if( !lhs )
        return nullptr;

    auto rhs = buildValue( inf, bo.rhs() );
    if( !rhs )
        return nullptr;

    return m_llvmBuilder.CreateAdd( lhs, rhs );
}

llvm::Value* Module::buildInstruction( Infos& inf, const cir::Sub& bo )
{
    auto lhs = buildValue( inf, bo.lhs() );
    if( !lhs )
        return nullptr;

    auto rhs = buildValue( inf, bo.rhs() );
    if( !rhs )
        return nullptr;

    return m_llvmBuilder.CreateSub( lhs, rhs );
}

llvm::Value* Module::buildInstruction( Infos& inf, const cir::Mul& bo )
{
    auto lhs = buildValue( inf, bo.lhs() );
    if( !lhs )
        return nullptr;

    auto rhs = buildValue( inf, bo.rhs() );
    if( !rhs )
        return nullptr;

    return m_llvmBuilder.CreateMul( lhs, rhs );
}

llvm::Value* Module::buildInstruction( Infos& inf, const cir::UDiv& bo )
{
    auto lhs = buildValue( inf, bo.lhs() );
    if( !lhs )
        return nullptr;

    auto rhs = buildValue( inf, bo.rhs() );
    if( !rhs )
        return nullptr;

    return m_llvmBuilder.CreateUDiv( lhs, rhs );
}

llvm::Value* Module::buildInstruction( Infos& inf, const cir::SDiv& bo )
{
    auto lhs = buildValue( inf, bo.lhs() );
    if( !lhs )
        return nullptr;

    auto rhs = buildValue( inf, bo.rhs() );
    if( !rhs )
        return nullptr;

    return m_llvmBuilder.CreateSDiv( lhs, rhs );
}

llvm::Value* Module::buildInstruction( Infos& inf, const cir::URem& bo )
{
    auto lhs = buildValue( inf, bo.lhs() );
    if( !lhs )
        return nullptr;

    auto rhs = buildValue( inf, bo.rhs() );
    if( !rhs )
        return nullptr;

    return m_llvmBuilder.CreateURem( lhs, rhs );
}

llvm::Value* Module::buildInstruction( Infos& inf, const cir::SRem& bo )
{
    auto lhs = buildValue( inf, bo.lhs() );
    if( !lhs )
        return nullptr;

    auto rhs = buildValue( inf, bo.rhs() );
    if( !rhs )
Changes to bs/codegen/basicblock.cpp.
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

    if( !buildTerminator( inf, *pBB->terminator() ) )
        return nullptr;

    return pBB->llvmBB();
}

bool Module::buildTerminator( Infos& inf, const llr::Terminator& terminator )
{
    return visit( [&]( auto&& e )
    {
        return buildTerminator( inf, e );
    }, terminator.content() );
}

bool Module::buildTerminator( Infos& inf, const llr::Ret& r )
{
    if( !r.value() )
    {
        m_llvmBuilder.CreateRetVoid();
        return true;
    }

    auto* pRetVal = buildValue( inf, *r.value() );
    if( !pRetVal )
        return false;

    m_llvmBuilder.CreateRet( pRetVal );
    return true;
}

bool Module::buildTerminator( Infos& inf, const llr::Branch& b )
{
    m_llvmBuilder.CreateBr( b.dest().lock()->llvmBB() );

    llvm::IRBuilderBase::InsertPointGuard g( m_llvmBuilder );

    if( !buildBasicBlock( inf, b.dest().lock() ) )
        return false;

    return true;
}

bool Module::buildTerminator( Infos& inf, const llr::CondBranch& cb )
{
    auto* pCondVal = buildValue( inf, cb.cond() );
    if( !pCondVal )
        return false;

    m_llvmBuilder.CreateCondBr( pCondVal,
        cb.trueDest().lock()->llvmBB(), cb.falseDest().lock()->llvmBB() );







|







|















|











|







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

    if( !buildTerminator( inf, *pBB->terminator() ) )
        return nullptr;

    return pBB->llvmBB();
}

bool Module::buildTerminator( Infos& inf, const cir::Terminator& terminator )
{
    return visit( [&]( auto&& e )
    {
        return buildTerminator( inf, e );
    }, terminator.content() );
}

bool Module::buildTerminator( Infos& inf, const cir::Ret& r )
{
    if( !r.value() )
    {
        m_llvmBuilder.CreateRetVoid();
        return true;
    }

    auto* pRetVal = buildValue( inf, *r.value() );
    if( !pRetVal )
        return false;

    m_llvmBuilder.CreateRet( pRetVal );
    return true;
}

bool Module::buildTerminator( Infos& inf, const cir::Branch& b )
{
    m_llvmBuilder.CreateBr( b.dest().lock()->llvmBB() );

    llvm::IRBuilderBase::InsertPointGuard g( m_llvmBuilder );

    if( !buildBasicBlock( inf, b.dest().lock() ) )
        return false;

    return true;
}

bool Module::buildTerminator( Infos& inf, const cir::CondBranch& cb )
{
    auto* pCondVal = buildValue( inf, cb.cond() );
    if( !pCondVal )
        return false;

    m_llvmBuilder.CreateCondBr( pCondVal,
        cb.trueDest().lock()->llvmBB(), cb.falseDest().lock()->llvmBB() );
Changes to bs/codegen/codegen.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#ifndef GOOSE_CODEGEN_H
#define GOOSE_CODEGEN_H

#include "llvm/IR/Module.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Verifier.h"
#include "llvm/Target/TargetMachine.h"

#include "llr/llr.h"
#include "sema/sema.h"

namespace goose::builtins
{
    class Func;
    class FuncType;
}

namespace goose::codegen
{
    using namespace ir;
    using namespace llr;
    using namespace sema;

    extern llvm::LLVMContext& GetLLVMContext();
    extern optional< string > Mangle( const Term& identity );
}

#include "module.h"









|










|
|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#ifndef GOOSE_CODEGEN_H
#define GOOSE_CODEGEN_H

#include "llvm/IR/Module.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Verifier.h"
#include "llvm/Target/TargetMachine.h"

#include "cir/cir.h"
#include "sema/sema.h"

namespace goose::builtins
{
    class Func;
    class FuncType;
}

namespace goose::codegen
{
    using namespace eir;
    using namespace cir;
    using namespace sema;

    extern llvm::LLVMContext& GetLLVMContext();
    extern optional< string > Mangle( const Term& identity );
}

#include "module.h"
Changes to bs/codegen/compareops.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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#include "codegen.h"
#include "builtins/builtins.h"

using namespace goose;
using namespace goose::codegen;
using namespace goose::builtins;

llvm::Value* Module::buildInstruction( Infos& inf, const llr::Eq& bo )
{
    auto lhs = buildValue( inf, bo.lhs() );
    if( !lhs )
        return nullptr;

    auto rhs = buildValue( inf, bo.rhs() );
    if( !rhs )
        return nullptr;

    return m_llvmBuilder.CreateICmpEQ( lhs, rhs );
}

llvm::Value* Module::buildInstruction( Infos& inf, const llr::Neq& bo )
{
    auto lhs = buildValue( inf, bo.lhs() );
    if( !lhs )
        return nullptr;

    auto rhs = buildValue( inf, bo.rhs() );
    if( !rhs )
        return nullptr;

    return m_llvmBuilder.CreateICmpNE( lhs, rhs );
}

llvm::Value* Module::buildInstruction( Infos& inf, const llr::UGT& bo )
{
    auto lhs = buildValue( inf, bo.lhs() );
    if( !lhs )
        return nullptr;

    auto rhs = buildValue( inf, bo.rhs() );
    if( !rhs )
        return nullptr;

    return m_llvmBuilder.CreateICmpUGT( lhs, rhs );
}

llvm::Value* Module::buildInstruction( Infos& inf, const llr::UGE& bo )
{
    auto lhs = buildValue( inf, bo.lhs() );
    if( !lhs )
        return nullptr;

    auto rhs = buildValue( inf, bo.rhs() );
    if( !rhs )
        return nullptr;

    return m_llvmBuilder.CreateICmpUGE( lhs, rhs );
}

llvm::Value* Module::buildInstruction( Infos& inf, const llr::ULT& bo )
{
    auto lhs = buildValue( inf, bo.lhs() );
    if( !lhs )
        return nullptr;

    auto rhs = buildValue( inf, bo.rhs() );
    if( !rhs )
        return nullptr;

    return m_llvmBuilder.CreateICmpULT( lhs, rhs );
}

llvm::Value* Module::buildInstruction( Infos& inf, const llr::ULE& bo )
{
    auto lhs = buildValue( inf, bo.lhs() );
    if( !lhs )
        return nullptr;

    auto rhs = buildValue( inf, bo.rhs() );
    if( !rhs )
        return nullptr;

    return m_llvmBuilder.CreateICmpULE( lhs, rhs );
}

llvm::Value* Module::buildInstruction( Infos& inf, const llr::SGT& bo )
{
    auto lhs = buildValue( inf, bo.lhs() );
    if( !lhs )
        return nullptr;

    auto rhs = buildValue( inf, bo.rhs() );
    if( !rhs )
        return nullptr;

    return m_llvmBuilder.CreateICmpSGT( lhs, rhs );
}

llvm::Value* Module::buildInstruction( Infos& inf, const llr::SGE& bo )
{
    auto lhs = buildValue( inf, bo.lhs() );
    if( !lhs )
        return nullptr;

    auto rhs = buildValue( inf, bo.rhs() );
    if( !rhs )
        return nullptr;

    return m_llvmBuilder.CreateICmpSGE( lhs, rhs );
}

llvm::Value* Module::buildInstruction( Infos& inf, const llr::SLT& bo )
{
    auto lhs = buildValue( inf, bo.lhs() );
    if( !lhs )
        return nullptr;

    auto rhs = buildValue( inf, bo.rhs() );
    if( !rhs )
        return nullptr;

    return m_llvmBuilder.CreateICmpSLT( lhs, rhs );
}

llvm::Value* Module::buildInstruction( Infos& inf, const llr::SLE& bo )
{
    auto lhs = buildValue( inf, bo.lhs() );
    if( !lhs )
        return nullptr;

    auto rhs = buildValue( inf, bo.rhs() );
    if( !rhs )







|












|












|












|












|












|












|












|












|












|







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
#include "codegen.h"
#include "builtins/builtins.h"

using namespace goose;
using namespace goose::codegen;
using namespace goose::builtins;

llvm::Value* Module::buildInstruction( Infos& inf, const cir::Eq& bo )
{
    auto lhs = buildValue( inf, bo.lhs() );
    if( !lhs )
        return nullptr;

    auto rhs = buildValue( inf, bo.rhs() );
    if( !rhs )
        return nullptr;

    return m_llvmBuilder.CreateICmpEQ( lhs, rhs );
}

llvm::Value* Module::buildInstruction( Infos& inf, const cir::Neq& bo )
{
    auto lhs = buildValue( inf, bo.lhs() );
    if( !lhs )
        return nullptr;

    auto rhs = buildValue( inf, bo.rhs() );
    if( !rhs )
        return nullptr;

    return m_llvmBuilder.CreateICmpNE( lhs, rhs );
}

llvm::Value* Module::buildInstruction( Infos& inf, const cir::UGT& bo )
{
    auto lhs = buildValue( inf, bo.lhs() );
    if( !lhs )
        return nullptr;

    auto rhs = buildValue( inf, bo.rhs() );
    if( !rhs )
        return nullptr;

    return m_llvmBuilder.CreateICmpUGT( lhs, rhs );
}

llvm::Value* Module::buildInstruction( Infos& inf, const cir::UGE& bo )
{
    auto lhs = buildValue( inf, bo.lhs() );
    if( !lhs )
        return nullptr;

    auto rhs = buildValue( inf, bo.rhs() );
    if( !rhs )
        return nullptr;

    return m_llvmBuilder.CreateICmpUGE( lhs, rhs );
}

llvm::Value* Module::buildInstruction( Infos& inf, const cir::ULT& bo )
{
    auto lhs = buildValue( inf, bo.lhs() );
    if( !lhs )
        return nullptr;

    auto rhs = buildValue( inf, bo.rhs() );
    if( !rhs )
        return nullptr;

    return m_llvmBuilder.CreateICmpULT( lhs, rhs );
}

llvm::Value* Module::buildInstruction( Infos& inf, const cir::ULE& bo )
{
    auto lhs = buildValue( inf, bo.lhs() );
    if( !lhs )
        return nullptr;

    auto rhs = buildValue( inf, bo.rhs() );
    if( !rhs )
        return nullptr;

    return m_llvmBuilder.CreateICmpULE( lhs, rhs );
}

llvm::Value* Module::buildInstruction( Infos& inf, const cir::SGT& bo )
{
    auto lhs = buildValue( inf, bo.lhs() );
    if( !lhs )
        return nullptr;

    auto rhs = buildValue( inf, bo.rhs() );
    if( !rhs )
        return nullptr;

    return m_llvmBuilder.CreateICmpSGT( lhs, rhs );
}

llvm::Value* Module::buildInstruction( Infos& inf, const cir::SGE& bo )
{
    auto lhs = buildValue( inf, bo.lhs() );
    if( !lhs )
        return nullptr;

    auto rhs = buildValue( inf, bo.rhs() );
    if( !rhs )
        return nullptr;

    return m_llvmBuilder.CreateICmpSGE( lhs, rhs );
}

llvm::Value* Module::buildInstruction( Infos& inf, const cir::SLT& bo )
{
    auto lhs = buildValue( inf, bo.lhs() );
    if( !lhs )
        return nullptr;

    auto rhs = buildValue( inf, bo.rhs() );
    if( !rhs )
        return nullptr;

    return m_llvmBuilder.CreateICmpSLT( lhs, rhs );
}

llvm::Value* Module::buildInstruction( Infos& inf, const cir::SLE& bo )
{
    auto lhs = buildValue( inf, bo.lhs() );
    if( !lhs )
        return nullptr;

    auto rhs = buildValue( inf, bo.rhs() );
    if( !rhs )
Changes to bs/codegen/func.cpp.
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
}

llvm::Function* Module::getOrCreateFunc( const Context& c, const builtins::Func& func )
{
    if( func.isExternal() )
        return getOrCreateFunc( c, func, *func.symbol(), llvm::Function::ExternalLinkage );

    auto name = Mangle( func.llr()->identity() );
    if( !name )
        return nullptr;

    return getOrCreateFunc( c, func, *name, llvm::Function::PrivateLinkage );
}

llvm::Function* Module::getOrCreateFunc( const Context& c, const builtins::Func& func, const string& name,







|







24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
}

llvm::Function* Module::getOrCreateFunc( const Context& c, const builtins::Func& func )
{
    if( func.isExternal() )
        return getOrCreateFunc( c, func, *func.symbol(), llvm::Function::ExternalLinkage );

    auto name = Mangle( func.cir()->identity() );
    if( !name )
        return nullptr;

    return getOrCreateFunc( c, func, *name, llvm::Function::PrivateLinkage );
}

llvm::Function* Module::getOrCreateFunc( const Context& c, const builtins::Func& func, const string& name,
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

    if( func.isExternal() )
        return pllvmFunc;

    Infos inf( c );

    // Generate allocas and stores for the args
    auto pEntryBB = func.llr()->body()->entryBB();
    if( !pEntryBB->llvmBB() )
        pEntryBB->setLLVMBB( llvm::BasicBlock::Create( GetLLVMContext(), "", pllvmFunc ) );

    inf.allocaBasicBlock = pEntryBB->llvmBB();
    m_llvmBuilder.SetInsertPoint( pEntryBB->llvmBB() );

    llvm::SmallVector< NullInit< llvm::Value* >, 8 > args;







|







48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

    if( func.isExternal() )
        return pllvmFunc;

    Infos inf( c );

    // Generate allocas and stores for the args
    auto pEntryBB = func.cir()->body()->entryBB();
    if( !pEntryBB->llvmBB() )
        pEntryBB->setLLVMBB( llvm::BasicBlock::Create( GetLLVMContext(), "", pllvmFunc ) );

    inf.allocaBasicBlock = pEntryBB->llvmBB();
    m_llvmBuilder.SetInsertPoint( pEntryBB->llvmBB() );

    llvm::SmallVector< NullInit< llvm::Value* >, 8 > args;
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
    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;
}

llvm::BasicBlock* Module::buildCFG( Infos& inf, llvm::Function* llvmFunc, const ptr< llr::CFG >& pCFG )
{
    pCFG->forEachBB( [&]( auto&& pBB )
    {
        if( !pBB->llvmBB() )
            pBB->setLLVMBB( llvm::BasicBlock::Create( GetLLVMContext(), "", llvmFunc ) );
    } );

    return buildBasicBlock( inf, pCFG->entryBB() );
}







|






|









71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
    for( auto&& arg : pllvmFunc->args() )
    {
        m_llvmBuilder.CreateStore( &arg, args[i] );
        inf.temporaries->set( i, args[i] );
        ++i;
    }

    if( !buildCFG( inf, pllvmFunc, func.cir()->body() ) )
        return nullptr;

    llvm::verifyFunction( *pllvmFunc );
    return pllvmFunc;
}

llvm::BasicBlock* Module::buildCFG( Infos& inf, llvm::Function* llvmFunc, const ptr< cir::CFG >& pCFG )
{
    pCFG->forEachBB( [&]( auto&& pBB )
    {
        if( !pBB->llvmBB() )
            pBB->setLLVMBB( llvm::BasicBlock::Create( GetLLVMContext(), "", llvmFunc ) );
    } );

    return buildBasicBlock( inf, pCFG->entryBB() );
}
Changes to bs/codegen/instructions.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include "codegen.h"
#include "builtins/builtins.h"

using namespace goose;
using namespace goose::codegen;
using namespace goose::builtins;

llvm::Value* Module::buildInstruction( Infos& inf, const llr::Instruction& instr )
{
    return visit( [&]( auto&& e )
    {
        return buildInstruction( inf, e );
    }, instr.content() );
}

llvm::Value* Module::buildInstruction( Infos& inf, const llr::Call& call )
{
    const auto& callee = call.func();
    if( IsBuiltinFunc( callee ) || IsIntrinsicFunc( callee ) )
    {
        DiagnosticsManager::GetInstance().emitErrorMessage(
            callee.locationId(), "builtin functions can't be called at runtime." );
    }







|







|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include "codegen.h"
#include "builtins/builtins.h"

using namespace goose;
using namespace goose::codegen;
using namespace goose::builtins;

llvm::Value* Module::buildInstruction( Infos& inf, const cir::Instruction& instr )
{
    return visit( [&]( auto&& e )
    {
        return buildInstruction( inf, e );
    }, instr.content() );
}

llvm::Value* Module::buildInstruction( Infos& inf, const cir::Call& call )
{
    const auto& callee = call.func();
    if( IsBuiltinFunc( callee ) || IsIntrinsicFunc( callee ) )
    {
        DiagnosticsManager::GetInstance().emitErrorMessage(
            callee.locationId(), "builtin functions can't be called at runtime." );
    }
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77

        args.emplace_back( parg );
    }

    return m_llvmBuilder.CreateCall( llvm::FunctionCallee( 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;
}







|




|







58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77

        args.emplace_back( parg );
    }

    return m_llvmBuilder.CreateCall( llvm::FunctionCallee( llvmCallee ), args );
}

llvm::Value* Module::buildInstruction( Infos& inf, const cir::CreateTemporary& ct )
{
    return createTemporary( inf, ct.index(), buildValue( inf, ct.value() ) );
}

llvm::Value* Module::buildInstruction( Infos& inf, const cir::GetTemporary& gt )
{
    auto* ppVal = inf.temporaries->get( gt.index() );
    assert( ppVal );
    if( !ppVal )
        return nullptr;
    return *ppVal;
}
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
        m_llvmBuilder.SetInsertPoint( inf.allocaBasicBlock, inf.allocaBasicBlock->begin() );

    inf.lastEmittedAlloca = m_llvmBuilder.CreateAlloca( type );

    return inf.lastEmittedAlloca;
}

llvm::Value* Module::buildInstruction( Infos& inf, const llr::AllocVar& av )
{
    auto type = LowerTypeForRuntime( inf.context, av.type() );
    if( !type )
        return nullptr;

    auto* pAlloca = buildAlloca( inf, GetLLVMType( *type ) );
    createTemporary( inf, av.index(), pAlloca );
    return pAlloca;
}

llvm::Value* Module::buildInstruction( Infos& inf, const llr::Load& load )
{
    auto type = LowerTypeForRuntime( inf.context, *ValueFromIRExpr( load.type() ) );
    if( !type )
        return nullptr;

    auto* llvmType = GetLLVMType( *type );
    assert( llvmType );

    auto* ptrVal = buildValue(inf, load.addr() );//  buildAddress( inf, load.addr() );
    return m_llvmBuilder.CreateLoad( llvmType, ptrVal );
}

llvm::Value* Module::buildInstruction( Infos& inf, const llr::Store& store )
{
    auto* pValue = buildValue( inf, store.val() );
    if( !pValue )
        return nullptr;

    auto* ptrVal = buildValue(inf, store.addr() );








|










|












|







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
        m_llvmBuilder.SetInsertPoint( inf.allocaBasicBlock, inf.allocaBasicBlock->begin() );

    inf.lastEmittedAlloca = m_llvmBuilder.CreateAlloca( type );

    return inf.lastEmittedAlloca;
}

llvm::Value* Module::buildInstruction( Infos& inf, const cir::AllocVar& av )
{
    auto type = LowerTypeForRuntime( inf.context, av.type() );
    if( !type )
        return nullptr;

    auto* pAlloca = buildAlloca( inf, GetLLVMType( *type ) );
    createTemporary( inf, av.index(), pAlloca );
    return pAlloca;
}

llvm::Value* Module::buildInstruction( Infos& inf, const cir::Load& load )
{
    auto type = LowerTypeForRuntime( inf.context, *ValueFromIRExpr( load.type() ) );
    if( !type )
        return nullptr;

    auto* llvmType = GetLLVMType( *type );
    assert( llvmType );

    auto* ptrVal = buildValue(inf, load.addr() );//  buildAddress( inf, load.addr() );
    return m_llvmBuilder.CreateLoad( llvmType, ptrVal );
}

llvm::Value* Module::buildInstruction( Infos& inf, const cir::Store& store )
{
    auto* pValue = buildValue( inf, store.val() );
    if( !pValue )
        return nullptr;

    auto* ptrVal = buildValue(inf, store.addr() );

142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
        return m_llvmBuilder.CreateMemCpy( ptrVal, llvm::None, pGlob, llvm::None,
            llvm::ConstantInt::get( llvm::Type::getInt32Ty( GetLLVMContext() ), size ) );
    }

    return m_llvmBuilder.CreateStore( pValue, ptrVal );
}

llvm::Value* Module::buildInstruction( Infos& inf, const llr::Phi& p )
{
    auto type = LowerTypeForRuntime( inf.context, p.type() );
    if( !type )
        return nullptr;

    auto* pPHI = m_llvmBuilder.CreatePHI( GetLLVMType( *type ), p.numIncomings() );
    if( !pPHI )







|







142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
        return m_llvmBuilder.CreateMemCpy( ptrVal, llvm::None, pGlob, llvm::None,
            llvm::ConstantInt::get( llvm::Type::getInt32Ty( GetLLVMContext() ), size ) );
    }

    return m_llvmBuilder.CreateStore( pValue, ptrVal );
}

llvm::Value* Module::buildInstruction( Infos& inf, const cir::Phi& p )
{
    auto type = LowerTypeForRuntime( inf.context, p.type() );
    if( !type )
        return nullptr;

    auto* pPHI = m_llvmBuilder.CreatePHI( GetLLVMType( *type ), p.numIncomings() );
    if( !pPHI )
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196

    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() ),
        lcs.str().size() + 1 );

    auto it = m_strings.find( lcs.str() );







|







182
183
184
185
186
187
188
189
190
191
192
193
194
195
196

    if( !pPHI )
        return nullptr;

    return createTemporary( inf, p.destIndex(), pPHI );
}

llvm::Value* Module::buildInstruction( Infos& inf, const cir::LoadConstStr& lcs )
{
    llvm::GlobalVariable* pGlob = nullptr;

    auto* arType = llvm::ArrayType::get( llvm::IntegerType::getInt8Ty( GetLLVMContext() ),
        lcs.str().size() + 1 );

    auto it = m_strings.find( lcs.str() );
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
        llvm::ConstantInt::get( llvm::Type::getInt8Ty( GetLLVMContext() ), 0 ),
        llvm::ConstantInt::get( llvm::Type::getInt8Ty( GetLLVMContext() ), 0 )
    };

    return m_llvmBuilder.CreateGEP( pGlob, idxs );
}

llvm::Value* Module::buildInstruction( Infos& inf, const llr::Assert& ass )
{
    // We can't just return null as it is considered an error by the rest of the code.
    // Since the assert instruction will only appear in a cfg instruction list, this
    // will not actually be used anyway.
    return llvm::ConstantInt::getTrue( GetLLVMContext() );
}

llvm::Value* Module::buildInstruction( Infos& inf, const llr::Placeholder& ph )
{
    // Same as above.
    return llvm::ConstantInt::getTrue( GetLLVMContext() );
}







|







|




214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
        llvm::ConstantInt::get( llvm::Type::getInt8Ty( GetLLVMContext() ), 0 ),
        llvm::ConstantInt::get( llvm::Type::getInt8Ty( GetLLVMContext() ), 0 )
    };

    return m_llvmBuilder.CreateGEP( pGlob, idxs );
}

llvm::Value* Module::buildInstruction( Infos& inf, const cir::Assert& ass )
{
    // We can't just return null as it is considered an error by the rest of the code.
    // Since the assert instruction will only appear in a cfg instruction list, this
    // will not actually be used anyway.
    return llvm::ConstantInt::getTrue( GetLLVMContext() );
}

llvm::Value* Module::buildInstruction( Infos& inf, const cir::Placeholder& ph )
{
    // Same as above.
    return llvm::ConstantInt::getTrue( GetLLVMContext() );
}
Changes to bs/codegen/logicops.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
#include "codegen.h"
#include "builtins/builtins.h"

using namespace goose;
using namespace goose::codegen;
using namespace goose::builtins;

llvm::Value* Module::buildInstruction( Infos& inf, const llr::Not& uo )
{
    auto operand = buildValue( inf, uo.operand() );
    if( !operand )
        return nullptr;

    return m_llvmBuilder.CreateXor( operand, llvm::ConstantInt::getTrue( GetLLVMContext() ) );
}

llvm::Value* Module::buildInstruction( Infos& inf, const llr::And& bo )
{
    auto lhs = buildValue( inf, bo.lhs() );
    if( !lhs )
        return nullptr;

    auto rhs = buildValue( inf, bo.rhs() );
    if( !rhs )
        return nullptr;

    return m_llvmBuilder.CreateAnd( lhs, rhs );
}

llvm::Value* Module::buildInstruction( Infos& inf, const llr::Or& bo )
{
    auto lhs = buildValue( inf, bo.lhs() );
    if( !lhs )
        return nullptr;

    auto rhs = buildValue( inf, bo.rhs() );
    if( !rhs )
        return nullptr;

    return m_llvmBuilder.CreateOr( lhs, rhs );
}

llvm::Value* Module::buildInstruction( Infos& inf, const llr::Xor& bo )
{
    auto lhs = buildValue( inf, bo.lhs() );
    if( !lhs )
        return nullptr;

    auto rhs = buildValue( inf, bo.rhs() );
    if( !rhs )
        return nullptr;

    return m_llvmBuilder.CreateXor( lhs, rhs );
}

llvm::Value* Module::buildInstruction( Infos& inf, const llr::Shl& bo )
{
    auto lhs = buildValue( inf, bo.lhs() );
    if( !lhs )
        return nullptr;

    auto rhs = buildValue( inf, bo.rhs() );
    if( !rhs )
        return nullptr;

    return m_llvmBuilder.CreateShl( lhs, rhs );
}

llvm::Value* Module::buildInstruction( Infos& inf, const llr::LShr& bo )
{
    auto lhs = buildValue( inf, bo.lhs() );
    if( !lhs )
        return nullptr;

    auto rhs = buildValue( inf, bo.rhs() );
    if( !rhs )
        return nullptr;

    return m_llvmBuilder.CreateLShr( lhs, rhs );
}

llvm::Value* Module::buildInstruction( Infos& inf, const llr::AShr& bo )
{
    auto lhs = buildValue( inf, bo.lhs() );
    if( !lhs )
        return nullptr;

    auto rhs = buildValue( inf, bo.rhs() );
    if( !rhs )







|








|












|












|












|












|












|







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
#include "codegen.h"
#include "builtins/builtins.h"

using namespace goose;
using namespace goose::codegen;
using namespace goose::builtins;

llvm::Value* Module::buildInstruction( Infos& inf, const cir::Not& uo )
{
    auto operand = buildValue( inf, uo.operand() );
    if( !operand )
        return nullptr;

    return m_llvmBuilder.CreateXor( operand, llvm::ConstantInt::getTrue( GetLLVMContext() ) );
}

llvm::Value* Module::buildInstruction( Infos& inf, const cir::And& bo )
{
    auto lhs = buildValue( inf, bo.lhs() );
    if( !lhs )
        return nullptr;

    auto rhs = buildValue( inf, bo.rhs() );
    if( !rhs )
        return nullptr;

    return m_llvmBuilder.CreateAnd( lhs, rhs );
}

llvm::Value* Module::buildInstruction( Infos& inf, const cir::Or& bo )
{
    auto lhs = buildValue( inf, bo.lhs() );
    if( !lhs )
        return nullptr;

    auto rhs = buildValue( inf, bo.rhs() );
    if( !rhs )
        return nullptr;

    return m_llvmBuilder.CreateOr( lhs, rhs );
}

llvm::Value* Module::buildInstruction( Infos& inf, const cir::Xor& bo )
{
    auto lhs = buildValue( inf, bo.lhs() );
    if( !lhs )
        return nullptr;

    auto rhs = buildValue( inf, bo.rhs() );
    if( !rhs )
        return nullptr;

    return m_llvmBuilder.CreateXor( lhs, rhs );
}

llvm::Value* Module::buildInstruction( Infos& inf, const cir::Shl& bo )
{
    auto lhs = buildValue( inf, bo.lhs() );
    if( !lhs )
        return nullptr;

    auto rhs = buildValue( inf, bo.rhs() );
    if( !rhs )
        return nullptr;

    return m_llvmBuilder.CreateShl( lhs, rhs );
}

llvm::Value* Module::buildInstruction( Infos& inf, const cir::LShr& bo )
{
    auto lhs = buildValue( inf, bo.lhs() );
    if( !lhs )
        return nullptr;

    auto rhs = buildValue( inf, bo.rhs() );
    if( !rhs )
        return nullptr;

    return m_llvmBuilder.CreateLShr( lhs, rhs );
}

llvm::Value* Module::buildInstruction( Infos& inf, const cir::AShr& bo )
{
    auto lhs = buildValue( inf, bo.lhs() );
    if( !lhs )
        return nullptr;

    auto rhs = buildValue( inf, bo.rhs() );
    if( !rhs )
Changes to bs/codegen/mangle.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
#include "codegen.h"

using namespace goose;
using namespace goose::ir;

// Mangling scheme:
//
// Functions, types and everything are uniquely identified by IR expressions
// (built out of ir::Term objects) called Identities.
// The mangling scheme is therefore a lossless text serialization of such an identity,
// with a simple compression scheme to make it shorter.
//
// All integers serialized as part of this scheme are in hex.
//
// Each element is introduced by one character. Hex digits (0-9, a-f) can't be used as
// intro characters.
//
// Literal elements:
//   i: integer, followed by its value
//   S: string, followed by its length, followed by ':', followed by the string itself.
//   n: anonymous StringId, followed by its unique id
//   s: StringId, followed by its length, followed by ':', followed by the string itself.
//   _ followed by an hex number: vector, whose length is that number,
//     followed by its contained elements, serialized recursively.
//   @ same as above, but the vector is of variable length and is followed by the repetition element.
//   p, P: a void* or ptr< void > term (unfortunately they have legitimate uses in some type identitiers
//      that we do need to be able to mangle)
//   x: an ir term placeholder.
//
// $: compressed string id: it is followed by the 0 based index of a previously encountered
//   StringId literal, in the order they were encountered.
//
// The letters V, o, v, t, q, u, r:
//   respectively the StringIDs: Value, Constant, void, type,
//   quote, func, param.



|




|


















|







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
#include "codegen.h"

using namespace goose;
using namespace goose::eir;

// Mangling scheme:
//
// Functions, types and everything are uniquely identified by IR expressions
// (built out of eir::Term objects) called Identities.
// The mangling scheme is therefore a lossless text serialization of such an identity,
// with a simple compression scheme to make it shorter.
//
// All integers serialized as part of this scheme are in hex.
//
// Each element is introduced by one character. Hex digits (0-9, a-f) can't be used as
// intro characters.
//
// Literal elements:
//   i: integer, followed by its value
//   S: string, followed by its length, followed by ':', followed by the string itself.
//   n: anonymous StringId, followed by its unique id
//   s: StringId, followed by its length, followed by ':', followed by the string itself.
//   _ followed by an hex number: vector, whose length is that number,
//     followed by its contained elements, serialized recursively.
//   @ same as above, but the vector is of variable length and is followed by the repetition element.
//   p, P: a void* or ptr< void > term (unfortunately they have legitimate uses in some type identitiers
//      that we do need to be able to mangle)
//   x: an eir term placeholder.
//
// $: compressed string id: it is followed by the 0 based index of a previously encountered
//   StringId literal, in the order they were encountered.
//
// The letters V, o, v, t, q, u, r:
//   respectively the StringIDs: Value, Constant, void, type,
//   quote, func, param.
Changes to bs/codegen/module.h.
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
            {
                Infos( const Context& c ) : context( c ) {}
                const Context& context;

                llvm::BasicBlock* allocaBasicBlock = nullptr;
                llvm::AllocaInst* lastEmittedAlloca = nullptr;

                using storage_type = llr::TempStorage< NullInit< llvm::Value* > >;
                ptr< storage_type > temporaries = make_shared< storage_type >();
            };

            llvm::Function* getCurrentFunction() const
            {
                return m_llvmBuilder.GetInsertBlock()->getParent();
            }

            llvm::BasicBlock* buildCFG( Infos& inf, llvm::Function* llvmFunc, const ptr< llr::CFG >& pCFG );
            llvm::BasicBlock* buildBasicBlock( Infos& inf, const ptr< llr::BasicBlock >& pBB );

            llvm::Value* buildValue( Infos& inf, const Value& val );
            llvm::Constant* buildConstant( Infos& inf, const Value& val );

            llvm::Value* buildInstruction( Infos& inf, const llr::Instruction& instr );
            llvm::Value* buildInstruction( Infos& inf, const llr::Call& call );
            llvm::Value* buildInstruction( Infos& inf, const llr::CalcAddress& ct );
            llvm::Value* buildInstruction( Infos& inf, const llr::CreateTemporary& ct );
            llvm::Value* buildInstruction( Infos& inf, const llr::GetTemporary& gt );
            llvm::Value* buildInstruction( Infos& inf, const llr::AllocVar& av );
            llvm::Value* buildInstruction( Infos& inf, const llr::Load& load );
            llvm::Value* buildInstruction( Infos& inf, const llr::Store& store );
            llvm::Value* buildInstruction( Infos& inf, const llr::Phi& p );
            llvm::Value* buildInstruction( Infos& inf, const llr::LoadConstStr& lcs );

            llvm::Value* buildInstruction( Infos& inf, const llr::Not& uo );
            llvm::Value* buildInstruction( Infos& inf, const llr::And& bo );
            llvm::Value* buildInstruction( Infos& inf, const llr::Or& bo );
            llvm::Value* buildInstruction( Infos& inf, const llr::Xor& bo );
            llvm::Value* buildInstruction( Infos& inf, const llr::Shl& bo );
            llvm::Value* buildInstruction( Infos& inf, const llr::LShr& bo );
            llvm::Value* buildInstruction( Infos& inf, const llr::AShr& bo );

            llvm::Value* buildInstruction( Infos& inf, const llr::Add& bo );
            llvm::Value* buildInstruction( Infos& inf, const llr::Sub& bo );
            llvm::Value* buildInstruction( Infos& inf, const llr::Mul& bo );
            llvm::Value* buildInstruction( Infos& inf, const llr::UDiv& bo );
            llvm::Value* buildInstruction( Infos& inf, const llr::SDiv& bo );
            llvm::Value* buildInstruction( Infos& inf, const llr::URem& bo );
            llvm::Value* buildInstruction( Infos& inf, const llr::SRem& bo );

            llvm::Value* buildInstruction( Infos& inf, const llr::Eq& bo );
            llvm::Value* buildInstruction( Infos& inf, const llr::Neq& bo );
            llvm::Value* buildInstruction( Infos& inf, const llr::UGT& bo );
            llvm::Value* buildInstruction( Infos& inf, const llr::UGE& bo );
            llvm::Value* buildInstruction( Infos& inf, const llr::ULT& bo );
            llvm::Value* buildInstruction( Infos& inf, const llr::ULE& bo );
            llvm::Value* buildInstruction( Infos& inf, const llr::SGT& bo );
            llvm::Value* buildInstruction( Infos& inf, const llr::SGE& bo );
            llvm::Value* buildInstruction( Infos& inf, const llr::SLT& bo );
            llvm::Value* buildInstruction( Infos& inf, const llr::SLE& bo );

            llvm::Value* buildInstruction( Infos& inf, const llr::Assert& ass );
            llvm::Value* buildInstruction( Infos& inf, const llr::Placeholder& ph );

            bool buildTerminator( Infos& inf, const llr::Terminator& terminator );
            bool buildTerminator( Infos& inf, const llr::Ret& r );
            bool buildTerminator( Infos& inf, const llr::Branch& b );
            bool buildTerminator( Infos& inf, const llr::CondBranch& cb );

            template< typename T >
            bool buildTerminator( Infos& inf, const T& t )
            {
                return false;
            }








|








|
|




|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|

|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|

|
|

|
|
|
|







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
            {
                Infos( const Context& c ) : context( c ) {}
                const Context& context;

                llvm::BasicBlock* allocaBasicBlock = nullptr;
                llvm::AllocaInst* lastEmittedAlloca = nullptr;

                using storage_type = cir::TempStorage< NullInit< llvm::Value* > >;
                ptr< storage_type > temporaries = make_shared< storage_type >();
            };

            llvm::Function* getCurrentFunction() const
            {
                return m_llvmBuilder.GetInsertBlock()->getParent();
            }

            llvm::BasicBlock* buildCFG( Infos& inf, llvm::Function* llvmFunc, const ptr< cir::CFG >& pCFG );
            llvm::BasicBlock* buildBasicBlock( Infos& inf, const ptr< cir::BasicBlock >& pBB );

            llvm::Value* buildValue( Infos& inf, const Value& val );
            llvm::Constant* buildConstant( Infos& inf, const Value& val );

            llvm::Value* buildInstruction( Infos& inf, const cir::Instruction& instr );
            llvm::Value* buildInstruction( Infos& inf, const cir::Call& call );
            llvm::Value* buildInstruction( Infos& inf, const cir::CalcAddress& ct );
            llvm::Value* buildInstruction( Infos& inf, const cir::CreateTemporary& ct );
            llvm::Value* buildInstruction( Infos& inf, const cir::GetTemporary& gt );
            llvm::Value* buildInstruction( Infos& inf, const cir::AllocVar& av );
            llvm::Value* buildInstruction( Infos& inf, const cir::Load& load );
            llvm::Value* buildInstruction( Infos& inf, const cir::Store& store );
            llvm::Value* buildInstruction( Infos& inf, const cir::Phi& p );
            llvm::Value* buildInstruction( Infos& inf, const cir::LoadConstStr& lcs );

            llvm::Value* buildInstruction( Infos& inf, const cir::Not& uo );
            llvm::Value* buildInstruction( Infos& inf, const cir::And& bo );
            llvm::Value* buildInstruction( Infos& inf, const cir::Or& bo );
            llvm::Value* buildInstruction( Infos& inf, const cir::Xor& bo );
            llvm::Value* buildInstruction( Infos& inf, const cir::Shl& bo );
            llvm::Value* buildInstruction( Infos& inf, const cir::LShr& bo );
            llvm::Value* buildInstruction( Infos& inf, const cir::AShr& bo );

            llvm::Value* buildInstruction( Infos& inf, const cir::Add& bo );
            llvm::Value* buildInstruction( Infos& inf, const cir::Sub& bo );
            llvm::Value* buildInstruction( Infos& inf, const cir::Mul& bo );
            llvm::Value* buildInstruction( Infos& inf, const cir::UDiv& bo );
            llvm::Value* buildInstruction( Infos& inf, const cir::SDiv& bo );
            llvm::Value* buildInstruction( Infos& inf, const cir::URem& bo );
            llvm::Value* buildInstruction( Infos& inf, const cir::SRem& bo );

            llvm::Value* buildInstruction( Infos& inf, const cir::Eq& bo );
            llvm::Value* buildInstruction( Infos& inf, const cir::Neq& bo );
            llvm::Value* buildInstruction( Infos& inf, const cir::UGT& bo );
            llvm::Value* buildInstruction( Infos& inf, const cir::UGE& bo );
            llvm::Value* buildInstruction( Infos& inf, const cir::ULT& bo );
            llvm::Value* buildInstruction( Infos& inf, const cir::ULE& bo );
            llvm::Value* buildInstruction( Infos& inf, const cir::SGT& bo );
            llvm::Value* buildInstruction( Infos& inf, const cir::SGE& bo );
            llvm::Value* buildInstruction( Infos& inf, const cir::SLT& bo );
            llvm::Value* buildInstruction( Infos& inf, const cir::SLE& bo );

            llvm::Value* buildInstruction( Infos& inf, const cir::Assert& ass );
            llvm::Value* buildInstruction( Infos& inf, const cir::Placeholder& ph );

            bool buildTerminator( Infos& inf, const cir::Terminator& terminator );
            bool buildTerminator( Infos& inf, const cir::Ret& r );
            bool buildTerminator( Infos& inf, const cir::Branch& b );
            bool buildTerminator( Infos& inf, const cir::CondBranch& cb );

            template< typename T >
            bool buildTerminator( Infos& inf, const T& t )
            {
                return false;
            }

Changes to bs/codegen/value.cpp.
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{
    if( val.isPoison() )
        return nullptr;

    if( val.isConstant() )
        return buildConstant( inf, val );

    return buildInstruction( inf, *val.llr() );
}

llvm::Constant* Module::buildConstant( Infos& inf, const Value& v )
{
    assert( v.isConstant() );

    auto val = LowerConstantForRuntime( inf.context, v );







|







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{
    if( val.isPoison() )
        return nullptr;

    if( val.isConstant() )
        return buildConstant( inf, val );

    return buildInstruction( inf, *val.cir() );
}

llvm::Constant* Module::buildConstant( Infos& inf, const Value& v )
{
    assert( v.isConstant() );

    auto val = LowerConstantForRuntime( inf.context, v );
Changes to bs/compile/compiler.cpp.
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include "llvm/Support/TargetSelect.h"

#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Signals.h"

using namespace goose;
using namespace goose::util;
using namespace goose::ir;
using namespace goose::sema;
using namespace goose::diagnostics;
using namespace goose::builtins;

namespace goose::compile
{
    Compiler::Compiler( int argc, char** argv ) :







|







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include "llvm/Support/TargetSelect.h"

#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Signals.h"

using namespace goose;
using namespace goose::util;
using namespace goose::eir;
using namespace goose::sema;
using namespace goose::diagnostics;
using namespace goose::builtins;

namespace goose::compile
{
    Compiler::Compiler( int argc, char** argv ) :
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
            return PoisonValue();
        }

        execute::VM vm;
        return vm.execute( cfg->entryBB() );
    }

    ptr< llr::CFG > Compiler::LoadAndParseFile( const ptr< Env >& e, const string& filename, const Term& identity,
        const Term& returnType, optional< Value > defRetVal )
    {
        auto& dm = DiagnosticsManager::GetInstance();

        assert( returnType == GetValueType< void >() || defRetVal );

        ifstream sourcefile( filename.c_str() );
        if( !sourcefile.good() )
        {
            dm.emitErrorMessage( 0,
                format( "can't open '{}'.", filename ) );
            return nullptr;
        }

        sema::Context c( e, identity, returnType );
        DiagnosticsContext dc( 0, true );
        VerbosityContext vc( Verbosity::Normal, true );

        auto cfg = make_shared< llr::CFG >( 0 );
        cfg->createBB();
        cfg->setCurrentBB( cfg->entryBB() );

        auto cb = make_shared< CodeBuilder >( cfg );
        c.setBuilder( cb );

        auto r = make_shared< parse::Resolver >(







|


















|







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
            return PoisonValue();
        }

        execute::VM vm;
        return vm.execute( cfg->entryBB() );
    }

    ptr< cir::CFG > Compiler::LoadAndParseFile( const ptr< Env >& e, const string& filename, const Term& identity,
        const Term& returnType, optional< Value > defRetVal )
    {
        auto& dm = DiagnosticsManager::GetInstance();

        assert( returnType == GetValueType< void >() || defRetVal );

        ifstream sourcefile( filename.c_str() );
        if( !sourcefile.good() )
        {
            dm.emitErrorMessage( 0,
                format( "can't open '{}'.", filename ) );
            return nullptr;
        }

        sema::Context c( e, identity, returnType );
        DiagnosticsContext dc( 0, true );
        VerbosityContext vc( Verbosity::Normal, true );

        auto cfg = make_shared< cir::CFG >( 0 );
        cfg->createBB();
        cfg->setCurrentBB( cfg->entryBB() );

        auto cb = make_shared< CodeBuilder >( cfg );
        c.setBuilder( cb );

        auto r = make_shared< parse::Resolver >(
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150

        if( cfg->currentBB() && !cfg->currentBB()->terminator() )
        {
            p.flushValue();
            cb->destroyAllLiveValues( c );

            if( returnType == GetValueType< void >() )
               cb->emitTerminator( r->currentLocation(), llr::Ret() );
            else if( !defRetVal )
            {
                dm.emitSyntaxErrorMessage( r->currentLocation(), "missing return statement." );
                return nullptr;
            }
            else
            {







|







136
137
138
139
140
141
142
143
144
145
146
147
148
149
150

        if( cfg->currentBB() && !cfg->currentBB()->terminator() )
        {
            p.flushValue();
            cb->destroyAllLiveValues( c );

            if( returnType == GetValueType< void >() )
               cb->emitTerminator( r->currentLocation(), cir::Ret() );
            else if( !defRetVal )
            {
                dm.emitSyntaxErrorMessage( r->currentLocation(), "missing return statement." );
                return nullptr;
            }
            else
            {
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
                            dm.emitErrorMessage( defRetVal->locationId(), "ambiguous default return value conversion." );
                            break;
                    }

                    return nullptr;
                }

                cb->emitTerminator( r->currentLocation(), llr::Ret( get< Value >( converted ) ) );
            }
        }

        verify::Func fv( c, cfg );
        if( !fv.verify() )
            return nullptr;

        return cfg;
    }
}







|










161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
                            dm.emitErrorMessage( defRetVal->locationId(), "ambiguous default return value conversion." );
                            break;
                    }

                    return nullptr;
                }

                cb->emitTerminator( r->currentLocation(), cir::Ret( get< Value >( converted ) ) );
            }
        }

        verify::Func fv( c, cfg );
        if( !fv.verify() )
            return nullptr;

        return cfg;
    }
}
Changes to bs/compile/compiler.h.
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

    class Compiler
    {
        public:
            Compiler( int argc, char** argv );
            uint32_t execute( const string& filename );

            static optional< ir::Value > LoadAndExecuteFile( const util::ptr< sema::Env >& e, const string& filename,
                const ir::Term& identity, const ir::Term& returnType, optional< ir::Value > defRetVal );

            static util::ptr< llr::CFG > LoadAndParseFile( const util::ptr< sema::Env >& e, const string& filename,
                const ir::Term& identity, const ir::Term& returnType, optional< ir::Value > defRetVal );

        private:
            util::ptr< sema::Env > m_pEnv;
    };
}

#endif







|
|

|
|







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

    class Compiler
    {
        public:
            Compiler( int argc, char** argv );
            uint32_t execute( const string& filename );

            static optional< eir::Value > LoadAndExecuteFile( const util::ptr< sema::Env >& e, const string& filename,
                const eir::Term& identity, const eir::Term& returnType, optional< eir::Value > defRetVal );

            static util::ptr< cir::CFG > LoadAndParseFile( const util::ptr< sema::Env >& e, const string& filename,
                const eir::Term& identity, const eir::Term& returnType, optional< eir::Value > defRetVal );

        private:
            util::ptr< sema::Env > m_pEnv;
    };
}

#endif
Changes to bs/diagnostics/diagnostics.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#ifndef GOOSE_DIAGNOSTICS_H
#define GOOSE_DIAGNOSTICS_H

#include "ir/ir.h"

namespace goose::diagnostics
{
    using namespace ir;
}

#include "location.h"
#include "renderer.h"
#include "diagnosticsmanager.h"
#include "diagnosticscontext.h"
#include "verbositycontext.h"



|



|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#ifndef GOOSE_DIAGNOSTICS_H
#define GOOSE_DIAGNOSTICS_H

#include "eir/eir.h"

namespace goose::diagnostics
{
    using namespace eir;
}

#include "location.h"
#include "renderer.h"
#include "diagnosticsmanager.h"
#include "diagnosticscontext.h"
#include "verbositycontext.h"
Name change from bs/ir/anyterm.h to bs/eir/anyterm.h.
1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_IR_ANYTERM_H
#define GOOSE_IR_ANYTERM_H

namespace goose::ir
{
    class AnyTerm
    {
        public:
            template< typename S >
            AnyTerm( S&& varName ) :
                m_varName( varName )
|
|

|







1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_EIR_ANYTERM_H
#define GOOSE_EIR_ANYTERM_H

namespace goose::eir
{
    class AnyTerm
    {
        public:
            template< typename S >
            AnyTerm( S&& varName ) :
                m_varName( varName )
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
        private:
            StringId m_varName;
    };
}

namespace std
{
    template<> struct hash< goose::ir::AnyTerm >
    {
        size_t operator()( const goose::ir::AnyTerm& x ) const
        {
            return hash< goose::util::StringId >()( x.varName() );
        }
    };
}

#endif







|

|







24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
        private:
            StringId m_varName;
    };
}

namespace std
{
    template<> struct hash< goose::eir::AnyTerm >
    {
        size_t operator()( const goose::eir::AnyTerm& x ) const
        {
            return hash< goose::util::StringId >()( x.varName() );
        }
    };
}

#endif
Name change from bs/ir/bridge.h to bs/eir/bridge.h.
1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_IR_BRIDGE_H
#define GOOSE_IR_BRIDGE_H

namespace goose::ir
{
    template< typename T >
    struct Bridge
    {};

    template< typename T, typename... P >
    auto GetValueType( P&&... params )
|
|

|







1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_EIR_BRIDGE_H
#define GOOSE_EIR_BRIDGE_H

namespace goose::eir
{
    template< typename T >
    struct Bridge
    {};

    template< typename T, typename... P >
    auto GetValueType( P&&... params )
Name change from bs/ir/compare.cpp to bs/eir/compare.cpp.
1
2
3
4
5
6
7
8
9
10
#include "ir.h"

namespace goose::ir
{
    bool Compare( const Trie<>& lhs, const Trie<>& rhs )
    {
        return Compare<>( lhs, rhs, []( auto&&, auto&& ){ return true; } );
    }

    bool operator==( const Term& lhs, const Term& rhs )
|

|







1
2
3
4
5
6
7
8
9
10
#include "eir.h"

namespace goose::eir
{
    bool Compare( const Trie<>& lhs, const Trie<>& rhs )
    {
        return Compare<>( lhs, rhs, []( auto&&, auto&& ){ return true; } );
    }

    bool operator==( const Term& lhs, const Term& rhs )
Name change from bs/ir/compare.h to bs/eir/compare.h.
1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_IR_COMPARE_H
#define GOOSE_IR_COMPARE_H

namespace goose::ir
{
    template< typename U, typename F >
    static bool Compare( const Trie< U >& lhs, const Trie< U >& rhs, F&& next );

    extern bool Compare( const Trie<>& lhs, const Trie<>& rhs );

    extern bool operator==( const Term& lhs, const Term& rhs );
|
|

|







1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_EIR_COMPARE_H
#define GOOSE_EIR_COMPARE_H

namespace goose::eir
{
    template< typename U, typename F >
    static bool Compare( const Trie< U >& lhs, const Trie< U >& rhs, F&& next );

    extern bool Compare( const Trie<>& lhs, const Trie<>& rhs );

    extern bool operator==( const Term& lhs, const Term& rhs );
Name change from bs/ir/compare.inl to bs/eir/compare.inl.
1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_IR_COMPARE_INL
#define GOOSE_IR_COMPARE_INL

namespace goose::ir
{
    //--------------------------------------------------------------------------------------------
    // Primitive types
    //--------------------------------------------------------------------------------------------
    template< typename T, typename U, typename F >
    static bool Compare( const ValueTrieNode< T, U >& lhs, const ValueTrieNode< T, U >& rhs, F&& next )
    {
|
|

|







1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_EIR_COMPARE_INL
#define GOOSE_EIR_COMPARE_INL

namespace goose::eir
{
    //--------------------------------------------------------------------------------------------
    // Primitive types
    //--------------------------------------------------------------------------------------------
    template< typename T, typename U, typename F >
    static bool Compare( const ValueTrieNode< T, U >& lhs, const ValueTrieNode< T, U >& rhs, F&& next )
    {
Name change from bs/ir/decompose.h to bs/eir/decompose.h.
1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_IR_DECOMPOSE_H
#define GOOSE_IR_DECOMPOSE_H

namespace goose::ir
{
    template< typename T >
    struct LiteralSpec
    {
        using return_type = bool;

        template< typename TT >
|
|

|







1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_EIR_DECOMPOSE_H
#define GOOSE_EIR_DECOMPOSE_H

namespace goose::eir
{
    template< typename T >
    struct LiteralSpec
    {
        using return_type = bool;

        template< typename TT >
Name change from bs/ir/decompose.inl to bs/eir/decompose.inl.
1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_IR_DECOMPOSE_INL
#define GOOSE_IR_DECOMPOSE_INL

namespace goose::ir
{
    template< typename T >
    auto Lit( T&& val )
    {
        return LiteralSpec< T >( forward< T >( val ) );
    }

|
|

|







1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_EIR_DECOMPOSE_INL
#define GOOSE_EIR_DECOMPOSE_INL

namespace goose::eir
{
    template< typename T >
    auto Lit( T&& val )
    {
        return LiteralSpec< T >( forward< T >( val ) );
    }

Name change from bs/ir/ir.h to bs/eir/eir.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
#ifndef GOOSE_IR_H
#define GOOSE_IR_H

#include "util/util.h"

namespace goose::ir
{
    using namespace util;

    struct EmptyPayload {};

    template< typename U = EmptyPayload >
    class Trie;
|
|



|







1
2
3
4
5
6
7
8
9
10
11
12
13
#ifndef GOOSE_EIR_H
#define GOOSE_EIR_H

#include "util/util.h"

namespace goose::eir
{
    using namespace util;

    struct EmptyPayload {};

    template< typename U = EmptyPayload >
    class Trie;
Name change from bs/ir/enumerate.cpp to bs/eir/enumerate.cpp.
1
2
3
4
5
6
7
8
9
10
#include "ir.h"

namespace goose::ir
{
    Generator< Term > Enumerate( const Trie<>& trie )
    {
        for( auto&& [t,p] : Enumerate<>( trie ) )
            co_yield move( t );
    }
}
|

|







1
2
3
4
5
6
7
8
9
10
#include "eir.h"

namespace goose::eir
{
    Generator< Term > Enumerate( const Trie<>& trie )
    {
        for( auto&& [t,p] : Enumerate<>( trie ) )
            co_yield move( t );
    }
}
Name change from bs/ir/enumerate.h to bs/eir/enumerate.h.
1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_IR_ENUMERATE_H
#define GOOSE_IR_ENUMERATE_H

namespace goose::ir
{
    template< typename U >
    static Generator< pair< Term, const U& > > Enumerate( const Trie< U >& trie );

    extern Generator< Term > Enumerate( const Trie<>& trie );
}

|
|

|







1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_EIR_ENUMERATE_H
#define GOOSE_EIR_ENUMERATE_H

namespace goose::eir
{
    template< typename U >
    static Generator< pair< Term, const U& > > Enumerate( const Trie< U >& trie );

    extern Generator< Term > Enumerate( const Trie<>& trie );
}

Name change from bs/ir/enumerate.inl to bs/eir/enumerate.inl.
1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_IR_ENUMERATE_INL
#define GOOSE_IR_ENUMERATE_INL

namespace goose::ir
{
    //--------------------------------------------------------------------------------------------
    // Primitive types
    //--------------------------------------------------------------------------------------------
    template< typename T, typename U >
    static Generator< pair< Term, const U& > > Enumerate( const ValueTrieNode< T, U >& trie )
    {
|
|

|







1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_EIR_ENUMERATE_INL
#define GOOSE_EIR_ENUMERATE_INL

namespace goose::eir
{
    //--------------------------------------------------------------------------------------------
    // Primitive types
    //--------------------------------------------------------------------------------------------
    template< typename T, typename U >
    static Generator< pair< Term, const U& > > Enumerate( const ValueTrieNode< T, U >& trie )
    {
Name change from bs/ir/graphviz.cpp to bs/eir/graphviz.cpp.
1
2
3
4
5
6
7
8
9
#include "ir.h"

namespace goose::ir
{
    void GraphVizDump( const char* pFilename, const Trie<>& trie )
    {
        GraphVizDump<>( pFilename, trie );
    }
}
|

|






1
2
3
4
5
6
7
8
9
#include "eir.h"

namespace goose::eir
{
    void GraphVizDump( const char* pFilename, const Trie<>& trie )
    {
        GraphVizDump<>( pFilename, trie );
    }
}
Name change from bs/ir/graphviz.h to bs/eir/graphviz.h.
1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_IR_GRAPHVIZ_H
#define GOOSE_IR_GRAPHVIZ_H

namespace goose::ir
{
    template< typename U >
    static void GraphVizDump( const char* pFilename, const Trie< U >& trie );

    extern void GraphVizDump( const char* pFilename, const Trie<>& trie );
}

|
|

|







1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_EIR_GRAPHVIZ_H
#define GOOSE_EIR_GRAPHVIZ_H

namespace goose::eir
{
    template< typename U >
    static void GraphVizDump( const char* pFilename, const Trie< U >& trie );

    extern void GraphVizDump( const char* pFilename, const Trie<>& trie );
}

Name change from bs/ir/graphviz.inl to bs/eir/graphviz.inl.
1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_IR_GRAPHVIZ_INL
#define GOOSE_IR_GRAPHVIZ_INL

namespace goose::ir
{
    template< typename U, typename F >
    static void GraphVizDump( GraphVizBuilder& builder, const Trie< U >& trie, F&& next );

    //--------------------------------------------------------------------------------------------
    // Primitive types
    //--------------------------------------------------------------------------------------------
|
|

|







1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_EIR_GRAPHVIZ_INL
#define GOOSE_EIR_GRAPHVIZ_INL

namespace goose::eir
{
    template< typename U, typename F >
    static void GraphVizDump( GraphVizBuilder& builder, const Trie< U >& trie, F&& next );

    //--------------------------------------------------------------------------------------------
    // Primitive types
    //--------------------------------------------------------------------------------------------
Name change from bs/ir/helpers.cpp to bs/eir/helpers.cpp.
1
2
3
4
5
6
7
8
9
10
#include "ir.h"

namespace goose::ir
{
    Term ConcatenateVectorTerms( const Term& vector1, const Term& vector2 )
    {
        const auto& vec1 = *get< pvec >( vector1 );
        const auto& vec2 = *get< pvec >( vector2 );
        auto newVec = Vector::MakeConcat( vec1, vec2 );
        return TERM( make_shared< Vector >( move( newVec ) ) );
|

|







1
2
3
4
5
6
7
8
9
10
#include "eir.h"

namespace goose::eir
{
    Term ConcatenateVectorTerms( const Term& vector1, const Term& vector2 )
    {
        const auto& vec1 = *get< pvec >( vector1 );
        const auto& vec2 = *get< pvec >( vector2 );
        auto newVec = Vector::MakeConcat( vec1, vec2 );
        return TERM( make_shared< Vector >( move( newVec ) ) );
Name change from bs/ir/helpers.h to bs/eir/helpers.h.
1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_IR_HELPERS_H
#define GOOSE_IR_HELPERS_H

namespace goose::ir
{
    static inline auto VecSize( const Term& vectorTerm )
    {
        return get< pvec >( vectorTerm )->terms().size();
    }

    template< typename... T >
|
|

|







1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_EIR_HELPERS_H
#define GOOSE_EIR_HELPERS_H

namespace goose::eir
{
    static inline auto VecSize( const Term& vectorTerm )
    {
        return get< pvec >( vectorTerm )->terms().size();
    }

    template< typename... T >
Name change from bs/ir/helpers.inl to bs/eir/helpers.inl.
1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_IR_HELPERS_INL
#define GOOSE_IR_HELPERS_INL

namespace goose::ir
{
    template< typename... T >
    Term AppendToVectorTerm( const Term& vectorTerm, T&&... t )
    {
        const auto& vec = *get< pvec >( vectorTerm );
        auto newVec = Vector::MakeAppend( vec, forward< T >( t )... );
        return TERM( make_shared< Vector >( move( newVec ) ) );
|
|

|







1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_EIR_HELPERS_INL
#define GOOSE_EIR_HELPERS_INL

namespace goose::eir
{
    template< typename... T >
    Term AppendToVectorTerm( const Term& vectorTerm, T&&... t )
    {
        const auto& vec = *get< pvec >( vectorTerm );
        auto newVec = Vector::MakeAppend( vec, forward< T >( t )... );
        return TERM( make_shared< Vector >( move( newVec ) ) );
Name change from bs/ir/match.cpp to bs/eir/match.cpp.
1
2
3
4
5
6
7
8
9
10
#include "ir.h"

namespace goose::ir
{
    size_t MatchSolution::numVars() const
    {
        if( !m_pVars )
            return 0;

        return m_pVars->size();
|

|







1
2
3
4
5
6
7
8
9
10
#include "eir.h"

namespace goose::eir
{
    size_t MatchSolution::numVars() const
    {
        if( !m_pVars )
            return 0;

        return m_pVars->size();
Name change from bs/ir/match.h to bs/eir/match.h.
1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_IR_MATCH_H
#define GOOSE_IR_MATCH_H

namespace goose::ir
{
    class MatchSolution
    {
        public:
            size_t complexity() const { return m_complexity; }
            size_t numVars() const;

|
|

|







1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_EIR_MATCH_H
#define GOOSE_EIR_MATCH_H

namespace goose::eir
{
    class MatchSolution
    {
        public:
            size_t complexity() const { return m_complexity; }
            size_t numVars() const;

Name change from bs/ir/match.inl to bs/eir/match.inl.
1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_IR_MATCH_INL
#define GOOSE_IR_MATCH_INL

namespace goose::ir
{
    template< typename U >
    static Generator< pair< MatchSolution, const U& > > Match( MatchSolution&& s, const Term& expression, const Trie< U >& patterns );

    template< size_t I = 0, typename U, typename V >
    static Generator< tuple< MatchSolution, const U&, const V& > > Match( MatchSolution&& s, const Trie< U >& expressions, const Trie< V >& patterns );

|
|

|







1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_EIR_MATCH_INL
#define GOOSE_EIR_MATCH_INL

namespace goose::eir
{
    template< typename U >
    static Generator< pair< MatchSolution, const U& > > Match( MatchSolution&& s, const Term& expression, const Trie< U >& patterns );

    template< size_t I = 0, typename U, typename V >
    static Generator< tuple< MatchSolution, const U&, const V& > > Match( MatchSolution&& s, const Trie< U >& expressions, const Trie< V >& patterns );

Name change from bs/ir/merge.cpp to bs/eir/merge.cpp.
1
2
3
4
5
6
7
8
9
#include "ir.h"

namespace goose::ir
{
    Trie<> Merge( const Trie<>& trie, const Term& term )
    {
        return Merge( trie, term, []( auto&& ){ return EmptyPayload(); } );
    }
}
|

|






1
2
3
4
5
6
7
8
9
#include "eir.h"

namespace goose::eir
{
    Trie<> Merge( const Trie<>& trie, const Term& term )
    {
        return Merge( trie, term, []( auto&& ){ return EmptyPayload(); } );
    }
}
Name change from bs/ir/merge.h to bs/eir/merge.h.
1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_IR_MERGE_H
#define GOOSE_IR_MERGE_H

namespace goose::ir
{
    template< typename U, typename F >
    static Trie< U > Merge( const Trie< U >& trie, const Term& term, F&& func );

    extern Trie<> Merge( const Trie<>& trie, const Term& term );
}

|
|

|







1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_EIR_MERGE_H
#define GOOSE_EIR_MERGE_H

namespace goose::eir
{
    template< typename U, typename F >
    static Trie< U > Merge( const Trie< U >& trie, const Term& term, F&& func );

    extern Trie<> Merge( const Trie<>& trie, const Term& term );
}

Name change from bs/ir/merge.inl to bs/eir/merge.inl.
1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_IR_MERGE_INL
#define GOOSE_IR_MERGE_INL

namespace goose::ir
{
    //--------------------------------------------------------------------------------------------
    // Primitive types
    //--------------------------------------------------------------------------------------------
    template< typename T, typename U, typename F >
    static ptr< TrieNode< T, U > > Merge( const ptr< TrieNode< T, U > >& lhs, const T& rhs, F&& next )
    {
|
|

|







1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_EIR_MERGE_INL
#define GOOSE_EIR_MERGE_INL

namespace goose::eir
{
    //--------------------------------------------------------------------------------------------
    // Primitive types
    //--------------------------------------------------------------------------------------------
    template< typename T, typename U, typename F >
    static ptr< TrieNode< T, U > > Merge( const ptr< TrieNode< T, U > >& lhs, const T& rhs, F&& next )
    {
Name change from bs/ir/meson.build to bs/eir/meson.build.
1
2
3
4
5
6
7
8
goose_ir = library( 'goose-ir',
    'tostring.cpp',
    'merge.cpp',
    'compare.cpp',
    'enumerate.cpp',
    'match.cpp',
    'graphviz.cpp',
    'value.cpp',
|







1
2
3
4
5
6
7
8
goose_eir = library( 'goose-eir',
    'tostring.cpp',
    'merge.cpp',
    'compare.cpp',
    'enumerate.cpp',
    'match.cpp',
    'graphviz.cpp',
    'value.cpp',
Name change from bs/ir/term.h to bs/eir/term.h.
1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_IR_TERM_H
#define GOOSE_IR_TERM_H

namespace goose::ir
{
    class Vector;
    using pvec = ptr< Vector >;

    // We use a distinct type to store locations so that we can handle it differently
    // in the pattern matching algorithms. We consider all LocationId to be equal to one another
    // regardless of their value. This way we can keep it around in IR expessions without having
|
|

|







1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_EIR_TERM_H
#define GOOSE_EIR_TERM_H

namespace goose::eir
{
    class Vector;
    using pvec = ptr< Vector >;

    // We use a distinct type to store locations so that we can handle it differently
    // in the pattern matching algorithms. We consider all LocationId to be equal to one another
    // regardless of their value. This way we can keep it around in IR expessions without having
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
    static inline ostream& operator<<( ostream& out, const Term& t )
    {
       return ToString( out, t );
    }

    // A term associated with a location id.
    // Used to represent tokens and tokens/values coming out of the resolver.
    using TermLoc = pair< ir::Term, uint32_t >;
}

namespace std
{
    template<> struct hash< goose::ir::Hole >
    {
        size_t operator()( const goose::ir::Hole& x ) const
        {
            return hash< goose::util::StringId >()( x.name );
        }
    };
}

#define TERM( x )           ir::Term( x )
#define TSTR( x )           TERM( string( x ) )
#define TSID( x )           TERM( #x##_sid )
#define HOLE( x )           TERM( ir::Hole{ x } )
#define ANYTERM( x )        TERM( ir::AnyTerm( #x##_sid ) )
#define VECOFLENGTH( x )    TERM( ir::VecOfLength( #x##_sid ) )
#define VEC( ... )          TERM( ir::Vector::Make( __VA_ARGS__ ) )
#define REPEAT( x )         ir::Repetition( x )

#endif







|




|

|






|


|
|
|
|
|


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
    static inline ostream& operator<<( ostream& out, const Term& t )
    {
       return ToString( out, t );
    }

    // A term associated with a location id.
    // Used to represent tokens and tokens/values coming out of the resolver.
    using TermLoc = pair< eir::Term, uint32_t >;
}

namespace std
{
    template<> struct hash< goose::eir::Hole >
    {
        size_t operator()( const goose::eir::Hole& x ) const
        {
            return hash< goose::util::StringId >()( x.name );
        }
    };
}

#define TERM( x )           eir::Term( x )
#define TSTR( x )           TERM( string( x ) )
#define TSID( x )           TERM( #x##_sid )
#define HOLE( x )           TERM( eir::Hole{ x } )
#define ANYTERM( x )        TERM( eir::AnyTerm( #x##_sid ) )
#define VECOFLENGTH( x )    TERM( eir::VecOfLength( #x##_sid ) )
#define VEC( ... )          TERM( eir::Vector::Make( __VA_ARGS__ ) )
#define REPEAT( x )         eir::Repetition( x )

#endif
Name change from bs/ir/tests/match-terms-trie.cpp to bs/eir/tests/match-terms-trie.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#define CATCH_CONFIG_MAIN
#include "catch2/catch.hpp"
#include "ir/ir.h"

using namespace std;
using namespace goose;
using namespace goose::ir;

SCENARIO( "Match works", "[match]" )
{
    WHEN( "Matching various expressions against various patterns stored in a trie" )
    {
        auto pat0 = ANYTERM( a );



|



|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
#define CATCH_CONFIG_MAIN
#include "catch2/catch.hpp"
#include "eir/eir.h"

using namespace std;
using namespace goose;
using namespace goose::eir;

SCENARIO( "Match works", "[match]" )
{
    WHEN( "Matching various expressions against various patterns stored in a trie" )
    {
        auto pat0 = ANYTERM( a );

Name change from bs/ir/tests/match-terms.cpp to bs/eir/tests/match-terms.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#define CATCH_CONFIG_MAIN
#include "catch2/catch.hpp"
#include "ir/ir.h"

using namespace std;
using namespace goose;
using namespace goose::ir;

SCENARIO( "Match works", "[match]" )
{
    WHEN( "Matching various expressions against various patterns" )
    {
        auto pat0 = ANYTERM( a );



|



|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
#define CATCH_CONFIG_MAIN
#include "catch2/catch.hpp"
#include "eir/eir.h"

using namespace std;
using namespace goose;
using namespace goose::eir;

SCENARIO( "Match works", "[match]" )
{
    WHEN( "Matching various expressions against various patterns" )
    {
        auto pat0 = ANYTERM( a );

Name change from bs/ir/tests/merge.cpp to bs/eir/tests/merge.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#define CATCH_CONFIG_MAIN
#include "catch2/catch.hpp"
#include "ir/ir.h"

using namespace std;
using namespace goose;
using namespace goose::ir;

SCENARIO( "Merge works", "[merge]" )
{
    WHEN( "Merging multiple terms into a trie" )
    {
        auto pat0 = ANYTERM( a );



|



|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
#define CATCH_CONFIG_MAIN
#include "catch2/catch.hpp"
#include "eir/eir.h"

using namespace std;
using namespace goose;
using namespace goose::eir;

SCENARIO( "Merge works", "[merge]" )
{
    WHEN( "Merging multiple terms into a trie" )
    {
        auto pat0 = ANYTERM( a );

Name change from bs/ir/tests/meson.build to bs/eir/tests/meson.build.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
tests = [
    'merge',
    'match-terms',
    'match-terms-trie'
]

foreach t : tests
    exe = executable( 'ir-' + t, t + '.cpp',
        link_with: [ goose_ir, goose_util ],
        include_directories: bsinc,
        dependencies: [catch2_dep, fmt_dep, llvm_dep]
    )
    test( 'ir-' + t, exe )
endforeach







|
|



|

1
2
3
4
5
6
7
8
9
10
11
12
13
14
tests = [
    'merge',
    'match-terms',
    'match-terms-trie'
]

foreach t : tests
    exe = executable( 'eir-' + t, t + '.cpp',
        link_with: [ goose_eir, goose_util ],
        include_directories: bsinc,
        dependencies: [catch2_dep, fmt_dep, llvm_dep]
    )
    test( 'eir-' + t, exe )
endforeach
Name change from bs/ir/tostring.cpp to bs/eir/tostring.cpp.
1
2
3
4
5
6
7
8
9
10
#include "ir.h"

namespace goose::ir
{
    ostream& ToString( ostream& out, const uint32_t& x )
    {
        return out << x;
    }

    ostream& ToString( ostream& out, const LocationId& x )
|

|







1
2
3
4
5
6
7
8
9
10
#include "eir.h"

namespace goose::eir
{
    ostream& ToString( ostream& out, const uint32_t& x )
    {
        return out << x;
    }

    ostream& ToString( ostream& out, const LocationId& x )
Name change from bs/ir/tostring.h to bs/eir/tostring.h.
1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_IR_TOSTRING_H
#define GOOSE_IR_TOSTRING_H

namespace goose::ir
{
    class Vector;
    enum class Delimiter;

    extern ostream& ToString( ostream& out, const uint32_t& x );
    extern ostream& ToString( ostream& out, const LocationId& x );
    extern ostream& ToString( ostream& out, const string& x );
|
|

|







1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_EIR_TOSTRING_H
#define GOOSE_EIR_TOSTRING_H

namespace goose::eir
{
    class Vector;
    enum class Delimiter;

    extern ostream& ToString( ostream& out, const uint32_t& x );
    extern ostream& ToString( ostream& out, const LocationId& x );
    extern ostream& ToString( ostream& out, const string& x );
Name change from bs/ir/trie.h to bs/eir/trie.h.
1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_IR_TRIE_H
#define GOOSE_IR_TRIE_H

namespace goose::ir
{
    template< typename T, typename U >
    struct TrieNode
    {};

    template< typename T, typename U >
    struct ValueTrieNode
|
|

|







1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_EIR_TRIE_H
#define GOOSE_EIR_TRIE_H

namespace goose::eir
{
    template< typename T, typename U >
    struct TrieNode
    {};

    template< typename T, typename U >
    struct ValueTrieNode
Name change from bs/ir/value.cpp to bs/eir/value.cpp.
1
2
3
4
5
6
7
8
9
10
#include "ir.h"

namespace goose::ir
{
    bool Value::isType() const
    {
        auto result = Decompose( type(),
            Vec(
                Lit( "type"_sid ),
                Val< uint32_t >(),
|

|







1
2
3
4
5
6
7
8
9
10
#include "eir.h"

namespace goose::eir
{
    bool Value::isType() const
    {
        auto result = Decompose( type(),
            Vec(
                Lit( "type"_sid ),
                Val< uint32_t >(),
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
            }

            return VEC( TSID( value ), TSID( constant ), v.type(), v.val(),
                static_cast< LocationId >( v.locationId() ) );
        }

        return VEC( TSID( value ), TSID( computed ), v.type(),
            TERM( static_pointer_cast< void >( v.llr() ) ),
            static_cast< LocationId >( v.locationId() ) );
    }

    optional< Value > ValueFromIRExpr( const Term& t )
    {
        // Special case for type's type
        auto typedecomp = Decompose( t,







|







52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
            }

            return VEC( TSID( value ), TSID( constant ), v.type(), v.val(),
                static_cast< LocationId >( v.locationId() ) );
        }

        return VEC( TSID( value ), TSID( computed ), v.type(),
            TERM( static_pointer_cast< void >( v.cir() ) ),
            static_cast< LocationId >( v.locationId() ) );
    }

    optional< Value > ValueFromIRExpr( const Term& t )
    {
        // Special case for type's type
        auto typedecomp = Decompose( t,
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
        if( !result )
            return nullopt;

        auto&& [sort, type, val, locationId] = *result;
        if( sort == "constant"_sid )
            return Value( type, val, static_cast< uint32_t >( locationId ) );

        auto llr = Decompose( val, Val< ptr< void > >() );
        if( !llr )
            return nullopt;

        return Value( type, static_pointer_cast< llr::Instruction >( ptr< void >( *llr ) ), static_cast< uint32_t >( locationId ) );
    }

    Term ValueToIRExpr( const ValuePattern& v )
    {
        return VEC( TSID( value ), v.sort(), v.type(), v.val(), static_cast< LocationId >( v.locationId() ) );
    }








|
|


|







92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
        if( !result )
            return nullopt;

        auto&& [sort, type, val, locationId] = *result;
        if( sort == "constant"_sid )
            return Value( type, val, static_cast< uint32_t >( locationId ) );

        auto cir = Decompose( val, Val< ptr< void > >() );
        if( !cir )
            return nullopt;

        return Value( type, static_pointer_cast< cir::Instruction >( ptr< void >( *cir ) ), static_cast< uint32_t >( locationId ) );
    }

    Term ValueToIRExpr( const ValuePattern& v )
    {
        return VEC( TSID( value ), v.sort(), v.type(), v.val(), static_cast< LocationId >( v.locationId() ) );
    }

Name change from bs/ir/value.h to bs/eir/value.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
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
#ifndef GOOSE_IR_VALUE_H
#define GOOSE_IR_VALUE_H

namespace goose::llr
{
    class Instruction;
}

namespace goose::ir
{
    class Value;
    class ValuePattern;

    extern const Term& TypeType();

    extern Term ValueToIRExpr( const Value& v );
    extern optional< Value > ValueFromIRExpr( const Term& t );

    extern Term ValueToIRExpr( const ValuePattern& v );
    extern optional< ValuePattern > ValuePatternFromIRExpr( const Term& t );

    class Value
    {
        public:
            Value() : m_locationId( ~0 ) {}

            template< typename T, typename VL >
            Value( T&& type, VL&& valOrLLR, uint32_t loc = 0 ) :
                m_type( forward< T >( type ) ),
                m_valOrLLR( forward< VL >( valOrLLR ) ),
                m_locationId( loc )
            {}

            const auto& type() const { return m_type; }
            const auto& val() const { return get< Term >( m_valOrLLR ); }
            auto& val() { return get< Term >( m_valOrLLR ); }
            auto llr() const
            {
                return get< ptr< llr::Instruction > >( m_valOrLLR );
            }

            auto locationId() const { return m_locationId; }
            auto&& setLocationId( uint32_t id )
            {
                if( !isPoison() )
                    m_locationId = id;
                return *this;
            }

            bool isPoison() const { return m_locationId == ~0; }
            auto&& setPoison() { m_locationId = ~0; return *this; }

            bool isConstant() const { return holds_alternative< Term >( m_valOrLLR ); }
            bool isType() const;

            friend ostream& operator<<( ostream& out, const Value& val )
            {
                return out << ValueToIRExpr( val );
            }

            bool operator==( const Value& rhs ) const
            {
                return m_type == rhs.m_type && m_valOrLLR == rhs.m_valOrLLR;
            }

            bool operator!=( const Value& rhs ) const
            {
                return m_type != rhs.m_type || m_valOrLLR != rhs.m_valOrLLR;
            }

        private:
            Term m_type;
            variant< Term, ptr< llr::Instruction > > m_valOrLLR;
            uint32_t m_locationId = 0;
    };

    class ValuePattern
    {
        public:
            template< typename S, typename T, 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
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
#ifndef GOOSE_EIR_VALUE_H
#define GOOSE_EIR_VALUE_H

namespace goose::cir
{
    class Instruction;
}

namespace goose::eir
{
    class Value;
    class ValuePattern;

    extern const Term& TypeType();

    extern Term ValueToIRExpr( const Value& v );
    extern optional< Value > ValueFromIRExpr( const Term& t );

    extern Term ValueToIRExpr( const ValuePattern& v );
    extern optional< ValuePattern > ValuePatternFromIRExpr( const Term& t );

    class Value
    {
        public:
            Value() : m_locationId( ~0 ) {}

            template< typename T, typename VL >
            Value( T&& type, VL&& valOrCIR, uint32_t loc = 0 ) :
                m_type( forward< T >( type ) ),
                m_valOrCIR( forward< VL >( valOrCIR ) ),
                m_locationId( loc )
            {}

            const auto& type() const { return m_type; }
            const auto& val() const { return get< Term >( m_valOrCIR ); }
            auto& val() { return get< Term >( m_valOrCIR ); }
            auto cir() const
            {
                return get< ptr< cir::Instruction > >( m_valOrCIR );
            }

            auto locationId() const { return m_locationId; }
            auto&& setLocationId( uint32_t id )
            {
                if( !isPoison() )
                    m_locationId = id;
                return *this;
            }

            bool isPoison() const { return m_locationId == ~0; }
            auto&& setPoison() { m_locationId = ~0; return *this; }

            bool isConstant() const { return holds_alternative< Term >( m_valOrCIR ); }
            bool isType() const;

            friend ostream& operator<<( ostream& out, const Value& val )
            {
                return out << ValueToIRExpr( val );
            }

            bool operator==( const Value& rhs ) const
            {
                return m_type == rhs.m_type && m_valOrCIR == rhs.m_valOrCIR;
            }

            bool operator!=( const Value& rhs ) const
            {
                return m_type != rhs.m_type || m_valOrCIR != rhs.m_valOrCIR;
            }

        private:
            Term m_type;
            variant< Term, ptr< cir::Instruction > > m_valOrCIR;
            uint32_t m_locationId = 0;
    };

    class ValuePattern
    {
        public:
            template< typename S, typename T, typename V >
Name change from bs/ir/vecgenerator.cpp to bs/eir/vecgenerator.cpp.
1
2
3
4
5
6
7
8
9
10
#include "ir.h"

namespace goose::ir
{
    bool VecGenerator::finished() const
    {
        return ( !m_cont.repetitionTerm() && m_index == m_cont.terms().size() )
            || ( m_cont.repetitionTerm() && m_index > m_cont.terms().size() );
    }
    bool VecGenerator::repeating() const { return m_cont.repetitionTerm() && m_index == m_cont.terms().size(); }
|

|







1
2
3
4
5
6
7
8
9
10
#include "eir.h"

namespace goose::eir
{
    bool VecGenerator::finished() const
    {
        return ( !m_cont.repetitionTerm() && m_index == m_cont.terms().size() )
            || ( m_cont.repetitionTerm() && m_index > m_cont.terms().size() );
    }
    bool VecGenerator::repeating() const { return m_cont.repetitionTerm() && m_index == m_cont.terms().size(); }
Name change from bs/ir/vecgenerator.h to bs/eir/vecgenerator.h.
1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_IR_VECGENERATOR_H
#define GOOSE_IR_VECGENERATOR_H

namespace goose::ir
{
    // Generator that outputs the elements of a vector term, and then the repetition term (if any) forever.
    class VecGenerator
    {
        public:
            VecGenerator( const Vector& cont ) : m_cont( cont ) {}

|
|

|







1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_EIR_VECGENERATOR_H
#define GOOSE_EIR_VECGENERATOR_H

namespace goose::eir
{
    // Generator that outputs the elements of a vector term, and then the repetition term (if any) forever.
    class VecGenerator
    {
        public:
            VecGenerator( const Vector& cont ) : m_cont( cont ) {}

Name change from bs/ir/vecoflength.h to bs/eir/vecoflength.h.
1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_IR_VECOFLENGTH_H
#define GOOSE_IR_VECOFLENGTH_H

namespace goose::ir
{
    class VecOfLength
    {
        public:
            template< typename S >
            VecOfLength( S&& varName ) :
                m_varName( varName )
|
|

|







1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_EIR_VECOFLENGTH_H
#define GOOSE_EIR_VECOFLENGTH_H

namespace goose::eir
{
    class VecOfLength
    {
        public:
            template< typename S >
            VecOfLength( S&& varName ) :
                m_varName( varName )
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
        private:
            StringId m_varName;
    };
}

namespace std
{
    template<> struct hash< goose::ir::VecOfLength >
    {
        size_t operator()( const goose::ir::VecOfLength& x ) const
        {
            return hash< goose::util::StringId >()( x.varName() );
        }
    };
}

#endif







|

|







24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
        private:
            StringId m_varName;
    };
}

namespace std
{
    template<> struct hash< goose::eir::VecOfLength >
    {
        size_t operator()( const goose::eir::VecOfLength& x ) const
        {
            return hash< goose::util::StringId >()( x.varName() );
        }
    };
}

#endif
Name change from bs/ir/vector.h to bs/eir/vector.h.
1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_IR_VECTOR_H
#define GOOSE_IR_VECTOR_H

namespace goose::ir
{
    static inline uint32_t GetComplexity( const Term& term );

    struct Repetition
    {
        Repetition( Term&& t ) :
            m_term( move( t ) )
|
|

|







1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_EIR_VECTOR_H
#define GOOSE_EIR_VECTOR_H

namespace goose::eir
{
    static inline uint32_t GetComplexity( const Term& term );

    struct Repetition
    {
        Repetition( Term&& t ) :
            m_term( move( t ) )
Changes to bs/execute/binaryops.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
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
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
#include "execute.h"
#include "builtins/builtins.h"
#include "binaryops.inl"

using namespace goose;
using namespace goose::execute;
using namespace goose::builtins;

optional< Value > VM::execute( const llr::And& bo )
{
    return executeLogicBinOp( bo, []< typename T >( const T& lhs, const T& rhs )
    {
        if constexpr( is_same_v< T, bool > )
        {
            return lhs && rhs;
        }
        else
        {
            return lhs & rhs;
        }
    } );
}

optional< Value > VM::execute( const llr::Or& bo )
{
    return executeLogicBinOp( bo, []< typename T >( const T& lhs, const T& rhs )
    {
        if constexpr( is_same_v< T, bool > )
        {
            return lhs || rhs;
        }
        else
        {
            return lhs | rhs;
        }
    } );
}

optional< Value > VM::execute( const llr::Xor& bo )
{
    return executeLogicBinOp( bo, []< typename T >( const T& lhs, const T& rhs )
    {
        if constexpr( is_same_v< T, bool > )
        {
            auto l = static_cast< uint8_t >( lhs );
            auto r = static_cast< uint8_t >( rhs );
            return !!( l ^ r );
        }
        else
        {
            return lhs ^ rhs;
        }
    } );
}

optional< Value > VM::execute( const llr::Shl& bo )
{
    return executeShiftBinOp( bo, []< typename T >( const T& lhs, auto&& rhs )
    {
        return lhs.shl( rhs );
    } );
}

optional< Value > VM::execute( const llr::LShr& bo )
{
    return executeShiftBinOp( bo, []( auto&& lhs, auto&& rhs )
    {
        return lhs.lshr( rhs );
    } );
}

optional< Value > VM::execute( const llr::AShr& bo )
{
    return executeShiftBinOp( bo, []( auto&& lhs, auto&& rhs )
    {
        return lhs.ashr( rhs );
    } );
}

optional< Value > VM::execute( const llr::Add& bo )
{
    return executeBinOp( bo, []( auto&& lhs, auto&& rhs )
    {
        return lhs + rhs;
    } );
}

optional< Value > VM::execute( const llr::Sub& bo )
{
    return executeBinOp( bo, []( auto&& lhs, auto&& rhs )
    {
        return lhs - rhs;
    } );
}

optional< Value > VM::execute( const llr::Mul& bo )
{
    return executeBinOp( bo, []( auto&& lhs, auto&& rhs )
    {
        return lhs * rhs;
    } );
}

optional< Value > VM::execute( const llr::UDiv& bo )
{
    return executeBinOp( bo, []( auto&& lhs, auto&& rhs )
    {
        return lhs / rhs;
    } );
}

optional< Value > VM::execute( const llr::SDiv& bo )
{
    return executeBinOp( bo, []( auto&& lhs, auto&& rhs )
    {
        return lhs / rhs;
    } );
}

optional< Value > VM::execute( const llr::URem& bo )
{
    return executeBinOp( bo, []( auto&& lhs, auto&& rhs )
    {
        return lhs % rhs;
    } );
}

optional< Value > VM::execute( const llr::SRem& bo )
{
    return executeBinOp( bo, []( auto&& lhs, auto&& rhs )
    {
        return lhs % rhs;
    } );
}

optional< Value > VM::execute( const llr::Eq& bo )
{
    return executeEqualityBinOp( bo, []( auto&& lhs, auto&& rhs )
    {
        return lhs == rhs;
    } );
}

optional< Value > VM::execute( const llr::Neq& bo )
{
    return executeEqualityBinOp( bo, []( auto&& lhs, auto&& rhs )
    {
        return lhs != rhs;
    } );
}

optional< Value > VM::execute( const llr::UGT& bo )
{
    return executeBinOp( bo, []( auto&& lhs, auto&& rhs )
    {
        return lhs > rhs;
    } );
}

optional< Value > VM::execute( const llr::UGE& bo )
{
    return executeBinOp( bo, []( auto&& lhs, auto&& rhs )
    {
        return lhs >= rhs;
    } );
}

optional< Value > VM::execute( const llr::ULT& bo )
{
    return executeBinOp( bo, []( auto&& lhs, auto&& rhs )
    {
        return lhs < rhs;
    } );
}

optional< Value > VM::execute( const llr::ULE& bo )
{
    return executeBinOp( bo, []( auto&& lhs, auto&& rhs )
    {
        return lhs <= rhs;
    } );
}

optional< Value > VM::execute( const llr::SGT& bo )
{
    return executeBinOp( bo, []( auto&& lhs, auto&& rhs )
    {
        return lhs > rhs;
    } );
}

optional< Value > VM::execute( const llr::SGE& bo )
{
    return executeBinOp( bo, []( auto&& lhs, auto&& rhs )
    {
        return lhs >= rhs;
    } );
}

optional< Value > VM::execute( const llr::SLT& bo )
{
    return executeBinOp( bo, []( auto&& lhs, auto&& rhs )
    {
        return lhs < rhs;
    } );
}

optional< Value > VM::execute( const llr::SLE& bo )
{
    return executeBinOp( bo, []( auto&& lhs, auto&& rhs )
    {
        return lhs <= rhs;
    } );
}








|














|














|
















|







|







|







|







|







|







|







|







|







|







|







|







|







|







|







|







|







|







|







|






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
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
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
#include "execute.h"
#include "builtins/builtins.h"
#include "binaryops.inl"

using namespace goose;
using namespace goose::execute;
using namespace goose::builtins;

optional< Value > VM::execute( const cir::And& bo )
{
    return executeLogicBinOp( bo, []< typename T >( const T& lhs, const T& rhs )
    {
        if constexpr( is_same_v< T, bool > )
        {
            return lhs && rhs;
        }
        else
        {
            return lhs & rhs;
        }
    } );
}

optional< Value > VM::execute( const cir::Or& bo )
{
    return executeLogicBinOp( bo, []< typename T >( const T& lhs, const T& rhs )
    {
        if constexpr( is_same_v< T, bool > )
        {
            return lhs || rhs;
        }
        else
        {
            return lhs | rhs;
        }
    } );
}

optional< Value > VM::execute( const cir::Xor& bo )
{
    return executeLogicBinOp( bo, []< typename T >( const T& lhs, const T& rhs )
    {
        if constexpr( is_same_v< T, bool > )
        {
            auto l = static_cast< uint8_t >( lhs );
            auto r = static_cast< uint8_t >( rhs );
            return !!( l ^ r );
        }
        else
        {
            return lhs ^ rhs;
        }
    } );
}

optional< Value > VM::execute( const cir::Shl& bo )
{
    return executeShiftBinOp( bo, []< typename T >( const T& lhs, auto&& rhs )
    {
        return lhs.shl( rhs );
    } );
}

optional< Value > VM::execute( const cir::LShr& bo )
{
    return executeShiftBinOp( bo, []( auto&& lhs, auto&& rhs )
    {
        return lhs.lshr( rhs );
    } );
}

optional< Value > VM::execute( const cir::AShr& bo )
{
    return executeShiftBinOp( bo, []( auto&& lhs, auto&& rhs )
    {
        return lhs.ashr( rhs );
    } );
}

optional< Value > VM::execute( const cir::Add& bo )
{
    return executeBinOp( bo, []( auto&& lhs, auto&& rhs )
    {
        return lhs + rhs;
    } );
}

optional< Value > VM::execute( const cir::Sub& bo )
{
    return executeBinOp( bo, []( auto&& lhs, auto&& rhs )
    {
        return lhs - rhs;
    } );
}

optional< Value > VM::execute( const cir::Mul& bo )
{
    return executeBinOp( bo, []( auto&& lhs, auto&& rhs )
    {
        return lhs * rhs;
    } );
}

optional< Value > VM::execute( const cir::UDiv& bo )
{
    return executeBinOp( bo, []( auto&& lhs, auto&& rhs )
    {
        return lhs / rhs;
    } );
}

optional< Value > VM::execute( const cir::SDiv& bo )
{
    return executeBinOp( bo, []( auto&& lhs, auto&& rhs )
    {
        return lhs / rhs;
    } );
}

optional< Value > VM::execute( const cir::URem& bo )
{
    return executeBinOp( bo, []( auto&& lhs, auto&& rhs )
    {
        return lhs % rhs;
    } );
}

optional< Value > VM::execute( const cir::SRem& bo )
{
    return executeBinOp( bo, []( auto&& lhs, auto&& rhs )
    {
        return lhs % rhs;
    } );
}

optional< Value > VM::execute( const cir::Eq& bo )
{
    return executeEqualityBinOp( bo, []( auto&& lhs, auto&& rhs )
    {
        return lhs == rhs;
    } );
}

optional< Value > VM::execute( const cir::Neq& bo )
{
    return executeEqualityBinOp( bo, []( auto&& lhs, auto&& rhs )
    {
        return lhs != rhs;
    } );
}

optional< Value > VM::execute( const cir::UGT& bo )
{
    return executeBinOp( bo, []( auto&& lhs, auto&& rhs )
    {
        return lhs > rhs;
    } );
}

optional< Value > VM::execute( const cir::UGE& bo )
{
    return executeBinOp( bo, []( auto&& lhs, auto&& rhs )
    {
        return lhs >= rhs;
    } );
}

optional< Value > VM::execute( const cir::ULT& bo )
{
    return executeBinOp( bo, []( auto&& lhs, auto&& rhs )
    {
        return lhs < rhs;
    } );
}

optional< Value > VM::execute( const cir::ULE& bo )
{
    return executeBinOp( bo, []( auto&& lhs, auto&& rhs )
    {
        return lhs <= rhs;
    } );
}

optional< Value > VM::execute( const cir::SGT& bo )
{
    return executeBinOp( bo, []( auto&& lhs, auto&& rhs )
    {
        return lhs > rhs;
    } );
}

optional< Value > VM::execute( const cir::SGE& bo )
{
    return executeBinOp( bo, []( auto&& lhs, auto&& rhs )
    {
        return lhs >= rhs;
    } );
}

optional< Value > VM::execute( const cir::SLT& bo )
{
    return executeBinOp( bo, []( auto&& lhs, auto&& rhs )
    {
        return lhs < rhs;
    } );
}

optional< Value > VM::execute( const cir::SLE& bo )
{
    return executeBinOp( bo, []( auto&& lhs, auto&& rhs )
    {
        return lhs <= rhs;
    } );
}
Changes to bs/execute/binaryops.inl.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#ifndef GOOSE_EXECUTE_BINARYOPS_INL
#define GOOSE_EXECUTE_BINARYOPS_INL

namespace goose::execute
{
    template< typename F >
    optional< Value > VM::executeEqualityBinOp( const llr::BinaryOp& bo, F&& func )
    {
        if( bo.lhs().isPoison() || bo.rhs().isPoison() )
            return PoisonValue();

        assert( bo.lhs().type() == bo.rhs().type() );
        if( bo.lhs().type() != bo.rhs().type() )
            return PoisonValue();






|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
#ifndef GOOSE_EXECUTE_BINARYOPS_INL
#define GOOSE_EXECUTE_BINARYOPS_INL

namespace goose::execute
{
    template< typename F >
    optional< Value > VM::executeEqualityBinOp( const cir::BinaryOp& bo, F&& func )
    {
        if( bo.lhs().isPoison() || bo.rhs().isPoison() )
            return PoisonValue();

        assert( bo.lhs().type() == bo.rhs().type() );
        if( bo.lhs().type() != bo.rhs().type() )
            return PoisonValue();
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
        }

        assert( false );
        return PoisonValue();
    }

    template< typename F >
    optional< Value > VM::executeLogicBinOp( const llr::BinaryOp& bo, F&& func )
    {
        if( bo.lhs().isPoison() || bo.rhs().isPoison() )
            return PoisonValue();

        assert( bo.lhs().type() == bo.rhs().type() );
        if( bo.lhs().type() != bo.rhs().type() )
            return PoisonValue();







|







53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
        }

        assert( false );
        return PoisonValue();
    }

    template< typename F >
    optional< Value > VM::executeLogicBinOp( const cir::BinaryOp& bo, F&& func )
    {
        if( bo.lhs().isPoison() || bo.rhs().isPoison() )
            return PoisonValue();

        assert( bo.lhs().type() == bo.rhs().type() );
        if( bo.lhs().type() != bo.rhs().type() )
            return PoisonValue();
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
        }

        assert( false );
        return PoisonValue();
    }

    template< typename F >
    optional< Value > VM::executeBinOp( const llr::BinaryOp& bo, F&& func )
    {
        if( bo.lhs().isPoison() || bo.rhs().isPoison() )
            return PoisonValue();

        assert( bo.lhs().type() == bo.rhs().type() );
        if( bo.lhs().type() != bo.rhs().type() )
            return PoisonValue();







|







94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
        }

        assert( false );
        return PoisonValue();
    }

    template< typename F >
    optional< Value > VM::executeBinOp( const cir::BinaryOp& bo, F&& func )
    {
        if( bo.lhs().isPoison() || bo.rhs().isPoison() )
            return PoisonValue();

        assert( bo.lhs().type() == bo.rhs().type() );
        if( bo.lhs().type() != bo.rhs().type() )
            return PoisonValue();
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
        }

        assert( false );
        return PoisonValue();
    }

    template< typename F >
    optional< Value > VM::executeShiftBinOp( const llr::BinaryOp& bo, F&& func )
    {
        if( bo.lhs().isPoison() || bo.rhs().isPoison() )
            return PoisonValue();

        auto lval = Evaluate( bo.lhs(), *this );
         if( lval.isPoison()  )
            return PoisonValue();







|







132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
        }

        assert( false );
        return PoisonValue();
    }

    template< typename F >
    optional< Value > VM::executeShiftBinOp( const cir::BinaryOp& bo, F&& func )
    {
        if( bo.lhs().isPoison() || bo.rhs().isPoison() )
            return PoisonValue();

        auto lval = Evaluate( bo.lhs(), *this );
         if( lval.isPoison()  )
            return PoisonValue();
Changes to bs/execute/eval.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
#include "execute.h"
#include "builtins/builtins.h"

using namespace goose;
using namespace goose::ir;
using namespace goose::builtins;

namespace goose::execute
{
    Value Evaluate( const Value& val, VM& vm )
    {
        if( val.isPoison() )
            DiagnosticsManager::GetInstance().setCurrentVerbosityLevel( Verbosity::Silent );

        auto v = val;

        if( !v.isConstant() )
        {
            const auto& llr = val.llr();
            if( !llr )
                return v.setPoison();

            auto result = vm.execute( *llr );

            // Execution may fail: there are some cases when we can't really
            // be sure that eager evaluation is possible until we actually try.
            // In this case we forget about the eager evaluation and return the
            // value as is.

            // Not returning a value isn't a failure, for instance




|













|
|


|







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
#include "execute.h"
#include "builtins/builtins.h"

using namespace goose;
using namespace goose::eir;
using namespace goose::builtins;

namespace goose::execute
{
    Value Evaluate( const Value& val, VM& vm )
    {
        if( val.isPoison() )
            DiagnosticsManager::GetInstance().setCurrentVerbosityLevel( Verbosity::Silent );

        auto v = val;

        if( !v.isConstant() )
        {
            const auto& cir = val.cir();
            if( !cir )
                return v.setPoison();

            auto result = vm.execute( *cir );

            // Execution may fail: there are some cases when we can't really
            // be sure that eager evaluation is possible until we actually try.
            // In this case we forget about the eager evaluation and return the
            // value as is.

            // Not returning a value isn't a failure, for instance
Changes to bs/execute/execute.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#ifndef GOOSE_EXECUTE_H
#define GOOSE_EXECUTE_H

#include "llr/llr.h"

namespace goose::execute
{
    using namespace ir;
    using namespace llr;

    class VM;

    // If the provided value isn't constant, execute its llr
    // to turn it into a constant.
    extern Value Evaluate( const Value& val, VM& vm );
}

#include "vm.h"

#endif



|



|
|



|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#ifndef GOOSE_EXECUTE_H
#define GOOSE_EXECUTE_H

#include "cir/cir.h"

namespace goose::execute
{
    using namespace eir;
    using namespace cir;

    class VM;

    // If the provided value isn't constant, execute its cir
    // to turn it into a constant.
    extern Value Evaluate( const Value& val, VM& vm );
}

#include "vm.h"

#endif
Changes to bs/execute/vm.cpp.
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
        bb = executeTerminator( *bb->terminator() );
    }

    m_pPreviousBB = pbbBackup;
    return m_retVal;
}

optional< Value > VM::execute( const llr::Instruction& instr )
{
    return visit( [&]( auto&& e )
    {
        return execute( e );
    }, instr.content() );
}

optional< Value > VM::execute( const llr::Call& call )
{
    if( !( ms_remainingBranchInstExecutions ) )
    {
        DiagnosticsManager::GetInstance().emitErrorMessage( 0,
            "Execute: compilation time execution budget exceeded." );
        return PoisonValue();
    }







|







|







29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
        bb = executeTerminator( *bb->terminator() );
    }

    m_pPreviousBB = pbbBackup;
    return m_retVal;
}

optional< Value > VM::execute( const cir::Instruction& instr )
{
    return visit( [&]( auto&& e )
    {
        return execute( e );
    }, instr.content() );
}

optional< Value > VM::execute( const cir::Call& call )
{
    if( !( ms_remainingBranchInstExecutions ) )
    {
        DiagnosticsManager::GetInstance().emitErrorMessage( 0,
            "Execute: compilation time execution budget exceeded." );
        return PoisonValue();
    }
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115

        if( !newVec )
            return nullopt;

        return ExecuteBuiltinFuncCall( func, TERM( newVec ) );
    }

    const auto* pFunc = GetFuncLLR( func );

    if( !pFunc || !pFunc->isValid() )
        return PoisonValue();

    auto savedStackSize = m_stack.size();

    for( auto&& a : vec.terms() )







|







101
102
103
104
105
106
107
108
109
110
111
112
113
114
115

        if( !newVec )
            return nullopt;

        return ExecuteBuiltinFuncCall( func, TERM( newVec ) );
    }

    const auto* pFunc = GetFuncCIR( func );

    if( !pFunc || !pFunc->isValid() )
        return PoisonValue();

    auto savedStackSize = m_stack.size();

    for( auto&& a : vec.terms() )
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
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
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
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
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290

optional< Value > VM::ExecuteBuiltinFuncCall( const Value& func, const Term& args )
{
    const auto& f = GetBuiltinFuncWrapper( func );
    return f( args );
}

optional< Value > VM::execute( const llr::CalcAddress& ref )
{
    auto* pAddr = calcAddress( ref );
    if( !pAddr )
        return nullopt;

    return ToValue( reinterpret_cast< uintptr_t >( pAddr ) );
}

optional< Value > VM::execute( const llr::CreateTemporary& ct )
{
    auto stackIndex = m_currentFrameStart + ct.index();
    if( m_stack.size() <= stackIndex )
        m_stack.resize( stackIndex + 1, TSID( UNINITIALIZED ) );

    m_stack[stackIndex] = ValueToIRExpr( Evaluate( ct.value(), *this ) );
    return nullopt;
}

optional< Value > VM::execute( const llr::GetTemporary& gt )
{
    auto stackIndex = gt.index() + m_currentFrameStart;
    if( stackIndex >= m_stack.size() )
        return PoisonValue();

    return ValueFromIRExpr( m_stack[stackIndex] );
}

optional< Value > VM::execute( const llr::AllocVar& av )
{
    auto stackIndex = m_currentFrameStart + av.index();

    if( m_stack.size() <= stackIndex )
        m_stack.resize( stackIndex + 1, TSID( UNINITIALIZED ) );

    m_stack[stackIndex] = BuildUninitializedValue( av.type() );
    return nullopt;
}

optional< Value > VM::execute( const llr::Load& l )
{
    auto addrInt = FromValue< uintptr_t >( Evaluate( l.addr(), *this ) );
    if( !addrInt )
        return nullopt;

    auto addr = reinterpret_cast< const Term* >( *addrInt );
    return ValueFromIRExpr( *addr );
}

optional< Value > VM::execute( const llr::Store& s )
{
    auto addrInt = FromValue< uintptr_t >( Evaluate( s.addr(), *this ) );
    if( !addrInt )
        return nullopt;

    auto addr = reinterpret_cast< Term* >( *addrInt );

    auto result = Evaluate( s.val(), *this );
    if( !result.isConstant() )
        return PoisonValue();

    *addr = ValueToIRExpr( result );
    return nullopt;
}

optional< Value > VM::execute( const llr::Phi& p )
{
    auto stackIndex = m_currentFrameStart + p.destIndex();
    if( m_stack.size() <= stackIndex )
        m_stack.resize( stackIndex + 1, TSID( UNINITIALIZED ) );

    p.forAllIncomings( [&]( auto&& bb, auto&& val )
    {
        if( bb == m_pPreviousBB )
        {
            m_stack[stackIndex] = ValueToIRExpr( Evaluate( val, *this ) );
            return false;
        }

        return true;
    } );

    return PoisonValue();
}

optional< Value > VM::execute( const llr::Not& uo )
{
    if( uo.operand().isPoison() )
        return PoisonValue();

    auto opval = Evaluate( uo.operand(), *this );
    if( opval.isPoison() )
        return PoisonValue();
    if( !opval.isConstant() )
        return nullopt;

    auto boolVal = FromValue< bool >( opval );
    if( !boolVal )
        return PoisonValue();

    return ToValue( !*boolVal );
}

ptr< BasicBlock > VM::executeTerminator( const llr::Terminator& terminator )
{
    return visit( [&]( auto&& e )
    {
        return executeTerminator( e );
    }, terminator.content() );
}

ptr< BasicBlock > VM::executeTerminator( const llr::Ret& r )
{
    if( r.value() )
        m_retVal = Evaluate( *r.value(), *this );

    return nullptr;
}

ptr< BasicBlock > VM::executeTerminator( const llr::Branch& b )
{
    if( !( ms_remainingBranchInstExecutions ) )
    {
        DiagnosticsManager::GetInstance().emitErrorMessage( 0,
            "Execute: compilation time execution budget exceeded." );
        m_retVal = PoisonValue();
        return nullptr;
    }

    --ms_remainingBranchInstExecutions;
    return b.dest().lock();
}

ptr< BasicBlock > VM::executeTerminator( const llr::CondBranch& cb )
{
    if( !( ms_remainingBranchInstExecutions ) )
    {
        DiagnosticsManager::GetInstance().emitErrorMessage( 0,
            "Execute: compilation time execution budget exceeded." );
        m_retVal = PoisonValue();
        return nullptr;







|








|









|








|










|









|















|



















|

















|







|







|













|







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
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
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
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
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290

optional< Value > VM::ExecuteBuiltinFuncCall( const Value& func, const Term& args )
{
    const auto& f = GetBuiltinFuncWrapper( func );
    return f( args );
}

optional< Value > VM::execute( const cir::CalcAddress& ref )
{
    auto* pAddr = calcAddress( ref );
    if( !pAddr )
        return nullopt;

    return ToValue( reinterpret_cast< uintptr_t >( pAddr ) );
}

optional< Value > VM::execute( const cir::CreateTemporary& ct )
{
    auto stackIndex = m_currentFrameStart + ct.index();
    if( m_stack.size() <= stackIndex )
        m_stack.resize( stackIndex + 1, TSID( UNINITIALIZED ) );

    m_stack[stackIndex] = ValueToIRExpr( Evaluate( ct.value(), *this ) );
    return nullopt;
}

optional< Value > VM::execute( const cir::GetTemporary& gt )
{
    auto stackIndex = gt.index() + m_currentFrameStart;
    if( stackIndex >= m_stack.size() )
        return PoisonValue();

    return ValueFromIRExpr( m_stack[stackIndex] );
}

optional< Value > VM::execute( const cir::AllocVar& av )
{
    auto stackIndex = m_currentFrameStart + av.index();

    if( m_stack.size() <= stackIndex )
        m_stack.resize( stackIndex + 1, TSID( UNINITIALIZED ) );

    m_stack[stackIndex] = BuildUninitializedValue( av.type() );
    return nullopt;
}

optional< Value > VM::execute( const cir::Load& l )
{
    auto addrInt = FromValue< uintptr_t >( Evaluate( l.addr(), *this ) );
    if( !addrInt )
        return nullopt;

    auto addr = reinterpret_cast< const Term* >( *addrInt );
    return ValueFromIRExpr( *addr );
}

optional< Value > VM::execute( const cir::Store& s )
{
    auto addrInt = FromValue< uintptr_t >( Evaluate( s.addr(), *this ) );
    if( !addrInt )
        return nullopt;

    auto addr = reinterpret_cast< Term* >( *addrInt );

    auto result = Evaluate( s.val(), *this );
    if( !result.isConstant() )
        return PoisonValue();

    *addr = ValueToIRExpr( result );
    return nullopt;
}

optional< Value > VM::execute( const cir::Phi& p )
{
    auto stackIndex = m_currentFrameStart + p.destIndex();
    if( m_stack.size() <= stackIndex )
        m_stack.resize( stackIndex + 1, TSID( UNINITIALIZED ) );

    p.forAllIncomings( [&]( auto&& bb, auto&& val )
    {
        if( bb == m_pPreviousBB )
        {
            m_stack[stackIndex] = ValueToIRExpr( Evaluate( val, *this ) );
            return false;
        }

        return true;
    } );

    return PoisonValue();
}

optional< Value > VM::execute( const cir::Not& uo )
{
    if( uo.operand().isPoison() )
        return PoisonValue();

    auto opval = Evaluate( uo.operand(), *this );
    if( opval.isPoison() )
        return PoisonValue();
    if( !opval.isConstant() )
        return nullopt;

    auto boolVal = FromValue< bool >( opval );
    if( !boolVal )
        return PoisonValue();

    return ToValue( !*boolVal );
}

ptr< BasicBlock > VM::executeTerminator( const cir::Terminator& terminator )
{
    return visit( [&]( auto&& e )
    {
        return executeTerminator( e );
    }, terminator.content() );
}

ptr< BasicBlock > VM::executeTerminator( const cir::Ret& r )
{
    if( r.value() )
        m_retVal = Evaluate( *r.value(), *this );

    return nullptr;
}

ptr< BasicBlock > VM::executeTerminator( const cir::Branch& b )
{
    if( !( ms_remainingBranchInstExecutions ) )
    {
        DiagnosticsManager::GetInstance().emitErrorMessage( 0,
            "Execute: compilation time execution budget exceeded." );
        m_retVal = PoisonValue();
        return nullptr;
    }

    --ms_remainingBranchInstExecutions;
    return b.dest().lock();
}

ptr< BasicBlock > VM::executeTerminator( const cir::CondBranch& cb )
{
    if( !( ms_remainingBranchInstExecutions ) )
    {
        DiagnosticsManager::GetInstance().emitErrorMessage( 0,
            "Execute: compilation time execution budget exceeded." );
        m_retVal = PoisonValue();
        return nullptr;
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
{
    return visit( [&]( auto&& ba )
    {
        return calcAddress( ba );
    }, baseAddr );
}

Term* VM::calcAddress( const llr::TemporaryBaseAddr& ta )
{
    auto stackIndex = m_currentFrameStart + ta.index;
    if( m_stack.size() <= stackIndex )
        m_stack.resize( stackIndex + 1, TSID( UNINITIALIZED ) );

    if( stackIndex >= m_stack.size() )
        return nullptr;

    if( m_stack[stackIndex] == TSID( UNINITIALIZED ) )
        m_stack[stackIndex] = ValueToIRExpr( Evaluate( ta.m_initValue, *this ) );

    return &m_stack[stackIndex];
}

Term* VM::calcAddress( const llr::VarBaseAddr& va )
{
    auto stackIndex = m_currentFrameStart + va.index;
    if( stackIndex >= m_stack.size() )
        return nullptr;

    return &m_stack[stackIndex];
}







|














|







338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
{
    return visit( [&]( auto&& ba )
    {
        return calcAddress( ba );
    }, baseAddr );
}

Term* VM::calcAddress( const cir::TemporaryBaseAddr& ta )
{
    auto stackIndex = m_currentFrameStart + ta.index;
    if( m_stack.size() <= stackIndex )
        m_stack.resize( stackIndex + 1, TSID( UNINITIALIZED ) );

    if( stackIndex >= m_stack.size() )
        return nullptr;

    if( m_stack[stackIndex] == TSID( UNINITIALIZED ) )
        m_stack[stackIndex] = ValueToIRExpr( Evaluate( ta.m_initValue, *this ) );

    return &m_stack[stackIndex];
}

Term* VM::calcAddress( const cir::VarBaseAddr& va )
{
    auto stackIndex = m_currentFrameStart + va.index;
    if( stackIndex >= m_stack.size() )
        return nullptr;

    return &m_stack[stackIndex];
}
Changes to bs/execute/vm.h.
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
            {
                ms_remainingBranchInstExecutions = b;
            }

            optional< Value > execute( CFG& cfg );
            optional< Value > execute( ptr< BasicBlock > bb );

            optional< Value > execute( const llr::Instruction& instr );
            optional< Value > execute( const llr::Call& call );
            optional< Value > execute( const llr::CalcAddress& ref );
            optional< Value > execute( const llr::CreateTemporary& ct );
            optional< Value > execute( const llr::GetTemporary& gt );
            optional< Value > execute( const llr::AllocVar& av );
            optional< Value > execute( const llr::Load& l );
            optional< Value > execute( const llr::Store& s );
            optional< Value > execute( const llr::Phi& p );

            optional< Value > execute( const llr::Not& uo );
            optional< Value > execute( const llr::And& bo );
            optional< Value > execute( const llr::Or& bo );
            optional< Value > execute( const llr::Xor& bo );
            optional< Value > execute( const llr::Shl& bo );
            optional< Value > execute( const llr::LShr& bo );
            optional< Value > execute( const llr::AShr& bo );

            optional< Value > execute( const llr::Add& bo );
            optional< Value > execute( const llr::Sub& bo );
            optional< Value > execute( const llr::Mul& bo );
            optional< Value > execute( const llr::UDiv& bo );
            optional< Value > execute( const llr::SDiv& bo );
            optional< Value > execute( const llr::URem& bo );
            optional< Value > execute( const llr::SRem& bo );

            optional< Value > execute( const llr::Eq& bo );
            optional< Value > execute( const llr::Neq& bo );
            optional< Value > execute( const llr::UGT& bo );
            optional< Value > execute( const llr::UGE& bo );
            optional< Value > execute( const llr::ULT& bo );
            optional< Value > execute( const llr::ULE& bo );
            optional< Value > execute( const llr::SGT& bo );
            optional< Value > execute( const llr::SGE& bo );
            optional< Value > execute( const llr::SLT& bo );
            optional< Value > execute( const llr::SLE& bo );

            template< typename T >
            optional< Value > execute( const T& )
            {
                return PoisonValue();
            }

            ptr< BasicBlock > executeTerminator( const llr::Terminator& terminator );
            ptr< BasicBlock > executeTerminator( const llr::Ret& r );
            ptr< BasicBlock > executeTerminator( const llr::Branch& b );
            ptr< BasicBlock > executeTerminator( const llr::CondBranch& cb );

            template< typename T >
            ptr< BasicBlock > executeTerminator( const T& )
            {
                return nullptr;
            }

        private:
            static optional< Value > ExecuteBuiltinFuncCall( const Value& func, const Term& args );
            static Term BuildUninitializedValue( const Value& type );

            template< typename F >
            optional< Value > executeEqualityBinOp( const llr::BinaryOp& bo, F&& func );

            template< typename F >
            optional< Value > executeLogicBinOp( const llr::BinaryOp& bo, F&& func );

            template< typename F >
            optional< Value > executeBinOp( const llr::BinaryOp& bo, F&& func );

            template< typename F >
            optional< Value > executeShiftBinOp( const llr::BinaryOp& bo, F&& func );

            Term* calcAddress( const CalcAddress& addr );
            Term* calcAddress( const BaseAddress& baseAddr );
            Term* calcAddress( const TemporaryBaseAddr& va );
            Term* calcAddress( const VarBaseAddr& va );

            llvm::SmallVector< Term, 8 > m_stack;







|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|

|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|







|
|
|
|












|


|


|


|







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
            {
                ms_remainingBranchInstExecutions = b;
            }

            optional< Value > execute( CFG& cfg );
            optional< Value > execute( ptr< BasicBlock > bb );

            optional< Value > execute( const cir::Instruction& instr );
            optional< Value > execute( const cir::Call& call );
            optional< Value > execute( const cir::CalcAddress& ref );
            optional< Value > execute( const cir::CreateTemporary& ct );
            optional< Value > execute( const cir::GetTemporary& gt );
            optional< Value > execute( const cir::AllocVar& av );
            optional< Value > execute( const cir::Load& l );
            optional< Value > execute( const cir::Store& s );
            optional< Value > execute( const cir::Phi& p );

            optional< Value > execute( const cir::Not& uo );
            optional< Value > execute( const cir::And& bo );
            optional< Value > execute( const cir::Or& bo );
            optional< Value > execute( const cir::Xor& bo );
            optional< Value > execute( const cir::Shl& bo );
            optional< Value > execute( const cir::LShr& bo );
            optional< Value > execute( const cir::AShr& bo );

            optional< Value > execute( const cir::Add& bo );
            optional< Value > execute( const cir::Sub& bo );
            optional< Value > execute( const cir::Mul& bo );
            optional< Value > execute( const cir::UDiv& bo );
            optional< Value > execute( const cir::SDiv& bo );
            optional< Value > execute( const cir::URem& bo );
            optional< Value > execute( const cir::SRem& bo );

            optional< Value > execute( const cir::Eq& bo );
            optional< Value > execute( const cir::Neq& bo );
            optional< Value > execute( const cir::UGT& bo );
            optional< Value > execute( const cir::UGE& bo );
            optional< Value > execute( const cir::ULT& bo );
            optional< Value > execute( const cir::ULE& bo );
            optional< Value > execute( const cir::SGT& bo );
            optional< Value > execute( const cir::SGE& bo );
            optional< Value > execute( const cir::SLT& bo );
            optional< Value > execute( const cir::SLE& bo );

            template< typename T >
            optional< Value > execute( const T& )
            {
                return PoisonValue();
            }

            ptr< BasicBlock > executeTerminator( const cir::Terminator& terminator );
            ptr< BasicBlock > executeTerminator( const cir::Ret& r );
            ptr< BasicBlock > executeTerminator( const cir::Branch& b );
            ptr< BasicBlock > executeTerminator( const cir::CondBranch& cb );

            template< typename T >
            ptr< BasicBlock > executeTerminator( const T& )
            {
                return nullptr;
            }

        private:
            static optional< Value > ExecuteBuiltinFuncCall( const Value& func, const Term& args );
            static Term BuildUninitializedValue( const Value& type );

            template< typename F >
            optional< Value > executeEqualityBinOp( const cir::BinaryOp& bo, F&& func );

            template< typename F >
            optional< Value > executeLogicBinOp( const cir::BinaryOp& bo, F&& func );

            template< typename F >
            optional< Value > executeBinOp( const cir::BinaryOp& bo, F&& func );

            template< typename F >
            optional< Value > executeShiftBinOp( const cir::BinaryOp& bo, F&& func );

            Term* calcAddress( const CalcAddress& addr );
            Term* calcAddress( const BaseAddress& baseAddr );
            Term* calcAddress( const TemporaryBaseAddr& va );
            Term* calcAddress( const VarBaseAddr& va );

            llvm::SmallVector< Term, 8 > m_stack;
Changes to bs/lex/lex.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#ifndef GOOSE_LEX_H
#define GOOSE_LEX_H

#include "util/util.h"
#include "ir/ir.h"
#include "diagnostics/diagnostics.h"

namespace goose::lex
{
    using namespace util;
    using namespace ir;
    using namespace diagnostics;
}

#include "tokenprovider.h"
#include "lexer.h"
#include "vectoradapter.h"





|





|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#ifndef GOOSE_LEX_H
#define GOOSE_LEX_H

#include "util/util.h"
#include "eir/eir.h"
#include "diagnostics/diagnostics.h"

namespace goose::lex
{
    using namespace util;
    using namespace eir;
    using namespace diagnostics;
}

#include "tokenprovider.h"
#include "lexer.h"
#include "vectoradapter.h"

Changes to bs/meson.build.
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
bsinc = include_directories( '.' )

subdir( 'util' )
subdir( 'ir' )
subdir( 'builtins' )
subdir( 'lex' )
subdir( 'parse' )
subdir( 'verify' )
subdir( 'execute' )
subdir( 'codegen' )
subdir( 'diagnostics' )
subdir( 'sema' )
subdir( 'compile' )
subdir( 'llr' )

goose = executable( 'goose',
    'goose.cpp',

    link_with:
    [
        goose_ir,
        goose_llr,
        goose_builtins,
        goose_lex,
        goose_parse,
        goose_verify,
        goose_execute,
        goose_codegen,
        goose_diagnostics,



|









|






|
|







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
bsinc = include_directories( '.' )

subdir( 'util' )
subdir( 'eir' )
subdir( 'builtins' )
subdir( 'lex' )
subdir( 'parse' )
subdir( 'verify' )
subdir( 'execute' )
subdir( 'codegen' )
subdir( 'diagnostics' )
subdir( 'sema' )
subdir( 'compile' )
subdir( 'cir' )

goose = executable( 'goose',
    'goose.cpp',

    link_with:
    [
        goose_eir,
        goose_cir,
        goose_builtins,
        goose_lex,
        goose_parse,
        goose_verify,
        goose_execute,
        goose_codegen,
        goose_diagnostics,
Changes to bs/parse/parse.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#ifndef GOOSE_PARSE_H
#define GOOSE_PARSE_H

#include "llr/llr.h"
#include "lex/lex.h"
#include "sema/sema.h"
#include "verify/verify.h"
#include "execute/execute.h"
#include "diagnostics/diagnostics.h"
#include "builtins/builtins.h"
#include "precedence.h"

namespace goose::parse
{
    using namespace util;
    using namespace ir;
    using namespace diagnostics;
}

#include "resolver.h"
#include "parser.h"
#include "rule.h"
#include "rule-helpers.h"



|











|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#ifndef GOOSE_PARSE_H
#define GOOSE_PARSE_H

#include "cir/cir.h"
#include "lex/lex.h"
#include "sema/sema.h"
#include "verify/verify.h"
#include "execute/execute.h"
#include "diagnostics/diagnostics.h"
#include "builtins/builtins.h"
#include "precedence.h"

namespace goose::parse
{
    using namespace util;
    using namespace eir;
    using namespace diagnostics;
}

#include "resolver.h"
#include "parser.h"
#include "rule.h"
#include "rule-helpers.h"
Changes to bs/parse/parser.inl.
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
            DiagnosticsManager::GetInstance().setCurrentVerbosityLevel( Verbosity::Silent );
            if( context().codeBuilder() )
                context().codeBuilder()->poison();
        }

        flushValue();

        if( val.isConstant() || !llr::CanValueBeEagerlyEvaluated( val ) )
        {
            m_lastValue = forward< V >( val );
            return;
        }

        if( !verify::VerifyCompTimeExpr( context(), val ) )
        {







|







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
            DiagnosticsManager::GetInstance().setCurrentVerbosityLevel( Verbosity::Silent );
            if( context().codeBuilder() )
                context().codeBuilder()->poison();
        }

        flushValue();

        if( val.isConstant() || !cir::CanValueBeEagerlyEvaluated( val ) )
        {
            m_lastValue = forward< V >( val );
            return;
        }

        if( !verify::VerifyCompTimeExpr( context(), val ) )
        {
Changes to bs/parse/rule-helpers.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
#include "parse.h"

using namespace goose;
using namespace goose::parse;

namespace goose::ir
{
    const Term& Bridge< parse::Rule >::Type()
    {
        static auto type = ValueToIRExpr( Value( TypeType(), VEC( TSID( ct_type ), TSID( rule ) ) ) );
        return type;
    }






|







1
2
3
4
5
6
7
8
9
10
11
12
13
#include "parse.h"

using namespace goose;
using namespace goose::parse;

namespace goose::eir
{
    const Term& Bridge< parse::Rule >::Type()
    {
        static auto type = ValueToIRExpr( Value( TypeType(), VEC( TSID( ct_type ), TSID( rule ) ) ) );
        return type;
    }

Changes to bs/parse/rule-helpers.h.
1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_PARSE_RULE_HELPERS_H
#define GOOSE_PARSE_RULE_HELPERS_H

namespace goose::ir
{
    template<>
    struct Bridge< parse::Rule >
    {
        static const Term& Type();
        static Value ToValue( parse::Rule&& r );
        static optional< ptr< parse::Rule > > FromValue( const Value& v );



|







1
2
3
4
5
6
7
8
9
10
11
#ifndef GOOSE_PARSE_RULE_HELPERS_H
#define GOOSE_PARSE_RULE_HELPERS_H

namespace goose::eir
{
    template<>
    struct Bridge< parse::Rule >
    {
        static const Term& Type();
        static Value ToValue( parse::Rule&& r );
        static optional< ptr< parse::Rule > > FromValue( const Value& v );
Changes to bs/sema/codebuilder.h.
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
                    ptr< CodeBuilder > m_builder;
            };

        private:
            // Destruction
            bool destroyLiveValue( const Context& c, const Value& v );

            ptr< llr::CFG > m_cfg;

            // The number of nested lifetime scopes.
            uint32_t m_lifeTimeScopeLevels = 0;

            // The number of nested breakable scopes.
            uint32_t m_breakableScopeLevels = 0;








|







144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
                    ptr< CodeBuilder > m_builder;
            };

        private:
            // Destruction
            bool destroyLiveValue( const Context& c, const Value& v );

            ptr< cir::CFG > m_cfg;

            // The number of nested lifetime scopes.
            uint32_t m_lifeTimeScopeLevels = 0;

            // The number of nested breakable scopes.
            uint32_t m_breakableScopeLevels = 0;

Changes to bs/sema/env.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include "sema.h"

using namespace goose;
using namespace goose::llr;
using namespace goose::sema;

vector< ptr< llr::Func > >   Env::ms_llrFuncs;
uint32_t Env::ms_nextUniqueId = 0;

Env::Env() :
    m_templateRuleSet( make_shared< TemplateRuleSet >() ),
    m_invocationRuleSet( make_shared< InvocationRuleSet >() ),
    m_unificationRuleSet( make_shared< TypeCheckingRuleSet >() ),
    m_memManager( make_shared< CTMemoryManager >() )



|


|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include "sema.h"

using namespace goose;
using namespace goose::cir;
using namespace goose::sema;

vector< ptr< cir::Func > >   Env::ms_cirFuncs;
uint32_t Env::ms_nextUniqueId = 0;

Env::Env() :
    m_templateRuleSet( make_shared< TemplateRuleSet >() ),
    m_invocationRuleSet( make_shared< InvocationRuleSet >() ),
    m_unificationRuleSet( make_shared< TypeCheckingRuleSet >() ),
    m_memManager( make_shared< CTMemoryManager >() )
Changes to bs/sema/env.h.
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
            auto& extLowerTypeForVerification() { return m_extLowerTypeForVerification; }
            const auto& extLowerTypeForVerification() const { return m_extLowerTypeForVerification; }

            auto& extLowerConstantForVerification() { return m_extLowerConstantForVerification; }
            const auto& extLowerConstantForVerification() const { return m_extLowerConstantForVerification; }

            template< typename... T >
            auto createLLRFunc( T&&... args )
            {
                ms_llrFuncs.emplace_back( make_shared< llr::Func >( forward< T >( args )... ) );
                return ms_llrFuncs.back();
            }

        private:
            Trie< ptr< ValueProvider > >        m_valueStore;
            ptr< TemplateRuleSet >              m_templateRuleSet;
            ptr< InvocationRuleSet >            m_invocationRuleSet;
            ptr< TypeCheckingRuleSet >           m_unificationRuleSet;







|

|
|







64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
            auto& extLowerTypeForVerification() { return m_extLowerTypeForVerification; }
            const auto& extLowerTypeForVerification() const { return m_extLowerTypeForVerification; }

            auto& extLowerConstantForVerification() { return m_extLowerConstantForVerification; }
            const auto& extLowerConstantForVerification() const { return m_extLowerConstantForVerification; }

            template< typename... T >
            auto createCIRFunc( T&&... args )
            {
                ms_cirFuncs.emplace_back( make_shared< cir::Func >( forward< T >( args )... ) );
                return ms_cirFuncs.back();
            }

        private:
            Trie< ptr< ValueProvider > >        m_valueStore;
            ptr< TemplateRuleSet >              m_templateRuleSet;
            ptr< InvocationRuleSet >            m_invocationRuleSet;
            ptr< TypeCheckingRuleSet >           m_unificationRuleSet;
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
            ptr< OverloadSet >                  m_extLowerTypeForVerification;
            ptr< OverloadSet >                  m_extLowerConstantForVerification;

            uint64_t                            m_valueStoreVersion = 0;

            ptr< CTMemoryManager >              m_memManager;

            // LLR funcs form a cyclic graph, since functions can
            // be recursive or mutually recursive.
            // Since they end up being stored in llr::Call in the form of values,
            // it means that func values have to keep a weak_ptr to their llr func.
            // Therefore we have Env take care of keeping the llr func ownership.
            static vector< ptr< llr::Func > >   ms_llrFuncs;

            static uint32_t ms_nextUniqueId;
    };
}

#endif







|

|
|
|
|






89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
            ptr< OverloadSet >                  m_extLowerTypeForVerification;
            ptr< OverloadSet >                  m_extLowerConstantForVerification;

            uint64_t                            m_valueStoreVersion = 0;

            ptr< CTMemoryManager >              m_memManager;

            // CIR funcs form a cyclic graph, since functions can
            // be recursive or mutually recursive.
            // Since they end up being stored in cir::Call in the form of values,
            // it means that func values have to keep a weak_ptr to their cir func.
            // Therefore we have Env take care of keeping the cir func ownership.
            static vector< ptr< cir::Func > >   ms_cirFuncs;

            static uint32_t ms_nextUniqueId;
    };
}

#endif
Changes to bs/sema/lower.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
#include "sema.h"
#include "builtins/builtins.h"

using namespace goose;
using namespace goose::ir;
using namespace goose::builtins;

namespace goose::sema
{
    optional< Value > LowerTypeForRuntime( const Context& c, const Value& type )
    {
        if( IsRuntimeType( type ) )




|







1
2
3
4
5
6
7
8
9
10
11
12
#include "sema.h"
#include "builtins/builtins.h"

using namespace goose;
using namespace goose::eir;
using namespace goose::builtins;

namespace goose::sema
{
    optional< Value > LowerTypeForRuntime( const Context& c, const Value& type )
    {
        if( IsRuntimeType( type ) )
Changes to bs/sema/sema.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#ifndef GOOSE_SEMA_H
#define GOOSE_SEMA_H

#include "util/util.h"
#include "ir/ir.h"
#include "llr/llr.h"
#include "diagnostics/diagnostics.h"

namespace goose::sema
{
    using namespace util;
    using namespace ir;
    using namespace diagnostics;

    class Context;
    extern optional< Value > LowerTypeForRuntime( const Context& c, const Value& type );
    extern optional< Value > LowerConstantForRuntime( const Context& c, const Value& val );
    extern optional< Value > LowerTypeForVerification( const Context& c, const Value& type );
    extern optional< Value > LowerConstantForVerification( const Context& c, const Value& val );




|
|





|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#ifndef GOOSE_SEMA_H
#define GOOSE_SEMA_H

#include "util/util.h"
#include "eir/eir.h"
#include "cir/cir.h"
#include "diagnostics/diagnostics.h"

namespace goose::sema
{
    using namespace util;
    using namespace eir;
    using namespace diagnostics;

    class Context;
    extern optional< Value > LowerTypeForRuntime( const Context& c, const Value& type );
    extern optional< Value > LowerConstantForRuntime( const Context& c, const Value& val );
    extern optional< Value > LowerTypeForVerification( const Context& c, const Value& type );
    extern optional< Value > LowerConstantForVerification( const Context& c, const Value& val );
Changes to bs/sema/tctrie.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
#ifndef GOOSE_SEMA_TCTRIE_H
#define GOOSE_SEMA_TCTRIE_H

namespace goose::sema
{
    // Similar to an ir trie, but instead of being used to find the best pattern among a set of patterns,
    // it is used to find the best typing among a set of vector terms.
    // This is used to construct overload sets and to efficiently resolve overloads.
    template< typename U >
    class TCTrie
    {
        public:
            template< typename F >





|







1
2
3
4
5
6
7
8
9
10
11
12
13
#ifndef GOOSE_SEMA_TCTRIE_H
#define GOOSE_SEMA_TCTRIE_H

namespace goose::sema
{
    // Similar to an eir trie, but instead of being used to find the best pattern among a set of patterns,
    // it is used to find the best typing among a set of vector terms.
    // This is used to construct overload sets and to efficiently resolve overloads.
    template< typename U >
    class TCTrie
    {
        public:
            template< typename F >
Changes to bs/sema/tctrie.inl.
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
        {
            auto nextIt = it;
            ++nextIt;

            return Merge< T >( payload, nextIt, end, forward< F >( next ) );
        } );

        pNewNode->m_trie = ir::Merge( pNewNode->m_trie, *it, move( f ) );
        return pNewNode;
    }

    template< typename U > template< typename F >
    ptr< typename TCTrie< U >::RepetitionNode > TCTrie< U >::Merge( const ptr< RepetitionNode >& lhs, const Term& rhs, F&& next )
    {
        auto pNewNode = make_shared< RepetitionNode >();

        pNewNode->m_next = next( lhs ? lhs->m_next : U() );

        if( lhs )
            pNewNode->m_repetition = lhs->m_repetition;

        pNewNode->m_repetition = ir::Merge( pNewNode->m_repetition, rhs );
        return pNewNode;
    }

    template< typename U > template< typename F >
    ptr< TCTrie< U > > TCTrie< U >::merge( const Vector& v, F&& next ) const
    {
        auto pNewTrie = make_shared< TCTrie< U > >( *this );







|













|







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
        {
            auto nextIt = it;
            ++nextIt;

            return Merge< T >( payload, nextIt, end, forward< F >( next ) );
        } );

        pNewNode->m_trie = eir::Merge( pNewNode->m_trie, *it, move( f ) );
        return pNewNode;
    }

    template< typename U > template< typename F >
    ptr< typename TCTrie< U >::RepetitionNode > TCTrie< U >::Merge( const ptr< RepetitionNode >& lhs, const Term& rhs, F&& next )
    {
        auto pNewNode = make_shared< RepetitionNode >();

        pNewNode->m_next = next( lhs ? lhs->m_next : U() );

        if( lhs )
            pNewNode->m_repetition = lhs->m_repetition;

        pNewNode->m_repetition = eir::Merge( pNewNode->m_repetition, rhs );
        return pNewNode;
    }

    template< typename U > template< typename F >
    ptr< TCTrie< U > > TCTrie< U >::merge( const Vector& v, F&& next ) const
    {
        auto pNewTrie = make_shared< TCTrie< U > >( *this );
Changes to bs/sema/tests/meson.build.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
tests = [
    'unify-holes',
    'tctrie-merge',
    'tctrie-typecheck'
]

foreach t : tests
    exe = executable( 'sema-' + t, t + '.cpp',
        link_with:
        [
            goose_util,
            goose_ir,
            goose_sema
        ],
        include_directories: bsinc,
        dependencies: [catch2_dep, fmt_dep, llvm_dep]
    )
    test( 'sema-' + t, exe )
endforeach











|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
tests = [
    'unify-holes',
    'tctrie-merge',
    'tctrie-typecheck'
]

foreach t : tests
    exe = executable( 'sema-' + t, t + '.cpp',
        link_with:
        [
            goose_util,
            goose_eir,
            goose_sema
        ],
        include_directories: bsinc,
        dependencies: [catch2_dep, fmt_dep, llvm_dep]
    )
    test( 'sema-' + t, exe )
endforeach
Changes to bs/sema/tests/tctrie-merge.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#define CATCH_CONFIG_MAIN
#include "catch2/catch.hpp"
#include "sema/sema.h"
#include "builtins/builtins.h"

using namespace std;
using namespace goose;
using namespace goose::ir;
using namespace goose::sema;
using namespace goose::builtins;

SCENARIO( "TCTrie merge works", "[utrie-merge]" )
{
    WHEN( "Merging various expressions into an utrie" )
    {







|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#define CATCH_CONFIG_MAIN
#include "catch2/catch.hpp"
#include "sema/sema.h"
#include "builtins/builtins.h"

using namespace std;
using namespace goose;
using namespace goose::eir;
using namespace goose::sema;
using namespace goose::builtins;

SCENARIO( "TCTrie merge works", "[utrie-merge]" )
{
    WHEN( "Merging various expressions into an utrie" )
    {
Changes to bs/sema/tests/tctrie-typecheck.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#define CATCH_CONFIG_MAIN
#include "catch2/catch.hpp"
#include "sema/sema.h"
#include "builtins/builtins.h"

using namespace std;
using namespace goose;
using namespace goose::ir;
using namespace goose::sema;
using namespace goose::builtins;

namespace
{
    auto GetSortedSolutions( const ptr< Env >& e, ptr< TCTrie< string > >& trie, const Vector& vec )
    {







|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#define CATCH_CONFIG_MAIN
#include "catch2/catch.hpp"
#include "sema/sema.h"
#include "builtins/builtins.h"

using namespace std;
using namespace goose;
using namespace goose::eir;
using namespace goose::sema;
using namespace goose::builtins;

namespace
{
    auto GetSortedSolutions( const ptr< Env >& e, ptr< TCTrie< string > >& trie, const Vector& vec )
    {
Changes to bs/sema/tests/unify-holes.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#define CATCH_CONFIG_MAIN
#include "catch2/catch.hpp"
#include "sema/sema.h"
#include "builtins/builtins.h"

using namespace std;
using namespace goose;
using namespace goose::ir;
using namespace goose::sema;
using namespace goose::builtins;

namespace
{
    // Verifies that the unification of lhs and rhs yields only one solution, that it is complete,
    // and that this solution is the expected one.







|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#define CATCH_CONFIG_MAIN
#include "catch2/catch.hpp"
#include "sema/sema.h"
#include "builtins/builtins.h"

using namespace std;
using namespace goose;
using namespace goose::eir;
using namespace goose::sema;
using namespace goose::builtins;

namespace
{
    // Verifies that the unification of lhs and rhs yields only one solution, that it is complete,
    // and that this solution is the expected one.
Changes to bs/verify/basicblock.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include "verify.h"
#include "builtins/builtins.h"
#include "diagnostics/diagnostics.h"

using namespace goose::diagnostics;

namespace goose::verify
{
    bool Func::buildZ3ExpressionsForBB( const llr::BasicBlock& bb )
    {
        uint32_t bbid = m_remapper.remapBBId( bb );

        if( m_convertedBBIndices.contains( bbid ) )
            return false;

        m_convertedBBIndices.emplace( bbid );








|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include "verify.h"
#include "builtins/builtins.h"
#include "diagnostics/diagnostics.h"

using namespace goose::diagnostics;

namespace goose::verify
{
    bool Func::buildZ3ExpressionsForBB( const cir::BasicBlock& bb )
    {
        uint32_t bbid = m_remapper.remapBBId( bb );

        if( m_convertedBBIndices.contains( bbid ) )
            return false;

        m_convertedBBIndices.emplace( bbid );
Changes to bs/verify/builder.h.
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
            const auto& context() const { return *m_context; }
            auto* solver() { return m_solver; }
            auto* remapper() { return m_remapper; }
            uint32_t currentBBIndex() const { return m_currentBBIndex; }

            void setTraceMode( bool b ) { m_traceMode = b; }

            void setCFG( const ptr< llr::CFG >& cfg )
            {
                m_cfg = cfg;
            }

            void setCurrentBB( uint32_t index )
            {
                m_currentBBIndex = index;







|







26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
            const auto& context() const { return *m_context; }
            auto* solver() { return m_solver; }
            auto* remapper() { return m_remapper; }
            uint32_t currentBBIndex() const { return m_currentBBIndex; }

            void setTraceMode( bool b ) { m_traceMode = b; }

            void setCFG( const ptr< cir::CFG >& cfg )
            {
                m_cfg = cfg;
            }

            void setCurrentBB( uint32_t index )
            {
                m_currentBBIndex = index;
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
        private:
            optional< Z3Val > getVarForBasicBlock( uint32_t bbIndex, uint32_t index ) const;

            const sema::Context* m_context;
            z3::solver* m_solver = nullptr;
            Remapper* m_remapper = nullptr;

            ptr< llr::CFG > m_cfg;
            uint32_t m_currentBBIndex = 1;

            // All emitted assumptions and assertions are wrapped
            // with implications 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;

            AssHandler m_assertionHandler;

            // For each variable and temporary, store its last value as a z3 expression.
            using VarState = llvm::SmallVector< optional< Z3Val >, 16 >;
            using VarStorage = llr::TempStorage< VarState >;

            VarStorage m_varStorage;
            unordered_map< StringId, z3::expr > m_placeholders;

            // TODO: investigate why this not being static breaks things, since it should
            // be saved and restored whenever the solver is, but apparently it causes name collisions
            // that invalidate the formulas. This works fine like this but it makes z3 formulas dumps







|













|







71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
        private:
            optional< Z3Val > getVarForBasicBlock( uint32_t bbIndex, uint32_t index ) const;

            const sema::Context* m_context;
            z3::solver* m_solver = nullptr;
            Remapper* m_remapper = nullptr;

            ptr< cir::CFG > m_cfg;
            uint32_t m_currentBBIndex = 1;

            // All emitted assumptions and assertions are wrapped
            // with implications 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;

            AssHandler m_assertionHandler;

            // For each variable and temporary, store its last value as a z3 expression.
            using VarState = llvm::SmallVector< optional< Z3Val >, 16 >;
            using VarStorage = cir::TempStorage< VarState >;

            VarStorage m_varStorage;
            unordered_map< StringId, z3::expr > m_placeholders;

            // TODO: investigate why this not being static breaks things, since it should
            // be saved and restored whenever the solver is, but apparently it causes name collisions
            // that invalidate the formulas. This works fine like this but it makes z3 formulas dumps
Changes to bs/verify/call.cpp.
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
                )
            );

            if( !result )
                return true;

            auto&& [type, val, locId] = *result;
            auto paramVal = BuildComputedValue( type, CalcAddress( llr::VarBaseAddr( varId++ ) ) );

            if( auto zv = BuildZ3ExprFromValue( cb, paramVal ) )
            {
                ForEachPredicate( cb, type, zv->expr, [&]( auto&& z3expr, auto locId )
                {
                    DiagnosticsContext dc( instr.func().locationId(), "At this call." );
                    b.checkAssertion( z3expr, locId );







|







55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
                )
            );

            if( !result )
                return true;

            auto&& [type, val, locId] = *result;
            auto paramVal = BuildComputedValue( type, CalcAddress( cir::VarBaseAddr( varId++ ) ) );

            if( auto zv = BuildZ3ExprFromValue( cb, paramVal ) )
            {
                ForEachPredicate( cb, type, zv->expr, [&]( auto&& z3expr, auto locId )
                {
                    DiagnosticsContext dc( instr.func().locationId(), "At this call." );
                    b.checkAssertion( z3expr, locId );
Changes to bs/verify/cfg.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include "verify.h"
#include "builtins/builtins.h"
#include "diagnostics/diagnostics.h"

using namespace goose::diagnostics;

namespace goose::verify
{
    bool Func::buildZ3Expressions( const llr::BasicBlock& bb, queue< const BasicBlock* >* parentWorkQueue )
    {
        uint32_t currentLoopId = m_remapper.getCurrentLoopId();

        queue< const BasicBlock* > workQueue;
        workQueue.push( &bb );

        while( !workQueue.empty() && !m_builder.hasCheckFailed() )








|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include "verify.h"
#include "builtins/builtins.h"
#include "diagnostics/diagnostics.h"

using namespace goose::diagnostics;

namespace goose::verify
{
    bool Func::buildZ3Expressions( const cir::BasicBlock& bb, queue< const BasicBlock* >* parentWorkQueue )
    {
        uint32_t currentLoopId = m_remapper.getCurrentLoopId();

        queue< const BasicBlock* > workQueue;
        workQueue.push( &bb );

        while( !workQueue.empty() && !m_builder.hasCheckFailed() )
Changes to bs/verify/comptime.cpp.
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
                    return false;
            }
        } );

        bool result = visit( [&]( auto&& instr )
        {
            return VerifyCompTimeExpr( b, instr );
        }, val.llr()->content() );

        if( Func::TraceMode() )
            cout << '\n';

        return result;
    }








|







66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
                    return false;
            }
        } );

        bool result = visit( [&]( auto&& instr )
        {
            return VerifyCompTimeExpr( b, instr );
        }, val.cir()->content() );

        if( Func::TraceMode() )
            cout << '\n';

        return result;
    }

140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
                )
            );

            if( !result )
                return true;

            auto&& [type, val, locId] = *result;
            builtins::Reference argRef( builtins::ReferenceType{ type, TSID( const ) }, llr::VarBaseAddr( varId++ ) );
            auto paramVal = BuildComputedValue( type, llr::Load( ToValue( argRef ), type ) );

            if( auto zv = BuildZ3ExprFromValue( b, paramVal ) )
            {
                ForEachPredicate( b, type, zv->expr, [&]( auto&& z3expr, auto locId )
                {
                    DiagnosticsContext dc( instr.func().locationId(), "At this compilation-time call." );
                    b.checkAssertion( z3expr, locId );







|
|







140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
                )
            );

            if( !result )
                return true;

            auto&& [type, val, locId] = *result;
            builtins::Reference argRef( builtins::ReferenceType{ type, TSID( const ) }, cir::VarBaseAddr( varId++ ) );
            auto paramVal = BuildComputedValue( type, cir::Load( ToValue( argRef ), type ) );

            if( auto zv = BuildZ3ExprFromValue( b, paramVal ) )
            {
                ForEachPredicate( b, type, zv->expr, [&]( auto&& z3expr, auto locId )
                {
                    DiagnosticsContext dc( instr.func().locationId(), "At this compilation-time call." );
                    b.checkAssertion( z3expr, locId );
Changes to bs/verify/func.cpp.
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
{
    bool Func::ms_TraceMode = false;
    bool Func::ms_DumpSolverOnFailure = false;
    bool Func::ms_DumpSolverOnSuccess = false;

    Func::Func( const sema::Context& c, const builtins::Func& func ) :
        m_func( &func ),
        m_cfg( func.llr()->body() ),
        m_solver( GetZ3Context() ),
        m_remapper( m_cfg->count() + 1 ),
        m_builder( c, m_solver, &m_remapper )
    {}

    Func::Func( const sema::Context& c, const ptr< llr::CFG >& cfg ) :
        m_cfg( cfg ),
        m_solver( GetZ3Context() ),
        m_remapper( m_cfg->count() + 1 ),
        m_builder( c, m_solver, &m_remapper )
    {}

    bool Func::verify()







|





|







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
{
    bool Func::ms_TraceMode = false;
    bool Func::ms_DumpSolverOnFailure = false;
    bool Func::ms_DumpSolverOnSuccess = false;

    Func::Func( const sema::Context& c, const builtins::Func& func ) :
        m_func( &func ),
        m_cfg( func.cir()->body() ),
        m_solver( GetZ3Context() ),
        m_remapper( m_cfg->count() + 1 ),
        m_builder( c, m_solver, &m_remapper )
    {}

    Func::Func( const sema::Context& c, const ptr< cir::CFG >& cfg ) :
        m_cfg( cfg ),
        m_solver( GetZ3Context() ),
        m_remapper( m_cfg->count() + 1 ),
        m_builder( c, m_solver, &m_remapper )
    {}

    bool Func::verify()
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
                        )
                    );

                    if( !result )
                        return true;

                    auto&& [type, val, locId] = *result;
                    builtins::Reference argRef( builtins::ReferenceType{ type, TSID( const ) }, llr::VarBaseAddr( varId ) );
                    auto paramVal = BuildComputedValue( type, llr::Load( ToValue( argRef ), type ) );

                    // Initialize every parameter containing variable with an freshly named constant of the right type.
                    if( auto paramInit = BuildZ3ConstantFromType( m_builder, type, format( "p{}", varId ) ) )
                        m_builder.setVar( varId, move( *paramInit ) );

                    ++varId;








|
|







67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
                        )
                    );

                    if( !result )
                        return true;

                    auto&& [type, val, locId] = *result;
                    builtins::Reference argRef( builtins::ReferenceType{ type, TSID( const ) }, cir::VarBaseAddr( varId ) );
                    auto paramVal = BuildComputedValue( type, cir::Load( ToValue( argRef ), type ) );

                    // Initialize every parameter containing variable with an freshly named constant of the right type.
                    if( auto paramInit = BuildZ3ConstantFromType( m_builder, type, format( "p{}", varId ) ) )
                        m_builder.setVar( varId, move( *paramInit ) );

                    ++varId;

Changes to bs/verify/func.h.
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

namespace goose::verify
{
    class Func
    {
        public:
            Func( const sema::Context& c, const builtins::Func& func );
            Func( const sema::Context& c, const ptr< llr::CFG >& cfg );
            bool verify();

            static void SetTraceMode( bool b ) { ms_TraceMode = b; }
            static void SetDumpSolverOnFailure( bool b ) { ms_DumpSolverOnFailure = b; }
            static void SetDumpSolverOnSuccess( bool b ) { ms_DumpSolverOnSuccess = b; }

            static bool TraceMode() { return ms_TraceMode; }
            static bool DumpSolverOnFailure() { return ms_DumpSolverOnFailure; }
            static bool DumpSolverOnSuccess() { return ms_DumpSolverOnSuccess; }

        private:
            bool buildZ3Expressions( const llr::BasicBlock& bb, queue< const BasicBlock* >* parentWorkQueue );
            bool buildZ3ExpressionsForBB( const llr::BasicBlock& bb );
            bool checkLoop( const llr::BasicBlock& header, queue< const BasicBlock* >& parentWorkQueue );

            bool handleTerminator( uint32_t bbIndex, const llr::Terminator& t );

            template< typename T >
            bool handleTerminator( uint32_t bbIndex, const T& t )
            {
                return true;
            }

            bool handleTerminator( uint32_t bbIndex, const llr::Ret& t );
            bool handleTerminator( uint32_t bbIndex, const llr::Branch& t );
            bool handleTerminator( uint32_t bbIndex, const llr::CondBranch& t );

            z3::expr makeEdgeExpression( uint32_t srcBBId, uint32_t destBBId, const z3::expr& cond );

            bool checkAssertion( const z3::expr& expr, const z3::expr& exprToCheck, uint32_t locationId );

            const builtins::Func* m_func = nullptr;
            ptr< llr::CFG > m_cfg;

            z3::solver m_solver;
            Remapper m_remapper;
            Builder m_builder;

            optional< z3::expr > m_currentBBPredicate;








|











|
|
|

|







|
|
|






|







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

namespace goose::verify
{
    class Func
    {
        public:
            Func( const sema::Context& c, const builtins::Func& func );
            Func( const sema::Context& c, const ptr< cir::CFG >& cfg );
            bool verify();

            static void SetTraceMode( bool b ) { ms_TraceMode = b; }
            static void SetDumpSolverOnFailure( bool b ) { ms_DumpSolverOnFailure = b; }
            static void SetDumpSolverOnSuccess( bool b ) { ms_DumpSolverOnSuccess = b; }

            static bool TraceMode() { return ms_TraceMode; }
            static bool DumpSolverOnFailure() { return ms_DumpSolverOnFailure; }
            static bool DumpSolverOnSuccess() { return ms_DumpSolverOnSuccess; }

        private:
            bool buildZ3Expressions( const cir::BasicBlock& bb, queue< const BasicBlock* >* parentWorkQueue );
            bool buildZ3ExpressionsForBB( const cir::BasicBlock& bb );
            bool checkLoop( const cir::BasicBlock& header, queue< const BasicBlock* >& parentWorkQueue );

            bool handleTerminator( uint32_t bbIndex, const cir::Terminator& t );

            template< typename T >
            bool handleTerminator( uint32_t bbIndex, const T& t )
            {
                return true;
            }

            bool handleTerminator( uint32_t bbIndex, const cir::Ret& t );
            bool handleTerminator( uint32_t bbIndex, const cir::Branch& t );
            bool handleTerminator( uint32_t bbIndex, const cir::CondBranch& t );

            z3::expr makeEdgeExpression( uint32_t srcBBId, uint32_t destBBId, const z3::expr& cond );

            bool checkAssertion( const z3::expr& expr, const z3::expr& exprToCheck, uint32_t locationId );

            const builtins::Func* m_func = nullptr;
            ptr< cir::CFG > m_cfg;

            z3::solver m_solver;
            Remapper m_remapper;
            Builder m_builder;

            optional< z3::expr > m_currentBBPredicate;

Changes to bs/verify/loop.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include "verify.h"
#include "builtins/builtins.h"
using namespace goose::diagnostics;

// This is an implementation of the "Software Verification Using k-Induction" algorithm.
// http://www.cprover.org/kinduction/

namespace goose::verify
{
    bool Func::checkLoop( const llr::BasicBlock& header, queue< const BasicBlock* >& parentWorkQueue )
    {
        if( ms_TraceMode )
            cout << "  == Checking loop " << header.index() << endl;

        AssertionHandlerGuard ahg( m_builder );

        m_remapper.beginLoopUnrolling( header.index() );









|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include "verify.h"
#include "builtins/builtins.h"
using namespace goose::diagnostics;

// This is an implementation of the "Software Verification Using k-Induction" algorithm.
// http://www.cprover.org/kinduction/

namespace goose::verify
{
    bool Func::checkLoop( const cir::BasicBlock& header, queue< const BasicBlock* >& parentWorkQueue )
    {
        if( ms_TraceMode )
            cout << "  == Checking loop " << header.index() << endl;

        AssertionHandlerGuard ahg( m_builder );

        m_remapper.beginLoopUnrolling( header.index() );
Changes to bs/verify/remapper.cpp.
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
    rm.emplace( blUnrollId, newRemappedIndex );

    m_originalBBIndices.emplace( newRemappedIndex, blUnrollId.first );

    return newRemappedIndex;
}

uint32_t Remapper::remapBBId( const llr::BasicBlock& bb )
{
    if( m_loopUnrollingStack.empty() )
        return bb.index();

    auto& lus = m_loopUnrollingStack.back();
    auto blUnrollId = make_pair( bb.index(), lus.currentUnrollIndex );
    return remap( lus.loopRemapping, blUnrollId );
}

uint32_t Remapper::remapOutgoingEdge( const llr::BasicBlock& currentBB, const llr::BasicBlock& succBB )
{
    if( succBB.isLoopHeader() )
    {
        // Exiting into a loop header. If it's an active loop, we are exiting into its next iteration.
        // Otherwise, we are exiting into its first iteration.
        auto it = find_if( m_loopUnrollingStack.rbegin(), m_loopUnrollingStack.rend(), [&]( auto&& lus )
        {







|









|







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
    rm.emplace( blUnrollId, newRemappedIndex );

    m_originalBBIndices.emplace( newRemappedIndex, blUnrollId.first );

    return newRemappedIndex;
}

uint32_t Remapper::remapBBId( const cir::BasicBlock& bb )
{
    if( m_loopUnrollingStack.empty() )
        return bb.index();

    auto& lus = m_loopUnrollingStack.back();
    auto blUnrollId = make_pair( bb.index(), lus.currentUnrollIndex );
    return remap( lus.loopRemapping, blUnrollId );
}

uint32_t Remapper::remapOutgoingEdge( const cir::BasicBlock& currentBB, const cir::BasicBlock& succBB )
{
    if( succBB.isLoopHeader() )
    {
        // Exiting into a loop header. If it's an active loop, we are exiting into its next iteration.
        // Otherwise, we are exiting into its first iteration.
        auto it = find_if( m_loopUnrollingStack.rbegin(), m_loopUnrollingStack.rend(), [&]( auto&& lus )
        {
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
    auto it = m_originalBBIndices.find( remappedId );
    if( it == m_originalBBIndices.end() )
        return remappedId;

    return it->second;
}

bool Remapper::areAllPredecessorsProcessed( const llr::BasicBlock& bb )
{
    auto bbid = remapBBId( bb );
    auto begin = m_edges.lower_bound( { bbid, 0U } );
    auto end = m_edges.upper_bound( { bbid, ~0U } );

    uint32_t expected = bb.backEdges().size();








|







101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
    auto it = m_originalBBIndices.find( remappedId );
    if( it == m_originalBBIndices.end() )
        return remappedId;

    return it->second;
}

bool Remapper::areAllPredecessorsProcessed( const cir::BasicBlock& bb )
{
    auto bbid = remapBBId( bb );
    auto begin = m_edges.lower_bound( { bbid, 0U } );
    auto end = m_edges.upper_bound( { bbid, ~0U } );

    uint32_t expected = bb.backEdges().size();

Changes to bs/verify/remapper.h.
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
    class Remapper
    {
        public:
            Remapper( uint32_t firstRemappedId ) :
                m_nextUniqueId( firstRemappedId )
            {}

            uint32_t remapBBId( const llr::BasicBlock& bb );
            uint32_t remapOutgoingEdge( const llr::BasicBlock& currentBB, const llr::BasicBlock& succBB );

            uint32_t getCurrentLoopId() const;

            void beginLoopUnrolling( uint32_t loopId );
            void endLoopUnrolling();
            void nextLoopIteration();








|
|







13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
    class Remapper
    {
        public:
            Remapper( uint32_t firstRemappedId ) :
                m_nextUniqueId( firstRemappedId )
            {}

            uint32_t remapBBId( const cir::BasicBlock& bb );
            uint32_t remapOutgoingEdge( const cir::BasicBlock& currentBB, const cir::BasicBlock& succBB );

            uint32_t getCurrentLoopId() const;

            void beginLoopUnrolling( uint32_t loopId );
            void endLoopUnrolling();
            void nextLoopIteration();

45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
            // Given a basic block index, if it's a remapped index (an invented index
            // for an unrolled basic block), return the original BB index.
            uint32_t getOriginalBBIndex( uint32_t remappedId ) const;

            // Indicate whether all the (possibly unrolled) predecessors of a
            // basic block have been processed by checking if the number of
            // generated edges matches the number of incoming edges of the block.
            bool areAllPredecessorsProcessed( const llr::BasicBlock& bb );

        private:
            struct LoopUnrollingState
            {
                RemappingMap loopRemapping;
                uint32_t loopId = 0;
                uint32_t currentUnrollIndex = 0;







|







45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
            // Given a basic block index, if it's a remapped index (an invented index
            // for an unrolled basic block), return the original BB index.
            uint32_t getOriginalBBIndex( uint32_t remappedId ) const;

            // Indicate whether all the (possibly unrolled) predecessors of a
            // basic block have been processed by checking if the number of
            // generated edges matches the number of incoming edges of the block.
            bool areAllPredecessorsProcessed( const cir::BasicBlock& bb );

        private:
            struct LoopUnrollingState
            {
                RemappingMap loopRemapping;
                uint32_t loopId = 0;
                uint32_t currentUnrollIndex = 0;
Changes to bs/verify/storage.cpp.
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
    {
        return visit( [&]( auto&& ba )
        {
            return LoadFromAddress( b, ba );
        }, baseAddr );
    }

    optional< Z3Val > LoadFromAddress( Builder& b, const llr::TemporaryBaseAddr& ta )
    {
        auto zv = b.retrieveVar( ta.index );
        if( zv )
            return zv;

        return b.setVar( ta.index, ta.m_initValue );
    }

    optional< Z3Val > LoadFromAddress( Builder& b, const llr::VarBaseAddr& va )
    {
        return b.retrieveVar( va.index );
    }

    optional< z3::expr > ModifyAggregate( Builder& b, const Z3Val& aggregate, const AddressPath& path, uint32_t index, Z3Val&& valToStore )
    {
        auto tinfo = TypeCache::GetInstance()->getTypeInfo( b.context(), ValueToIRExpr( aggregate.type ) );







|








|







32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
    {
        return visit( [&]( auto&& ba )
        {
            return LoadFromAddress( b, ba );
        }, baseAddr );
    }

    optional< Z3Val > LoadFromAddress( Builder& b, const cir::TemporaryBaseAddr& ta )
    {
        auto zv = b.retrieveVar( ta.index );
        if( zv )
            return zv;

        return b.setVar( ta.index, ta.m_initValue );
    }

    optional< Z3Val > LoadFromAddress( Builder& b, const cir::VarBaseAddr& va )
    {
        return b.retrieveVar( va.index );
    }

    optional< z3::expr > ModifyAggregate( Builder& b, const Z3Val& aggregate, const AddressPath& path, uint32_t index, Z3Val&& valToStore )
    {
        auto tinfo = TypeCache::GetInstance()->getTypeInfo( b.context(), ValueToIRExpr( aggregate.type ) );
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
    {
        return visit( [&]( auto&& ba )
        {
            return StoreToAddress( b, ba, move( val ) );
        }, baseAddr );
    }

    void StoreToAddress( Builder& b, const llr::TemporaryBaseAddr& ta, Z3Val&& val )
    {
        b.setVar( ta.index, move( val ) );
    }

    void StoreToAddress( Builder& b, const llr::VarBaseAddr& va, Z3Val&& val )
    {
        b.setVar( va.index, move( val ) );
    }

    void HavocAddress( Builder& b, uint32_t bbIndex, const Term& type, const CalcAddress& addr )
    {
        auto valToStore = BuildZ3ConstantFromType( b, type, format( "v{}", b.newUniqueId() ) );
        if( !valToStore )
            return;

        StoreToAddress( b, addr, move( *valToStore ) );
    }
}







|




|













119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
    {
        return visit( [&]( auto&& ba )
        {
            return StoreToAddress( b, ba, move( val ) );
        }, baseAddr );
    }

    void StoreToAddress( Builder& b, const cir::TemporaryBaseAddr& ta, Z3Val&& val )
    {
        b.setVar( ta.index, move( val ) );
    }

    void StoreToAddress( Builder& b, const cir::VarBaseAddr& va, Z3Val&& val )
    {
        b.setVar( va.index, move( val ) );
    }

    void HavocAddress( Builder& b, uint32_t bbIndex, const Term& type, const CalcAddress& addr )
    {
        auto valToStore = BuildZ3ConstantFromType( b, type, format( "v{}", b.newUniqueId() ) );
        if( !valToStore )
            return;

        StoreToAddress( b, addr, move( *valToStore ) );
    }
}
Changes to bs/verify/storage.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#ifndef GOOSE_VERIFY_STORAGE_H
#define GOOSE_VERIFY_STORAGE_H

namespace goose::verify
{
    extern optional< Z3Val > LoadFromAddress( Builder& b, const llr::CalcAddress& addr );
    extern optional< Z3Val > LoadFromAddress( Builder& b, const BaseAddress& baseAddr );
    extern optional< Z3Val > LoadFromAddress( Builder& b, const llr::TemporaryBaseAddr& ta );
    extern optional< Z3Val > LoadFromAddress( Builder& b, const llr::VarBaseAddr& va );

    extern void StoreToAddress( Builder& b, const llr::CalcAddress& addr, Z3Val&& val );
    extern void StoreToAddress( Builder& b, const BaseAddress& baseAddr, Z3Val&& val );
    extern void StoreToAddress( Builder& b, const llr::TemporaryBaseAddr& ta, Z3Val&& val );
    extern void StoreToAddress( Builder& b, const llr::VarBaseAddr& va, Z3Val&& val );

    extern void HavocAddress( Builder& b, uint32_t bbIndex, const Term& type, const llr::CalcAddress& addr );
}

#endif





|

|
|

|

|
|

|



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#ifndef GOOSE_VERIFY_STORAGE_H
#define GOOSE_VERIFY_STORAGE_H

namespace goose::verify
{
    extern optional< Z3Val > LoadFromAddress( Builder& b, const cir::CalcAddress& addr );
    extern optional< Z3Val > LoadFromAddress( Builder& b, const BaseAddress& baseAddr );
    extern optional< Z3Val > LoadFromAddress( Builder& b, const cir::TemporaryBaseAddr& ta );
    extern optional< Z3Val > LoadFromAddress( Builder& b, const cir::VarBaseAddr& va );

    extern void StoreToAddress( Builder& b, const cir::CalcAddress& addr, Z3Val&& val );
    extern void StoreToAddress( Builder& b, const BaseAddress& baseAddr, Z3Val&& val );
    extern void StoreToAddress( Builder& b, const cir::TemporaryBaseAddr& ta, Z3Val&& val );
    extern void StoreToAddress( Builder& b, const cir::VarBaseAddr& va, Z3Val&& val );

    extern void HavocAddress( Builder& b, uint32_t bbIndex, const Term& type, const cir::CalcAddress& addr );
}

#endif
Changes to bs/verify/terminator.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
#include "verify.h"
#include "builtins/builtins.h"
#include "diagnostics/diagnostics.h"
#include "helpers.inl"

using namespace goose::diagnostics;

namespace goose::verify
{
    bool Func::handleTerminator( uint32_t bbIndex, const llr::Terminator& t )
    {
        return visit( [&]( auto&& t )
        {
            return handleTerminator( bbIndex, t );
        }, t.content() );
    }

    bool Func::handleTerminator( uint32_t bbIndex, const llr::Ret& tr )
    {
        // Emit the "ensures" expressions as assertions.
        if( !m_func )
            return true;

        // Deal with the return value.
        Builder cb( m_builder.context(), *m_builder.solver(), &m_remapper );









|







|







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
#include "verify.h"
#include "builtins/builtins.h"
#include "diagnostics/diagnostics.h"
#include "helpers.inl"

using namespace goose::diagnostics;

namespace goose::verify
{
    bool Func::handleTerminator( uint32_t bbIndex, const cir::Terminator& t )
    {
        return visit( [&]( auto&& t )
        {
            return handleTerminator( bbIndex, t );
        }, t.content() );
    }

    bool Func::handleTerminator( uint32_t bbIndex, const cir::Ret& tr )
    {
        // Emit the "ensures" expressions as assertions.
        if( !m_func )
            return true;

        // Deal with the return value.
        Builder cb( m_builder.context(), *m_builder.solver(), &m_remapper );
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

            return true;
        } );

        return success;
    }

    bool Func::handleTerminator( uint32_t bbIndex, const llr::Branch& t )
    {
        const auto& bb = m_cfg->getBB( bbIndex );

        uint32_t srcBBId = m_remapper.remapBBId( *bb );
        auto pDestBB = t.dest().lock();

        auto cond = GetZ3Context().bool_const( format( "b{}", srcBBId ).c_str() );

        uint32_t destBBId = m_remapper.remapOutgoingEdge( *bb, *pDestBB );
        m_remapper.addEdge( srcBBId, destBBId, move( cond ) );
        return true;
    }

    bool Func::handleTerminator( uint32_t bbIndex, const llr::CondBranch& t )
    {
        auto pTrueDestBB = t.trueDest().lock();
        auto pFalseDestBB = t.falseDest().lock();

        const auto& bb = m_cfg->getBB( bbIndex );

        uint32_t srcBBId = m_remapper.remapBBId( *bb );







|













|







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

            return true;
        } );

        return success;
    }

    bool Func::handleTerminator( uint32_t bbIndex, const cir::Branch& t )
    {
        const auto& bb = m_cfg->getBB( bbIndex );

        uint32_t srcBBId = m_remapper.remapBBId( *bb );
        auto pDestBB = t.dest().lock();

        auto cond = GetZ3Context().bool_const( format( "b{}", srcBBId ).c_str() );

        uint32_t destBBId = m_remapper.remapOutgoingEdge( *bb, *pDestBB );
        m_remapper.addEdge( srcBBId, destBBId, move( cond ) );
        return true;
    }

    bool Func::handleTerminator( uint32_t bbIndex, const cir::CondBranch& t )
    {
        auto pTrueDestBB = t.trueDest().lock();
        auto pFalseDestBB = t.falseDest().lock();

        const auto& bb = m_cfg->getBB( bbIndex );

        uint32_t srcBBId = m_remapper.remapBBId( *bb );
Changes to bs/verify/type.h.
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

            optional< TypeInfo > getTypeInfo( const sema::Context& c, const Term& type );

        private:
            static optional< TypeInfo > CreateTypeInfoForBasicType( const sema::Context& c, const Value& typeVal );
            static optional< TypeInfo > CreateTypeInfo( const sema::Context& c, const Term& type );

            // We use a trie to map the type ir expressions
            // to z3 constructor funcs.
            Trie< TypeInfo > m_typeInfos;

            static uint32_t ms_nextUniqueId;
    };
}








|







21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

            optional< TypeInfo > getTypeInfo( const sema::Context& c, const Term& type );

        private:
            static optional< TypeInfo > CreateTypeInfoForBasicType( const sema::Context& c, const Value& typeVal );
            static optional< TypeInfo > CreateTypeInfo( const sema::Context& c, const Term& type );

            // We use a trie to map the type eir expressions
            // to z3 constructor funcs.
            Trie< TypeInfo > m_typeInfos;

            static uint32_t ms_nextUniqueId;
    };
}

Changes to bs/verify/value.cpp.
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
        const auto* expr = b.retrievePlaceholder( instr.name() );
        if( expr )
            return Z3Val{ *expr, *ValueFromIRExpr( instr.type() ) };

        return BuildZ3ConstantFromType( b, instr.type(), format( "p{}", instr.name() ) );
    }

    optional< Z3Val > BuildZ3Op( Builder& b, const llr::Instruction& instr )
    {
        return visit( [&]( auto&& e )
        {
            return BuildZ3Op( b, e );
        }, instr.content() );
    }

    optional< Z3Val > BuildZ3ExprFromValue( Builder& b, const Value& val )
    {
        if( val.isPoison() )
            return nullopt;

        if( val.isConstant() )
            return BuildZ3ValFromConstant( b, val );

        if( auto expr = BuildZ3Op( b, *val.llr() )  )
            return expr;

        return BuildZ3ConstantFromType( b, val.type(), format( "val{}", b.newUniqueId() ) );
    }
}







|















|





383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
        const auto* expr = b.retrievePlaceholder( instr.name() );
        if( expr )
            return Z3Val{ *expr, *ValueFromIRExpr( instr.type() ) };

        return BuildZ3ConstantFromType( b, instr.type(), format( "p{}", instr.name() ) );
    }

    optional< Z3Val > BuildZ3Op( Builder& b, const cir::Instruction& instr )
    {
        return visit( [&]( auto&& e )
        {
            return BuildZ3Op( b, e );
        }, instr.content() );
    }

    optional< Z3Val > BuildZ3ExprFromValue( Builder& b, const Value& val )
    {
        if( val.isPoison() )
            return nullopt;

        if( val.isConstant() )
            return BuildZ3ValFromConstant( b, val );

        if( auto expr = BuildZ3Op( b, *val.cir() )  )
            return expr;

        return BuildZ3ConstantFromType( b, val.type(), format( "val{}", b.newUniqueId() ) );
    }
}
Changes to bs/verify/value.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#ifndef GOOSE_VERIFY_VALUE_H
#define GOOSE_VERIFY_VALUE_H

#include "z3++.h"
#include "llr/llr.h"

namespace goose::verify
{
    struct Z3Val
    {
        z3::expr expr;
        ir::Value type;
    };

    extern optional< Z3Val > BuildZ3ValFromConstant( Builder& b, const Value& val );
    extern optional< Z3Val > BuildZ3ExprFromValue( Builder& b, const Value& val );
    extern optional< Z3Val > BuildZ3ConstantFromType( Builder& b, const Value& type, const string& name );
    extern optional< Z3Val > BuildZ3ConstantFromType( Builder& b, const Term& type, const string& name );
    extern optional< Z3Val > BuildZ3Op( Builder& b, const llr::Instruction& instr );

    extern z3::expr GetAsBitVec( const z3::expr& expr, const Value& type );
    extern z3::expr GetAsBitVec( const Z3Val& zv );

    extern z3::expr GetAsInt( const z3::expr& expr, const Value& type );
    extern z3::expr GetAsInt( const Z3Val& zv );
}




|






|






|







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_VERIFY_VALUE_H
#define GOOSE_VERIFY_VALUE_H

#include "z3++.h"
#include "cir/cir.h"

namespace goose::verify
{
    struct Z3Val
    {
        z3::expr expr;
        eir::Value type;
    };

    extern optional< Z3Val > BuildZ3ValFromConstant( Builder& b, const Value& val );
    extern optional< Z3Val > BuildZ3ExprFromValue( Builder& b, const Value& val );
    extern optional< Z3Val > BuildZ3ConstantFromType( Builder& b, const Value& type, const string& name );
    extern optional< Z3Val > BuildZ3ConstantFromType( Builder& b, const Term& type, const string& name );
    extern optional< Z3Val > BuildZ3Op( Builder& b, const cir::Instruction& instr );

    extern z3::expr GetAsBitVec( const z3::expr& expr, const Value& type );
    extern z3::expr GetAsBitVec( const Z3Val& zv );

    extern z3::expr GetAsInt( const z3::expr& expr, const Value& type );
    extern z3::expr GetAsInt( const Z3Val& zv );
}
Changes to bs/verify/verify.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#ifndef GOOSE_VERIFY_H
#define GOOSE_VERIFY_H

#include <z3++.h>
#include "llr/llr.h"
#include "sema/sema.h"

namespace goose::verify
{
    using namespace ir;
    using namespace llr;

    class Builder;

    extern z3::context& GetZ3Context();

    extern bool VerifyCompTimeExpr( const sema::Context& c, const Value& val );
}




|




|
|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#ifndef GOOSE_VERIFY_H
#define GOOSE_VERIFY_H

#include <z3++.h>
#include "cir/cir.h"
#include "sema/sema.h"

namespace goose::verify
{
    using namespace eir;
    using namespace cir;

    class Builder;

    extern z3::context& GetZ3Context();

    extern bool VerifyCompTimeExpr( const sema::Context& c, const Value& val );
}