Accumulator Registers - Accumulator Registers - 2025.2 English - UG1079

AI Engine Kernel and Graph Programming Guide (UG1079)

Document ID
UG1079
Release Date
2025-11-26
Version
2025.2 English

The accumulation registers are 384 bits wide and can be viewed as eight vector lanes of 48 bits each. The idea is to have 32-bit multiplication results and accumulate over those results without bit overflows. The 16 guard bits allow up to 216 accumulations. The output of fixed-point vector MAC and MUL intrinsic functions is stored in the accumulator registers. The following table shows the set of accumulator registers and how smaller registers are combined to form large registers.

Table 1. Accumulator Registers
384-bit 768-bit
aml0 bm0
amh0
aml1 bm1
amh1
aml2 bm2
amh2
aml3 bm3
amh3

The accumulator registers are prefixed with the letters 'am'. Two of them are aliased to form a 768-bit register that is prefixed with 'bm'. The to_vector operation moves a value from an accumulator register to a vector register with any required shifting and rounding.

aie::accum<acc48,8> acc;

// shift right 10 bits from accumulator 
aie::vector<int32,8> res=acc.to_vector<int32>(10);register to vector register

The from_vector operation is used to move a value from a vector register to an accumulator register with upshifting.

aie::vector<int32,8> v;
aie::accum<acc48,8> acc;

// shift left 10 bits
// from vector register to accumulator register
acc.from_vector(v, 10);
aie::print(acc,true,"acc value=");

Besides from_vector() and to_vector() functions, aie::accum class has the following member functions similar to aie::vector:

insert()
Updates the contents of a region of the accumulator using the values in the given native subaccumulator and returns a reference to the updated accumulator.
grow()
Returns a copy of the current accumulator in a larger accumulator. The value of the new elements is undefined.
extract()
Returns a subaccumulator with the contents of a region of the accumulator.
cast_to()
Reinterprets the current accumulator as an accumulator of the given type. The number of elements is automatically computed by the function.
int32 data[8]={1,2,3,4,5,6,7,8};
aie::vector<int32,8> v=aie::load_v<8>(data);
aie::accum<acc48,8> acc; 

// shift left 0 bits
acc.from_vector(v, 0); 

aie::accum<acc48,16> acc2=acc.grow<16>();
aie::print(acc2,true,"acc2 value=");


acc2.insert(1,acc);
aie::print(acc2,true,"acc2 value=");


// extract lower part, and cast to cacc48
aie::accum<cacc48,4> cacc1=acc2.extract<8>(0).cast_to<cacc48>();
aie::print(cacc1,true,"cacc1 value=");
Floating-point intrinsic functions do not have separate accumulation registers and instead return their results in a vector register. The following streaming data APIs can be used to read and write floating-point accumulator data from or to the cascade stream.
aie::vector<float,8> readincr_v<8>(input_cascade<accfloat> * str);
aie::vector<cfloat,4> readincr_v<4>(input_cascade<caccfloat> * str);
void writeincr(output_cascade<accfloat>* str, aie::vector<float,8> value);
void writeincr(output_cascade<caccfloat>* str, aie::vector<cfloat,4> value);

For additional details on stream APIs, see Streaming Data API. For additional details on buffers, see Input and Output Buffers.