Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

Assembly (x86-64, AArch64, RISC-V)  Module 14 – Performance and microarchitecture

Branch prediction and speculative execution

Why a hard-to-predict branch is slow, measured on sorted and shuffled data, how compilers remove it, and how speculation opens a side channel and is defended.

  • Intermediate
  • 20 minutes
  • Examples run with Python 3.14.8 and Pyodide 314.0.7
  • By MySmartCoPilot
Free core, Pro depth: 7 of 20 minutes free
Free: A branch the core cannot predict is the slow part · What the predictor learns, and when it fails · Practise. With a pass: 3 in-depth parts and 3 interview answers, about 13 minutes.

What you will learn

  • Explain how branch prediction and misprediction affect speed
  • Measure sorted and shuffled data through a branchy loop
  • Describe how a compiler removes a data-dependent branch
  • Describe how speculative execution creates side channels and how they are mitigated

Before you start

What you’ll learn · Before you start

What you will learn

  • Explain how branch prediction and misprediction affect speed
  • Measure sorted and shuffled data through a branchy loop
  • Describe how a compiler removes a data-dependent branch
  • Describe how speculative execution creates side channels and how they are mitigated

Before you start

On this page

The count_branch loop on this page reads ten million bytes and counts those at least 128. On shuffled data it takes about 2.7 ns a byte; on the same bytes sorted first, about 0.25 ns, roughly ten times faster, though it counts the same number. The bytes did not change, only their order, and with it how often one branch guessed right.

A modern core does not wait for a branch to resolve before going on. Branch prediction guesses which way the branch will go, and speculative execution: A core running instructions past a branch on the predictor's guess before it is known to be correct, discarding their results if the guess turns out wrong. runs ahead on that guess; a right guess is already done when the branch resolves, and a wrong one is thrown away. Here you measure what branch prediction costs when it fails and what the branch predictor: The hardware that guesses, from the history of earlier branches, which way a conditional branch will go, so the pipeline can keep fetching before the branch is resolved. can and cannot learn.

A branch the core cannot predict is the slow part

The loop that counts bytes at or above 128, count_branch in branch.s, has a data-dependent branch: for each byte it compares with 128 and jumps over the increment when the byte is below, so whether the branch is taken follows the data. Beside it, count_branchless turns the comparison into a 0 or 1 with cset and adds it, with no branch:

branch.s: the branchy and branchless counting loops S · branch.s
// branch.s (AArch64): two counting loops. a is in x0, n in x1; the result returns in x0.
        .text

// long count_branch(const uint8_t *a, long n): if (a[i] >= 128) count++;
        .p2align 4
        .globl  _count_branch
_count_branch:
        mov     x2, #0                  // i
        mov     x3, #0                  // count
.Lb_loop:
        cmp     x2, x1
        b.ge    .Lb_done
        ldrb    w5, [x0, x2]
        cmp     w5, #128
        b.lo    .Lb_skip                // below 128: skip the increment (a data-dependent branch)
        add     x3, x3, #1
.Lb_skip:
        add     x2, x2, #1
        b       .Lb_loop
.Lb_done:
        mov     x0, x3
        ret

// long count_branchless(const uint8_t *a, long n): count += (a[i] >= 128);
        .p2align 4
        .globl  _count_branchless
_count_branchless:
        mov     x2, #0                  // i
        mov     x3, #0                  // count
.Lbl_loop:
        cmp     x2, x1
        b.ge    .Lbl_done
        ldrb    w5, [x0, x2]
        cmp     w5, #128
        cset    w6, hs                  // w6 = 1 if byte >= 128, else 0: no data-dependent branch
        add     x3, x3, x6
        add     x2, x2, #1
        b       .Lbl_loop
.Lbl_done:
        mov     x0, x3
        ret

Step through one byte of the branchy loop, once with the guess right and once wrong:

Interactive · stage by stage A wrong guess throws speculative work away Step through the branchy count loop reading one byte, once with the guess right and once wrong.
A wrong guess throws speculative work away, step 6 of 6. Showing cmp w5,#128; b.lo, predict not taken, run ahead, the byte is known, keep the work, throw it away. In focus: throw it away, cmp w5,#128; b.lo.mispredictedother targetcmp w5,#128; b.loa data-dependent branchpredict not takenfrom recent historyrun aheadcount++, next loadthe byte is knownwas the guess right?keep the workguess was rightthrow it awaywrong guess; refetchother target

