andrew@teletron.UUCP (Andrew Scott) (10/06/87)
Many C compilers have one variation or another on the asm() "function". It allows one to insert inline assembly code in the middle of C code. I have been playing around with it a bit, and have a question. (The code I'm writing is targeted for a specific hardware system, so no flames for unportability please). What can I do in an asm() statement? The question arises because I was bitten by the compiler's code generation method. I was writing a function (for the 68000, if you don't recognize the assembly code) which must be non-interruptable. I have to disable all interrupts before executing the code, and re-enable them to the previous level when I'm done. My function looked something like: #define disable asm("mov.w %sr,-(%sp)"); asm("mov.w &0x2700,%sr") /* push current status register on stack, mask out interrupts */ #define restore asm("mov.w (%sp)+,%sr") /* restore status register from stack save location */ foo(a, b) int a, b; { int x, y; disable; bar(a, b); /* other stuff */ restore; } Was I correct in assuming the stack would be available to save the status reg.? The compiler I use (stock AT&T /bin/cc) does a wierd thing upon the call to foo. It allocates one more longword than necessary when creating foo's stack frame. The actual assembly output of the above function (obtained via cc -S) is: global foo foo: link %fp,&-12 /* allocate space for x, y & ? */ mov.w %sr,-(%sp) /* disable */ mov.w &0x2700,%sr /* "" */ mov.l 12(%fp),(%sp) /* note this is not a push of b */ mov.l 8(%fp),-(%sp) /* push a on stack */ jsr bar add.w &4,%sp /* clean up stack */ mov.w (%sp)+,%sr /* restore */ unlk %fp /* dealloocate stack frame */ rts Note that 12 bytes were allocated for local variables within the stack frame. Only 8 bytes (four each for x & y) are needed. Therefore, the stack pointer points to an unused longword location. Notice that the call to bar only pushes one argument. The argument b is simply moved to the unused location. This really messes up the intended action of disable, because the saved status register is overwritten. To conclude a long story, should I really be angry at whoever wrote the compiler for doing such a strange thing, or should I avoid asm statements altogether because I can't count on anything? The alternative is rather barfy: foo(a, b) int a, b; { int x, y; short ps; ps = disable(); /* actual function call */ bar(a, b); /* other stuff */ restore(ps); } Here, disable & restore are actual function calls to external assembly coded subroutines. There is much more overhead involved, and the functions which require the use of disable & restore are all quite time critical. Thanks for enduring a rather long posting and question. Andrew
eric@ms.uky.edu (Eric Herrin) (10/07/87)
My general philosophy when doing this sort of thing is to use static data structures instead of the stack. This at least allows the compiler to do any funny business it likes with the stack. The method of keeping the stack pointer pointing at an unused location is quite common, as I have used many unix compilers which do this. I believe if you are going to the trouble of hacking in assembly code anyway, you should simply look at what is being generated before running the routines. Then you could, in your case, use the unused location yourself and then decrement the stack pointer to keep the compiled code happy. eric -- | Eric Herrin II cbosgd!ukma!eric | | "'tis better to be silent eric@UKMA.BITNET | | and be THOUGHT a fool, than to open eric@ms.uky.csnet | | one's mouth and remove all doubt." eric@ms.uky.edu |
karl@haddock.ISC.COM (Karl Heuer) (10/08/87)
In article <110@teletron.UUCP> andrew@teletron.UUCP (Andrew Scott) writes: >[Tried to use the stack from an asm() instruction, and got bitten] Well, in my opinion, the compiler is free to do whatever is easiest or most efficient as long as it has the appropriate semantics. If an asm() escape is provided, it's the user's responsibility to know enough about the compiler to avoid colliding with the generated code. >The compiler I use ... allocates one more longword than necessary when >creating foo's stack frame. If this is a consistent feature, you could save %sr in that slot, and then decrement the stack to make a new slot for the function to use. Or, you could avoid the stack entirely and store %sr in a static location, if you don't need to nest the disable/enable calls. Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint
chip@ateng.UUCP (Chip Salzenberg) (10/09/87)
In article <110@teletron.UUCP> andrew@teletron.UUCP (Andrew Scott) writes: > > #define disable asm("mov.w %sr,-(%sp)"); asm("mov.w &0x2700,%sr") > /* push current status register on stack, mask out interrupts */ > > #define restore asm("mov.w (%sp)+,%sr") > /* restore status register from stack save location */ > >The compiler I use (stock AT&T /bin/cc) does a wierd thing upon the call to foo. >It allocates one more longword than necessary when creating foo's stack frame. This is a feature! Your C code runs faster as a result. Try the following: #define disable { asm("mov.w %sr,(%sp)"); \ asm("subq.l &4,%sp"); \ asm("mov.w &0x2700,%sr"); } #define enable { asm("addq.l &4,%sp"); \ asm("mov.w (%sp),%sr"); } > Andrew -- Chip Salzenberg "chip@ateng.UUCP" or "{uunet,usfvax2}!ateng!chip" A.T. Engineering My employer's opinions are not mine, but these are. "Gentlemen, your work today has been outstanding. I intend to recommend you all for promotion -- in whatever fleet we end up serving." - JTK
jholbach@wright.EDU (Jim Holbach) (10/10/87)
in article <110@teletron.UUCP>, andrew@teletron.UUCP (Andrew Scott) says: > > The compiler I use (stock AT&T /bin/cc) does a wierd thing upon the call to foo. > It allocates one more longword than necessary when creating foo's stack frame. The logic I've read for this is that it reduces the amount of pushing and popping required for function calls (from within functions) because at least one longword is always sitting on the stack. Only when more than one parameter is used, is it necessary to change the stack pointer. (This was from the manual for C with CPM-68K but it seems that the same logic is involved here. ) > This really messes up the intended action of disable, because the saved > status register is overwritten. > > To conclude a long story, should I really be angry at whoever wrote the compiler > for doing such a strange thing, or should I avoid asm statements altogether > because I can't count on anything? The alternative is rather barfy: > require the use of disable & restore are all quite time critical. Why not just adapt your definitions of enable/disable to the observed behavior of your compiler? Since you know and accept that the definitions are machine/compiler specific, how about something like the following: #define disable asm("mov.w %sr,(%sp)"); \ asm("mov.w &0x2700,%sr"); \ asm("sub.w &4,%sp") #define restore asm("add.w &4,%sp"); \ asm("mov.w (%sp)+,%sr") Jim Holbach Wright State University Dayton, Ohio
henry@utzoo.UUCP (Henry Spencer) (10/11/87)
> What can I do in an asm() statement? ...
The answer is utterly, totally, irremediably compiler-dependent. If your
compiler documentation does not discuss the issue, then the only answer is
"try it and see", remembering that you will have to re-try it with every
new release of the compiler!
--
"Mir" means "peace", as in | Henry Spencer @ U of Toronto Zoology
"the war is over; we've won". | {allegra,ihnp4,decvax,utai}!utzoo!henry
henry@utzoo.UUCP (Henry Spencer) (10/11/87)
> The method of keeping the stack pointer pointing at an unused location is > quite common, as I have used many unix compilers which do this... Yes, people trying to work in assembler around C compilers should be aware that this is a standard tactic. There are three reasons for it. First, moving a value to an already-vacant stack-top location is quicker than pushing it onto the stack in many machines. Second, it becomes unnecessary to remove the argument from the stack after calling a one-argument function. And third, on some machines it is easier to remove one or two words from the stack than to remove a more general number, and these efficient removal sequences then apply to a larger fraction of all functions. The first and second reasons also apply to using the stacktop location as an expression-evaluation temporary. This tactic does require careful attention to situations like function calls within function argument lists, but it is a cheap and effective optimization if done right. -- "Mir" means "peace", as in | Henry Spencer @ U of Toronto Zoology "the war is over; we've won". | {allegra,ihnp4,decvax,utai}!utzoo!henry
john@frog.UUCP (John Woods, Software) (10/15/87)
In article <110@teletron.UUCP>, andrew@teletron.UUCP (Andrew Scott) writes: > > Many C compilers have one variation or another on the asm() "function"... > What can I do in an asm() statement? "Nothing." > The question arises because I was > bitten by the compiler's code generation method. That's where the answer comes from. > I was writing a function which must be non-interruptable. ... > Should I be angry with the compiler writer...? No. The only solution you can believe in is to use function calls to assembly modules. This way, you can (A) know that it really works for real, not by accident, (B) change the compiler at will (next release of the same one, or a new compiler altogether -- which would basically chuck your old asm()s out the window, most likely, and SOME compilers do not permit asm statements at all (some don't even have an assembly language intermediate stage)), and (C) change to a new processor type with less effort (the assembly code is localized in one module). If your time-critical routine cannot deal with wasting 72 clock cycles on subroutine linkage (5.76 microseconds at 12.5Mc, plus wait states), then you probably ought to write the whole routine in assembly, because the C compiler is probably wasting more than that on other little bobbles. "Pluck the millisecond-wasting bad algorithms from thine own mind before complaining about the micro-second wasting nature of high-level languages." Or something like that. -- John Woods, Charles River Data Systems, Framingham MA, (617) 626-1101 ...!decvax!frog!john, ...!mit-eddie!jfw, jfw@eddie.mit.edu "Cutting the space budget really restores my faith in humanity. It eliminates dreams, goals, and ideals and lets us get straight to the business of hate, debauchery, and self-annihilation." -- Johnny Hart