0

I'm trying to read a csr register using function macro

I have a struct array that contains name and address of csr registers

typedef struct csr_lists
{
    int address;
    const cahr* name;
} csr_lists;

csr_lists list[] = 
{
    {0xc00, "CYCLE"},
    ...
};

And the function I made:

#define csr_read(csr)                               \
({                                                  \
    register uint32_t v;                            \
    __asm__ __volatile__ ("csrr %0, %1"             \
                  : "=r" (v)                        \
                  : "n" (csr)                       \
                  : "memory");                      \
    v;                                              \
})

So it is called like uint64_t value = csr_read(list[i].address); or uint64_t value = csr_read(0xc00);

And the compiler gives me following errors

csr.h:68:2: error: asm operand 1 probably doesn’t match constraints [-Werror]
   68 |  __asm__ __volatile__ ("csrr %0, %1"    \
      |  ^~~~~~~
csr.c:127:25: note: in expansion of macro ‘csr_read’
  127 |         value[i] = csr_read(list[i].address);
      |  
csr.h:68:2: error: impossible constraint in ‘asm’
   68 |  __asm__ __volatile__ ("csrr %0, %1"    \
      |  ^~~~~~~
csr.c:127:25: note: in expansion of macro ‘csr_read’
  127 |         value[i] = csr_read(list[i].address);
      |   
cc1: all warnings being treated as errors
/mnt/d/project/riscv32-linux/buildroot-2021.02.10/output/host/lib/gcc/riscv32-buildroot-linux-gnu/9.4.0/../../../../riscv32-buildroot-linux-gnu/bin/ld: ./libhpm.so: undefined reference to `csr_read'

How can I fix this problem?

edit) The problem happens at these lines

#define MAX    7
for (i = 0; i < MAX; i++)
{
    value[i] = csr_read(list[i].address);
}
lemoncake
  • 31
  • 5
  • 1
    Compiles fine for me with GCC10 with a constant operand. https://godbolt.org/z/aoMMax138. Obviously an [`"n"` constraint](https://gcc.gnu.org/onlinedocs/gcc/Simple-Constraints.html) can only work with a compile-time constant since it has to become a literal number in the asm at compile-time, so `csr_read(list[i].address)` is going to require optimization enabled, and constant propagation of `i` to be possible, e.g. in a loop that gets fully unrolled. – Peter Cordes May 05 '22 at 09:14
  • @PeterCordes Thank you for the comment. But I still have the same problem even after I used -funoll-all-loops options. – lemoncake May 05 '22 at 12:27
  • Oh right, `csr_lists list[]` is a non-`const` global, so constant-propagation is only possible if you enabled `-flto` or maybe only `-fwhole-program`. Or better just make it `const` or `static const`. – Peter Cordes May 05 '22 at 12:33
  • @PeterCordes Sorry to bother you again. I have a question, -flto option works very well, but making list[] a const static global variable gives me same issues. gcc options I'm using is: -c -Wall -Werror -fpic. What could go wrong? – lemoncake May 05 '22 at 14:10
  • Those options don't include optimization, so I'm not surprised there isn't sufficient constant-propagation through a named variable. Unless `i` is also `const`. – Peter Cordes May 05 '22 at 14:11
  • @PeterCordes How could `i` be `const`? – lemoncake May 05 '22 at 14:16
  • IDK, it's your program. Your options are to enable optimization (with a `const` array), or use `const` on *everything* involved in the expression including the local vars. At `-O0`, all non-`const` variables are [similar to `volatile` as far as the optimizer is concerned](https://stackoverflow.com/questions/53366394/why-does-clang-produce-inefficient-asm-with-o0-for-this-simple-floating-point), defeating constant-propagation. I thought it was clear I was recommending building with `-Og` at least. – Peter Cordes May 05 '22 at 14:17
  • Works fine for me (https://godbolt.org/z/z8oYcsaaW) with optimization enabled and the array being a global `const`. – Peter Cordes May 05 '22 at 14:22
  • @PeterCordes I unrolled the loop using `#pragma`, sorry to not mention that. Anyway, using `#pragma` or `-funroll-all-loop` option changes nothing. I made `list` and `list.address` const, but not `i` and 'value' for they are used in for loop. Ah, thank you for the comment. optimization option worked for me as well, thank you – lemoncake May 05 '22 at 14:22
  • `-funroll-all-loops` doesn't override the `-O0` default and stop the compiler from treating all variables like `volatile`. [g++ O1 is not equal to O0 with all related optimization flags](https://stackoverflow.com/q/53175916). So everything in [Why does clang produce inefficient asm with -O0 (for this simple floating point sum)?](https://stackoverflow.com/q/53366394) still applies. Even if the compiler did unroll the loop without assuming any known length, there would still be iterations without a constant `i`. – Peter Cordes May 05 '22 at 14:27

0 Answers0