3.5.2.4.2 Limitations and Workarounds

Access-based partitioning will not create new accessing instructions and therefore can only modify existing ones. This limits partitions to be the same shape as the range of accesses, with overlapping ranges merged into the same partition. A side-effect of this is that if there are multiple overlapping ranges, the partition may become large and reduce performance gain.

int array[8];
int result = 0;

...

#pragma HLS loop unroll factor(1)
for (i = 0; i < 5; i++) {
    result += array[i]
}

#pragma HLS loop unroll factor(1)
for (i = 4; i < 8; i++) {
    result += array[i]
}

In the above snippet there are two accesses to an array in two loops. The range of accesses of the first loop is from element 0 to 4 of the array, the range of accesses of the second loop is from element 4 to 7 of the array. In this case the two accesses have element 4 overlapping. They will be merged and the generated partition will cover the entire array which results in the memory being left unpartitioned.

int array[8];
int result = 0;

...

#pragma HLS loop unroll factor(1)
for (i = 0; i < 4; i++) {
    result += array[i]
}

result += array[4];
result += array[4];

#pragma HLS loop unroll factor(1)
for (i = 5; i < 8; i++) {
    result += array[i]
}

To work around this, try unrolling the loops with pragmas or manually unrolling overlapping accesses, as shown in the code snippet above. This is done to create more non-overlapping access ranges and therefore more partitions. In the above code snippet, the loops are manually unrolled so that each access has a range that does not overlap with any other access. This allows access-based partitioning to partition the array into three partitions, one for each non-overlapping access.

Indexing arrays outside of any array dimension, even when the resulting address is inside of the memory, is not supported by memory partitioning and may cause incorrect circuit behavior. An example of this is casting a 2-d array to a pointer or only using the lowest dimension index to iterate through the entire 2-d array.

#pragma HLS memory partition variable(array)
int array[8][8];
int result = 0;

...

int *p = array;
#pragma HLS loop unroll factor(1)
// unsupported loop 1
for (i = 0; i < 64; i++) {
    result += *(p+i);
}

#pragma HLS loop unroll factor(1)
// unsupported loop 2
for (i = 0; i < 64; i++) {
    result += array[0][i];
}

In the code snippet above, both styles of access to the array go past the end of the right-most dimension bound by incrementing the index from 0 to the size of the array. A supported access pattern would to be to access the array as a 2-d array in a nested for loop, with the index to each dimension never going outside of the dimension bound.

int array[2][2] = {{0, 1}, {2, 3}};

In the same way, initializers, memcpy calls and other memory intrinsic calls are unsupported as they cast the pointer given to a byte pointer and accesses the number of bytes specified in a loop. In the access-based partitioning case, memory intrinsic calls will be detected and partitioning of the affected memories will be disabled. With user-specified partitioning, the memory intrinsic call will be handled to allow correct analysis of the out of bounds accesses. To avoid this in the access-based partitioning case, you can manually initialize memories in a nested for loop to ensure correct analysis.

In general, avoid aliasing memories if you want to use memory partitioning on a memory.

Avoid comparisons and other non-arithmetic operators on pointers as they are not supported by memory partitioning and will prevent partitioning.