#include <array>
#include <cstddef>
#include <iostream>
#include <numeric>
#include <stdexcept>
#include <vector>
int block_reduce(const std::vector<int>& input) {
    if(input.size()>4) throw std::invalid_argument("single block model");
    std::array<int,4> shared{};
    for(std::size_t lane=0;lane<4;++lane) shared[lane]=lane<input.size()?input[lane]:0;
    // Logical phase boundary, not a GPU barrier or a device simulation.
    for(std::size_t stride=2;stride>0;stride/=2) {
        const auto previous=shared;
        for(std::size_t lane=0;lane<stride;++lane) shared[lane]=previous[lane]+previous[lane+stride];
    }
    return shared[0];
}
int main() {
    for(std::size_t n=0;n<=4;++n) {
        std::vector<int> input(n);std::iota(input.begin(),input.end(),1);
        if(block_reduce(input)!=std::accumulate(input.begin(),input.end(),0)) throw std::runtime_error("tail");
    }
    bool rejected=false;
    try {
        const int unexpected=block_reduce({1,2,3,4,5});
        std::cout<<"unexpected oversized block sum="<<unexpected<<'\n';
        return 1;
    } catch(const std::invalid_argument&){rejected=true;}
    if(!rejected || block_reduce({3,1,4})!=8) throw std::runtime_error("block");
    std::cout<<"block_sum=8 inactive_lane=0\n";
}
