Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

miniscript: make operator""_mst consteval #28657

Merged
merged 1 commit into from May 4, 2024

Conversation

sipa
Copy link
Member

@sipa sipa commented Oct 16, 2023

It seems modern compilers don't realize that all invocations of operator""_mst can be evaluated at compile time, despite the constexpr keyword.

Since C++20, we can force them to evaluate at compile time using consteval, turning all the miniscript type constants into actual compile-time constants.

This should give a nice but not very important speedup for miniscript logic, but it's also a way to start testing C++20 features.

@DrahtBot
Copy link
Contributor

DrahtBot commented Oct 16, 2023

The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

Code Coverage

For detailed information about the code coverage, see the test coverage report.

Reviews

See the guideline for information on the review process.

Type Reviewers
ACK hebasto, theuni
Concept ACK fanquake

If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update.

@sipa
Copy link
Member Author

sipa commented Oct 16, 2023

Ping @maflcko.

src/script/miniscript.h Outdated Show resolved Hide resolved
@sipa sipa force-pushed the 202310_miniscript_consteval branch 5 times, most recently from 3f33a3f to d6777bc Compare October 16, 2023 16:34
@sipa sipa changed the title miniscript: make operator_mst consteval in C++20 mode miniscript: make operator""_mst consteval in C++20 mode Oct 16, 2023
@fanquake fanquake added this to the 27.0 milestone Oct 17, 2023
@fanquake
Copy link
Member

Concept ACK. It's annoying that we have to refactor this code just to accomodate MSVC. I agree that we should just wait until branch-off, and use conteval directly. Put this on 27.x.

@sipa
Copy link
Member Author

sipa commented Dec 11, 2023

Rebased.

@sipa sipa changed the title miniscript: make operator""_mst consteval in C++20 mode miniscript: make operator""_mst consteval Dec 11, 2023
@darosior
Copy link
Member

CI is failing with

