Goose  Check-in [bb17e9f3dd]

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

Overview
Comment:
  • Added a "LowerConstantForRuntime" extension point, similar to LowerTypeForRunTime.
  • Added a way to represent Record constants.
  • Implemented LowerConstantForRunTime for tuples, which lowers them into a constant record.
  • Implemented codegen for constant records.
  • Implemented codegen for storing an aggregate constant.
  • Implemented a way (not exposed in the syntax for now) to create vararg function types, to be able to call vararg external functions such as printf.
  • Enabled the tuple runtime/compilation combined test which is now working.
  • Various bug fixes.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: bb17e9f3dd6fb2f5be52f7a0e20f21158d2f27e4184539c5837c18f5c34f9b7c
User & Date: achavasse 2020-05-25 22:08:44.976
Context
2020-05-30
14:25
Enable's z3 new arith solver as the old one takes a very long time in one of the tests with the latest version of z3. check-in: 4b56796791 user: achavasse tags: trunk
2020-05-25
22:08
  • Added a "LowerConstantForRuntime" extension point, similar to LowerTypeForRunTime.
  • Added a way to represent Record constants.
  • Implemented LowerConstantForRunTime for tuples, which lowers them into a constant record.
  • Implemented codegen for constant records.
  • Implemented codegen for storing an aggregate constant.
  • Implemented a way (not exposed in the syntax for now) to create vararg function types, to be able to call vararg external functions such as printf.
  • Enabled the tuple runtime/compilation combined test which is now working.
  • Various bug fixes.
check-in: bb17e9f3dd user: achavasse tags: trunk
2020-05-23
12:58
  • Fixed the hole matching score which prevented some unification rules to be selected.
  • Implemented LowerTypeForRuntime for tuples.
  • Implemented an unification rule for constant tuples.
  • Added some debugging helpers.
check-in: c39a302502 user: achavasse tags: trunk
Changes
Unified Diff Ignore Whitespace Patch
Changes to bs/builtins/api/compiler.cpp.
99
100
101
102
103
104
105










