fevm-replay

Where Fe saves gas

Every mainnet call to a function ran twice: once on the code solc compiled, once on the Fe port. fevm-replay's tracer charged each opcode the gas it took, inside that function only (the calls it makes are left out). Same inputs, same results; the difference is the compiler.

◀ Fe spends lessFe spends more ▶
OpcodeSolidityFeFe − Solidity

What it shows

Six functions of four ports, one pattern. Over all six, Fe spends 44% less gas on stack shuffling, 66% less on arithmetic and logic and 28% less on control flow, and 25% more on memory. Memory is the one group where Fe costs more, and it does in every function, from withdraw (−10.8% overall) to the proxy (+1.9%).

Fe moves fewer values around the stack. The largest saving in every function but the proxy is stack shuffling: fewer POP, DUP and SWAP. solc 0.4 and 0.5 keep many temporaries on the stack; Fe's Sonatina backend allocates them more tightly.

Arithmetic is leaner: no EXP to compute 2**112, fewer masks with AND. In swap the port also reads storage less often (SLOAD), keeping the packed reserves it has already read, though it takes more jumps between its smaller functions.

Fe spends more on memory: it copies calldata and return data into its own buffers (CALLDATACOPY, RETURNDATACOPY, MSTORE), where solc reads them in place. On a proxy, which does little else, that is the whole difference: the Fe proxy of USDC costs 40 to 60 gas more per call.

Measured with fevm_replay opgas over blocks 26,400,000 to 26,400,199. An opcode's cost is the gas left before it minus the gas left before the next opcode in the same call.