Jmp
C++20 Static Branch library
Install / Use
/learn @qlibs/JmpREADME
// <!-- // The MIT License (MIT) // // Copyright (c) 2024 Kris Jusiak <kris@jusiak.net> // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. // #if 0 // --> Overview / Examples / API / FAQ / Resources
jmp: Static Branch library
https://en.wikipedia.org/wiki/Branch_(computer_science)
Use cases (Performance)
- Branch is relatively stable through its life cycle
and/or - Branch is expensive to compute / require memory access
and/or - Branch is hard to learn by the branch predictor
Examples: logging, tracing, dispatching, fast path, devirtualization, ...
Features
- Single header (https://raw.githubusercontent.com/qlibs/jmp/main/jmp) / C++20 module (https://raw.githubusercontent.com/qlibs/jmp/main/jmp.cppm)
- Minimal API
- Verifies itself upon include (can be disabled with
-DNTEST- see FAQ)
Requirements
- C++20 (clang++10+, g++10+) / x86-64 / Linux
Overview
static_branch<bool>(https://godbolt.org/z/v8W3Pzbxd)
/**
* constexpr minimal overhead static branch changed at run-time via code patching
*/
constexpr jmp::static_branch<bool> static_bool = false;
/**
* Note: `fn` can be inline/noinline/constexpr/etc.
*/
void fn() {
if (static_bool) { // Note: [[likely]], [[unlikely]] has no impact
std::puts("taken");
} else {
std::puts("not taken");
}
}
int main() {
if (not jmp::init()) { // enables run-time code patching
return errno;
}
fn(); // not taken
static_bool = true;
fn(); // taken
}
main: // $CXX -O3
# init
...
# fn(); // not taken
nop
.Ltmp0:
mov edi, OFFSET FLAT:.LC0
jmp puts
ret
.Ltmp1:
mov edi, OFFSET FLAT:.LC1
jmp puts
ret
# static_bool = true;
call static_bool.operator=(true)
# fn(); // taken
jmp .Ltmp1 // code patching (nop->jmp .Ltmp1)
.Ltmp0:
mov edi, OFFSET FLAT:.LC0
jmp puts
ret
.Ltmp1:
mov edi, OFFSET FLAT:.LC1
jmp puts
ret
.LC0: .asciz "not taken"
.LC1: .asciz "taken"
static_branch<bool> vs bool(https://godbolt.org/z/jvKGdPMWK)
constexpr jmp::static_branch<bool> static_bool = false;
void fn() {
if (static_bool) {
throw;
} else {
std::puts("else");
}
}
fn():
// static_bool = false;
[1] [2] [3] [4] [5] [6] Instructions:
1 0 0.25 nop
1 1 0.33 lea rdi, [rip + .L.str]
1 1 0.50 jmp puts
1 1 1.00 * .LBB0_1: push rax
1 1 0.50 call __cxa_rethrow@PLT
// static_bool = true;
[1] [2] [3] [4] [5] [6] Instructions:
1 1 0.50 jmp .LBB0_1
1 1 0.50 lea rdi, [rip + .L.str]
1 1 0.50 jmp puts
3 2 1.00 * .LBB0_1: push rax
4 3 1.00 call __cxa_rethrow@PLT
[1]: #uOps [2]: Latency [3]: RThroughput
[4]: MayLoad [5]: MayStore [6]: HasSideEffects (U)
bool dynamic_bool = false;
void fn() {
if (dynamic_bool) {
throw;
} else {
std::puts("else");
}
}
fn():
// dynamic_bool = false;
[1] [2] [3] [4] [5] [6] Instructions:
2 5 0.50 * cmp byte ptr [rip + dynamic_bool], 1
1 1 0.25 je .LBB0_1
1 1 0.25 lea rdi, [rip + .L.str]
1 1 0.25 jmp puts
1 1 0.50 * .LBB0_1: push rax
1 1 0.25 call __cxa_rethrow@PLT
// dynamic_bool = true;
[1] [2] [3] [4] [5] [6] Instructions:
2 5 0.50 * cmp byte ptr [rip + dynamic_bool], 1
1 1 0.25 je .LBB0_1
1 1 0.25 lea rdi, [rip + .L.str]
1 1 0.25 jmp puts
1 1 0.50 * .LBB0_1: push rax
1 1 0.25 call __cxa_rethrow@PLT
[1]: #uOps [2]: Latency [3]: RThroughput
[4]: MayLoad [5]: MayStore [6]: HasSideEffects (U)
static_branch<T, T Min, T Max>(https://godbolt.org/z/Tz4ox7ncv)
constexpr jmp::static_branch<int, 0, 2> static_int = 0; // range: <0, 2>
void fn() {
switch (static_int) {
default: std::unreachable();
case 0: std::puts("0"); return;
case 1: std::puts("1"); return;
case 2: std::puts("2"); return;
}
}
int main() {
if (not jmp::init()) { // enables run-time code patching
return errno;
}
fn(); // 0
static_int = 1;
fn(); // 1
static_int = 2;
fn(); // 2
}
fn: // $CXX -O3 -fno-inline
nop # code patching (nop->jmp .Ltmp1|.Ltmp2)
.Ltmp0:
mov edi, OFFSET FLAT:.LC0
jmp puts
ret
.Ltmp1:
mov edi, OFFSET FLAT:.LC1
jmp puts
ret
.Ltmp2:
mov edi, OFFSET FLAT:.LC2
jmp puts
ret
main:
// ... init
fn() // 0
call static_int.operator=(1)
fn() // 1
call static_int.operator=(2)
fn() // 2
.LC0: .asciz "0"
.LC1: .asciz "1"
.LC2: .asciz "2"
Examples
variant(https://godbolt.org/z/TKPdYPv3P) | (https://wg21.link/P2996)
template<class... Ts>
class variant {
static constexpr jmp::static_branch<std::size_t, 0, sizeof...(Ts)> index_ = 0u;
public:
constexpr variant() = default;
template<class T> requires (not std::is_base_of_v<variant, std::remove_cvref_t<T>>)
constexpr explicit(false) variant(T&& t) {
constexpr auto index = [] {
std::array match{std::is_same_v<Ts, std::remove_cvref_t<T>>...};
return std::ranges::find(match, true) - match.begin();
}();
index_ = index;
std::construct_at(&storage_.[:
nonstatic_data_members_of(^storage)[index + 1u]
:], std::forward<T>(t));
}
constexpr ~variant()
requires (std::is_trivially_destructible_v<Ts> and ...) = default;
template<class Fn>
constexpr auto visit(Fn&& fn) const -> decltype(auto) {
return [&]<auto I = 0u>(this auto&& self) {
if constexpr (I == sizeof...(Ts)) {
std::unreachable();
} else {
switch (index_) {
default: return self.template operator()<I + 1u>();
case I: return std::invoke(std::forward<Fn>(fn), storage_.[:
nonstatic_data_members_of(^storage)[I + 1u]
:]);
}
}
}();
}
private:
union storage;
struct empty{ };
static_assert(is_type(define_class(^storage, {
std::meta::data_member_spec(^empty, {.name = "empty"}),
std::meta::data_member_spec(^Ts)...
})));
storage storage_{.empty={}};
};
void usage(const variant<bool, int, float>& v) {
v.visit(overload{
[](bool) { std::puts("bool"); },
[](int) { std::puts("int"); },
[](float) { std::puts("float"); },
});
}
int main() {
if (not jmp::init()) { // enables run-time code patching
return errno;
}
variant<bool, int, float> v{};
v = true;
usage(v);
v = 42;
usage(v);
v = 42.f;
usage(v);
}
usage(variant<bool, int, float> const&):
nop # code patching (nop->jmp .Ltmp1|.Ltmp2)
.Ltmp0:
mov edi, OFFSET FLAT:.LC0
jmp puts
ret
.Ltmp1:
mov edi, OFFSET FLAT:.LC1
jmp puts
ret
.Ltmp2:
mov edi, OFFSET FLAT:.LC2
jmp puts
ret
.LC0: .asciz "bool"
.LC1: .asciz "int"
.LC2: .asciz "float"
Dispatching techniques (https://godbolt.org/z/cfKP9E8W9)
auto f1() -> int { return 42; }
auto f2() -> int { return 77; }
auto f3() -> int { return 99; }
auto if_else(bool b) -> int { # if_else(bool):
if (b) { # testl %edi, %edi
return f1(); # movl $42, %ecx
} else { # movl $77, %eax
return f2(); # cmovnel %ecx, %eax # cmove or cmp
} # retq
} #
auto if_else_likely(bool b) -> int { # if_else_likely(bool):
if (b) [[likely]] { # movl $42, %eax # likely
return f1();
Related Skills
node-connect
351.8kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
110.9kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
351.8kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
351.8kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
