EmbeddedRelated.com
Forums

mixing C and assembly

Started by Lax April 22, 2008
Chris H wrote:

> The whole point is that the C can be as fast and as small as the ASM but > MUCH easier to read, debug and maintain. Certainly far faster to write.
Actually, no, that's not the point under discussion. The point is this, and only this statement taken from your post of 2008-04-26, 07:36h+0100h:
> In fact I have seen comparisons where some C compilers produce faster smaller code than assembler.
I rejected exactly that statement, as written, and you think I shouldn't. I haven't seen any argument to support that statement. Instead you (and Walter) argue against things I didn't say. Yes, compilers users produce good code faster than assembler users. But that doesn't mean compilers produce faster code than assembler. There is no code a compiler can "produce" that an assembler couldn't, so it's impossible for them to have the rigid advantage claimed by the quoted statement.
Hans-Bernhard Br=F6ker wrote:
> Chris H wrote: > > > The whole point is that the C can be as fast and as small as the ASM but=
> > MUCH easier to read, debug and maintain. Certainly far faster to write. > > Actually, no, that's not the point under discussion. The point is this, > and only this statement taken from your post of 2008-04-26, 07:36h+0100h: > > > In fact I have seen comparisons where some C compilers produce faster sm=
aller code than assembler.
> > I rejected exactly that statement, as written, and you think I > shouldn't. I haven't seen any argument to support that statement.
And you will not. I have been trying to get some reasonably sized code example to be put for comparison to something similar that I have written using my VPA for years, all I have been given has been general babble. Walter certainly knows what he is doing and what he claims is that you can write anything in C (if I got it right), I doubt he would claim one can write better code in C than in assembly. What he says (again, if I got that right) there is no code you can write in assembly which you could not reproduce exactly in C using his compiler (meaning getting the same object code). Makes sense, certainly you can extend any language to say anything you can say in any other language. Whether going through all the C hoops to achieve that is worth it is a completely different matter.
> Yes, compilers users produce good code faster than assembler users.
That can be true in some cases. Which assembler? x86? Of course. PIC or some similar mess? Sure. Any assembler? Well, if the purpose is to output "hello world" then it is again a "yes". But try to beat my time on a larger project which I will do using VPA and my libraries - no C coder I have encountered has a vague chance. And it is not because I am so much better, it is because of the tools I have (created).
> But that doesn't mean compilers produce faster code than assembler.
They could, if the assembler programmer writes poor code. Apart from the cases where they recognize some widely popular pieces of code and insert a well written piece of assembly code, they have no chance against a good programmer, of course. But OTOH how many good programmers are walking around nowadays for whom this is valid...? High level languages are good if one needs to use a system for a short while. If one will spend his working time within a system, though, they are only in the way of the user. In other words, you can learn a few phrases in a foreign language and be fine with them as a tourist in the respective country over the weekend or so, but if you intend to live in that country and work there as a journalist you better learn the language... Dimiter ------------------------------------------------------ Dimiter Popoff Transgalactic Instruments http://www.tgi-sci.com ------------------------------------------------------ http://www.flickr.com/photos/didi_tgi/sets/72157600228621276/ Original message: http://groups.google.com/group/comp.arch.embedded/msg/5155= d05b49849bb6?dmode=3Dsource
Chris H wrote:
> Hans-Bernhard Br&#4294967295;ker <HBBroeker@t-online.de> writes >
... snip ...
> >> Huh? Is something wrong with my writing or with your reading? >> Where in the above did you see me talking about maintainability >> or difficulty? The issue at hand is _speed_ and _size_. No >> more, no less. > > In which case you loose... I can read the C. I cant read the ASM > so I won't be able to see that what you have done is the same as > the C or even correct.... :-)
Most people simply admit that inability to read something largely inhibits the ability to criticize it. :-) -- [mail]: Chuck F (cbfalconer at maineline dot net) [page]: <http://cbfalconer.home.att.net> Try the download section. ** Posted from http://www.teranews.com **
Walter Banks wrote:
> CBFalconer wrote: >> Walter Banks wrote: >>
... snip ...
>>> >>> I should have used fixed point type to make the listing fragment >>> clearer. This is the source used in the example. >>> >>> void bar (void); >>> >>> void foo (void) { >>> NOP(); >>> bar(); >>> } >>> >>> void bar (void) { >>> NOP(); >>> } >>> >>> void main (void) { >>> foo(); >>> bar(); >>> }
(above diddled to reduce vertical space, shouldn't affect meaning) (If it does that is a serious effect)
>> >> Well, that executes foo (and thus bar), followed by bar. I see >> no savings there from fall-thru. See my message of Sat. 11:13 am >> EDT > > There is a savings > > Look at the listing I posted before. It follows in fixed point > type. Don't start a rant about html please.
OK. But you should be aware that opening the receiver to accept html mail allows all sorts of evil monsters to sneak in on many systems. Text is safe.
> void bar (void); > > void foo (void) > { > 0100 9D NOP NOP(); > bar(); > } > > void bar (void) > { > 0101 9D NOP NOP(); > 0102 81 RTS } > > > void main (void) > { > 0103 AD FB BSR $0100 foo(); > 0105 20 FA BRA $0101 bar(); > } > > __MAIN: > FFFE 01 03
Now this shows the fall-thru. Yet, as far as I can see, the C source has no way to control it. A foo call here exercises foobar, and a bar call is independant. I am not doubting that you can do it - I just don't see how you can control it. Are you making some sort of extra requirement for prototypes? Are you doing some sort of possible path analysis? What if we put foo, bar, and foobar in one c file, and main in another? For example: void bar(void) {NOP();) void foo(void) {NOP();} void foobar(void) {NOP(); bar();} maybe with some extrn definitions. No prototypes needed for the file, only for linkage. The generated code can be: void foobar (void) { 0100 9D NOP NOP(); bar(); } void bar (void) { 0101 9D NOP NOP(); 0102 81 RTS } void foo (void) { 0103 9D NOP NOP(); 0104 81 RTS } and the loader can drop the code for foo, because it is never called. However there are differences in source order for C compatibility and for _easy_ fall-thru detection. Note that source and object are in different order. -- [mail]: Chuck F (cbfalconer at maineline dot net) [page]: <http://cbfalconer.home.att.net> Try the download section. ** Posted from http://www.teranews.com **
In article <4815376D.EF541A20@yahoo.com>, cbfalconer@yahoo.com says...
> Walter Banks wrote: > > CBFalconer wrote: > >> Walter Banks wrote: > >> > ... snip ... > >>> > >>> I should have used fixed point type to make the listing fragment > >>> clearer. This is the source used in the example. > >>> > >>> void bar (void); > >>> > >>> void foo (void) { > >>> NOP(); > >>> bar(); > >>> } > >>> > >>> void bar (void) { > >>> NOP(); > >>> } > >>> > >>> void main (void) { > >>> foo(); > >>> bar(); > >>> } > > (above diddled to reduce vertical space, shouldn't affect meaning) > (If it does that is a serious effect) > > >> > >> Well, that executes foo (and thus bar), followed by bar. I see > >> no savings there from fall-thru. See my message of Sat. 11:13 am > >> EDT > > > > There is a savings > > > > Look at the listing I posted before. It follows in fixed point > > type. Don't start a rant about html please. > > OK. But you should be aware that opening the receiver to accept > html mail allows all sorts of evil monsters to sneak in on many > systems. Text is safe. > > > void bar (void); > > > > void foo (void) > > { > > 0100 9D NOP NOP(); > > bar(); > > } > > > > void bar (void) > > { > > 0101 9D NOP NOP(); > > 0102 81 RTS } > > > > > > void main (void) > > { > > 0103 AD FB BSR $0100 foo(); > > 0105 20 FA BRA $0101 bar(); > > } > > > > __MAIN: > > FFFE 01 03 > > Now this shows the fall-thru. Yet, as far as I can see, the C > source has no way to control it. A foo call here exercises foobar, > and a bar call is independant. I am not doubting that you can do > it - I just don't see how you can control it. Are you making some > sort of extra requirement for prototypes? Are you doing some sort > of possible path analysis?
I would guess that path analysis is possible---unless you have functions called with function pointers. My recollection of 8051 C compilers from the 90's is that they did a lot of analyis to allow variable overlays. Call path analysis seems of comparable complexity. A decade or so back, I used the Keil 8051 C compiler on a project for one of the smaller variants. I had done earlier projects with assembler, but I wanted to take advantage of the compiler overlay capability to maximize variable space and to take advantage of some of the math library routines. IIRC, the CPU had only 2K flash (89C2051). At that time, IIRC, it was pretty much a "burn and learn" process as I didn't have a JTAG debugger comparable to the systems I use (and enjoy) for the MSP430 today.
> What if we put foo, bar, and foobar in > one c file, and main in another? For example: > > void bar(void) {NOP();) > void foo(void) {NOP();} > void foobar(void) {NOP(); bar();} > > maybe with some extrn definitions. No prototypes needed for the > file, only for linkage. The generated code can be: > > void foobar (void) { > 0100 9D NOP NOP(); > bar(); > } > void bar (void) { > 0101 9D NOP NOP(); > 0102 81 RTS } > void foo (void) { > 0103 9D NOP NOP(); > 0104 81 RTS } > > and the loader can drop the code for foo, because it is never > called. However there are differences in source order for C > compatibility and for _easy_ fall-thru detection. Note that source > and object are in different order. >
Mark Borgerson
In message <MPG.227ee89292430b1798983f@newsgroups.comcast.net>, Mark 
Borgerson <mborgerson@comcast.net> writes
>In article <4815376D.EF541A20@yahoo.com>, cbfalconer@yahoo.com says... > >A decade or so back, I used the Keil 8051 C compiler >on a project for one of the smaller variants. I had done >earlier projects with assembler, but I wanted to take advantage >of the compiler overlay capability to maximize variable space >and to take advantage of some of the math library routines. >IIRC, the CPU had only 2K flash (89C2051). > >At that time, IIRC, it was pretty much a "burn and learn" process >as I didn't have a JTAG debugger comparable to the systems I use >(and enjoy) for the MSP430 today.
Now I do worry... "burn and .Learn"? The Keil system has one of the best simulators for 8051 there is. For the 8051 family there are only a couple of oddballs with the Jtag debugger on them. Professionals would use an Emulator. They were not expensive and gave full vision and control of the MCU. -- \/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ \/\/\/\/\ Chris Hills Staffs England /\/\/\/\/ \/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
CBFalconer wrote:
> In addition, the assembly programmer always has some > extra tricks available, that result in shorter and faster > programs. For example, consider a program than needs functions > foo() and bar(). It turns out that a foo call is always followed > by a bar call, but that bar needs to be separately callable.
[...]
> The C > programmer doesn't have this capability.
But surely the C compiler has the freedom to emit the same code as the assembly programmer did? I don't know if any compiler would do it, but if this was a frequent enough case to optimize, it does not seem too hard to do. -- Pertti

CBFalconer wrote:

> Now this shows the fall-thru. Yet, as far as I can see, the C > source has no way to control it. A foo call here exercises foobar, > and a bar call is independant. I am not doubting that you can do > it - I just don't see how you can control it.
There is no need to control it. C is a way to describe the problem and compiler is responsible for code generation. As a program evolves the compiler/linker on each build have an opportunity to start over and create new code based on the requirements embodied in the source. w..
On Fri, 25 Apr 2008 00:08:56 +0200, David Brown wrote:
> Neil wrote: >> Walter Banks wrote: >>> >>> Neil wrote: >>> >>>> Walter Banks wrote: >>>>> Vladimir Vassilevsky wrote: >>>>> >>>>>> You have to resort to assembly in the two special cases: >>>>>> >>>>>> 1. The system level work like switching the contexts of the tasks, C >>>>>> startup code, etc. >>>>>> >>>>>> 2. The parts of code where the performance is very critical. >>>>> In your second point I would qualify it to parts of code >>>>> requiring exact timing on anything that we have released >>>>> recently that seems to be the only limitation. >>>>> >>>>> >>>> Do not forget the startup code >>> >>> Our startup code is in C. >>> >>> w.. >>> >>> >>> >> I am not sure how that works. I am talking about the code that jumps to >> main after setting up the C environment. > > So is he. > > There are small bits of the startup that must be in assembler (I use > embedded assembly within the C code - Walter uses C extensions in his > compilers that translate directly to matching assembly). But most of it > can be written perfectly well in C. For example, code to copy the > initialised data from flash to ram, and to zero the bss, can be written > in C.
I've written the startup code in C on the SDCC compiler and the small C comiler. Basically the compiler did nothing and I had to do everything. I basically wouldn't use this for professional work but it was simple enough and I just managed everything. -- Linux Home Automation Neil Cherry ncherry@linuxha.com http://www.linuxha.com/ Main site http://linuxha.blogspot.com/ My HA Blog Author of: Linux Smart Homes For Dummies
In article <4813D4E6.44B6D3BE@yahoo.com>,
CBFalconer  <cbfalconer@maineline.net> wrote:
>Walter Banks wrote: >> CBFalconer wrote: >> >... snip ... >> >>> but he can combine these, saving a 'ret' execution, some stack >>> space, and a call. The result is: >>> >>> foobar: /* foo code */ >>> ; /* fall through */ >>> bar: /* bar code */ >>> ret >>> >>> eliminating two calls and two rets from the earlier code. The C >>> programmer doesn't have this capability. Believe me, it adds up >>> over a medium complicated system. >> >> You mean something like this? >> >> void bar (void); >> void foo (void) >> { >> 0100 9D NOP NOP(); >> bar(); >> } >> void bar (void) >> { >> 0101 9D NOP NOP(); >> 0102 81 RTS } >> void main (void) >> { >> 0103 AD FB BSR $0100 foo(); >> 0105 20 FA BRA $0101 bar(); >> >> It does add up.. > >Well, that looks impressive, but you must be loosing something. >You must be doing something illegal and non-understandable (to a C >programmer) with one or more of indentation, braces placement, >illegal statements (a call to foo should never enter bar). I see >no reason for bar to exit while foo falls through.
Apparently you don't know the first thing about compiler optimisation. This trick is called tail optimisation and is a standard technique, with all respect to Walter Banks, who implemented this technique neatly. See also http://home.hccnet.nl/a.w.m.van.der.horst/forthlecture5.html I'm a good assembler programmer myself, and I don't find Banks claim extravagant, though a little provocative.
> [mail]: Chuck F (cbfalconer at maineline dot net)
Groetjes Albert -- -- Albert van der Horst, UTRECHT,THE NETHERLANDS Economic growth -- like all pyramid schemes -- ultimately falters. albert@spe&ar&c.xs4all.nl &=n http://home.hccnet.nl/a.w.m.van.der.horst