I want to use inline asm for ARMv7 with clang 3.4, in order to write low level code that accesses the CPUs control registers. As a test, I wrote a program that reads from a register, conditionally fiddles with some bits, and writes back the new value.
However, when I look at the produced machine code the entire bit-fiddling has been optimized away. Apparently I have not used the right asm constraints to tell clang that the result of writing to the register depends on what is being written. (I only used a simple "volatile" modifier).
How should I write the inline asm code so that clang generates correct asm? Here is the code test.c
typedef unsigned int uint32_t;
// code that reads and writes the ID_PFR1 register
uint32_t read_ID_PFR1() {
uint32_t a;
asm volatile ("mrc p15, 0, %0, c0, c1, 1" : : "r"(a) : );
return a;
}
void write_ID_PFR1(uint32_t a) {
asm volatile ("mcr p15, 0, %0, c0, c1, 1" :"=r"(a) : : );
}
// regular c code that modifies the register
uint32_t foo(uint32_t b) {
uint32_t a;
a = read_ID_PFR1();
write_ID_PFR1(b);
return a+b;
}
void bit_fiddle() {
uint32_t a;
a = read_ID_PFR1();
if ((a & 0x3) == 1) {
a |= 1<<2;
}
a |= 1<<3;
write_ID_PFR1(a);
}
I compiled it with
clang-3.4 -target armv7a-none-eabi test.c -o test -O3
This is the resulting machine code
$ arm-linux-gnueabi-objdump -S test
test: file format elf32-littlearm
Disassembly of section .text:
00000000 <read_ID_PFR1>:
0: ee100f31 mrc 15, 0, r0, cr0, cr1, {1}
4: e12fff1e bx lr
00000008 <write_ID_PFR1>:
8: ee000f31 mcr 15, 0, r0, cr0, cr1, {1}
c: e12fff1e bx lr
00000010 <foo>:
10: ee100f31 mrc 15, 0, r0, cr0, cr1, {1}
14: ee000f31 mcr 15, 0, r0, cr0, cr1, {1}
18: e12fff1e bx lr
0000001c <bit_fiddle>:
1c: ee100f31 mrc 15, 0, r0, cr0, cr1, {1}
20: ee000f31 mcr 15, 0, r0, cr0, cr1, {1}
24: e12fff1e bx lr
As you can see in <bit_fiddle>, nothing is left between the mrc and mcr instructions. And also see how foo fails to add together a+b in the produced machine code.
clang-3.4 -target armv7a-none-eabi test.c -o test -O0- 0x90