Cannot build solidity with gcc-15.0.1 -O3 but builds just fine with -O2
Description
I'm trying to build solidity with GCC 15.0.1 with O3 (default) and with 02 (default in Fedora Linux) on x86_64. The latter builds just fine, but the former halts with the following error
Environment
- Compiler version: gcc 15.0.1
- Compilation pipeline (legacy, IR, EOF): n/a (compile-time issue)
- Target EVM version (as per compiler settings): n/a (compile-time issue)
- Framework/IDE (e.g. Foundry, Hardhat, Remix): n/a (compile-time issue)
- EVM execution environment / backend / blockchain client: n/a (compile-time issue)
- Operating system: Fedora Linux 43
Steps to Reproduce
CFLAGS='-O2 -flto=auto -ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=3 -Wp,-D_GLIBCXX_ASSERTIONS -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -mbranch-protection=standard -fasynchronous-unwind-tables -fstack-clash-protection -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer '
CXXFLAGS='-O2 -flto=auto -ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=3 -Wp,-D_GLIBCXX_ASSERTIONS -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -mbranch-protection=standard -fasynchronous-unwind-tables -fstack-clash-protection -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer '
LDFLAGS='-Wl,-z,relro -Wl,--as-needed -Wl,-z,pack-relative-relocs -Wl,-z,now -specs=/usr/lib/rpm/redhat/redhat-hardened-ld -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -Wl,--build-id=sha1 -specs=/usr/lib/rpm/redhat/redhat-package-notes '
LT_SYS_LIBRARY_PATH=/usr/lib64:
CC=gcc
CXX=g++
/usr/bin/cmake -S . -B redhat-linux-build -DCMAKE_C_FLAGS_RELEASE:STRING=-DNDEBUG -DCMAKE_CXX_FLAGS_RELEASE:STRING=-DNDEBUG -DCMAKE_Fortran_FLAGS_RELEASE:STRING=-DNDEBUG -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -DCMAKE_INSTALL_DO_STRIP:BOOL=OFF -DCMAKE_INSTALL_PREFIX:PATH=/usr -DCMAKE_INSTALL_FULL_SBINDIR:PATH=/usr/bin -DCMAKE_INSTALL_SBINDIR:PATH=bin -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -DBUILD_SHARED_LIBS:BOOL=ON -DIGNORE_VENDORED_DEPENDENCIES:BOOL=ON -DBoost_USE_STATIC_LIBS:BOOL=OFF -DSTRICT_Z3_VERSION:BOOL=OFF -DTESTS:BOOL=OFF
...
[ 20%] Building CXX object libevmasm/CMakeFiles/evmasm.dir/SimplificationRules.cpp.o
cd /builddir/build/BUILD/solidity-0.8.29-build/solidity-0.8.29/redhat-linux-build/libevmasm && /usr/bin/g++ -DBOOST_ATOMIC_DYN_LINK -DBOOST_ATOMIC_NO_LIB -DBOOST_FILESYSTEM_DYN_LINK -DBOOST_FILESYSTEM_NO_LIB -DBOOST_SYSTEM_DYN_LINK -DBOOST_SYSTEM_NO_LIB -DFMT_HEADER_ONLY=1 -I/builddir/build/BUILD/solidity-0.8.29-build/solidity-0.8.29/redhat-linux-build/include -I/builddir/build/BUILD/solidity-0.8.29-build/solidity-0.8.29 -O2 -flto=auto -ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=3 -Wp,-D_GLIBCXX_ASSERTIONS -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -mbranch-protection=standard -fasynchronous-unwind-tables -fstack-clash-protection -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -O3 -DNDEBUG -std=c++20 -fstack-protector-strong -Wimplicit-fallthrough -fmacro-prefix-map=/builddir/build/BUILD/solidity-0.8.29-build/solidity-0.8.29=/solidity -Wpessimizing-move -Wredundant-move -Wall -Wextra -Werror -pedantic -Wmissing-declarations -Wno-unknown-pragmas -Wsign-conversion -Wconversion -Wextra-semi -Wno-dangling-reference -Wduplicated-cond -Wlogical-op -fdiagnostics-color -MD -MT libevmasm/CMakeFiles/evmasm.dir/SimplificationRules.cpp.o -MF CMakeFiles/evmasm.dir/SimplificationRules.cpp.o.d -o CMakeFiles/evmasm.dir/SimplificationRules.cpp.o -c /builddir/build/BUILD/solidity-0.8.29-build/solidity-0.8.29/libevmasm/SimplificationRules.cpp
In file included from /builddir/build/BUILD/solidity-0.8.29-build/solidity-0.8.29/libevmasm/Assembly.h:23,
from /builddir/build/BUILD/solidity-0.8.29-build/solidity-0.8.29/libevmasm/Inliner.h:25,
from /builddir/build/BUILD/solidity-0.8.29-build/solidity-0.8.29/libevmasm/Inliner.cpp:23:
In member function ‘solidity::evmasm::AssemblyItem::AssemblyItem(solidity::evmasm::AssemblyItem const&)’,
inlined from ‘std::_Construct<solidity::evmasm::AssemblyItem, solidity::evmasm::AssemblyItem const&>(solidity::evmasm::AssemblyItem*, solidity::evmasm::AssemblyItem const&)void’ at /usr/include/c++/15/bits/stl_construct.h:133:7,
inlined from ‘std::__do_uninit_copy<solidity::evmasm::AssemblyItem const*, solidity::evmasm::AssemblyItem const*, solidity::evmasm::AssemblyItem*>(solidity::evmasm::AssemblyItem const*, solidity::evmasm::AssemblyItem const*, solidity::evmasm::AssemblyItem*)solidity::evmasm::AssemblyItem*’ at /usr/include/c++/15/bits/stl_uninitialized.h:145:17,
inlined from ‘std::uninitialized_copy<solidity::evmasm::AssemblyItem const*, solidity::evmasm::AssemblyItem*>(solidity::evmasm::AssemblyItem const*, solidity::evmasm::AssemblyItem const*, solidity::evmasm::AssemblyItem*)solidity::evmasm::AssemblyItem*’ at /usr/include/c++/15/bits/stl_uninitialized.h:260:30,
inlined from ‘std::__uninitialized_copy_a<solidity::evmasm::AssemblyItem const*, solidity::evmasm::AssemblyItem const*, solidity::evmasm::AssemblyItem*, solidity::evmasm::AssemblyItem>(solidity::evmasm::AssemblyItem const*, solidity::evmasm::AssemblyItem const*, solidity::evmasm::AssemblyItem*, std::allocator<solidity::evmasm::AssemblyItem>&)solidity::evmasm::AssemblyItem*’ at /usr/include/c++/15/bits/stl_uninitialized.h:617:32,
inlined from ‘std::vector<solidity::evmasm::AssemblyItem, std::allocator<solidity::evmasm::AssemblyItem> >::_M_range_initialize<solidity::evmasm::AssemblyItem const*>(solidity::evmasm::AssemblyItem const*, solidity::evmasm::AssemblyItem const*, std::forward_iterator_tag)void’ at /usr/include/c++/15/bits/stl_vector.h:1890:6,
inlined from ‘std::vector<solidity::evmasm::AssemblyItem, std::allocator<solidity::evmasm::AssemblyItem> >::vector(std::initializer_list<solidity::evmasm::AssemblyItem>, std::allocator<solidity::evmasm::AssemblyItem> const&)’ at /usr/include/c++/15/bits/stl_vector.h:709:21,
inlined from ‘solidity::evmasm::Inliner::shouldInlineFullFunctionBody(unsigned long, ranges::span<solidity::evmasm::AssemblyItem const, -1l>, unsigned long) const’ at /builddir/build/BUILD/solidity-0.8.29-build/solidity-0.8.29/libevmasm/Inliner.cpp:159:2:
/builddir/build/BUILD/solidity-0.8.29-build/solidity-0.8.29/libevmasm/AssemblyItem.h:163:9: error: ‘MEM[(const struct AssemblyItem &)&D.578956].m_instruction’ may be used uninitialized [-Werror=maybe-uninitialized]
163 | AssemblyItem(AssemblyItem const&) = default;
| ^~~~~~~~~~~~
/builddir/build/BUILD/solidity-0.8.29-build/solidity-0.8.29/libevmasm/Inliner.cpp: In member function ‘solidity::evmasm::Inliner::shouldInlineFullFunctionBody(unsigned long, ranges::span<solidity::evmasm::AssemblyItem const, -1l>, unsigned long) const’:
/builddir/build/BUILD/solidity-0.8.29-build/solidity-0.8.29/libevmasm/Inliner.cpp:159:9: note: ‘<anonymous>’ declared here
159 | };
| ^
cc1plus: all warnings being treated as errors
gmake[2]: *** [libevmasm/CMakeFiles/evmasm.dir/build.make:236: libevmasm/CMakeFiles/evmasm.dir/Inliner.cpp.o] Error 1
gmake[2]: *** Waiting for unfinished jobs....
gmake[2]: Leaving directory '/builddir/build/BUILD/solidity-0.8.29-build/solidity-0.8.29/redhat-linux-build'
gmake[1]: Leaving directory '/builddir/build/BUILD/solidity-0.8.29-build/solidity-0.8.29/redhat-linux-build'
gmake[1]: *** [CMakeFiles/Makefile2:453: libevmasm/CMakeFiles/evmasm.dir/all] Error 2
gmake: *** [Makefile:139: all] Error 2
Btw are you really sure you need -03? AFAIK it works (improves performance) only in a limited number of use cases while surely increases a binary size. In some use cases it is known to decrease performance.
Ubuntu folks after a discussion and benchmarking decided to keep -O2:
Earlier in this cycle, we [announced plans](https://discourse.ubuntu.com/t/ubuntu-foundations-25-04-plucky-puffin-
roadmap/50695) to enable the O3 optimization level for all Ubuntu packages by default. As part of this effort, we conducted
extensive benchmarking, which revealed that while some workloads saw improvements, overall system performance slightly
declined, and binary sizes increased. Given these results, we are likely to revert this change soon. Stay tuned for a detailed
post on our findings in the next few week!
It is known that you need to build apps with Profile-Guided Optimization to fully enjoy performance increase (if any) and I don't see if solidity is here yet.
Also here is a GCC developer's comment on switching to -O3 blindly.
Thanks for reporting this! Ignoring the debate on O2 vs O3 for now: while these maybe-uninitialized warnings are sometimes spurious, GCC was indeed right in this case. I have opened a PR that hopefully fixes that.
Btw are you really sure you need -03?
Not really. I would not be surprised if we do not. These settings go all the way back to the initial configuration of cpp-ethereum (https://github.com/ethereum/cpp-ethereum-cmake/commit/e064ae0a8003f1f1f6cd2fd26b969122111fd118) that was done in ancient times. Solidity started as a part of that project but the repo was later split off (still sharing configuration) and eventually became completely separate (#770). Most of the CMake configuration was brought in back then. It's 10 years of accumulated cruft by now and could use some serious refactoring.
This never seemed cause problems so there was not much reason to look deeper into it, especially since there are always more pressing things to work on. But if -O2 is indeed better or even just the same, we would not have anything against switching to that. If anyone is up for playing with this and benchmarking the results, we'd appreciate a PR :)
BTW, since the warning wasn't really spurious, I wonder why it did not appear with -O2. It's odd for optimization to affect analysis, but if anything, I'd expect the more optimized code to mangle the input more and silence something.
To investigate this further, I ran some benchmarks on the legacy pipeline and viaIR pipeline. Here are the results averaged over three runs for the current develop:
Legacy
uniswap-v4-2022-06-16: 2.0% change from 3.9s (-O3) to 4.0s (-O2)
openzeppelin-5.0.2: 6.3% change from 7.7s (-O3) to 8.2s (-O2)
openzeppelin-4.9.0: 5.3% change from 9.5s (-O3) to 10.0s (-O2)
liquity-2024-10-30: 5.6% change from 8.2s (-O3) to 8.6s (-O2)
openzeppelin-4.7.0: 4.9% change from 14.0s (-O3) to 14.7s (-O2)
openzeppelin-4.8.0: 5.8% change from 15.8s (-O3) to 16.7s (-O2)
viaIR
uniswap-v4-2022-06-16: 9.3% change from 14.7s (-O3) to 16.1s (-O2)
openzeppelin-5.0.2: 8.0% change from 23.5s (-O3) to 25.4s (-O2)
openzeppelin-4.9.0: 8.3% change from 30.1s (-O3) to 32.6s (-O2)
liquity-2024-10-30: 8.1% change from 34.2s (-O3) to 37.0s (-O2)
openzeppelin-4.7.0: 7.8% change from 41.9s (-O3) to 45.2s (-O2)
openzeppelin-4.8.0: 22.6% change from 38.5s (-O3) to 47.2s (-O2)
... which is not that great. OZ 4.8 on viaIR might have been a fluke due to something else going on on my system. Still, an 8% performance hit is probably not something we can live with, especially not on viaIR.
When executing the same benchmarks on the viaIR pipeline with numerical ids integrated:
viaIR
uniswap-v4-2022-06-16: 8.2% change from 12.2s (-O3) to 13.2s (-O2)
openzeppelin-5.0.2: 7.6% change from 19.7s (-O3) to 21.2s (-O2)
openzeppelin-4.9.0: 10.1% change from 24.5s (-O3) to 27.0s (-O2)
liquity-2024-10-30: 3.1% change from 26.6s (-O3) to 27.4s (-O2)
openzeppelin-4.7.0: 3.3% change from 32.6s (-O3) to 33.7s (-O2)
openzeppelin-4.8.0: 3.2% change from 37.0s (-O3) to 38.2s (-O2)
@clonker Did you post the right results for the numerical ID branch? They are via IR but seem more in line with legacy timing.
You made me rightfully paranoid, I reran the benchmarks, updated the data. It is in line with legacy timing now. Unfortunately but also not surprisingly :)