The drawing shows the whole scene; its 6 steps are listed below.

Every step as text
  1. The branch is reached. The loop compares the byte with 128 and branches on the result. The byte has just been loaded, so the comparison is not ready for a cycle or two.
  2. The predictor guesses. Rather than wait, the core guesses the branch from the recent history of this branch, say not taken, and keeps going at once.
  3. It runs ahead on the guess. On the guess the core speculatively runs the next instructions: the increment, the next load, the next compare. None of it is final yet.
  4. A right guess costs nothing. When the comparison resolves and the guess was right, the speculative work is already done and is kept. A well-predicted branch costs almost nothing.
  5. A wrong guess is thrown away. If the byte went the other way, every speculative instruction is discarded and the core refetches from the correct target. That waste is the misprediction cost.
  6. Why shuffled data is slow. With shuffled bytes the branch is a coin flip, so about half the guesses are wrong and the loop pays the flush again and again. Sorted data makes the guess easy.

A correct guess costs almost nothing. A wrong one is a pipeline flush: Discarding the instructions a core ran speculatively after a branch is resolved the other way, and refetching from the correct target; the cost of a misprediction.: the work on the predicted path is discarded and the core refetches from the correct target. LLVM’s scheduling models put that at 13 cycles on AMD’s Zen 4, 14 on Intel’s Skylake and 10 on Arm’s Neoverse V2. The run times the branchy count against the branchless one, on the bytes shuffled and then sorted:

Counting bytes >= 128, branchy and branchless, shuffled and sorted Python · branch_session.py
import pathlib
import sys

sys.path.insert(0, str(pathlib.Path(__file__).parent / "sessions"))
import session

session.run("""
# The machine the timings come from, then build the counting loops and run them
/usr/sbin/sysctl -n machdep.cpu.brand_string
clang -O2 -o branch branch_main.c branch.s
./branch
""")

Output

# The machine the timings come from, then build the counting loops and run them
$ /usr/sbin/sysctl -n machdep.cpu.brand_string
Apple M5 Pro
$ clang -O2 -o branch branch_main.c branch.s
$ ./branch
10000000 bytes, counting those >= 128, fastest of 11 runs
data       count    branchy ns/byte  branchless ns/byte
shuffled   4999537  2.658            0.261
sorted     4999537  0.250            0.250
branchy:    shuffled / sorted = 10.6x
branchless: shuffled / sorted = 1.0x
all four counts agree: yes

This output changes from run to run: the per-byte nanosecond timings and the two ratios change from run to run with the machine's load, while the counts, the check that all four agree and the shape of the table stay the same

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 branch_session.py

The branchy loop is about ten times slower on shuffled bytes than on the same bytes sorted. The branchless loop runs at the same speed on both, a ratio of 1.0: its time does not depend on the data’s order because there is no guess to get wrong. All four runs count the same 4,999,537 bytes.

Key idea

A correct branch prediction costs almost nothing; a wrong one throws away the speculative work and refetches, ten or more cycles each time. A branch whose outcome follows unpredictable data pays that cost again and again.

Checkpoint

Check: The cost of a misprediction

  1. Question 1 of 2 What does a core do when a branch it predicted turns out to go the other way?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: It discards the work it ran speculatively and refetches from the correct target.

    A wrong guess means every instruction run on the predicted path is discarded and the core starts again at the right target. That flush, ten or more cycles, is what a hard-to-predict branch costs.

  2. Question 2 of 2 In the run, the branchy count took about ten times longer on shuffled bytes than on sorted bytes, while the branchless count took the same on both. Why?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: Shuffled bytes make the branch unpredictable, so it mispredicts about half the time; the branchless loop has no such branch.

    A branch whose outcome follows the data is easy when the data is sorted and a coin flip when it is shuffled. The branchless loop replaces the branch with arithmetic, so the data's order no longer matters.

What the predictor learns, and when it fails

