Hello! Everybody!
Please help me. I would like to use named register. R6 for example. After a subroutine, which modify this register, the compiler doesnt recognize it, and place a nop where I want to rewrite this register. Here is my simple example:
register unsigned int akku __asm("r6");
unsigned char test1() { akku=1; return 12; }
unsigned char test(void) { unsigned char x,y; akku=10; //it is ok x=test1(); //this subroutine modify the akku(R6) register to 1 akku=10; //here is the problem if (x==12) { y=akku; } return y; } After the subroutine y=1. But the correct value is 10.
Here you can see the dissasembly window. The problem is the 0x8000CE6. Why it is NOP???
41: { 42: unsigned char x,y; 0x08000CDC B500 PUSH {lr} 43: akku=10; 0x08000CDE 260A MOVS r6,#0x0A 44: x=test1(); 0x08000CE0 F000F807 BL.W test1 (0x08000CF2) 0x08000CE4 4602 MOV r2,r0 45: akku=10; 0x08000CE6 BF00 NOP 46: if (x==12) 47: { 0x08000CE8 2A0C CMP r2,#0x0C 0x08000CEA D100 BNE 0x08000CEE 48: y=akku; 49: } 0x08000CEC B2F1 UXTB r1,r6 50: return y; 0x08000CEE 4608 MOV r0,r1 51: }
Thank you.
It is easier to read. The problem occured when I call the test routine...
unsigned char test(void) { unsigned char x,y; akku=10; //it is ok x=test1(); //this subroutine modify the akku(R6) register to 1 akku=10; //here is the problem if (x==12) { y=akku; } return y; }
41: { 42: unsigned char x,y; 0x08000CDC B500 PUSH {lr}
43: akku=10; 0x08000CDE 260A MOVS r6,#0x0A
44: x=test1(); 0x08000CE0 F000F807 BL.W test1 (0x08000CF2) 0x08000CE4 4602 MOV r2,r0
45: akku=10; 0x08000CE6 BF00 NOP
46: if (x==12)
47: { 0x08000CE8 2A0C CMP r2,#0x0C 0x08000CEA D100 BNE 0x08000CEE
48: y=akku;
49: } 0x08000CEC B2F1 UXTB r1,r6
50: return y; 0x08000CEE 4608 MOV r0,r1
51: }
Can you please explain it to us mere mortals. What are you trying to do? and why?
I would like to use "named register variable". It is a global variable, which is physically a core register. In my example:
so the "akku" variable is stored in R6. It is good because much more faster than access the ram. My program is very complicated, so I made a simple example program.
When I call the test() function, I set a value to akku:
akku=10; It is ok, if you see the disassembly line: 0x08000CDE 260A MOVS r6,#0x0A
after I call a subroutine, which modify the akku variable:
x=test1(); (value of x is not important)
after I want to set again the same value to akku. And this is the problem. The compiler thinks that, I want to set the same value to akku, which is already stored.
akku=10;
and this line is compilded as NOP: 0x08000CE6 BF00 NOP
Do you understand?
Long post removed, because Keil spam protection falsely detected a word not in the post - and since the word isn't in the post I can't know what to rewrite. And testing to remove different sections to locate the false match would be a waste of time.
But the compiler really needs the registers to produce good code. So use assembler if you don't like the compiler.
Thank you for your answer. I dont understand what is removed. I can read the whole post.
The cortex core has 13 general purpose registers. The C compliler doesnt use all of them. The compiler gives possibility to the user to use these registers. Of course I would like to use the complier, but it is wrong.
My original post was maybe 5 times longer.
I'm pretty sure the compiler does a better job than you can. Taking away a register from the compiler makes the compiler produce worse code. The compiler is smart enough to use the registers for the most important variables - and to adapt and switch use of the registers from function to function adapting to the needs.
You trying to lock a single variable into lifetime use of a register is in this case rather silly.
If you don't trust the compiler, then write the code in assembler and then time your code and compare with the timings of the computer-generated code. And be prepared to be surprised.
I'm programming in assembly and C for 10years, but you all right... usually... But some special situation the asm much faster and shorter. For example in my program if I turn off the named registers, and I use normal variables, I lose 10kbyte. The whole program is 150kbyte. So the the compliler not as clever as you think...
So this compliler fault is a big point for me.
An end user isn't likely to be able to resolve a compiler problem.
If you think you have found a genuine fault then keil support is a far better option.
"For example in my program if I turn off the named registers, and I use normal variables, I lose 10kbyte."
If having a single register-mapped global variable changes the code size of 10kB for a 150kB program, then you have gremlins in the program. And since you claim your smaller program isn't even working the size of it is irrelevant.
If your functions are arranged according to how your algorithms works, then the compiler would already have noticed the value of keeping this akku variable in a register for the majority of the code lines. Because the compiler will count each access to different variables and try to figure out how probable it is that a loop will happen or a jump will be taken. And then select the most important variables for use in registers.
A great way to fail that is if the variable in question is used in such a way that it needs the volatile keyword - then the compiler isn't allowed to keep RAM copies and the number of memory accesses will escalate. If your code has huge numbers of accesses to volatile variables, then it's time to take one step back and see if the code can be redesigned.
An important thing to remember is aliasing. Global variables means the compiler will have to be very wary of aliasing, which affects the ability to produce good code. Having a value sent in as a value and then returned back on function exit indicates to the compiler that the function is given ownership of the variable - so the compiler can produce much better code.
Thank you for your help. I will test these suggestions. And I try to get help from technical support.