106
107
108
109
110
111
112
            {
                auto ft = FromValue< FuncType >( f );
                if( !ft )
                    return PoisonValue();

                return ToValue( BuildExternalFunc( *ft, symbol ) );
            } );











        RegisterBuiltinFunc< void ( string, Value ) >( e, "CreateConstant"_sid,
            [pEnv]( const string& name, const Value& v )
            {
                if( !v.isConstant() )
                {
                    DiagnosticsManager::GetInstance().emitErrorMessage( v.locationId(),







>
>
>
>
>
>
>
>
>
>







99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
            {
                auto ft = FromValue< FuncType >( f );
                if( !ft )
                    return PoisonValue();

                return ToValue( BuildExternalFunc( *ft, symbol ) );
            } );

        RegisterBuiltinFunc< Eager< Value > ( Value, string ) >( e, "ExternalVarArgFunction"_sid,
            [pEnv]( const Value& f, const string& symbol )
            {
                auto ft = FromValue< FuncType >( f );
                if( !ft )
                    return PoisonValue();

                return ToValue( BuildExternalFunc( *ft, symbol, true ) );
            } );

        RegisterBuiltinFunc< void ( string, Value ) >( e, "CreateConstant"_sid,
            [pEnv]( const string& name, const Value& v )
            {
                if( !v.isConstant() )
                {
                    DiagnosticsManager::GetInstance().emitErrorMessage( v.locationId(),
Changes to bs/builtins/builtins.cpp.
1
2
3
4
5
6
7
8
9

10
11
12
13
14
15
16
#include "builtins/builtins.h"

namespace goose::builtins
{
    void SetupBuiltins( Env& e )
    {
        e.extDropValue() = CreateOverloadSet( e, "DropValue"_sid );
        e.extDestroyValue() = CreateOverloadSet( e, "DestroyValue"_sid );
        e.extLowerTypeForRuntime() = CreateOverloadSet( e, "LowerTypeForRuntime"_sid );

        e.extInitialize() = CreateOverloadSet( e, "Initialize"_sid );

        SetupBuiltinTypes( e );
        SetupBuiltinOperators( e );
        SetupBuiltinStatements( e );
        SetupBuiltinApi( e );
    }









>







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

namespace goose::builtins
{
    void SetupBuiltins( Env& e )
    {
        e.extDropValue() = CreateOverloadSet( e, "DropValue"_sid );
        e.extDestroyValue() = CreateOverloadSet( e, "DestroyValue"_sid );
        e.extLowerTypeForRuntime() = CreateOverloadSet( e, "LowerTypeForRuntime"_sid );
        e.extLowerConstantForRuntime() = CreateOverloadSet( e, "LowerConstantForRuntime"_sid );
        e.extInitialize() = CreateOverloadSet( e, "Initialize"_sid );

        SetupBuiltinTypes( e );
        SetupBuiltinOperators( e );
        SetupBuiltinStatements( e );
        SetupBuiltinApi( e );
    }
Changes to bs/builtins/types/func/bfunc.cpp.
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
        auto decomp = Decompose( funcType->val(),
            Vec(
                Lit( "func"_sid ),
                Lit( "builtin"_sid ),
                SubTerm(),  // domain
                SubTerm(),  // return type
                SubTerm(),  // param types

                SubTerm()   // verif info
            )
        );

        if( decomp )
            return true;

        decomp = Decompose( funcType->val(),
            Vec(
                Lit( "func"_sid ),
                Lit( "builtin_eager"_sid ),
                SubTerm(),  // domain
                SubTerm(),  // return type
                SubTerm(),  // param types

                SubTerm()   // verif info
            )
        );

        return !!decomp;
    }

    bool IsNonEagerBuiltinFunc( const Value& func )
    {
        auto funcType = ValueFromIRExpr( func.type() );
        assert( funcType );

        auto decomp = Decompose( funcType->val(),
            Vec(
                Lit( "func"_sid ),
                Lit( "builtin"_sid ),
                SubTerm(),  // domain
                SubTerm(),  // return type
                SubTerm(),  // param types

                SubTerm()   // verif info
            )
        );

        return !!decomp;
    }

    bool IsEagerBuiltinFunc( const Value& func )
    {
        auto funcType = ValueFromIRExpr( func.type() );
        assert( funcType );

        auto decomp = Decompose( funcType->val(),
            Vec(
                Lit( "func"_sid ),
                Lit( "builtin_eager"_sid ),
                SubTerm(),  // domain
                SubTerm(),  // return type
                SubTerm(),  // param types

                SubTerm()   // verif info
            )
        );

        return !!decomp;
    }

    const BuiltinFuncWrapper& GetBuiltinFuncWrapper( const Value& func )







>
|













>
|


















>
|


















>
|







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
        auto decomp = Decompose( funcType->val(),
            Vec(
                Lit( "func"_sid ),
                Lit( "builtin"_sid ),
                SubTerm(),  // domain
                SubTerm(),  // return type
                SubTerm(),  // param types
                SubTerm(),  // verif info
                SubTerm()   // varArg
            )
        );

        if( decomp )
            return true;

        decomp = Decompose( funcType->val(),
            Vec(
                Lit( "func"_sid ),
                Lit( "builtin_eager"_sid ),
                SubTerm(),  // domain
                SubTerm(),  // return type
                SubTerm(),  // param types
                SubTerm(),  // verif info
                SubTerm()   // varArg
            )
        );

        return !!decomp;
    }

    bool IsNonEagerBuiltinFunc( const Value& func )
    {
        auto funcType = ValueFromIRExpr( func.type() );
        assert( funcType );

        auto decomp = Decompose( funcType->val(),
            Vec(
                Lit( "func"_sid ),
                Lit( "builtin"_sid ),
                SubTerm(),  // domain
                SubTerm(),  // return type
                SubTerm(),  // param types
                SubTerm(),  // verif info
                SubTerm()   // varArg
            )
        );

        return !!decomp;
    }

    bool IsEagerBuiltinFunc( const Value& func )
    {
        auto funcType = ValueFromIRExpr( func.type() );
        assert( funcType );

        auto decomp = Decompose( funcType->val(),
            Vec(
                Lit( "func"_sid ),
                Lit( "builtin_eager"_sid ),
                SubTerm(),  // domain
                SubTerm(),  // return type
                SubTerm(),  // param types
                SubTerm(),  // verif info
                SubTerm()   // varArg
            )
        );

        return !!decomp;
    }

    const BuiltinFuncWrapper& GetBuiltinFuncWrapper( const Value& func )
Changes to bs/builtins/types/func/bfunc.inl.
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
    template< typename R, typename... T >
    const Term& Bridge< R ( T... ) >::Type( const ptr< builtins::FuncVerificationInfos >& fvi )
    {
        static auto type = ValueToIRExpr( Value( TypeType(), VEC( TSID( func ),
            builtins::is_eager_v< R > ? TSID( builtin_eager ) : TSID( builtin ),
            sema::Quote( sema::DomainAny() ), GetValueType< builtins::remove_eager_t< R > >(),
            sema::Quote( BuildBuiltinFuncParamTypeList< T... >() ),
            static_pointer_cast< void >( fvi )
        ) ) );
        return type;
    }

    template< typename R, typename... T >
    template< typename F >
    Value Bridge< R ( T... ) >::ToValue( F&& func, const ptr< builtins::FuncVerificationInfos >& fvi )







|







92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
    template< typename R, typename... T >
    const Term& Bridge< R ( T... ) >::Type( const ptr< builtins::FuncVerificationInfos >& fvi )
    {
        static auto type = ValueToIRExpr( Value( TypeType(), VEC( TSID( func ),
            builtins::is_eager_v< R > ? TSID( builtin_eager ) : TSID( builtin ),
            sema::Quote( sema::DomainAny() ), GetValueType< builtins::remove_eager_t< R > >(),
            sema::Quote( BuildBuiltinFuncParamTypeList< T... >() ),
            static_pointer_cast< void >( fvi ), TERM( 0U )
        ) ) );
        return type;
    }

    template< typename R, typename... T >
    template< typename F >
    Value Bridge< R ( T... ) >::ToValue( F&& func, const ptr< builtins::FuncVerificationInfos >& fvi )
Changes to bs/builtins/types/func/build.cpp.
48
49
50
51
52
53
54
55
56
57

58
59
60
61
62
63
64
                ValueToIRExpr( BuildComputedValue( rtTerm, llr::Placeholder( rtTerm, name ) ) ) );
        }

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

    Func BuildExternalFunc( FuncType funcType, const string& symbol )
    {
        funcType.setDomain( DomainRunTime() );

        return Func( funcType, symbol );
    }

    Func BuildFunc( const Context& c, const Term& funcIdentity, const Term& domain, const Value& returnType, const Value& paramsDecl, const ptr< void >& unparsedBody, Context& out_bodyContext )
    {
        auto funcType = BuildFuncType( c, domain, returnType, paramsDecl );
        return BuildFunc( c, funcType, funcIdentity, paramsDecl, unparsedBody, out_bodyContext );







|


>







48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
                ValueToIRExpr( BuildComputedValue( rtTerm, llr::Placeholder( rtTerm, name ) ) ) );
        }

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

    Func BuildExternalFunc( FuncType funcType, const string& symbol, bool varArg )
    {
        funcType.setDomain( DomainRunTime() );
        funcType.setVarArg( varArg );
        return Func( funcType, symbol );
    }

    Func BuildFunc( const Context& c, const Term& funcIdentity, const Term& domain, const Value& returnType, const Value& paramsDecl, const ptr< void >& unparsedBody, Context& out_bodyContext )
    {
        auto funcType = BuildFuncType( c, domain, returnType, paramsDecl );
        return BuildFunc( c, funcType, funcIdentity, paramsDecl, unparsedBody, out_bodyContext );
Changes to bs/builtins/types/func/build.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#ifndef GOOSE_BUILTINS_FUNC_BUILD_H
#define GOOSE_BUILTINS_FUNC_BUILD_H

namespace goose::builtins
{
    extern FuncType BuildFuncType( const Context& c, const Term& domain, const Value& returnType, const Value& params );

    extern Func BuildExternalFunc( FuncType funcType, const string& symbol );
    extern Func BuildFunc( const Context& c, const Term& funcIdentity, const Term& domain, const Value& returnType, const Value& paramsDecl, const ptr< void >& unparsedBody, Context& out_bodyContext );
    extern Func BuildFunc( const Context& c, const FuncType& funcType, const Term& funcIdentity, const Value& paramsDecl, const ptr< void >& unparsedBody,
        Context& out_bodyContext );

    extern Term BuildCallPatternFromFuncType( const Value& funcType );
}








|







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

namespace goose::builtins
{
    extern FuncType BuildFuncType( const Context& c, const Term& domain, const Value& returnType, const Value& params );

    extern Func BuildExternalFunc( FuncType funcType, const string& symbol, bool varArg = false );
    extern Func BuildFunc( const Context& c, const Term& funcIdentity, const Term& domain, const Value& returnType, const Value& paramsDecl, const ptr< void >& unparsedBody, Context& out_bodyContext );
    extern Func BuildFunc( const Context& c, const FuncType& funcType, const Term& funcIdentity, const Value& paramsDecl, const ptr< void >& unparsedBody,
        Context& out_bodyContext );

    extern Term BuildCallPatternFromFuncType( const Value& funcType );
}

Changes to bs/builtins/types/func/func.cpp.
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
namespace goose::builtins
{
    const Term& FuncPattern::GetPattern()
    {
        static auto pattern = ValueToIRExpr(
            Value( TypeType(), VEC( TSID( func ), HOLE( "llvmType"_sid ),
            HOLE( "_"_sid ), HOLE( "_"_sid ), HOLE( "_"_sid ),
            HOLE( "_"_sid ) ) ) );

        return pattern;
    }

    bool IsExternalFunc( const Value& f )
    {
        if( !f.isConstant() )







|







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
namespace goose::builtins
{
    const Term& FuncPattern::GetPattern()
    {
        static auto pattern = ValueToIRExpr(
            Value( TypeType(), VEC( TSID( func ), HOLE( "llvmType"_sid ),
            HOLE( "_"_sid ), HOLE( "_"_sid ), HOLE( "_"_sid ),
            HOLE( "_"_sid ), HOLE( "_"_sid ) ) ) );

        return pattern;
    }

    bool IsExternalFunc( const Value& f )
    {
        if( !f.isConstant() )
37
38
39
40
41
42
43

44
45
46
47
48
49
50
51
        auto result = Decompose( t.val(),
            Vec(
                Lit( "func"_sid ),
                Val< void* >(),
                SubTerm(),  // domain
                SubTerm(),  // return type
                SubTerm(),  // param types

                SubTerm()   // verif infos
            )
        );

        return !!result;
    }

    Term GetFuncSig( const Value& func )







>
|







37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
        auto result = Decompose( t.val(),
            Vec(
                Lit( "func"_sid ),
                Val< void* >(),
                SubTerm(),  // domain
                SubTerm(),  // return type
                SubTerm(),  // param types
                SubTerm(),  // verif infos
                SubTerm()   // VarArg
            )
        );

        return !!result;
    }

    Term GetFuncSig( const Value& func )
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
        auto typeDecomp = Decompose( funcType.val(),
            Vec(
                Lit( "func"_sid ),
                SubTerm(),  // kind
                SubTerm(),  // domain
                SubTerm(),  // return type
                SubTerm(),  // param types

                SubTerm()   // verif infos
            )
        );
        assert( typeDecomp );
        auto&& [kind, domain, rtype, ptypes, vinf] = *typeDecomp;

        return VEC( *Unquote( domain ), *Unquote( ptypes ), rtype );
    }

    Term GetFuncRType( const Value& func )
    {
        auto funcType = ValueFromIRExpr( func.type() );
        assert( funcType );

        auto typeDecomp = Decompose( funcType->val(),
            Vec(
                Lit( "func"_sid ),
                SubTerm(),  // kind
                SubTerm(),  // domain
                SubTerm(),  // return type
                SubTerm(),  // param types

                SubTerm()   // verif infos
            )
        );
        assert( typeDecomp );
        auto&& [kind, domain, rtype, ptypes, vinf] = *typeDecomp;

        return rtype;
    }

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







>
|



|
















>
|



|







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
        auto typeDecomp = Decompose( funcType.val(),
            Vec(
                Lit( "func"_sid ),
                SubTerm(),  // kind
                SubTerm(),  // domain
                SubTerm(),  // return type
                SubTerm(),  // param types
                SubTerm(),  // verif infos
                SubTerm()   // VarArg
            )
        );
        assert( typeDecomp );
        auto&& [kind, domain, rtype, ptypes, vinf, varArg] = *typeDecomp;

        return VEC( *Unquote( domain ), *Unquote( ptypes ), rtype );
    }

    Term GetFuncRType( const Value& func )
    {
        auto funcType = ValueFromIRExpr( func.type() );
        assert( funcType );

        auto typeDecomp = Decompose( funcType->val(),
            Vec(
                Lit( "func"_sid ),
                SubTerm(),  // kind
                SubTerm(),  // domain
                SubTerm(),  // return type
                SubTerm(),  // param types
                SubTerm(),  // verif infos
                SubTerm()   // VarArg
            )
        );
        assert( typeDecomp );
        auto&& [kind, domain, rtype, ptypes, vinf, varArg] = *typeDecomp;

        return rtype;
    }

    const llr::Func* GetFuncLLR( const Value& f )
    {
        if( !f.isConstant() )
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
        return TypeType();
    }

    Value Bridge< FuncType >::ToValue( const FuncType& ft )
    {
        return Value( Type(), VEC( TSID( func ), TERM( ft.llvmType() ),
            Quote( ft.domain() ), ft.returnType(), Quote( ft.params() ),
            static_pointer_cast< void >( ft.verifInfos() ) ) );

    }

    optional< FuncType > Bridge< FuncType >::FromValue( const Value& v )
    {
        auto result = Decompose( v.val(),
            Vec(
                Lit( "func"_sid ),
                Val< void* >(),
                SubTerm(),  // domain
                SubTerm(),  // return type
                SubTerm(),  // param types
                Val< ptr< void > >()   // verif infos

            )
        );

        if( !result )
            return nullopt;

        auto&& [llvmtype, domain, rtype, params, vinf] = *result;
        return FuncType( *Unquote( domain ), rtype, *Unquote( params ),
            static_pointer_cast< FuncVerificationInfos >( vinf ),
            static_cast< llvm::FunctionType* >( llvmtype ) );
    }

    Term Bridge< Func >::Type( const builtins::Func& func )
    {
        return ValueToIRExpr( ::ToValue( func.type() ) );
    }








|
>











|
>






|


|







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
        return TypeType();
    }

    Value Bridge< FuncType >::ToValue( const FuncType& ft )
    {
        return Value( Type(), VEC( TSID( func ), TERM( ft.llvmType() ),
            Quote( ft.domain() ), ft.returnType(), Quote( ft.params() ),
            static_pointer_cast< void >( ft.verifInfos() ),
            TERM( ft.varArg() ? 1U : 0U ) ) );
    }

    optional< FuncType > Bridge< FuncType >::FromValue( const Value& v )
    {
        auto result = Decompose( v.val(),
            Vec(
                Lit( "func"_sid ),
                Val< void* >(),
                SubTerm(),  // domain
                SubTerm(),  // return type
                SubTerm(),  // param types
                Val< ptr< void > >(),  // verif infos
                Val< uint32_t >()  // varArg
            )
        );

        if( !result )
            return nullopt;

        auto&& [llvmtype, domain, rtype, params, vinf, varArg] = *result;
        return FuncType( *Unquote( domain ), rtype, *Unquote( params ),
            static_pointer_cast< FuncVerificationInfos >( vinf ),
            static_cast< llvm::FunctionType* >( llvmtype ), varArg );
    }

    Term Bridge< Func >::Type( const builtins::Func& func )
    {
        return ValueToIRExpr( ::ToValue( func.type() ) );
    }

Changes to bs/builtins/types/func/func.h.
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
            Term m_postConditions = VEC();
    };

    class FuncType
    {
        public:
            template< typename D, typename R, typename P, typename VI >
            FuncType( D&& domain, R&& returnType, P&& params, VI&& verifInfos, llvm::FunctionType* pLLVMType = nullptr ) :
                m_domain( forward< D >( domain ) ),
                m_returnType( forward< R >( returnType ) ),
                m_params( forward< P >( params ) ),
                m_verifInfos( forward< VI >( verifInfos ) ),
                m_pllvmType( pLLVMType )

            {}

            const auto& domain() const { return m_domain; }
            const auto& returnType() const { return m_returnType; }
            const auto& params() const { return m_params; }
            const auto& verifInfos() const { return m_verifInfos; }
            auto* llvmType() const { return m_pllvmType; }


            template< typename D >
            void setDomain( D&& domain )
            {
                m_domain = forward< D >( domain );
            }






        private:
            Term m_domain;
            Term m_returnType;
            Term m_params;
            ptr< FuncVerificationInfos > m_verifInfos;
            llvm::FunctionType* m_pllvmType = nullptr;

    };

    extern bool IsExternalFunc( const Value& f );
    extern bool IsFuncType( const Value& t );

    class Func
    {







|




|
>







>






>
>
>
>
>







>







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
            Term m_postConditions = VEC();
    };

    class FuncType
    {
        public:
            template< typename D, typename R, typename P, typename VI >
            FuncType( D&& domain, R&& returnType, P&& params, VI&& verifInfos, llvm::FunctionType* pLLVMType = nullptr, bool varArg = false ) :
                m_domain( forward< D >( domain ) ),
                m_returnType( forward< R >( returnType ) ),
                m_params( forward< P >( params ) ),
                m_verifInfos( forward< VI >( verifInfos ) ),
                m_pllvmType( pLLVMType ),
                m_varArg( varArg )
            {}

            const auto& domain() const { return m_domain; }
            const auto& returnType() const { return m_returnType; }
            const auto& params() const { return m_params; }
            const auto& verifInfos() const { return m_verifInfos; }
            auto* llvmType() const { return m_pllvmType; }
            bool varArg() const { return m_varArg; }

            template< typename D >
            void setDomain( D&& domain )
            {
                m_domain = forward< D >( domain );
            }

            void setVarArg( bool varArg )
            {
                m_varArg = varArg;
            }

        private:
            Term m_domain;
            Term m_returnType;
            Term m_params;
            ptr< FuncVerificationInfos > m_verifInfos;
            llvm::FunctionType* m_pllvmType = nullptr;
            bool m_varArg = false;
    };

    extern bool IsExternalFunc( const Value& f );
    extern bool IsFuncType( const Value& t );

    class Func
    {
Changes to bs/builtins/types/func/invoke.cpp.
111
112
113
114
115
116
117
118
119
120
121
122
123
    void SetupFunctionInvocationRule( Env& e )
    {
        e.invocationRuleSet()->addRule(
            ValueToIRExpr( ValuePattern( ANYTERM( _ ),

                ValueToIRExpr( Value( TypeType(), VEC( TSID( func ),
                ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ),
                ANYTERM( _ ) ) ) ),

                ANYTERM( _ ) ) ),
            GetFuncInvocationRule() );
    }
}







|





111
112
113
114
115
116
117
118
119
120
121
122
123
    void SetupFunctionInvocationRule( Env& e )
    {
        e.invocationRuleSet()->addRule(
            ValueToIRExpr( ValuePattern( ANYTERM( _ ),

                ValueToIRExpr( Value( TypeType(), VEC( TSID( func ),
                ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ),
                ANYTERM( _ ), ANYTERM( _ ) ) ) ),

                ANYTERM( _ ) ) ),
            GetFuncInvocationRule() );
    }
}
Changes to bs/builtins/types/func/lower.cpp.
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72

            return true;
        } );

        if( !success )
            return nullopt;

        auto* pLLVMType = llvm::FunctionType::get( GetLLVMType( *rt ), paramTypes, false );
        if( !pLLVMType )
            return nullopt;

        return FuncType( ft.domain(), ValueToIRExpr( *rt ), pv, nullptr, pLLVMType );
    }

    void SetupFunctionLowering( Env& e )