The predictor guesses each branch from the recent history of how it and its neighbours have gone. A branch that is almost always taken is predicted taken and is right almost always; a branch that alternates with no pattern defeats it. That is the whole difference between the two runs above. Sorted bytes make the branch taken for every low byte, which skips the increment, and then not taken for every high byte: one switch, which the predictor learns at once. Shuffled bytes make it a coin flip, so about half the guesses are wrong and the loop pays a flush on half its passes.

This is why the same instructions run fast or slow on different data. Three threads follow. A compiler can replace the data-dependent branch with a conditional select that has nothing to mispredict. The predictor’s memory is finite, so a repeating pattern is learned only while it is short enough to fit. And speculative execution has a cost beyond speed: a speculative load can leave a trace in the cache that outlasts the discarded work. That trace, a side channel: A way to learn a secret not from the data itself but from a measurable effect of handling it, such as how long an operation took or whether a cache line was loaded. left by speculative execution past a bounds check, is the mechanism of Spectre variant 1, bounds check bypass, and the reason for the defences this lesson ends with.

Checkpoint

Check: What the predictor learns

  1. Question 1 of 2 What does a branch predictor use to guess which way a branch will go?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: The recent history of how that branch and others have gone.

    A branch predictor keeps a history of outcomes and guesses from it. A branch that is almost always taken is predicted taken; one that alternates unpredictably defeats it.

  2. Question 2 of 2 A loop branches on data[i] & 1 over random data. How well will the predictor do, and what would help?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: Poorly, because the low bit is a coin flip; making the work branchless would remove the cost.

    Random data gives the branch no pattern, so the predictor is near chance. Rewriting the body without a data-dependent branch, as the compiler often does, removes the penalty.

Practise

Work on copies of branch.s, above, and of branch_main.c:

branch_main.c: fills the bytes, times both loops, then sorts C · branch_main.c
// branch_main.c: count how many of 10,000,000 bytes are >= 128, four ways, and time each.
// A branchy count has an if; a branchless count adds the comparison's 0/1 result. The data is either
// sorted (so a run of lows is followed by a run of highs: the branch is easy to predict) or shuffled
// (so each byte is a coin flip: the branch is hard to predict). The four combinations show when a branch costs.
#include <pthread/qos.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

long count_branch(const uint8_t *a, long n);      // in branch.s: if (a[i] >= 128) count++;
long count_branchless(const uint8_t *a, long n);   // in branch.s: count += (a[i] >= 128);

enum { N = 10000000, REPEAT = 11 };
static uint8_t data[N];

static uint64_t now(void) { return clock_gettime_nsec_np(CLOCK_UPTIME_RAW); }

// A small deterministic generator, so the run repeats exactly.
static uint64_t seed = 0x2545F4914F6CDD1DULL;
static uint32_t next_rand(void) {
    seed ^= seed << 13; seed ^= seed >> 7; seed ^= seed << 17;
    return (uint32_t)(seed >> 32);
}

static int by_byte(const void *a, const void *b) { return (int)*(const uint8_t *)a - (int)*(const uint8_t *)b; }

static uint64_t best_ns(long (*f)(const uint8_t *, long), long *out) {
    uint64_t best = UINT64_MAX;
    for (int r = 0; r < REPEAT; r++) {
        uint64_t t0 = now();
        *out = f(data, N);
        uint64_t t = now() - t0;
        if (t < best) best = t;
    }
    return best;
}

int main(void) {
    pthread_set_qos_class_self_np(QOS_CLASS_USER_INTERACTIVE, 0);
    for (long i = 0; i < N; i++) data[i] = (uint8_t)next_rand();
    long c;
    printf("%d bytes, counting those >= 128, fastest of %d runs\n", N, REPEAT);
    printf("data       count    branchy ns/byte  branchless ns/byte\n");
    // shuffled first: every byte is an independent draw, so >=128 is about a coin flip
    uint64_t sb = best_ns(count_branch, &c);
    long cs = c;
    uint64_t sl = best_ns(count_branchless, &c);
    long ls = c;
    printf("shuffled   %-8ld %-16.3f %.3f\n", cs, (double)sb / N, (double)sl / N);
    // sort, so all the lows come before all the highs: the branch is taken for every low byte, then never again
    qsort(data, N, 1, by_byte);
    uint64_t pb = best_ns(count_branch, &c);
    long cp = c;
    uint64_t pl = best_ns(count_branchless, &c);
    long lp = c;
    printf("sorted     %-8ld %-16.3f %.3f\n", cp, (double)pb / N, (double)pl / N);
    // The time ratios say whether the data's order matters; the counts show all four runs did the same work.
    int same = cs == cp && ls == cs && lp == cs;
    printf("branchy:    shuffled / sorted = %.1fx\n", (double)sb / pb);
    printf("branchless: shuffled / sorted = %.1fx\n", (double)sl / pl);
    printf("all four counts agree: %s\n", same ? "yes" : "no");
    return same ? 0 : 1;
}
  1. Change the threshold in branch.s from 128 to 200 and predict, before you run, how the shuffled branchy time changes.
  2. Change the data generator in branch_main.c to fill the array with a fixed repeating pattern, 0, 255, 0, 255, and predict whether the branchy loop is fast or slow on it before you measure.

