├── .github ├── LICENSE └── README.md ├── jmp └── jmp.cppm /.github/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2025 Kris Jusiak 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.github/README.md: -------------------------------------------------------------------------------- 1 | ../jmp -------------------------------------------------------------------------------- /jmp: -------------------------------------------------------------------------------- 1 | // 26 | [Overview](#Overview) / [Examples](#Examples) / [API](#API) / [FAQ](#FAQ) / [Resources](#Resources) 27 | 28 | ## `jmp`: Static Branch library 29 | 30 | [![MIT Licence](http://img.shields.io/badge/license-MIT-blue.svg)](https://opensource.org/license/mit) 31 | [![Version](https://img.shields.io/github/v/release/qlibs/jmp)](https://github.com/qlibs/jmp/releases) 32 | [![Build](https://img.shields.io/badge/build-green.svg)](https://godbolt.org/z/K9TErenc4) 33 | [![Try it online](https://img.shields.io/badge/try%20it-online-blue.svg)](https://godbolt.org/z/v8W3Pzbxd) 34 | 35 | > https://en.wikipedia.org/wiki/Branch_(computer_science) 36 | 37 | ### Use cases (Performance) 38 | 39 | - Branch is relatively stable through its life cycle `and/or` 40 | - Branch is expensive to compute / require [memory access](https://en.wikipedia.org/wiki/CPU_cache) `and/or` 41 | - Branch is hard to learn by the [branch predictor](https://en.wikipedia.org/wiki/Branch_predictor) 42 | 43 | > Examples: logging, tracing, dispatching, fast path, devirtualization, ... 44 | 45 | ### Features 46 | 47 | - Single header (https://raw.githubusercontent.com/qlibs/jmp/main/jmp) / C++20 module (https://raw.githubusercontent.com/qlibs/jmp/main/jmp.cppm) 48 | - Minimal [API](#api) 49 | - Verifies itself upon include (can be disabled with `-DNTEST` - see [FAQ](#faq)) 50 | 51 | ### Requirements 52 | 53 | - C++20 ([clang++10+, g++10+](https://en.cppreference.com/w/cpp/compiler_support)) / [x86-64](https://en.wikipedia.org/wiki/X86-64) / [Linux](https://en.wikipedia.org/wiki/Linux) 54 | 55 | ### Overview 56 | 57 | > `static_branch` (https://godbolt.org/z/v8W3Pzbxd) 58 | 59 | ```cpp 60 | /** 61 | * constexpr minimal overhead static branch changed at run-time via code patching 62 | */ 63 | constexpr jmp::static_branch static_bool = false; 64 | 65 | /** 66 | * Note: `fn` can be inline/noinline/constexpr/etc. 67 | */ 68 | void fn() { 69 | if (static_bool) { // Note: [[likely]], [[unlikely]] has no impact 70 | std::puts("taken"); 71 | } else { 72 | std::puts("not taken"); 73 | } 74 | } 75 | 76 | int main() { 77 | if (not jmp::init()) { // enables run-time code patching 78 | return errno; 79 | } 80 | 81 | fn(); // not taken 82 | 83 | static_bool = true; 84 | fn(); // taken 85 | } 86 | ``` 87 | 88 | ```cpp 89 | main: // $CXX -O3 90 | # init 91 | ... 92 | 93 | # fn(); // not taken 94 | nop 95 | .Ltmp0: 96 | mov edi, OFFSET FLAT:.LC0 97 | jmp puts 98 | ret 99 | .Ltmp1: 100 | mov edi, OFFSET FLAT:.LC1 101 | jmp puts 102 | ret 103 | 104 | # static_bool = true; 105 | call static_bool.operator=(true) 106 | 107 | # fn(); // taken 108 | jmp .Ltmp1 // code patching (nop->jmp .Ltmp1) 109 | .Ltmp0: 110 | mov edi, OFFSET FLAT:.LC0 111 | jmp puts 112 | ret 113 | .Ltmp1: 114 | mov edi, OFFSET FLAT:.LC1 115 | jmp puts 116 | ret 117 | 118 | .LC0: .asciz "not taken" 119 | .LC1: .asciz "taken" 120 | ``` 121 | 122 | > `static_branch vs bool` (https://godbolt.org/z/jvKGdPMWK) 123 | 124 | ```cpp 125 | constexpr jmp::static_branch static_bool = false; 126 | 127 | void fn() { 128 | if (static_bool) { 129 | throw; 130 | } else { 131 | std::puts("else"); 132 | } 133 | } 134 | 135 | fn(): 136 | // static_bool = false; 137 | [1] [2] [3] [4] [5] [6] Instructions: 138 | 1 0 0.25 nop 139 | 1 1 0.33 lea rdi, [rip + .L.str] 140 | 1 1 0.50 jmp puts 141 | 1 1 1.00 * .LBB0_1: push rax 142 | 1 1 0.50 call __cxa_rethrow@PLT 143 | 144 | // static_bool = true; 145 | [1] [2] [3] [4] [5] [6] Instructions: 146 | 1 1 0.50 jmp .LBB0_1 147 | 1 1 0.50 lea rdi, [rip + .L.str] 148 | 1 1 0.50 jmp puts 149 | 3 2 1.00 * .LBB0_1: push rax 150 | 4 3 1.00 call __cxa_rethrow@PLT 151 | 152 | [1]: #uOps [2]: Latency [3]: RThroughput 153 | [4]: MayLoad [5]: MayStore [6]: HasSideEffects (U) 154 | ``` 155 | 156 | ```cpp 157 | bool dynamic_bool = false; 158 | 159 | void fn() { 160 | if (dynamic_bool) { 161 | throw; 162 | } else { 163 | std::puts("else"); 164 | } 165 | } 166 | 167 | fn(): 168 | // dynamic_bool = false; 169 | [1] [2] [3] [4] [5] [6] Instructions: 170 | 2 5 0.50 * cmp byte ptr [rip + dynamic_bool], 1 171 | 1 1 0.25 je .LBB0_1 172 | 1 1 0.25 lea rdi, [rip + .L.str] 173 | 1 1 0.25 jmp puts 174 | 1 1 0.50 * .LBB0_1: push rax 175 | 1 1 0.25 call __cxa_rethrow@PLT 176 | 177 | // dynamic_bool = true; 178 | [1] [2] [3] [4] [5] [6] Instructions: 179 | 2 5 0.50 * cmp byte ptr [rip + dynamic_bool], 1 180 | 1 1 0.25 je .LBB0_1 181 | 1 1 0.25 lea rdi, [rip + .L.str] 182 | 1 1 0.25 jmp puts 183 | 1 1 0.50 * .LBB0_1: push rax 184 | 1 1 0.25 call __cxa_rethrow@PLT 185 | 186 | [1]: #uOps [2]: Latency [3]: RThroughput 187 | [4]: MayLoad [5]: MayStore [6]: HasSideEffects (U) 188 | ``` 189 | 190 | > `static_branch` (https://godbolt.org/z/Tz4ox7ncv) 191 | 192 | ```cpp 193 | constexpr jmp::static_branch static_int = 0; // range: <0, 2> 194 | 195 | void fn() { 196 | switch (static_int) { 197 | default: std::unreachable(); 198 | case 0: std::puts("0"); return; 199 | case 1: std::puts("1"); return; 200 | case 2: std::puts("2"); return; 201 | } 202 | } 203 | 204 | int main() { 205 | if (not jmp::init()) { // enables run-time code patching 206 | return errno; 207 | } 208 | 209 | fn(); // 0 210 | 211 | static_int = 1; 212 | fn(); // 1 213 | 214 | static_int = 2; 215 | fn(); // 2 216 | } 217 | ``` 218 | 219 | ```cpp 220 | fn: // $CXX -O3 -fno-inline 221 | nop # code patching (nop->jmp .Ltmp1|.Ltmp2) 222 | .Ltmp0: 223 | mov edi, OFFSET FLAT:.LC0 224 | jmp puts 225 | ret 226 | .Ltmp1: 227 | mov edi, OFFSET FLAT:.LC1 228 | jmp puts 229 | ret 230 | .Ltmp2: 231 | mov edi, OFFSET FLAT:.LC2 232 | jmp puts 233 | ret 234 | 235 | main: 236 | // ... init 237 | 238 | fn() // 0 239 | 240 | call static_int.operator=(1) 241 | fn() // 1 242 | 243 | call static_int.operator=(2) 244 | fn() // 2 245 | 246 | .LC0: .asciz "0" 247 | .LC1: .asciz "1" 248 | .LC2: .asciz "2" 249 | ``` 250 | 251 | ### Examples 252 | 253 | > `variant` (https://godbolt.org/z/TKPdYPv3P) | (https://wg21.link/P2996) 254 | 255 | ```cpp 256 | template 257 | class variant { 258 | static constexpr jmp::static_branch index_ = 0u; 259 | 260 | public: 261 | constexpr variant() = default; 262 | 263 | template requires (not std::is_base_of_v>) 264 | constexpr explicit(false) variant(T&& t) { 265 | constexpr auto index = [] { 266 | std::array match{std::is_same_v>...}; 267 | return std::ranges::find(match, true) - match.begin(); 268 | }(); 269 | index_ = index; 270 | std::construct_at(&storage_.[: 271 | nonstatic_data_members_of(^storage)[index + 1u] 272 | :], std::forward(t)); 273 | } 274 | constexpr ~variant() 275 | requires (std::is_trivially_destructible_v and ...) = default; 276 | 277 | template 278 | constexpr auto visit(Fn&& fn) const -> decltype(auto) { 279 | return [&](this auto&& self) { 280 | if constexpr (I == sizeof...(Ts)) { 281 | std::unreachable(); 282 | } else { 283 | switch (index_) { 284 | default: return self.template operator()(); 285 | case I: return std::invoke(std::forward(fn), storage_.[: 286 | nonstatic_data_members_of(^storage)[I + 1u] 287 | :]); 288 | } 289 | } 290 | }(); 291 | } 292 | 293 | private: 294 | union storage; 295 | struct empty{ }; 296 | static_assert(is_type(define_class(^storage, { 297 | std::meta::data_member_spec(^empty, {.name = "empty"}), 298 | std::meta::data_member_spec(^Ts)... 299 | }))); 300 | storage storage_{.empty={}}; 301 | }; 302 | ``` 303 | 304 | ```cpp 305 | void usage(const variant& v) { 306 | v.visit(overload{ 307 | [](bool) { std::puts("bool"); }, 308 | [](int) { std::puts("int"); }, 309 | [](float) { std::puts("float"); }, 310 | }); 311 | } 312 | 313 | int main() { 314 | if (not jmp::init()) { // enables run-time code patching 315 | return errno; 316 | } 317 | 318 | variant v{}; 319 | 320 | v = true; 321 | usage(v); 322 | 323 | v = 42; 324 | usage(v); 325 | 326 | v = 42.f; 327 | usage(v); 328 | } 329 | ``` 330 | 331 | ```cpp 332 | usage(variant const&): 333 | nop # code patching (nop->jmp .Ltmp1|.Ltmp2) 334 | .Ltmp0: 335 | mov edi, OFFSET FLAT:.LC0 336 | jmp puts 337 | ret 338 | .Ltmp1: 339 | mov edi, OFFSET FLAT:.LC1 340 | jmp puts 341 | ret 342 | .Ltmp2: 343 | mov edi, OFFSET FLAT:.LC2 344 | jmp puts 345 | ret 346 | 347 | .LC0: .asciz "bool" 348 | .LC1: .asciz "int" 349 | .LC2: .asciz "float" 350 | ``` 351 | 352 | > Dispatching techniques (https://godbolt.org/z/cfKP9E8W9) 353 | 354 | ```cpp 355 | auto f1() -> int { return 42; } 356 | auto f2() -> int { return 77; } 357 | auto f3() -> int { return 99; } 358 | ``` 359 | 360 | ```cpp 361 | auto if_else(bool b) -> int { # if_else(bool): 362 | if (b) { # testl %edi, %edi 363 | return f1(); # movl $42, %ecx 364 | } else { # movl $77, %eax 365 | return f2(); # cmovnel %ecx, %eax # cmove or cmp 366 | } # retq 367 | } # 368 | 369 | auto if_else_likely(bool b) -> int { # if_else_likely(bool): 370 | if (b) [[likely]] { # movl $42, %eax # likely 371 | return f1(); # testl %edi, %edi 372 | } else { # je .LBB3_1 373 | return f2(); # retq 374 | } # .LBB3_1: 375 | } # movl $77, %eax 376 | # retq 377 | 378 | auto ternary_op(bool b) -> int { # ternary_op(bool): 379 | return b ? f1() : f2(); # testl %edi, %edi 380 | } # movl $42, %ecx 381 | # movl $77, %eax 382 | # cmovnel %ecx, %eax # often cmove 383 | # retq 384 | 385 | auto jump_table(bool b) -> int { # jump_table(bool): 386 | static constexpr int (*dispatch[])(){ # movl %edi, %eax 387 | &f1, &f2 # leaq dispatch(%rip), %rcx 388 | }; # jmpq *(%rcx,%rax,8) # or call 389 | return dispatch[b](); # 390 | } # dispatch: 391 | # .quad f1() 392 | # .quad f2() 393 | 394 | auto jump_table_musttail(bool b) -> int { # jump_table_musttail(bool): 395 | static constexpr int (*dispatch[])(bool){ # movl %edi, %eax 396 | [](bool) { return f1(); }, # leaq dispatch(%rip), %rcx 397 | [](bool) { return f2(); }, # jmpq *(%rcx,%rax,8) # always jmp 398 | }; # 399 | [[clang::musttail]] return dispatch[b](b); # dispatch: 400 | } # .quad f1::__invoke(bool) 401 | # .quad f2::__invoke(bool) 402 | 403 | auto computed_goto(bool b) -> int { # computed_goto(bool): 404 | static constexpr void* labels[]{&&L1, &&L2}; # movl %edi, %eax 405 | goto *labels[b]; # leaq labels(%rip), %rcx 406 | L1: return f1(); # jmpq *(%rcx,%rax,8) 407 | L2: return f2(); # .Ltmp15: 408 | } # movl $42, %eax 409 | # retq 410 | # .Ltmp17: 411 | # movl $77, %eax 412 | # retq 413 | # 414 | # labels: 415 | # .quad .Ltmp15 416 | # .quad .Ltmp17 417 | 418 | jmp::static_branch branch = false; # jmp(): 419 | auto jmp() -> int { # nop|jmp .Ltmp1 # code patching 420 | if (branch) { # .Ltmp0: 421 | return f1(); # movl $42, %eax 422 | } else { # retq 423 | return f2(); # .Ltmp1: 424 | } # movl $77, %eax 425 | } # retq 426 | ``` 427 | 428 | ```cpp 429 | auto if_else(int i) -> int { # if_else(int): 430 | [[assume(i >= 0 and i <= 2)]]; # cmpl $1, %edi 431 | if (i == 0) { # movl $77, %eax 432 | return f1(); # movl $99, %ecx 433 | } else if (i == 1) { # cmovel %eax, %ecx 434 | return f2(); # testl %edi, %edi 435 | } else if (i == 2) { # movl $42, %eax 436 | return f3(); # cmovnel %ecx, %eax 437 | } else { # retq 438 | std::unreachable(); 439 | } 440 | } 441 | 442 | auto switch_case(int i) -> int { # switch_case(int): 443 | [[assume(i >= 0 and i <= 2)]]; # movl %edi, %eax 444 | switch (i) { # leaq .Lswitch.table(%rip), %rcx 445 | default: std::unreachable(); # movl (%rcx,%rax,4), %eax 446 | case 0: return f1(); # retq 447 | case 1: return f2(); # .Lswitch.table(int): 448 | case 2: return f3(); # .long 42 449 | } # .long 77 450 | } # .long 99 451 | 452 | auto jump_table(int i) -> int { # jump_table(int): 453 | [[assume(i >= 0 and i <= 2)]]; # movl %edi, %eax 454 | static constexpr int (*dispatch[])(int){ # leaq dispatch(%rip), %rcx 455 | [](int) { return f1(); }, # jmpq *(%rcx,%rax,8) # always jmp 456 | [](int) { return f2(); }, # dispatch: 457 | [](int) { return f3(); }, # .quad f1() 458 | }; # .quad f2() 459 | [[clang::musttail]] return dispatch[i](i); # .quad f3() 460 | } 461 | 462 | auto computed_goto(int i) -> int { # computed_goto(int): 463 | [[assume(i >= 0 and i <= 2)]]; # movl %edi, %eax 464 | static constexpr void* labels[]{ # leaq labels(%rip), %rcx 465 | &&L1, &&L2, &&L3 # jmpq *(%rcx,%rax,8) 466 | }; # .Ltmp35: 467 | goto *labels[i]; # movl $42, %eax 468 | L1: return f1(); # retq 469 | L2: return f2(); # .Ltmp37: 470 | L3: return f3(); # movl $99, %eax 471 | } # retq 472 | # .Ltmp39: 473 | # movl $77, %eax 474 | # retq 475 | # 476 | # labels: 477 | # .quad .Ltmp35 478 | # .quad .Ltmp37 479 | # .quad .Ltmp39 480 | 481 | jmp::static_branch branch = 0; # jmp(): 482 | auto jmp() -> int { # jmp .LBB21_0|.LBB21_1|.LBB21_2 483 | switch (branch) { # .LBB21_0: 484 | default: std::unreachable(); # movl $42, %eax 485 | case 0: return f1(); # retq 486 | case 1: return f2(); # .LBB21_1: 487 | case 2: return f3(); # movl $99, %eax 488 | } # retq 489 | } # .LBB21_2: 490 | # movl $77, %eax 491 | # retq 492 | ``` 493 | 494 | > [Fast/Slow path](https://en.wikipedia.org/wiki/Fast_path) (https://godbolt.org/z/qvar9ThK9) 495 | 496 | ```cpp 497 | [[gnu::always_inline]] inline void fast_path() { std::puts("fast_path"); } 498 | [[gnu::cold]] void slow_path() { std::puts("slow_path"); } 499 | 500 | constexpr jmp::static_branch disarmed = false; 501 | 502 | void trigger() { 503 | if (not disarmed) { // { false: nop, true: jmp } 504 | fast_path(); 505 | } else { 506 | slow_path(); 507 | } 508 | } 509 | ``` 510 | 511 | ```cpp 512 | trigger(): // $CXX -O3 513 | nop # code patching (nop->jmp .Ltmp1) 514 | .Ltmp0: # fast path (inlined) 515 | mov edi, OFFSET FLAT:.LC1 516 | jmp puts 517 | .Ltmp1: # slow path (cold) 518 | jmp slow_path() # [clone .cold] 519 | ``` 520 | 521 | ### API 522 | 523 | ```cpp 524 | namespace jmp::inline v5_0_3 { 525 | /** 526 | * Minimal overhead (via code patching) static branch 527 | */ 528 | template struct static_branch; 529 | 530 | template<> struct static_branch final { 531 | /** 532 | * static_assert(sizeof(static_branch) == 1u) 533 | * @param value initial branch value (false) 534 | */ 535 | constexpr explicit(false) static_branch(const bool value) noexcept; 536 | constexpr static_branch(const static_branch&) noexcept = delete; 537 | constexpr static_branch(static_branch&&) noexcept = delete; 538 | constexpr static_branch& operator=(const static_branch&) noexcept = delete; 539 | constexpr static_branch& operator=(static_branch&&) noexcept = delete; 540 | 541 | /** 542 | * Updates branch value 543 | * @param value new branch value 544 | */ 545 | constexpr const auto& operator=(const bool value) const noexcept; 546 | 547 | [[gnu::always_inline]] [[nodiscard]] 548 | inline explicit(false) operator bool() const noexcept; 549 | }; 550 | 551 | template 552 | requires requires(T t) { reinterpret_cast(t); } and 553 | (Max - Min >= 2 and Max - Min <= 7) 554 | struct static_branch final { 555 | /** 556 | * static_assert(sizeof(static_branch) == 1u) 557 | * @param value initial branch value (false) 558 | */ 559 | constexpr explicit(false) static_branch(const T value) noexcept; 560 | constexpr static_branch(const static_branch&) noexcept = delete; 561 | constexpr static_branch(static_branch&&) noexcept = delete; 562 | constexpr static_branch& operator=(const static_branch&) noexcept = delete; 563 | constexpr static_branch& operator=(static_branch&&) noexcept = delete; 564 | 565 | /** 566 | * Updates branch value 567 | * @param value new branch value 568 | */ 569 | constexpr const auto& operator=(const T value) const noexcept; 570 | 571 | [[gnu::always_inline]] [[nodiscard]] 572 | inline explicit(false) operator T() const noexcept; 573 | }; 574 | } // namespace jmp 575 | ``` 576 | 577 | --- 578 | 579 | ### FAQ 580 | 581 | > - How does it work? 582 | > 583 | > `jmp` is using technique called code patching - which basically means that the code modifies itself. 584 | > 585 | > `jmp::static_branch` is based on https://docs.kernel.org/staging/static-keys.html and it requires `asm goto` support (gcc, clang). 586 | > `jmp` currently supports x86-64 Linux, but other platforms can be added using the same technique. 587 | > 588 | > - Walkthrough 589 | > 590 | > ```cpp 591 | > constexpr jmp::static_branch b = false; 592 | > 593 | > if (b) { 594 | > return 42; 595 | > } else { 596 | > return 0; 597 | > } 598 | > ``` 599 | > 600 | > - Will emit... 601 | > 602 | > ```cpp 603 | > main: 604 | > .byte 15 31 68 0 0 # nop - https://www.felixcloutier.com/x86/nop 605 | > .LBB0: 606 | > xor eax, eax # return 0 607 | > ret 608 | > .LBB1: 609 | > mov eax, 42 # return 42 610 | > ret 611 | > ``` 612 | > 613 | > - Will effectively execute... 614 | > 615 | > ```cpp 616 | > main: 617 | > nop 618 | > xor eax, eax # return 0 619 | > ret 620 | > ``` 621 | > 622 | > - If the branch value will be changed (at run-time)... 623 | > 624 | > ```cpp 625 | > b = true; 626 | > 627 | > if (b) { 628 | > return 42; 629 | > } else { 630 | > return 0; 631 | > } 632 | > ``` 633 | > 634 | > - Will emit... 635 | > 636 | > ```cpp 637 | > main: 638 | > call b.operator=(true); # nop->jmp or jmp->nop 639 | > 640 | > jmp .LBB1: (nop->jmp - changed in the memory of the program) 641 | > .LBB0: 642 | > xor eax, eax # return 0 643 | > ret 644 | > .LBB1: 645 | > mov eax, 42 # return 42 646 | > ret 647 | > ``` 648 | > 649 | > - What platforms are supported? 650 | > 651 | > Only x86_64 is currently supported but the technique is compatible with other platforms as proven by https://docs.kernel.org/staging/static-keys.html. 652 | > 653 | > - What is the cost of switching the branch? 654 | > 655 | > Cost = number of inlined versions * memcpy (`5 bytes` for `static_branch` or `4 bytes` for `static_branch`). 656 | > In case of `[[gnu::noinline]]` the cost is a single memcpy otherwise it will be a loop over all inlined versions. 657 | > 658 | > - How to disable running tests at compile-time? 659 | > 660 | > When `-DNTEST` is defined static_asserts tests wont be executed upon include. 661 | > Note: Use with caution as disabling tests means that there are no gurantees upon include that given compiler/env combination works as expected. 662 | 663 | ### Resources 664 | 665 | > - Linux Static Keys - https://docs.kernel.org/staging/static-keys.html 666 | > - Intel Optimization Reference Manual - https://www.intel.com/content/www/us/en/developer/articles/technical/intel-sdm.html 667 | > - X86 Instruction Tables - https://www.agner.org/optimize/instruction_tables.pdf 668 | > - X86 Instruction Reference - https://www.felixcloutier.com/x86 669 | > - Latency, Throughput, and Port Usage Information - https://uops.info/table.html 670 | > - Extended Asm - https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html 671 | > - GCC`s Assembler Syntax - https://www.felixcloutier.com/documents/gcc-asm.html 672 | > - Copy-and-Patch Compilation - https://arxiv.org/abs/2308.14185 673 | > - Semi-static Conditions in Low-latency C++ for High Frequency Trading - https://arxiv.org/abs/2011.13127 674 | 675 | ### License 676 | 677 | > - [MIT](LICENSE) 678 | 679 |