|







58
59
60
61
62
63
64
65
66
67
68
69
70
71
72

            return true;
        } );

        if( !success )
            return nullopt;

        auto* pLLVMType = llvm::FunctionType::get( GetLLVMType( *rt ), paramTypes, ft.varArg() );
        if( !pLLVMType )
            return nullopt;

        return FuncType( ft.domain(), ValueToIRExpr( *rt ), pv, nullptr, pLLVMType );
    }

    void SetupFunctionLowering( Env& e )
Changes to bs/builtins/types/func/unify.cpp.
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
        {
            auto lhsVal = *ValuePatternFromIRExpr( lhs );
            lhsVal.sort() = HOLE( "_"_sid );
            co_yield Unify( ValueToIRExpr( lhsVal ), rhs, uc );
        } );

        auto funcTypePat = ValueToIRExpr( Value( TypeType(), VEC( TSID( func ),
            ANYTERM( _ ), ANYTERM( _ ), ANYTERM( RT ), ANYTERM( P ), ANYTERM( _ ) ) ) );

        auto tFuncTypePat = ValueToIRExpr( Value( TypeType(), VEC( TSID( texpr ), TSID( tfunc ),
            ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ) ) ) );

        // func type param / func arg
        e.unificationRuleSet()->addSymRule( URINFOS,








|







26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
        {
            auto lhsVal = *ValuePatternFromIRExpr( lhs );
            lhsVal.sort() = HOLE( "_"_sid );
            co_yield Unify( ValueToIRExpr( lhsVal ), rhs, uc );
        } );

        auto funcTypePat = ValueToIRExpr( Value( TypeType(), VEC( TSID( func ),
            ANYTERM( _ ), ANYTERM( _ ), ANYTERM( RT ), ANYTERM( P ), ANYTERM( _ ), ANYTERM( VA ) ) ) );

        auto tFuncTypePat = ValueToIRExpr( Value( TypeType(), VEC( TSID( texpr ), TSID( tfunc ),
            ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ) ) ) );

        // func type param / func arg
        e.unificationRuleSet()->addSymRule( URINFOS,

Changes to bs/builtins/types/intrinsic/intrinsic.cpp.
10
11
12
13
14
15
16

17
18
19
20
21
22
23
24
        auto decomp = Decompose( funcType->val(),
            Vec(
                Lit( "func"_sid ),
                Lit( "intrinsic"_sid ),
                SubTerm(),  // domain
                SubTerm(),  // return type
                SubTerm(),  // param types

                SubTerm()   // verif info
            )
        );

        return !!decomp;
    }

    const BuiltinIntrinsicFuncWrapper& GetBuiltinIntrinsicFuncWrapper( const Value& func )







>
|







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
        auto decomp = Decompose( funcType->val(),
            Vec(
                Lit( "func"_sid ),
                Lit( "intrinsic"_sid ),
                SubTerm(),  // domain
                SubTerm(),  // return type
                SubTerm(),  // param types
                SubTerm(),  // verif info
                SubTerm()   // varArg
            )
        );

        return !!decomp;
    }

    const BuiltinIntrinsicFuncWrapper& GetBuiltinIntrinsicFuncWrapper( const Value& func )
Changes to bs/builtins/types/intrinsic/intrinsic.inl.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#ifndef GOOSE_BUILTINS_TYPES_INTRINSIC_INL
#define GOOSE_BUILTINS_TYPES_INTRINSIC_INL

