EmbeddedRelated.com
Forums
Memfault Beyond the Launch

IAR MSP430 compiler problem

Started by brOS November 23, 2009
Dear all,

Does anybody knows how to force compiler to use call instruction instead of
br(branch)for disassembling function call?
It is extremely important for me to specific function is disassembled using
call instead of brunch, as compiler always does.

Please help.....	   
					
---------------------------------------		
This message was sent using the comp.arch.embedded web interface on
http://www.EmbeddedRelated.com
On Mon, 23 Nov 2009 14:19:14 -0600
"brOS" <bogdanrosandic@gmail.com> wrote:

> Dear all, > > Does anybody knows how to force compiler to use call instruction > instead of br(branch)for disassembling function call? > It is extremely important for me to specific function is disassembled > using call instead of brunch, as compiler always does. >
A) Why is it so important to you to use CALL rather than BR? You may be falling into the trap of attacking the wrong problem. B) I think the world would be a generally happier place if more processors had a dedicated brunch instruction. I figure that properly implemented it ought to take a good hour and a half to return, and then come back with the stack smelling of coffee and bacon. -- Rob Gaddi, Highland Technology Email address is currently out of order
>On Mon, 23 Nov 2009 14:19:14 -0600 >"brOS" <bogdanrosandic@gmail.com> wrote: > >> Dear all, >> >> Does anybody knows how to force compiler to use call instruction >> instead of br(branch)for disassembling function call? >> It is extremely important for me to specific function is disassembled >> using call instead of brunch, as compiler always does. >> > >A) Why is it so important to you to use CALL rather than BR? You may >be falling into the trap of attacking the wrong problem. > >B) I think the world would be a generally happier place if more >processors had a dedicated brunch instruction. I figure that properly >implemented it ought to take a good hour and a half to return, and then >come back with the stack smelling of coffee and bacon. > >-- >Rob Gaddi, Highland Technology >Email address is currently out of order >
A) This is why...Function i'm calling have structure like this: void Spin(void){ } --------------------------------------- This message was sent using the comp.arch.embedded web interface on http://www.EmbeddedRelated.com
>On Mon, 23 Nov 2009 14:19:14 -0600 >"brOS" <bogdanrosandic@gmail.com> wrote: > >> Dear all, >> >> Does anybody knows how to force compiler to use call instruction >> instead of br(branch)for disassembling function call? >> It is extremely important for me to specific function is disassembled >> using call instead of brunch, as compiler always does. >> > >A) Why is it so important to you to use CALL rather than BR? You may >be falling into the trap of attacking the wrong problem. > >B) I think the world would be a generally happier place if more >processors had a dedicated brunch instruction. I figure that properly >implemented it ought to take a good hour and a half to return, and then >come back with the stack smelling of coffee and bacon. > >-- >Rob Gaddi, Highland Technology >Email address is currently out of order >
This is why i need it.... Function I'm calling have looks something like this: void Spin(void){ for(;;){} } So if it is disassembled with call before entering in pc will be saved on stack and it will point to instruction after function spin....So I want to use that pc and to save context so when my scheduler schedule that task again it will not continue spinning in that forever loop but it will jump to next instruction after Spin function..... branch doesn t push pc to stack so taht s my problem;) --------------------------------------- This message was sent using the comp.arch.embedded web interface on http://www.EmbeddedRelated.com
brOS wrote:
>> On Mon, 23 Nov 2009 14:19:14 -0600 >> "brOS" <bogdanrosandic@gmail.com> wrote: >> >>> Dear all, >>> >>> Does anybody knows how to force compiler to use call instruction >>> instead of br(branch)for disassembling function call? >>> It is extremely important for me to specific function is disassembled >>> using call instead of brunch, as compiler always does. >>>
...
>> > This is why i need it.... > Function I'm calling have looks something like this: > void Spin(void){ > for(;;){} > } > So if it is disassembled with call before entering in pc will be saved on > stack and it will point to instruction after function spin....So I want to > use that pc and to save context so when my scheduler schedule that task > again it will not continue spinning in that forever loop but it will jump > to next instruction after Spin function..... > branch doesn t push pc to stack so taht s my problem;)
The compiler has deduced that a branch instruction is as good as a call instruction for this/these calls of Spin. There can be two reasons for that: 1. If the compiler has seen the code of Spin (if it is in the same source-code file as the calling function) it may have deduced that Spin never returns, so it does not need the return address that a call instruction would push on the stack. Of course the compiler cannot know that your scheduler breaks C semantics (I assume by interrupting the eternal loop in Spin) and needs the return address. 2. If the call to Spin is the last statement in the calling function (a "tail call"), the compiler understands that the call does not have to push a return address, because Spin will return (assuming it would return) to the end of the calling function, which immediately returns to *its* caller. The branch instruction leaves the calling function's return address on the stack, so when Spin returns (assuming it could return) it will take a short-cut and return to the caller of the calling function. This optimization saves time and stack space. In case 1, try to put the Spin function in its own source-code file and compile it separately. When the compiler then compiles a call to Spin, it should assume that Spin may return, and therefore needs a return address and a call instruction, not a branch. In case 2, you could add some statement in the calling function after the call to Spin, that is, make sure that the call to Spin is never a tail call. On the other hand, since a tail call still leaves a valid return address on the stack, your scheduler could use this return address (the return address for the function that calls Spin). Then you don't have to do anything, it should work even with a branch instruction. Another possibility is to avoid the "High" optimization level of the compiler. I did not find a specific explanation of the tail-call-to-branch optimization in my copy of the compiler manual, but the "High" level seems to have most of the inter-procedural optimizations, of which this may be one. Try the "Medium" level for the compilation of the calling functions, and hope that the compiler does not do tail-call optimization at this level. HTH, -- Niklas Holsti Tidorum Ltd niklas holsti tidorum fi . @ .
Niklas Holsti wrote:
> brOS wrote: >>> On Mon, 23 Nov 2009 14:19:14 -0600 >>> "brOS" <bogdanrosandic@gmail.com> wrote: >>> >>>> Does anybody knows how to force compiler to use call instruction >>>> instead of br(branch)for disassembling function call? >>>> It is extremely important for me to specific function is disassembled >>>> using call instead of brunch, as compiler always does.
>> This is why i need it.... >> Function I'm calling have looks something like this: >> void Spin(void){ >> for(;;){} >> }
>
> The compiler has deduced that a branch instruction is as good as a call > instruction for this/these calls of Spin. There can be two reasons for > that:
[return address]
> In case 2, you could add some statement in the calling function after > the call to Spin, that is, make sure that the call to Spin is never a > tail call. On the other hand, since a tail call still leaves a valid > return address on the stack, your scheduler could use this return > address (the return address for the function that calls Spin). Then you > don't have to do anything, it should work even with a branch instruction. > > Another possibility is to avoid the "High" optimization level of the > compiler. I did not find a specific explanation of the > tail-call-to-branch optimization in my copy of the compiler manual, but > the "High" level seems to have most of the inter-procedural > optimizations, of which this may be one. Try the "Medium" level for the > compilation of the calling functions, and hope that the compiler does > not do tail-call optimization at this level.
volatile void Spin(void) {} ?
On Mon, 23 Nov 2009 15:08:12 -0600, "brOS" <bogdanrosandic@gmail.com>
wrote:


