From 02c20698c9fa50c31d008ed8af7af3c330053e20 Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 20 Apr 2020 23:05:14 +0200 Subject: [PATCH] IR generation for constants. --- libsolidity/codegen/ir/IRGenerator.cpp | 12 +++++++- .../codegen/ir/IRGeneratorForStatements.cpp | 30 +++++++++++++++---- .../codegen/ir/IRGeneratorForStatements.h | 4 +++ .../accessor_for_const_state_variable.sol | 3 +- ...signment_to_const_var_involving_keccak.sol | 2 ++ .../constants/constant_string.sol | 2 ++ .../simple_constant_variables_test.sol | 2 ++ .../inherited_constant_state_var.sol | 2 ++ ...ment_to_const_var_involving_expression.sol | 2 ++ 9 files changed, 52 insertions(+), 7 deletions(-) diff --git a/libsolidity/codegen/ir/IRGenerator.cpp b/libsolidity/codegen/ir/IRGenerator.cpp index 620daa86e..bac4fea66 100644 --- a/libsolidity/codegen/ir/IRGenerator.cpp +++ b/libsolidity/codegen/ir/IRGenerator.cpp @@ -202,11 +202,11 @@ string IRGenerator::generateGetter(VariableDeclaration const& _varDecl) Type const* type = _varDecl.annotation().type; - solAssert(!_varDecl.isConstant(), ""); solAssert(_varDecl.isStateVariable(), ""); if (auto const* mappingType = dynamic_cast(type)) return m_context.functionCollector().createFunction(functionName, [&]() { + solAssert(!_varDecl.isConstant(), ""); pair slot_offset = m_context.storageLocationOfVariable(_varDecl); solAssert(slot_offset.second == 0, ""); FunctionType funType(_varDecl); @@ -268,6 +268,16 @@ string IRGenerator::generateGetter(VariableDeclaration const& _varDecl) ("id", to_string(_varDecl.id())) .render(); } + else if (_varDecl.isConstant()) + return Whiskers(R"( + function () -> { + := () + } + )") + ("functionName", functionName) + ("constantValueFunction", IRGeneratorForStatements(m_context, m_utils).constantValueFunction(_varDecl)) + ("ret", suffixedVariableNameList("ret_", 0, _varDecl.type()->sizeOnStack())) + .render(); else { pair slot_offset = m_context.storageLocationOfVariable(_varDecl); diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index f8c8b2956..cdb5f3c26 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -178,6 +178,28 @@ IRVariable IRGeneratorForStatements::evaluateExpression(Expression const& _expre return variable; } +string IRGeneratorForStatements::constantValueFunction(VariableDeclaration const& _constant) +{ + string functionName = "constant_" + _constant.name() + "_" + to_string(_constant.id()); + return m_context.functionCollector().createFunction(functionName, [&] { + Whiskers templ(R"( + function () -> { + + := + } + )"); + templ("functionName", functionName); + IRGeneratorForStatements generator(m_context, m_utils); + solAssert(_constant.value(), ""); + Type const& constantType = *_constant.type(); + templ("value", generator.evaluateExpression(*_constant.value(), constantType).commaSeparatedList()); + templ("code", generator.code()); + templ("ret", IRVariable("ret", constantType).commaSeparatedList()); + + return templ.render(); + }); +} + void IRGeneratorForStatements::endVisit(VariableDeclarationStatement const& _varDeclStatement) { if (Expression const* expression = _varDeclStatement.initialValue()) @@ -1576,11 +1598,9 @@ void IRGeneratorForStatements::handleVariableReference( Expression const& _referencingExpression ) { - // TODO for the constant case, we have to be careful: - // If the value is visited twice, `defineExpression` is called twice on - // the same expression. - solUnimplementedAssert(!_variable.isConstant(), ""); - if (_variable.isStateVariable() && _variable.immutable()) + if (_variable.isStateVariable() && _variable.isConstant()) + define(_referencingExpression) << constantValueFunction(_variable) << "()\n"; + else if (_variable.isStateVariable() && _variable.immutable()) setLValue(_referencingExpression, IRLValue{ *_variable.annotation().type, IRLValue::Immutable{&_variable} diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.h b/libsolidity/codegen/ir/IRGeneratorForStatements.h index b8fafd8b6..a35c09fbb 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.h +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.h @@ -54,6 +54,10 @@ public: /// Calculates expression's value and returns variable where it was stored IRVariable evaluateExpression(Expression const& _expression, Type const& _to); + /// @returns the name of a function that computes the value of the given constant + /// and also generates the function. + std::string constantValueFunction(VariableDeclaration const& _constant); + void endVisit(VariableDeclarationStatement const& _variableDeclaration) override; bool visit(Conditional const& _conditional) override; bool visit(Assignment const& _assignment) override; diff --git a/test/libsolidity/semanticTests/accessor/accessor_for_const_state_variable.sol b/test/libsolidity/semanticTests/accessor/accessor_for_const_state_variable.sol index a9402aa86..a56956a90 100644 --- a/test/libsolidity/semanticTests/accessor/accessor_for_const_state_variable.sol +++ b/test/libsolidity/semanticTests/accessor/accessor_for_const_state_variable.sol @@ -1,6 +1,7 @@ contract Lotto { uint256 public constant ticketPrice = 555; } - +// ==== +// compileViaYul: also // ---- // ticketPrice() -> 555 diff --git a/test/libsolidity/semanticTests/builtinFunctions/assignment_to_const_var_involving_keccak.sol b/test/libsolidity/semanticTests/builtinFunctions/assignment_to_const_var_involving_keccak.sol index 2fc479d0e..a1bdf3236 100644 --- a/test/libsolidity/semanticTests/builtinFunctions/assignment_to_const_var_involving_keccak.sol +++ b/test/libsolidity/semanticTests/builtinFunctions/assignment_to_const_var_involving_keccak.sol @@ -5,5 +5,7 @@ contract C { return x; } } +// ==== +// compileViaYul: also // ---- // f() -> 0x4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45 diff --git a/test/libsolidity/semanticTests/constants/constant_string.sol b/test/libsolidity/semanticTests/constants/constant_string.sol index 56cbf982d..6b588571d 100644 --- a/test/libsolidity/semanticTests/constants/constant_string.sol +++ b/test/libsolidity/semanticTests/constants/constant_string.sol @@ -16,6 +16,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f() -> 0x20, 3, "\x03\x01\x02" // g() -> 0x20, 3, "\x03\x01\x02" diff --git a/test/libsolidity/semanticTests/constants/simple_constant_variables_test.sol b/test/libsolidity/semanticTests/constants/simple_constant_variables_test.sol index c05060b7e..613cf62bb 100644 --- a/test/libsolidity/semanticTests/constants/simple_constant_variables_test.sol +++ b/test/libsolidity/semanticTests/constants/simple_constant_variables_test.sol @@ -6,5 +6,7 @@ contract Foo { uint256 constant x = 56; } +// ==== +// compileViaYul: also // ---- // getX() -> 56 diff --git a/test/libsolidity/semanticTests/intheritance/inherited_constant_state_var.sol b/test/libsolidity/semanticTests/intheritance/inherited_constant_state_var.sol index e25db0dcb..ab7a097cc 100644 --- a/test/libsolidity/semanticTests/intheritance/inherited_constant_state_var.sol +++ b/test/libsolidity/semanticTests/intheritance/inherited_constant_state_var.sol @@ -9,5 +9,7 @@ contract B is A { } } +// ==== +// compileViaYul: also // ---- // f() -> 7 diff --git a/test/libsolidity/semanticTests/various/assignment_to_const_var_involving_expression.sol b/test/libsolidity/semanticTests/various/assignment_to_const_var_involving_expression.sol index b83b1c598..4f849be89 100644 --- a/test/libsolidity/semanticTests/various/assignment_to_const_var_involving_expression.sol +++ b/test/libsolidity/semanticTests/various/assignment_to_const_var_involving_expression.sol @@ -6,5 +6,7 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f() -> 0x57a