33
33
#include < libsolidity/experimental/codegen/Common.h>
34
34
35
35
#include < range/v3/view/drop_last.hpp>
36
+ #include < range/v3/view/zip.hpp>
36
37
37
38
using namespace solidity ;
38
39
using namespace solidity ::util;
@@ -101,7 +102,7 @@ struct CopyTranslate: public yul::ASTCopier
101
102
auto type = m_context.analysis .annotation <TypeInference>(*varDecl).type ;
102
103
solAssert (type);
103
104
solAssert (m_context.env ->typeEquals (*type, m_context.analysis .typeSystem ().type (PrimitiveType::Word, {})));
104
- std::string value = IRNames::localVariable (*varDecl );
105
+ std::string value = IRVariable{*varDecl, *type, IRGeneratorForStatements::stackSize (m_context, *type)}. name ( );
105
106
return yul::Identifier{_identifier.debugData , yul::YulString{value}};
106
107
}
107
108
@@ -112,14 +113,75 @@ struct CopyTranslate: public yul::ASTCopier
112
113
113
114
}
114
115
116
+ std::size_t IRGeneratorForStatements::stackSize (IRGenerationContext const & _context, Type _type)
117
+ {
118
+ TypeSystemHelpers helper{_context.analysis .typeSystem ()};
119
+ _type = _context.env ->resolve (_type);
120
+ solAssert (std::holds_alternative<TypeConstant>(_type), " No monomorphized type." );
121
+
122
+ // type -> # stack slots
123
+ // unit, itself -> 0
124
+ // void, literals(integer), typeFunction -> error (maybe generate a revert)
125
+ // word, bool, function -> 1
126
+ // pair -> sum(stackSize(args))
127
+ // user-defined -> stackSize(underlying type)
128
+ TypeConstant typeConstant = std::get<TypeConstant>(_type);
129
+ if (
130
+ helper.isPrimitiveType (_type, PrimitiveType::Unit) ||
131
+ helper.isPrimitiveType (_type, PrimitiveType::Itself)
132
+ )
133
+ return 0 ;
134
+ else if (
135
+ helper.isPrimitiveType (_type, PrimitiveType::Bool) ||
136
+ helper.isPrimitiveType (_type, PrimitiveType::Word)
137
+ )
138
+ {
139
+ solAssert (typeConstant.arguments .empty (), " Primitive type Bool or Word should have no arguments." );
140
+ return 1 ;
141
+ }
142
+ else if (helper.isFunctionType (_type))
143
+ return 1 ;
144
+ else if (
145
+ helper.isPrimitiveType (_type, PrimitiveType::Integer) ||
146
+ helper.isPrimitiveType (_type, PrimitiveType::Void) ||
147
+ helper.isPrimitiveType (_type, PrimitiveType::TypeFunction)
148
+ )
149
+ solAssert (false , " Attempted to query the stack size of a type without stack representation." );
150
+ else if (helper.isPrimitiveType (_type, PrimitiveType::Pair))
151
+ {
152
+ solAssert (typeConstant.arguments .size () == 2 );
153
+ return stackSize (_context, typeConstant.arguments .front ()) + stackSize (_context, typeConstant.arguments .back ());
154
+ }
155
+ else
156
+ {
157
+ Type underlyingType = _context.env ->resolve (
158
+ _context.analysis .annotation <TypeInference>().underlyingTypes .at (typeConstant.constructor ));
159
+ if (helper.isTypeConstant (underlyingType))
160
+ return stackSize (_context, underlyingType);
161
+
162
+ TypeEnvironment env = _context.env ->clone ();
163
+ Type genericFunctionType = helper.typeFunctionType (
164
+ helper.tupleType (typeConstant.arguments ),
165
+ env.typeSystem ().freshTypeVariable ({}));
166
+ solAssert (env.unify (genericFunctionType, underlyingType).empty ());
167
+
168
+ Type resolvedType = env.resolveRecursive (genericFunctionType);
169
+ auto [argumentType, resultType] = helper.destTypeFunctionType (resolvedType);
170
+ return stackSize (_context, resultType);
171
+ }
172
+
173
+ // TODO: sum types
174
+ return 0 ;
175
+ }
176
+
115
177
bool IRGeneratorForStatements::visit (TupleExpression const & _tupleExpression)
116
178
{
117
179
std::vector<std::string> components;
118
180
for (auto const & component: _tupleExpression.components ())
119
181
{
120
182
solUnimplementedAssert (component);
121
183
component->accept (*this );
122
- components.emplace_back (IRNames::localVariable (*component));
184
+ components.emplace_back (var (*component). commaSeparatedList ( ));
123
185
}
124
186
125
187
solUnimplementedAssert (false , " No support for tuples." );
@@ -144,10 +206,11 @@ bool IRGeneratorForStatements::visit(VariableDeclarationStatement const& _variab
144
206
VariableDeclaration const * variableDeclaration = _variableDeclarationStatement.declarations ().front ().get ();
145
207
solAssert (variableDeclaration);
146
208
// TODO: check the type of the variable; register local variable; initialize
147
- m_code << " let " << IRNames::localVariable (*variableDeclaration);
148
209
if (_variableDeclarationStatement.initialValue ())
149
- m_code << " := " << IRNames::localVariable (*_variableDeclarationStatement.initialValue ());
150
- m_code << " \n " ;
210
+ define (var (*variableDeclaration), var (*_variableDeclarationStatement.initialValue ()));
211
+ else
212
+ declare (var (*variableDeclaration));
213
+
151
214
return false ;
152
215
}
153
216
@@ -158,10 +221,8 @@ bool IRGeneratorForStatements::visit(ExpressionStatement const&)
158
221
159
222
bool IRGeneratorForStatements::visit (Identifier const & _identifier)
160
223
{
161
- if (auto const * var = dynamic_cast <VariableDeclaration const *>(_identifier.annotation ().referencedDeclaration ))
162
- {
163
- m_code << " let " << IRNames::localVariable (_identifier) << " := " << IRNames::localVariable (*var) << " \n " ;
164
- }
224
+ if (auto const * variable = dynamic_cast <VariableDeclaration const *>(_identifier.annotation ().referencedDeclaration ))
225
+ define (var (_identifier), var (*variable));
165
226
else if (auto const * function = dynamic_cast <FunctionDefinition const *>(_identifier.annotation ().referencedDeclaration ))
166
227
solAssert (m_expressionDeclaration.emplace (&_identifier, function).second );
167
228
else if (auto const * typeClass = dynamic_cast <TypeClassDefinition const *>(_identifier.annotation ().referencedDeclaration ))
@@ -179,7 +240,8 @@ void IRGeneratorForStatements::endVisit(Return const& _return)
179
240
{
180
241
solAssert (_return.annotation ().function , " Invalid return." );
181
242
solAssert (_return.annotation ().function ->experimentalReturnExpression (), " Invalid return." );
182
- m_code << IRNames::localVariable (*_return.annotation ().function ->experimentalReturnExpression ()) << " := " << IRNames::localVariable (*value) << " \n " ;
243
+ auto returnExpression = _return.annotation ().function ->experimentalReturnExpression ();
244
+ assign (var (*returnExpression), var (*value));
183
245
}
184
246
185
247
m_code << " leave\n " ;
@@ -201,13 +263,44 @@ void IRGeneratorForStatements::endVisit(BinaryOperation const& _binaryOperation)
201
263
Type functionType = helper.functionType (helper.tupleType ({leftType, rightType}), resultType);
202
264
auto [typeClass, memberName] = m_context.analysis .annotation <TypeInference>().operators .at (_binaryOperation.getOperator ());
203
265
auto const & functionDefinition = resolveTypeClassFunction (typeClass, memberName, functionType);
204
- // TODO: deduplicate with FunctionCall
266
+ std::string result = var (_binaryOperation).commaSeparatedList ();
267
+ if (!result.empty ())
268
+ m_code << " let " << result << " := " ;
269
+ m_code << buildFunctionCall (functionDefinition, functionType, _binaryOperation.arguments ());
270
+ }
271
+
272
+ std::string IRGeneratorForStatements::buildFunctionCall (FunctionDefinition const & _functionDefinition, Type _functionType, std::vector<ASTPointer<Expression const >> const & _arguments)
273
+ {
274
+ // Ensure type is resolved
205
275
// TODO: get around resolveRecursive by passing the environment further down?
206
- functionType = m_context.env ->resolveRecursive (functionType);
207
- m_context.enqueueFunctionDefinition (&functionDefinition, functionType);
208
- // TODO: account for return stack size
209
- m_code << " let " << IRNames::localVariable (_binaryOperation) << " := " << IRNames::function (*m_context.env , functionDefinition, functionType) << " ("
210
- << IRNames::localVariable (_binaryOperation.leftExpression ()) << " , " << IRNames::localVariable (_binaryOperation.rightExpression ()) << " )\n " ;
276
+ Type resolvedFunctionType = m_context.env ->resolveRecursive (_functionType);
277
+ m_context.enqueueFunctionDefinition (&_functionDefinition, resolvedFunctionType);
278
+
279
+ std::ostringstream output;
280
+ output << IRNames::function (*m_context.env , _functionDefinition, resolvedFunctionType) << " (" ;
281
+ if (_arguments.size () == 1 )
282
+ output << var (*_arguments.back ()).commaSeparatedList ();
283
+ else if (_arguments.size () > 1 )
284
+ {
285
+ for (auto arg: _arguments | ranges::views::drop_last (1 ))
286
+ output << var (*arg).commaSeparatedList ();
287
+ output << var (*_arguments.back ()).commaSeparatedListPrefixed ();
288
+ }
289
+ output << " )\n " ;
290
+ return output.str ();
291
+ }
292
+
293
+ void IRGeneratorForStatements::assign (IRVariable const & _lhs, IRVariable const & _rhs, bool _declare)
294
+ {
295
+ solAssert (stackSize (m_context, _lhs.type ()) == stackSize (m_context, _rhs.type ()));
296
+ for (auto && [lhsSlot, rhsSlot]: ranges::zip_view (_lhs.stackSlots (), _rhs.stackSlots ()))
297
+ m_code << (_declare ? " let " : " " ) << lhsSlot << " := " << rhsSlot << " \n " ;
298
+ }
299
+
300
+ void IRGeneratorForStatements::declare (IRVariable const & _var)
301
+ {
302
+ if (_var.stackSize () > 0 )
303
+ m_code << " let " << _var.commaSeparatedList () << " \n " ;
211
304
}
212
305
213
306
namespace
@@ -308,32 +401,23 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
308
401
case Builtins::FromBool:
309
402
case Builtins::Identity:
310
403
solAssert (_functionCall.arguments ().size () == 1 );
311
- m_code << " let " << IRNames::localVariable ( _functionCall) << " := " << IRNames::localVariable (*_functionCall.arguments ().front ()) << " \n " ;
404
+ define ( var ( _functionCall), var (*_functionCall.arguments ().front ())) ;
312
405
return ;
313
406
case Builtins::ToBool:
314
407
solAssert (_functionCall.arguments ().size () == 1 );
315
- m_code << " let " << IRNames::localVariable (_functionCall) << " := iszero(iszero(" << IRNames::localVariable (*_functionCall.arguments ().front ()) << " ))\n " ;
408
+ m_code << " let " << var (_functionCall). name () << " := iszero(iszero(" << var (*_functionCall.arguments ().front ()). name ( ) << " ))\n " ;
316
409
return ;
317
410
}
318
411
solAssert (false );
319
412
}
320
413
FunctionDefinition const * functionDefinition = dynamic_cast <FunctionDefinition const *>(std::get<Declaration const *>(declaration));
321
414
solAssert (functionDefinition);
322
- // TODO: get around resolveRecursive by passing the environment further down?
323
- functionType = m_context.env ->resolveRecursive (functionType);
324
- m_context.enqueueFunctionDefinition (functionDefinition, functionType);
325
415
// TODO: account for return stack size
326
416
solAssert (!functionDefinition->returnParameterList ());
327
- if (functionDefinition->experimentalReturnExpression ())
328
- m_code << " let " << IRNames::localVariable (_functionCall) << " := " ;
329
- m_code << IRNames::function (*m_context.env , *functionDefinition, functionType) << " (" ;
330
- auto const & arguments = _functionCall.arguments ();
331
- if (arguments.size () > 1 )
332
- for (auto arg: arguments | ranges::views::drop_last (1 ))
333
- m_code << IRNames::localVariable (*arg) << " , " ;
334
- if (!arguments.empty ())
335
- m_code << IRNames::localVariable (*arguments.back ());
336
- m_code << " )\n " ;
417
+ std::string result = var (_functionCall).commaSeparatedList ();
418
+ if (!result.empty ())
419
+ m_code << " let " << result << " := " ;
420
+ m_code << buildFunctionCall (*functionDefinition, functionType, _functionCall.arguments ());
337
421
}
338
422
339
423
bool IRGeneratorForStatements::visit (FunctionCall const &)
@@ -356,7 +440,7 @@ bool IRGeneratorForStatements::visit(IfStatement const& _ifStatement)
356
440
_ifStatement.condition ().accept (*this );
357
441
if (_ifStatement.falseStatement ())
358
442
{
359
- m_code << " switch " << IRNames::localVariable (_ifStatement.condition ()) << " {\n " ;
443
+ m_code << " switch " << var (_ifStatement.condition ()). name ( ) << " {\n " ;
360
444
m_code << " case 0 {\n " ;
361
445
_ifStatement.falseStatement ()->accept (*this );
362
446
m_code << " }\n " ;
@@ -366,7 +450,7 @@ bool IRGeneratorForStatements::visit(IfStatement const& _ifStatement)
366
450
}
367
451
else
368
452
{
369
- m_code << " if " << IRNames::localVariable (_ifStatement.condition ()) << " {\n " ;
453
+ m_code << " if " << var (_ifStatement.condition ()). name ( ) << " {\n " ;
370
454
_ifStatement.trueStatement ().accept (*this );
371
455
m_code << " }\n " ;
372
456
}
@@ -380,9 +464,8 @@ bool IRGeneratorForStatements::visit(Assignment const& _assignment)
380
464
solAssert (lhs, " Can only assign to identifiers." );
381
465
auto const * lhsVar = dynamic_cast <VariableDeclaration const *>(lhs->annotation ().referencedDeclaration );
382
466
solAssert (lhsVar, " Can only assign to identifiers referring to variables." );
383
- m_code << IRNames::localVariable (*lhsVar) << " := " << IRNames::localVariable (_assignment.rightHandSide ()) << " \n " ;
384
-
385
- m_code << " let " << IRNames::localVariable (_assignment) << " := " << IRNames::localVariable (*lhsVar) << " \n " ;
467
+ assign (var (*lhsVar), var (_assignment.rightHandSide ()));
468
+ define (var (_assignment), var (*lhsVar));
386
469
return false ;
387
470
}
388
471
0 commit comments