CommandLineInterface: Make --yul-optimizations work in strict assembly mode

This commit is contained in:
Kamil Śliwak 2020-05-08 18:20:14 +02:00
parent 5d4b9022f0
commit 6a58227830
10 changed files with 217 additions and 13 deletions

View File

@ -5,6 +5,7 @@ Language Features:
Compiler Features: Compiler Features:
* Commandline Interface: Don't ignore `--yul-optimizations` in assembly mode.

View File

@ -1041,8 +1041,7 @@ Optimization step sequence
-------------------------- --------------------------
By default the Yul optimizer applies its predefined sequence of optimization steps to the generated assembly. By default the Yul optimizer applies its predefined sequence of optimization steps to the generated assembly.
You can override this sequence and supply your own using the `--yul-optimizations` option when compiling You can override this sequence and supply your own using the `--yul-optimizations` option:
in Solidity mode:
.. code-block:: sh .. code-block:: sh

View File

@ -787,19 +787,19 @@ Allowed options)").c_str(),
( (
g_argAssemble.c_str(), g_argAssemble.c_str(),
("Switch to assembly mode, ignoring all options except " ("Switch to assembly mode, ignoring all options except "
"--" + g_argMachine + ", --" + g_strYulDialect + " and --" + g_argOptimize + " " "--" + g_argMachine + ", --" + g_strYulDialect + ", --" + g_argOptimize + " and --" + g_strYulOptimizations + " "
"and assumes input is assembly.").c_str() "and assumes input is assembly.").c_str()
) )
( (
g_argYul.c_str(), g_argYul.c_str(),
("Switch to Yul mode, ignoring all options except " ("Switch to Yul mode, ignoring all options except "
"--" + g_argMachine + ", --" + g_strYulDialect + " and --" + g_argOptimize + " " "--" + g_argMachine + ", --" + g_strYulDialect + ", --" + g_argOptimize + " and --" + g_strYulOptimizations + " "
"and assumes input is Yul.").c_str() "and assumes input is Yul.").c_str()
) )
( (
g_argStrictAssembly.c_str(), g_argStrictAssembly.c_str(),
("Switch to strict assembly mode, ignoring all options except " ("Switch to strict assembly mode, ignoring all options except "
"--" + g_argMachine + ", --" + g_strYulDialect + " and --" + g_argOptimize + " " "--" + g_argMachine + ", --" + g_strYulDialect + ", --" + g_argOptimize + " and --" + g_strYulOptimizations + " "
"and assumes input is strict assembly.").c_str() "and assumes input is strict assembly.").c_str()
) )
( (
@ -1079,6 +1079,29 @@ bool CommandLineInterface::processInput()
serr() << "--" << g_strNoOptimizeYul << " is invalid in assembly mode. Optimization is disabled by default and can be enabled with --" << g_argOptimize << "." << endl; serr() << "--" << g_strNoOptimizeYul << " is invalid in assembly mode. Optimization is disabled by default and can be enabled with --" << g_argOptimize << "." << endl;
return false; return false;
} }
optional<string> yulOptimiserSteps;
if (m_args.count(g_strYulOptimizations))
{
if (!optimize)
{
serr() << "--" << g_strYulOptimizations << " is invalid if Yul optimizer is disabled" << endl;
return false;
}
try
{
yul::OptimiserSuite::validateSequence(m_args[g_strYulOptimizations].as<string>());
}
catch (yul::OptimizerException const& _exception)
{
serr() << "Invalid optimizer step sequence in --" << g_strYulOptimizations << ": " << _exception.what() << endl;
return false;
}
yulOptimiserSteps = m_args[g_strYulOptimizations].as<string>();
}
if (m_args.count(g_argMachine)) if (m_args.count(g_argMachine))
{ {
string machine = m_args[g_argMachine].as<string>(); string machine = m_args[g_argMachine].as<string>();
@ -1130,7 +1153,7 @@ bool CommandLineInterface::processInput()
"Warning: Yul is still experimental. Please use the output with care." << "Warning: Yul is still experimental. Please use the output with care." <<
endl; endl;
return assemble(inputLanguage, targetMachine, optimize); return assemble(inputLanguage, targetMachine, optimize, yulOptimiserSteps);
} }
if (m_args.count(g_argLink)) if (m_args.count(g_argLink))
{ {
@ -1542,18 +1565,21 @@ string CommandLineInterface::objectWithLinkRefsHex(evmasm::LinkerObject const& _
bool CommandLineInterface::assemble( bool CommandLineInterface::assemble(
yul::AssemblyStack::Language _language, yul::AssemblyStack::Language _language,
yul::AssemblyStack::Machine _targetMachine, yul::AssemblyStack::Machine _targetMachine,
bool _optimize bool _optimize,
optional<string> _yulOptimiserSteps
) )
{ {
solAssert(_optimize || !_yulOptimiserSteps.has_value(), "");
bool successful = true; bool successful = true;
map<string, yul::AssemblyStack> assemblyStacks; map<string, yul::AssemblyStack> assemblyStacks;
for (auto const& src: m_sourceCodes) for (auto const& src: m_sourceCodes)
{ {
auto& stack = assemblyStacks[src.first] = yul::AssemblyStack( OptimiserSettings settings = _optimize ? OptimiserSettings::full() : OptimiserSettings::minimal();
m_evmVersion, if (_yulOptimiserSteps.has_value())
_language, settings.yulOptimiserSteps = _yulOptimiserSteps.value();
_optimize ? OptimiserSettings::full() : OptimiserSettings::minimal()
); auto& stack = assemblyStacks[src.first] = yul::AssemblyStack(m_evmVersion, _language, settings);
try try
{ {
if (!stack.parseAndAnalyze(src.first, src.second)) if (!stack.parseAndAnalyze(src.first, src.second))

View File

@ -56,7 +56,12 @@ private:
/// @returns the full object with library placeholder hints in hex. /// @returns the full object with library placeholder hints in hex.
static std::string objectWithLinkRefsHex(evmasm::LinkerObject const& _obj); static std::string objectWithLinkRefsHex(evmasm::LinkerObject const& _obj);
bool assemble(yul::AssemblyStack::Language _language, yul::AssemblyStack::Machine _targetMachine, bool _optimize); bool assemble(
yul::AssemblyStack::Language _language,
yul::AssemblyStack::Machine _targetMachine,
bool _optimize,
std::optional<std::string> _yulOptimiserSteps = std::nullopt
);
void outputCompilationResults(); void outputCompilationResults();

View File

@ -0,0 +1,26 @@
{
"language": "Yul",
"sources":
{
"A":
{
"content": "{ let x := mload(0) sstore(add(x, 0), 0) }"
}
},
"settings":
{
"optimizer": {
"enabled": true,
"details": {
"yul": true,
"yulDetails": {
"optimizerSteps": "dhfoDgvulfnTUtnIf"
}
}
},
"outputSelection":
{
"*": { "*": ["*"], "": [ "*" ] }
}
}
}

View File

@ -0,0 +1,30 @@
{"contracts":{"A":{"object":{"evm":{"assembly":" /* \"A\":17:18 */
0x00
/* \"A\":11:19 */
mload
/* \"A\":38:39 */
0x00
/* \"A\":34:35 */
0x00
/* \"A\":31:32 */
dup3
/* \"A\":27:36 */
add
/* \"A\":20:40 */
sstore
pop
","bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}},"ir":"object \"object\" {
code {
let x := mload(0)
sstore(add(x, 0), 0)
}
}
","irOptimized":"object \"object\" {
code {
{
let x := mload(0)
sstore(add(x, 0), 0)
}
}
}
"}}},"errors":[{"component":"general","formattedMessage":"Yul is still experimental. Please use the output with care.","message":"Yul is still experimental. Please use the output with care.","severity":"warning","type":"Warning"}]}

View File

@ -0,0 +1 @@
--strict-assembly --optimize --yul-optimizations dhfoDgvulfnTUtnIf

View File

@ -0,0 +1 @@
Warning: Yul is still experimental. Please use the output with care.

View File

@ -0,0 +1,27 @@
object "C_6" {
code {
mstore(64, 128)
if callvalue() { revert(0, 0) }
codecopy(0, dataoffset("C_6_deployed"), datasize("C_6_deployed"))
return(0, datasize("C_6_deployed"))
}
object "C_6_deployed" {
code {
{
mstore(64, 128)
if iszero(lt(calldatasize(), 4))
{
let selector := shift_right_224_unsigned(calldataload(0))
pop(selector)
}
pop(iszero(calldatasize()))
revert(0, 0)
}
function shift_right_224_unsigned(value) -> newValue
{
newValue := shr(224, value)
}
}
}
}

View File

@ -0,0 +1,88 @@
======= strict_asm_optimizer_steps/input.yul (EVM) =======
Pretty printed source:
object "C_6" {
code {
{
mstore(64, 128)
if callvalue() { revert(0, 0) }
codecopy(0, dataoffset("C_6_deployed"), datasize("C_6_deployed"))
return(0, datasize("C_6_deployed"))
}
}
object "C_6_deployed" {
code {
{
mstore(64, 128)
pop(iszero(lt(calldatasize(), 4)))
revert(0, 0)
}
}
}
}
Binary representation:
60806040523415600f5760006000fd5b6010601d60003960106000f3fe608060405260043610155060006000fd
Text representation:
/* "strict_asm_optimizer_steps/input.yul":45:48 */
0x80
/* "strict_asm_optimizer_steps/input.yul":41:43 */
0x40
/* "strict_asm_optimizer_steps/input.yul":34:49 */
mstore
/* "strict_asm_optimizer_steps/input.yul":61:72 */
callvalue
/* "strict_asm_optimizer_steps/input.yul":58:60 */
iszero
tag_1
jumpi
/* "strict_asm_optimizer_steps/input.yul":85:86 */
0x00
/* "strict_asm_optimizer_steps/input.yul":82:83 */
0x00
/* "strict_asm_optimizer_steps/input.yul":75:87 */
revert
/* "strict_asm_optimizer_steps/input.yul":58:60 */
tag_1:
/* "strict_asm_optimizer_steps/input.yul":98:163 */
dataSize(sub_0)
dataOffset(sub_0)
/* "strict_asm_optimizer_steps/input.yul":107:108 */
0x00
/* "strict_asm_optimizer_steps/input.yul":98:163 */
codecopy
/* "strict_asm_optimizer_steps/input.yul":172:207 */
dataSize(sub_0)
/* "strict_asm_optimizer_steps/input.yul":179:180 */
0x00
/* "strict_asm_optimizer_steps/input.yul":172:207 */
return
stop
sub_0: assembly {
/* "strict_asm_optimizer_steps/input.yul":298:301 */
0x80
/* "strict_asm_optimizer_steps/input.yul":294:296 */
0x40
/* "strict_asm_optimizer_steps/input.yul":287:302 */
mstore
/* "strict_asm_optimizer_steps/input.yul":348:349 */
0x04
/* "strict_asm_optimizer_steps/input.yul":332:346 */
calldatasize
/* "strict_asm_optimizer_steps/input.yul":329:350 */
lt
/* "strict_asm_optimizer_steps/input.yul":322:351 */
iszero
/* "strict_asm_optimizer_steps/input.yul":319:321 */
pop
/* "strict_asm_optimizer_steps/input.yul":570:571 */
0x00
/* "strict_asm_optimizer_steps/input.yul":567:568 */
0x00
/* "strict_asm_optimizer_steps/input.yul":560:572 */
revert
}