The exercise works the measurement backwards: from the sorted and shuffled times and the share of wrong guesses, it estimates what one misprediction costs in cycles.

Exercise · Medium · Python

Estimate the cost of a mispredicted branch

The branchy count reads the same bytes in the same order whether they are sorted or shuffled, so the difference between its two times is the cost of the guesses it gets wrong. Write two Python functions for that model:

  1. time_per_byte(base_ns, miss_rate, penalty_cycles, ghz): the expected nanoseconds a byte, when the loop takes base_ns a byte with every guess right, a share miss_rate (from 0 to 1) of the bytes is mispredicted, and each misprediction costs penalty_cycles cycles of a core clocked at ghz gigahertz (cycles a nanosecond).
  2. penalty_cycles(sorted_ns, shuffled_ns, miss_rate, ghz): the reverse, the misprediction penalty in cycles that explains the shuffled time, taking the sorted time as the time with every guess right.

On shuffled bytes the test >= 128 is a coin flip, so about half the guesses are wrong: miss_rate is 0.5. With times close to the run on the page, 0.25 ns a byte sorted and 2.65 shuffled, and a clock taken as 4 GHz for the exercise, penalty_cycles(0.25, 2.65, 0.5, 4.0) is about 19.2 cycles, in line with the ten or more cycles a misprediction costs on current cores.

The sample tests compare results rounded to six decimal places, so floating-point rounding does not matter.

Starter code · cost.py

def time_per_byte(base_ns, miss_rate, penalty_cycles, ghz):
    """Expected nanoseconds a byte: the time with every guess right, plus the mispredictions' share."""
    return 0.0  # replace with your code


def penalty_cycles(sorted_ns, shuffled_ns, miss_rate, ghz):
    """The misprediction penalty, in cycles, that explains the shuffled time."""
    return 0.0  # replace with your code
The sample tests · test_cost.py
"""Sample tests: times close to the page's run, and a few made-up loops."""

from cost import penalty_cycles, time_per_byte


def test_no_misses_costs_nothing_extra():
    assert round(time_per_byte(0.25, 0.0, 15, 4.0), 6) == 0.25


def test_half_the_bytes_mispredicted():
    assert round(time_per_byte(0.25, 0.5, 16, 4.0), 6) == 2.25


def test_a_slower_clock_makes_each_miss_longer():
    assert round(time_per_byte(0.5, 0.25, 12, 2.0), 6) == 2.0


def test_penalty_from_times_close_to_the_page():
    assert round(penalty_cycles(0.25, 2.65, 0.5, 4.0), 6) == 19.2


def test_penalty_of_a_made_up_loop():
    assert round(penalty_cycles(1.0, 2.0, 0.25, 3.0), 6) == 12.0


def test_fewer_misses_mean_a_larger_penalty_for_the_same_gap():
    assert round(penalty_cycles(0.4, 0.9, 0.1, 2.0), 6) == 10.0


def test_the_two_functions_undo_each_other():
    shuffled = time_per_byte(0.31, 0.5, 14, 3.5)
    assert round(penalty_cycles(0.31, shuffled, 0.5, 3.5), 6) == 14.0
A hint