namespace goose::ir
{
    template< bool useVerifDomain, typename R, typename... T >
    const Term& IntrinsicBridge< useVerifDomain, R, T... >::Type( const ptr< builtins::FuncVerificationInfos >& fvi )
    {
        static auto dom = useVerifDomain ? sema::DomainVerification() : sema::DomainAny();
        static auto type = ValueToIRExpr( Value( TypeType(), VEC( TSID( func ), TSID( intrinsic ),
            sema::Quote( dom ), GetValueType< Value >(),
            sema::Quote( BuildBuiltinFuncParamTypeList< T... >() ),
            static_pointer_cast< void >( fvi )
        ) ) );
        return type;
    }

    template< bool useVerifDomain, typename R, typename... T >
    template< typename F >
    Value IntrinsicBridge< useVerifDomain, R, T... >::ToValue( F&& func, const ptr< builtins::FuncVerificationInfos >& fvi )












|







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

namespace goose::ir
{
    template< bool useVerifDomain, typename R, typename... T >
    const Term& IntrinsicBridge< useVerifDomain, R, T... >::Type( const ptr< builtins::FuncVerificationInfos >& fvi )
    {
        static auto dom = useVerifDomain ? sema::DomainVerification() : sema::DomainAny();
        static auto type = ValueToIRExpr( Value( TypeType(), VEC( TSID( func ), TSID( intrinsic ),
            sema::Quote( dom ), GetValueType< Value >(),
            sema::Quote( BuildBuiltinFuncParamTypeList< T... >() ),
            static_pointer_cast< void >( fvi ), TERM( 0U )
        ) ) );
        return type;
    }

    template< bool useVerifDomain, typename R, typename... T >
    template< typename F >
    Value IntrinsicBridge< useVerifDomain, R, T... >::ToValue( F&& func, const ptr< builtins::FuncVerificationInfos >& fvi )
Changes to bs/builtins/types/overloadset/unify.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include "builtins/builtins.h"

using namespace goose;
using namespace goose::ir;

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

        auto tFuncTypePat = ValueToIRExpr( Value( TypeType(), VEC( TSID( texpr ), TSID( tfunc ),
            ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ) ) ) );

        // func type param / overloadset arg
        e.unificationRuleSet()->addSymRule( URINFOS,











|







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

using namespace goose;
using namespace goose::ir;

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

        auto tFuncTypePat = ValueToIRExpr( Value( TypeType(), VEC( TSID( texpr ), TSID( tfunc ),
            ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ) ) ) );

