/* This file is part of solidity. solidity is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. solidity is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with solidity. If not, see . */ #include #include #include #include #include using namespace std; using namespace dev; using namespace yul; void WordSizeTransform::operator()(FunctionDefinition& _fd) { rewriteVarDeclList(_fd.parameters); rewriteVarDeclList(_fd.returnVariables); (*this)(_fd.body); } void WordSizeTransform::operator()(FunctionalInstruction& _ins) { rewriteFunctionCallArguments(_ins.arguments); } void WordSizeTransform::operator()(FunctionCall& _fc) { rewriteFunctionCallArguments(_fc.arguments); } void WordSizeTransform::operator()(If& _if) { _if.condition = make_unique(FunctionCall{ locationOf(*_if.condition), Identifier{locationOf(*_if.condition), "or_bool"_yulstring}, // TODO make sure this is not used expandValueToVector(*_if.condition) }); (*this)(_if.body); } void WordSizeTransform::operator()(Switch&) { yulAssert(false, "Switch statement not implemented."); } void WordSizeTransform::operator()(Block& _block) { iterateReplacing( _block.statements, [&](Statement& _s) -> boost::optional> { if (_s.type() == typeid(VariableDeclaration)) { VariableDeclaration& varDecl = boost::get(_s); if ( !varDecl.value || varDecl.value->type() == typeid(FunctionalInstruction) || varDecl.value->type() == typeid(FunctionCall) ) { if (varDecl.value) visit(*varDecl.value); rewriteVarDeclList(varDecl.variables); return boost::none; } else if ( varDecl.value->type() == typeid(Identifier) || varDecl.value->type() == typeid(Literal) ) { yulAssert(varDecl.variables.size() == 1, ""); auto newRhs = expandValue(*varDecl.value); auto newLhs = generateU64IdentifierNames(varDecl.variables[0].name); vector ret; for (int i = 0; i < 4; i++) ret.push_back( VariableDeclaration{ varDecl.location, {TypedName{varDecl.location, newLhs[i], "u64"_yulstring}}, std::move(newRhs[i]) } ); return ret; } else yulAssert(false, ""); } else if (_s.type() == typeid(Assignment)) { Assignment& assignment = boost::get(_s); yulAssert(assignment.value, ""); if ( assignment.value->type() == typeid(FunctionalInstruction) || assignment.value->type() == typeid(FunctionCall) ) { if (assignment.value) visit(*assignment.value); rewriteIdentifierList(assignment.variableNames); return boost::none; } else if ( assignment.value->type() == typeid(Identifier) || assignment.value->type() == typeid(Literal) ) { yulAssert(assignment.variableNames.size() == 1, ""); auto newRhs = expandValue(*assignment.value); YulString lhsName = assignment.variableNames[0].name; vector ret; for (int i = 0; i < 4; i++) ret.push_back( Assignment{ assignment.location, {Identifier{assignment.location, m_variableMapping.at(lhsName)[i]}}, std::move(newRhs[i]) } ); return ret; } else yulAssert(false, ""); } else visit(_s); return boost::none; } ); } void WordSizeTransform::run(Block& _ast, NameDispenser& _nameDispenser) { WordSizeTransform{_nameDispenser}(_ast); } void WordSizeTransform::rewriteVarDeclList(TypedNameList& _nameList) { iterateReplacing( _nameList, [&](TypedName const& _n) -> boost::optional { TypedNameList ret; for (auto newName: generateU64IdentifierNames(_n.name)) ret.emplace_back(TypedName{_n.location, newName, "u64"_yulstring}); return ret; } ); } void WordSizeTransform::rewriteIdentifierList(vector& _ids) { iterateReplacing( _ids, [&](Identifier const& _id) -> boost::optional> { vector ret; for (auto newId: m_variableMapping.at(_id.name)) ret.push_back(Identifier{_id.location, newId}); return ret; } ); } void WordSizeTransform::rewriteFunctionCallArguments(vector& _args) { iterateReplacing( _args, [&](Expression& _e) -> boost::optional> { return expandValueToVector(_e); } ); } array WordSizeTransform::generateU64IdentifierNames(YulString const& _s) { yulAssert(m_variableMapping.find(_s) == m_variableMapping.end(), ""); for (int i = 0; i < 4; i++) m_variableMapping[_s][i] = m_nameDispenser.newName(YulString{_s.str() + "_" + to_string(i)}); return m_variableMapping[_s]; } array, 4> WordSizeTransform::expandValue(Expression const& _e) { array, 4> ret; if (_e.type() == typeid(Identifier)) { Identifier const& id = boost::get(_e); for (int i = 0; i < 4; i++) ret[i] = make_unique(Identifier{id.location, m_variableMapping.at(id.name)[i]}); } else if (_e.type() == typeid(Literal)) { Literal const& lit = boost::get(_e); u256 val = valueOfLiteral(lit); for (int i = 3; i >= 0; i--) { u256 currentVal = val & std::numeric_limits::max(); val >>= 64; ret[i] = make_unique( Literal{ lit.location, LiteralKind::Number, YulString(currentVal.str()), "u64"_yulstring } ); } } else yulAssert(false, ""); return ret; } vector WordSizeTransform::expandValueToVector(Expression const& _e) { vector ret; for (unique_ptr& val: expandValue(_e)) ret.emplace_back(std::move(*val)); return ret; }