Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Language Features:
Compiler Features:
* Commandline Interface: Accept nested brackets in step sequences passed to ``--yul-optimizations``.
* Commandline Interface: Add ``--debug-info`` option for selecting how much extra debug information should be included in the produced EVM assembly and Yul code.
* Commandline Interface: Support ``--asm``, ``--bin``, ``--ir-optimized``, ``--ewasm`` and ``--ewasm-ir`` output selection options in assembler mode.
* Commandline Interface: Use different colors when printing errors, warnings and infos.
* SMTChecker: Output values for ``block.*``, ``msg.*`` and ``tx.*`` variables that are present in the called functions.
* SMTChecker: Report contract invariants and reentrancy properties. This can be enabled via the CLI option ``--model-checker-invariants`` or the Standard JSON option ``settings.modelChecker.invariants``.
Expand Down
48 changes: 33 additions & 15 deletions solc/CommandLineInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1042,34 +1042,52 @@ bool CommandLineInterface::assemble(yul::AssemblyStack::Language _language, yul:

yul::AssemblyStack& stack = assemblyStacks[src.first];

sout() << endl << "Pretty printed source:" << endl;
sout() << stack.print() << endl;
if (m_options.compiler.outputs.irOptimized)
{
// NOTE: This actually outputs unoptimized code when the optimizer is disabled but
// 'ir' output in StandardCompiler works the same way.
sout() << endl << "Pretty printed source:" << 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;
if (m_options.compiler.outputs.ewasmIR)
{
sout() << endl << "==========================" << endl;
sout() << endl << "Translated source:" << endl;
sout() << stack.print() << endl;
}
}

yul::MachineAssemblyObject object;
object = stack.assemble(_targetMachine);
object.bytecode->link(m_options.linker.libraries);

sout() << endl << "Binary representation:" << endl;
if (object.bytecode)
sout() << object.bytecode->toHex() << endl;
else
serr() << "No binary representation found." << endl;
if (m_options.compiler.outputs.binary)
{
sout() << endl << "Binary representation:" << endl;
if (object.bytecode)
sout() << object.bytecode->toHex() << endl;
else
serr() << "No binary representation found." << endl;
}

sout() << endl << "Text representation:" << endl;
if (!object.assembly.empty())
sout() << object.assembly << endl;
else
serr() << "No text representation found." << endl;
solAssert(_targetMachine == yul::AssemblyStack::Machine::Ewasm || _targetMachine == yul::AssemblyStack::Machine::EVM, "");
if (
(_targetMachine == yul::AssemblyStack::Machine::EVM && m_options.compiler.outputs.asm_) ||
(_targetMachine == yul::AssemblyStack::Machine::Ewasm && m_options.compiler.outputs.ewasm)
)
{
sout() << endl << "Text representation:" << endl;
if (!object.assembly.empty())
sout() << object.assembly << endl;
else
serr() << "No text representation found." << endl;
}
}