        // func type param / overloadset arg
        e.unificationRuleSet()->addSymRule( URINFOS,

Changes to bs/builtins/types/runtime/record.cpp.
43
44
45
46
47
48
49



50

51
52
53
54
55
56
57

    llvm::Type* GetLLVMType( const RecordType& rt )
    {
        vector< llvm::Type* > elements;
        elements.reserve( rt.m_memberTypes->terms().size() );

        for( auto&& mt : rt.m_memberTypes->terms() )



            elements.emplace_back( GetLLVMType( *ValueFromIRExpr( mt ) ) );


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

namespace goose::ir
{







>
>
>
|
>







43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61

    llvm::Type* GetLLVMType( const RecordType& rt )
    {
        vector< llvm::Type* > elements;
        elements.reserve( rt.m_memberTypes->terms().size() );

        for( auto&& mt : rt.m_memberTypes->terms() )
        {
            auto llvmType = GetLLVMType( *ValueFromIRExpr( mt ) );
            assert( llvmType );
            elements.emplace_back( llvmType );
        }

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

namespace goose::ir
{
Changes to bs/builtins/types/runtime/record.h.
17
18
19
20
21
22
23







24
25
26
27
28
29
30
            m_memberTypes( forward< M >( memberTypes ) ),
            m_packed( packed )
        {}

        pvec                m_memberTypes;
        bool                m_packed = false;
    };








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

namespace goose::ir
{
    template<>







>
>
>
>
>
>
>







17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
            m_memberTypes( forward< M >( memberTypes ) ),
            m_packed( packed )
        {}

        pvec                m_memberTypes;
        bool                m_packed = false;
    };

    template< typename T, typename V >
    Value CreateRecord( T&& types, V&& vals, bool packed )
    {
        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<>
Changes to bs/builtins/types/runtime/runtime.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 "codegen/codegen.h"

using namespace goose;
using namespace goose::builtins;
using namespace goose::codegen;

namespace goose::builtins
{
    bool IsRuntimeType( const Value& t )
    {
        return !!GetLLVMType( t );
    }

    llvm::Type* GetLLVMType( const Value& t )
    {
        if( !t.isType() )
            return nullptr;












|







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

using namespace goose;
using namespace goose::builtins;
using namespace goose::codegen;

namespace goose::builtins
{
    bool IsRuntimeType( const Value& t )
    {
        return t.type() == GetValueType< bool >() || !!GetLLVMType( t );
    }

    llvm::Type* GetLLVMType( const Value& t )
    {
        if( !t.isType() )
            return nullptr;

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

using namespace goose;
using namespace goose::ir;

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

        auto tFuncTypePat = ValueToIRExpr( Value( TypeType(), VEC( TSID( texpr ), TSID( tfunc ),
            ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ) ) ) );

        // func type param / tfunc arg
        e.unificationRuleSet()->addSymRule( URINFOS,











|







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

using namespace goose;
using namespace goose::ir;

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

        auto tFuncTypePat = ValueToIRExpr( Value( TypeType(), VEC( TSID( texpr ), TSID( tfunc ),
            ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ) ) ) );

        // func type param / tfunc arg
        e.unificationRuleSet()->addSymRule( URINFOS,

Changes to bs/builtins/types/tuple/lower.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





















        {
            RecordType rt;
            bool success = true;

            ForEachInTupleType( tupType, [&]( auto&& t )
            {
                auto loweredType = LowerTypeForRuntime( c, t );
                if( !loweredType )
                {
                    success = false;
                    return false;
                }

                rt.m_memberTypes->append( ValueToIRExpr( *loweredType ) );
                return true;
            } );

            if( !success )
                return PoisonValue();

            return ToValue( rt );
        } );
    }






}




























|














|
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
        {
            RecordType rt;
            bool success = true;

            ForEachInTupleType( tupType, [&]( auto&& t )
            {
                auto loweredType = LowerTypeForRuntime( c, t );
                if( !loweredType || loweredType->isPoison() )
                {
                    success = false;
                    return false;
                }

                rt.m_memberTypes->append( ValueToIRExpr( *loweredType ) );
                return true;
            } );

            if( !success )
                return PoisonValue();

            return ToValue( rt );
        } );

        RegisterBuiltinFunc< Intrinsic< Value ( CustomPattern< Value, TuplePattern > ) > >( e, e.extLowerConstantForRuntime(),
            []( const Context& c, const Value& tup )
        {
            auto types = make_shared< Vector >();
            auto vals = make_shared< Vector >();
            bool success = true;

            ForEachInTuple( tup, [&]( auto&& t )
            {
                auto member = LowerConstantForRuntime( c, t );
                if( !member || member->isPoison() )
                {
                    success = false;
                    return false;
                }

                types->append( member->type() );
                vals->append( ValueToIRExpr( *member ) );
                return true;
            } );

            if( !success )
                return PoisonValue();

            return CreateRecord( move( types ), move( vals ), false );
        } );
    }
}
Changes to bs/codegen/address.cpp.
11
12
13
14
15
16
17


18
19
20
21
22
23
24
25
26
    if( !baseAddrVal )
        return nullptr;

    if( addr.path().empty() )
        return baseAddrVal;

    llvm::SmallVector< llvm::Value*, 4 > idxs;


    for( auto&& index : addr.path() )
        idxs.push_back( llvm::ConstantInt::get( llvm::Type::getInt8Ty( GetLLVMContext() ), index ) );

    return m_llvmBuilder.CreateGEP( baseAddrVal, idxs );
}

llvm::Value* Module::buildAddress( Infos& inf, const BaseAddress& baseAddr )
{
    return visit( [&]( auto&& ba )







>
>

|







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
    if( !baseAddrVal )
        return nullptr;

    if( addr.path().empty() )
        return baseAddrVal;

    llvm::SmallVector< llvm::Value*, 4 > idxs;
    idxs.push_back( llvm::ConstantInt::get( llvm::Type::getInt32Ty( GetLLVMContext() ), 0 ) );

    for( auto&& index : addr.path() )
        idxs.push_back( llvm::ConstantInt::get( llvm::Type::getInt32Ty( GetLLVMContext() ), index ) );

    return m_llvmBuilder.CreateGEP( baseAddrVal, idxs );
}

llvm::Value* Module::buildAddress( Infos& inf, const BaseAddress& baseAddr )
{
    return visit( [&]( auto&& ba )
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
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include "codegen.h"
#include "builtins/builtins.h"

using namespace goose;
using namespace goose::codegen;
using namespace goose::builtins;

llvm::Value* Module::buildValue( Infos& inf, const Value& val )
{
    if( val.isPoison() )
        return nullptr;

    if( val.isConstant() )
    {
        if( auto b = FromValue< bool >( val ) )
        {
            return *b ?
                llvm::ConstantInt::getTrue( GetLLVMContext() ) :
                llvm::ConstantInt::getFalse( GetLLVMContext() );
        }
        else if( auto intVal = FromValue< APSInt >( val ) )
        {
             return llvm::ConstantInt::get( GetLLVMType( *ValueFromIRExpr( val.type() ) ),
                *FromValue< APSInt >( val ) );
        }
        else if( auto ptType = FromValue< PointerType >( *ValueFromIRExpr( val.type() ) ) )
        {
            // The only kind of pointer constant we can have at the moment are nullptr.
            return llvm::ConstantPointerNull::get( static_cast< llvm::PointerType* >
                ( GetLLVMType( *ValueFromIRExpr( val.type() ) ) ) );
        }

        DiagnosticsManager::GetInstance().emitErrorMessage(
            val.locationId(), "constants with compile time types are not supported.", 0 );
        return nullptr;
    }

    return buildInstruction( inf, *val.llr() );
}

llvm::Value* Module::buildInstruction( Infos& inf, const llr::Instruction& instr )
{
    return visit( [&]( auto&& e )
    {
        return buildInstruction( inf, e );
    }, instr.content() );
}







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







1
2
3
4
5
6
7

































8
9
10
11
12
13
14
#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() );
}
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
    auto* pAlloca = buildAlloca( inf, GetLLVMType( *type ) );
    createTemporary( inf, av.index(), pAlloca );
    return pAlloca;
}

llvm::Value* Module::buildInstruction( Infos& inf, const llr::Load& load )
{







    auto* ptrVal = buildAddress( inf, load.addr() );
    return m_llvmBuilder.CreateLoad( ptrVal );
}

llvm::Value* Module::buildInstruction( Infos& inf, const llr::Store& store )
{
    auto* pValue = buildValue( inf, store.val() );
    if( !pValue )
        return nullptr;

    auto* ptrVal = buildAddress( inf, store.addr() );
















    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 )







>
>
>
>
>
>
>

|









>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







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
    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 = 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 = buildAddress( inf, store.addr() );

    if( llvm::isa< llvm::ConstantAggregate >( pValue ) )
    {
        stringstream name;
        name << ".constaggr" << hex << m_nextAggregateID++;

        auto pGlob = new llvm::GlobalVariable( m_llvmModule,
            pValue->getType(), true, llvm::GlobalValue::LinkageTypes::PrivateLinkage,
            static_cast< llvm::Constant* >( pValue ), name.str() );

        auto size = m_dataLayout.getTypeAllocSize( pValue->getType() );

        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 )
Changes to bs/codegen/meson.build.
1
2
3
4
5
6
7

8
9
10
11
12
13
14
goose_codegen = library( 'goose-codegen',
    'codegen.cpp',
    'module.cpp',
    'func.cpp',
    'mangle.cpp',
    'basicblock.cpp',
    'instructions.cpp',

    'address.cpp',
    'logicops.cpp',
    'arithops.cpp',
    'compareops.cpp',

    include_directories: bsinc,
    dependencies: fmt_dep







>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
goose_codegen = library( 'goose-codegen',
    'codegen.cpp',
    'module.cpp',
    'func.cpp',
    'mangle.cpp',
    'basicblock.cpp',
    'instructions.cpp',
    'value.cpp',
    'address.cpp',
    'logicops.cpp',
    'arithops.cpp',
    'compareops.cpp',

    include_directories: bsinc,
    dependencies: fmt_dep
Changes to bs/codegen/module.cpp.
8
9
10
11
12
13
14

15
16
17
18
19
20
21
#include "llvm/IR/LegacyPassManager.h"

using namespace goose;
using namespace goose::codegen;

Module::Module( const string& name ) :
    m_llvmModule( name, GetLLVMContext() ),

    m_llvmBuilder( GetLLVMContext() )
{}

void Module::dumpAsLlvmIr( const string& filename ) const
{
    error_code err;
    llvm::raw_fd_ostream out( filename, err );







>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include "llvm/IR/LegacyPassManager.h"

using namespace goose;
using namespace goose::codegen;

Module::Module( const string& name ) :
    m_llvmModule( name, GetLLVMContext() ),
    m_dataLayout( &m_llvmModule ),
    m_llvmBuilder( GetLLVMContext() )
{}

void Module::dumpAsLlvmIr( const string& filename ) const
{
    error_code err;
    llvm::raw_fd_ostream out( filename, err );
Changes to bs/codegen/module.h.
46
47
48
49
50
51
52

53
54
55
56
57
58
59
                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::Value* buildInstruction( Infos& inf, const llr::Instruction& instr );
            llvm::Value* buildInstruction( Infos& inf, const llr::Call& call );
            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 );







>







46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
                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::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 );
107
108
109
110
111
112
113

114
115
116
117

118
119
120
121
            llvm::Value* buildAddress( Infos& inf, const TemporaryAddress& ta );
            llvm::Value* buildAddress( Infos& inf, const VarAddress& va );

            llvm::Value* buildAlloca( Infos& inf, llvm::Type* type );
            llvm::Value* createTemporary( Infos& inf, uint32_t index, llvm::Value* pValue ) const;

            llvm::Module m_llvmModule;

            llvm::IRBuilder<> m_llvmBuilder;
            llvm::TargetMachine* m_targetMachine = nullptr;

            unordered_map< string, llvm::GlobalVariable* > m_strings;

    };
}

#endif







>




>




108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
            llvm::Value* buildAddress( Infos& inf, const TemporaryAddress& ta );
            llvm::Value* buildAddress( Infos& inf, const VarAddress& va );

            llvm::Value* buildAlloca( Infos& inf, llvm::Type* type );
            llvm::Value* createTemporary( Infos& inf, uint32_t index, llvm::Value* pValue ) const;

            llvm::Module m_llvmModule;
            llvm::DataLayout m_dataLayout;
            llvm::IRBuilder<> m_llvmBuilder;
            llvm::TargetMachine* m_targetMachine = nullptr;

            unordered_map< string, llvm::GlobalVariable* > m_strings;
            uint32_t m_nextAggregateID = 0;
    };
}

#endif
Added bs/codegen/value.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
#include "codegen.h"
#include "builtins/builtins.h"

using namespace goose;
using namespace goose::codegen;
using namespace goose::builtins;

llvm::Value* Module::buildValue( Infos& inf, const Value& val )
{
    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 );
    if( !val )
        return nullptr;

    if( auto b = FromValue< bool >( *val ) )
    {
        return *b ?
            llvm::ConstantInt::getTrue( GetLLVMContext() ) :
            llvm::ConstantInt::getFalse( GetLLVMContext() );
    }
    else if( auto intVal = FromValue< APSInt >( *val ) )
    {
            return llvm::ConstantInt::get( GetLLVMType( *ValueFromIRExpr( val->type() ) ),
            *FromValue< APSInt >( *val ) );
    }
    else if( auto ptType = FromValue< PointerType >( *ValueFromIRExpr( val->type() ) ) )
    {
        // The only kind of pointer constant we can have at the moment are nullptr.
        return llvm::ConstantPointerNull::get( static_cast< llvm::PointerType* >
            ( GetLLVMType( *ValueFromIRExpr( val->type() ) ) ) );
    }
    else if( auto recType = FromValue< RecordType >( *ValueFromIRExpr( val->type() ) ) )
    {
        llvm::SmallVector< llvm::Constant*, 8 > members;
        assert( holds_alternative< pvec >( val->val() ) );

        bool success = true;

        ForEachInVectorTerm( val->val(), [&]( auto&& t )
        {
            auto* pMemberVal = buildConstant( inf, *ValueFromIRExpr( t ) );
            if( !pMemberVal )
            {
                success = false;
                return false;
            }

            members.push_back( pMemberVal );
            return true;
        } );

        if( !success )
            return nullptr;

        return llvm::ConstantStruct::get( static_cast< llvm::StructType* >
            ( GetLLVMType( *ValueFromIRExpr( val->type() ) ) ), members );
    }

    DiagnosticsManager::GetInstance().emitErrorMessage(
        v.locationId(), "constants with compile time types are not supported.", 0 );
    return nullptr;
}
Changes to bs/sema/env.h.
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

            auto& extDestroyValue() { return m_extDestroyValue; }
            const auto& extDestroyValue() const { return m_extDestroyValue; }

            auto& extLowerTypeForRuntime() { return m_extLowerTypeForRuntime; }
            const auto& extLowerTypeForRuntime() const { return m_extLowerTypeForRuntime; }




            auto& extInitialize() { return m_extInitializeLocalVar; }
            const auto& extInitialize() const { return m_extInitializeLocalVar; }

            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< UnificationRuleSet >           m_unificationRuleSet;

            ptr< OverloadSet >                  m_extDropValue;
            ptr< OverloadSet >                  m_extDestroyValue;
            ptr< OverloadSet >                  m_extLowerTypeForRuntime;

            ptr< OverloadSet >                  m_extInitializeLocalVar;

            uint64_t                            m_valueStoreVersion = 0;

            ptr< CTMemoryManager >              m_memManager;

            // LLR funcs form a cyclic graph, since functions can







>
>
>



















>







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

            auto& extDestroyValue() { return m_extDestroyValue; }
            const auto& extDestroyValue() const { return m_extDestroyValue; }

            auto& extLowerTypeForRuntime() { return m_extLowerTypeForRuntime; }
            const auto& extLowerTypeForRuntime() const { return m_extLowerTypeForRuntime; }

