Interpreting the test cases for fixed-point arithmetic

I am trying to learn more about fixed-point arithmetic via the test case on Clang here:

https://github.com/llvm/llvm-project/blob/main/clang/test/Frontend/fixed_point_div_const.c

https://github.com/llvm/llvm-project/blob/main/clang/test/Frontend/fixed_point_div.c

and I am stuck trying to figure out how to interpret these lines of checks that seem to be happening, for examples:

short _Accum sa_const = 1.0hk / 2.0hk;
// CHECK-DAG: @sa_const  = {{.*}}global i16 64, align 2
// CHECK-LABEL: @sdiv_sasasa(
// CHECK-NEXT:  entry:
// CHECK-NEXT:    [[TMP0:%.*]] = load i16, i16* @sa, align 2
// CHECK-NEXT:    [[TMP1:%.*]] = load i16, i16* @sa, align 2
// CHECK-NEXT:    [[TMP2:%.*]] = call i16 @llvm.sdiv.fix.i16(i16 [[TMP0]], i16 [[TMP1]], i32 7)
// CHECK-NEXT:    store i16 [[TMP2]], i16* @sa, align 2
// CHECK-NEXT:    ret void
//
void sdiv_sasasa(void) {
  sa = sa / sa;
}

I tried to search around and I arrived at this FileCheck - Flexible pattern matching file verifier — LLVM 16.0.0git documentation, but it wasn’t very clear to me how to interpret these strings in the comment. If I have to take a guess at what was written in the first code block provided here, i.e.:

// CHECK-DAG: @sa_const  = {{.*}}global i16 64, align 2

This is checking if the bit patterns of @sa_const match whatever is describe with {{.*}}global i16 64, align 2. If that is the case, how should I interpret the string {{.*}}global i16 64, align 2? My guess is that this is a 16-bit integer that corresponds to value of 64? But then, what does align 2 mean?

Any suggestions/recommendations on how I could search for relevant materials that would help?

The output of the clang invocation is LLVM IR. LLVM Language Reference Manual — LLVM 16.0.0git documentation describes the syntax for global variables. So it’s checking that there’s a 16-bit global variable named sa_const, with alignment of 2 bytes, initialized with the value 64.

1 Like

@efriedma-quic Thanks for the response - the link to the LLVM-IR documentation does help a lot. Do you know if there would be a way for me to print out this global variable? My crude attempt looks like this:

#include <stdio.h>
#include <stdint.h>

int main() {
    short _Accum sa_const = 1.0hk / 2.0hk;
    printf("%i \n", sa_const);
}

compiled with clang:

$ clang fxpt.c -ffixed-point
fxpt.c:7:21: warning: format specifies type 'int' but the argument has type 'short _Accum' [-Wformat]
    printf("%i \n", sa_const);
            ~~      ^~~~~~~~

Even though it does print out 64 as expected, the warning message seems to indicate that I am doing something wrong…

printf doesn’t support fixed-point types; you need to convert to some other type it does support. For example:

#include <stdio.h>
#include <stdint.h>
#include <string.h>

int main() {
    short _Accum sa_const = 1.0hk / 2.0hk;
    printf("Float: %f \n", (double)sa_const);
    short reinterp;
    memcpy(&reinterp, &sa_const, sizeof(short));
    printf("Raw: %i \n", reinterp);
}
1 Like