← Glossary
CUDA glossaryExecution model
CC 7.5

What is a lane in a CUDA warp?

A thread's position inside its warp, 0 to 31, which is what shuffle and vote instructions address.

Lane 0 of warp 1 is thread 32. Every thread carries two numbers, the one you gave it and the one the hardware gave it, and the second is the one the collective instructions speak. A shuffle names a source lane. A ballot returns one bit per lane. __activemask() hands back a word where "The Nth bit is set if the Nth lane in the warp is active", so a mask is a set of lanes and never a set of thread IDs. NVIDIA's own guidance on the warp primitives puts the mask first: "The set of threads that participates in invoking each primitive is specified using a 32-bit mask, which is the first argument of these primitives."

Getting the number is cheap and the usual two spellings are the same thing. threadIdx.x & 31 and threadIdx.x % 32 both extract the low five bits, because the operand is unsigned and 32 is a power of two, so the compiler has no division to emit either way. PTX also names it outright as the special register %laneid (section 10.3 of the ISA), which is what you reach for when reading SASS on day 46.

The trap is that neither spelling is the lane id in general. Warps are cut from the linear thread ID, x + y * blockDim.x + z * blockDim.x * blockDim.y, so threadIdx.x % 32 is a lane id only while the block is one-dimensional or its x extent is a multiple of 32. A 32 by 8 block puts one row in each warp and the shortcut survives. A 16 by 16 block does not: warp 0 holds two whole rows, threads (0,0) and (0,1) are lanes 0 and 16, and the shortcut calls them both lane 0. Compute the linear ID first, then mask it.

The reason to care is that the lane number decides what an instruction costs. Memory coalescing is a statement about lanes: consecutive lanes on consecutive addresses is the cheap case. A shared-memory bank is (byteAddress / 4) % 32, one bank per lane when the mapping works out and a bank conflict when it does not. Nothing on either list mentions block IDs, and neither does the hardware.

Measured

Tesla T4, driver 595.84, CUDA 12.6 (V12.6.85), built with nvcc -O3 -arch=sm_75. Day 21 has every thread record __activemask() into its own slot and prints one launch, the 48-thread block, thread by thread. Captured 2026-08-30 on the project's verification node.

Threads Warp Lanes present Active mask each of them recorded
0 to 31 0 0 to 31 0xffffffff
32 to 47 1 0 to 15 0x0000ffff

Thread 32 is lane 0, thread 47 is lane 15, and the sixteen of them agree on a mask with sixteen bits set. Lanes 16 to 31 of that warp would be threads 48 to 63, which the launch never created, so the mask names exactly the threads that exist. Push the block down to 33 threads and the second warp is one lane wide: mask 0x00000001.

The program checks the mapping rather than printing it. For every thread of every launch in the sweep it recomputes the lane on the host and asserts that bit is set in the mask the device wrote, on the guide's rule that a calling thread is active. Every gate passed, so the lane arithmetic on this page came back off the hardware and is not a diagram of it.

Code

From code/day21-warps/warps.cu, the host-side gate. t is a thread index inside one block, so the mask and the shift are computed by two different machines and compared.

const unsigned int lane = static_cast<unsigned int>(t % kWarpSize);
if (((h_masks[t] >> lane) & 1u) == 0u) {
    std::fprintf(stderr,
                 "thread %d of the %d-thread block recorded mask "
                 "0x%08x, which does not include its own lane %u\n",
                 t, blockSize, h_masks[t], lane);
    status = EXIT_FAILURE;
    break;
}

Diagram

occupancy-stepper, preset partial-warp, lane labels on: two warp slots holding a 48-thread block, the lanes of each slot numbered 0 to 31 and the thread ID printed under each live lane, so thread 32 sits over lane 0 of the second slot.

Alt text: "Two warp slots holding 48 threads. Lane numbers restart at zero in the second warp, so thread 32 is lane 0, and the last sixteen lane positions carry no thread at all."

Related terms

Where you meet this

Sources

Byline

Written by: pending. Reviewed by: pending. Written on: pending. Last checked on: pending. The numbers came off the verification node on 2026-08-30, and this entry stays a draft until a named author and a different named reviewer sign it.