            auto& extLowerConstantForRuntime() { return m_extLowerConstantForRuntime; }
            const auto& extLowerConstantForRuntime() const { return m_extLowerConstantForRuntime; }

            auto& extInitialize() { return m_extInitializeLocalVar; }
            const auto& extInitialize() const { return m_extInitializeLocalVar; }

            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< UnificationRuleSet >           m_unificationRuleSet;

            ptr< OverloadSet >                  m_extDropValue;
            ptr< OverloadSet >                  m_extDestroyValue;
            ptr< OverloadSet >                  m_extLowerTypeForRuntime;
            ptr< OverloadSet >                  m_extLowerConstantForRuntime;
            ptr< OverloadSet >                  m_extInitializeLocalVar;

            uint64_t                            m_valueStoreVersion = 0;

            ptr< CTMemoryManager >              m_memManager;

            // LLR funcs form a cyclic graph, since functions can
Changes to bs/sema/lower.cpp.
13
14
15
16
17
18
19













20
21
22
            return type;

        DiagnosticsContext dc( type.locationId(), "When invoking LowerTypeForRuntime." );
        auto result = InvokeOverloadSet( c, c.env()->extLowerTypeForRuntime(), AppendToTuple( EmptyTuple(), type ) );
        if( result.isPoison() || !IsRuntimeType( result ) )
            return nullopt;














        return result;
    }
}







>
>
>
>
>
>
>
>
>
>
>
>
>



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
            return type;

        DiagnosticsContext dc( type.locationId(), "When invoking LowerTypeForRuntime." );
        auto result = InvokeOverloadSet( c, c.env()->extLowerTypeForRuntime(), AppendToTuple( EmptyTuple(), type ) );
        if( result.isPoison() || !IsRuntimeType( result ) )
            return nullopt;

        return result;
    }

    optional< Value > LowerConstantForRuntime( const Context& c, const Value& val )
    {
        if( val.type() == GetValueType< bool >() || IsRuntimeType( *ValueFromIRExpr( val.type() ) ) )
            return val;

        DiagnosticsContext dc( val.locationId(), "When invoking LowerConstantForRuntime." );
        auto result = InvokeOverloadSet( c, c.env()->extLowerConstantForRuntime(), AppendToTuple( EmptyTuple(), val ) );
        if( result.isPoison() || !IsRuntimeType( *ValueFromIRExpr( result.type() ) ) )
            return nullopt;

        return result;
    }
}
Changes to bs/sema/sema.h.
10
11
12
13
14
15
16

17
18
19
20
21
22
23
{
    using namespace util;
    using namespace ir;
    using namespace diagnostics;

    class Context;
    extern optional< Value > LowerTypeForRuntime( const Context& c, const Value& type );

}

#include "hole.h"
#include "domain.h"
#include "context.h"
#include "ctmm.h"
#include "env.h"







>







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{
    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 );
}

#include "hole.h"
#include "domain.h"
#include "context.h"
#include "ctmm.h"
#include "env.h"
Changes to tests/noprelude/codegen/bitwiseops.ll.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
  %8 = alloca i16
  store i8 %0, i8* %5
  store i8 %1, i8* %6
  store i16 %2, i16* %7
  store i16 %3, i16* %8
  %9 = load i8, i8* %5
  %10 = load i8, i8* %6
  %11 = call i8 @"_3R_4Rs2:g0s6:lomarf_3R_2_5Vr_5Vo_3ti0_4s7:integerPp_2i8i0hs1:__5Vr_5Vo_3ti0_4$2Pp_2i8i0h$3_5Vo_3ti0_4$2Pp_2i8i0_5Vo_3ti0_6up_2qR_5Vo_3ti0_4$2Pp_2i8i0_2q_2_5Vr_5Vo_3ti0_4$2Pp_2i8i0h$3_5Vr_5Vo_3ti0_4$2Pp_2i8i0h$3P"(i8 %9, i8 %10)
  %12 = load i16, i16* %8
  %13 = call i16 @"_3R_4Rs2:g0s6:lomarf_3R_2_5Vr_5Vo_3ti0_4s7:integerPp_2i10i1hs1:__5Vr_5Vo_3ti0_4$2Pp_2i10i1h$3_5Vo_3ti0_4$2Pp_2i10i1_5Vo_3ti0_6up_2qR_5Vo_3ti0_4$2Pp_2i10i1_2q_2_5Vr_5Vo_3ti0_4$2Pp_2i10i1h$3_5Vr_5Vo_3ti0_4$2Pp_2i10i1h$3P"(i16 219, i16 %12)
  %14 = load i16, i16* %8
  %15 = call i16 @"_3R_4Rs2:g0s6:lomarf_3R_2_5Vr_5Vo_3ti0_4s7:integerPp_2i10i1hs1:__5Vr_5Vo_3ti0_4$2Pp_2i10i1h$3_5Vo_3ti0_4$2Pp_2i10i1_5Vo_3ti0_6up_2qR_5Vo_3ti0_4$2Pp_2i10i1_2q_2_5Vr_5Vo_3ti0_4$2Pp_2i10i1h$3_5Vr_5Vo_3ti0_4$2Pp_2i10i1h$3P"(i16 %14, i16 69)
  %16 = load i8, i8* %5
  %17 = load i8, i8* %6
  %18 = xor i8 %16, %17
  %19 = load i16, i16* %7
  %20 = load i16, i16* %8
  %21 = xor i16 %19, %20
  %22 = load i16, i16* %7







|

|

|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
  %8 = alloca i16
  store i8 %0, i8* %5
  store i8 %1, i8* %6
  store i16 %2, i16* %7
  store i16 %3, i16* %8
  %9 = load i8, i8* %5
  %10 = load i8, i8* %6
  %11 = call i8 @"_3R_4Rs2:g0s6:lomarf_3R_2_5Vr_5Vo_3ti0_4s7:integerPp_2i8i0hs1:__5Vr_5Vo_3ti0_4$2Pp_2i8i0h$3_5Vo_3ti0_4$2Pp_2i8i0_5Vo_3ti0_7up_2qR_5Vo_3ti0_4$2Pp_2i8i0_2q_2_5Vr_5Vo_3ti0_4$2Pp_2i8i0h$3_5Vr_5Vo_3ti0_4$2Pp_2i8i0h$3Pi0"(i8 %9, i8 %10)
  %12 = load i16, i16* %8
  %13 = call i16 @"_3R_4Rs2:g0s6:lomarf_3R_2_5Vr_5Vo_3ti0_4s7:integerPp_2i10i1hs1:__5Vr_5Vo_3ti0_4$2Pp_2i10i1h$3_5Vo_3ti0_4$2Pp_2i10i1_5Vo_3ti0_7up_2qR_5Vo_3ti0_4$2Pp_2i10i1_2q_2_5Vr_5Vo_3ti0_4$2Pp_2i10i1h$3_5Vr_5Vo_3ti0_4$2Pp_2i10i1h$3Pi0"(i16 219, i16 %12)
  %14 = load i16, i16* %8
  %15 = call i16 @"_3R_4Rs2:g0s6:lomarf_3R_2_5Vr_5Vo_3ti0_4s7:integerPp_2i10i1hs1:__5Vr_5Vo_3ti0_4$2Pp_2i10i1h$3_5Vo_3ti0_4$2Pp_2i10i1_5Vo_3ti0_7up_2qR_5Vo_3ti0_4$2Pp_2i10i1_2q_2_5Vr_5Vo_3ti0_4$2Pp_2i10i1h$3_5Vr_5Vo_3ti0_4$2Pp_2i10i1h$3Pi0"(i16 %14, i16 69)
  %16 = load i8, i8* %5
  %17 = load i8, i8* %6
  %18 = xor i8 %16, %17
  %19 = load i16, i16* %7
  %20 = load i16, i16* %8
  %21 = xor i16 %19, %20
  %22 = load i16, i16* %7
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
  %38 = load i16, i16* %7
  %39 = shl i16 %38, 4
  %40 = load i16, i16* %7
  %41 = ashr i16 %40, 4
  ret void
}

define private i8 @"_3R_4Rs2:g0s6:lomarf_3R_2_5Vr_5Vo_3ti0_4s7:integerPp_2i8i0hs1:__5Vr_5Vo_3ti0_4$2Pp_2i8i0h$3_5Vo_3ti0_4$2Pp_2i8i0_5Vo_3ti0_6up_2qR_5Vo_3ti0_4$2Pp_2i8i0_2q_2_5Vr_5Vo_3ti0_4$2Pp_2i8i0h$3_5Vr_5Vo_3ti0_4$2Pp_2i8i0h$3P"(i8 %0, i8 %1) {
  %3 = alloca i8
  %4 = alloca i8
  store i8 %0, i8* %3
  store i8 %1, i8* %4
  %5 = load i8, i8* %3
  %6 = load i8, i8* %4
  %7 = xor i8 %5, %6
  ret i8 %7
}

