From: SourceForge.net <no...@so...> - 2006-12-29 13:53:42
|
Feature Requests item #1613840, was opened at 2006-12-12 11:28 Message generated for change (Comment added) made by rguetlein You can respond by visiting: https://sourceforge.net/tracker/?func=detail&atid=350599&aid=1613840&group_id=599 Please note that this message will contain a full copy of the comment thread, including the initial issue submission, for this request, not just the latest update. Category: None Group: None Status: Open Priority: 5 Private: No Submitted By: Nobody/Anonymous (nobody) Assigned to: Nobody/Anonymous (nobody) Summary: proposal: change in calling convention (C51) Initial Comment: Wouldn't it be better to use general registers r2..r7 for parameter passing? The use of dptr/b/a for passing the first parameter seems a bad choice to me, because these registers are used mostly for other purposes in the called functions and therefore will be copied to general registers or to the stack in the entry code of the function. For example, the C function int AddInt(int a, int b) { return a+b; } leads to the following assembler code (with --stack-auto) _AddInt: push _bp mov _bp,sp mov r2,dpl mov r3,dph mov a,_bp add a,#0xfffffffc mov r0,a mov a,@r0 add a,r2 mov dpl,a inc r0 mov a,@r0 addc a,r3 mov dph,a pop _bp ret Assumed that all 4 parameter bytes were passed in registers the code would look sth. like: _AddInt: mov a,r4 add a,r2 mov r2,a mov a,r5 addc a,r3 mov r3,a ret (Also assumed that the return value is in R2/R3) This concept would also lead to tighter code in the calling function. Best Regards, Ralf ---------------------------------------------------------------------- Comment By: Ralf Guetlein (rguetlein) Date: 2006-12-29 14:53 Message: Logged In: YES user_id=145736 Originator: NO Bernhard, I appreciate your and your fellows' work. Please, do not think that I unfairly compare SDCC to a commercial tool chain that costs thousands of euros. After all, the commercial compilers have their quirks, too (no ANSI compatibility, no bit fields in structs with more than 8 bits, "wrong" endian). Still, I think my proposal is worth thinking about, for future improvements. I am not an expert in compiler design, but if I will find the time I will take a deeper look into this issue. I wish every member of this project all the best for the New Year. Ralf ---------------------------------------------------------------------- Comment By: Bernhard Held (bernhardheld) Date: 2006-12-26 23:07 Message: Logged In: YES user_id=203539 Originator: NO Unfortunately a "simple" renaming of registers doesn't help and is even counter productive. Prior to this a much bigger improvement of sdcc is needed. Let's have a look at: char xdata *foo (char xdata *p) { return p; } It compiles to: _foo: ret This looks nice, but the comment ;p Allocated to registers r2 r3 tells us the truth. To see what really happens compile it with --no-peep. Now we get: _foo: ; genReceive mov r2,dpl mov r3,dph ; genRet mov dpl,r2 mov dph,r3 ret Yes, this is really ugly. It was just the peephole optimizer, which made the code looking somewhat nicer. What happens? The phases in sdcc are totally separate - the last phases are: - register allocation (RA) - assembler code generation - peephole optimization The register allocator allocates registers for all variables (and all temporary variables, which you don't always see in the source code). It doesn't know if the code generator will ever use this register, or if the peephole optimizer will remove the usage. If a register is allocated but unused in the final code, then it's simply lost. There's no 2nd pass, which could feed back this information in the register allocator. This is the first and even bigger thing, which needs improvement. Then we might think about changing the calling convention. There's a long, long way to go until sdcc will emit code given in your initial post. Please remember that sdcc is a retargetable C-compiler. I'm afraid that 1) commercial compilers use optimization technics, which can't be implemented in sdcc and 2) sdcc will never ever reach the code quality of commercial compilers. ---------------------------------------------------------------------- Comment By: Nobody/Anonymous (nobody) Date: 2006-12-12 15:51 Message: Logged In: NO Bernhard, I could not find any documenation on the --parms-in-bank1, but if it does what I think it does, it will void reentrancy, which I need for my application. Still, it does not help with the first function parameter. In many cases I inspected there's a sequence like mov r2, dpl mov r3, dph in the entry of the function, even if R2/R3 is never used. Both commercial compilers (KEIL and TASKING) use general registers for parameter passing with proves to deliver good results. ---------------------------------------------------------------------- Comment By: Bernhard Held (bernhardheld) Date: 2006-12-12 14:08 Message: Logged In: YES user_id=203539 Originator: NO > This concept would also lead to tighter code in the calling function. No, this is not always true. There's only an advantage in simple functions. In calling functions with high register pressure many push/pop operations will appear in order to free the required registers. This will eat up the whole advantage and will result in even longer code. Unfortunately you meet 'high register pressure' in all non-trivial functions with only 8 bytes register space. Try --parms-in-bank1 and/or --callee-saves for better results. Remember to recompile your library with the same options. ---------------------------------------------------------------------- You can respond by visiting: https://sourceforge.net/tracker/?func=detail&atid=350599&aid=1613840&group_id=599 |