SkillAgentSearch skills...

Jmp

C++20 Static Branch library

Install / Use

/learn @qlibs/Jmp
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

// <!-- // 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

MIT Licence Version Build Try it online

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

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

View on GitHub
GitHub Stars98
CategoryDevelopment
Updated18h ago
Forks8

Languages

C++

Security Score

85/100

Audited on Apr 7, 2026

No findings