/usr/bin/ld: /usr/bin/ld: DWARF error: invalid or unhandled FORM value: 0x23
libbitcoin_common.a(libbitcoin_common_a-descriptor.o): in function `(anonymous namespace)::ParseScript(unsigned int&, Span<char const>&, (anonymous namespace)::ParseScriptContext, FlatSigningProvider&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&)':
descriptor.cpp:(.text+0x390f): undefined reference to `miniscript::operator"" _mst(char const*, unsigned int)'
/usr/bin/ld: descriptor.cpp:(.text+0x396c): undefined reference to `miniscript::operator"" _mst(char const*, unsigned int)'
/usr/bin/ld: descriptor.cpp:(.text+0x39ed): undefined reference to `miniscript::operator"" _mst(char const*, unsigned int)'
/usr/bin/ld: libbitcoin_common.a(libbitcoin_common_a-descriptor.o): in function `std::shared_ptr<miniscript::Node<unsigned int> const> miniscript::internal::Parse<unsigned int, (anonymous namespace)::KeyParser>(Span<char const>, (anonymous namespace)::KeyParser const&)':
descriptor.cpp:(.text+0x1df07): undefined reference to `miniscript::operator"" _mst(char const*, unsigned int)'
/usr/bin/ld: libbitcoin_common.a(libbitcoin_common_a-descriptor.o): in function `(anonymous namespace)::MiniscriptDescriptor::MaxSatisfactionElems() const':
descriptor.cpp:(.text+0x2d316): undefined reference to `miniscript::operator"" _mst(char const*, unsigned int)'
/usr/bin/ld: libbitcoin_common.a(libbitcoin_common_a-descriptor.o):descriptor.cpp:(.text+0x2d333): more undefined references to `miniscript::operator"" _mst(char const*, unsigned int)' follow
clang: error: linker command failed with exit code 1 (use -v to see invocation)

@hebasto
Copy link
Member

hebasto commented Jan 1, 2024

Concept ACK.

@hebasto
Copy link
Member

hebasto commented Jan 1, 2024

Could the CI issues be due to Clang partially supporting consteval before clang-17?

@maflcko
Copy link
Member

maflcko commented Jan 2, 2024

Locally, it works, starting with clang++-15.

@maflcko
Copy link
Member

maflcko commented Jan 2, 2024

Confirmed that this cuts a third of the runtime off of the fuzz input from #28832 (comment)

@fanquake
Copy link
Member

fanquake commented Jan 2, 2024

Maybe we should also retry the straight constexpr -> consteval change, without having to do all the refactoring for MSVC? Microsoft might have fixed their compiler.

@sipa
Copy link
Member Author

sipa commented Jan 2, 2024

@fanquake See #29167

@maflcko maflcko mentioned this pull request Jan 5, 2024
@maflcko
Copy link
Member

maflcko commented Jan 12, 2024

Maybe mark as draft while this is waiting on #29165? (29165 won't happen unless someone bumps google's oss-fuzz's clang)

@sipa sipa marked this pull request as draft January 12, 2024 15:28
@maflcko maflcko modified the milestones: 27.0, 28.0 Jan 29, 2024
@DrahtBot DrahtBot removed this from the 28.0 milestone Apr 25, 2024
@maflcko
Copy link
Member

maflcko commented Apr 29, 2024

Could rebase, as CI on master should now be passing with clang-15 in.

@maflcko
Copy link
Member

maflcko commented May 3, 2024

@sipa

@hebasto
Copy link
Member

hebasto commented May 3, 2024

Could rebase, as CI on master should now be passing with clang-15 in.

As we now build the fuzz.exe on MSVC, this PR seems require a little adjustment while rebasing:

--- a/src/test/fuzz/miniscript.cpp
+++ b/src/test/fuzz/miniscript.cpp
@@ -391,6 +391,7 @@ std::optional<NodeInfo> ConsumeNodeStable(MsCtx script_ctx, FuzzedDataProvider&
     bool allow_K = (type_needed == ""_mst) || (type_needed << "K"_mst);
     bool allow_V = (type_needed == ""_mst) || (type_needed << "V"_mst);
     bool allow_W = (type_needed == ""_mst) || (type_needed << "W"_mst);
+    static constexpr auto B{"B"_mst}, K{"K"_mst}, V{"V"_mst}, W{"W"_mst};
 
     switch (provider.ConsumeIntegral<uint8_t>()) {
         case 0:
@@ -440,22 +441,22 @@ std::optional<NodeInfo> ConsumeNodeStable(MsCtx script_ctx, FuzzedDataProvider&
         }
         case 11:
             if (!(allow_B || allow_K || allow_V)) return {};
-            return {{{"B"_mst, type_needed, type_needed}, Fragment::ANDOR}};
+            return {{{B, type_needed, type_needed}, Fragment::ANDOR}};
         case 12:
             if (!(allow_B || allow_K || allow_V)) return {};
-            return {{{"V"_mst, type_needed}, Fragment::AND_V}};
+            return {{{V, type_needed}, Fragment::AND_V}};
         case 13:
             if (!allow_B) return {};
-            return {{{"B"_mst, "W"_mst}, Fragment::AND_B}};
+            return {{{B, W}, Fragment::AND_B}};
         case 15:
             if (!allow_B) return {};
-            return {{{"B"_mst, "W"_mst}, Fragment::OR_B}};
+            return {{{B, W}, Fragment::OR_B}};
         case 16:
             if (!allow_V) return {};
-            return {{{"B"_mst, "V"_mst}, Fragment::OR_C}};
+            return {{{B, V}, Fragment::OR_C}};
         case 17:
             if (!allow_B) return {};
-            return {{{"B"_mst, "B"_mst}, Fragment::OR_D}};
+            return {{{B, B}, Fragment::OR_D}};
         case 18:
             if (!(allow_B || allow_K || allow_V)) return {};
             return {{{type_needed, type_needed}, Fragment::OR_I}};
@@ -472,25 +473,25 @@ std::optional<NodeInfo> ConsumeNodeStable(MsCtx script_ctx, FuzzedDataProvider&
         }
         case 20:
             if (!allow_W) return {};
-            return {{{"B"_mst}, Fragment::WRAP_A}};
+            return {{{B}, Fragment::WRAP_A}};
         case 21:
             if (!allow_W) return {};
-            return {{{"B"_mst}, Fragment::WRAP_S}};
+            return {{{B}, Fragment::WRAP_S}};
         case 22:
             if (!allow_B) return {};
-            return {{{"K"_mst}, Fragment::WRAP_C}};
+            return {{{K}, Fragment::WRAP_C}};
         case 23:
             if (!allow_B) return {};
-            return {{{"V"_mst}, Fragment::WRAP_D}};
+            return {{{V}, Fragment::WRAP_D}};
         case 24:
             if (!allow_V) return {};
-            return {{{"B"_mst}, Fragment::WRAP_V}};
+            return {{{B}, Fragment::WRAP_V}};
         case 25:
             if (!allow_B) return {};
-            return {{{"B"_mst}, Fragment::WRAP_J}};
+            return {{{B}, Fragment::WRAP_J}};
         case 26:
             if (!allow_B) return {};
-            return {{{"B"_mst}, Fragment::WRAP_N}};
+            return {{{B}, Fragment::WRAP_N}};
         case 27: {
             if (!allow_B || !IsTapscript(script_ctx)) return {};
             const auto k = provider.ConsumeIntegral<uint16_t>();

@sipa sipa force-pushed the 202310_miniscript_consteval branch from 190fa2a to 73619b8 Compare May 3, 2024 12:05
@sipa
Copy link
Member Author

sipa commented May 3, 2024

@hebasto Thanks, rebased and applied.

@sipa sipa marked this pull request as ready for review May 3, 2024 12:05
@hebasto
Copy link
Member

hebasto commented May 3, 2024

@hebasto Thanks, rebased and applied.

Sorry. It doesn't work -- #30031.

UPD. More adjustment needed.

Copy link
Member

@hebasto hebasto left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK 73619b8.

I apologise for messing up.

The #30031, which is built on top of this PR, succeeds. It includes additional code changes in src/test/fuzz/miniscript.cpp (with some inconsistency in local variable naming).

@sipa feel free to pull changes from #30031 into this PR.

@DrahtBot DrahtBot requested a review from fanquake May 3, 2024 12:55
@DrahtBot DrahtBot removed the CI failed label May 3, 2024
@theuni
Copy link
Member

theuni commented May 3, 2024

utACK with or without @hebasto's additional changes.

It seems modern compilers don't realize that all invocations of operator""_mst
can be evaluated at compile time, despite the constexpr keyword.

Since C++20, we can force them to evaluate at compile time, turning all the
miniscript type constants into actual compile-time constants.

It appears that MSVC does not support consteval operator"" when used inside
certain expressions. For the few places where this happens, define a
constant outside the operator call.

Co-Authored-By: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com>
@sipa sipa force-pushed the 202310_miniscript_consteval branch from 73619b8 to 6331710 Compare May 3, 2024 15:39
@sipa
Copy link
Member Author

sipa commented May 3, 2024

Incorporated the changes from #30031.

Copy link
Member

@hebasto hebasto left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

re-ACK 6331710.

@DrahtBot DrahtBot requested a review from theuni May 3, 2024 15:44
Copy link
Member

@theuni theuni left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

utACK 6331710

@fanquake fanquake merged commit eb0bdbd into bitcoin:master May 4, 2024
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants