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: |
7d2def7b7561cbe9e14dfef5f2a89fe5 |
| 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
Changes to bs/builtins/api/codegen/func.cpp.
1 | #include "builtins/builtins.h" | | | 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 | #include "builtins/builtins.h" | | | | 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 | #include "builtins/builtins.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 |
#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 | #include "builtins/builtins.h" | | | 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 |
[]( const ptr< codegen::Module >& module, const string& filename )
{
return module->emitToFile( filename, llvm::CGFT_ObjectFile );
} );
}
}
| | | 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 |
#ifndef GOOSE_BUILTINS_API_CODEGEN_MODULE_H
#define GOOSE_BUILTINS_API_CODEGEN_MODULE_H
namespace goose::builtins
{
extern void SetupApiCGModule( Env& e );
}
| | | 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 |
auto funcIdentity = AppendToVectorTerm( builtins::RootIdentity(),
TERM( StringId( Env::NewUniqueId() ) ) );
c.env()->addVisibilityRule( builtins::RootIdentity(), funcIdentity );
auto func = BuildFunc( localC, ftype, funcIdentity, params, nullptr, c );
| | | | 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 | #include "builtins/builtins.h" | | | | 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 | #ifndef GOOSE_BUILTINS_API_EXTENSIBILITY_CODEBUILDER_H #define GOOSE_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::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 | #include "builtins/builtins.h" | | | | 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 |
}
private:
Term m_term;
};
}
| | | 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 | #include "builtins/builtins.h" | | | | 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 |
}
private:
Value m_value;
};
}
| | | 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 | #include "builtins/builtins.h" | | | 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 | #include "builtins/builtins.h" | | | | 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 | #ifndef GOOSE_BUILTINS_H #define GOOSE_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 "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 |
#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 >(),
| | | | | | | | | | | | | | | 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 |
#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 ) );
}
| | | 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 |
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.
| | | 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 | #include "builtins/builtins.h" #include "precedence.h" #include "helpers.h" #include "tuple.h" using namespace goose; | | | | 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 |
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(
| | | 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 |
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(
| | | 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 |
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(
| | | 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 |
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(
| | | 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 | #include "builtins/builtins.h" #include "precedence.h" #include "helpers.h" #include "tuple.h" using namespace goose; | | | | 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 | #include "builtins/builtins.h" #include "precedence.h" #include "helpers.h" using namespace goose; | | | 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 | #include "builtins/builtins.h" #include "precedence.h" #include "helpers.h" #include "tuple.h" using namespace goose; | | | | 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 | #include "builtins/builtins.h" #include "precedence.h" #include "helpers.h" using namespace goose; | | | | 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 | #include "builtins/builtins.h" #include "precedence.h" #include "builtins/helpers.h" using namespace goose; | | | | 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 | #include "builtins/builtins.h" #include "precedence.h" #include "helpers.h" #include "tuple.h" using namespace goose; | | | | 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 | #include "builtins/builtins.h" #include "precedence.h" #include "helpers.h" #include "tuple.h" using namespace goose; | | | | | 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 |
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(
| | | 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 |
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(
| | | 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 |
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(
| | | 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 | #include "builtins/builtins.h" #include "precedence.h" #include "builtins/helpers.h" using namespace goose; | | | 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 | #include "builtins/builtins.h" #include "precedence.h" #include "builtins/helpers.h" using namespace goose; | | | 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 | #include "builtins/builtins.h" #include "parse/parse.h" #include "precedence.h" #include "builtins/helpers.h" using namespace goose; | | | 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 |
cb->poison();
return true;
}
// Emit cleanups for all live variables in the scopes that we are breaking through.
cb->destroyAllLiveValuesFromBreakScope( p.context(), cb->breakableScopeLevels() );
| | | 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 | #include "builtins/builtins.h" #include "parse/parse.h" #include "precedence.h" #include "builtins/helpers.h" using namespace goose; | | | 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 |
cb->poison();
return true;
}
// Emit cleanups for all live variables in the scopes that we are continuing through.
cb->destroyAllLiveValuesFromBreakScope( p.context(), cb->continuableScopeLevels() );
| | | 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 | #include "builtins/builtins.h" #include "parse/parse.h" #include "precedence.h" #include "builtins/helpers.h" using namespace goose; | | | 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 | #include "builtins/builtins.h" #include "parse/parse.h" #include "precedence.h" #include "builtins/helpers.h" using namespace goose; | | | 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 |
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();
| | | 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 |
pElseSuccBB = cfg->currentBB();
}
}
if( !pPrecBB )
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 | #include "builtins/builtins.h" #include "parse/parse.h" #include "precedence.h" #include "builtins/helpers.h" using namespace goose; | | | 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 |
// 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 >() )
{
| | | | | | | 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 | #include "builtins/builtins.h" #include "parse/parse.h" #include "precedence.h" using namespace goose; | | | 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 | #include "builtins/builtins.h" #include "precedence.h" #include "builtins/helpers.h" using namespace goose; | | | 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 | #include "builtins/builtins.h" #include "parse/parse.h" #include "precedence.h" #include "builtins/helpers.h" using namespace goose; | | | 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 |
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
| | | | | | | | | 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 |
const Term& ValuePatternT::GetPattern()
{
static auto pattern = HOLE( "T"_sid );
return pattern;
}
}
| | | 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 |
}
};
template< typename T >
using ValueTypeOf = CustomPattern< Value, PatternValueTypeOf< T > >;
}
| | | 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 |
#include "builtins/builtins.h"
using namespace goose::builtins;
bool goose::builtins::IsConstrainedFunc( const Value& tcc )
{
return tcc.type() == GetValueType< ConstrainedFunc >();
}
| | | 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 |
ptr< InvocationRule > m_pInvRule;
Value m_func;
};
extern bool IsConstrainedFunc( const Value& tcc );
}
| | | 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 | #include "builtins/builtins.h" using namespace goose; | | | 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 |
static auto pattern = ValueToIRExpr(
Value( TypeType(), VEC( TSID( decl ), HOLE( "_"_sid ) ) ) );
return pattern;
}
}
| | | 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 |
Term m_type;
StringId m_name;
};
extern bool IsDecl( const Value& d );
}
| | | 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 | #include "builtins/builtins.h" #include "parse/parse.h" using namespace goose::parse; | | | 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 | #include "builtins/builtins.h" #include "parse/parse.h" using namespace goose::parse; | | | | | | 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 |
// Same as above, but takes a type pattern provider.
template< typename PP >
struct TypePatternParam
{};
}
| | | 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 |
{
return GetValueType< T >();
}
template< typename TT >
static auto ToValue( TT&& val )
{
| | | | 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 |
if( !pOvlSet->add( env, ToValue< FT >( forward< F >( func ), fvi ), GetFuncInvocationRule() ) )
throw logic_error( "panic: duplicate overload registered for builtin func." );
return fvi;
}
}
| | | 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 |
if constexpr( is_void_v< builtins::remove_eager_t< R > > )
{
apply( func, *params );
return Value( GetValueType< void >(), 0U );
}
else
| | | 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 |
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() ) );
| | | | | | 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 |
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() );
| | | | 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 |
}
bool ParseFuncBody( const Context& c, const Func& f )
{
if( !ParseFuncConstraints( c, f.type() ) )
return false;
| | | | | | | | | | | 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 |
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.
| | | | | | 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 |
);
assert( typeDecomp );
auto&& [kind, rtype, ptypes, vinf, varArg] = *typeDecomp;
return rtype;
}
| | | | 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 |
return true;
} );
return av;
}
}
| | | 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 |
Value Bridge< Func >::ToValue( const builtins::Func& func )
{
if( func.isExternal() )
return Value( Type( func ), TERM( *func.symbol() ) );
return Value( Type( func ), VEC(
| | | | | | 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 |
Template,
Invalid
};
extern Term GetFuncSig( const Value& func );
extern Term GetFuncSigFromType( const Value& funcType );
extern Term GetFuncRType( const Value& 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 |
extern bool IsExternalFunc( const Value& f );
extern bool IsFuncType( const Value& t );
class Func
{
public:
template< typename T, typename B, typename P >
| | | | | | | | | 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 |
);
auto&& [unifiedArgs, unifiedRType] = *callDecomp;
newCallee.setLocationId( loc );
if( IsBuiltinFunc( newCallee ) )
| | | | 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 | #include "builtins/builtins.h" using namespace goose; | | | 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 | #include "builtins/builtins.h" using namespace goose; | | | 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 | #include "builtins/builtins.h" #include "parse/parse.h" using namespace goose::parse; | | | 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 |
struct VerificationIntrinsic
{};
using BuiltinIntrinsicFuncWrapper = function< Value ( const Context& c, const Term& argVec ) >;
extern const BuiltinIntrinsicFuncWrapper& GetBuiltinIntrinsicFuncWrapper( const Value& func );
}
| | | 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 | #ifndef GOOSE_BUILTINS_TYPES_INTRINSIC_INL #define GOOSE_BUILTINS_TYPES_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::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 | #include "builtins/builtins.h" #include "parse/parse.h" using namespace goose::parse; | | | 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 |
{
public:
bool canBeInvoked( const Context& c, const Value& callee ) const final
{
auto lv = *FromValue< LocalVar >( callee );
auto val = BuildComputedValue( lv.type(),
| | | | 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 | #include "builtins/builtins.h" #include "parse/parse.h" using namespace goose::builtins; | | | 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 |
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 ) );
| | | 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 |
}
cb->pushLiveValue( locVar, lv.index() );
return locVar;
}
}
| | | 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 |
private:
StringId m_name;
Term m_type;
uint32_t m_index = 0;
};
}
| | | 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 | #include "builtins/builtins.h" using namespace goose; | | | | 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 | #include "builtins/builtins.h" #include "parse/parse.h" using namespace goose::parse; | | | 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 |
assert( pOvlSet );
Context localC( c.env(), c.identity(), GetValueType< uint32_t >() );
localC.setBuilder( c.codeBuilder() );
execute::VM 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 |
#include "builtins/builtins.h"
using namespace goose::builtins;
bool goose::builtins::IsOverloadSet( const Value& os )
{
return os.type() == GetValueType< ptr< OverloadSet > >();
}
| | | 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 |
extern ptr< InvocationRule >& GetOverloadSetInvocationRule();
extern void SetupOverloadSetInvocationRule( Env& e );
extern void SetupOverloadSetTypeChecking( Env& e );
extern bool IsOverloadSet( const Value& os );
}
| | | 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 | #include "builtins/builtins.h" using namespace goose; | | | 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 | #include "builtins/builtins.h" #include "parse/parse.h" #include "precedence.h" using namespace goose; | | | 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 | #include "builtins/builtins.h" #include "parse/parse.h" using namespace goose::builtins; | | | 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 |
{
static auto pattern = GetValueType< Reference >( HOLE( "T"_sid ), TSID( mut ) );
return pattern;
}
Reference BuildLocalVarConstRef( const LocalVar& lv )
{
| | | | | 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 |
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 )
{
| | | | | | 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 |
static auto pattern = GetValueType< Reference >( PP::GetPattern(), TSID( const ) );
return pattern;
}
};
private:
ReferenceType m_type;
| | | | 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 | #include "builtins/builtins.h" using namespace goose; | | | | 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 |
{
auto refval = *ValueFromIRExpr( rhs );
auto ref = FromValue< Reference >( refval );
if( !ref )
co_return;
auto content = ValueToIRExpr( BuildComputedValue( ref->type().type(),
| | | 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 |
llvm::Type* GetLLVMType( const ArrayType& a )
{
return llvm::ArrayType::get( GetLLVMType( *ValueFromIRExpr( a.m_containedType ) ), a.m_count );
}
}
| | | 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 |
Term m_containedType;
uint32_t m_count = 1;
};
extern llvm::Type* GetLLVMType( const ArrayType& a );
}
| | | 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 |
llvm::Type* GetLLVMType( const IntegerType& t )
{
return llvm::IntegerType::get( GetLLVMContext(), t.m_numBits );
}
}
| | | 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 |
auto&& [predicates, llvmType, params] = *result;
auto&& [numBits, signd] = params;
return IntegerType( numBits, !!signd );
}
Term Bridge< APSInt >::Type( const APSInt& 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 |
return *result;
}
const Term& Bridge< uint8_t >::Type()
{
| | | | | | | | 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 |
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 );
}
| | | 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 | #include "builtins/builtins.h" #include "parse/parse.h" using namespace goose::parse; | | | 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 |
llvm::Type* GetLLVMType( const PointerType& p )
{
return llvm::PointerType::getUnqual( GetLLVMType( *ValueFromIRExpr( 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 |
return nullopt;
return NullPointerType();
}
const Term& Bridge< NullPointer >::Type()
{
| | | 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 |
struct NullPointer
{};
extern llvm::Type* GetLLVMType( const PointerType& p );
}
| | | 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 |
elements.emplace_back( llvmType );
}
return llvm::StructType::get( GetLLVMContext(), elements, rt.m_packed );
}
}
| | | 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 |
#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 ) :
| | | 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 |
auto rt = ValueToIRExpr( ToValue( RecordType( forward< T >( types ), packed ) ) );
return Value( move( rt ), forward< V >( vals ) );
}
extern llvm::Type* GetLLVMType( const RecordType& rt );
}
| | | 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 | #include "builtins/builtins.h" #include "builtins/helpers.h" using namespace goose; | | | 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 |
[]( 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,
| | | 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 |
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 ):
| | | | 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 |
#include "builtins/builtins.h"
using namespace goose::builtins;
namespace goose::builtins
{
bool IsTDecl( const Value& td )
{
return td.type() == GetValueType< TDecl >();
}
}
| | | 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 |
Term m_type;
StringId m_name;
};
extern bool IsTDecl( const Value& td );
}
| | | 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 | #include "builtins/builtins.h" #include "lex/lex.h" #include "parse/parse.h" using namespace goose::builtins; using namespace goose::parse; | | | 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 |
Term m_identity;
ptr< void > m_toks;
};
extern Value InstantiateTFunc( const Context& c, const Value& callee, const Term& unifiedCallPat, const TypeCheckingContext& tcc );
}
| | | 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 |
bool IsTFunc( const Value& t )
{
return IsTFuncType( *ValueFromIRExpr( t.type() ) );
}
}
| | | 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 |
ptr< vector< TermLoc > > m_postCondToks = make_shared< vector< TermLoc > >();
};
extern bool IsTFuncType( const Value& t );
extern bool IsTFunc( const Value& t );
}
| | | 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 |
const Term& TNamedDecl::Pattern::GetPattern()
{
static auto pattern = GetValueType< TNamedDecl >();
return pattern;
}
}
| | | 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 |
Term m_type;
StringId m_name;
};
extern bool IsTNamedDecl( const Value& td );
}
| | | 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 |
bool IsTVar( const Value& tv )
{
return tv.type() == GetValueType< TVar >();
}
}
| | | 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 |
};
extern bool IsTExpr( const optional< Value >& te );
extern bool IsTExpr( const Value& te );
extern bool IsTVar( const Value& tv );
}
| | | 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 | #include "builtins/builtins.h" using namespace goose::builtins; | | | 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 |
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.
//
| | | | 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 | #include "builtins/builtins.h" using namespace goose; | | | 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 | #include "builtins/builtins.h" #include "parse/parse.h" using namespace goose::parse; | | | 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 | #include "builtins/builtins.h" #include "parse/parse.h" using namespace goose::parse; | | | 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 | #include "builtins/builtins.h" #include "parse/parse.h" using namespace goose::parse; | | | 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 | #include "builtins/builtins.h" using namespace goose; | | | 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 | #include "builtins/builtins.h" using namespace goose; | | | 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 |
struct TuplePatternOfTypeT
{
static const Term& GetPattern();
};
}
| | | 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 |
return ForEachInVectorTerms( tup1.val(), tup2.val(), [&]( auto&& t1, auto&& t2 )
{
return func( *ValueFromIRExpr( t1 ), *ValueFromIRExpr( t2 ) );
} );
}
}
| | | 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 | #include "builtins/builtins.h" using namespace goose; | | | 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 |
if( index == ( tupSize - 1 ) )
co_yield { ValueToIRExpr( newOut ), tcc };
else
co_yield TypeCheckConstantTuple( tcc, tupType, tupArg, index + 1, newOut );
}
}
| | | 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 |
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();
| | | 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 |
c.env()->addVisibilityRule( parentIdentity, predicatesIdentity );
auto typeTerm = ValueToIRExpr( type );
auto name = "@val"_sid;
auto valuePlaceholderIdentity = AppendToVectorTerm( predicatesIdentity, TERM( name ) );
c.env()->storeValue( valuePlaceholderIdentity, ANYTERM( _ ),
| | | 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_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 |
bool canBeEagerlyEvaluated() const
{
return false;
}
private:
| | | 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_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_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 |
bool canBeEagerlyEvaluated() const
{
return false;
}
private:
| | | 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_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_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 "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_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_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_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 |
{
return CanValueBeEagerlyEvaluated( m_cond );
}
void addCFGEdges( const ptr< CFG >& cfg, uint32_t srcBBIndex );
private:
| | | 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_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_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 "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 |
if( !argsCanBeExecuted )
return false;
if( IsBuiltinFunc( m_func ) )
return true;
| | | 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 |
if( !argsAreConstant )
return false;
if( IsEagerBuiltinFunc( m_func ) )
return true;
| | | | | 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_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 "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_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 |
// calling ComputeDominators().
optional< uint32_t > getDominatorDistance( uint32_t bbIndex1, uint32_t bbIndex2 ) const;
const auto& getBB( uint32_t index ) const { return m_basicBlocks[index - 1]; }
auto count() const { return m_basicBlocks.size(); }
| | | | 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
// 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 |
// 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.
| | | 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 "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 |
for( auto&& instr : *bb )
CfgViz( builder, instr );
if( bb->terminator() )
CfgViz( builder, *bb->terminator() );
}
| | | | 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_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_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_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_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_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 |
bool canBeEagerlyEvaluated() const
{
return CanValueBeEagerlyEvaluated( m_value );
}
private:
uint32_t m_index = 0;
| | | 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 "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 |
{
st.ancestor[s] = v;
s = st.child[s];
}
}
}
| | | 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 "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_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 |
bool canBeExecuted() const;
bool isValid() const { return m_valid; }
void setInvalid() { m_valid = false; }
private:
| | | 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_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 |
bool canBeEagerlyEvaluated() const
{
return false;
}
private:
| | | 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 "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_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 "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_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_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_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_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 |
bool canBeEagerlyEvaluated() const
{
return CanValueBeEagerlyEvaluated( m_operand );
}
private:
| | | 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 "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 "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_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_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 |
bool canBeEagerlyEvaluated() const
{
return true;
}
private:
| | | | 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_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 |
bool canBeEagerlyEvaluated() const
{
return false;
}
private:
| | | 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_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 |
{
return !m_value || CanValueBeEagerlyEvaluated( *m_value );
}
void addCFGEdges( const ptr< CFG >& cfg, uint32_t srcBBIndex ) {}
private:
| | | 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_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 |
bool canBeEagerlyEvaluated() const
{
return IsCompileTimeTempRef( m_addr )
&& CanValueBeEagerlyEvaluated( m_val );
}
private:
| | | | 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 "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_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 | #include <exception> #define CATCH_CONFIG_MAIN #include "catch2/catch.hpp" | | | | | | 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 | #include <exception> #define CATCH_CONFIG_MAIN #include "catch2/catch.hpp" | | | | | | 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 |
tests = [
'dom-1',
'dom-2'
]
| | | | | | | 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 | #include "codegen.h" #include "builtins/builtins.h" using namespace goose; using namespace goose::codegen; using namespace goose::builtins; | | | | | | | | | 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 |
if( !buildTerminator( inf, *pBB->terminator() ) )
return nullptr;
return pBB->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 | #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" | | | | | 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 | #include "codegen.h" #include "builtins/builtins.h" using namespace goose; using namespace goose::codegen; using namespace goose::builtins; | | | | | | | | | | | | 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 |
}
llvm::Function* Module::getOrCreateFunc( const Context& c, const builtins::Func& func )
{
if( func.isExternal() )
return getOrCreateFunc( c, func, *func.symbol(), llvm::Function::ExternalLinkage );
| | | 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 |
if( func.isExternal() )
return pllvmFunc;
Infos inf( c );
// Generate allocas and stores for the 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 |
for( auto&& arg : pllvmFunc->args() )
{
m_llvmBuilder.CreateStore( &arg, args[i] );
inf.temporaries->set( i, args[i] );
++i;
}
| | | | 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 | #include "codegen.h" #include "builtins/builtins.h" using namespace goose; using namespace goose::codegen; using namespace goose::builtins; | | | | 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 |
args.emplace_back( parg );
}
return m_llvmBuilder.CreateCall( llvm::FunctionCallee( llvmCallee ), args );
}
| | | | 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 |
m_llvmBuilder.SetInsertPoint( inf.allocaBasicBlock, inf.allocaBasicBlock->begin() );
inf.lastEmittedAlloca = m_llvmBuilder.CreateAlloca( type );
return inf.lastEmittedAlloca;
}
| | | | | 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 |
return m_llvmBuilder.CreateMemCpy( ptrVal, llvm::None, pGlob, llvm::None,
llvm::ConstantInt::get( llvm::Type::getInt32Ty( GetLLVMContext() ), size ) );
}
return m_llvmBuilder.CreateStore( pValue, ptrVal );
}
| | | 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 |
if( !pPHI )
return nullptr;
return createTemporary( inf, p.destIndex(), 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 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 |
llvm::ConstantInt::get( llvm::Type::getInt8Ty( GetLLVMContext() ), 0 ),
llvm::ConstantInt::get( llvm::Type::getInt8Ty( GetLLVMContext() ), 0 )
};
return m_llvmBuilder.CreateGEP( pGlob, idxs );
}
| | | | 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 | #include "codegen.h" #include "builtins/builtins.h" using namespace goose; using namespace goose::codegen; using namespace goose::builtins; | | | | | | | | | 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 | #include "codegen.h" using namespace goose; | | | | | 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 |
{
Infos( const Context& c ) : context( c ) {}
const Context& context;
llvm::BasicBlock* allocaBasicBlock = nullptr;
llvm::AllocaInst* lastEmittedAlloca = nullptr;
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 |
{
if( val.isPoison() )
return nullptr;
if( val.isConstant() )
return buildConstant( inf, val );
| | | 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 | #include "llvm/Support/TargetSelect.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Signals.h" using namespace goose; using namespace goose::util; | | | 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 |
return PoisonValue();
}
execute::VM vm;
return vm.execute( cfg->entryBB() );
}
| | | | 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 |
if( cfg->currentBB() && !cfg->currentBB()->terminator() )
{
p.flushValue();
cb->destroyAllLiveValues( c );
if( returnType == GetValueType< void >() )
| | | 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 |
dm.emitErrorMessage( defRetVal->locationId(), "ambiguous default return value conversion." );
break;
}
return nullptr;
}
| | | 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 |
class Compiler
{
public:
Compiler( int argc, char** argv );
uint32_t execute( const string& filename );
| | | | | | 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 | #ifndef GOOSE_DIAGNOSTICS_H #define GOOSE_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 "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_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 |
private:
StringId m_varName;
};
}
namespace std
{
| | | | 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_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 "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_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_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_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_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_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 "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_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_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 "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_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_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 "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_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_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 "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_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_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 "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_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_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_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_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 |
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.
| | | | | | | | | | | 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 | #define CATCH_CONFIG_MAIN #include "catch2/catch.hpp" | | | | 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 | #define CATCH_CONFIG_MAIN #include "catch2/catch.hpp" | | | | 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 | #define CATCH_CONFIG_MAIN #include "catch2/catch.hpp" | | | | 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 |
tests = [
'merge',
'match-terms',
'match-terms-trie'
]
foreach t : tests
| | | | | 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 "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_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_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 "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 |
}
return VEC( TSID( value ), TSID( constant ), v.type(), v.val(),
static_cast< LocationId >( v.locationId() ) );
}
return VEC( TSID( value ), TSID( computed ), v.type(),
| | | 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 |
if( !result )
return nullopt;
auto&& [sort, type, val, locationId] = *result;
if( sort == "constant"_sid )
return Value( type, val, static_cast< uint32_t >( 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_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 "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_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_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 |
private:
StringId m_varName;
};
}
namespace std
{
| | | | 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_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 | #include "execute.h" #include "builtins/builtins.h" #include "binaryops.inl" using namespace goose; using namespace goose::execute; using namespace goose::builtins; | | | | | | | | | | | | | | | | | | | | | | | | | 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 |
#ifndef GOOSE_EXECUTE_BINARYOPS_INL
#define GOOSE_EXECUTE_BINARYOPS_INL
namespace goose::execute
{
template< typename F >
| | | 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 |
}
assert( false );
return PoisonValue();
}
template< typename F >
| | | 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 |
}
assert( false );
return PoisonValue();
}
template< typename F >
| | | 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 |
}
assert( false );
return PoisonValue();
}
template< typename F >
| | | 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 | #include "execute.h" #include "builtins/builtins.h" using namespace goose; | | | | | | 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 | #ifndef GOOSE_EXECUTE_H #define GOOSE_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 "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 |
bb = executeTerminator( *bb->terminator() );
}
m_pPreviousBB = pbbBackup;
return m_retVal;
}
| | | | 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 |
if( !newVec )
return nullopt;
return ExecuteBuiltinFuncCall( func, TERM( newVec ) );
}
| | | 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 |
optional< Value > VM::ExecuteBuiltinFuncCall( const Value& func, const Term& args )
{
const auto& f = GetBuiltinFuncWrapper( func );
return f( args );
}
| | | | | | | | | | | | | | 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 |
{
return visit( [&]( auto&& ba )
{
return calcAddress( ba );
}, baseAddr );
}
| | | | 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 |
{
ms_remainingBranchInstExecutions = b;
}
optional< Value > execute( CFG& cfg );
optional< Value > execute( ptr< BasicBlock > bb );
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 | #ifndef GOOSE_LEX_H #define GOOSE_LEX_H #include "util/util.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 | bsinc = include_directories( '.' ) subdir( 'util' ) | | | | | | 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 | #ifndef GOOSE_PARSE_H #define GOOSE_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 "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 |
DiagnosticsManager::GetInstance().setCurrentVerbosityLevel( Verbosity::Silent );
if( context().codeBuilder() )
context().codeBuilder()->poison();
}
flushValue();
| | | 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 | #include "parse.h" using namespace goose; using namespace goose::parse; | | | 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 | #ifndef GOOSE_PARSE_RULE_HELPERS_H #define GOOSE_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::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 |
ptr< CodeBuilder > m_builder;
};
private:
// Destruction
bool destroyLiveValue( const Context& c, const Value& v );
| | | 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 | #include "sema.h" using namespace goose; | | | | 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 |
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 >
| | | | | 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 |
ptr< OverloadSet > m_extLowerTypeForVerification;
ptr< OverloadSet > m_extLowerConstantForVerification;
uint64_t m_valueStoreVersion = 0;
ptr< CTMemoryManager > m_memManager;
| | | | | | | 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 | #include "sema.h" #include "builtins/builtins.h" using namespace goose; | | | 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 | #ifndef GOOSE_SEMA_H #define GOOSE_SEMA_H #include "util/util.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 "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 |
#ifndef GOOSE_SEMA_TCTRIE_H
#define GOOSE_SEMA_TCTRIE_H
namespace goose::sema
{
| | | 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 |
{
auto nextIt = it;
++nextIt;
return Merge< T >( payload, nextIt, end, forward< F >( next ) );
} );
| | | | 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 |
tests = [
'unify-holes',
'tctrie-merge',
'tctrie-typecheck'
]
foreach t : tests
exe = executable( 'sema-' + t, t + '.cpp',
link_with:
[
goose_util,
| | | 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 | #define CATCH_CONFIG_MAIN #include "catch2/catch.hpp" #include "sema/sema.h" #include "builtins/builtins.h" using namespace std; using namespace goose; | | | 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 | #define CATCH_CONFIG_MAIN #include "catch2/catch.hpp" #include "sema/sema.h" #include "builtins/builtins.h" using namespace std; using namespace goose; | | | 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 | #define CATCH_CONFIG_MAIN #include "catch2/catch.hpp" #include "sema/sema.h" #include "builtins/builtins.h" using namespace std; using namespace goose; | | | 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 |
#include "verify.h"
#include "builtins/builtins.h"
#include "diagnostics/diagnostics.h"
using namespace goose::diagnostics;
namespace goose::verify
{
| | | 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 |
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; }
| | | 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 |
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;
| | | | 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 |
)
);
if( !result )
return true;
auto&& [type, val, locId] = *result;
| | | 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 |
#include "verify.h"
#include "builtins/builtins.h"
#include "diagnostics/diagnostics.h"
using namespace goose::diagnostics;
namespace goose::verify
{
| | | 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 |
return false;
}
} );
bool result = visit( [&]( auto&& instr )
{
return VerifyCompTimeExpr( b, instr );
| | | 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 |
)
);
if( !result )
return true;
auto&& [type, val, locId] = *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 ) }, 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 |
{
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 ),
| | | | 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 |
)
);
if( !result )
return true;
auto&& [type, val, locId] = *result;
| | | | 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 |
namespace goose::verify
{
class Func
{
public:
Func( const sema::Context& c, const builtins::Func& func );
| | | | | | | | | | | 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 |
#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
{
| | | 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 |
rm.emplace( blUnrollId, newRemappedIndex );
m_originalBBIndices.emplace( newRemappedIndex, blUnrollId.first );
return newRemappedIndex;
}
| | | | 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 |
auto it = m_originalBBIndices.find( remappedId );
if( it == m_originalBBIndices.end() )
return remappedId;
return it->second;
}
| | | 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 |
class Remapper
{
public:
Remapper( uint32_t firstRemappedId ) :
m_nextUniqueId( firstRemappedId )
{}
| | | | 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 |
// 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.
| | | 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 |
{
return visit( [&]( auto&& ba )
{
return LoadFromAddress( b, ba );
}, baseAddr );
}
| | | | 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 |
{
return visit( [&]( auto&& ba )
{
return StoreToAddress( b, ba, move( val ) );
}, baseAddr );
}
| | | | 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 |
#ifndef GOOSE_VERIFY_STORAGE_H
#define GOOSE_VERIFY_STORAGE_H
namespace goose::verify
{
| | | | | | | | | 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 |
#include "verify.h"
#include "builtins/builtins.h"
#include "diagnostics/diagnostics.h"
#include "helpers.inl"
using namespace goose::diagnostics;
namespace goose::verify
{
| | | | 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 |
return true;
} );
return success;
}
| | | | 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 |
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 );
| | | 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 |
const auto* expr = b.retrievePlaceholder( instr.name() );
if( expr )
return Z3Val{ *expr, *ValueFromIRExpr( instr.type() ) };
return BuildZ3ConstantFromType( b, instr.type(), format( "p{}", instr.name() ) );
}
| | | | 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 | #ifndef GOOSE_VERIFY_VALUE_H #define GOOSE_VERIFY_VALUE_H #include "z3++.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 "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 | #ifndef GOOSE_VERIFY_H #define GOOSE_VERIFY_H #include <z3++.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 "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 );
}
|
| ︙ | ︙ |