>This is why i need it.... >Function I'm calling have looks something like this: >void Spin(void){ >for(;;){} >} >So if it is disassembled with call before entering in pc will be saved on >stack and it will point to instruction after function spin....So I want to >use that pc and to save context so when my scheduler schedule that task >again it will not continue spinning in that forever loop but it will jump >to next instruction after Spin function..... > branch doesn t push pc to stack so taht s my problem;)
Why don't you call a context_switch() function ? -- 42Bastian Do not email to bastian42@yahoo.com, it's a spam-only account :-) Use <same-name>@monlynx.de instead !
Niklas Holsti wrote:
> brOS wrote: >>> On Mon, 23 Nov 2009 14:19:14 -0600 >>> "brOS" <bogdanrosandic@gmail.com> wrote: >>> >>>> Dear all, >>>> >>>> Does anybody knows how to force compiler to use call instruction >>>> instead of br(branch)for disassembling function call? >>>> It is extremely important for me to specific function is disassembled >>>> using call instead of brunch, as compiler always does. >>>> > ... >>> >> This is why i need it.... >> Function I'm calling have looks something like this: >> void Spin(void){ >> for(;;){} >> } >> So if it is disassembled with call before entering in pc will be saved on >> stack and it will point to instruction after function spin....So I >> want to >> use that pc and to save context so when my scheduler schedule that task >> again it will not continue spinning in that forever loop but it will jump >> to next instruction after Spin function..... >> branch doesn t push pc to stack so taht s my problem;) > > The compiler has deduced that a branch instruction is as good as a call > instruction for this/these calls of Spin. There can be two reasons for > that: > > 1. If the compiler has seen the code of Spin (if it is in the same > source-code file as the calling function) it may have deduced that Spin > never returns, so it does not need the return address that a call > instruction would push on the stack. Of course the compiler cannot know > that your scheduler breaks C semantics (I assume by interrupting the > eternal loop in Spin) and needs the return address. > > 2. If the call to Spin is the last statement in the calling function (a > "tail call"), the compiler understands that the call does not have to > push a return address, because Spin will return (assuming it would > return) to the end of the calling function, which immediately returns to > *its* caller. The branch instruction leaves the calling function's > return address on the stack, so when Spin returns (assuming it could > return) it will take a short-cut and return to the caller of the calling > function. This optimization saves time and stack space. > > In case 1, try to put the Spin function in its own source-code file and > compile it separately. When the compiler then compiles a call to Spin, > it should assume that Spin may return, and therefore needs a return > address and a call instruction, not a branch. > > In case 2, you could add some statement in the calling function after > the call to Spin, that is, make sure that the call to Spin is never a > tail call. On the other hand, since a tail call still leaves a valid > return address on the stack, your scheduler could use this return > address (the return address for the function that calls Spin). Then you > don't have to do anything, it should work even with a branch instruction. > > Another possibility is to avoid the "High" optimization level of the > compiler. I did not find a specific explanation of the > tail-call-to-branch optimization in my copy of the compiler manual, but > the "High" level seems to have most of the inter-procedural > optimizations, of which this may be one. Try the "Medium" level for the > compilation of the calling functions, and hope that the compiler does > not do tail-call optimization at this level. > > HTH, >
Your diagnosis of the problem is fair enough, but your workarounds are, IMHO, totally wrong. Anything that involves trying to trick or cripple the compiler (separate compiled files, disabling optimisations, fake extra inline assembly, gratuitous function pointer usage, etc.) is at best an ugly hack, and at worst a maintenance nightmare. Remember, the compiler is free to work around all these workarounds - lying to your tools is a bad idea. The function is called by branch, not call, because it never returns. That's what you (OP) wrote in the source code, so that's what the compiler does. If you want the function to return, you have to write code that allows the function to return. In particular, you need to have some way of exiting the spin, otherwise it is useless. Thus you should write your spin function so that it exits when that condition is satisfied. For example, void Spin(volatile uint8_t char *pBlockedFlag) { while (!(*pBlockedFlag)) ; } If you can't see why you need something along these lines, you'll have to think a bit harder about how you want your code to work. But telling the compiler you want a tight infinite loop, and then trying to find some way to break out of it, is definitely not the answer.
D Yuniskis wrote:
> Niklas Holsti wrote: >> brOS wrote: >>>> On Mon, 23 Nov 2009 14:19:14 -0600 >>>> "brOS" <bogdanrosandic@gmail.com> wrote: >>>> >>>>> Does anybody knows how to force compiler to use call instruction >>>>> instead of br(branch)for disassembling function call? >>>>> It is extremely important for me to specific function is disassembled >>>>> using call instead of brunch, as compiler always does. > >>> This is why i need it.... >>> Function I'm calling have looks something like this: >>> void Spin(void){ >>> for(;;){} >>> } > > >> The compiler has deduced that a branch instruction is as good as a >> call instruction for this/these calls of Spin. There can be two >> reasons for that: > > [return address]
Could you graciously use a few more precious key-strokes to explain what you mean by that cryptic comment?
>> In case 2, you could add some statement in the calling function after >> the call to Spin, that is, make sure that the call to Spin is never a >> tail call. On the other hand, since a tail call still leaves a valid >> return address on the stack, your scheduler could use this return >> address (the return address for the function that calls Spin). Then >> you don't have to do anything, it should work even with a branch >> instruction. >> >> Another possibility is to avoid the "High" optimization level of the >> compiler. I did not find a specific explanation of the >> tail-call-to-branch optimization in my copy of the compiler manual, >> but the "High" level seems to have most of the inter-procedural >> optimizations, of which this may be one. Try the "Medium" level for >> the compilation of the calling functions, and hope that the compiler >> does not do tail-call optimization at this level. > > volatile void Spin(void) {} ?
The IAR MSP430 C compiler reference guide explains "volatile" for objects only, it does not give "volatile" any meaning for functions. Interestingly, it accepts the above "volatile" function declaration without complaint. What do you suppose "volatile" should do, here? -- Niklas Holsti Tidorum Ltd niklas holsti tidorum fi . @ .
> Niklas Holsti wrote: >> brOS wrote: >>>> On Mon, 23 Nov 2009 14:19:14 -0600 >>>> "brOS" <bogdanrosandic@gmail.com> wrote: >>>> >>>>> Dear all, >>>>> >>>>> Does anybody knows how to force compiler to use call instruction >>>>> instead of br(branch)for disassembling function call? >>>>> It is extremely important for me to specific function is disassembled >>>>> using call instead of brunch, as compiler always does. >>>>> >> ... >>>> >>> This is why i need it.... >>> Function I'm calling have looks something like this: >>> void Spin(void){ >>> for(;;){} >>> } >>> So if it is disassembled with call before entering in pc will be >>> saved on >>> stack and it will point to instruction after function spin....So I >>> want to >>> use that pc and to save context so when my scheduler schedule that task >>> again it will not continue spinning in that forever loop but it will >>> jump >>> to next instruction after Spin function..... >>> branch doesn t push pc to stack so taht s my problem;) >> >> The compiler has deduced that a branch instruction is as good as a >> call instruction for this/these calls of Spin. There can be two >> reasons for that: >> >> 1. If the compiler has seen the code of Spin (if it is in the same >> source-code file as the calling function) it may have deduced that >> Spin never returns, so it does not need the return address that a call >> instruction would push on the stack. Of course the compiler cannot >> know that your scheduler breaks C semantics (I assume by interrupting >> the eternal loop in Spin) and needs the return address.
I experimented a bit with the IAR MSP430 compiler (current "kickstart" version), and it uses call instructions to call a non-returning function containing only an eternal for-loop, even if the function is presented in the same source-code file as the call. If the function is marked with the __noreturn keyword the compiler will use a branch or jump instruction, though. (I assume that the OP has not marked Spin with __noreturn.) So it seems my suggested reason 1 is not the true explanation.
>> 2. If the call to Spin is the last statement in the calling function >> (a "tail call"), the compiler understands that the call does not have >> to push a return address, because Spin will return (assuming it would >> return) to the end of the calling function, which immediately returns >> to *its* caller. The branch instruction leaves the calling function's >> return address on the stack, so when Spin returns (assuming it could >> return) it will take a short-cut and return to the caller of the >> calling function. This optimization saves time and stack space.
In my small experiments, the IAR compiler does code a tail call to Spin using a branch or jump instruction, instead of a call. So reason 2 is a possible explanation for the OP's observation. Interestingly, this happens even if the optimization level is set to "None", so this advice of mine:
>> Another possibility is to avoid the "High" optimization level of the >> compiler.
does not work. David Brown wrote:
> Your diagnosis of the problem is fair enough, but your workarounds are, > IMHO, totally wrong. Anything that involves trying to trick or cripple > the compiler (separate compiled files, disabling optimisations, fake > extra inline assembly, gratuitous function pointer usage, etc.) is at > best an ugly hack, and at worst a maintenance nightmare. Remember, the > compiler is free to work around all these workarounds - lying to your > tools is a bad idea.
In general I agree with you, David, but the OP is trying to run C code under a custom scheduler, apparently in some kind of simple multi-threading or coroutine style. This is out of scope for the C language, so the operation of the scheduler will involve some things that the compiler does not know about -- and should not (have to) know about. The scheduler/kernel routines should follow the C compiler's calling protocols, but will themselves do things that exceed C's semantics. Of course, the person writing the scheduler should know all about the C compiler's calling protocols and run-time system so that the scheduler can save and restore thread contexts properly. The Spin function seems intended to be part of the application/scheduler interface; an application task calls it when it has finished its job and yields to the scheduler. Writing this "yield" routine as an eternal loop is unusual, but can be OK for a custom kernel. In a more conventional kernel, the application would call a kernel "yield" or "suspend_me" function, the kernel would check if some other thread is ready to run, and if not the kernel would stick in a loop, or schedule a looping "null thread" that is always ready to run.
> The function is called by branch, not call, because it never returns.
That could be a reason, but I now doubt it for the IAR compiler -- see my note on experiments above. The tail-call explanation is the more likely one.
> That's what you (OP) wrote in the source code, so that's what the > compiler does. > If you want the function to return, you have to write > code that allows the function to return. In particular, you need to > have some way of exiting the spin, otherwise it is useless.
As I understand it, the OP's scheduler (most likely running in an interrupt handler) will break out of the "eternal" loop by popping the return address from the stack into the PC, forcing a return from Spin. This is legal MSP430 code, but out of C semantics.
> If you can't see why you need something along these lines, you'll have > to think a bit harder about how you want your code to work. But telling > the compiler you want a tight infinite loop, and then trying to find > some way to break out of it, is definitely not the answer.
Making Spin test a flag that the scheduler sets is a solution, but a different solution. It could be safer to write Spin in assembly language, to prevent the C compiler gaining any false knowledge about its behaviour, such as "does not return" knowledge. But if the OP knows that the C compiler does not transport such knowledge across compilation units, writing Spin in C (for separate compilation) is safe. Of course this has to be rechecked for each new version of the compiler, so it is indeed a maintenance burden, over and above the burden of checking for changes in the calling protocols and run-time system structure, which a scheduler author has to do for every compiler version anyway. Summary: Tail call optimization is the likely cause of the compiler using a branch instead of a call instruction. So: - If the scheduler needs the return address (on the stack) only for resuming execution at the code following the call to Spin, there is no problem; the branch instruction leaves the return address of the calling function on the stack, and the scheduler can resume execution at this address. - If the scheduler needs the return address to mark the location of the call to Spin (but why?), there is a problem if the call happens through a branch instruction, since the stacked return address then marks the location of the call to the function that calls Spin (or even the call to some even higher-level function, if there is more than one tail call at the end of the call path). In this case, and as there seems to be no way to disable the tail-call optimization in the IAR compiler, the only option is to make sure that no call to Spin is a tail-call. Or use some other kind of Spin, for example following David's suggestions. -- Niklas Holsti Tidorum Ltd niklas holsti tidorum fi . @ .

Memfault Beyond the Launch