Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Changes In Branch cir-stack-language
Excluding Merge-Ins
This is equivalent to a diff from
b8a2990900
to 9814f18b04
|
2022-06-29
| | |
| 21:47 |
|
check-in: 1f87fbda15 user: zlodo tags: trunk
|
| 21:39 |
|
Closed-Leaf
check-in: 9814f18b04 user: zlodo tags: cir-stack-language
|
|
2022-06-28
| | |
| 22:51 |
|
check-in: 6c5b747f5c user: zlodo tags: cir-stack-language
|
|
2022-05-26
| | |
| 22:48 |
|
check-in: 536a94f712 user: zlodo tags: cir-stack-language
|
| 22:42 |
|
check-in: b8a2990900 user: zlodo tags: trunk
|
|
2022-05-15
| | |
| 19:25 |
|
check-in: 2503738366 user: zlodo tags: trunk
|
| | |
Changes to bs/builtins/builders/codebuilder.cpp.
| ︙ | | |
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
|
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
|
-
+
|
auto result = InvokeOverloadSet( c, c.env()->extDestroyValue(),
MakeTuple( v ) );
if( result.isPoison() )
return false;
if( !result.isConstant() )
cfg()->currentBB()->emplace_back( *result.cir() );
cfg()->currentBB()->append( result );
return true;
}
void CodeBuilder::extendValueLifetime( uint32_t index )
{
// Find the live value.
|
| ︙ | | |
Changes to bs/builtins/exprhelpers.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
|
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
|
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
|
#ifndef GOOSE_BUILTINS_EXPRHELPERS_H
#define GOOSE_BUILTINS_EXPRHELPERS_H
#include "parse/parse.h"
namespace goose::builtins::exprhelpers
{
template< typename V >
Value Not( V&& val )
{
auto locId = val.locationId();
return BuildComputedValue( GetValueType< bool >(),
cir::Not( forward< V >( val ) ) ).setLocationId( val.locationId() );
forward< V >( val ), cir::Not( locId ) ).setLocationId( locId );
}
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 ) ) ).setLocationId( locId );
forward< L >( lhs ), forward< R >( rhs ), cir::Or( locId ) ).setLocationId( locId );
}
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 );
forward< L >( lhs ), forward< R >( rhs ), cir::And( locId ) ).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 );
forward< L >( lhs ), forward< R >( rhs ), cir::Eq( locId ) ).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 );
forward< L >( lhs ), forward< R >( rhs ), cir::Neq( locId ) ).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 );
forward< L >( lhs ), forward< R >( rhs ), cir::UGT( locId ) ).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 );
forward< L >( lhs ), forward< R >( rhs ), cir::UGE( locId ) ).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 );
forward< L >( lhs ), forward< R >( rhs ), cir::ULT( locId ) ).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 );
forward< L >( lhs ), forward< R >( rhs ), cir::ULE( locId ) ).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 );
forward< L >( lhs ), forward< R >( rhs ), cir::SGT( locId ) ).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 );
forward< L >( lhs ), forward< R >( rhs ), cir::SGE( locId ) ).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 );
forward< L >( lhs ), forward< R >( rhs ), cir::SLT( locId ) ).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 ) ) ).setLocationId( locId );
forward< L >( lhs ), forward< R >( rhs ), cir::SLE( locId ) ).setLocationId( locId );
}
}
#endif
|
Changes to bs/builtins/meson.build.
| ︙ | | |
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
|
-
+
+
+
+
+
+
+
+
|
'types/func/bfunc.cpp',
'types/func/bintrinsic.cpp',
'types/func/functype.cpp',
'types/func/func.cpp',
'types/func/build.cpp',
'types/func/compile.cpp',
'types/func/invoke.cpp',
'types/func/typecheck.cpp',
'types/func/lower.cpp',
'types/func/invocation/beagerfunc.cpp',
'types/func/invocation/bfunc.cpp',
'types/func/invocation/bintrinsic.cpp',
'types/func/invocation/common.cpp',
'types/func/invocation/func.cpp',
'types/func/invocation/ghostfunc.cpp',
'types/func/invocation/intrinsic.cpp',
'types/template/tvec.cpp',
'types/template/tvar.cpp',
'types/template/ttvar.cpp',
'types/template/tdecl.cpp',
'types/template/tnameddecl.cpp',
'types/template/tfunctype.cpp',
|
| ︙ | | |
Changes to bs/builtins/operators/arith.cpp.
| ︙ | | |
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
|
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
|
-
+
-
+
-
-
+
+
-
+
-
+
|
LeftAssInfixOp( "operator_add"_sid, precedence::AddSubOp,
BuildGenericTupleOperator(),
ForType< BigInt, Add >(),
ForType< CustomPattern< IntegerType, IntegerType::Pattern > >(
[]( auto&& c, auto&& lhs, auto&& rhs ) -> Value
{
return BuildComputedValue( lhs.type(),
Add( lhs, rhs ) );
lhs, rhs, Add( c.locationId() ) );
} )
)
);
BuildParseRule( e, "-"_sid,
PrefixOp( "operator_unary_minus"_sid, precedence::UnaryOps,
BuildGenericTupleOperator(),
ForType< BigInt >( []( auto&& c, auto&& operand ) -> Value
{
return BuildComputedValue( GetValueType< BigInt >(),
Sub( ToValue( BigInt() ), operand ) );
ToValue( BigInt() ), operand, Sub( c.locationId() ) );
} ),
ForType< CustomPattern< IntegerType, IntegerType::PatternSigned > >(
[]( auto&& c, auto&& operand ) -> Value
{
auto opTypeVal = *EIRToValue( operand.type() );
auto opType = *FromValue< IntegerType >( opTypeVal );
return BuildComputedValue( operand.type(),
Sub( Value( operand.type(), APSInt( opType.m_numBits, false ) ),
operand ) );
Value( operand.type(), APSInt( opType.m_numBits, false ) ),
operand, Sub( c.locationId() ) );
} )
),
LeftAssInfixOp( "operator_sub"_sid, precedence::AddSubOp,
BuildGenericTupleOperator(),
ForType< BigInt, Sub >(),
ForType< CustomPattern< IntegerType, IntegerType::Pattern > >(
[]( auto&& c, auto&& lhs, auto&& rhs ) -> Value
{
return BuildComputedValue( lhs.type(),
Sub( lhs, rhs ) );
lhs, rhs, Sub( c.locationId() ) );
} )
)
);
BuildParseRule( e, "*"_sid,
LeftAssInfixOp( "operator_multiply"_sid, precedence::MulDivOp,
BuildGenericTupleOperator(),
ForType< BigInt, Mul >(),
ForType< CustomPattern< IntegerType, IntegerType::Pattern > >(
[]( auto&& c, auto&& lhs, auto&& rhs ) -> Value
{
return BuildComputedValue( lhs.type(),
Mul( lhs, rhs ) );
lhs, rhs, Mul( c.locationId() ) );
} )
)
);
BuildParseRule( e, "/"_sid,
LeftAssInfixOp( "operator_divide"_sid, precedence::MulDivOp,
BuildGenericTupleOperator(),
|
| ︙ | | |
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
|
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
|
-
-
+
+
-
+
-
-
+
+
-
+
|
// to construct the assertion expression.
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 ) )
cfg->currentBB()->append(
move( cond ), cir::Assert( rhs.locationId() )
);
return BuildComputedValue( lhs.type(),
SDiv( lhs, rhs ) );
lhs, rhs, SDiv( c.locationId() ) );
} ),
ForType< CustomPattern< IntegerType, IntegerType::PatternUnsigned > >(
[]( auto&& c, auto&& lhs, auto&& rhs ) -> Value
{
using namespace goose::builtins::exprhelpers;
auto cfg = GetCFG( c );
assert( cfg );
// Build a zero constant of the same type as the denominator
// to construct the assertion expression.
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 ) )
cfg->currentBB()->append(
move( cond ), cir::Assert( rhs.locationId() )
);
return BuildComputedValue( lhs.type(),
UDiv( lhs, rhs ) );
lhs, rhs, UDiv( c.locationId() ) );
} )
)
);
BuildParseRule( e, "%"_sid,
LeftAssInfixOp( "operator_modulo"_sid, precedence::MulDivOp,
BuildGenericTupleOperator(),
|
| ︙ | | |
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
|
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
|
-
-
+
+
-
+
-
-
+
+
-
+
|
// to construct the assertion expression.
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 ) )
cfg->currentBB()->append(
move( cond ), cir::Assert( rhs.locationId() )
);
return BuildComputedValue( lhs.type(),
SRem( lhs, rhs ) );
lhs, rhs, SRem( c.locationId() ) );
} ),
ForType< CustomPattern< IntegerType, IntegerType::PatternUnsigned > >(
[]( auto&& c, auto&& lhs, auto&& rhs ) -> Value
{
using namespace goose::builtins::exprhelpers;
auto cfg = GetCFG( c );
assert( cfg );
// Build a zero constant of the same type as the denominator
// to construct the assertion expression.
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 ) )
cfg->currentBB()->append(
move( cond ), cir::Assert( rhs.locationId() )
);
return BuildComputedValue( lhs.type(),
URem( lhs, rhs ) );
lhs, rhs, URem( c.locationId() ) );
} )
)
);
}
}
|
Changes to bs/builtins/operators/assignment.cpp.
| ︙ | | |
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
-
+
|
auto cfg = GetCFG( c );
if( !cfg )
{
DiagnosticsManager::GetInstance().emitSyntaxErrorMessage( 0, "assignments are not allowed here." );
return PoisonValue();
}
else if( auto bb = cfg->currentBB() )
bb->emplace_back( Store( lhs.cir(), refType.type(), rhs, lhs.locationId() ) );
bb->append( lhs, rhs, Store( refType.type(), rhs.locationId(), lhs.locationId() ) );
// Return the ref to support chained assignments, like in c++.
return Value( lhs );
};
// Generic function to assign a value to a decl (local variable declaration)
auto DeclAssignment = []( auto&& c, auto&& lhs, auto&& rhs ) -> Value
|
| ︙ | | |
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
|
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
|
+
+
+
+
+
+
+
+
+
+
-
+
|
return PoisonValue();
return result;
};
auto RTTupleAssignment = [assOp]( auto&& c, auto&& lhs, auto&& rhs ) -> Value
{
auto cfg = GetCFG( c );
if( !cfg )
return PoisonValue();
auto tupSize = TupleSize( lhs );
auto tupRefType = *FromValue< ReferenceType >( *EIRToValue( rhs.type() ) );
auto rhsTupType = *EIRToValue( tupRefType.type() );
if( tupSize != TupleTypeSize( rhsTupType ) )
{
DiagnosticsManager::GetInstance().emitErrorMessage( 0, "incompatible tuple sizes." );
return PoisonValue();
}
// Store the source tuple as a temporary, otherwise we're going to recompute rhs
// for each member assigned (which is bad)
auto rhsIndex = cfg->getNewTemporaryIndex();
cfg->currentBB()->append( rhs, CreateTemporary( rhsIndex, rhs.locationId() ) );
auto srcTup = BuildComputedValue( rhs.type(), GetTemporary( rhs.type(), rhsIndex, rhs.locationId() ) );
// Load the values from the rhs tuple into temporary vars.
vector< Value > tempVars;
tempVars.reserve( tupSize );
uint32_t index = 0;
bool success = true;
ForEachInTupleType( rhsTupType, [&]( auto&& srcType )
{
auto rt = ValueToEIR( ToValue( ReferenceType( srcType, ConstAccessSpecifer() ) ) );
auto srcVal = BuildComputedValue( rt, Select( rhs.cir(), index++ ) );
auto srcVal = BuildComputedValue( rt, srcTup, Select( index++, ( c.locationId() ) ) );
// We go at very high level to construct the temporary variables by resolving an invocation
// of the assignment of the rhs value to a TNamedDecl with an empty name.
// The reason we need to work at such high level is so that the initializer value gets
// resolved exactly like if it was a regular assignment. In particular, if the value in question
// is a locvar, we want it to go through the type checking process to be replaced with its content.
// This is the simplest and most robust way to achieve this, which should honor every relevant
|
| ︙ | | |
Changes to bs/builtins/operators/comparison.cpp.
| ︙ | | |
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
|
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
|
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
|
ForType< BigInt, Eq, bool >(),
ForType< char32_t, Eq, bool >(),
ForType< string, Eq, bool >(),
ForType< CustomPattern< IntegerType, IntegerType::Pattern > >(
[]( auto&& c, auto&& lhs, auto&& rhs ) -> Value
{
return BuildComputedValue( GetValueType< bool >(),
Eq( lhs, rhs ) );
lhs, rhs, Eq( c.locationId() ) );
} )
)
);
BuildParseRule( e, "!="_sid,
LeftAssInfixOp( "operator_not_equals"_sid, precedence::EqualityOp,
ForType< bool, Neq, bool >(),
ForType< BigInt, Neq, bool >(),
ForType< char32_t, Neq, bool >(),
ForType< string, Neq, bool >(),
ForType< CustomPattern< IntegerType, IntegerType::Pattern > >(
[]( auto&& c, auto&& lhs, auto&& rhs ) -> Value
{
return BuildComputedValue( GetValueType< bool >(),
Neq( lhs, rhs ) );
lhs, rhs, Neq( c.locationId() ) );
} )
)
);
BuildParseRule( e, ">"_sid,
LeftAssInfixOp( "operator_greater"_sid, precedence::GreaterLesserOp,
ForType< BigInt, SGT, bool >(),
ForType< CustomPattern< IntegerType, IntegerType::PatternSigned > >(
[]( auto&& c, auto&& lhs, auto&& rhs ) -> Value
{
return BuildComputedValue( GetValueType< bool >(),
SGT( lhs, rhs ) );
lhs, rhs, SGT( c.locationId() ) );
} ),
ForType< CustomPattern< IntegerType, IntegerType::PatternUnsigned > >(
[]( auto&& c, auto&& lhs, auto&& rhs ) -> Value
{
return BuildComputedValue( GetValueType< bool >(),
UGT( lhs, rhs ) );
lhs, rhs, UGT( c.locationId() ) );
} )
)
);
BuildParseRule( e, ">="_sid,
LeftAssInfixOp( "operator_greater_or_equals"_sid, precedence::GreaterLesserOp,
ForType< BigInt, SGE, bool >(),
ForType< CustomPattern< IntegerType, IntegerType::PatternSigned > >(
[]( auto&& c, auto&& lhs, auto&& rhs ) -> Value
{
return BuildComputedValue( GetValueType< bool >(),
SGE( lhs, rhs ) );
lhs, rhs, SGE( c.locationId() ) );
} ),
ForType< CustomPattern< IntegerType, IntegerType::PatternUnsigned > >(
[]( auto&& c, auto&& lhs, auto&& rhs ) -> Value
{
return BuildComputedValue( GetValueType< bool >(),
UGE( lhs, rhs ) );
lhs, rhs, UGE( c.locationId() ) );
} )
)
);
BuildParseRule( e, "<"_sid,
LeftAssInfixOp( "operator_lesser"_sid, precedence::GreaterLesserOp,
ForType< BigInt, SLT, bool >(),
ForType< CustomPattern< IntegerType, IntegerType::PatternSigned > >(
[]( auto&& c, auto&& lhs, auto&& rhs ) -> Value
{
return BuildComputedValue( GetValueType< bool >(),
SLT( lhs, rhs ) );
lhs, rhs, SLT( c.locationId() ) );
} ),
ForType< CustomPattern< IntegerType, IntegerType::PatternUnsigned > >(
[]( auto&& c, auto&& lhs, auto&& rhs ) -> Value
{
return BuildComputedValue( GetValueType< bool >(),
ULT( lhs, rhs ) );
lhs, rhs, ULT( c.locationId() ) );
} )
)
);
BuildParseRule( e, "<="_sid,
LeftAssInfixOp( "operator_lesser_or_equals"_sid, precedence::GreaterLesserOp,
ForType< BigInt, SLE, bool >(),
ForType< CustomPattern< IntegerType, IntegerType::PatternSigned > >(
[]( auto&& c, auto&& lhs, auto&& rhs ) -> Value
{
return BuildComputedValue( GetValueType< bool >(),
SLE( lhs, rhs ) );
lhs, rhs, SLE( c.locationId() ) );
} ),
ForType< CustomPattern< IntegerType, IntegerType::PatternUnsigned > >(
[]( auto&& c, auto&& lhs, auto&& rhs ) -> Value
{
return BuildComputedValue( GetValueType< bool >(),
ULE( lhs, rhs ) );
lhs, rhs, ULE( c.locationId() ) );
} )
)
);
}
}
|
Changes to bs/builtins/operators/dot.cpp.
| ︙ | | |
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
-
-
+
|
if( index >= TupleTypeSize( tupType ) )
{
DiagnosticsManager::GetInstance().emitErrorMessage( rhs.locationId(),
"the index is out of range." );
return PoisonValue();
}
auto loc = Location::CreateSpanningLocation( lhs.locationId(), rhs.locationId() );
auto rt = ValueToEIR( ToValue( ReferenceType( GetTupleTypeElement( tupType, index ), refType.behavior() ) ) );
return BuildComputedValue( rt, Select( lhs.cir(), index ) ).setLocationId( loc );
return BuildComputedValue( rt, lhs, Select( index, c.locationId() ) );
} )
)
);
}
}
|
Changes to bs/builtins/operators/helpers.h.
| ︙ | | |
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
|
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
|
-
+
-
+
-
+
-
+
-
+
|
auto ForType()
{
return []< typename tag >( auto&& e, auto&& pOvlSet, tag t )
{
using intrinsicType = Intrinsic< Value ( T, T ) >;
auto intrinsicFunc = []( const Context& c, const Value& lhs, const Value& rhs )
{
return BuildComputedValue( GetValueType< RT >(), I( lhs, rhs ) );
return BuildComputedValue( GetValueType< RT >(), lhs, rhs, I( ( c.locationId() ) ) );
};
pOvlSet->add( e, ToValue< intrinsicType >( move( intrinsicFunc ) ), GetFuncInvocationRule() );
pOvlSet->add( e, ToValue< intrinsicType >( move( intrinsicFunc ) ), GetBuiltinIntrinsicFuncInvocationRule() );
};
}
template< typename T, typename F >
auto ForType( F&& func )
{
return [&]< typename tag >( auto&& e, auto&& pOvlSet, tag t )
{
if constexpr( is_same_v< tag, UnaryOpTag > )
{
using intrinsicType = Intrinsic< Value ( T ) >;
pOvlSet->add( e, ToValue< intrinsicType >( forward< F >( func ) ), GetFuncInvocationRule() );
pOvlSet->add( e, ToValue< intrinsicType >( forward< F >( func ) ), GetBuiltinIntrinsicFuncInvocationRule() );
}
else
{
using intrinsicType = Intrinsic< Value ( T, T ) >;
pOvlSet->add( e, ToValue< intrinsicType >( forward< F >( func ) ), GetFuncInvocationRule() );
pOvlSet->add( e, ToValue< intrinsicType >( forward< F >( func ) ), GetBuiltinIntrinsicFuncInvocationRule() );
}
};
}
template< typename T1, typename T2, typename F >
auto ForTypes( F&& func )
{
return [=]< typename tag >( auto&& e, auto&& pOvlSet, tag t )
{
using intrinsicType = Intrinsic< Value ( T1, T2 ) >;
pOvlSet->add( e, ToValue< intrinsicType >( func ), GetFuncInvocationRule() );
pOvlSet->add( e, ToValue< intrinsicType >( func ), GetBuiltinIntrinsicFuncInvocationRule() );
};
}
}
#endif
|
Changes to bs/builtins/operators/logic.cpp.
| ︙ | | |
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
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
|
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
|
-
+
-
-
-
+
+
+
-
-
+
-
+
-
+
-
+
-
+
|
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 ) );
operand, cir::Not( c.locationId() ) );
} )
)
);
BuildParseRule( e, "~"_sid,
PrefixOp( "operator_bitwise_not"_sid, precedence::UnaryOps,
BuildGenericTupleOperator(),
ForType< CustomPattern< IntegerType, IntegerType::Pattern > >( []( auto&& c, auto&& operand ) -> Value
{
auto opTypeVal = *EIRToValue( operand.type() );
auto opType = *FromValue< IntegerType >( opTypeVal );
return BuildComputedValue( operand.type(),
Xor( operand,
Value( operand.type(), APSInt::getMaxValue( opType.m_numBits, true ) )
) );
operand, Value( operand.type(), APSInt::getMaxValue( opType.m_numBits, true ) ),
Xor( c.locationId() )
);
} )
)
);
BuildParseRule( e, "^"_sid,
LeftAssInfixOp( "operator_xor"_sid, precedence::OrOp,
BuildGenericTupleOperator(),
// Logical xor
ForType< bool, Xor >(),
// ct_int xor
ForType< BigInt >(
[]( auto&& c, auto&& lhs, auto&& rhs ) -> Value
{
if( !lhs.isConstant() || !rhs.isConstant() )
{
auto loc = Location::CreateSpanningLocation( lhs.locationId(), rhs.locationId() );
DiagnosticsManager::GetInstance().emitSyntaxErrorMessage( loc, "bitwise operations between ct_int values are only allowed on constants." );
DiagnosticsManager::GetInstance().emitSyntaxErrorMessage( c.locationId(), "bitwise operations between ct_int values are only allowed on constants." );
return PoisonValue();
}
return BuildComputedValue( lhs.type(),
Xor( lhs, rhs ) );
lhs, rhs, Xor( c.locationId() ) );
} ),
// runtime integer xor, defined to work for any two integers of same
// bit size and signedness.
ForType< CustomPattern< IntegerType, IntegerType::Pattern > >(
[]( auto&& c, auto&& lhs, auto&& rhs ) -> Value
{
return BuildComputedValue( lhs.type(),
Xor( lhs, rhs ) );
lhs, rhs, Xor( c.locationId() ) );
} )
)
);
BuildParseRule( e, "|"_sid,
LeftAssInfixOp( "operator_or"_sid, precedence::OrOp,
BuildGenericTupleOperator(),
// ct_int or
ForType< BigInt >(
[]( auto&& c, auto&& lhs, auto&& rhs ) -> Value
{
if( !lhs.isConstant() || !rhs.isConstant() )
{
auto loc = Location::CreateSpanningLocation( lhs.locationId(), rhs.locationId() );
DiagnosticsManager::GetInstance().emitSyntaxErrorMessage( loc, "bitwise operations between ct_int values are only allowed on constants." );
return PoisonValue();
}
return BuildComputedValue( lhs.type(),
Or( lhs, rhs ) );
lhs, rhs, Or( c.locationId() ) );
} ),
// runtime integer or, defined to work for any two integers of same
// bit size and signedness.
ForType< CustomPattern< IntegerType, IntegerType::Pattern > >(
[]( auto&& c, auto&& lhs, auto&& rhs ) -> Value
{
return BuildComputedValue( lhs.type(),
Or( lhs, rhs ) );
lhs, rhs, Or( c.locationId() ) );
} ),
// bool or
ForType< bool >( [orOp]< typename L, typename R >( auto&& c, L&& lhs, R&& rhs ) -> Value
{
// Handle the case where lhs is constant, so that
// the result gets properly eagerly evaluated (in case
|
| ︙ | | |
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
|
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
|
-
+
+
-
+
-
+
-
+
-
+
-
+
-
+
-
-
+
-
+
-
+
|
} )
)
);
RegisterBuiltinFunc< Intrinsic< bool ( Value, bool, bool ) > >( e, orOp,
[]( auto&& c, auto&& b, auto&& lhs, auto&& rhs )
{
return BuildComputedValue( GetValueType< bool >(), Or( lhs, rhs ) );
return BuildComputedValue( GetValueType< bool >(), lhs, rhs, Or( c.locationId() ) );
} );
RegisterBuiltinFunc< Intrinsic< bool ( TypeWrapper< ptr< CodeBuilder > >, bool, bool ) > >( e, orOp,
[]( auto&& c, auto&& b, auto&& lhs, auto&& rhs )
{
auto cb = *FromValue< TypeWrapper< ptr< CodeBuilder > > >( b );
const auto& cfg = cb->cfg();
// Build the control flow for shortcut evaluation.
const auto& predBB = cfg->currentBB();
auto pRhsBB = cfg->createBB();
auto pSuccBB = cfg->createBB();
// If the lhs is true, skip to the end directly.
// Otherwise, jump to the BB that computes rhs.
predBB->append( lhs );
predBB->setTerminator( CondBranch( lhs, pSuccBB, pRhsBB ) );
predBB->setTerminator( CondBranch( pSuccBB, pRhsBB ) );
auto rhsIndex = cfg->getNewTemporaryIndex();
pRhsBB->emplace_back( CreateTemporary( rhsIndex, rhs ) );
pRhsBB->append( rhs, CreateTemporary( rhsIndex, c.locationId() ) );
pRhsBB->setTerminator( Branch( pSuccBB ) );
auto resultIndex = cfg->getNewTemporaryIndex();
// Build the Phi instruction that will collect the final result.
auto phi = Phi( *EIRToValue( GetValueType< bool >() ), 2,
resultIndex );
resultIndex, c.locationId() );
// If coming directly from the lhs BB, we know the result is true.
phi.setIncoming( predBB, ToValue( true ) );
// Otherwise, the result is whatever was computed by the rhs block.
phi.setIncoming( pRhsBB, BuildComputedValue( GetValueType< bool >(),
GetTemporary( GetValueType< bool >(), rhsIndex ) ) );
GetTemporary( GetValueType< bool >(), rhsIndex, c.locationId() ) ) );
pSuccBB->emplace_back( move( phi ) );
pSuccBB->append( move( phi ) );
cfg->setCurrentBB( pSuccBB );
// Build the result val which pulls the temporary created above.
return BuildComputedValue( GetValueType< bool >(),
GetTemporary( GetValueType< bool >(), resultIndex ) );
GetTemporary( GetValueType< bool >(), resultIndex, c.locationId() ) );
} );
BuildParseRule( e, "&"_sid,
LeftAssInfixOp( "operator_and"_sid, precedence::AndOp,
BuildGenericTupleOperator(),
// ct_int and
ForType< BigInt >(
[]( auto&& c, auto&& lhs, auto&& rhs ) -> Value
{
if( !lhs.isConstant() || !rhs.isConstant() )
{
auto loc = Location::CreateSpanningLocation( lhs.locationId(), rhs.locationId() );
DiagnosticsManager::GetInstance().emitSyntaxErrorMessage( loc, "bitwise operations between ct_int values are only allowed on constants." );
DiagnosticsManager::GetInstance().emitSyntaxErrorMessage( c.locationId(), "bitwise operations between ct_int values are only allowed on constants." );
return PoisonValue();
}
return BuildComputedValue( lhs.type(),
And( lhs, rhs ) );
lhs, rhs, And( c.locationId() ) );
} ),
// runtime integer and, defined to work for any two integers of same
// bit size and signedness.
ForType< CustomPattern< IntegerType, IntegerType::Pattern > >(
[]( auto&& c, auto&& lhs, auto&& rhs ) -> Value
{
return BuildComputedValue( lhs.type(),
And( lhs, rhs ) );
lhs, rhs, And( c.locationId() ) );
} ),
// bool and
ForType< bool >( [andOp]< typename L, typename R >( auto&& c, L&& lhs, R&& rhs ) -> Value
{
// Handle the case where lhs is constant, so that
// the result gets properly eagerly evaluated (in case
|
| ︙ | | |
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
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
|
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
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
|
-
+
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
-
+
+
-
+
-
-
+
-
+
|
} )
)
);
RegisterBuiltinFunc< Intrinsic< bool ( Value, bool, bool ) > >( e, andOp,
[]( auto&& c, auto&& b, auto&& lhs, auto&& rhs )
{
return BuildComputedValue( GetValueType< bool >(), And( lhs, rhs ) );
return BuildComputedValue( GetValueType< bool >(), lhs, rhs, And( c.locationId() ) );
} );
RegisterBuiltinFunc< Intrinsic< bool ( TypeWrapper< ptr< CodeBuilder > >, bool, bool ) > >( e, andOp,
[]( auto&& c, auto&& b, auto&& lhs, auto&& rhs )
{
auto cb = *FromValue< TypeWrapper< ptr< CodeBuilder > > >( b );
const auto& cfg = cb->cfg();
// Build the control flow for shortcut evaluation.
const auto& predBB = cfg->currentBB();
auto pRhsBB = cfg->createBB();
auto pSuccBB = cfg->createBB();
// If the lhs is false, skip to the end directly.
// Otherwise, jump to the BB that computes rhs.
predBB->append( lhs );
predBB->setTerminator( CondBranch( lhs, pRhsBB, pSuccBB ) );
predBB->setTerminator( CondBranch( pRhsBB, pSuccBB ) );
auto rhsIndex = cfg->getNewTemporaryIndex();
pRhsBB->emplace_back( CreateTemporary( rhsIndex, rhs ) );
pRhsBB->append( rhs, CreateTemporary( rhsIndex, c.locationId() ) );
pRhsBB->setTerminator( Branch( pSuccBB ) );
auto resultIndex = cfg->getNewTemporaryIndex();
// Build the Phi instruction that will collect the final result.
auto phi = Phi( *EIRToValue( GetValueType< bool >() ), 2,
resultIndex );
resultIndex, c.locationId() );
// If coming directly from the lhs BB, we know the result is false.
phi.setIncoming( predBB, ToValue( false ) );
// Otherwise, the result is whatever was computed by the rhs block.
phi.setIncoming( pRhsBB, BuildComputedValue( GetValueType< bool >(),
GetTemporary( GetValueType< bool >(), rhsIndex ) ) );
GetTemporary( GetValueType< bool >(), rhsIndex, c.locationId() ) ) );
pSuccBB->emplace_back( move( phi ) );
pSuccBB->append( move( phi ) );
cfg->setCurrentBB( pSuccBB );
// Build the result val which pulls the temporary created above.
return BuildComputedValue( GetValueType< bool >(),
GetTemporary( GetValueType< bool >(), resultIndex ) );
GetTemporary( GetValueType< bool >(), resultIndex, c.locationId() ) );
} );
BuildParseRule( e, "<<"_sid,
LeftAssInfixOp( "operator_shift_left"_sid, precedence::BitShiftOp,
BuildGenericTupleOperator(),
// ct_int left shift
ForTypes< BigInt, uint32_t >(
[]( auto&& c, auto&& lhs, auto&& rhs ) -> Value
{
if( !lhs.isConstant() || !rhs.isConstant() )
{
auto loc = Location::CreateSpanningLocation( lhs.locationId(), rhs.locationId() );
DiagnosticsManager::GetInstance().emitSyntaxErrorMessage( loc, "bitwise operations between ct_int values are only allowed on constants." );
return PoisonValue();
}
return BuildComputedValue( lhs.type(),
Shl( lhs, rhs ) );
lhs, rhs, Shl( c.locationId() ) );
} ),
// runtime integer left shift.
ForTypes< CustomPattern< IntegerType, IntegerType::Pattern >,
CustomPattern< IntegerType, IntegerType::PatternUnsigned > >(
[]( auto&& c, auto&& lhs, auto&& rhs ) -> Value
{
using namespace goose::builtins::exprhelpers;
auto cfg = GetCFG( c );
assert( cfg );
// Shifting for a number of bits equal or larger than the bitsize
// of lhs is an undefined behavior, so we require verification that
// it won't happen.
// Extract the integer type of lhs to retreieve its bit size.
// Extract the integer type of lhs to retrieve its bit size.
auto lhsType = *FromValue< IntegerType >( *EIRToValue( lhs.type() ) );
auto bitSizeValue = Value( rhs.type(), APSInt::get( lhsType.m_numBits) );
auto bitSizeValue = Value( rhs.type(), APSInt::get( lhsType.m_numBits ) );
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 ) )
cfg->currentBB()->append(
move( cond ), cir::Assert( rhs.locationId() )
);
return BuildComputedValue( lhs.type(),
Shl( lhs, rhs ) );
lhs, rhs, Shl( c.locationId() ) );
} )
)
);
BuildParseRule( e, ">>"_sid,
LeftAssInfixOp( "operator_shift_right"_sid, precedence::BitShiftOp,
BuildGenericTupleOperator(),
// ct_int right shift
ForTypes< BigInt, uint32_t >(
[]( auto&& c, auto&& lhs, auto&& rhs ) -> Value
{
if( !lhs.isConstant() || !rhs.isConstant() )
{
auto loc = Location::CreateSpanningLocation( lhs.locationId(), rhs.locationId() );
DiagnosticsManager::GetInstance().emitSyntaxErrorMessage( loc, "bitwise operations between ct_int values are only allowed on constants." );
DiagnosticsManager::GetInstance().emitSyntaxErrorMessage( c.locationId(), "bitwise operations between ct_int values are only allowed on constants." );
return PoisonValue();
}
return BuildComputedValue( lhs.type(),
AShr( lhs, rhs ) );
lhs, rhs, AShr( c.locationId() ) );
} ),
// runtime signed integer right shift, defined to work for any two integers of same
// bit size.
ForTypes< CustomPattern< IntegerType, IntegerType::PatternSigned >,
CustomPattern< IntegerType, IntegerType::PatternUnsigned > >(
[]( auto&& c, auto&& lhs, auto&& rhs ) -> Value
|
| ︙ | | |
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
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
412
|
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
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
|
-
-
+
+
-
+
-
+
-
-
+
+
-
+
|
auto bitSizeValue = Value( rhs.type(), APSInt::get( lhsType.m_numBits) );
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 ) )
cfg->currentBB()->append(
move( cond ), cir::Assert( rhs.locationId() )
);
return BuildComputedValue( lhs.type(),
AShr( lhs, rhs ) );
lhs, rhs, AShr( c.locationId() ) );
} ),
// runtime unsigned integer right shift, defined to work for any two integers of same
// bit size.
ForType< CustomPattern< IntegerType, IntegerType::PatternUnsigned > >(
[]( auto&& c, auto&& lhs, auto&& rhs ) -> Value
{
using namespace goose::builtins::exprhelpers;
auto cfg = GetCFG( c );
assert( cfg );
// Shifting for a number of bits equal or larger than the bitsize
// of lhs is an undefined behavior, so we require verification that
// it won't happen.
// Extract the integer type of lhs to retreieve its bit size.
auto lhsType = *FromValue< IntegerType >( *EIRToValue( lhs.type() ) );
auto bitSizeValue = Value( rhs.type(), APSInt::get( lhsType.m_numBits) );
auto bitSizeValue = Value( rhs.type(), APSInt::get( lhsType.m_numBits ) );
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 ) )
cfg->currentBB()->append(
move( cond ), cir::Assert( rhs.locationId() )
);
return BuildComputedValue( lhs.type(),
LShr( lhs, rhs ) );
lhs, rhs, LShr( c.locationId() ) );
} )
)
);
}
}
|
Changes to bs/builtins/operators/tuple.h.
| ︙ | | |
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
-
+
|
result = AppendToTuple( result, r );
return true;
} );
return result;
};
pOvlSet->add( e, ToValue< intrinsicType >( move( intrinsicFunc ) ), GetFuncInvocationRule() );
pOvlSet->add( e, ToValue< intrinsicType >( move( intrinsicFunc ) ), GetBuiltinIntrinsicFuncInvocationRule() );
}
else
{
using intrinsicType = Intrinsic< Value ( CustomPattern< Value, TuplePattern >, CustomPattern< Value, TuplePattern > ) >;
auto intrinsicFunc = [pOvlSet]( const Context& c, const Value& lhs, const Value& rhs )
{
if( TupleSize( lhs ) != TupleSize( rhs ) )
|
| ︙ | | |
54
55
56
57
58
59
60
61
62
63
64
65
66
67
|
54
55
56
57
58
59
60
61
62
63
64
65
66
67
|
-
+
|
result = AppendToTuple( result, r );
return true;
} );
return result;
};
pOvlSet->add( e, ToValue< intrinsicType >( move( intrinsicFunc ) ), GetFuncInvocationRule() );
pOvlSet->add( e, ToValue< intrinsicType >( move( intrinsicFunc ) ), GetBuiltinIntrinsicFuncInvocationRule() );
}
};
}
}
#endif
|
Changes to bs/builtins/statements/if.cpp.
| ︙ | | |
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
+
-
|
// 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 = cfg->createBB();
pPrecBB->append( get< Value >( converted ) );
pPrecBB->setTerminator( cir::CondBranch(
get< Value >( converted ),
pThenBB,
pElseBB ? pElseBB : pSuccBB ) );
if( pThenSuccBB && !pThenSuccBB->terminator() )
pThenSuccBB->setTerminator( cir::Branch( pSuccBB ) );
if( pElseSuccBB && !pElseSuccBB->terminator() )
|
| ︙ | | |
Changes to bs/builtins/statements/return.cpp.
| ︙ | | |
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
|
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
|
-
+
+
-
+
+
-
+
+
-
+
-
+
+
|
// Emit cleanups (destructor calls) for all currently live values in the function.
DestroyAllLiveValues( p.context() );
const auto& context = p.context();
if( context.returnType() == GetValueType< void >() )
{
cfg->emitTerminator( p.resolver()->currentLocation(), cir::Ret() );
cfg->emitTerminator( locationId, cir::RetVoid( locationId ) );
return true;
}
auto np = p.makeNestedParser();
if( !np.parseExpression( precedence::ReturnStmt + 1 ) )
{
dm.emitSyntaxErrorMessage( locationId, "expected an expression following the return statement.", 0 );
cfg->currentBB()->append( PoisonValue() );
cfg->emitTerminator( p.resolver()->currentLocation(), cir::Ret( PoisonValue() ) );
cfg->emitTerminator( locationId, cir::Ret( locationId ) );
return false;
}
auto retVal = np.popValue();
if( !retVal )
{
dm.emitSyntaxErrorMessage( locationId, "expected an expression following the return statement.", 0 );
cfg->currentBB()->append( PoisonValue() );
cfg->emitTerminator( p.resolver()->currentLocation(), cir::Ret( PoisonValue() ) );
cfg->emitTerminator( locationId, cir::Ret( locationId ) );
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.
cfg->currentBB()->append( PoisonValue() );
cfg->emitTerminator( p.resolver()->currentLocation(), cir::Ret( PoisonValue() ) );
cfg->emitTerminator( locationId, cir::Ret( locationId ) );
PoisonBuilder( p.context() );
return true;
}
cfg->emitTerminator( p.resolver()->currentLocation(), cir::Ret( get< Value >( converted ) ) );
cfg->currentBB()->append( get< Value >( converted ) );
cfg->emitTerminator( locationId, cir::Ret( locationId ) );
return true;
};
RegisterRule( e, "return"_sid, Rule( handleReturn ) );
}
}
|
Changes to bs/builtins/statements/while.cpp.
| ︙ | | |
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
|
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
|
+
-
|
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->append( get< Value >( converted ) );
pHeaderBB->setTerminator( cir::CondBranch(
get< Value >( converted ),
pBodyBB, pSuccBB ) );
cfg->setCurrentBB( pSuccBB );
return true;
};
RegisterRule( e, "while"_sid, Rule( handleWhile ) );
|
| ︙ | | |
Changes to bs/builtins/types/drop.cpp.
| ︙ | | |
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
-
-
-
-
+
-
+
|
// is appended to the current BB of the current parser.
RegisterBuiltinFunc< Intrinsic< void ( Value, Value ) > >( e, e.extDropValue(),
[]( const Context& c, const Value& b, const Value& v )
{
if( v.isConstant() )
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() ) )
if( !DoesInstrSeqHaveSideEffects( *v.cir() ) )
return;
auto cfg = GetCFG( c );
if( !cfg )
return;
auto bb = cfg->currentBB();
bb->emplace_back( move( *v.cir() ) );
bb->append( 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.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
-
+
|
#ifndef GOOSE_BUILTINS_TYPES_BFUNC_H
#define GOOSE_BUILTINS_TYPES_BFUNC_H
namespace goose::builtins
{
class FuncVerificationInfos;
using BuiltinFuncWrapper = function< Value ( const Term& argVec ) >;
template< typename F >
template< typename FT, typename F >
ptr< FuncVerificationInfos > RegisterBuiltinFunc( Env& env, StringId name, F&& func );
template< typename FT, typename F >
ptr< FuncVerificationInfos > RegisterBuiltinFunc( Env& env, ptr< OverloadSet > pOvlSet, F&& func );
extern bool IsBuiltinFunc( const Value& func );
extern bool IsEagerBuiltinFunc( const Value& func );
|
| ︙ | | |
Changes to bs/builtins/types/func/bfunc.inl.
| ︙ | | |
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
-
+
|
}
template< typename FT, typename F >
ptr< FuncVerificationInfos > RegisterBuiltinFunc( Env& env, ptr< OverloadSet > pOvlSet, F&& func )
{
auto fvi = make_shared< builtins::FuncVerificationInfos >( RootG0Identity() );
if( !pOvlSet->add( env, ToValue< FT >( forward< F >( func ), fvi ), GetFuncInvocationRule() ) )
if( !pOvlSet->add( env, ToValue< FT >( forward< F >( func ), fvi ), GetInvocationRule< FT >() ) )
G_ERROR( "duplicate overload registered for builtin func." );
return fvi;
}
}
namespace goose::eir
|
| ︙ | | |
Changes to bs/builtins/types/func/build.cpp.
| ︙ | | |
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
|
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
|
-
+
+
-
+
|
// Bind a stand-in value with the parameters name to be used inside of verification expressions.
auto paramVerificationIdentity = AppendToVectorTerm( verificationIdentity,
TERM( decl.name() ) );
c.env()->storeValue( paramVerificationIdentity, ANYTERM( _ ),
ValueToEIR( BuildComputedValue( decl.type(),
cir::Load( make_shared< cir::Instruction >( cir::VarAddr( varId++, decl.type() ) ), decl.type() ) ) ) );
cir::VarAddr( varId++, decl.type(), param.locationId() ),
cir::Load( decl.type(), param.locationId() ) ) ) );
}
else if( param.isConstant() )
tv->append( ValueToEIR( param ) );
return true;
} );
if( failed )
return nullopt;
// 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 = ValueToEIR( returnType );
if( rtTerm != GetValueType< void >() )
{
auto name = "@result"_sid;
auto retValVerificationIdentity = AppendToVectorTerm( verificationIdentity, TERM( name ) );
c.env()->storeValue( retValVerificationIdentity, ANYTERM( _ ),
ValueToEIR( BuildComputedValue( rtTerm, cir::Placeholder( rtTerm, name ) ) ) );
ValueToEIR( BuildComputedValue( rtTerm, cir::Placeholder( rtTerm, name, returnType.locationId() ) ) ) );
}
auto pVerifInfos = make_shared< FuncVerificationInfos >( move( verificationIdentity ) );
return FuncType( rtTerm, tv, move( pVerifInfos ) );
}
Func BuildExternalFunc( FuncType funcType, const string& symbol, bool varArg )
|
| ︙ | | |
Changes to bs/builtins/types/func/compile.cpp.
| ︙ | | |
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
|
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
|
-
+
|
// 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 );
cfg->emitTerminator( r->currentLocation(), cir::Ret() );
cfg->emitTerminator( r->currentLocation(), cir::RetVoid( r->currentLocation() ) );
}
pFuncCIR->body() = cfg;
verify::Func fv( localContext, f );
return fv.verify();
}
}
|
Changes to bs/builtins/types/func/func.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
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 "builtins/builtins.h"
#include "lex/lex.h"
#include "parse/parse.h"
#include "verify/verify.h"
using namespace goose::builtins;
using namespace goose::parse;
namespace goose::builtins
{
cir::InstrSeq BuildArgsInstrSeq( const Term& args )
{
cir::InstrSeq result;
ForEachInVectorTerm( args, [&]( auto&& arg )
{
cir::AppendToInstrSeq( result, *EIRToValue( arg ) );
return true;
} );
return result;
}
const Term& FuncPattern::GetPattern()
{
static auto pattern = ValueToEIR(
Value( TypeType(), VEC( TSID( func ), HOLE( "llvmType"_sid ),
HOLE( "_"_sid ), HOLE( "_"_sid ),
HOLE( "_"_sid ), HOLE( "_"_sid ) ) ) );
|
| ︙ | | |
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
|
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
|
-
+
-
+
+
-
+
+
-
+
-
+
+
|
Term GetFuncSig( const Value& func )
{
auto funcType = EIRToValue( func.type() );
assert( funcType );
return GetFuncSigFromType( *funcType );
}
Term GetFuncRType( const Value& func )
optional< Term > GetFuncRType( const Value& func )
{
auto funcType = EIRToValue( func.type() );
assert( funcType );
if( !funcType )
return nullopt;
auto typeDecomp = Decompose( funcType->val(),
Vec(
Lit( "func"_sid ),
SubTerm(), // kind
SubTerm(), // return type
SubTerm(), // param types
SubTerm(), // verif infos
SubTerm() // kind
SubTerm() // varArg
)
);
assert( typeDecomp );
if( !typeDecomp )
auto&& [kind, rtype, ptypes, vinf, varArg] = *typeDecomp;
return nullopt;
auto&& [kind, rtype, ptypes, vinf, varArg] = *typeDecomp;
return rtype;
}
const cir::Func* GetFuncCIR( const Value& f )
{
if( !f.isConstant() )
return nullptr;
|
| ︙ | | |
Changes to bs/builtins/types/func/func.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
|
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_BUILTINS_TYPES_FUNC_H
#define GOOSE_BUILTINS_TYPES_FUNC_H
namespace goose::builtins
{
extern ptr< InvocationRule >& GetFuncInvocationRule();
extern void SetupFunctionInvocationRule( Env& e );
extern void SetupFunctionTypeChecking( Env& e );
extern void SetupFunctionLowering( Env& e );
// Helper to provide generic param patterns for functions.
struct FuncPattern
{
static const Term& GetPattern();
};
extern Term GetFuncSig( const Value& func );
extern Term GetFuncRType( const Value& func );
extern optional< Term > GetFuncRType( const Value& func );
extern const cir::Func* GetFuncCIR( const Value& func );
template< typename F >
void ForEachDeclInTuple( const Value& tup, F&& func );
extern bool IsExternalFunc( const Value& f );
extern bool IsIntrinsicFunc( const Value& f );
|
| ︙ | | |
81
82
83
84
85
86
87
88
89
90
91
92
93
94
|
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
|
+
+
|
};
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 );
extern cir::InstrSeq BuildArgsInstrSeq( const Term& args );
}
namespace goose::eir
{
template<>
struct Bridge< builtins::Func >
{
|
| ︙ | | |
Changes to bs/builtins/types/func/functype.cpp.
| ︙ | | |
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
|
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
|
-
+
-
+
|
auto result = Decompose( t.val(),
Vec(
Lit( "func"_sid ),
Lit( "intrinsic"_sid ),
SubTerm(), // return type
SubTerm(), // param types
SubTerm(), // verif infos
SubTerm() // kind
SubTerm() // varArg
)
);
return !!result;
}
Term GetFuncSigFromType( const Value& funcType )
{
auto typeDecomp = Decompose( funcType.val(),
Vec(
Lit( "func"_sid ),
SubTerm(), // kind
SubTerm(), // return type
SubTerm(), // param types
SubTerm(), // verif infos
SubTerm() // kind
SubTerm() // varArg
)
);
assert( typeDecomp );
auto&& [kind, rtype, ptypes, vinf, varArg] = *typeDecomp;
return PrependToVectorTerm( *Unquote( ptypes ), rtype );
}
|
| ︙ | | |
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
|
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
+
-
+
+
|
bool failed = false;
ForEachInVectorTerms( ft.params(), unifiedArgs, [&]( auto&& p, auto&& a )
{
auto vp = ValuePatternFromEIR( p );
if( vp->val() == HOLE( "_"_sid ) )
{
auto arg = *EIRToValue( a );
auto convertedArg = InvokeOverloadSet( c, c.env()->extConvertFuncArg(),
MakeTuple( *EIRToValue( a ), *EIRToValue( vp->type() ) ) );
MakeTuple( arg, *EIRToValue( vp->type() ) ) );
if( convertedArg.isPoison() )
{
failed = true;
return false;
}
convertedArg.setLocationId( arg.locationId() );
av->append( ValueToEIR( convertedArg ) );
}
return true;
} );
if( failed )
|
| ︙ | | |
Added bs/builtins/types/func/invocation/beagerfunc.cpp.
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
|
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
|
#include "builtins/builtins.h"
#include "common.h"
using namespace goose::sema;
namespace goose::builtins
{
class BuiltinEagerFuncInvocationRule : public BaseFuncInvocationRule
{
public:
Value invoke( Context& c, LocationId loc, const Value& callee, const Term& args, const Term& typeCheckedCallPat, TypeCheckingContext& tcc ) const final
{
auto callDecomp = Decompose( typeCheckedCallPat,
Val< pvec >()
);
const auto& typeCheckedRType = callDecomp->get()->terms().front();
auto typeCheckedArgs = DropVectorTerm( typeCheckedCallPat, 1 );
auto argCount = VecSize( typeCheckedArgs );
auto argsInstrSeq = BuildArgsInstrSeq( typeCheckedArgs );
auto call = BuildComputedValue( typeCheckedRType, argsInstrSeq, callee,
cir::Call( argCount, loc ) );
if( !cir::CanValueBeEagerlyEvaluated( call ) )
return call;
execute::VM vm;
return execute::Evaluate( call, vm );
}
Value prepareFunc( const Context& c, LocationId funcValLocation, const Value& callee, const Term& typeCheckedCallPat, TypeCheckingContext& tcc ) const final
{
return callee;
}
};
const ptr< InvocationRule >& GetBuiltinEagerFuncInvocationRule()
{
static ptr< InvocationRule > pRule = make_shared< BuiltinEagerFuncInvocationRule >();
return pRule;
}
void SetupBuiltinEagerFuncInvocationRule( Env& e )
{
e.invocationRuleSet()->addRule(
ValueToEIR( ValuePattern( ANYTERM( _ ),
ValueToEIR( Value( TypeType(), VEC( TSID( func ),
TSID( builtin_eager ),
ANYTERM( _ ), ANYTERM( _ ),
ANYTERM( _ ), ANYTERM( _ ) ) ) ),
ANYTERM( _ ) ) ),
GetBuiltinEagerFuncInvocationRule() );
}
}
|
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
Added bs/builtins/types/func/invocation/bfunc.cpp.
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
|
#include "builtins/builtins.h"
#include "common.h"
using namespace goose::sema;
namespace goose::builtins
{
class BuiltinFuncInvocationRule : public BaseFuncInvocationRule
{
public:
Value invoke( Context& c, LocationId loc, const Value& callee, const Term& args, const Term& typeCheckedCallPat, TypeCheckingContext& tcc ) const final
{
auto callDecomp = Decompose( typeCheckedCallPat,
Val< pvec >()
);
const auto& typeCheckedRType = callDecomp->get()->terms().front();
auto typeCheckedArgs = DropVectorTerm( typeCheckedCallPat, 1 );
auto argCount = VecSize( typeCheckedArgs );
auto argsInstrSeq = BuildArgsInstrSeq( typeCheckedArgs );
return BuildComputedValue( typeCheckedRType, argsInstrSeq, callee, cir::Call( argCount, loc ) );
}
Value prepareFunc( const Context& c, LocationId funcValLocation, const Value& callee, const Term& typeCheckedCallPat, TypeCheckingContext& tcc ) const final
{
return callee;
}
};
const ptr< InvocationRule >& GetBuiltinFuncInvocationRule()
{
static ptr< InvocationRule > pRule = make_shared< BuiltinFuncInvocationRule >();
return pRule;
}
void SetupBuiltinFuncInvocationRule( Env& e )
{
e.invocationRuleSet()->addRule(
ValueToEIR( ValuePattern( ANYTERM( _ ),
ValueToEIR( Value( TypeType(), VEC( TSID( func ),
TSID( builtin ),
ANYTERM( _ ), ANYTERM( _ ),
ANYTERM( _ ), ANYTERM( _ ) ) ) ),
ANYTERM( _ ) ) ),
GetBuiltinFuncInvocationRule() );
}
}
|
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
Added bs/builtins/types/func/invocation/bintrinsic.cpp.
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
|
#include "builtins/builtins.h"
#include "common.h"
using namespace goose::sema;
namespace goose::builtins
{
class BuiltinIntrinsicFuncInvocationRule : public BaseFuncInvocationRule
{
public:
Value invoke( Context& c, LocationId loc, const Value& callee, const Term& args, const Term& typeCheckedCallPat, TypeCheckingContext& tcc ) const final
{
auto typeCheckedArgs = DropVectorTerm( typeCheckedCallPat, 1 );
return GetBuiltinIntrinsicFuncWrapper( callee )( c, move( typeCheckedArgs ) );
}
Value prepareFunc( const Context& c, LocationId funcValLocation, const Value& callee, const Term& typeCheckedCallPat, TypeCheckingContext& tcc ) const final
{
return callee;
}
};
const ptr< InvocationRule >& GetBuiltinIntrinsicFuncInvocationRule()
{
static ptr< InvocationRule > pRule = make_shared< BuiltinIntrinsicFuncInvocationRule >();
return pRule;
}
void SetupBuiltinIntrinsicFuncInvocationRule( Env& e )
{
e.invocationRuleSet()->addRule(
ValueToEIR( ValuePattern( ANYTERM( _ ),
ValueToEIR( Value( TypeType(), VEC( TSID( func ),
TSID( intrinsic_builtin ),
ANYTERM( _ ), ANYTERM( _ ),
ANYTERM( _ ), ANYTERM( _ ) ) ) ),
ANYTERM( _ ) ) ),
GetBuiltinIntrinsicFuncInvocationRule() );
}
}
|
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
Added bs/builtins/types/func/invocation/common.cpp.
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
|
#include "builtins/builtins.h"
#include "common.h"
using namespace goose::sema;
namespace goose::builtins
{
Value BaseFuncInvocationRule::resolveInvocation( Context& c, LocationId loc, const Value& callee, const Term& args ) const
{
optional< TypeCheckingContext > bestTCC;
optional< Term > bestSol;
auto sig = GetFuncSig( callee );
auto callPat = PrependToVectorTerm( args, HOLE( "_"_sid ) );
auto us = FindBestTyping( sig, callPat, c );
if( holds_alternative< NoUnification >( us ) )
{
// TODO display details
DiagnosticsManager::GetInstance().emitErrorMessage( loc,
"function arguments mismatch." );
return PoisonValue();
}
if( holds_alternative< AmbiguousTypeCheck >( us ) )
{
// TODO display details
DiagnosticsManager::GetInstance().emitErrorMessage( loc,
"ambiguous function call." );
return PoisonValue();
}
auto&& [s,tcc] = get< TCSol >( us );
return invoke( c, loc, callee, args, s, tcc );
}
optional< Term > BaseFuncInvocationRule::getSignature( const Value& callee ) const
{
return GetFuncSig( callee );
}
}
|
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
Added bs/builtins/types/func/invocation/common.h.
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
+
+
+
+
+
+
+
+
+
+
+
+
+
+
|
#ifndef GOOSE_BUILTINS_TYPES_FUNC_INVOCATION_COMMON_H
#define GOOSE_BUILTINS_TYPES_FUNC_INVOCATION_COMMON_H
namespace goose::builtins
{
class BaseFuncInvocationRule : public InvocationRule
{
public:
Value resolveInvocation( Context& c, LocationId loc, const Value& callee, const Term& args ) const final;
optional< Term > getSignature( const Value& callee ) const final;
};
}
#endif
|
| | | | | | | | | | | | |
Added bs/builtins/types/func/invocation/func.cpp.
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
|
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
|
#include "builtins/builtins.h"
#include "common.h"
using namespace goose::sema;
namespace goose::builtins
{
class FuncInvocationRule : public BaseFuncInvocationRule
{
public:
Value invoke( Context& c, LocationId loc, const Value& callee, const Term& args, const Term& typeCheckedCallPat, TypeCheckingContext& tcc ) const final
{
auto preparedCallee = prepareFunc( c, 0, callee, typeCheckedCallPat, tcc );
if( preparedCallee.isPoison() )
return PoisonValue();
auto callDecomp = Decompose( typeCheckedCallPat,
Val< pvec >()
);
const auto& typeCheckedRType = callDecomp->get()->terms().front();
auto typeCheckedArgs = DropVectorTerm( typeCheckedCallPat, 1 );
preparedCallee.setLocationId( loc );
auto ft = *FromValue< FuncType >( *EIRToValue( preparedCallee.type() ) );
auto argList = BuildArgListForCall( c, ft, typeCheckedArgs );
if( !argList )
return PoisonValue();
auto argsInstrSeq = BuildArgsInstrSeq( *argList );
auto argCount = VecSize( *argList );
auto result = BuildComputedValue( typeCheckedRType, argsInstrSeq, preparedCallee,
cir::Call( argCount, loc ) );
if( result.type() != GetValueType< void >() && !IsExternalFunc( callee ) )
{
if( cir::CanValueBeEagerlyEvaluated( result ) )
{
if( !verify::VerifyInstrSeq( c, *result.cir() ) )
return PoisonValue();
execute::VM vm;
result = execute::Evaluate( result, vm );
}
// Register the result for destruction.
if( auto cfg = GetCFG( c ) )
DeclareValue( c, result, cfg->getNewTemporaryIndex() );
}
return result;
}
Value prepareFunc( const Context& c, LocationId funcValLocation, const Value& callee, const Term& typeCheckedCallPat, TypeCheckingContext& tcc ) const final
{
// TODO better description with the function's name if possible (we may need to explicitely store it in the func)
DiagnosticsContext dc( 0, true );
VerbosityContext vc( Verbosity::Normal, true );
return CompileFunc( c, callee );
}
};
void SetupFuncInvocationRule( Env& e )
{
e.invocationRuleSet()->addRule(
ValueToEIR( ValuePattern( ANYTERM( _ ),
ValueToEIR( Value( TypeType(), VEC( TSID( func ),
ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ),
ANYTERM( _ ), ANYTERM( _ ) ) ) ),
ANYTERM( _ ) ) ),
make_shared< FuncInvocationRule >() );
}
}
|
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
Added bs/builtins/types/func/invocation/ghostfunc.cpp.
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
|
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
|
#include "builtins/builtins.h"
#include "common.h"
using namespace goose::sema;
namespace goose::builtins
{
class GhostFuncInvocationRule : public BaseFuncInvocationRule
{
public:
Value invoke( Context& c, LocationId loc, const Value& callee, const Term& args, const Term& typeCheckedCallPat, TypeCheckingContext& tcc ) const final
{
if( !CanInvokeGhostFuncs( c ) )
{
DiagnosticsManager::GetInstance().emitErrorMessage( loc,
"ghost functions can't be called in this context." );
return PoisonValue();
}
auto callDecomp = Decompose( typeCheckedCallPat,
Val< pvec >()
);
const auto& typeCheckedRType = callDecomp->get()->terms().front();
auto typeCheckedArgs = DropVectorTerm( typeCheckedCallPat, 1 );
auto argCount = VecSize( typeCheckedArgs );
auto ft = *FromValue< FuncType >( *EIRToValue( callee.type() ) );
auto argList = BuildArgListForCall( c, ft, typeCheckedArgs );
if( !argList )
return PoisonValue();
auto argsInstrSeq = BuildArgsInstrSeq( *argList );
// A ghost call is a mutable reference to a ghost closure, using the special "GhostCall"
// as the instruction to compute its "address"
auto rt = ValueToEIR( ToValue( ReferenceType{ typeCheckedRType, MutAccessSpecifer() } ) );
return BuildComputedValue( rt, argsInstrSeq, callee, cir::GhostCall( argCount, loc ) );
}
Value prepareFunc( const Context& c, LocationId funcValLocation, const Value& callee, const Term& typeCheckedCallPat, TypeCheckingContext& tcc ) const final
{
return callee;
}
};
void SetupGhostFuncInvocationRule( Env& e )
{
e.invocationRuleSet()->addRule(
ValueToEIR( ValuePattern( ANYTERM( _ ),
ValueToEIR( Value( TypeType(), VEC( TSID( func ),
ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ),
ANYTERM( _ ),
TERM( static_cast< uint64_t >( FuncType::Kind::Ghost ) ) ) ) ),
ANYTERM( _ ) ) ),
make_shared< GhostFuncInvocationRule >() );
}
}
|
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
Added bs/builtins/types/func/invocation/intrinsic.cpp.
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
|
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
|
#include "builtins/builtins.h"
#include "common.h"
using namespace goose::sema;
namespace goose::builtins
{
class IntrinsicFuncInvocationRule : public BaseFuncInvocationRule
{
public:
Value invoke( Context& c, LocationId loc, const Value& callee, const Term& args, const Term& typeCheckedCallPat, TypeCheckingContext& tcc ) const final
{
auto preparedCallee = prepareFunc( c, 0, callee, typeCheckedCallPat, tcc );
if( preparedCallee.isPoison() )
return PoisonValue();
auto typeCheckedArgs = DropVectorTerm( typeCheckedCallPat, 1 );
preparedCallee.setLocationId( loc );
auto ft = *FromValue< FuncType >( *EIRToValue( preparedCallee.type() ) );
// Intrinsic call: we insert the context wrapper as first param,
// wrap all args with TypeWrapper< Value >, and execute the function directly.
auto argList = BuildArgListForIntrinsicCall( c, ft, typeCheckedArgs );
if( !argList )
return PoisonValue();
auto argsInstrSeq = BuildArgsInstrSeq( *argList );
auto argCount = VecSize( *argList );
execute::VM vm;
cir::InstrSeq is;
AppendToInstrSeq( is, argsInstrSeq, preparedCallee, cir::Call( argCount, loc ) );
if( !vm.execute( is ) )
return PoisonValue();
if( ft.returnType() == GetValueType< void >() )
return Value( GetValueType< void >(), 0U );
auto result = vm.pop();
if( !result )
return PoisonValue();
// Unwrap the returned value
auto unwrapped = FromValue< TypeWrapper< Value > >( *result );
return unwrapped ? *unwrapped : PoisonValue();
}
Value prepareFunc( const Context& c, LocationId funcValLocation, const Value& callee, const Term& typeCheckedCallPat, TypeCheckingContext& tcc ) const final
{
// TODO better description with the function's name if possible (we may need to explicitely store it in the func)
DiagnosticsContext dc( 0, true );
VerbosityContext vc( Verbosity::Normal, true );
return CompileFunc( c, callee );
}
};
void SetupIntrinsicFuncInvocationRule( Env& e )
{
e.invocationRuleSet()->addRule(
ValueToEIR( ValuePattern( ANYTERM( _ ),
ValueToEIR( Value( TypeType(), VEC( TSID( func ),
ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ),
ANYTERM( _ ),
TERM( static_cast< uint64_t >( FuncType::Kind::Intrinsic ) ) ) ) ),
ANYTERM( _ ) ) ),
make_shared< IntrinsicFuncInvocationRule >() );
}
}
|
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
Added bs/builtins/types/func/invocation/invocation.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
|
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
|
#ifndef GOOSE_BUILTINS_TYPES_FUNC_INVOCATION_H
#define GOOSE_BUILTINS_TYPES_FUNC_INVOCATION_H
namespace goose::builtins
{
extern void SetupBuiltinEagerFuncInvocationRule( Env& e );
extern void SetupBuiltinFuncInvocationRule( Env& e );
extern void SetupBuiltinIntrinsicFuncInvocationRule( Env& e );
extern void SetupFuncInvocationRule( Env& e );
extern void SetupGhostFuncInvocationRule( Env& e );
extern void SetupIntrinsicFuncInvocationRule( Env& e );
extern const ptr< InvocationRule >& GetBuiltinFuncInvocationRule();
extern const ptr< InvocationRule >& GetBuiltinEagerFuncInvocationRule();
extern const ptr< InvocationRule >& GetBuiltinIntrinsicFuncInvocationRule();
template< typename F >
struct InvocationRuleSelector
{
static const auto& Get() { return GetBuiltinFuncInvocationRule(); }
};
template< typename R, typename... T >
struct InvocationRuleSelector< Eager< R >( T... ) >
{
static const auto& Get() { return GetBuiltinEagerFuncInvocationRule(); }
};
template< typename F >
struct InvocationRuleSelector< Intrinsic< F > >
{
static const auto& Get() { return GetBuiltinIntrinsicFuncInvocationRule(); }
};
template< typename F >
const ptr< InvocationRule >& GetInvocationRule()
{
return InvocationRuleSelector< F >::Get();
}
static inline void SetupFuncInvocationRules( Env& e )
{
SetupBuiltinEagerFuncInvocationRule( e );
SetupBuiltinFuncInvocationRule( e );
SetupBuiltinIntrinsicFuncInvocationRule( e );
SetupFuncInvocationRule( e );
SetupGhostFuncInvocationRule( e );
SetupIntrinsicFuncInvocationRule( e );
}
}
#endif
|
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
Deleted bs/builtins/types/func/invoke.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
|
|
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
|
#include "builtins/builtins.h"
using namespace goose::sema;
namespace goose::builtins
{
class FunctionInvocationRule : public InvocationRule
{
public:
Value resolveInvocation( Context& c, LocationId loc, const Value& callee, const Term& args ) const final
{
optional< TypeCheckingContext > bestTCC;
optional< Term > bestSol;
auto sig = GetFuncSig( callee );
auto callPat = PrependToVectorTerm( args, HOLE( "_"_sid ) );
auto us = FindBestTyping( sig, callPat, c );
if( holds_alternative< NoUnification >( us ) )
{
// TODO display details
DiagnosticsManager::GetInstance().emitErrorMessage( loc,
"function arguments mismatch." );
return PoisonValue();
}
if( holds_alternative< AmbiguousTypeCheck >( us ) )
{
// TODO display details
DiagnosticsManager::GetInstance().emitErrorMessage( loc,
"ambiguous function call." );
return PoisonValue();
}
auto&& [s,tcc] = get< TCSol >( us );
return invoke( c, loc, callee, args, s, tcc );
}
Value invoke( Context& c, LocationId loc, const Value& callee, const Term& args, const Term& typeCheckedCallPat, TypeCheckingContext& tcc ) const final
{
auto preparedCallee = prepareFunc( c, 0, callee, typeCheckedCallPat, tcc );
if( preparedCallee.isPoison() )
return PoisonValue();
auto callDecomp = Decompose( typeCheckedCallPat,
Val< pvec >()
);
const auto& typeCheckedRType = callDecomp->get()->terms().front();
auto typeCheckedArgs = DropVectorTerm( typeCheckedCallPat, 1 );
preparedCallee.setLocationId( loc );
if( IsBuiltinFunc( preparedCallee ) )
return BuildComputedValue( typeCheckedRType, cir::Call( preparedCallee, move( typeCheckedArgs ) ) );
if( IsBuiltinIntrinsicFunc( preparedCallee ) )
return GetBuiltinIntrinsicFuncWrapper( preparedCallee )( c, move( typeCheckedArgs ) );
auto ft = *FromValue< FuncType >( *EIRToValue( preparedCallee.type() ) );
if( ft.kind() == FuncType::Kind::Intrinsic )
{
// Intrinsic call: we insert the context wrapper as first param,
// wrap all args with TypeWrapper< Value >, and execute the function directly.
auto argList = BuildArgListForIntrinsicCall( c, ft, typeCheckedArgs );
if( !argList )
return PoisonValue();
execute::VM vm;
auto result = vm.execute( cir::Call( preparedCallee, move( *argList ) ) );
if( ft.returnType() == GetValueType< void >() )
return Value( GetValueType< void >(), 0U );
if( !result )
return PoisonValue();
// Unwrap the returned value
auto unwrapped = FromValue< TypeWrapper< Value > >( *result );
return unwrapped ? *unwrapped : PoisonValue();
}
auto argList = BuildArgListForCall( c, ft, typeCheckedArgs );
if( !argList )
return PoisonValue();
if( ft.kind() == FuncType::Kind::Ghost )
{
if( !CanInvokeGhostFuncs( c ) )
{
DiagnosticsManager::GetInstance().emitErrorMessage( loc,
"ghost functions can't be called in this context." );
return PoisonValue();
}
// A ghost call is a mutable reference to a ghost closure, using the special "GhostCall"
// as the instruction to compute its "address"
auto rt = ValueToEIR( ToValue( ReferenceType{ typeCheckedRType, MutAccessSpecifer() } ) );
return BuildComputedValue( rt, cir::GhostCall( preparedCallee, move( *argList ) ) );
}
else
{
auto result = BuildComputedValue( typeCheckedRType, cir::Call( preparedCallee, move( *argList ) ) );
// If the result is non-void, register it for destruction.
if( result.type() != GetValueType< void >() )
{
if( auto cfg = GetCFG( c ) )
DeclareValue( c, result, cfg->getNewTemporaryIndex() );
}
return result;
}
}
optional< Term > getSignature( const Value& callee ) const final
{
return GetFuncSig( callee );
}
Value prepareFunc( const Context& c, LocationId funcValLocation, const Value& callee, const Term& typeCheckedCallPat, TypeCheckingContext& tcc ) const final
{
if( IsBuiltinFunc( callee ) || IsBuiltinIntrinsicFunc( callee ) || IsGhostFunc( callee ) )
return callee;
// TODO better description with the function's name if possible (we may need to explicitely store it in the func)
DiagnosticsContext dc( 0, true );
VerbosityContext vc( Verbosity::Normal, true );
return CompileFunc( c, callee );
}
};
ptr< InvocationRule >& GetFuncInvocationRule()
{
static ptr< InvocationRule > pRule = make_shared< FunctionInvocationRule >();
return pRule;
}
void SetupFunctionInvocationRule( Env& e )
{
e.invocationRuleSet()->addRule(
ValueToEIR( ValuePattern( ANYTERM( _ ),
ValueToEIR( Value( TypeType(), VEC( TSID( func ),
ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ),
ANYTERM( _ ), ANYTERM( _ ) ) ) ),
ANYTERM( _ ) ) ),
GetFuncInvocationRule() );
}
}
|
Changes to bs/builtins/types/ghostcode/drop.cpp.
| ︙ | | |
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
-
-
+
+
|
{
// When a boolean is dropped into a ghost code block, it is appended as an assertion check.
RegisterBuiltinFunc< Intrinsic< void ( TypeWrapper< ptr< GhostCode > >, bool ) > >( e, e.extDropValue(),
[]( const Context& c, const Value& gcv, const Value& b )
{
auto gc = *FromValue< TypeWrapper< ptr< GhostCode > > >( gcv );
gc->cfg()->currentBB()->emplace_back(
cir::Assert( b )
gc->cfg()->currentBB()->append(
b, cir::Assert( b.locationId() )
);
} );
// When a ghost code block is dropped into a code builder, we append it using a GhostBranch terminator.
RegisterBuiltinFunc< Intrinsic< void ( TypeWrapper< ptr< CodeBuilder > >, TypeWrapper< ptr< GhostCode > > ) > >( e, e.extDropValue(),
[]( const Context& c, const Value& cbv, const Value& gcv )
{
|
| ︙ | | |
Changes to bs/builtins/types/init.cpp.
| ︙ | | |
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
|
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
|
-
+
-
+
-
+
|
// binary runtime code.
RegisterBuiltinFunc< Intrinsic< Value ( MutRefOfTypeT, ValueOfTypeT ) > >( e, e.extInitialize(),
[]( auto&& c, const Value& r, const Value& initVal )
{
G_VAL_ASSERT( r, !r.isConstant() );
auto refType = *FromValue< ReferenceType >( *EIRToValue( r.type() ) );
return BuildComputedValue( GetValueType< void >(),
Store( r.cir(), refType.type(), initVal, r.locationId() ) );
r, initVal, Store( refType.type(), initVal.locationId(), r.locationId() ) );
} );
// Default initialization for ct_int vars
RegisterBuiltinFunc< Intrinsic< Value ( CTIntMutRefType ) > >( e, e.extInitialize(),
[]( auto&& c, const Value& r )
{
G_VAL_ASSERT( r, !r.isConstant() );
auto refType = *FromValue< ReferenceType >( *EIRToValue( r.type() ) );
return BuildComputedValue( GetValueType< void >(),
Store( r.cir(), refType.type(), ToValue( BigInt() ), r.locationId() ) );
r, ToValue( BigInt() ), Store( refType.type(), {}, r.locationId() ) );
} );
// Default initialization for ct_string vars
RegisterBuiltinFunc< Intrinsic< Value ( CTStringMutRefType ) > >( e, e.extInitialize(),
[]( auto&& c, const Value& r )
{
G_VAL_ASSERT( r, !r.isConstant() );
auto refType = *FromValue< ReferenceType >( *EIRToValue( r.type() ) );
return BuildComputedValue( GetValueType< void >(),
Store( r.cir(), refType.type(), ToValue( ""s ), r.locationId() ) );
r, ToValue( ""s ), Store( refType.type(), {}, r.locationId() ) );
} );
}
}
|
Changes to bs/builtins/types/localvar/invoke.cpp.
| ︙ | | |
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
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
|
-
+
+
-
+
+
|
{
public:
bool canBeInvoked( const Context& c, const Value& callee ) const final
{
auto lv = *FromValue< LocalVar >( callee );
auto val = BuildComputedValue( lv.type(),
cir::Load( GetAddrFromLocalVar( lv ), lv.type() ) );
GetAddrFromLocalVar( lv ),
cir::Load( lv.type(), {} ) );
return sema::CanBeInvoked( c, val );
}
Value resolveInvocation( Context& c, LocationId locationId, const Value& callee, const Term& args ) const final
{
auto lv = *FromValue< LocalVar >( callee );
auto val = BuildComputedValue( lv.type(),
cir::Load( GetAddrFromLocalVar( lv ), lv.type() ) );
GetAddrFromLocalVar( lv ),
cir::Load( lv.type(), locationId ) );
return sema::GetInvocationRule( *c.env(), val )->resolveInvocation( c, locationId, val, args );
}
};
void SetupLocalVarInvocationRule( Env& e )
{
|
| ︙ | | |
Changes to bs/builtins/types/localvar/localvar.cpp.
| ︙ | | |
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
-
+
|
if( !typeVal.isType() )
typeVal = ToType( c, typeVal );
if( !ParseTypePredicates( c, typeVal ) )
return PoisonValue();
LocalVar lv( name, ValueToEIR( typeVal ), index );
bb->emplace_back( AllocVar( typeVal, index ) );
bb->append( AllocVar( typeVal, index, locId ) );
Value initResult;
{
DiagnosticsContext dc( 0, "When invoking Initialize." );
if( initializer )
|
| ︙ | | |
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
|
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
|
-
+
|
// Retrieve the texpr's location and set it on the inferred type. This way if an
// error occurs later with it, for instance when calling LowerTypeForRuntime on it during codegen,
// it will have a meaningful location for the error message to attach itself on.
auto typeLoc = EIRToValue( typeTExpr )->locationId();
LocalVar lv( name, type, index );
bb->emplace_back( AllocVar( EIRToValue( lv.type() )->setLocationId( typeLoc ), index ) );
bb->append( AllocVar( EIRToValue( lv.type() )->setLocationId( typeLoc ), index, locId ) );
DiagnosticsContext dc( 0, "When invoking Initialize." );
auto initResult = InvokeOverloadSet( c,
c.env()->extInitialize(),
MakeTuple( ToValue( lv ).setLocationId( locId ), initVal ) );
|
| ︙ | | |
Changes to bs/builtins/types/lower.cpp.
| ︙ | | |
17
18
19
20
21
22
23
24
25
26
27
|
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
+
+
+
+
+
+
+
+
|
} );
// Default implementation of LowerConstantForVerification():
// Do nothing.
RegisterBuiltinFunc< Intrinsic< Value ( Value ) > >( e, e.extLowerConstantForVerification(),
[]( const Context& c, const Value& v )
{
return v;
} );
// Default implementation of LowerConstantForRuntime():
// Do nothing.
RegisterBuiltinFunc< Intrinsic< Value ( Value ) > >( e, e.extLowerConstantForRuntime(),
[]( const Context& c, const Value& v )
{
return v;
} );
}
}
|
Changes to bs/builtins/types/pretty.cpp.
| ︙ | | |
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
|
+
-
+
+
+
+
+
|
{
auto v = *EIRToValue( t );
auto ty = EIRToValue( v.type() );
out << "value[ ";
pp.print( out, ty ? ty->val() : v.type() );
out << " ]";
if( v.cir() )
{
out << "{ " << *v.cir() << " }";
out << "{ ";
for( const auto& instr : *v.cir() )
out << instr << ' ';
out << "}";
}
return true;
} );
pp.addRule( ValueToEIR( ValuePattern( TSID( constant ),
ValueToEIR( Value( TypeType(), VEC( TSID( decl ), ANYTERM( _ ) ) ) ),
ANYTERM( _ ) ) ),
[&]( auto&& out, auto&& t )
|
| ︙ | | |
Changes to bs/builtins/types/propositions/propositions.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
-
+
|
#include "builtins/builtins.h"
namespace goose::builtins
{
size_t Propositions::hash() const
{
if( !m_hash )
{
auto g1 = goose::eir::ContainerHashGenerator( m_propositions );
auto g1 = ContainerHashGenerator( m_propositions );
m_hash = llvm::hash_combine_range( g1.begin(), g1.end() );
}
return *m_hash;
}
bool Propositions::parse( const Context& c )
{
|
| ︙ | | |
Changes to bs/builtins/types/reference/init.cpp.
| ︙ | | |
12
13
14
15
16
17
18
19
20
21
22
|
12
13
14
15
16
17
18
19
20
21
22
|
-
+
|
ReferenceType::PatternMutableOf< ReferenceType::PatternXOfTypeT > >,
CustomPattern< Value, ReferenceType::PatternXOfTypeT > ) > >( e, e.extInitialize(),
[]( auto&& c, const Value& r, const Value& initVal )
{
G_VAL_ASSERT( r, !r.isConstant() );
auto refType = *FromValue< ReferenceType >( *EIRToValue( r.type() ) );
return BuildComputedValue( GetValueType< void >(),
Store( r.cir(), refType.type(), initVal, r.locationId() ) );
r, initVal, Store( refType.type(), initVal.locationId(), r.locationId() ) );
} );
}
}
|
Changes to bs/builtins/types/reference/reference.cpp.
| ︙ | | |
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
|
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
|
-
+
+
-
+
+
-
+
|
const Term& ReferenceType::PatternXOfTypeT::GetPattern()
{
static auto pattern = ValueToEIR( ToValue( ReferenceType( HOLE( "T"_sid, TSID( ttvar ) ), HOLE( "X"_sid ) ) ) );
return pattern;
}
// Returns an instruction that computes the address of whatever's contained in the locvar.
ptr< cir::Instruction > GetAddrFromLocalVar( const LocalVar& lv )
cir::Instruction GetAddrFromLocalVar( const LocalVar& lv )
{
// TODO LOC: may need loc in LocalVar
return make_shared< cir::Instruction >( cir::VarAddr( lv.index(), lv.type() ) );
return cir::VarAddr( lv.index(), lv.type(), {} );
}
Value BuildLocalVarMutRef( const LocalVar& lv )
{
// TODO LOC: may need loc in LocalVar
auto rt = ValueToEIR( ToValue( ReferenceType{ lv.type(), MutAccessSpecifer() } ) );
return BuildComputedValue( move( rt ), cir::VarAddr( lv.index(), lv.type() ) );
return BuildComputedValue( move( rt ), cir::VarAddr( lv.index(), lv.type(), {} ) );
}
const Term& MutAccessSpecifer()
{
static auto al = ValueToEIR( ToValue( AccessSpecifier( "mut"_sid ) ) );
return al;
}
|
| ︙ | | |
Changes to bs/builtins/types/reference/reference.h.
| ︙ | | |
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
|
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
|
-
+
|
// Not an enum because we want to be able
// to have holes there and it's a pain in
// the ass
Term m_behavior;
};
extern ptr< cir::Instruction > GetAddrFromLocalVar( const LocalVar& lv );
extern cir::Instruction GetAddrFromLocalVar( const LocalVar& lv );
extern Value BuildLocalVarMutRef( const LocalVar& lv );
}
namespace goose::eir
{
template<>
struct Bridge< builtins::ReferenceType >
|
| ︙ | | |
Changes to bs/builtins/types/reference/typecheck.cpp.
| ︙ | | |
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
+
-
-
+
+
|
if( !refval )
co_return;
auto refType = FromValue< ReferenceType >( *EIRToValue( refval->type() ) );
if( !refType )
co_return;
auto loc = refval->locationId() ;
auto content = ValueToEIR( BuildComputedValue( refType->type(),
cir::Load( refval->cir(), refType->type() ) )
.setLocationId( refval->locationId() ) );
*refval, cir::Load( refType->type(), loc ) )
.setLocationId( loc ) );
// TypeCheck the param with the ref's content
co_yield TypeCheck( lhs, content, tcc );
}
TCGen TypeCheckingBuildTempRef( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc )
{
|
| ︙ | | |
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
|
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
|
+
-
-
+
+
|
auto rhsVal = *EIRToValue( rhs );
auto cfg = GetCFG( tcc.context() );
if( !cfg )
return nullopt;
// TODO create an ext point for this
auto loc = rhsVal.locationId();
auto tempIndex = cfg->getNewTemporaryIndex();
return ValueToEIR( BuildComputedValue( ValueToEIR( ToValue( rt ) ), TempAddr( tempIndex, rhsVal ) )
.setLocationId( rhsVal.locationId() ) );
return ValueToEIR( BuildComputedValue( ValueToEIR( ToValue( rt ) ), rhsVal,
TempAddr( tempIndex, loc ) ).setLocationId( loc ) );
} );
// Override the weight because we don't want
// this solution to count more than directly using
// the value without wrapping it into a tempref
SetWeight( wrapped, GetWeight( rhs ) - 1 );
co_yield { move( wrapped ), tcc };
|
| ︙ | | |
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
|
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
|
+
-
+
|
auto ltype = ValuePatternFromEIR( lhs )->type();
auto rrefVal = *EIRToValue( rhs );
auto rrType = FromValue< ReferenceType >( *EIRToValue( rrefVal.type() ) );
if( !rrType )
co_return;
auto loc = rrefVal.locationId();
auto content = ValueToEIR( BuildComputedValue( rrType->type(),
cir::Load( rrefVal.cir(), rrType->type() ) ).setLocationId( rrefVal.locationId() ) );
rrefVal, cir::Load( rrType->type(), loc ) ).setLocationId( loc ) );
co_yield TypeCheck( lhs, content, tcc );
} );
// Implicit referencing of non-variables against a non mutable ref: build a tempref
e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,
|
| ︙ | | |
Changes to bs/builtins/types/runtime/init.cpp.
| ︙ | | |
16
17
18
19
20
21
22
23
24
25
26
|
16
17
18
19
20
21
22
23
24
25
26
|
-
+
|
// Initialization for integer vars
RegisterBuiltinFunc< Intrinsic< Value ( IntegerMutRefType, IntegerType ) > >( e, e.extInitialize(),
[]( auto&& c, const Value& r, const Value& initVal )
{
G_VAL_ASSERT( r, !r.isConstant() );
auto refType = *FromValue< ReferenceType >( *EIRToValue( r.type() ) );
return BuildComputedValue( GetValueType< void >(),
Store( r.cir(), refType.type(), initVal, r.locationId() ) );
r, initVal, Store( refType.type(), initVal.locationId(), r.locationId() ) );
} );
}
}
|
Changes to bs/builtins/types/template/invoke.cpp.
| ︙ | | |
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
|
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
|
+
+
+
+
-
+
|
{
DiagnosticsContext dc( loc, loc.invalid() ? "" : "Called here.", false );
auto instanceFunc = InstantiateTFunc( c, callee, checkedCallPat, tcc );
if( instanceFunc.isPoison() )
return PoisonValue();
auto pIR = GetInvocationRule( *c.env(), instanceFunc );
G_VAL_ASSERT( callee, pIR );
G_VAL_ASSERT( callee, pIR->canBeInvoked( c, instanceFunc ) );
return GetFuncInvocationRule()->resolveInvocation( c, loc, instanceFunc, args );
return pIR->resolveInvocation( c, loc, instanceFunc, args );
}
optional< Term > getSignature( const Value& callee ) const final
{
auto tfuncVal = FromValue< TFunc >( callee );
assert( tfuncVal );
return tfuncVal->signature();
|
| ︙ | | |
Changes to bs/builtins/types/tuple/init.cpp.
| ︙ | | |
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
+
-
+
|
DiagnosticsManager::GetInstance().emitErrorMessage( 0, "Incompatible tuple sizes." );
return;
}
ForEachInTupleType( tupType, [&]( auto&& t )
{
auto elemType = *EIRToValue( t );
auto loc = elemType.locationId();
// Create a mutable reference to the element to initialize
ReferenceType rt( t, MutAccessSpecifer() );
auto elemRef = BuildComputedValue( ValueToEIR( ToValue( rt ) ),
Select( tupRef.cir(), index ) ).setLocationId( elemType.locationId() );
tupRef, Select( index, loc ) ).setLocationId( loc );
auto elemInit = *EIRToValue( GetTupleElement( initTup, index++ ) );
DiagnosticsContext dc( elemType.locationId(), "When invoking Initialize." );
auto init = InvokeOverloadSet( c, c.env()->extInitialize(),
MakeTuple( elemRef, move( elemInit ) ) );
|
| ︙ | | |
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
|
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
|
+
-
+
|
uint32_t index = 0;
auto tupType = *EIRToValue( refType.type() );
ForEachInTupleType( tupType, [&]( auto&& t )
{
auto elemType = *EIRToValue( t );
auto loc = elemType.locationId();
// Create a mutable reference to the element to initialize
ReferenceType rt( t, MutAccessSpecifer() );
auto elemRef = BuildComputedValue( ValueToEIR( ToValue( rt ) ),
Select( tupRef.cir(), index++ ) ).setLocationId( elemType.locationId() );
tupRef, Select( index++, loc ) ).setLocationId( loc );
DiagnosticsContext dc( elemType.locationId(), "When invoking Initialize." );
auto init = InvokeOverloadSet( c, c.env()->extInitialize(),
MakeTuple( elemRef ) );
DiagnosticsContext dc2( elemType.locationId(), "When invoking DropValue." );
InvokeOverloadSet( c, c.env()->extDropValue(),
|
| ︙ | | |
Changes to bs/builtins/types/tuple/typecheck.cpp.
| ︙ | | |
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
-
-
+
|
{
auto param = ParamPat( GetTupleTypeElement( tupType, index ) );
auto argType = GetTupleElementType( tupArg, index );
ReferenceType rt( argType, ConstAccessSpecifer() );
G_VAL_ASSERT( tupArgRef, !tupArgRef.isConstant() );
auto argAddr = cir::Select( tupArgRef.cir(), index );
auto argRef = ValueToEIR( BuildComputedValue( ValueToEIR( ToValue( rt ) ),
move( argAddr ) ) );
tupArgRef, cir::Select( index, tupArg.locationId() ) ) );
auto tupSize = TupleTypeSize( tupType );
for( auto&& [s,tcc] : TypeCheck( param, argRef, tcc ) )
{
auto val = ValuePatternFromEIR( s );
assert( val );
|
| ︙ | | |
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
|
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
|
-
+
|
auto tupType = *EIRToValue( ltup->type() );
assert( TupleTypeSize( tupType ) == TupleTypeSize( *EIRToValue( rtup->type() ) ) );
// TODO create an ext point for this instead of going directly thru cfg
auto tempIndex = cfg->getNewTemporaryIndex();
auto rtupref = BuildComputedValue( ValueToEIR( ToValue( ReferenceType{ rtup->type(), ConstAccessSpecifer() } ) ),
cir::TempAddr( tempIndex, *rtup ) );
*rtup, cir::TempAddr( tempIndex, rtup->locationId() ) );
co_yield TypeCheckComputedTuple( tcc, tupType, *rtup, rtupref, 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/types.cpp.
| ︙ | | |
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
-
+
|
SetupPredicatesTypeChecking( e );
SetupBasicTypes( e );
SetupBasicTypesPrettyPrinting();
SetupTupleTypeChecking( e );
SetupFunctionInvocationRule( e );
SetupFuncInvocationRules( e );
SetupFunctionTypeChecking( e );
SetupFunctionLowering( e );
SetupTemplateRules( e );
SetupTemplateFunctionInvocationRule( e );
SetupTemplateFunctionTypeChecking( e );
SetupTDeclTypeChecking( e );
|
| ︙ | | |
Changes to bs/builtins/types/types.h.
| ︙ | | |
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
+
|
#include "ghostcode/ghostcode.h"
#include "func/bfunc.h"
#include "func/bintrinsic.h"
#include "func/functype.h"
#include "func/func.h"
#include "func/build.h"
#include "func/invocation/invocation.h"
#include "basic.h"
#include "decl.h"
#include "runtime/runtime.h"
#include "wrapper.h"
#include "template/tvar.h"
|
| ︙ | | |
Changes to bs/cir/allocvar.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
|
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
|
-
+
-
+
+
+
|
#ifndef GOOSE_CIR_ALLOCVAR_H
#define GOOSE_CIR_ALLOCVAR_H
namespace goose::cir
{
class AllocVar
class AllocVar : public BaseInstr< 0, false >
{
public:
template< typename T >
AllocVar( T&& type, uint32_t index ) :
AllocVar( T&& type, uint32_t index, LocationId loc ) :
BaseInstr( loc ),
m_type( forward< T >( type ) ),
m_index( index )
{}
const auto& type() const { return m_type; }
const auto& index() const { return m_index; }
bool canBeExecuted() const { return true; }
bool canBeEagerlyEvaluated() const { return false; }
bool haveSideEffects() const { return true; }
bool operator<( const AllocVar& rhs ) const
{
if( m_index != rhs.m_index )
return m_index < rhs.m_index;
return m_type < rhs.m_type;
}
|
| ︙ | | |
Changes to bs/cir/arith.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
|
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
|
-
-
+
+
+
-
+
-
-
+
+
+
-
+
-
-
+
+
+
-
+
-
-
+
+
+
-
+
-
-
+
+
+
-
+
-
-
+
+
+
-
+
-
-
+
+
+
-
+
|
#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 ) ) {}
Add( LocationId loc ) :
BinaryOp( loc )
{}
friend ostream& operator<<( ostream& out, const Add& ins )
{
return ins.print( out, "ADD" );
return out << "ADD";
}
};
class Sub : public BinaryOp
{
public:
template< typename L, typename R >
Sub( L&& lhs, R&& rhs ) : BinaryOp( forward< L >( lhs ), forward< R >( rhs ) ) {}
Sub( LocationId loc ) :
BinaryOp( loc )
{}
friend ostream& operator<<( ostream& out, const Sub& ins )
{
return ins.print( out, "SUB" );
return out << "SUB";
}
};
class Mul : public BinaryOp
{
public:
template< typename L, typename R >
Mul( L&& lhs, R&& rhs ) : BinaryOp( forward< L >( lhs ), forward< R >( rhs ) ) {}
Mul( LocationId loc ) :
BinaryOp( loc )
{}
friend ostream& operator<<( ostream& out, const Mul& ins )
{
return ins.print( out, "MUL" );
return out << "MUL";
}
};
class UDiv : public BinaryOp
{
public:
template< typename L, typename R >
UDiv( L&& lhs, R&& rhs ) : BinaryOp( forward< L >( lhs ), forward< R >( rhs ) ) {}
UDiv( LocationId loc ) :
BinaryOp( loc )
{}
friend ostream& operator<<( ostream& out, const UDiv& ins )
{
return ins.print( out, "UDIV" );
return out << "UDIV";
}
};
class SDiv : public BinaryOp
{
public:
template< typename L, typename R >
SDiv( L&& lhs, R&& rhs ) : BinaryOp( forward< L >( lhs ), forward< R >( rhs ) ) {}
SDiv( LocationId loc ) :
BinaryOp( loc )
{}
friend ostream& operator<<( ostream& out, const SDiv& ins )
{
return ins.print( out, "SDIV" );
return out << "SDIV";
}
};
class URem : public BinaryOp
{
public:
template< typename L, typename R >
URem( L&& lhs, R&& rhs ) : BinaryOp( forward< L >( lhs ), forward< R >( rhs ) ) {}
URem( LocationId loc ) :
BinaryOp( loc )
{}
friend ostream& operator<<( ostream& out, const URem& ins )
{
return ins.print( out, "UREM" );
return out << "UREM";
}
};
class SRem : public BinaryOp
{
public:
template< typename L, typename R >
SRem( L&& lhs, R&& rhs ) : BinaryOp( forward< L >( lhs ), forward< R >( rhs ) ) {}
SRem( LocationId loc ) :
BinaryOp( loc )
{}
friend ostream& operator<<( ostream& out, const SRem& ins )
{
return ins.print( out, "SREM" );
return out << "SREM";
}
};
}
#endif
|
Changes to bs/cir/ass.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
|
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
|
-
+
-
-
+
-
+
-
-
+
-
+
-
+
-
-
-
|
#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 shorthand and an accurate description of the problem
namespace goose::cir
{
class Assert
class Assert : public BaseInstr< 1, false >
{
public:
template< typename V >
Assert( V&& cond ) :
Assert( LocationId loc ) :
m_cond( forward< V >( cond ) )
BaseInstr( loc )
{}
const auto& cond() const { return m_cond; }
bool canBeExecuted() const { return true; }
bool canBeEagerlyEvaluated() const { return false; }
bool haveSideEffects() const { return true; }
bool operator<( const Assert& rhs ) const
{
return m_cond < rhs.m_cond;
return false;
}
friend ostream& operator<<( ostream& out, const Assert& ins )
{
return out << "ASSERT(" << ins.m_cond << ')';
return out << "ASSERT";
}
private:
eir::Value m_cond;
};
}
#endif
|
Changes to bs/cir/basicblock.h.
| ︙ | | |
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
|
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
|
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
+
-
-
-
-
+
+
+
+
+
-
+
|
const auto& loopEdges() const { return m_loopEdges; }
uint32_t loopId() const { return m_loopId; }
bool isLoopHeader() const { return m_isLoopHeader; }
void setLoopId( uint32_t id ) { m_loopId = id; }
void setLoopHeader() { m_isLoopHeader = true; }
const auto& operator[]( size_t i ) const { return m_instructions[i]; }
auto& operator[]( size_t i ) { return m_instructions[i]; }
auto* llvmBB() { return m_llvmBB; }
void setLLVMBB( llvm::BasicBlock* pBB ) { m_llvmBB = pBB; }
auto begin() const { return m_instructions.begin(); }
auto end() const { return m_instructions.end(); }
auto empty() const { return m_instructions.empty(); }
const auto& instructions() const { return m_instructions; }
using RunnableInstructions = llvm::SmallVector< Instruction, 16 >;
const RunnableInstructions* runnableInstructions() const
{
if( m_dirty )
{
m_dirty = false;
const auto& front() const { return m_instructions.front(); }
const auto& back() const { return m_instructions.back(); }
auto& front() { return m_instructions.front(); }
auto& back() { return m_instructions.back(); }
auto empty() const { return m_instructions.empty(); }
uint32_t size() const { return m_instructions.size(); }
m_runnableInstructions.clear();
if( !FilterVerificationInstructions( m_instructions, m_runnableInstructions ) )
return nullptr;
}
return &m_runnableInstructions;
}
void reserve( size_t size ) { m_instructions.reserve( size ); }
void clear()
{
m_instructions.clear();
m_dirty = true;
}
template< typename... T >
void emplace_back( T&&... args );
template< typename... T >
template< typename... I >
void append( I&&... instrs )
{
AppendToInstrSeq( m_instructions, forward< I >( instrs )... );
m_dirty = true;
void push_back_from_var( const variant< T... >& instr );
}
template< typename T >
void setTerminator( T&& terminator );
const auto& terminator() const { return m_terminator; }
bool canBeExecuted() const
|
| ︙ | | |
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
|
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
|
-
+
+
+
+
|
bool codeGenStarted() const { return m_codeGenStarted; }
void setCodeGenStarted( bool b = true ) { m_codeGenStarted = b; }
template< typename F >
void forEachSuccessor( F&& func ) const;
private:
vector< Instruction > m_instructions;
InstrSeq m_instructions;
mutable RunnableInstructions m_runnableInstructions;
optional< Terminator > m_terminator;
weak_ptr< CFG > m_owner;
llvm::SmallVector< uint32_t, 8 > m_backEdges;
llvm::SmallVector< uint32_t, 8 > m_loopEdges;
llvm::BasicBlock* m_llvmBB = nullptr;
uint32_t m_index = 0;
uint32_t m_loopId = 0; // Id of the header of the loop that this block belongs to, or 0.
eir::LocationId m_locId = 0; // An optional location id. Used by the verifier on loop headers
// to indicate the location of a loop that it failed to verify.
bool m_isLoopHeader = false;
bool m_canBeExecuted = true;
bool m_canBeEagerlyEvaluated = true;
mutable bool m_dirty = false;
mutable bool m_codeGenStarted = false;
};
}
#endif
|
Changes to bs/cir/basicblock.inl.
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
|
1
2
3
4
5
6
7
8
9
10
11
12
|
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
|
#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();
}
template< typename... T >
void BasicBlock::push_back_from_var( const variant< T... >& instr )
{
visit( [&]( auto&& e )
{
m_canBeExecuted = m_canBeExecuted && e.canBeExecuted();
m_canBeEagerlyEvaluated = m_canBeEagerlyEvaluated && e.canBeEagerlyEvaluated();
m_instructions.emplace_back( e );
}, instr );
}
template< typename T >
void BasicBlock::setTerminator( T&& terminator )
{
m_terminator = forward< T >( terminator );
m_terminator->addCFGEdges( m_owner.lock(), index() );
}
|
| ︙ | | |
Deleted bs/cir/binaryop.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
|
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
|
#include "cir.h"
namespace goose::cir
{
bool BinaryOp::canBeExecuted() const
{
return IsValueConstantOrExecutable( m_lhs )
&& IsValueConstantOrExecutable( m_rhs );
}
bool BinaryOp::canBeEagerlyEvaluated() const
{
return CanValueBeEagerlyEvaluated( m_lhs )
&& CanValueBeEagerlyEvaluated( m_rhs );
}
}
|
Changes 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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
-
+
-
-
-
+
+
-
-
-
-
-
-
+
+
+
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
|
#ifndef GOOSE_CIR_BINARYINSTR_H
#define GOOSE_CIR_BINARYINSTR_H
namespace goose::cir
{
class BinaryOp
class BinaryOp : public BaseInstr< 2, true >
{
public:
template< typename L, typename R >
BinaryOp( L&& lhs, R&& rhs ) :
m_lhs( forward< L >( lhs ) ),
BinaryOp( LocationId loc ) :
BaseInstr( loc )
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;
bool canBeExecuted() const { return true; }
bool canBeEagerlyEvaluated() const { return true; }
bool haveSideEffects() const { return false; }
bool operator<( const BinaryOp& rhs ) const
{
if( m_lhs != rhs.m_lhs )
return m_lhs < rhs.m_lhs;
return false;
return m_rhs < rhs.m_rhs;
}
protected:
ostream& print( ostream& out, const char* name ) const
{
return out << name << '(' << m_lhs << ", " << m_rhs << ')';
}
private:
eir::Value m_lhs;
eir::Value m_rhs;
};
class BinaryOpSameTypes : public BinaryOp
{
public:
template< typename L, typename R >
BinaryOpSameTypes( L&& l, R&& r ) :
BinaryOp( forward< L >( l ), forward< R >( r ) )
{
assert( lhs().type() == rhs().type() );
}
};
}
#endif
|
Changes to bs/cir/bitwise.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
|
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
|
-
-
+
+
+
-
+
-
-
+
+
+
-
+
-
-
+
+
+
-
+
|
#ifndef GOOSE_CIR_BITWISE_H
#define GOOSE_CIR_BITWISE_H
namespace goose::cir
{
class Shl : public BinaryOp
{
public:
template< typename L, typename R >
Shl( L&& lhs, R&& rhs ) : BinaryOp( forward< L >( lhs ), forward< R >( rhs ) ) {}
Shl( LocationId loc ) :
BinaryOp( loc )
{}
friend ostream& operator<<( ostream& out, const Shl& ins )
{
return ins.print( out, "SHL" );
return out << "SHL";
}
};
class LShr : public BinaryOp
{
public:
template< typename L, typename R >
LShr( L&& lhs, R&& rhs ) : BinaryOp( forward< L >( lhs ), forward< R >( rhs ) ) {}
LShr( LocationId loc ) :
BinaryOp( loc )
{}
friend ostream& operator<<( ostream& out, const LShr& ins )
{
return ins.print( out, "LSHR" );
return out << "LSHR";
}
};
class AShr : public BinaryOp
{
public:
template< typename L, typename R >
AShr( L&& lhs, R&& rhs ) : BinaryOp( forward< L >( lhs ), forward< R >( rhs ) ) {}
AShr( LocationId loc ) :
BinaryOp( loc )
{}
friend ostream& operator<<( ostream& out, const AShr& ins )
{
return ins.print( out, "ASHR" );
return out << "ASHR";
}
};
}
#endif
|
Changes to bs/cir/branch.h.
| ︙ | | |
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
|
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:
wptr< BasicBlock > m_dest;
};
class CondBranch
{
public:
template< typename V, typename BT, typename BF >
CondBranch( V&& cond, BT&& trueDest, BF&& falseDest ) :
template< typename BT, typename BF >
CondBranch( BT&& trueDest, BF&& falseDest ) :
m_cond( forward< V >( cond ) ),
m_trueDest( forward< BT >( trueDest ) ),
m_falseDest( forward< BF >( falseDest ) )
{}
const auto& cond() const { return m_cond; }
const auto& trueDest() const { return m_trueDest; }
const auto& falseDest() const { return m_falseDest; }
bool canBeExecuted() const
bool canBeExecuted() const { return true; }
{
return IsValueConstantOrExecutable( m_cond );
}
bool canBeEagerlyEvaluated() const
bool canBeEagerlyEvaluated() const { return true; }
{
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;
};
// A special terminator that points to a basic block to use only
// during verification (containing "ghost code") and to a continuation
// basic block
|
| ︙ | | |
Deleted bs/cir/call.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
|
|
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
|
#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 ) )
return false;
bool argsCanBeExecuted = true;
ForEachInVectorTerm( m_args, [&]( auto&& arg )
{
if( !IsValueConstantOrExecutable( *EIRToValue( arg ) ) )
{
argsCanBeExecuted = false;
return false;
}
return true;
} );
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();
}
bool Call::canBeEagerlyEvaluated() const
{
// Functions with void return type are assumed to have side effects
// and therefore that they should never be eagerly evaluated,
// It's not like they would need to be anyway.
// An exception is builtin functions that have been explicitely marked to be eagerly evaluated.
if( GetFuncRType( m_func ) == GetValueType< void >() )
return IsEagerBuiltinFunc( m_func );
if( IsNonEagerBuiltinFunc( m_func ) )
return false;
if( IsExternalFunc( m_func ) )
return false;
bool argsAreConstant = true;
ForEachInVectorTerm( m_args, [&]( auto&& arg )
{
if( !CanValueBeEagerlyEvaluated( *EIRToValue( arg ) ) )
{
argsAreConstant = false;
return false;
}
return true;
} );
if( !argsAreConstant )
return false;
if( IsEagerBuiltinFunc( m_func ) )
return true;
const auto* pFuncCIR = GetFuncCIR( m_func );
if( !pFuncCIR )
return false;
return pFuncCIR->canBeExecuted();
}
ostream& operator<<( ostream& out, const Call& ins )
{
return out << "CALL(" << ins.m_func << ", " << ins.m_args << ')';
}
}
|
Changes 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
28
29
30
31
32
33
34
35
36
|
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
|
-
+
-
-
-
-
+
+
+
-
-
+
-
-
+
+
+
-
-
-
+
-
-
+
+
+
+
+
-
+
-
|
#ifndef GOOSE_CIR_CALL_H
#define GOOSE_CIR_CALL_H
namespace goose::cir
{
class Call
class Call : public BaseInstr< 1, true > // Can pop more depending on arg count
{
public:
template< typename F, typename A >
Call( F&& func, A&& args ) :
m_func( forward< F >( func ) ),
m_args( forward< A >( args ) )
Call( uint32_t numArgs, LocationId loc ) :
BaseInstr( loc ),
m_numArgs( numArgs )
{}
const auto& func() const { return m_func; }
const auto& args() const { return m_args; }
const auto& numArgs() const { return m_numArgs; }
bool canBeExecuted() const;
bool canBeEagerlyEvaluated() const;
bool canBeExecuted() const { return true; }
bool canBeEagerlyEvaluated() const { return true; }
bool haveSideEffects() const { return true; }
bool operator<( const Call& rhs ) const
{
if( m_func != rhs.m_func )
return m_func < rhs.m_func;
return m_args < rhs.m_args;
return m_numArgs < rhs.m_numArgs;
}
friend ostream& operator<<( ostream& out, const Call& ins );
friend ostream& operator<<( ostream& out, const Call& ins )
{
return out << "CALL";
}
private:
eir::Value m_func;
uint32_t m_numArgs = 0;
eir::Term m_args;
};
}
#endif
|
Changes to bs/cir/cfg.h.
| ︙ | | |
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
-
+
+
+
+
|
{
public:
CFG( uint32_t numParams ) :
m_temporariesCount( numParams )
{}
bool isPoisoned() const { return m_poisoned; }
void poison() { m_poisoned = true; }
void poison()
{
m_poisoned = true;
}
const auto& entryBB() const { return m_basicBlocks.front(); }
const auto& lastBB() const { return m_basicBlocks.back(); }
const auto& currentBB() const { return m_currentBB; }
template< typename T >
void setCurrentBB( T&& pBB )
|
| ︙ | | |
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
|
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
|
+
-
+
-
+
-
+
-
-
+
+
|
const auto& getBB( uint32_t index ) const { return m_basicBlocks[index - 1]; }
auto count() const { return m_basicBlocks.size(); }
const ptr< BasicBlock >& createBB();
auto getNewTemporaryIndex() { return m_temporariesCount++; }
auto temporariesCount() const { 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 Instruction& addrCalculation )
void setStorageLocationModifiedByLoop( uint32_t loopId, const eir::Term& type, const StorageLocation& sloc )
{
m_loopModifiedAddresses.emplace( make_pair( loopId, addrCalculation ), type );
m_loopModifiedStorageLocations.emplace( make_pair( loopId, sloc ), type );
}
template< typename F >
void forEachAddressModifiedByLoop( uint32_t loopId, F&& func ) const
void forEachStorageLocationModifiedByLoop( uint32_t loopId, F&& func ) const
{
auto begin = m_loopModifiedAddresses.lower_bound( { loopId, {} } );
auto end = m_loopModifiedAddresses.upper_bound( { loopId, Placeholder( TERM( 0U ), ""_sid ) } );
auto begin = m_loopModifiedStorageLocations.lower_bound( { loopId, Address{ Address::Origin::Stack, 0, 0 } } );
auto end = m_loopModifiedStorageLocations.upper_bound( { loopId, monostate() } );
for( auto it = begin; it != end; ++it )
func( it->second, it->first.second );
}
template< typename F >
void forEachReachableBlock( const ptr< BasicBlock >& bb, F&& func ) const
|
| ︙ | | |
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
|
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
|
-
+
-
+
|
// All the edges of the CFG in SrcBBIndex, DestBBIndex form
unordered_multimap< uint32_t, uint32_t > m_edges;
// 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
// For each loop, store all of the storage locations modified
// during that loop.
// May be be empty if it has not (yet) been computed.
multimap< pair< uint32_t, Instruction >, eir::Term > m_loopModifiedAddresses;
multimap< pair< uint32_t, StorageLocation >, eir::Term > m_loopModifiedStorageLocations;
// The number of temporary indices used by this CFG.
uint32_t m_temporariesCount = 0;
uint32_t m_loopCount = 0;
bool m_poisoned = false;
|
| ︙ | | |
Changes to bs/cir/cfgviz.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
+
+
+
+
+
+
|
#include "cir/cir.h"
#include "builtins/builtins.h"
using namespace goose::builtins;
namespace goose::cir
{
void CfgViz( GraphVizBuilder& builder, const Func& func )
{
if( func.body() )
CfgViz( builder, *func.body() );
}
void CfgViz( GraphVizBuilder& builder, const CFG& cfg )
{
CfgViz( builder, cfg.entryBB() );
}
void CfgViz( GraphVizBuilder& builder, const ptr< BasicBlock >& bb )
{
|
| ︙ | | |
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
-
+
|
sstr << ", L" << bb->loopId();
if( bb->isLoopHeader() )
sstr << ", LH";
GraphVizBuilder::Node n( builder, bb.get(), sstr.str().c_str() );
for( auto&& instr : *bb )
for( auto&& instr : bb->instructions() )
CfgViz( builder, instr );
if( bb->terminator() )
CfgViz( builder, *bb->terminator() );
}
void CfgViz( GraphVizBuilder& builder, const eir::Value& val )
|
| ︙ | | |
44
45
46
47
48
49
50
51
52
53
54
55
56
57
|
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
|
+
+
+
+
+
+
|
GraphVizBuilder::Color col( builder );
builder.output() << val;
return;
}
CfgViz( builder, *val.cir() );
}
void CfgViz( GraphVizBuilder& builder, const InstrSeq& is )
{
for( const auto& instr : is )
CfgViz( builder, instr );
}
void CfgViz( GraphVizBuilder& builder, const Instruction& instr )
{
visit( [&]( auto&& ins )
{
CfgViz( builder, ins );
}, instr.content() );
|
| ︙ | | |
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
|
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
|
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
-
+
-
-
-
-
-
-
-
+
-
+
-
|
void CfgViz( GraphVizBuilder& builder, const Call& instr )
{
GraphVizBuilder::Row row( builder );
GraphVizBuilder::Cell cell( builder );
GraphVizBuilder::Color col( builder );
builder.output() << "Call " << instr.numArgs();
}
// TODO also visualize the func and the args
builder.output() << "Call";
void CfgViz( GraphVizBuilder& builder, const Constant& instr )
{
GraphVizBuilder::Row row( builder );
GraphVizBuilder::Cell cell( builder );
GraphVizBuilder::Color col( builder );
stringstream sstr;
sstr << instr.value();
for( auto c : sstr.str() )
{
switch( c )
{
case '<':
builder.output() << "<";
break;
case '>':
builder.output() << ">";
break;
default:
builder.output() << c;
}
}
}
void CfgViz( GraphVizBuilder& builder, const VarAddr& instr )
{
GraphVizBuilder::Row row( builder );
GraphVizBuilder::Cell cell( builder );
GraphVizBuilder::Color col( builder );
builder.output() << "VarAddr";
builder.output() << "VarAddr " << instr.varIndex();
}
void CfgViz( GraphVizBuilder& builder, const TempAddr& instr )
{
GraphVizBuilder::Row row( builder );
GraphVizBuilder::Cell cell( builder );
GraphVizBuilder::Color col( builder );
builder.output() << "TempAddr";
builder.output() << "TempAddr " << instr.tempIndex();
}
void CfgViz( GraphVizBuilder& builder, const Select& instr )
{
GraphVizBuilder::Row row( builder );
GraphVizBuilder::Cell cell( builder );
GraphVizBuilder::Color col( builder );
builder.output() << "Select";
builder.output() << "Select " << instr.memberIndex();
}
void CfgViz( GraphVizBuilder& builder, const CreateTemporary& instr )
{
builder.queueWork( [&]
{
CfgViz( builder, instr.value() );
} );
auto id = builder.getNodeId( &instr.value() );
GraphVizBuilder::Row row( builder );
GraphVizBuilder::Cell cell( builder );
GraphVizBuilder::Color col( builder, GraphVizBuilder::GetNodeColor( id ) );
GraphVizBuilder::Color col( builder );
builder.output() << "CreateTemporary " << instr.index() << ", " << id;
builder.output() << "CreateTemporary " << instr.index();
builder.addEdge( builder.currentNodeId(), id );
}
void CfgViz( GraphVizBuilder& builder, const GetTemporary& instr )
{
GraphVizBuilder::Row row( builder );
GraphVizBuilder::Cell cell( builder );
GraphVizBuilder::Color col( builder );
|
| ︙ | | |
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
|
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
|
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
|
auto id = builder.getNodeId( pBB.get() );
GraphVizBuilder::Color col( builder, GraphVizBuilder::GetNodeColor( id ) );
builder.output() << "BB #" << id << ", " << index;
return true;
} );
}
void CfgViz( GraphVizBuilder& builder, const RetVoid& t )
{
GraphVizBuilder::Row row( builder );
GraphVizBuilder::Cell cell( builder );
GraphVizBuilder::Color col( builder );
builder.output() << "RetVoid";
}
void CfgViz( GraphVizBuilder& builder, const Ret& t )
{
GraphVizBuilder::Row row( builder );
GraphVizBuilder::Cell cell( builder );
if( t.value() )
{
builder.queueWork( [&]
{
CfgViz( builder, *t.value() );
} );
auto id = builder.getNodeId( &*t.value() );
GraphVizBuilder::Color col( builder, GraphVizBuilder::GetNodeColor( id ) );
builder.output() << "Ret " << id;
builder.addEdge( builder.currentNodeId(), id );
}
else
{
GraphVizBuilder::Color col( builder );
builder.output() << "Ret";
GraphVizBuilder::Color col( builder );
builder.output() << "Ret";
}
}
void CfgViz( GraphVizBuilder& builder, const Not& instr )
{
GraphVizBuilder::Row row( builder );
GraphVizBuilder::Cell cell( builder );
GraphVizBuilder::Color col( builder );
|
| ︙ | | |
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
|
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
|
-
-
-
-
-
-
-
+
-
-
+
-
-
+
+
+
+
+
+
+
+
+
-
+
|
builder.output() << "BinaryOp";
}
void CfgViz( GraphVizBuilder& builder, const Assert& instr )
{
GraphVizBuilder::Row row( builder );
GraphVizBuilder::Cell cell( builder );
/*builder.queueWork( [&]
{
CfgViz( builder, instr.cond() );
} );*/
auto id = builder.getNodeId( &instr.cond() );
GraphVizBuilder::Color col( builder, GraphVizBuilder::GetNodeColor( id ) );
GraphVizBuilder::Color col( builder );
builder.output() << "Assert " << id;
builder.output() << "Assert";
//builder.addEdge( builder.currentNodeId(), id );
}
void CfgViz( GraphVizBuilder& builder, const Placeholder& instr )
{
GraphVizBuilder::Row row( builder );
GraphVizBuilder::Cell cell( builder );
builder.output() << '@' << instr.name();
}
void CfgViz( GraphVizBuilder& builder, const PHOverride& instr )
void CfgViz( GraphVizBuilder& builder, const PHOverrideSet& instr )
{
GraphVizBuilder::Row row( builder );
GraphVizBuilder::Cell cell( builder );
GraphVizBuilder::Color col( builder );
builder.output() << "PHOverrideSet";
}
void CfgViz( GraphVizBuilder& builder, const PHOverrideClear& instr )
{
GraphVizBuilder::Row row( builder );
GraphVizBuilder::Cell cell( builder );
GraphVizBuilder::Color col( builder );
builder.output() << "PHOverride";
builder.output() << "PHOverrideClear";
}
void CfgViz( GraphVizBuilder& builder, const GhostCall& instr )
{
GraphVizBuilder::Row row( builder );
GraphVizBuilder::Cell cell( builder );
GraphVizBuilder::Color col( builder );
|
| ︙ | | |
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
|
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
|
-
-
+
-
+
|
CfgViz( builder, t.trueDest().lock() );
CfgViz( builder, t.falseDest().lock() );
} );
{
GraphVizBuilder::Row row( builder );
GraphVizBuilder::Cell cell( builder );
auto id = builder.getNodeId( &t.cond() );
GraphVizBuilder::Color col( builder, GraphVizBuilder::GetNodeColor( id ) );
GraphVizBuilder::Color col( builder );
builder.output() << "CondBranch " << id;
builder.output() << "CondBranch";
}
GraphVizBuilder::Row row( builder );
{
GraphVizBuilder::Cell cell( builder );
|
| ︙ | | |
325
326
327
328
329
330
331
332
333
334
335
336
337
338
|
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
|
+
|
CfgViz( builder, t.ghostCode().lock() );
CfgViz( builder, t.continuation().lock() );
} );
{
GraphVizBuilder::Row row( builder );
GraphVizBuilder::Cell cell( builder );
GraphVizBuilder::Color col( builder );
builder.output() << "GhostBranch";
}
GraphVizBuilder::Row row( builder );
{
|
| ︙ | | |
Changes 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
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
|
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
|
+
+
+
+
-
+
+
+
|
#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 Func& func );
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 InstrSeq& is );
extern void CfgViz( GraphVizBuilder& builder, const Instruction& instr );
extern void CfgViz( GraphVizBuilder& builder, const Terminator& t );
extern void CfgViz( GraphVizBuilder& builder, const monostate& );
extern void CfgViz( GraphVizBuilder& builder, const Call& instr );
extern void CfgViz( GraphVizBuilder& builder, const Constant& instr );
extern void CfgViz( GraphVizBuilder& builder, const VarAddr& instr );
extern void CfgViz( GraphVizBuilder& builder, const TempAddr& instr );
extern void CfgViz( GraphVizBuilder& builder, const Select& instr );
extern void CfgViz( GraphVizBuilder& builder, const CreateTemporary& instr );
extern void CfgViz( GraphVizBuilder& builder, const GetTemporary& instr );
extern void CfgViz( GraphVizBuilder& builder, const AllocVar& instr );
extern void CfgViz( GraphVizBuilder& builder, const Load& instr );
extern void CfgViz( GraphVizBuilder& builder, const Store& instr );
extern void CfgViz( GraphVizBuilder& builder, const Phi& instr );
extern void CfgViz( GraphVizBuilder& builder, const Not& instr );
extern void CfgViz( GraphVizBuilder& builder, const BinaryOp& instr );
extern void CfgViz( GraphVizBuilder& builder, const Assert& instr );
extern void CfgViz( GraphVizBuilder& builder, const Placeholder& instr );
extern void CfgViz( GraphVizBuilder& builder, const PHOverride& instr );
extern void CfgViz( GraphVizBuilder& builder, const PHOverrideSet& instr );
extern void CfgViz( GraphVizBuilder& builder, const PHOverrideClear& instr );
extern void CfgViz( GraphVizBuilder& builder, const GhostCall& instr );
extern void CfgViz( GraphVizBuilder& builder, const RetVoid& t );
extern void CfgViz( GraphVizBuilder& builder, const Ret& t );
extern void CfgViz( GraphVizBuilder& builder, const Branch& t );
extern void CfgViz( GraphVizBuilder& builder, const CondBranch& t );
extern void CfgViz( GraphVizBuilder& builder, const GhostBranch& t );
extern void CfgViz( GraphVizBuilder& builder, const Break& t );
extern void CfgViz( GraphVizBuilder& builder, const Continue& t );
}
#endif
|
Changes to bs/cir/cir.h.
| ︙ | | |
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
+
+
+
|
static constexpr uint32_t InvalidVarId = numeric_limits< uint32_t >::max();
class CFG;
}
#include "helpers.h"
#include "storagelocation.h"
#include "constant.h"
#include "varaddr.h"
#include "tempaddr.h"
#include "select.h"
#include "call.h"
#include "createtemporary.h"
#include "gettemporary.h"
#include "allocvar.h"
|
| ︙ | | |
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
|
+
|
#include "ass.h"
#include "placeholder.h"
#include "phoverride.h"
#include "ghostcall.h"
#include "instruction.h"
#include "terminator.h"
#include "verifinstrfilter.h"
#include "basicblock.h"
#include "cfg.h"
#include "func.h"
#include "hash.h"
#include "decorator.h"
#include "cfgviz.h"
#include "basicblock.inl"
#endif
|
Changes to bs/cir/comparison.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
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
|
-
+
-
-
+
+
+
-
+
-
+
-
-
+
+
+
-
+
-
+
-
-
+
+
+
-
+
-
+
-
-
+
+
+
-
+
-
+
-
-
+
+
+
-
+
-
+
-
-
+
+
+
-
+
-
+
-
-
+
+
+
-
+
-
+
-
-
+
+
+
-
+
-
+
-
-
+
+
+
-
+
-
+
-
-
+
+
+
-
+
|
#ifndef GOOSE_CIR_COMPARISON_H
#define GOOSE_CIR_COMPARISON_H
namespace goose::cir
{
class Eq : public BinaryOpSameTypes
class Eq : public BinaryOp
{
public:
template< typename L, typename R >
Eq( L&& lhs, R&& rhs ) : BinaryOpSameTypes( forward< L >( lhs ), forward< R >( rhs ) ) {}
Eq( LocationId loc ) :
BinaryOp( loc )
{}
friend ostream& operator<<( ostream& out, const Eq& ins )
{
return ins.print( out, "EQ" );
return out << "EQ";
}
};
class Neq : public BinaryOpSameTypes
class Neq : public BinaryOp
{
public:
template< typename L, typename R >
Neq( L&& lhs, R&& rhs ) : BinaryOpSameTypes( forward< L >( lhs ), forward< R >( rhs ) ) {}
Neq( LocationId loc ) :
BinaryOp( loc )
{}
friend ostream& operator<<( ostream& out, const Neq& ins )
{
return ins.print( out, "NEQ" );
return out << "NEQ";
}
};
class UGT : public BinaryOpSameTypes
class UGT : public BinaryOp
{
public:
template< typename L, typename R >
UGT( L&& lhs, R&& rhs ) : BinaryOpSameTypes( forward< L >( lhs ), forward< R >( rhs ) ) {}
UGT( LocationId loc ) :
BinaryOp( loc )
{}
friend ostream& operator<<( ostream& out, const UGT& ins )
{
return ins.print( out, "UGT" );
return out << "UGT";
}
};
class UGE : public BinaryOpSameTypes
class UGE : public BinaryOp
{
public:
template< typename L, typename R >
UGE( L&& lhs, R&& rhs ) : BinaryOpSameTypes( forward< L >( lhs ), forward< R >( rhs ) ) {}
UGE( LocationId loc ) :
BinaryOp( loc )
{}
friend ostream& operator<<( ostream& out, const UGE& ins )
{
return ins.print( out, "UGE" );
return out << "UGE";
}
};
class ULT : public BinaryOpSameTypes
class ULT : public BinaryOp
{
public:
template< typename L, typename R >
ULT( L&& lhs, R&& rhs ) : BinaryOpSameTypes( forward< L >( lhs ), forward< R >( rhs ) ) {}
ULT( LocationId loc ) :
BinaryOp( loc )
{}
friend ostream& operator<<( ostream& out, const ULT& ins )
{
return ins.print( out, "ULT" );
return out << "ULT";
}
};
class ULE : public BinaryOpSameTypes
class ULE : public BinaryOp
{
public:
template< typename L, typename R >
ULE( L&& lhs, R&& rhs ) : BinaryOpSameTypes( forward< L >( lhs ), forward< R >( rhs ) ) {}
ULE( LocationId loc ) :
BinaryOp( loc )
{}
friend ostream& operator<<( ostream& out, const ULE& ins )
{
return ins.print( out, "ULE" );
return out << "ULE";
}
};
class SGT : public BinaryOpSameTypes
class SGT : public BinaryOp
{
public:
template< typename L, typename R >
SGT( L&& lhs, R&& rhs ) : BinaryOpSameTypes( forward< L >( lhs ), forward< R >( rhs ) ) {}
SGT( LocationId loc ) :
BinaryOp( loc )
{}
friend ostream& operator<<( ostream& out, const SGT& ins )
{
return ins.print( out, "SGT" );
return out << "SGT";
}
};
class SGE : public BinaryOpSameTypes
class SGE : public BinaryOp
{
public:
template< typename L, typename R >
SGE( L&& lhs, R&& rhs ) : BinaryOpSameTypes( forward< L >( lhs ), forward< R >( rhs ) ) {}
SGE( LocationId loc ) :
BinaryOp( loc )
{}
friend ostream& operator<<( ostream& out, const SGE& ins )
{
return ins.print( out, "SGE" );
return out << "SGE";
}
};
class SLT : public BinaryOpSameTypes
class SLT : public BinaryOp
{
public:
template< typename L, typename R >
SLT( L&& lhs, R&& rhs ) : BinaryOpSameTypes( forward< L >( lhs ), forward< R >( rhs ) ) {}
SLT( LocationId loc ) :
BinaryOp( loc )
{}
friend ostream& operator<<( ostream& out, const SLT& ins )
{
return ins.print( out, "SLT" );
return out << "SLT";
}
};
class SLE : public BinaryOpSameTypes
class SLE : public BinaryOp
{
public:
template< typename L, typename R >
SLE( L&& lhs, R&& rhs ) : BinaryOpSameTypes( forward< L >( lhs ), forward< R >( rhs ) ) {}
SLE( LocationId loc ) :
BinaryOp( loc )
{}
friend ostream& operator<<( ostream& out, const SLE& ins )
{
return ins.print( out, "SLE" );
return out << "SLE";
}
};
}
#endif
|
Added bs/cir/constant.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
|
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
|
#ifndef GOOSE_CIR_CONSTANT_H
#define GOOSE_CIR_CONSTANT_H
namespace goose::cir
{
class Constant : public BaseInstr< 0, true >
{
public:
template< typename V >
Constant( V&& val ) :
BaseInstr( val.locationId() ),
m_value( forward< V >( val ) )
{}
const auto& value() const { return m_value; }
bool canBeExecuted() const { return true; }
bool canBeEagerlyEvaluated() const { return true; }
bool haveSideEffects() const { return false; }
bool operator<( const Constant& rhs ) const
{
return m_value < rhs.m_value;
}
friend ostream& operator<<( ostream& out, const Constant& ins )
{
return out << "CONSTANT(" << ins.m_value << ')';
}
private:
eir::Value m_value;
};
}
#endif
|
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
Changes to bs/cir/createtemporary.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
|
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
|
-
+
-
-
-
+
+
+
-
-
-
+
-
-
-
-
-
+
-
-
+
-
-
-
+
-
-
+
-
|
#ifndef GOOSE_CIR_CREATETEMPORARY_H
#define GOOSE_CIR_CREATETEMPORARY_H
namespace goose::cir
{
class CreateTemporary
class CreateTemporary : public BaseInstr< 1, false >
{
public:
template< typename V >
CreateTemporary( uint32_t index, V&& val ) :
m_index( index ),
CreateTemporary( uint32_t index, LocationId loc ) :
BaseInstr( loc ),
m_index( index )
m_value( forward< V >( val ) )
{}
const auto& index() const { return m_index; }
const auto& value() const { return m_value; }
bool canBeExecuted() const
bool canBeExecuted() const { return true; }
{
return IsValueConstantOrExecutable( m_value );
}
bool canBeEagerlyEvaluated() const
bool canBeEagerlyEvaluated() const { return true; }
{
return CanValueBeEagerlyEvaluated( m_value );
bool haveSideEffects() const { return true; }
}
bool operator<( const CreateTemporary& rhs ) const
{
if( m_index != rhs.m_index )
return m_index < rhs.m_index;
return m_index < rhs.m_index;
return m_value < rhs.m_value;
}
friend ostream& operator<<( ostream& out, const CreateTemporary& ins )
{
return out << "CREATETEMP(" << ins.m_index << ", " << ins.m_value << ')';
return out << "CREATETEMP(" << ins.m_index << ')';
}
private:
uint32_t m_index = 0;
eir::Value m_value;
};
}
#endif
|
Changes to bs/cir/decorator.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
1
2
3
4
5
6
7
8
9
10
|
-
-
-
+
-
-
-
+
-
-
-
+
-
|
#include "cir.h"
using namespace goose::cir;
void Decorator::appendTo( BasicBlock& bb ) &&
{
bb.reserve( bb.size() + m_prologue.size() + m_operation.size() + m_epilogue.size() );
for( auto&& x : m_prologue )
bb.append( move( m_prologue ) );
bb.emplace_back( move( x ) );
for( auto&& x : m_operation )
bb.append( move( m_operation ) );
bb.emplace_back( move( x ) );
for( auto&& x : m_epilogue )
bb.append( move( m_epilogue) );
bb.emplace_back( move( x ) );
}
|
Changes to bs/cir/decorator.h.
| ︙ | | |
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
-
-
-
+
+
+
|
{
m_epilogue.emplace_back( forward< I >( instr ) );
}
void appendTo( BasicBlock& bb ) &&;
private:
llvm::SmallVector< Instruction, 8 > m_prologue;
llvm::SmallVector< Instruction, 8 > m_operation;
llvm::SmallVector< Instruction, 8 > m_epilogue;
InstrSeq m_prologue;
InstrSeq m_operation;
InstrSeq m_epilogue;
};
}
#endif
|
Changes to bs/cir/gettemporary.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
|
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
|
-
+
-
+
+
+
|
#ifndef GOOSE_CIR_GETTEMPORARY_H
#define GOOSE_CIR_GETTEMPORARY_H
namespace goose::cir
{
class GetTemporary
class GetTemporary : public BaseInstr< 0, true >
{
public:
template< typename T >
GetTemporary( T&& type, uint32_t index ) :
GetTemporary( T&& type, uint32_t index, LocationId loc ) :
BaseInstr( loc ),
m_type( forward< T >( type ) ),
m_index( index )
{}
const auto& type() const { return m_type; }
const auto& index() const { return m_index; }
bool canBeExecuted() const { return true; }
bool canBeEagerlyEvaluated() const { return true; }
bool haveSideEffects() const { return false; }
bool operator<( const GetTemporary& rhs ) const
{
if( m_index != rhs.m_index )
return m_index < rhs.m_index;
return m_type < rhs.m_type;
}
|
| ︙ | | |
Changes to bs/cir/ghostcall.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
|
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
|
-
+
-
-
-
-
+
+
+
-
-
+
+
-
-
-
+
-
+
-
+
-
|
#ifndef GOOSE_CIR_GHOSTCALL_H
#define GOOSE_CIR_GHOSTCALL_H
namespace goose::cir
{
class GhostCall
class GhostCall : public BaseInstr< 1, true > // Can pop more depending on arg count
{
public:
template< typename F, typename A >
GhostCall( F&& func, A&& args ) :
m_func( forward< F >( func ) ),
m_args( forward< A >( args ) )
GhostCall( uint32_t numArgs, LocationId loc ) :
BaseInstr( loc ),
m_numArgs( numArgs )
{}
const auto& func() const { return m_func; }
const auto& args() const { return m_args; }
const auto& numArgs() const { return m_numArgs; }
bool canBeExecuted() const { return false; }
bool canBeEagerlyEvaluated() const { return false; }
bool haveSideEffects() const { return true; }
bool operator<( const GhostCall& rhs ) const
{
if( m_func != rhs.m_func )
return m_func < rhs.m_func;
return m_args < rhs.m_args;
return m_numArgs < rhs.m_numArgs;
}
friend ostream& operator<<( ostream& out, const GhostCall& ins )
{
return out << "GHOSTCALL(" << ins.m_func << ", " << ins.m_args << ')';
return out << "GHOSTCALL";
}
private:
eir::Value m_func;
uint32_t m_numArgs = 0;
eir::Term m_args;
};
}
#endif
|
Changes to bs/cir/hash.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
|
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
215
216
217
218
219
220
221
222
|
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
+
+
+
+
+
-
+
|
#include "cir/cir.h"
namespace std
{
size_t hash< goose::cir::InstrSeq >::operator()( const goose::cir::InstrSeq& is ) const
{
auto g = goose::util::ContainerHashGenerator( is );
return llvm::hash_combine_range( g.begin(), g.end() );
}
size_t hash< goose::cir::Instruction >::operator()( const goose::cir::Instruction& x ) const
{
return goose::util::ComputeHash( x.content() );
}
size_t hash< goose::cir::Call >::operator()( const goose::cir::Call& x ) const
{
return goose::util::ComputeHash( x.numArgs() );
}
size_t hash< goose::cir::Constant >::operator()( const goose::cir::Constant& x ) const
{
return llvm::hash_combine( goose::util::ComputeHash( x.func() ), goose::util::ComputeHash( x.args() ) );
return goose::util::ComputeHash( x.value() );
}
size_t hash< goose::cir::VarAddr >::operator()( const goose::cir::VarAddr& x ) const
{
return llvm::hash_combine( goose::util::ComputeHash( x.varIndex() ), goose::util::ComputeHash( x.type() ) );
}
size_t hash< goose::cir::TempAddr >::operator()( const goose::cir::TempAddr& x ) const
{
return llvm::hash_combine( goose::util::ComputeHash( x.tempIndex() ), goose::util::ComputeHash( x.initValue() ) );
return goose::util::ComputeHash( x.tempIndex() );
}
size_t hash< goose::cir::Select >::operator()( const goose::cir::Select& x ) const
{
return llvm::hash_combine( goose::util::ComputeHash( x.baseAddr() ), goose::util::ComputeHash( x.memberIndex() ) );
return goose::util::ComputeHash( x.memberIndex() );
}
size_t hash< goose::cir::CreateTemporary >::operator()( const goose::cir::CreateTemporary& x ) const
{
return llvm::hash_combine( goose::util::ComputeHash( x.index() ), goose::util::ComputeHash( x.value() ) );
return goose::util::ComputeHash( x.index() );
}
size_t hash< goose::cir::GetTemporary >::operator()( const goose::cir::GetTemporary& x ) const
{
return llvm::hash_combine( goose::util::ComputeHash( x.type() ), goose::util::ComputeHash( x.index() ) );
}
size_t hash< goose::cir::AllocVar >::operator()( const goose::cir::AllocVar& x ) const
{
return llvm::hash_combine( goose::util::ComputeHash( x.type() ), goose::util::ComputeHash( x.index() ) );
}
size_t hash< goose::cir::Load >::operator()( const goose::cir::Load& x ) const
{
return llvm::hash_combine( goose::util::ComputeHash( *x.addr() ), goose::util::ComputeHash( x.type() ) );
return goose::util::ComputeHash( x.type() );
}
size_t hash< goose::cir::Store >::operator()( const goose::cir::Store& x ) const
{
return llvm::hash_combine( goose::util::ComputeHash( *x.addr() ), goose::util::ComputeHash( x.type() ), goose::util::ComputeHash( x.val() ) );
return goose::util::ComputeHash( x.type() );
}
size_t hash< goose::cir::Phi >::operator()( const goose::cir::Phi& x ) const
{
// Note: we don't bother hashing the incomings here, and we don't really care because we only really need hashing for the
// predicates and phi doesn't make sense there
return llvm::hash_combine( goose::util::ComputeHash( x.type() ), goose::util::ComputeHash( x.numIncomings() ), goose::util::ComputeHash( x.destIndex() ) );
}
size_t hash< goose::cir::Not >::operator()( const goose::cir::Not& x ) const
{
return goose::util::ComputeHash( x.operand() );
return 0;
}
size_t hash< goose::cir::And >::operator()( const goose::cir::And& x ) const
{
return llvm::hash_combine( goose::util::ComputeHash( x.lhs() ), goose::util::ComputeHash( x.rhs() ) );
return 0;
}
size_t hash< goose::cir::Or >::operator()( const goose::cir::Or& x ) const
{
return llvm::hash_combine( goose::util::ComputeHash( x.lhs() ), goose::util::ComputeHash( x.rhs() ) );
return 0;
}
size_t hash< goose::cir::Xor >::operator()( const goose::cir::Xor& x ) const
{
return llvm::hash_combine( goose::util::ComputeHash( x.lhs() ), goose::util::ComputeHash( x.rhs() ) );
return 0;
}
size_t hash< goose::cir::Implies >::operator()( const goose::cir::Implies& x ) const
{
return llvm::hash_combine( goose::util::ComputeHash( x.lhs() ), goose::util::ComputeHash( x.rhs() ) );
return 0;
}
size_t hash< goose::cir::Shl >::operator()( const goose::cir::Shl& x ) const
{
return llvm::hash_combine( goose::util::ComputeHash( x.lhs() ), goose::util::ComputeHash( x.rhs() ) );
return 0;
}
size_t hash< goose::cir::LShr >::operator()( const goose::cir::LShr& x ) const
{
return llvm::hash_combine( goose::util::ComputeHash( x.lhs() ), goose::util::ComputeHash( x.rhs() ) );
return 0;
}
size_t hash< goose::cir::AShr >::operator()( const goose::cir::AShr& x ) const
{
return llvm::hash_combine( goose::util::ComputeHash( x.lhs() ), goose::util::ComputeHash( x.rhs() ) );
return 0;
}
size_t hash< goose::cir::Add >::operator()( const goose::cir::Add& x ) const
{
return llvm::hash_combine( goose::util::ComputeHash( x.lhs() ), goose::util::ComputeHash( x.rhs() ) );
return 0;
}
size_t hash< goose::cir::Sub >::operator()( const goose::cir::Sub& x ) const
{
return llvm::hash_combine( goose::util::ComputeHash( x.lhs() ), goose::util::ComputeHash( x.rhs() ) );
return 0;
}
size_t hash< goose::cir::Mul >::operator()( const goose::cir::Mul& x ) const
{
return llvm::hash_combine( goose::util::ComputeHash( x.lhs() ), goose::util::ComputeHash( x.rhs() ) );
return 0;
}
size_t hash< goose::cir::UDiv >::operator()( const goose::cir::UDiv& x ) const
{
return llvm::hash_combine( goose::util::ComputeHash( x.lhs() ), goose::util::ComputeHash( x.rhs() ) );
return 0;
}
size_t hash< goose::cir::SDiv >::operator()( const goose::cir::SDiv& x ) const
{
return llvm::hash_combine( goose::util::ComputeHash( x.lhs() ), goose::util::ComputeHash( x.rhs() ) );
return 0;
}
size_t hash< goose::cir::URem >::operator()( const goose::cir::URem& x ) const
{
return llvm::hash_combine( goose::util::ComputeHash( x.lhs() ), goose::util::ComputeHash( x.rhs() ) );
return 0;
}
size_t hash< goose::cir::SRem >::operator()( const goose::cir::SRem& x ) const
{
return llvm::hash_combine( goose::util::ComputeHash( x.lhs() ), goose::util::ComputeHash( x.rhs() ) );
return 0;
}
size_t hash< goose::cir::Eq >::operator()( const goose::cir::Eq& x ) const
{
return llvm::hash_combine( goose::util::ComputeHash( x.lhs() ), goose::util::ComputeHash( x.rhs() ) );
return 0;
}
size_t hash< goose::cir::Neq >::operator()( const goose::cir::Neq& x ) const
{
return llvm::hash_combine( goose::util::ComputeHash( x.lhs() ), goose::util::ComputeHash( x.rhs() ) );
return 0;
}
size_t hash< goose::cir::UGT >::operator()( const goose::cir::UGT& x ) const
{
return llvm::hash_combine( goose::util::ComputeHash( x.lhs() ), goose::util::ComputeHash( x.rhs() ) );
return 0;
}
size_t hash< goose::cir::UGE >::operator()( const goose::cir::UGE& x ) const
{
return llvm::hash_combine( goose::util::ComputeHash( x.lhs() ), goose::util::ComputeHash( x.rhs() ) );
return 0;
}
size_t hash< goose::cir::ULT >::operator()( const goose::cir::ULT& x ) const
{
return llvm::hash_combine( goose::util::ComputeHash( x.lhs() ), goose::util::ComputeHash( x.rhs() ) );
return 0;
}
size_t hash< goose::cir::ULE >::operator()( const goose::cir::ULE& x ) const
{
return llvm::hash_combine( goose::util::ComputeHash( x.lhs() ), goose::util::ComputeHash( x.rhs() ) );
return 0;
}
size_t hash< goose::cir::SGT >::operator()( const goose::cir::SGT& x ) const
{
return llvm::hash_combine( goose::util::ComputeHash( x.lhs() ), goose::util::ComputeHash( x.rhs() ) );
return 0;
}
size_t hash< goose::cir::SGE >::operator()( const goose::cir::SGE& x ) const
{
return llvm::hash_combine( goose::util::ComputeHash( x.lhs() ), goose::util::ComputeHash( x.rhs() ) );
return 0;
}
size_t hash< goose::cir::SLT >::operator()( const goose::cir::SLT& x ) const
{
return llvm::hash_combine( goose::util::ComputeHash( x.lhs() ), goose::util::ComputeHash( x.rhs() ) );
return 0;
}
size_t hash< goose::cir::SLE >::operator()( const goose::cir::SLE& x ) const
{
return llvm::hash_combine( goose::util::ComputeHash( x.lhs() ), goose::util::ComputeHash( x.rhs() ) );
return 0;
}
size_t hash< goose::cir::Assert >::operator()( const goose::cir::Assert& x ) const
{
return goose::util::ComputeHash( x.cond() );
return 0;
}
size_t hash< goose::cir::Placeholder >::operator()( const goose::cir::Placeholder& x ) const
{
return llvm::hash_combine( goose::util::ComputeHash( x.type() ), goose::util::ComputeHash( x.name() ) );
}
size_t hash< goose::cir::PHOverride >::operator()( const goose::cir::PHOverride& x ) const
size_t hash< goose::cir::PHOverrideSet >::operator()( const goose::cir::PHOverrideSet& x ) const
{
return llvm::hash_combine( goose::util::ComputeHash( x.name() ), goose::util::ComputeHash( x.phVal() ), goose::util::ComputeHash( x.val() ) );
return goose::util::ComputeHash( x.name() );
}
size_t hash< goose::cir::PHOverrideClear >::operator()( const goose::cir::PHOverrideClear& x ) const
{
return goose::util::ComputeHash( x.name() );
}
size_t hash< goose::cir::GhostCall >::operator()( const goose::cir::GhostCall& x ) const
{
return llvm::hash_combine( goose::util::ComputeHash( x.func() ), goose::util::ComputeHash( x.args() ) );
return goose::util::ComputeHash( x.numArgs() );
}
}
|
Changes to bs/cir/hash.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
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
|
+
+
+
+
+
+
+
+
+
+
|
#ifndef GOOSE_CIR_HASH_H
#define GOOSE_CIR_HASH_H
namespace std
{
template<> struct hash< goose::cir::InstrSeq >
{
size_t operator()( const goose::cir::InstrSeq& is ) const;
};
template<> struct hash< goose::cir::Instruction >
{
size_t operator()( const goose::cir::Instruction& x ) const;
};
template<> struct hash< goose::cir::Call >
{
size_t operator()( const goose::cir::Call& x ) const;
};
template<> struct hash< goose::cir::Constant >
{
size_t operator()( const goose::cir::Constant& x ) const;
};
template<> struct hash< goose::cir::VarAddr >
{
size_t operator()( const goose::cir::VarAddr& x ) const;
};
template<> struct hash< goose::cir::TempAddr >
|
| ︙ | | |
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
|
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
|
-
+
-
+
+
+
+
+
+
|
};
template<> struct hash< goose::cir::Placeholder >
{
size_t operator()( const goose::cir::Placeholder& x ) const;
};
template<> struct hash< goose::cir::PHOverride >
template<> struct hash< goose::cir::PHOverrideSet >
{
size_t operator()( const goose::cir::PHOverride& x ) const;
size_t operator()( const goose::cir::PHOverrideSet& x ) const;
};
template<> struct hash< goose::cir::PHOverrideClear >
{
size_t operator()( const goose::cir::PHOverrideClear& x ) const;
};
template<> struct hash< goose::cir::GhostCall >
{
size_t operator()( const goose::cir::GhostCall& x ) const;
};
}
#endif
|
Changes 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
|
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
|
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
|
#include "cir/cir.h"
namespace goose::cir
{
void AppendInstrSeq( InstrSeq& is, InstrSeq&& isToAppend )
{
is.splice( is.end(), isToAppend );
// TODO update canBeExecuted, store it in InstrSeq?
}
void AppendInstrSeq( InstrSeq& is, const InstrSeq& isToAppend )
{
for( auto&& instr : isToAppend )
AppendToInstrSeq( is, instr );
}
void AppendValue( InstrSeq& is, Value&& v )
{
if( v.cir() )
AppendToInstrSeq( is, move( *v.cir() ) );
else
is.emplace_back( Constant( move( v ) ) );
}
void AppendValue( InstrSeq& is, const Value& v )
{
if( v.cir() )
AppendToInstrSeq( is, *v.cir() );
else
is.emplace_back( Constant( v ) );
}
bool IsValueConstantOrExecutable( const eir::Value& val )
{
if( val.isConstant() )
return true;
for( const auto& instr : *val.cir() )
{
return val.cir()->canBeExecuted();
if( !instr.canBeExecuted() )
return false;
}
return true;
}
bool CanValueBeEagerlyEvaluated( const eir::Value& val )
{
if( val.isConstant() )
return true;
for( const auto& instr : *val.cir() )
{
return val.cir()->canBeEagerlyEvaluated();
if( !instr.canBeEagerlyEvaluated() )
return false;
}
return true;
}
bool DoesInstrSeqHaveSideEffects( const InstrSeq& is )
{
for( auto&& instr : is )
{
if( instr.haveSideEffects() )
return true;
}
return false;
}
}
|
Changes 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
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
|
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
|
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
+
+
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
-
-
+
+
+
+
-
-
-
+
+
+
-
-
-
-
-
+
+
+
-
-
-
+
|
#ifndef GOOSE_CIR_HELPERS_H
#define GOOSE_CIR_HELPERS_H
namespace goose::cir
{
class Instruction;
using InstrSeq = list< Instruction >;
bool IsValueConstantOrExecutable( const eir::Value& val );
bool CanValueBeEagerlyEvaluated( const eir::Value& val );
extern bool IsValueConstantOrExecutable( const eir::Value& val );
extern bool CanValueBeEagerlyEvaluated( const eir::Value& val );
extern bool DoesInstrSeqHaveSideEffects( const InstrSeq& is );
extern void AppendInstrSeq( InstrSeq& is, InstrSeq&& isToAppend );
extern void AppendInstrSeq( InstrSeq& is, const InstrSeq& isToAppend );
extern void AppendValue( InstrSeq& is, Value&& v );
extern void AppendValue( InstrSeq& is, const Value& v );
template< typename I >
void AppendToInstrSeq( InstrSeq& is, I&& instr )
{
using II = remove_cvref_t< I >;
if constexpr( is_same_v< II, InstrSeq > )
{
AppendInstrSeq( is, forward< I >( instr ) );
}
else if constexpr( is_same_v< II, Value > )
{
AppendValue( is, forward< I >( instr ) );
}
else
{
is.emplace_back( Instruction( forward< I >( instr ) ) );
}
}
static inline void AppendToInstrSeq( InstrSeq& is, const ptr< InstrSeq >& instr )
{
AppendToInstrSeq( is, *instr );
}
static inline void AppendToInstrSeq( InstrSeq& is, ptr< InstrSeq >&& instr )
{
AppendToInstrSeq( is, move( *instr ) );
}
template< typename HI, typename... TI >
void AppendToInstrSeq( InstrSeq& is, HI&& headInstr, TI&&... tailInstrs )
{
AppendToInstrSeq( is, forward< HI >( headInstr ) );
AppendToInstrSeq( is, forward< TI >( tailInstrs )... );
}
template< typename T, typename I >
auto BuildComputedValue( T&& type, I&& instr )
template< typename T, typename... I >
auto BuildComputedValue( T&& type, I&&... instrs )
{
auto is = make_shared< InstrSeq >();
AppendToInstrSeq( *is, forward< I >( instrs )... );
return eir::Value( forward< T >( type ),
make_shared< Instruction >( forward< I >( instr ) ) );
}
return eir::Value( forward< T >( type ), move( is ) );
}
template< size_t popCount, bool pushesResult >
class BaseInstr
{
public:
BaseInstr( LocationId loc ) :
m_loc( loc )
{}
void setLocationId( LocationId loc ) { m_loc = loc; }
auto locationId() const { return m_loc; }
static constexpr size_t PopCount = popCount;
static constexpr bool PushesResult = pushesResult;
private:
LocationId m_loc;
};
template< typename T >
class TempStorage
{
public:
TempStorage( size_t size ) :
m_storage( size )
{}
template< typename TT >
auto& set( uint32_t index, TT&& x )
T& set( uint32_t index, TT&& x )
{
auto [it, inserted] = m_storage.try_emplace( index );
it->second = forward< TT >( x );
return it->second;
if( index >= m_storage.size() )
m_storage.resize( index + 1 );
m_storage[index] = forward< TT >( x );
return m_storage[index];
}
const T* get( uint32_t index ) const
{
auto it = m_storage.find( index );
if( it == m_storage.end() )
return nullptr;
if( index < m_storage.size() )
return &m_storage[index];
return nullptr;
return &it->second;
}
T* get( uint32_t index )
{
auto it = m_storage.find( index );
if( it == m_storage.end() )
return nullptr;
if( index < m_storage.size() )
return &m_storage[index];
return nullptr;
return &it->second;
}
private:
unordered_map< uint32_t, T > m_storage;
llvm::SmallVector< T, 16 > m_storage;
};
}
#endif
|
Changes to bs/cir/instruction.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
|
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
|
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
-
-
-
-
-
+
-
-
-
-
-
+
-
-
-
-
-
-
+
-
+
-
+
-
+
-
+
-
-
+
-
-
-
+
-
-
-
-
-
-
+
+
+
+
+
+
-
+
-
-
+
-
-
-
|
#include "cir/cir.h"
namespace goose::cir
{
bool Instruction::canBeExecuted() const
{
return visit( []< typename ET >( const ET& e )
{
if constexpr( is_same_v< ET, monostate > )
return false;
else if constexpr( is_same_v< ET, ptr< CFG > > )
return e->canBeExecuted();
else
return e.canBeExecuted();
}, m_content );
}
bool Instruction::canBeEagerlyEvaluated() const
{
return visit( []< typename ET >( const ET& e )
{
if constexpr( is_same_v< ET, monostate > )
return false;
else if constexpr( is_same_v< ET, ptr< CFG > > )
return e->canBeEagerlyEvaluated();
else
return e.canBeEagerlyEvaluated();
}, m_content );
}
bool Instruction::haveSideEffects() const
{
return visit( []< typename ET >( const ET& e )
{
if constexpr( is_same_v< ET, monostate > )
return false;
else
return e.haveSideEffects();
}, m_content );
}
ostream& operator<<( ostream& out, const Instruction& inst )
{
return visit( [&]< typename ET >( const ET& e ) -> ostream&
{
if constexpr( is_same_v< ET, monostate > )
return out << "NIL";
else if constexpr( is_same_v< ET, ptr< CFG > > )
return out << "NESTED_CFG";
else
return out << e;
}, inst.m_content );
}
ostream& operator<<( ostream& out, const Select& ins )
{
out << "SELECT(" << ins.m_memberIndex << ", ";
out << "SELECT(" << ins.m_memberIndex;
if( ins.m_baseAddr )
out << *ins.m_baseAddr;
else
out << "null" ;
return out << ')';
return out << ')';
}
ostream& operator<<( ostream& out, const Load& ins )
{
out << "LOAD(";
if( ins.m_addr )
out << *ins.m_addr;
else
out << "null";
return out << ", " << ins.m_type << ')';
return out << ins.m_type << ')';
}
ostream& operator<<( ostream& out, const Store& ins )
{
out << "STORE(";
if( ins.m_addr )
out << *ins.m_addr;
else
out << "null";
return out << ", " << ins.m_val << ')';
return out << "STORE";
}
ostream& operator<<( ostream& out, const PHOverride& ins )
ostream& operator<<( ostream& out, const PHOverrideSet& ins )
{
return out << "PHOVERRIDE(" << ins.m_name << ", " << ins.m_phVal << ", " << ins.m_val << ')';
return out << "PHOVERRIDESET(" << ins.m_name << ')';
}
bool Store::canBeEagerlyEvaluated() const
ostream& operator<<( ostream& out, const PHOverrideClear& ins )
{
return m_addr && CanValueBeEagerlyEvaluated( m_val );
return out << "PHOVERRIDECLEAR(" << ins.m_name << ')';
}
bool Select::operator<( const Select& rhs ) const
{
if( m_memberIndex != rhs.m_memberIndex )
return m_memberIndex < rhs.m_memberIndex;
return m_memberIndex < rhs.m_memberIndex;
return *m_baseAddr < *rhs.m_baseAddr;
}
bool Load::operator<( const Load& rhs ) const
{
if( m_type != rhs.m_type )
return m_type < rhs.m_type;
return m_type < rhs.m_type;
return *m_addr < *rhs.m_addr;
}
bool Store::operator<( const Store& rhs ) const
{
if( m_type != rhs.m_type )
return m_type < rhs.m_type;
if( m_addr != rhs.m_addr )
return *m_addr < *rhs.m_addr;
return m_val < rhs.m_val;
return m_type < rhs.m_type;
}
bool PHOverrideSet::operator<( const PHOverrideSet& rhs ) const
{
return m_name < rhs.m_name;
}
bool PHOverride::operator<( const PHOverride& rhs ) const
bool PHOverrideClear::operator<( const PHOverrideClear& rhs ) const
{
if( m_name != rhs.m_name )
return m_name < rhs.m_name;
return m_name < rhs.m_name;
if( m_phVal != rhs.m_phVal )
return m_phVal < rhs.m_phVal;
return m_val < rhs.m_val;
}
}
|
Changes to bs/cir/instruction.h.
| ︙ | | |
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
+
+
+
+
|
Instruction( TempAddr&& tad ) :
m_content( move( tad ) )
{}
Instruction( Select&& sel ) :
m_content( move( sel ) )
{}
Instruction( Constant&& cst ) :
m_content( move( cst ) )
{}
Instruction( CreateTemporary&& ct ) :
m_content( move( ct ) )
{}
Instruction( GetTemporary&& gt ) :
m_content( move( gt ) )
|
| ︙ | | |
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
|
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
|
-
+
+
+
+
+
+
|
m_content( move( x ) )
{}
Instruction( Placeholder&& x ) :
m_content( move( x ) )
{}
Instruction( PHOverride&& x ) :
Instruction( PHOverrideSet&& x ) :
m_content( move( x ) )
{}
Instruction( PHOverrideClear&& x ) :
m_content( move( x ) )
{}
Instruction( GhostCall&& x ) :
m_content( move( x ) )
{}
using Content = variant
<
monostate,
Call,
VarAddr,
TempAddr,
Select,
Constant,
CreateTemporary,
GetTemporary,
AllocVar,
Load,
Store,
Phi,
|
| ︙ | | |
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
|
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
|
+
-
+
-
-
-
-
+
|
SGT,
SGE,
SLT,
SLE,
Assert,
GhostCall,
PHOverrideSet,
PHOverride,
PHOverrideClear,
Placeholder
// WARNING AWFUL SHIT:
// If the last instruction changes, make sure to update the upper bound lookup in
// CFG::forEachAddressModifiedByLoop accordingly!
>;
const auto& content() const { return m_content; }
bool canBeExecuted() const;
bool canBeEagerlyEvaluated() const;
bool haveSideEffects() const;
friend ostream& operator<<( ostream& out, const Instruction& inst );
bool operator<( const Instruction& rhs ) const
{
return m_content < rhs.m_content;
}
|
| ︙ | | |
Changes 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
|
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_LOAD_H
#define GOOSE_CIR_LOAD_H
namespace goose::cir
{
class Load
class Load : public BaseInstr< 1, true >
{
public:
template< typename A, typename T >
Load( A&& addr, T&& type ) :
m_addr( forward< A >( addr ) ),
template< typename T >
Load( T&& type, LocationId loc ) :
BaseInstr( loc ),
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 true; }
bool haveSideEffects() const { return false; }
bool operator<( const Load& rhs ) const;
friend ostream& operator<<( ostream& out, const Load& ins );
private:
ptr< Instruction > m_addr;
eir::Term m_type;
};
}
#endif
|
Changes to bs/cir/logic.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
|
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
|
-
-
+
+
+
-
+
-
-
+
+
+
-
+
-
-
+
+
+
-
+
-
-
+
+
+
-
+
|
#ifndef GOOSE_CIR_LOGIC_H
#define GOOSE_CIR_LOGIC_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 ) ) {}
And( LocationId loc ) :
BinaryOp( loc )
{}
friend ostream& operator<<( ostream& out, const And& ins )
{
return ins.print( out, "AND" );
return out << "AND";
}
};
class Or : public BinaryOp
{
public:
template< typename L, typename R >
Or( L&& lhs, R&& rhs ) : BinaryOp( forward< L >( lhs ), forward< R >( rhs ) ) {}
Or( LocationId loc ) :
BinaryOp( loc )
{}
friend ostream& operator<<( ostream& out, const Or& ins )
{
return ins.print( out, "OR" );
return out << "OR";
}
};
class Xor : public BinaryOp
{
public:
template< typename L, typename R >
Xor( L&& lhs, R&& rhs ) : BinaryOp( forward< L >( lhs ), forward< R >( rhs ) ) {}
Xor( LocationId loc ) :
BinaryOp( loc )
{}
friend ostream& operator<<( ostream& out, const Xor& ins )
{
return ins.print( out, "XOR" );
return out << "XOR";
}
};
// Logical implication (to be used only for verification expression)
class Implies : public BinaryOp
{
public:
template< typename L, typename R >
Implies( L&& lhs, R&& rhs ) : BinaryOp( forward< L >( lhs ), forward< R >( rhs ) ) {}
Implies( LocationId loc ) :
BinaryOp( loc )
{}
friend ostream& operator<<( ostream& out, const Implies& ins )
{
return ins.print( out, "IMPLIES" );
return out << "IMPLIES";
}
};
}
#endif
|
Changes 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
|
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
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
|
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
-
+
-
-
-
-
-
-
+
-
-
-
-
-
-
+
+
+
|
#include "cir.h"
namespace goose::cir
{
// EvalStores is a tiny CIR InstrSeq evaluator that only considers store instructions
// to addresses whose path can be calculated entirely at compilation time
class AddrEvalStack
{
public:
template< typename T >
void push( T&& x )
{
m_stack.push( forward< T >( x ) );
}
bool pop()
{
if( m_stack.empty() )
return false;
m_stack.pop();
return true;
}
template< typename T >
optional< T > pop()
{
if( m_stack.empty() )
return nullopt;
if( !holds_alternative< T >( m_stack.top() ) )
return nullopt;
optional< T > result = move( get< T >( m_stack.top() ) );
m_stack.pop();
return result;
}
bool empty() const { return m_stack.empty(); }
private:
stack< variant< monostate, StorageLocation, Value > > m_stack;
};
template< typename I, typename F >
bool EvalStores( AddrEvalStack& stack, const I& instr, F&& storeHandler )
{
// For all the instructions we don't care about here,
// push/pop mock values on the stack to keep the stack layout
// as intended by the instruction sequence.
for( size_t i = 0; i < I::PopCount; ++i )
{
if( !stack.pop() )
return false;
}
if( I::PushesResult )
stack.push( monostate() );
return true;
}
template< typename F >
bool EvalStores( AddrEvalStack& stack, const monostate&, F&& storeHandler )
{
return true;
}
template< typename F >
bool EvalStores( AddrEvalStack& stack, const Constant& instr, F&& storeHandler )
{
stack.push( instr.value() );
return true;
}
template< typename F >
bool EvalStores( AddrEvalStack& stack, const Call& instr, F&& storeHandler )
{
if( !stack.pop() )
return false;
for( size_t i = 0; i < instr.numArgs(); ++i )
{
if( !stack.pop() )
return false;
}
stack.push( monostate() );
return true;
}
template< typename F >
bool EvalStores( AddrEvalStack& stack, const GhostCall& instr, F&& storeHandler )
{
auto gfunc = stack.pop< Value >();
if( !gfunc )
return false;
auto argCount = instr.numArgs();
GhostFuncApplication gfa( move( *gfunc ), instr.locationId() );
auto& args = gfa.args();
args.resize( argCount );
for( size_t i = 0; i < argCount; ++i )
{
variant< Value, Address > arg;
auto a = stack.pop< Value >();
if( a )
arg = move( *a );
else
{
auto a = stack.pop< StorageLocation >();
if( !a || holds_alternative< Address >( *a ) )
return false;
arg = move( get< Address >( *a ) );
}
args[argCount - i - 1] = move( arg );
}
stack.push( StorageLocation { move( gfa ) } );
return true;
}
template< typename F >
bool EvalStores( AddrEvalStack& stack, const VarAddr& instr, F&& storeHandler )
{
stack.push( Address( Address::Origin::Stack, instr.varIndex(), instr.locationId() ) );
return true;
}
template< typename F >
bool EvalStores( AddrEvalStack& stack, const TempAddr& instr, F&& storeHandler )
{
if( !stack.pop() )
return false;
stack.push( Address( Address::Origin::Stack, instr.tempIndex(), instr.locationId() ) );
return true;
}
template< typename F >
bool EvalStores( AddrEvalStack& stack, const Select& instr, F&& storeHandler )
{
if( stack.empty() )
return false;
auto baseAddr = stack.pop< StorageLocation >();
if( !baseAddr )
{
// Not an error, just means the base address comes from an indrection,
// or a function call and we don't handle this case here.
//
// TODO:
// Later we might either outright emit an error right here if this occurs
// inside of a loop because it means we can't verify it and risk a false
// positive. Or we could try and go the extra mile to represent
// the indirection in a way that can be verified.
return true;
}
if( !holds_alternative< Address >( *baseAddr ) )
return false;
stack.push( StorageLocation{
Address::Select( move( get< Address >( *baseAddr ) ),
instr.memberIndex(), instr.locationId() ) } );
return true;
}
template< typename F >
bool EvalStores( AddrEvalStack& stack, const Store& instr, F&& storeHandler )
{
if( !stack.pop() )
return false;
if( stack.empty() )
return false;
auto sloc = stack.pop< StorageLocation >();
if( !sloc )
{
// Not an error, see comment in the function above
return true;
}
storeHandler( instr.type(), *sloc );
return true;
}
template< typename F >
bool EvalStores( AddrEvalStack& stack, const Instruction& instr, F&& storeHandler )
{
return visit( [&]( auto&& i )
{
return EvalStores( stack, i, forward< F >( storeHandler ) );
}, instr.content() );
}
template< typename F >
bool EvalStores( const BasicBlock& bb, F&& storeHandler )
{
AddrEvalStack stack;
for( auto&& instr : bb.instructions() )
{
if( !EvalStores( stack, instr, storeHandler ) )
return false;
}
return true;
}
void MarkAddrChangedByLoop( const ptr< CFG >& cfg, uint32_t loopId, const eir::Term& type, const Instruction& addrCalculation )
void MarkSLocChangedByLoop( const ptr< CFG >& cfg, uint32_t loopId, const eir::Term& type, const StorageLocation& sloc )
{
cfg->setAddressModifiedByLoop( loopId, type, addrCalculation );
cfg->setStorageLocationModifiedByLoop( loopId, type, sloc );
const auto& pHeader = cfg->getBB( loopId );
if( pHeader->loopId() )
MarkAddrChangedByLoop( cfg, pHeader->loopId(), type, addrCalculation );
MarkSLocChangedByLoop( cfg, pHeader->loopId(), type, sloc );
}
void ComputeLoopModifiedAddrs( const ptr< CFG >& cfg )
{
cfg->forEachBB( [&]( auto&& bb )
{
if( !bb->loopId() )
return;
for( auto&& instr : *bb )
{
auto st = get_if< Store >( &instr.content() );
if( !st )
continue;
EvalStores( *bb, [&]( auto&& type, auto&& sloc )
auto cir = st->addr();
if( !cir )
continue;
MarkAddrChangedByLoop( cfg, bb->loopId(), st->val().type(), *cir );
}
{
MarkSLocChangedByLoop( cfg, bb->loopId(), type, sloc );
} );
} );
}
}
|
Changes to bs/cir/meson.build.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
-
-
+
|
goose_cir = library( 'goose-cir',
'cfg.cpp',
'dominators.cpp',
'loops.cpp',
'loopaddrs.cpp',
'instruction.cpp',
'binaryop.cpp',
'terminator.cpp',
'call.cpp',
'func.cpp',
'helpers.cpp',
'verifinstrfilter.cpp',
'hash.cpp',
'decorator.cpp',
'cfgviz.cpp',
include_directories: bsinc,
dependencies: [tracy_dep]
)
|
| ︙ | | |
Changes to bs/cir/not.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
|
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_NOT_H
#define GOOSE_CIR_NOT_H
namespace goose::cir
{
class Not
class Not : public BaseInstr< 1, true >
{
public:
template< typename T >
Not( T&& operand ) :
Not( LocationId loc ) :
m_operand( forward< T >( operand ) )
BaseInstr( loc )
{}
const auto& operand() const { return m_operand; }
bool canBeExecuted() const
bool canBeExecuted() const { return true; }
{
return IsValueConstantOrExecutable( m_operand );
}
bool canBeEagerlyEvaluated() const
bool canBeEagerlyEvaluated() const { return true; }
{
return CanValueBeEagerlyEvaluated( m_operand );
bool haveSideEffects() const { return false; }
}
bool operator<( const Not& rhs ) const
{
return m_operand < rhs.m_operand;
return false;
}
friend ostream& operator<<( ostream& out, const Not& ins )
{
return out << "NOT("<< ins.m_operand << ')';
return out << "NOT";
}
private:
eir::Value m_operand;
};
}
#endif
|
Changes to bs/cir/phi.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
-
+
-
+
+
|
#ifndef GOOSE_CIR_PHI_H
#define GOOSE_CIR_PHI_H
namespace goose::cir
{
class BasicBlock;
class Phi
class Phi : public BaseInstr< 0, false >
{
public:
template< typename T >
Phi( T&& type, uint32_t numIncomings, uint32_t destIndex ) :
Phi( T&& type, uint32_t numIncomings, uint32_t destIndex, LocationId loc ) :
BaseInstr( loc ),
m_type( forward< T >( type ) ),
m_destIndex( destIndex )
{
m_incomings.reserve( numIncomings );
}
const auto& type() const { return m_type; }
|
| ︙ | | |
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
+
|
if( !func( bb.lock(), val ) )
return;
}
}
bool canBeExecuted() const { return true; }
bool canBeEagerlyEvaluated() const { return true; }
bool haveSideEffects() const { return true; }
bool operator<( const Phi& rhs ) const
{
if( m_type != rhs.m_type )
return m_type < rhs.m_type;
return m_destIndex < rhs.m_destIndex;
|
| ︙ | | |
Changes to bs/cir/phoverride.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
|
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
|
-
+
-
-
+
-
-
-
+
+
+
+
-
-
+
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
-
-
|
#ifndef GOOSE_CIR_PHOVERRIDE_H
#define GOOSE_CIR_PHOVERRIDE_H
namespace goose::cir
{
// A pseudo instruction that defines an override value for a placeholder, to be applied to
// A pseudo instruction that defines an override value for a placeholder
// its contained value
class PHOverride
class PHOverrideSet : public BaseInstr< 1, false >
{
public:
template< typename S, typename P, typename V >
PHOverride( S&& name, P&& phVal, V&& val ) :
m_name( forward< S >( name ) ),
template< typename S >
PHOverrideSet( S&& name, LocationId loc ) :
BaseInstr( loc ),
m_name( forward< S >( name ) )
m_phVal( forward< P >( phVal ) ),
m_val( forward< V >( val ) )
{}
const auto& name() const { return m_name; }
// This can't be executed, it's only meant to appear
// in expressions handled by the verifier.
const auto& phVal() const { return m_phVal; }
const auto& val() const { return m_val; }
bool canBeExecuted() const { return false; }
bool canBeEagerlyEvaluated() const { return false; }
bool haveSideEffects() const { return false; }
bool operator<( const PHOverrideSet& rhs ) const;
friend ostream& operator<<( ostream& out, const PHOverrideSet& ins );
private:
StringId m_name;
};
// A pseudo instruction that clears an override value for a placeholder
class PHOverrideClear : public BaseInstr< 0, 0 >
{
public:
template< typename S >
PHOverrideClear( S&& name, LocationId loc ) :
BaseInstr( loc ),
m_name( forward< S >( name ) )
{}
const auto& name() const { return m_name; }
// This can't be executed, it's only meant to appear
// in expressions handled by the verifier.
bool canBeExecuted() const { return false; }
bool canBeEagerlyEvaluated() const { return false; }
bool haveSideEffects() const { return false; }
bool operator<( const PHOverride& rhs ) const;
friend ostream& operator<<( ostream& out, const PHOverride& ins );
bool operator<( const PHOverrideClear& rhs ) const;
friend ostream& operator<<( ostream& out, const PHOverrideClear& ins );
private:
StringId m_name;
eir::Value m_phVal;
eir::Value m_val;
};
}
#endif
|
Changes to bs/cir/placeholder.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
|
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
|
-
-
+
+
-
+
-
+
+
+
|
#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'
// A placeholder value with a name, to be replaced with something else.
// Intended to represent the @ return value placeholder in functions'
// post conditions.
class Placeholder
class Placeholder : public BaseInstr< 0, true >
{
public:
template< typename T, typename S >
Placeholder( T&& type, S&& name ) :
Placeholder( T&& type, S&& name, LocationId loc ) :
BaseInstr( loc ),
m_type( forward< T >( type ) ),
m_name( forward< S >( name ) )
{}
const auto& type() const { return m_type; }
const auto& name() const { return m_name; }
// This can't be executed, it's only meant to appear
// in expressions handled by the verifier.
bool canBeExecuted() const { return false; }
bool canBeEagerlyEvaluated() const { return false; }
bool haveSideEffects() const { return false; }
bool operator<( const Placeholder& rhs ) const
{
if( m_name != rhs.m_name )
return m_name < rhs.m_name;
return m_type < rhs.m_type;
}
|
| ︙ | | |
Changes to bs/cir/ret.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
|
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
|
-
+
-
-
+
+
-
-
-
-
+
+
-
-
-
-
+
+
+
+
+
+
+
-
-
+
+
-
-
+
+
+
+
+
+
+
+
+
-
+
|
#ifndef GOOSE_CIR_RET_H
#define GOOSE_CIR_RET_H
namespace goose::cir
{
class Ret
class RetVoid
{
public:
Ret() {}
RetVoid( LocationId loc ) :
m_loc( loc )
template< typename V >
Ret( V&& val ) :
m_value( forward< V >( val ) )
{}
const auto& value() const { return m_value; }
bool canBeExecuted() const { return true; }
bool canBeEagerlyEvaluated() const { return true; }
bool canBeExecuted() const
{
return !m_value || IsValueConstantOrExecutable( *m_value );
}
void addCFGEdges( const ptr< CFG >& cfg, uint32_t srcBBIndex ) {}
const auto& locationId() const { return m_loc; }
private:
LocationId m_loc;
};
bool canBeEagerlyEvaluated() const
{
class Ret
{
return !m_value || CanValueBeEagerlyEvaluated( *m_value );
}
public:
Ret( LocationId loc ) :
m_loc( loc )
{}
bool canBeExecuted() const { return true; }
bool canBeEagerlyEvaluated() const { return true; }
void addCFGEdges( const ptr< CFG >& cfg, uint32_t srcBBIndex ) {}
const auto& locationId() const { return m_loc; }
private:
optional< eir::Value > m_value;
LocationId m_loc;
};
}
#endif
|
Changes to bs/cir/select.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
|
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
|
-
+
-
-
-
+
+
-
-
-
-
-
+
-
|
#ifndef GOOSE_CIR_SELECT_H
#define GOOSE_CIR_SELECT_H
namespace goose::cir
{
class Select
class Select : public BaseInstr< 1, true >
{
public:
template< typename BA >
Select( BA&& baseAddr, uint32_t memberIndex ) :
m_baseAddr( forward< BA >( baseAddr ) ),
Select( uint32_t memberIndex, LocationId loc ) :
BaseInstr( loc ),
m_memberIndex( memberIndex )
{}
const auto& baseAddr() const
{
return m_baseAddr;
}
uint32_t memberIndex() const
{
return m_memberIndex;
}
bool canBeExecuted() const { return true; }
bool canBeEagerlyEvaluated() const { return false; }
bool haveSideEffects() const { return false; }
bool operator<( const Select& rhs ) const;
friend ostream& operator<<( ostream& out, const Select& ins );
private:
ptr< Instruction > m_baseAddr;
uint32_t m_memberIndex = 0;
};
}
#endif
|
Added bs/cir/storagelocation.h.