define private i16 @"_3R_4Rs2:g0s6:lomarf_3R_2_5Vr_5Vo_3ti0_4s7:integerPp_2i10i1hs1:__5Vr_5Vo_3ti0_4$2Pp_2i10i1h$3_5Vo_3ti0_4$2Pp_2i10i1_5Vo_3ti0_6up_2qR_5Vo_3ti0_4$2Pp_2i10i1_2q_2_5Vr_5Vo_3ti0_4$2Pp_2i10i1h$3_5Vr_5Vo_3ti0_4$2Pp_2i10i1h$3P"(i16 %0, i16 %1) {
  %3 = alloca i16
  %4 = alloca i16
  store i16 %0, i16* %3
  store i16 %1, i16* %4
  %5 = load i16, i16* %3
  %6 = load i16, i16* %4
  %7 = xor i16 %5, %6
  ret i16 %7
}







|










|









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
  %38 = load i16, i16* %7
  %39 = shl i16 %38, 4
  %40 = load i16, i16* %7
  %41 = ashr i16 %40, 4
  ret void
}

define private i8 @"_3R_4Rs2:g0s6:lomarf_3R_2_5Vr_5Vo_3ti0_4s7:integerPp_2i8i0hs1:__5Vr_5Vo_3ti0_4$2Pp_2i8i0h$3_5Vo_3ti0_4$2Pp_2i8i0_5Vo_3ti0_7up_2qR_5Vo_3ti0_4$2Pp_2i8i0_2q_2_5Vr_5Vo_3ti0_4$2Pp_2i8i0h$3_5Vr_5Vo_3ti0_4$2Pp_2i8i0h$3Pi0"(i8 %0, i8 %1) {
  %3 = alloca i8
  %4 = alloca i8
  store i8 %0, i8* %3
  store i8 %1, i8* %4
  %5 = load i8, i8* %3
  %6 = load i8, i8* %4
  %7 = xor i8 %5, %6
  ret i8 %7
}

define private i16 @"_3R_4Rs2:g0s6:lomarf_3R_2_5Vr_5Vo_3ti0_4s7:integerPp_2i10i1hs1:__5Vr_5Vo_3ti0_4$2Pp_2i10i1h$3_5Vo_3ti0_4$2Pp_2i10i1_5Vo_3ti0_7up_2qR_5Vo_3ti0_4$2Pp_2i10i1_2q_2_5Vr_5Vo_3ti0_4$2Pp_2i10i1h$3_5Vr_5Vo_3ti0_4$2Pp_2i10i1h$3Pi0"(i16 %0, i16 %1) {
  %3 = alloca i16
  %4 = alloca i16
  store i16 %0, i16* %3
  store i16 %1, i16* %4
  %5 = load i16, i16* %3
  %6 = load i16, i16* %4
  %7 = xor i16 %5, %6
  ret i16 %7
}
Changes to tests/noprelude/codegen/func.ll.
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
; ModuleID = 'testfuncmodule'
source_filename = "testfuncmodule"

@.str0 = private constant [7 x i8] c"lomarf\00"
@.str1 = private constant [9 x i8] c"whatever\00"

define void @main(i1 %0) {
  %2 = alloca i1
  store i1 %0, i1* %2
  %3 = load i1, i1* %2
  %4 = xor i1 %3, true
  call void @"_3R_3xs2:g0s3:meh_5Vo_3ti0_6up_2qhs1:__5Vo_3ti0v_2q_1_5Vr_5Vo_3ti0_3s4:boolPph$2P"(i1 %4)
  call void @"_3R_3xs2:g0s3:meh_5Vo_3ti0_6up_2qhs1:__5Vo_3ti0v_2q_1_5Vr_5Vo_3ti0_4s7:pointerPp_5Vo_3ti0_4s7:integerPp_2i8i0h$2P"(i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str1, i8 0, i8 0))
  call void @lomarf(i32 219)
  ret void
}

define private void @"_3R_3xs2:g0s3:meh_5Vo_3ti0_6up_2qhs1:__5Vo_3ti0v_2q_1_5Vr_5Vo_3ti0_3s4:boolPph$2P"(i1 %0) {
  %2 = alloca i1
  store i1 %0, i1* %2
  call void @puts(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str0, i8 0, i8 0))
  ret void
}

declare void @puts(i8*)

define private void @"_3R_3xs2:g0s3:meh_5Vo_3ti0_6up_2qhs1:__5Vo_3ti0v_2q_1_5Vr_5Vo_3ti0_4s7:pointerPp_5Vo_3ti0_4s7:integerPp_2i8i0h$2P"(i8* %0) {
  %2 = alloca i8*
  store i8* %0, i8** %2
  %3 = load i8*, i8** %2
  call void @puts(i8* %3)
  call void @"_3R_3xs2:g0s3:meh_5Vo_3ti0_6up_2qhs1:__5Vo_3ti0v_2q_1_5Vr_5Vo_3ti0_3s4:boolPph$2P"(i1 true)
  call void @"_3R_3xs2:g0s3:meh_5Vo_3ti0_6up_2qhs1:__5Vo_3ti0v_2q_1_5Vr_5Vo_3ti0_3s4:boolPph$2P"(i1 false)
  ret void
}

declare void @lomarf(i32)











|
|




|








|




|
|




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
; ModuleID = 'testfuncmodule'
source_filename = "testfuncmodule"

@.str0 = private constant [7 x i8] c"lomarf\00"
@.str1 = private constant [9 x i8] c"whatever\00"

define void @main(i1 %0) {
  %2 = alloca i1
  store i1 %0, i1* %2
  %3 = load i1, i1* %2
  %4 = xor i1 %3, true
  call void @"_3R_3xs2:g0s3:meh_5Vo_3ti0_7up_2qhs1:__5Vo_3ti0v_2q_1_5Vr_5Vo_3ti0_3s4:boolPph$2Pi0"(i1 %4)
  call void @"_3R_3xs2:g0s3:meh_5Vo_3ti0_7up_2qhs1:__5Vo_3ti0v_2q_1_5Vr_5Vo_3ti0_4s7:pointerPp_5Vo_3ti0_4s7:integerPp_2i8i0h$2Pi0"(i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str1, i8 0, i8 0))
  call void @lomarf(i32 219)
  ret void
}

define private void @"_3R_3xs2:g0s3:meh_5Vo_3ti0_7up_2qhs1:__5Vo_3ti0v_2q_1_5Vr_5Vo_3ti0_3s4:boolPph$2Pi0"(i1 %0) {
  %2 = alloca i1
  store i1 %0, i1* %2
  call void @puts(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str0, i8 0, i8 0))
  ret void
}

declare void @puts(i8*)

define private void @"_3R_3xs2:g0s3:meh_5Vo_3ti0_7up_2qhs1:__5Vo_3ti0v_2q_1_5Vr_5Vo_3ti0_4s7:pointerPp_5Vo_3ti0_4s7:integerPp_2i8i0h$2Pi0"(i8* %0) {
  %2 = alloca i8*
  store i8* %0, i8** %2
  %3 = load i8*, i8** %2
  call void @puts(i8* %3)
  call void @"_3R_3xs2:g0s3:meh_5Vo_3ti0_7up_2qhs1:__5Vo_3ti0v_2q_1_5Vr_5Vo_3ti0_3s4:boolPph$2Pi0"(i1 true)
  call void @"_3R_3xs2:g0s3:meh_5Vo_3ti0_7up_2qhs1:__5Vo_3ti0v_2q_1_5Vr_5Vo_3ti0_3s4:boolPph$2Pi0"(i1 false)
  ret void
}

declare void @lomarf(i32)
Changes to tests/noprelude/codegen/if.ll.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
; ModuleID = 'iftest'
source_filename = "iftest"

@.str0 = private constant [7 x i8] c"lomarf\00"
@.str1 = private constant [3 x i8] c"gg\00"
@.str2 = private constant [5 x i8] c"blah\00"
@.str3 = private constant [4 x i8] c"lol\00"

define void @main() {
  call void @"_3R_3xs2:g0s3:meh_5Vo_3ti0_6up_2qhs1:__5Vo_3ti0v_2q_2_5Vr_5Vo_3ti0_3s4:boolPph$2_5Vr_5Vo_3ti0_3$3Pph$2P"(i1 true, i1 false)
  call void @"_3R_3xs2:g0s3:meh_5Vo_3ti0_6up_2qhs1:__5Vo_3ti0v_2q_2_5Vr_5Vo_3ti0_3s4:boolPph$2_5Vr_5Vo_3ti0_3$3Pph$2P"(i1 true, i1 true)
  call void @"_3R_3xs2:g0s3:meh_5Vo_3ti0_6up_2qhs1:__5Vo_3ti0v_2q_2_5Vr_5Vo_3ti0_3s4:boolPph$2_5Vr_5Vo_3ti0_3$3Pph$2P"(i1 false, i1 false)
  ret void
}