One misprediction costs penalty_cycles / ghz nanoseconds, and a share miss_rate of the bytes pays it, so each byte pays miss_rate * penalty_cycles / ghz on top of base_ns. For the reverse, the extra time a byte is shuffled_ns - sorted_ns: divide it by miss_rate for the cost of one miss in nanoseconds, then turn nanoseconds into cycles.

The sample tests run on this device, in your browser (Pyodide): nothing is sent to mysmartcopilot.com. The first run downloads Python (about 13.5 MB), which is kept for the next runs. A check in your browser is feedback for you, not proof that the code is right for every input.

Practice that adapts to you

Practise this lesson

5 questions about 5 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.

  1. Question 1 of 5 What is a branch misprediction?

    Choose one answer.

    Show the answer: Question 1 of 5

    Answer: The predictor guessed a branch the wrong way, so the core discards the speculative work and refetches.

    A misprediction is a wrong guess by the branch predictor: the core had run ahead on the predicted path, and now must throw that work away and start at the correct target.

  2. Question 2 of 5 A loop runs 1,000,000 passes, and its branch is guessed wrong on 10 % of them. With the 14-cycle penalty of LLVM's Skylake model, about how many cycles do the wrong guesses add?

    Type a number.

    Show the answer: Question 2 of 5

    Answer: 1400000 cycles

    10 % of 1,000,000 passes is 100,000 wrong guesses, and each throws away about 14 cycles of work, so the misses add 100,000 × 14 = 1,400,000 cycles, about a third of a millisecond at 4 GHz. A rate that looks small still costs a lot in a hot loop.

  3. Question 3 of 5 A hot loop is slow. Its only branch guards a rare error path and goes the same way on 999 of every 1,000 passes. With a misprediction costing 10 to 20 cycles, is misprediction a likely cause?

    Choose one answer.

    Show the answer: Question 3 of 5

    Answer: Unlikely: about one pass in 1,000 mispredicts, which adds only 0.01 to 0.02 cycles a pass on average, so the time goes elsewhere.

    The cost of mispredictions is the miss rate times the penalty. One miss in 1,000 passes at 10 to 20 cycles is 0.01 to 0.02 cycles a pass, so a strongly biased branch cannot explain a slow loop; look for another cause.

  4. Question 4 of 5 A branch is taken on 999 of every 1,000 passes in no fixed pattern. How well will a branch predictor do on it?

    Choose one answer.

    Show the answer: Question 4 of 5

    Answer: Very well: it will predict taken and be right about 999 times in 1,000.

    Predictors follow the bias of a branch, not a strict pattern. A branch that is taken nearly always is guessed taken and is right nearly always; only a near-even, patternless branch defeats it.

  5. Question 5 of 5 Why did sorting the array make the branchy count fast?

    Choose one answer.

    Show the answer: Question 5 of 5

    Answer: Sorted data turns the branch into a long run of taken, while the low bytes skip the increment, then a long run of not taken: one switch the predictor handles easily.

    With the bytes sorted, the branch is taken for every low byte and then not taken for every high byte: a single change the predictor learns at once, so almost every guess is right.

Removing the branch the predictor can miss Pro: opens with a Pro, Premium or Ultimate pass

If a branch has nothing to predict, it cannot be mispredicted. A compiler turns a simple data-dependent if into a conditional move: An instruction that writes its destination from one of two sources (or a cheap change of one, such as +1 or NOT) under a condition, without a branch. x86-64 cmovcc and AArch64 csel test the flags; RISC-V has no flags, so Zicond's czero pair tests a register, and two of them with an or make the select. More in “Branchless code: cmov, csel and Zicond”, computing both outcomes and choosing between them with no branch. This part reads what it emits on three ISAs and weighs when the branchless form actually wins.

In this part:

  • The compiler removes the branch
  • When removing the branch pays

2 runnable examples (Python) · about 4 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

How far ahead the predictor can see Pro: opens with a Pro, Premium or Ultimate pass

A predictor is not magic: it learns a branch’s history in a finite table, so a pattern it can follow must be short enough to fit. This part measures that reach directly.

In this part:

  • A repeating pattern is learned up to a point
  • Why a predictor needs a memory of history

2 runnable examples (Python) · about 4 minutes

Opening this part with your pass…Pro part. It opens with the same pass as the part above.

Speculation, side channels and the defences Pro: opens with a Pro, Premium or Ultimate pass

