diff --git a/libyul/CMakeLists.txt b/libyul/CMakeLists.txt
index b70d813b4..2e04bf9be 100644
--- a/libyul/CMakeLists.txt
+++ b/libyul/CMakeLists.txt
@@ -40,6 +40,8 @@ add_library(yul
backends/evm/NoOutputAssembly.cpp
backends/wasm/WasmDialect.cpp
backends/wasm/WasmDialect.h
+ backends/wasm/WordSizeTransform.cpp
+ backends/wasm/WordSizeTransform.h
optimiser/ASTCopier.cpp
optimiser/ASTCopier.h
optimiser/ASTWalker.cpp
diff --git a/libyul/backends/wasm/WordSizeTransform.cpp b/libyul/backends/wasm/WordSizeTransform.cpp
new file mode 100644
index 000000000..d99d4cc26
--- /dev/null
+++ b/libyul/backends/wasm/WordSizeTransform.cpp
@@ -0,0 +1,238 @@
+/*
+ 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&)
+{
+ yulAssert(false, "If statement not implemented.");
+}
+
+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;
+ yulAssert(m_variableMapping.find(_n.name) == m_variableMapping.end(), "");
+ for (int i = 0; i < 4; i++)
+ {
+ auto newName = m_nameDispenser.newName(_n.name);
+ m_variableMapping[_n.name][i] = newName;
+ ret.push_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>
+ {
+ // ExpressionSplitter guarantees arguments to be Identifier or Literal
+ yulAssert(_e.type() == typeid(Identifier) || _e.type() == typeid(Literal), "");
+ vector ret;
+ for (auto& v: expandValue(_e))
+ ret.push_back(*v);
+ return ret;
+ }
+ );
+}
+
+array WordSizeTransform::generateU64IdentifierNames(YulString const& _s)
+{
+ yulAssert(m_variableMapping.find(_s) == m_variableMapping.end(), "");
+ array ret;
+ for (int i = 0; i < 4; i++)
+ {
+ auto newName = m_nameDispenser.newName(_s);
+ m_variableMapping[_s][i] = newName;
+ ret[i] = newName;
+ }
+ return ret;
+}
+
+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;
+}
+
diff --git a/libyul/backends/wasm/WordSizeTransform.h b/libyul/backends/wasm/WordSizeTransform.h
new file mode 100644
index 000000000..a9f480551
--- /dev/null
+++ b/libyul/backends/wasm/WordSizeTransform.h
@@ -0,0 +1,81 @@
+/*
+ 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 .
+*/
+/**
+ * Replace every u256 variable with four u64 variables.
+ */
+
+#pragma once
+
+#include
+#include
+
+#include
+#include
+
+namespace yul
+{
+
+/**
+ * A stage that replace every u256 variable with four u64 variables.
+ * This transformation stage is required because values in EVM are 256 bits,
+ * but wasm only supports values up to 64 bits, so we use four u64 values to simulate
+ * one u256 value.
+ *
+ * For FunctionalInstruction that accepts or returns u256 values, they accepts or returns
+ * four times the number of values after this transformation, with the order of significance,
+ * from the most significant to the least significant.
+ *
+ * For example, the FunctionalInstruction MUL supplied by code generator
+ * should take 8 arguments and return 4 values (instead of 2 and 1) after this transformation.
+ *
+ * mul(a1, a2, a3, a4, b1, b2, b3, b4) -> c1, c2, c3, c4
+ *
+ * the value of c4 should be
+ * ((a1*(2^192) + a2*(2^128) + a3(2^64) + a4) * (b1*(2^192) + b2*(2^128) + b3(2^64) + b4)) & ((1<<64)-1)
+ *
+ * Prerequisite: Disambiguator, ExpressionSplitter
+ */
+class WordSizeTransform: public ASTModifier
+{
+public:
+ void operator()(FunctionDefinition&) override;
+ void operator()(FunctionalInstruction&) override;
+ void operator()(FunctionCall&) override;
+ void operator()(If&) override;
+ void operator()(Switch&) override;
+ void operator()(Block& _block) override;
+
+ static void run(Block& _ast, NameDispenser& _nameDispenser);
+
+private:
+ explicit WordSizeTransform(NameDispenser& _nameDispenser):
+ m_nameDispenser(_nameDispenser)
+ { }
+
+ void rewriteVarDeclList(std::vector&);
+ void rewriteIdentifierList(std::vector&);
+ void rewriteFunctionCallArguments(std::vector&);
+
+ std::array generateU64IdentifierNames(YulString const& _s);
+ std::array, 4> expandValue(Expression const& _e);
+
+ NameDispenser& m_nameDispenser;
+ /// maps original u256 variable's name to corresponding u64 variables' names
+ std::map> m_variableMapping;
+};
+
+}