argotorg / argotorg/solidity

perf: evmasm hasInstruction called unnecessarily

Open
#16,292 0 comments 0 reactions 0 assignees View on GitHub
bug :bug:
Dominant language
C++
Stars
25.7k
Forks
6.2k
Avg merge
2d 19h
Merged PRs (30d)
29

Description

evmasm::AssemblyItem::operator== is pretty hot, especially in the peephole optimizer:

https://github.com/argotorg/solidity/blob/08c4e0c6cfab9d6f303fefbf0ad081e06fa4a532/libevmasm/AssemblyItem.h#L248-L252

This operator calls hasInstruction() twice, once in the actual operator, and the second time in the instruction() solAssert: https://github.com/argotorg/solidity/blob/08c4e0c6cfab9d6f303fefbf0ad081e06fa4a532/libevmasm/AssemblyItem.h#L218

This is enough to show up in profiles. The solAssert should either be a debug-only assert, or operator== should not repeat the check by using m_instruction directly. I would prefer the former since operator== is not the only hot callsite for hasInstruction().

This function (instruction() calling hasInstruction()) is BY FAR the most time consuming operation in the evmasm optimizer.

This should be a single line change for an estimated E2E 5-10% performance improvement in optimized compilations.

---

On solady:
```
~/github/solady main !1 ?3 ❯ hyperfine -w1 --prepare 'forge clean' 'SOLC=solcd forge b' 'SOLC=solcd2 forge b' ✘ INT 18:34:21
Benchmark 1: SOLC=solcd forge b
Time (mean ± σ): 18.934 s ± 0.425 s [User: 17.609 s, System: 0.865 s]
Range (min … max): 18.657 s … 19.703 s 10 runs

Warning: Statistical outliers were detected. Consider re-running this benchmark on a quiet system without any interferences from other programs.

Benchmark 2: SOLC=solcd2 forge b
Time (mean ± σ): 17.796 s ± 0.332 s [User: 16.329 s, System: 0.834 s]
Range (min … max): 17.639 s … 18.735 s 10 runs

Warning: Statistical outliers were detected. Consider re-running this benchmark on a quiet system without any interferences from other programs.

Summary
SOLC=solcd2 forge b ran
1.06 ± 0.03 times faster than SOLC=solcd forge b

```

this is using a custom script as solc that uses the binary in the SOLC env var. this is the same as '--use X' in forge but i was using it for other profiling.

version 0.8.31-develop.2025.11.19+commit.08c4e0c6.mod.Darwin.appleclang (08c4e0c6cfab9d6f303fefbf0ad081e06fa4a532)

the diff for solcd and solcd2 is:
```diff
diff --git a/libevmasm/AssemblyItem.h b/libevmasm/AssemblyItem.h
index dcb4bf3a7..59ebb7e15 100644
--- a/libevmasm/AssemblyItem.h
+++ b/libevmasm/AssemblyItem.h
@@ -215,7 +215,7 @@ public:
/// @returns the instruction of this item (only valid if hasInstruction returns true)
Instruction instruction() const
{
- solAssert(hasInstruction());
+ // solAssert(hasInstruction());
return *m_instruction;
}
```

Contributor guide

Open the contributing guide

Research direction

Start in libevmasm/AssemblyItem.h at AssemblyItem::instruction() and operator==, then review the linked lines and existing optimizer checks. Use the solady hyperfine comparison described in the issue to verify the change; done means the redundant hasInstruction() cost is removed without changing instruction handling.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
compilers, performance
Issue type
Refactor
Difficulty
1/5
Estimated time
Under an hour
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.