In this lab we will be working on AArch64 system.
Part 1: Auto-Vectorization
- For this lab, we are using the same vol1.c file as in the Algorithm Selection Lab. For the first requirement we had to modify the Makefile to include -fopt-info-vec-all. After compilation, this option generates a list of loops that have been vectorized as well as non-vectorized along with reasons for the same.
CCOPTS = -g -O3 -fopt-info-vec-all
- We compiled vol1.c and the output shows us that loop 1 and 3 are not vectorized. Loop 2 is vectorized.
Analyzing loop at vol1.c:38 vol1.c:38:2: note: not vectorized: unsupported use in stmt. Analyzing loop at vol1.c:32 vol1.c:32:2: note: LOOP VECTORIZED Analyzing loop at vol1.c:25 vol1.c:25:2: note: not vectorized: loop contains function calls or data references that cannot be analyzed
- Our next goal is to modify one more loop (1 or 3) so that it becomes vectorized. Initially this is what our last non-vectorized loop looked like
// Sum up the data
for (x = 0; x < SAMPLES; x++) {
ttl=(ttl+data[x])%1000;
}
‘data’ is summed up and added to ‘ttl’ and then its remainder. This loop was not being vectorized because of the modular that calculates the remainder. We slightly changed the code to get the remainder after the loop
// Sum up the data
for (x = 0; x < SAMPLES; x++) {
ttl+=data[x];
}
ttl=ttl%1000;
After compiling again, the loop is now vectorized.

Part 2: Inline Assembler
- We looked into add.c and understood its functioning. The code adds ‘a’ and ‘b’ and assigns it to ‘c’
int main() {
int a = 3;
int b = 19;
int c;
// __asm__("assembly code template" : inputs : outputs : clobbers)
__asm__("add %0, %1, %2" : "=r"(c) : "r"(a),"r"(b) );
printf("%d\n", c);
}
Our next step was to modify the code so that does ‘b%a’ instead of the addition using inline assembler. I used ‘udiv’ to find the result of ‘b/a’. ‘udiv r0, r1, r2’ divides ‘r1’ and ‘r2’ and places the quotient in ‘r0’. The remainder should calculated separately. For the remainder I used msub. ‘msub r0, r1, r2, r3’ loads ‘r0’ with ‘r3-(r1*r2)’ which is the remainder.
// __asm__("assembly code template" : inputs : outputs : clobbers)
__asm__("udiv %0, %1, %2" : "=r"(c) : "r"(b),"r"(a));
__asm__("msub %0, %1, %2, %3" : "=r"(c) : "r"(a),"r"(c), "r"(b));
printf("%d\n", c);
}

- In the next part, we had examine vol_inline.c. It contains a volume scaling program which uses inline assembler and SQDMULH. This is the result with 5000000 SAMPLES (this is the value of SAMPLES in vol.h)

- When using 500000000 SAMPLES, here is the result

- when reducing it to 50 SAMPLES,

The run time and the results of the program depends on the value of SAMPLES. Increasing the value of SAMPLES results in a greater run time.
Part 3: C Intrinsics
- In this part, we have to examine vol_intrinsics.c which uses C intrinsics for a volume scaling problem to access AArch64 SIMD instructions. As I did earlier I ran the program with initial 5000000 SAMPLES

- When increasing it to 10000 SAMPLES, here is the result

- when reducing it to 10 SAMPLES, this is the result

Once again, the run time and the results of the program depends on the value of SAMPLES. Increasing the value of SAMPLES results in a greater run time.
























