mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #7797 from ethereum/allowTranslationInAssemblyMode
Allow EVM to EWasm translation in assembly mode.
This commit is contained in:
commit
c61ed0b22d
@ -6,6 +6,7 @@ Language Features:
|
|||||||
|
|
||||||
|
|
||||||
Compiler Features:
|
Compiler Features:
|
||||||
|
* Commandline Interface: Allow translation from yul / strict assembly to EWasm using ``solc --yul --yul-dialect evm --machine eWasm``
|
||||||
* SMTChecker: Add support to constructors including constructor inheritance.
|
* SMTChecker: Add support to constructors including constructor inheritance.
|
||||||
* Yul: When compiling via Yul, string literals from the Solidity code are kept as string literals if every character is safely printable.
|
* Yul: When compiling via Yul, string literals from the Solidity code are kept as string literals if every character is safely printable.
|
||||||
* Yul Optimizer: Perform loop-invariant code motion.
|
* Yul Optimizer: Perform loop-invariant code motion.
|
||||||
|
@ -1060,25 +1060,17 @@ void CompilerStack::generateEWasm(ContractDefinition const& _contract)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// Re-parse the Yul IR in EVM dialect
|
// Re-parse the Yul IR in EVM dialect
|
||||||
yul::AssemblyStack evmStack(m_evmVersion, yul::AssemblyStack::Language::StrictAssembly, m_optimiserSettings);
|
yul::AssemblyStack stack(m_evmVersion, yul::AssemblyStack::Language::StrictAssembly, m_optimiserSettings);
|
||||||
evmStack.parseAndAnalyze("", compiledContract.yulIROptimized);
|
stack.parseAndAnalyze("", compiledContract.yulIROptimized);
|
||||||
|
|
||||||
// Turn into eWasm dialect
|
stack.optimize();
|
||||||
yul::Object ewasmObject = yul::EVMToEWasmTranslator(
|
stack.translate(yul::AssemblyStack::Language::EWasm);
|
||||||
yul::EVMDialect::strictAssemblyForEVMObjects(m_evmVersion)
|
stack.optimize();
|
||||||
).run(*evmStack.parserResult());
|
|
||||||
|
|
||||||
// Re-inject into an assembly stack for the eWasm dialect
|
//cout << yul::AsmPrinter{}(*stack.parserResult()->code) << endl;
|
||||||
yul::AssemblyStack ewasmStack(m_evmVersion, yul::AssemblyStack::Language::EWasm, m_optimiserSettings);
|
|
||||||
// TODO this is a hack for now - provide as structured AST!
|
|
||||||
ewasmStack.parseAndAnalyze("", "{}");
|
|
||||||
*ewasmStack.parserResult() = move(ewasmObject);
|
|
||||||
ewasmStack.optimize();
|
|
||||||
|
|
||||||
//cout << yul::AsmPrinter{}(*ewasmStack.parserResult()->code) << endl;
|
|
||||||
|
|
||||||
// Turn into eWasm text representation.
|
// Turn into eWasm text representation.
|
||||||
auto result = ewasmStack.assemble(yul::AssemblyStack::Machine::eWasm);
|
auto result = stack.assemble(yul::AssemblyStack::Machine::eWasm);
|
||||||
compiledContract.eWasm = std::move(result.assembly);
|
compiledContract.eWasm = std::move(result.assembly);
|
||||||
compiledContract.eWasmObject = std::move(*result.bytecode);
|
compiledContract.eWasmObject = std::move(*result.bytecode);
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
#include <libyul/backends/evm/EVMMetrics.h>
|
#include <libyul/backends/evm/EVMMetrics.h>
|
||||||
#include <libyul/backends/wasm/WasmDialect.h>
|
#include <libyul/backends/wasm/WasmDialect.h>
|
||||||
#include <libyul/backends/wasm/EWasmObjectCompiler.h>
|
#include <libyul/backends/wasm/EWasmObjectCompiler.h>
|
||||||
|
#include <libyul/backends/wasm/EVMToEWasmTranslator.h>
|
||||||
#include <libyul/optimiser/Metrics.h>
|
#include <libyul/optimiser/Metrics.h>
|
||||||
#include <libyul/ObjectParser.h>
|
#include <libyul/ObjectParser.h>
|
||||||
#include <libyul/optimiser/Suite.h>
|
#include <libyul/optimiser/Suite.h>
|
||||||
@ -102,6 +103,23 @@ void AssemblyStack::optimize()
|
|||||||
solAssert(analyzeParsed(), "Invalid source code after optimization.");
|
solAssert(analyzeParsed(), "Invalid source code after optimization.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AssemblyStack::translate(AssemblyStack::Language _targetLanguage)
|
||||||
|
{
|
||||||
|
if (m_language == _targetLanguage)
|
||||||
|
return;
|
||||||
|
|
||||||
|
solAssert(
|
||||||
|
m_language == Language::StrictAssembly && _targetLanguage == Language::EWasm,
|
||||||
|
"Invalid language combination"
|
||||||
|
);
|
||||||
|
|
||||||
|
*m_parserResult = EVMToEWasmTranslator(
|
||||||
|
languageToDialect(m_language, m_evmVersion)
|
||||||
|
).run(*parserResult());
|
||||||
|
|
||||||
|
m_language = _targetLanguage;
|
||||||
|
}
|
||||||
|
|
||||||
bool AssemblyStack::analyzeParsed()
|
bool AssemblyStack::analyzeParsed()
|
||||||
{
|
{
|
||||||
solAssert(m_parserResult, "");
|
solAssert(m_parserResult, "");
|
||||||
|
@ -81,6 +81,9 @@ public:
|
|||||||
/// If the settings (see constructor) disabled the optimizer, nothing is done here.
|
/// If the settings (see constructor) disabled the optimizer, nothing is done here.
|
||||||
void optimize();
|
void optimize();
|
||||||
|
|
||||||
|
/// Translate the source to a different language / dialect.
|
||||||
|
void translate(Language _targetLanguage);
|
||||||
|
|
||||||
/// Run the assembly step (should only be called after parseAndAnalyze).
|
/// Run the assembly step (should only be called after parseAndAnalyze).
|
||||||
MachineAssemblyObject assemble(Machine _machine) const;
|
MachineAssemblyObject assemble(Machine _machine) const;
|
||||||
|
|
||||||
|
@ -122,6 +122,7 @@ static string const g_strHelp = "help";
|
|||||||
static string const g_strInputFile = "input-file";
|
static string const g_strInputFile = "input-file";
|
||||||
static string const g_strInterface = "interface";
|
static string const g_strInterface = "interface";
|
||||||
static string const g_strYul = "yul";
|
static string const g_strYul = "yul";
|
||||||
|
static string const g_strYulDialect = "yul-dialect";
|
||||||
static string const g_strIR = "ir";
|
static string const g_strIR = "ir";
|
||||||
static string const g_strEWasm = "ewasm";
|
static string const g_strEWasm = "ewasm";
|
||||||
static string const g_strLicense = "license";
|
static string const g_strLicense = "license";
|
||||||
@ -220,6 +221,13 @@ static set<string> const g_machineArgs
|
|||||||
g_streWasm
|
g_streWasm
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Possible arguments to for --yul-dialect
|
||||||
|
static set<string> const g_yulDialectArgs
|
||||||
|
{
|
||||||
|
g_strEVM,
|
||||||
|
g_streWasm
|
||||||
|
};
|
||||||
|
|
||||||
static void version()
|
static void version()
|
||||||
{
|
{
|
||||||
sout() <<
|
sout() <<
|
||||||
@ -685,15 +693,20 @@ Allowed options)",
|
|||||||
)
|
)
|
||||||
(
|
(
|
||||||
g_argAssemble.c_str(),
|
g_argAssemble.c_str(),
|
||||||
"Switch to assembly mode, ignoring all options except --machine and --optimize and assumes input is assembly."
|
"Switch to assembly mode, ignoring all options except --machine, --yul-dialect and --optimize and assumes input is assembly."
|
||||||
)
|
)
|
||||||
(
|
(
|
||||||
g_argYul.c_str(),
|
g_argYul.c_str(),
|
||||||
"Switch to Yul mode, ignoring all options except --machine and --optimize and assumes input is Yul."
|
"Switch to Yul mode, ignoring all options except --machine, --yul-dialect and --optimize and assumes input is Yul."
|
||||||
)
|
)
|
||||||
(
|
(
|
||||||
g_argStrictAssembly.c_str(),
|
g_argStrictAssembly.c_str(),
|
||||||
"Switch to strict assembly mode, ignoring all options except --machine and --optimize and assumes input is strict assembly."
|
"Switch to strict assembly mode, ignoring all options except --machine, --yul-dialect and --optimize and assumes input is strict assembly."
|
||||||
|
)
|
||||||
|
(
|
||||||
|
g_strYulDialect.c_str(),
|
||||||
|
po::value<string>()->value_name(boost::join(g_yulDialectArgs, ",")),
|
||||||
|
"Input dialect to use in assembly or yul mode."
|
||||||
)
|
)
|
||||||
(
|
(
|
||||||
g_argMachine.c_str(),
|
g_argMachine.c_str(),
|
||||||
@ -911,7 +924,27 @@ bool CommandLineInterface::processInput()
|
|||||||
}
|
}
|
||||||
if (targetMachine == Machine::eWasm && inputLanguage == Input::StrictAssembly)
|
if (targetMachine == Machine::eWasm && inputLanguage == Input::StrictAssembly)
|
||||||
inputLanguage = Input::EWasm;
|
inputLanguage = Input::EWasm;
|
||||||
if (optimize && inputLanguage != Input::StrictAssembly)
|
if (m_args.count(g_strYulDialect))
|
||||||
|
{
|
||||||
|
string dialect = m_args[g_strYulDialect].as<string>();
|
||||||
|
if (dialect == g_strEVM)
|
||||||
|
inputLanguage = Input::StrictAssembly;
|
||||||
|
else if (dialect == g_streWasm)
|
||||||
|
{
|
||||||
|
inputLanguage = Input::EWasm;
|
||||||
|
if (targetMachine != Machine::eWasm)
|
||||||
|
{
|
||||||
|
serr() << "If you select eWasm as --yul-dialect, --machine has to be eWasm as well." << endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
serr() << "Invalid option for --yul-dialect: " << dialect << endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (optimize && (inputLanguage != Input::StrictAssembly && inputLanguage != Input::EWasm))
|
||||||
{
|
{
|
||||||
serr() <<
|
serr() <<
|
||||||
"Optimizer can only be used for strict assembly. Use --" <<
|
"Optimizer can only be used for strict assembly. Use --" <<
|
||||||
@ -1331,14 +1364,14 @@ bool CommandLineInterface::assemble(
|
|||||||
for (auto const& sourceAndStack: assemblyStacks)
|
for (auto const& sourceAndStack: assemblyStacks)
|
||||||
{
|
{
|
||||||
auto const& stack = sourceAndStack.second;
|
auto const& stack = sourceAndStack.second;
|
||||||
unique_ptr<SourceReferenceFormatter> formatter;
|
|
||||||
if (m_args.count(g_argNewReporter))
|
|
||||||
formatter = make_unique<SourceReferenceFormatterHuman>(serr(false), m_coloredOutput);
|
|
||||||
else
|
|
||||||
formatter = make_unique<SourceReferenceFormatter>(serr(false));
|
|
||||||
|
|
||||||
for (auto const& error: stack.errors())
|
for (auto const& error: stack.errors())
|
||||||
{
|
{
|
||||||
|
unique_ptr<SourceReferenceFormatter> formatter;
|
||||||
|
if (m_args.count(g_argNewReporter))
|
||||||
|
formatter = make_unique<SourceReferenceFormatterHuman>(serr(false), m_coloredOutput);
|
||||||
|
else
|
||||||
|
formatter = make_unique<SourceReferenceFormatter>(serr(false));
|
||||||
|
|
||||||
g_hasOutput = true;
|
g_hasOutput = true;
|
||||||
formatter->printErrorInformation(*error);
|
formatter->printErrorInformation(*error);
|
||||||
}
|
}
|
||||||
@ -1356,11 +1389,22 @@ bool CommandLineInterface::assemble(
|
|||||||
_targetMachine == yul::AssemblyStack::Machine::EVM15 ? "EVM 1.5" :
|
_targetMachine == yul::AssemblyStack::Machine::EVM15 ? "EVM 1.5" :
|
||||||
"eWasm";
|
"eWasm";
|
||||||
sout() << endl << "======= " << src.first << " (" << machine << ") =======" << endl;
|
sout() << endl << "======= " << src.first << " (" << machine << ") =======" << endl;
|
||||||
|
|
||||||
yul::AssemblyStack& stack = assemblyStacks[src.first];
|
yul::AssemblyStack& stack = assemblyStacks[src.first];
|
||||||
|
|
||||||
sout() << endl << "Pretty printed source:" << endl;
|
sout() << endl << "Pretty printed source:" << endl;
|
||||||
sout() << stack.print() << endl;
|
sout() << stack.print() << endl;
|
||||||
|
|
||||||
|
if (_language != yul::AssemblyStack::Language::EWasm && _targetMachine == yul::AssemblyStack::Machine::eWasm)
|
||||||
|
{
|
||||||
|
stack.translate(yul::AssemblyStack::Language::EWasm);
|
||||||
|
stack.optimize();
|
||||||
|
|
||||||
|
sout() << endl << "==========================" << endl;
|
||||||
|
sout() << endl << "Translated source:" << endl;
|
||||||
|
sout() << stack.print() << endl;
|
||||||
|
}
|
||||||
|
|
||||||
yul::MachineAssemblyObject object;
|
yul::MachineAssemblyObject object;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
1
test/cmdlineTests/evm_to_wasm/args
Normal file
1
test/cmdlineTests/evm_to_wasm/args
Normal file
@ -0,0 +1 @@
|
|||||||
|
--assemble --optimize --yul-dialect evm --machine ewasm
|
1
test/cmdlineTests/evm_to_wasm/err
Normal file
1
test/cmdlineTests/evm_to_wasm/err
Normal file
@ -0,0 +1 @@
|
|||||||
|
Warning: Yul and its optimizer are still experimental. Please use the output with care.
|
3
test/cmdlineTests/evm_to_wasm/input.sol
Normal file
3
test/cmdlineTests/evm_to_wasm/input.sol
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
sstore(0, 1)
|
||||||
|
}
|
104
test/cmdlineTests/evm_to_wasm/output
Normal file
104
test/cmdlineTests/evm_to_wasm/output
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
|
||||||
|
======= evm_to_wasm/input.sol (eWasm) =======
|
||||||
|
|
||||||
|
Pretty printed source:
|
||||||
|
object "object" {
|
||||||
|
code { { sstore(0, 1) } }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
==========================
|
||||||
|
|
||||||
|
Translated source:
|
||||||
|
object "object" {
|
||||||
|
code {
|
||||||
|
function main()
|
||||||
|
{
|
||||||
|
let _1 := 0
|
||||||
|
mstore_internal(0, _1, _1, _1, _1)
|
||||||
|
mstore_internal(32, _1, _1, _1, 1)
|
||||||
|
eth.storageStore(0, 32)
|
||||||
|
}
|
||||||
|
function endian_swap_16(x) -> y
|
||||||
|
{
|
||||||
|
y := i64.or(i64.and(i64.shl(x, 8), 0xff00), i64.and(i64.shr_u(x, 8), 0xff))
|
||||||
|
}
|
||||||
|
function endian_swap_32(x) -> y
|
||||||
|
{
|
||||||
|
let hi := i64.shl(endian_swap_16(x), 16)
|
||||||
|
y := i64.or(hi, endian_swap_16(i64.shr_u(x, 16)))
|
||||||
|
}
|
||||||
|
function endian_swap(x) -> y
|
||||||
|
{
|
||||||
|
let hi := i64.shl(endian_swap_32(x), 32)
|
||||||
|
y := i64.or(hi, endian_swap_32(i64.shr_u(x, 32)))
|
||||||
|
}
|
||||||
|
function mstore_internal(pos, y1, y2, y3, y4)
|
||||||
|
{
|
||||||
|
i64.store(pos, endian_swap(y1))
|
||||||
|
i64.store(i64.add(pos, 8), endian_swap(y2))
|
||||||
|
i64.store(i64.add(pos, 16), endian_swap(y3))
|
||||||
|
i64.store(i64.add(pos, 24), endian_swap(y4))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Binary representation:
|
||||||
|
0061736d0100000001160460000060017e017e60057e7e7e7e7e0060027f7f0002190108657468657265756d0c73746f7261676553746f7265000303060500010101020503010001060100071102066d656d6f72790200046d61696e00010ab501052801017e420021004200200020002000200010054220200020002000420110054200a74220a710000b1c01017e20004208864280fe0383200042088842ff018384210120010b1b01027e20001002421086210220022000421088100284210120010b1b01027e20001003422086210220022000422088100384210120010b3501007e2000a720011004370300200042087ca720021004370300200042107ca720031004370300200042187ca7200410043703000b
|
||||||
|
|
||||||
|
Text representation:
|
||||||
|
(module
|
||||||
|
(import "ethereum" "storageStore" (func $eth.storageStore (param i32 i32)))
|
||||||
|
(memory $memory (export "memory") 1)
|
||||||
|
(export "main" (func $main))
|
||||||
|
|
||||||
|
(func $main
|
||||||
|
(local $_1 i64)
|
||||||
|
(local.set $_1 (i64.const 0))
|
||||||
|
(call $mstore_internal (i64.const 0) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1))
|
||||||
|
(call $mstore_internal (i64.const 32) (local.get $_1) (local.get $_1) (local.get $_1) (i64.const 1))
|
||||||
|
(call $eth.storageStore (i32.wrap_i64 (i64.const 0)) (i32.wrap_i64 (i64.const 32)))
|
||||||
|
)
|
||||||
|
|
||||||
|
(func $endian_swap_16
|
||||||
|
(param $x i64)
|
||||||
|
(result i64)
|
||||||
|
(local $y i64)
|
||||||
|
(local.set $y (i64.or (i64.and (i64.shl (local.get $x) (i64.const 8)) (i64.const 65280)) (i64.and (i64.shr_u (local.get $x) (i64.const 8)) (i64.const 255))))
|
||||||
|
(local.get $y)
|
||||||
|
)
|
||||||
|
|
||||||
|
(func $endian_swap_32
|
||||||
|
(param $x i64)
|
||||||
|
(result i64)
|
||||||
|
(local $y i64)
|
||||||
|
(local $hi i64)
|
||||||
|
(local.set $hi (i64.shl (call $endian_swap_16 (local.get $x)) (i64.const 16)))
|
||||||
|
(local.set $y (i64.or (local.get $hi) (call $endian_swap_16 (i64.shr_u (local.get $x) (i64.const 16)))))
|
||||||
|
(local.get $y)
|
||||||
|
)
|
||||||
|
|
||||||
|
(func $endian_swap
|
||||||
|
(param $x i64)
|
||||||
|
(result i64)
|
||||||
|
(local $y i64)
|
||||||
|
(local $hi i64)
|
||||||
|
(local.set $hi (i64.shl (call $endian_swap_32 (local.get $x)) (i64.const 32)))
|
||||||
|
(local.set $y (i64.or (local.get $hi) (call $endian_swap_32 (i64.shr_u (local.get $x) (i64.const 32)))))
|
||||||
|
(local.get $y)
|
||||||
|
)
|
||||||
|
|
||||||
|
(func $mstore_internal
|
||||||
|
(param $pos i64)
|
||||||
|
(param $y1 i64)
|
||||||
|
(param $y2 i64)
|
||||||
|
(param $y3 i64)
|
||||||
|
(param $y4 i64)
|
||||||
|
(i64.store (i32.wrap_i64 (local.get $pos)) (call $endian_swap (local.get $y1)))
|
||||||
|
(i64.store (i32.wrap_i64 (i64.add (local.get $pos) (i64.const 8))) (call $endian_swap (local.get $y2)))
|
||||||
|
(i64.store (i32.wrap_i64 (i64.add (local.get $pos) (i64.const 16))) (call $endian_swap (local.get $y3)))
|
||||||
|
(i64.store (i32.wrap_i64 (i64.add (local.get $pos) (i64.const 24))) (call $endian_swap (local.get $y4)))
|
||||||
|
)
|
||||||
|
|
||||||
|
)
|
Loading…
Reference in New Issue
Block a user