define private void @"_3R_3xs2:g0s3:meh_5Vo_3ti0_6up_2qhs1:__5Vo_3ti0v_2q_2_5Vr_5Vo_3ti0_3s4:boolPph$2_5Vr_5Vo_3ti0_3$3Pph$2P"(i1 %0, i1 %1) {
  %3 = alloca i1
  %4 = alloca i1
  store i1 %0, i1* %3
  store i1 %1, i1* %4
  %5 = load i1, i1* %3
  br i1 %5, label %6, label %12










|
|
|



|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
; ModuleID = 'iftest'
source_filename = "iftest"

@.str0 = private constant [7 x i8] c"lomarf\00"
@.str1 = private constant [3 x i8] c"gg\00"
@.str2 = private constant [5 x i8] c"blah\00"
@.str3 = private constant [4 x i8] c"lol\00"

define void @main() {
  call void @"_3R_3xs2:g0s3:meh_5Vo_3ti0_7up_2qhs1:__5Vo_3ti0v_2q_2_5Vr_5Vo_3ti0_3s4:boolPph$2_5Vr_5Vo_3ti0_3$3Pph$2Pi0"(i1 true, i1 false)
  call void @"_3R_3xs2:g0s3:meh_5Vo_3ti0_7up_2qhs1:__5Vo_3ti0v_2q_2_5Vr_5Vo_3ti0_3s4:boolPph$2_5Vr_5Vo_3ti0_3$3Pph$2Pi0"(i1 true, i1 true)
  call void @"_3R_3xs2:g0s3:meh_5Vo_3ti0_7up_2qhs1:__5Vo_3ti0v_2q_2_5Vr_5Vo_3ti0_3s4:boolPph$2_5Vr_5Vo_3ti0_3$3Pph$2Pi0"(i1 false, i1 false)
  ret void
}

define private void @"_3R_3xs2:g0s3:meh_5Vo_3ti0_7up_2qhs1:__5Vo_3ti0v_2q_2_5Vr_5Vo_3ti0_3s4:boolPph$2_5Vr_5Vo_3ti0_3$3Pph$2Pi0"(i1 %0, i1 %1) {
  %3 = alloca i1
  %4 = alloca i1
  store i1 %0, i1* %3
  store i1 %1, i1* %4
  %5 = load i1, i1* %3
  br i1 %5, label %6, label %12

Changes to tests/noprelude/codegen/logicops.ll.
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
; ModuleID = 'logic ops test'
source_filename = "logic ops test"

define void @main(i1 %0, i1 %1) {
  %3 = alloca i1
  %4 = alloca i1
  store i1 %0, i1* %3
  store i1 %1, i1* %4
  %5 = load i1, i1* %3
  %6 = load i1, i1* %4
  %7 = call i1 @"_3R_3xs2:g0s6:lomarf_5Vo_3ti0_6up_2qhs1:__5Vo_3ti0_3s4:boolPp_2q_2_5Vr_5Vo_3ti0_3$3Pph$2_5Vr_5Vo_3ti0_3$3Pph$2P"(i1 %5, i1 %6)
  %8 = load i1, i1* %3
  %9 = load i1, i1* %4
  %10 = call i1 @"_3R_3xs2:g0s4:blah_5Vo_3ti0_6up_2qhs1:__5Vo_3ti0_3s4:boolPp_2q_2_5Vr_5Vo_3ti0_3$3Pph$2_5Vr_5Vo_3ti0_3$3Pph$2P"(i1 %8, i1 %9)
  ret void
}

define private i1 @"_3R_3xs2:g0s6:lomarf_5Vo_3ti0_6up_2qhs1:__5Vo_3ti0_3s4:boolPp_2q_2_5Vr_5Vo_3ti0_3$3Pph$2_5Vr_5Vo_3ti0_3$3Pph$2P"(i1 %0, i1 %1) {
  %3 = alloca i1
  %4 = alloca i1
  store i1 %0, i1* %3
  store i1 %1, i1* %4
  %5 = load i1, i1* %3
  br i1 %5, label %8, label %6

6:                                                ; preds = %2
  %7 = load i1, i1* %4
  br label %8

8:                                                ; preds = %6, %2
  %9 = phi i1 [ true, %2 ], [ %7, %6 ]
  ret i1 %9
}

define private i1 @"_3R_3xs2:g0s4:blah_5Vo_3ti0_6up_2qhs1:__5Vo_3ti0_3s4:boolPp_2q_2_5Vr_5Vo_3ti0_3$3Pph$2_5Vr_5Vo_3ti0_3$3Pph$2P"(i1 %0, i1 %1) {
  %3 = alloca i1
  %4 = alloca i1
  store i1 %0, i1* %3
  store i1 %1, i1* %4
  %5 = load i1, i1* %3
  br i1 %5, label %6, label %8











|


|



|
















|







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
; ModuleID = 'logic ops test'
source_filename = "logic ops test"

define void @main(i1 %0, i1 %1) {
  %3 = alloca i1
  %4 = alloca i1
  store i1 %0, i1* %3
  store i1 %1, i1* %4
  %5 = load i1, i1* %3
  %6 = load i1, i1* %4
  %7 = call i1 @"_3R_3xs2:g0s6:lomarf_5Vo_3ti0_7up_2qhs1:__5Vo_3ti0_3s4:boolPp_2q_2_5Vr_5Vo_3ti0_3$3Pph$2_5Vr_5Vo_3ti0_3$3Pph$2Pi0"(i1 %5, i1 %6)
  %8 = load i1, i1* %3
  %9 = load i1, i1* %4
  %10 = call i1 @"_3R_3xs2:g0s4:blah_5Vo_3ti0_7up_2qhs1:__5Vo_3ti0_3s4:boolPp_2q_2_5Vr_5Vo_3ti0_3$3Pph$2_5Vr_5Vo_3ti0_3$3Pph$2Pi0"(i1 %8, i1 %9)
  ret void
}

define private i1 @"_3R_3xs2:g0s6:lomarf_5Vo_3ti0_7up_2qhs1:__5Vo_3ti0_3s4:boolPp_2q_2_5Vr_5Vo_3ti0_3$3Pph$2_5Vr_5Vo_3ti0_3$3Pph$2Pi0"(i1 %0, i1 %1) {
  %3 = alloca i1
  %4 = alloca i1
  store i1 %0, i1* %3
  store i1 %1, i1* %4
  %5 = load i1, i1* %3
  br i1 %5, label %8, label %6

6:                                                ; preds = %2
  %7 = load i1, i1* %4
  br label %8

8:                                                ; preds = %6, %2
  %9 = phi i1 [ true, %2 ], [ %7, %6 ]
  ret i1 %9
}

define private i1 @"_3R_3xs2:g0s4:blah_5Vo_3ti0_7up_2qhs1:__5Vo_3ti0_3s4:boolPp_2q_2_5Vr_5Vo_3ti0_3$3Pph$2_5Vr_5Vo_3ti0_3$3Pph$2Pi0"(i1 %0, i1 %1) {
  %3 = alloca i1
  %4 = alloca i1
  store i1 %0, i1* %3
  store i1 %1, i1* %4
  %5 = load i1, i1* %3
  br i1 %5, label %6, label %8

Changes to tests/noprelude/combined/meson.build.
1
2
3
4
5
6
7
8
9
tests = [
    #'tuple', # Not enabled yet
    'mandelbrot'
]

testrunner_interp = find_program( 'test_runner_interp.sh' )
testrunner_compile = find_program( 'test_runner_compile.sh' )

foreach t : tests

|







1
2
3
4
5
6
7
8
9
tests = [
    'tuple',
    'mandelbrot'
]

testrunner_interp = find_program( 'test_runner_interp.sh' )
testrunner_compile = find_program( 'test_runner_compile.sh' )

foreach t : tests
Changes to tests/noprelude/combined/test_runner_compile.sh.
1
2
3
4
5
6
7
8
9
#!/bin/sh
OUTFILE=$(mktemp)

$1 $2.g
if [ "$?" -eq "1" ]; then
    exit 1
fi

$2.g.out > $OUTFILE

|







1
2
3
4
5
6
7
8
9
#!/bin/sh
OUTFILE=FUCK.txt #$(mktemp)

$1 $2.g
if [ "$?" -eq "1" ]; then
    exit 1
fi

$2.g.out > $OUTFILE
Changes to tests/noprelude/combined/tuple.g.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

using puts = ExternalFunction( uint(32) ( pointer( uint(8) ) str ), "puts" )

void print( ct_string str )
{
    #if IsCompiling
    {
        puts( str )
    }
    #else
    {
        Print( str )
    }
}

bool check( bool cond, ct_string message )
{
    print( message )
    print( ": " )
    if cond print( "OK\n" ) else print( "Failed\n" )
    return cond
}

// Multiple return values
bool, uint(32) foo()
>
|

|



|



|



|

|







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

using puts = ExternalVarArgFunction( uint(32) ( pointer( uint(8) ) str ), "printf" )

void print( $str )
{
    #if IsCompiling
    {
        puts( $str )
    }
    #else
    {
        Print( $str )
    }
}

bool check( bool cond, $message )
{
    print( $message )
    print( ": " )
    if cond print( "OK\n" ) else print( "Failed\n" )
    return cond
}

// Multiple return values
bool, uint(32) foo()
43
44
45
46
47
48
49











    return 1

// Modifying individual tuple members
tup2.2 = 654654

if !check( tup2.0 == 219 & tup2.1 & tup2.2 == 654654 & tup2.3 == 420, "tuple test 3"  )
    return 1


















>
>
>
>
>
>
>
>
>
>
>
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
    return 1

// Modifying individual tuple members
tup2.2 = 654654

if !check( tup2.0 == 219 & tup2.1 & tup2.2 == 654654 & tup2.3 == 420, "tuple test 3"  )
    return 1

using fflush = ExternalFunction( uint(32) ( pointer(void) stream ), "fflush" )

#if IsCompiling
{
    fflush( nullptr )
}
#else
{
    FlushOutput();
}