Dear all, I am using the Keil 5.23 and running simulation for the STM32F103ZE
I am using optimization Level 0 (-O0)
In C, I have declared two variables i j i = 0x12345678 j = 0x87654321
then I have 2 instructions in C
dummy = i + j;
dummy = i - j;
When I switch to Disassembly and looking to the disassembly code,
the register value
R2 = 0x12345678; R3 = 0x87654321; before executing the ADD r2,r2,r3 the XPSR shows
N = 1, Z = 0, C = 1, V = 0, Q = 0, T = 1; After the ADD instruction, results remains the same.. However, from the addition, there should be NO Carry after the addition, why the status of the xPSR not updated ?
It would be grateful if I can get any help on that.. Thanks, Yours FOX
Dear Sir,
Thanks for your reply. However, the Assembly instruction is translated by the ARMCC How can I force the ARMCC to use ADDS instead of ADD
Since for similar code dummy = i - j, the ARMCC translated to SUBS.
Thanks for your help
How can I force the ARMCC to use ADDS instead of ADD
You cannot.
Dear Robert, Thanks for your reply. However, in that case, can you enlighten me why the compiler will do this way ?
Actually I want to let the students know in assembly how the flags works.
in my program I tried to let them do some operations.
i.e.
int i,j, dummy;
dummy = i & j ; <- In assembly, it will be translated to ANDS dummy = i | j ; <- In assembly, it will be translated to ORRS dummy = i ^ j ; <- In assembly, it will be translated to EORS dummy = i + j ; <- In assembly, it will be translated to ADD dummy = i - j ; <- In assembly, it will be translated to SUBS
How come only ADD it will not affect the flags ? if i = 0x7FFFFFFF; and j = 0x00000001; then after ADD, it will have an overflow
Can you enlighten me why the compiler translated this way ?
As you said, if I cannot force the compiler to use ADDS, any alternatives that I can do ? Thanks for your help. Yours WU, Chi Hang
If you want full control of what instructions are generated you should be writing in assembly language.
As far as the code generated, what you say is generated seems valid so there is nothing there to complain about. When I write assembly language I never set the flags unless I am going to test the flags, but that is mostly because it is an extra letter to type. That is not really an issue for the code generation from the compiler so it really only has to make sure the code generated is valid.
Dear Robert, Thanks for your reply. I understand that if I want to full use, I need to use assembly language.
Even if I write in assembly language, I am not setting the flags because the flags should be set by the machine upon the result of the execution of the code.
Anyway, I am not complaining anything but just want somebody to enlighten me why this exception of ADD is in the case while all others instruction will have an S suffix..
As you said, it is complier generated assembly language, generating one more S will not take too much time but that would affect others to use assembly to check if the status of the processor is correct.
Thanks for your help. Yours WU, Chi Hang
How can you be teaching this stuff when you clearly lack understanding yourself?
But, that said, I remember being in classes where some students were way more familiar with the subject than the lecturer.
You might find it useful to read up on the ARM instruction set and some C tutorials.
Dear Nevil,
Thanks for your comment, and I am sure I am clear what I teach to my students.
As said in my previous post, and up to now, there is no one telling me why the compiler is doing this way and I am trying my best to understand the logic from the compiler.
Learning is a continuous process, and that's why I am eager to ask and see if I can learn more things from the forum and I am stating my point and let others to comment in what way I am thinking wrongly.
Finally, I had my solution to solve the problem using the assembly code, but at this moment I still cannot understand why the compiler only translate the i + j differently in comparison to other & | ^ and - commands.
Actually I am switching from IAR to Keil, the other compiler does not have this problem and that makes me to think why Keil is doing this way.
For sure I will be trying my best to read the ARM instruction set and the C tutorials to make my teaching better, but I am disappointed with the atmosphere of this forum.
Thanks anyway. Yours WU, Chi Hang
The very first thing you must understand is that the compiler is doing nothing wrong and it is not a problem.
So long as the compiler produces code that satisfies the requirements of the original source code and the relevant language standards, then it is free to create that code in any way it wishes. So long as the compiler complies with these requirements it is free to use ADD or ADDS.
Most sane people using the compiler will not care what precise instructions are being generated by the compiler. To expect otherwise is a problem of the person questioning the situation.
As already stated, if you need precise instruction sequences, you should be using assembler.
Thanks for your prompt reply and enlighten me by the following..
So long as the compiler produces code that satisfies the requirements of the original source code and the relevant language standards, then it is free to create that code in any way it wishes.
As a result, I will solve the problem using assembly language.
Many thanks for your time and effort.
Yours, WU, Chi Hang.
> I still cannot understand why the compiler only translate the i + j differently in comparison to other & | ^ and - commands. <
In my testing,
int main(void) { int i; int x = 0x12345678; // volatile int y = 0xDEADBEEF; // volatile int z; // volatile for(;;) { z = x + y; UART2_putchar( z ); z = x - y; UART2_putchar( z ); z = x & y; UART2_putchar( z ); z = x | y; UART2_putchar( z ); z = x ^ y; UART2_putchar( z ); } }
My result is: + <-> ADDS - <-> SUBS & <-> AND | <-> ORR ^ <-> EOR
I would assume that more testing is needed.
Dear John, Thanks for your further help ...
From your setting, AND ORR EOR will not update flags.. and upon my further testing ..
my setting is somehow differ than you and as follows..
int i,j; int dummy; int main(void) { int x, y; // int z; i = 0x12345678; j = 0x87654321; x = i; y = j; dummy = i & j; // ANDS dummy = x & y; // AND // z = i & j; // results NOP // z = x & y; // results NOP dummy = i | j; // ORRS dummy = x | y; // ORR // z = i | j; // results NOP // z = x | y; // results NOP dummy = i ^ j; // EORS dummy = x ^ y; // EOR // z = i ^ j; // results NOP // z = x ^ y; // results NOP dummy = i + j; // ADD dummy = x + y; // ADDS // z = i + j; // results NOP // z = x + y; // results NOP dummy = i - j ; // SUBS dummy = x - y ; // SUBS // z = i - j; // results NOP // z = x - y; // results NOP while(1) { __asm("NOP"); }; }
I tried to declare a int z; in main and repeat all the instructions and replace dummy with z // as above.. all are translated as NOP.
It seems related to global and local variable ?
Thanks for your time, John. I really appreciate your help and testing.
BTW, all the code are in Optimization Level 0.
You're using the word testing as if you're trying to identify a fault.
There is NO fault. Even if you find a way of achieving what you want today, there is absolutely NO guarantee that the next release (or previous release) will create the same code.
As I indicated before, the compiler is free to use whatever instructions it wants. If you want specific instructions, you'll need to do so in assembler.
Rather than trying to persuade the compiler to do what you want, you should really understand what the compiler is permitted to do.
The compiler is likely trying to preserve the state of the flags so it can carry forward a previous test. That's the point of having the ADD and ADDS variants in the first place.
The compiler gets to manage the use of the general purpose registers, including the flags. It also has to work with the subset of instructions a particular ISA provides.
These are more likely to use the ADDS form because the result is of importance. if (++c == 0) puts("foo"); if ((a += b) >= 0) puts("bar");
One might want to review RISC concepts, especially ARM's conditional execution. In other architectures the dependency hazards caused by the availability of the result/status of the prior instruction to the pipeline.
>>For sure I will be trying my best to read the ARM instruction set and the C tutorials to make my teaching better, but I am disappointed with the atmosphere of this forum.
Unfortunately we see the results of poor/ineffective teaching methods here a lot, so it is a point of frustration.
If a student comes here expecting us to do their homework from scratch the teacher has failed. Failed to provide them with the insight to do the work, and failed to teach basic problem solving and logical deduction, rather than just "ask the internet" or cut-n-paste some code together, they don't understand, hoping for a Shakespeare-Monkey event to occur.
I'm an EE with a BEng, on paper you are likely a lot more qualified, so I have higher expectations.
Chi Hang,
I believe that, you already know that your above assumption is incorrect. This is what I have tried to convince you.
And I also believe that, from Westonsupermare Pier's 15-Jun-2017 13:34 GMT post, you (and me) already know that compiler chooses instructions based on the Source Code Context. When the demo source code is so short, compiler just chooses instructions whatever it likes.
Please don't be disappointed with the atmosphere of this forum, you did get the help you need (not from me) from Westonsupermare Pier's valuable post.
Many Thanks for Westonsupermare Pier.