return true;
Expand Down
28 changes: 25 additions & 3 deletions solc/CommandLineParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -446,10 +446,18 @@ bool CommandLineParser::parseOutputSelection()
{
static auto outputSupported = [](InputMode _mode, string_view _outputName)
{
static set<string> const compilerModeOutputs =
static set<string> const compilerModeOutputs = (
CompilerOutputs::componentMap() |
ranges::views::keys |
ranges::to<set>();
ranges::to<set>()
) - set<string>{CompilerOutputs::componentName(&CompilerOutputs::ewasmIR)};
static set<string> const assemblerModeOutputs = {
CompilerOutputs::componentName(&CompilerOutputs::asm_),
CompilerOutputs::componentName(&CompilerOutputs::binary),
CompilerOutputs::componentName(&CompilerOutputs::irOptimized),
CompilerOutputs::componentName(&CompilerOutputs::ewasm),
CompilerOutputs::componentName(&CompilerOutputs::ewasmIR),
};

switch (_mode)
{
Expand All @@ -461,6 +469,7 @@ bool CommandLineParser::parseOutputSelection()
case InputMode::CompilerWithASTImport:
return contains(compilerModeOutputs, _outputName);
case InputMode::Assembler:
return contains(assemblerModeOutputs, _outputName);
case InputMode::StandardJson:
case InputMode::Linker:
return false;
Expand All @@ -472,6 +481,17 @@ bool CommandLineParser::parseOutputSelection()
for (auto&& [optionName, outputComponent]: CompilerOutputs::componentMap())
m_options.compiler.outputs.*outputComponent = (m_args.count(optionName) > 0);

if (m_options.input.mode == InputMode::Assembler && m_options.compiler.outputs == CompilerOutputs{})
{
// In assembly mode keep the default outputs enabled for backwards-compatibility.
// TODO: Remove this (must be done in a breaking release).
m_options.compiler.outputs.asm_ = true;
m_options.compiler.outputs.binary = true;
m_options.compiler.outputs.irOptimized = true;
m_options.compiler.outputs.ewasm = true;
m_options.compiler.outputs.ewasmIR = true;
}

vector<string> unsupportedOutputs;
for (auto&& [optionName, outputComponent]: CompilerOutputs::componentMap())
if (m_options.compiler.outputs.*outputComponent && !outputSupported(m_options.input.mode, optionName))
Expand Down Expand Up @@ -692,6 +712,7 @@ General Information)").c_str(),
(CompilerOutputs::componentName(&CompilerOutputs::ir).c_str(), "Intermediate Representation (IR) of all contracts (EXPERIMENTAL).")
(CompilerOutputs::componentName(&CompilerOutputs::irOptimized).c_str(), "Optimized intermediate Representation (IR) of all contracts (EXPERIMENTAL).")
(CompilerOutputs::componentName(&CompilerOutputs::ewasm).c_str(), "Ewasm text representation of all contracts (EXPERIMENTAL).")
(CompilerOutputs::componentName(&CompilerOutputs::ewasmIR).c_str(), "Intermediate representation (IR) converted to a form that can be translated directly into Ewasm text representation (EXPERIMENTAL).")
(CompilerOutputs::componentName(&CompilerOutputs::signatureHashes).c_str(), "Function signature hashes of the contracts.")
(CompilerOutputs::componentName(&CompilerOutputs::natspecUser).c_str(), "Natspec user documentation of all contracts.")
(CompilerOutputs::componentName(&CompilerOutputs::natspecDev).c_str(), "Natspec developer documentation of all contracts.")
Expand Down Expand Up @@ -906,11 +927,12 @@ bool CommandLineParser::processArgs()
if (!checkMutuallyExclusive({g_strColor, g_strNoColor}))
return false;

array<string, 8> const conflictingWithStopAfter{
array<string, 9> const conflictingWithStopAfter{
CompilerOutputs::componentName(&CompilerOutputs::binary),
CompilerOutputs::componentName(&CompilerOutputs::ir),
CompilerOutputs::componentName(&CompilerOutputs::irOptimized),
CompilerOutputs::componentName(&CompilerOutputs::ewasm),
CompilerOutputs::componentName(&CompilerOutputs::ewasmIR),
g_strGas,
CompilerOutputs::componentName(&CompilerOutputs::asm_),
CompilerOutputs::componentName(&CompilerOutputs::asmJson),
Expand Down
2 changes: 2 additions & 0 deletions solc/CommandLineParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ struct CompilerOutputs
{"ir", &CompilerOutputs::ir},
{"ir-optimized", &CompilerOutputs::irOptimized},
{"ewasm", &CompilerOutputs::ewasm},
{"ewasm-ir", &CompilerOutputs::ewasmIR},
{"hashes", &CompilerOutputs::signatureHashes},
{"userdoc", &CompilerOutputs::natspecUser},
{"devdoc", &CompilerOutputs::natspecDev},
Expand All @@ -97,6 +98,7 @@ struct CompilerOutputs
bool ir = false;
bool irOptimized = false;
bool ewasm = false;
bool ewasmIR = false;
bool signatureHashes = false;
bool natspecUser = false;
bool natspecDev = false;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
--assemble --optimize --yul-dialect evm --machine ewasm --asm
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Warning: Yul is still experimental. Please use the output with care.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
let x := 42
sstore(0, x)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@

======= evm_to_wasm_output_selection_asm_only/input.yul (Ewasm) =======
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
--assemble --optimize --yul-dialect evm --machine ewasm --ewasm-ir
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Warning: Yul is still experimental. Please use the output with care.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
let x := 42
sstore(0, x)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@

======= evm_to_wasm_output_selection_ewasm_ir_only/input.yul (Ewasm) =======

==========================

Translated source:
object "object" {
code {
function main()
{
let hi := i64.shl(i64.extend_i32_u(bswap32(i32.wrap_i64(0))), 32)
let y := i64.or(hi, i64.extend_i32_u(bswap32(i32.wrap_i64(i64.shr_u(0, 32)))))
i64.store(0:i32, y)
i64.store(i32.add(0:i32, 8:i32), y)
i64.store(i32.add(0:i32, 16:i32), y)
i64.store(i32.add(0:i32, 24:i32), y)
i64.store(32:i32, y)
i64.store(i32.add(32:i32, 8:i32), y)
i64.store(i32.add(32:i32, 16:i32), y)
let hi_1 := i64.shl(i64.extend_i32_u(bswap32(i32.wrap_i64(42))), 32)
i64.store(i32.add(32:i32, 24:i32), i64.or(hi_1, i64.extend_i32_u(bswap32(i32.wrap_i64(i64.shr_u(42, 32))))))
eth.storageStore(0:i32, 32:i32)
}
function bswap16(x:i32) -> y:i32
{
y := i32.or(i32.and(i32.shl(x, 8:i32), 0xff00:i32), i32.and(i32.shr_u(x, 8:i32), 0xff:i32))
}
function bswap32(x:i32) -> y:i32
{
let hi:i32 := i32.shl(bswap16(x), 16:i32)
y := i32.or(hi, bswap16(i32.shr_u(x, 16:i32)))
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
--assemble --optimize --yul-dialect evm --machine ewasm --ewasm
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Warning: Yul is still experimental. Please use the output with care.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
let x := 42
sstore(0, x)
}
54 changes: 54 additions & 0 deletions test/cmdlineTests/evm_to_wasm_output_selection_ewasm_only/output
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@

======= evm_to_wasm_output_selection_ewasm_only/input.yul (Ewasm) =======

Text representation:
(module
(import "ethereum" "storageStore" (func $eth.storageStore (param i32 i32)))
(memory $memory (export "memory") 1)
(export "main" (func $main))

(func $main
(local $hi i64)
(local $y i64)
(local $hi_1 i64)
(block $label_
(local.set $hi (i64.shl (i64.extend_i32_u (call $bswap32 (i32.wrap_i64 (i64.const 0)))) (i64.const 32)))
(local.set $y (i64.or (local.get $hi) (i64.extend_i32_u (call $bswap32 (i32.wrap_i64 (i64.shr_u (i64.const 0) (i64.const 32)))))))
(i64.store (i32.const 0) (local.get $y))
(i64.store (i32.add (i32.const 0) (i32.const 8)) (local.get $y))
(i64.store (i32.add (i32.const 0) (i32.const 16)) (local.get $y))
(i64.store (i32.add (i32.const 0) (i32.const 24)) (local.get $y))
(i64.store (i32.const 32) (local.get $y))
(i64.store (i32.add (i32.const 32) (i32.const 8)) (local.get $y))
(i64.store (i32.add (i32.const 32) (i32.const 16)) (local.get $y))
(local.set $hi_1 (i64.shl (i64.extend_i32_u (call $bswap32 (i32.wrap_i64 (i64.const 42)))) (i64.const 32)))
(i64.store (i32.add (i32.const 32) (i32.const 24)) (i64.or (local.get $hi_1) (i64.extend_i32_u (call $bswap32 (i32.wrap_i64 (i64.shr_u (i64.const 42) (i64.const 32)))))))
(call $eth.storageStore (i32.const 0) (i32.const 32))
)
)

(func $bswap16
(param $x i32)
(result i32)
(local $y i32)
(block $label__1
(local.set $y (i32.or (i32.and (i32.shl (local.get $x) (i32.const 8)) (i32.const 65280)) (i32.and (i32.shr_u (local.get $x) (i32.const 8)) (i32.const 255))))

)
(local.get $y)
)

(func $bswap32
(param $x i32)
(result i32)
(local $y i32)
(local $hi i32)
(block $label__2
(local.set $hi (i32.shl (call $bswap16 (local.get $x)) (i32.const 16)))
(local.set $y (i32.or (local.get $hi) (call $bswap16 (i32.shr_u (local.get $x) (i32.const 16)))))

)
(local.get $y)
)

)
1 change: 1 addition & 0 deletions test/cmdlineTests/output_selection_ewasm_ir_only/args
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
--optimize --ewasm-ir
1 change: 1 addition & 0 deletions test/cmdlineTests/output_selection_ewasm_ir_only/err
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
The following outputs are not supported in compiler mode: --ewasm-ir.
1 change: 1 addition & 0 deletions test/cmdlineTests/output_selection_ewasm_ir_only/exit
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1
4 changes: 4 additions & 0 deletions test/cmdlineTests/output_selection_ewasm_ir_only/input.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// SPDX-License-Identifier: GPL-2.0
pragma solidity *;

contract C {}
Original file line number Diff line number Diff line change
@@ -1 +1 @@
--ast-compact-json --asm --asm-json --opcodes --bin --bin-runtime --abi --ir --ir-optimized --ewasm --hashes --userdoc --devdoc --metadata --storage-layout
--ast-compact-json --asm --asm-json --opcodes --bin --bin-runtime --abi --ir --ir-optimized --ewasm --ewasm-ir --hashes --userdoc --devdoc --metadata --storage-layout
Original file line number Diff line number Diff line change
@@ -1 +1 @@
The following outputs are not supported in standard JSON mode: --abi, --asm, --asm-json, --ast-compact-json, --bin, --bin-runtime, --devdoc, --ewasm, --hashes, --ir, --ir-optimized, --metadata, --opcodes, --storage-layout, --userdoc.
The following outputs are not supported in standard JSON mode: --abi, --asm, --asm-json, --ast-compact-json, --bin, --bin-runtime, --devdoc, --ewasm, --ewasm-ir, --hashes, --ir, --ir-optimized, --metadata, --opcodes, --storage-layout, --userdoc.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
--strict-assembly --optimize --asm
1 change: 1 addition & 0 deletions test/cmdlineTests/strict_asm_output_selection_asm_only/err
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Warning: Yul is still experimental. Please use the output with care.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
let x := 42
sstore(0, x)
}
12 changes: 12 additions & 0 deletions test/cmdlineTests/strict_asm_output_selection_asm_only/output
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

======= strict_asm_output_selection_asm_only/input.yul (EVM) =======

Text representation:
/* "strict_asm_output_selection_asm_only/input.yul":15:17 */
0x2a
/* "strict_asm_output_selection_asm_only/input.yul":29:30 */
0x00
/* "strict_asm_output_selection_asm_only/input.yul":22:34 */
sstore
/* "strict_asm_output_selection_asm_only/input.yul":0:36 */
stop
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
--strict-assembly --optimize --bin
1 change: 1 addition & 0 deletions test/cmdlineTests/strict_asm_output_selection_bin_only/err
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Warning: Yul is still experimental. Please use the output with care.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
let x := 42
sstore(0, x)
}
5 changes: 5 additions & 0 deletions test/cmdlineTests/strict_asm_output_selection_bin_only/output
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

======= strict_asm_output_selection_bin_only/input.yul (EVM) =======

Binary representation:
602a60005500
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
--strict-assembly --optimize --ewasm-ir
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Warning: Yul is still experimental. Please use the output with care.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
let x := 42
sstore(0, x)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@

======= strict_asm_output_selection_ewasm_ir_only/input.yul (EVM) =======
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
--strict-assembly --optimize --ewasm
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Warning: Yul is still experimental. Please use the output with care.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
let x := 42
sstore(0, x)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@

======= strict_asm_output_selection_ewasm_only/input.yul (EVM) =======
2 changes: 1 addition & 1 deletion test/cmdlineTests/strict_asm_output_selection_invalid/err
Original file line number Diff line number Diff line change
@@ -1 +1 @@
The following outputs are not supported in assembler mode: --abi, --asm, --asm-json, --bin, --bin-runtime, --devdoc, --ewasm, --hashes, --ir, --ir-optimized, --metadata, --opcodes, --storage-layout, --userdoc.
The following outputs are not supported in assembler mode: --abi, --asm-json, --bin-runtime, --devdoc, --hashes, --ir, --metadata, --opcodes, --storage-layout, --userdoc.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
--strict-assembly --optimize --ir-optimized
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Warning: Yul is still experimental. Please use the output with care.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
let x := 42
sstore(0, x)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

======= strict_asm_output_selection_ir_optimized_only/input.yul (EVM) =======

Pretty printed source:
object "object" {
code { { sstore(0, 42) } }
}
Loading