The speculation that makes a correct prediction cost almost nothing has a price that is not about speed. Because the core acts on a guess before it is known to be right, it can touch data it would never have reached on the correct path, and the trace it leaves can be measured. This part explains the mechanism in defensive terms and the standard defences; it contains no attack code.

In this part:

  • How speculation leaves a trace
  • The defences: barriers, hardening and hardware
  • What to remember about branches, patterns and speculation

1 runnable example (Python) · about 5 minutes

Opening this part with your pass…Pro part. It opens with the same pass as the part above.

Interview questions

A warm-up: a loop that filters an array is slow, and a colleague blames the cache. How would you check whether it is really branch misprediction?

I would first look at the branch in the loop and ask whether its outcome follows the data unpredictably, as a filter on a near-even condition does. Then I would sort the input, so the branch becomes predictable, and measure again: the loop still reads the same memory in the same order, so if the time falls sharply the cost was misprediction, not the cache. A second check is a branchless version, whose time should no longer depend on the order. On Linux, perf stat reads the branch-miss counter directly and settles it.

Three further questions build on it: diagnosing a data-dependent slowdown, choosing branchless, and a speculative side channel:

  1. Mid to senior

    A service's request filter runs at very different speeds on two production data sets of the same size. Profiling shows the hot function is identical. How do you find out why, and confirm it is branch misprediction?

    Model answer, Pro. Model answers open with any pass; prices are in the notice on this page. First step and follow-ups

  2. Mid to senior

    A teammate wants to make every branch in a hot loop branchless after reading that branches are slow. When do you agree, and when do you push back, with the reasoning you would give?

    Model answer, Pro. First step and follow-ups

  3. Senior to staff

    A security audit of code that indexes a buffer after a bounds check asks whether it is exposed to a speculative side channel and, if so, how to defend it without rewriting everything. How do you answer?

    Model answer, Pro. First step and follow-ups

Flashcards · 4 cards

Recall it, then check

Say the answer to yourself before you look: recalling it is what makes it stick.

  1. What does a correct branch prediction cost, and what does a wrong one cost?

    A correct guess costs almost nothing. A wrong one throws away the work done on the guessed path and refetches from the right target, ten or more cycles on current cores each time.

  2. Why did sorting the input make the same branchy filter loop about ten times faster?

    The predictor learns from history. On shuffled data the branch's outcome was unpredictable and mispredicted again and again; sorted, the outcome came in long runs the predictor guesses right.

  3. A filter loop is slow and someone blames the cache. How do you check whether branch misprediction is the cause?

    Sort the input and measure again: the loop reads the same memory in the same order, so a large drop means misprediction. A branchless version whose time no longer depends on the order confirms it, and perf stat on Linux reads the branch-miss counter directly.

  4. The core discards the work it did on a wrong guess. What can a speculative load still leave behind?

    A trace in the cache. The core runs ahead on every guess, and what a speculative load brought into the cache can outlast the discarded work.

Key takeaways

  • A correct branch prediction costs almost nothing; a misprediction flushes the speculative work and refetches, ten or more cycles on current cores.
  • The predictor learns from history, so a branch that follows unpredictable data is slow: sorting the data made the same branchy loop about ten times faster.
  • Speculative execution runs ahead on every guess, and a speculative load can leave a trace in the cache that outlasts the discarded work.

Terms in this lesson

branch predictor
The hardware that guesses, from the history of earlier branches, which way a conditional branch will go, so the pipeline can keep fetching before the branch is resolved.
pipeline flush
Discarding the instructions a core ran speculatively after a branch is resolved the other way, and refetching from the correct target; the cost of a misprediction.
side channel
A way to learn a secret not from the data itself but from a measurable effect of handling it, such as how long an operation took or whether a cache line was loaded.
speculation barrier
An instruction that limits speculative execution at the point where a program places it, one of the defences against the side channels that speculation opens.
speculative execution
A core running instructions past a branch on the predictor's guess before it is known to be correct, discarding their results if the guess turns out wrong.
speculative load hardening
A compiler defence against speculative side channels: the compiler changes the code around a program's loads so that a load run on a mispredicted path cannot pass a secret on to the instructions after it.

References

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.