Stage 0 - Stage 0 - 2026.1 English - XD100

Vitis Tutorials: AI Engine Development (XD100)

Document ID
XD100
Release Date
2026-07-20
Version
2026.1 English

The following figure shows the processing performed by Stage 0. Here a single butterfly round reorders local pairs of consecutive samples. You must perform a total of eight parallel comparisons per stage. With float data types, you use fpmax() and fpmin() intrinsics. Alternatively you call the AIE API functions as shown in the example.

figure

The following code block implements Stage 0 using intrinsics. You store the full compliment of 16 input samples in a 16-lane vector register. The fpmax() and fpmin() intrinsics provide the core sorting functionality, each performing eight parallel comparisons in SIMD fashion in a single cycle. The fpshuffle16() intrinsics perform input and output data shuffling, moving all eight top butterfly samples to a single 8-lane vector register and all eight bottom samples to another. After identifying the maximum and minimum samples, you store them back in the 16-lane vector. Smaller values occupy the top positions, and larger values occupy the bottom positions. Profiling with aiesimulator shows this intrinsic code requires 27 cycles per invocation.

void __attribute__((noinline)) bitonic_fp16::stage0_intrinsic( aie::vector<float,16>& vec )
{
  static constexpr unsigned BFLY_STAGE0_TOP_I = 0xECA86420;
  static constexpr unsigned BFLY_STAGE0_BOT_I = 0xFDB97531;
  static constexpr unsigned BFLY_STAGE0_TOP_O = 0xB3A29180;
  static constexpr unsigned BFLY_STAGE0_BOT_O = 0xF7E6D5C4;
  vec = fpshuffle16(vec,0,BFLY_STAGE0_TOP_I,BFLY_STAGE0_BOT_I);
  aie::vector<float,8> v_top = vec.extract<8>(0);
  aie::vector<float,8> v_bot = vec.extract<8>(1);
  aie::vector<float,8> v_mx = fpmax(v_top,v_bot);
  aie::vector<float,8> v_mn = fpmin(v_top,v_bot);
  vec = aie::concat(v_mn,v_mx);
  vec = fpshuffle16(vec,0,BFLY_STAGE0_TOP_O,BFLY_STAGE0_BOT_O);
}

The code below implements Stage 0 using AIE API. The full compliment of 16 input samples are stored in a 16-lane vector register. Here, the aie::filter_even() API pulls out the top butterfly samples by selecting the even numbered lanes. The aie::filter_odd() pulls out the bottom butterfly samples by selecting the odd numbered lanes. The aie::max() and aie::min() API’s identify the largest and smallest samples for each butterfly. Finally, the aie::interleave_zip() API collects the two 8-lane inputs into a 16-lane output vector, assigning even lanes from the first vector and odd lanes from the second vector. This code is functionally equivalent to the intrinsic version above. Profiling reveals it requires 28 cycles per invocation.

void __attribute__((noinline)) bitonic_fp16::stage0_api( aie::vector<float,16>& vec )
{
  aie::vector<float,8> v_top = aie::filter_even(vec);
  aie::vector<float,8> v_bot = aie::filter_odd(vec);
  aie::vector<float,8> v_mx = aie::max(v_top,v_bot);
  aie::vector<float,8> v_mn = aie::min(v_top,v_bot);
  std::tie(v_mn,v_mx) = aie::interleave_zip(v_mn,v_mx,1);
  vec = aie::concat(v_mn,v_mx);
}