Limitations and Differences from Upstream solc
This chapter summarizes where solx differs from upstream solc, and which limitations currently apply.
Compilation Modes
solx supports two codegen pipelines:
- Yul pipeline: enabled with
--via-ir(matching solc's--via-irflag). - Legacy EVM assembly pipeline: the default code generation path.
The --evmla and --ethir debug flags are only available in the legacy (non-via-ir) pipeline.
solc Fork Modifications
The solx-solidity fork includes the following changes relative to upstream solc:
extraMetadataoutput: emits user-defined function metadata (name, entry tag, input/output sizes, AST IDs) used during LLVM lowering.DUPX/SWAPXinstructions: extends stack access beyond depth 16 to avoid classic "stack too deep" failures.spillAreaSizesetting: configures a memory spill region for values that cannot remain on stack.- Function pointer dispatch tables: uses static dispatch through
FuncPtrTrackerinstead of dynamic jump-based dispatch. - Simplified
try/catchin legacy mode: reduces control-flow complexity for translator compatibility. - Bypassed EVM bytecode generation: solx does not use solc's EVM bytecode output; final bytecode is produced by the LLVM backend.
- Disabled optimizer: the solc optimizer is turned off to preserve function boundaries and metadata validity. All optimization is handled by the LLVM backend.
Behavioral Differences
- Generated bytecode can differ from upstream solc output because final code generation happens in LLVM.
- Optimization levels map to LLVM optimization pipelines, not upstream
solcoptimization heuristics. - Final code size can differ from upstream due to LLVM pass behavior.
Optimizer and Assembly Semantics
solx treats Yul and inline assembly as compiler input, not as verbatim EVM bytecode. LLVM may combine, reorder, replace, or remove source operations. The final opcode sequence is therefore not guaranteed to match the source or upstream solc output.
Generated bytecode can differ in:
- Exact gas consumption and values returned by
gas(). - Memory expansion history and values returned by
msize(). - The presence and order of EVM instructions corresponding to source operations.
Memory operations that do not change memory contents may be removed even if the corresponding EVM instruction would have expanded memory. For example, an mcopy with identical source and destination addresses is not guaranteed to remain solely for its effects on gas or msize().
Contracts whose functional behavior depends on exact gas consumption or
msize()values are not supported. Use--asmto inspect the final instructions generated by solx.
These differences do not include incorrect results for other supported operations, compiler panics, or malformed compiler output. Such behavior is a compiler bug.
Memory-Safe Assembly
The memory-safe annotation is a guarantee provided by the source author, not a compiler check. It allows solx to reserve memory for stack spills and perform additional memory optimizations.
The free memory pointer at 0x40 may be greater than its initial value of 0x80 at the beginning of a memory-safe assembly block. Code that uses the free memory pointer must read its current value with mload(0x40) and must not assume that it still equals 0x80.
A memory-safe block that temporarily changes the free memory pointer must restore its original value or an increment of it. If the block modifies the zero slot at 0x60, it must restore the slot to zero before returning to Solidity code.
Incorrectly marking an assembly block as memory-safe results in undefined behavior and can corrupt Solidity objects or compiler spill values. See the upstream Memory Safety documentation for the complete requirements.
If stack spilling is required in a contract that contains memory-unsafe assembly, solx rejects the contract at compile time. Mark an assembly block as memory-safe only after verifying that it satisfies the requirements above.
The
EVM_DISABLE_MEMORY_SAFE_ASM_CHECKenvironment variable disables this check project-wide. It does not make an assembly block memory-safe. Using it with incompatible assembly can cause memory corruption.
Unsupported Features
CALLCODEis rejected at compile time. UseDELEGATECALLinstead.SELFDESTRUCTis rejected at compile time (deprecated by EIP-6049).PC(program counter) is not supported.solcoptimizer settings are ignored since the solc optimizer is disabled.
Version Support
- The solx-solidity fork tracks upstream solc releases.
- The minimum supported Solidity version matches the forked solc version.