Debug vs Release mode - Problem with nstackwords

Technical questions regarding the XTC tools and programming with XMOS.
User avatar
lilltroll
XCore Expert
Posts: 956
Joined: Fri Dec 11, 2009 3:53 am
Location: Sweden, Eskilstuna

Debug vs Release mode - Problem with nstackwords

Post by lilltroll »

Hi

I made a program that works in release mode - but when I compile it in debug mode I get the following error report:
xmap: Error: Value of undefined resource symbol "filtersection.nstackwords" cannot be determined.
xmap: Error: ...needed for function I2S_slave
xmap: Error: Symbol "filtersection.nstackwords" for resolution of resource expression for ".LLNK21" is undefined.
xmap: Error: Symbol for resolution of resource expression for ".LLNK24" is undefined.
xmap: Error: Symbol for resolution of resource expression for ".LLNK25" is undefined.
xmap: Error: Symbol for resolution of resource expression for ".LLNK26" is undefined.
xmap: Error: Symbol for resolution of resource expression for ".LLNK27" is undefined.
xmap: Error: Symbol for resolution of resource expression for ".LLNK30" is undefined.
xmap: Error: Symbol for resolution of resource expression for ".LLNK31" is undefined.
xmap: Error: Symbol for resolution of resource expression for ".LLNK32" is undefined.
xmap: Error: Symbol for resolution of resource expression for ".LLNK33" is undefined.
xmap: Error: Symbol for resolution of resource expression for ".LLNK36" is undefined.
xmap: Error: Symbol for resolution of resource expression for ".LLNK37" is undefined.
xmap: Error: Symbol for resolution of resource expression for ".LLNK38" is undefined.
xmap: Error: Symbol for resolution of resource expression for ".LLNK39" is undefined.
xmap: Error: Symbol for resolution of resource expression for ".LLNK42" is undefined.
xmap: Error: Symbol for resolution of resource expression for ".LLNK43" is undefined.
xmap: Error: Symbol for resolution of resource expression for ".LLNK44" is undefined.
xmap: Error: Symbol for resolution of resource expression for ".LLNK45" is undefined.
xmap: Error: Symbol for resolution of resource expression for ".LLNK48" is undefined.
xmap: Error: Symbol for resolution of resource expression for ".LLNK49" is undefined.
xmap: Error: Symbol for resolution of resource expression for ".LLNK50" is undefined.
xmap: Error: Symbol for resolution of resource expression for ".LLNK53" is undefined.
xmap: Error: Symbol for resolution of resource expression for ".LLNK54" is undefined.
xmap: Error: Symbol for resolution of resource expression for ".LLNK97" is undefined.
xmap: Error: Symbol for resolution of resource expression for ".LLNK98" is undefined.
xmap: Error: Symbol for resolution of resource expression for ".LLNK99" is undefined.
xmap: Error: Symbol for resolution of resource expression for ".LLNK100" is undefined.
What do I need to change to get rid of the LLNK problem and what does it mean ??


Probably not the most confused programmer anymore on the XCORE forum.
User avatar
lilltroll
XCore Expert
Posts: 956
Joined: Fri Dec 11, 2009 3:53 am
Location: Sweden, Eskilstuna

Post by lilltroll »

OK if I skip the inline before the header filtersection it works.

So why cannot I use inline in debug mode ?
Probably not the most confused programmer anymore on the XCORE forum.
User avatar
skoe
Experienced Member
Posts: 94
Joined: Tue Apr 27, 2010 10:55 pm

Post by skoe »

I don't know the exact function header of the "filtersection", but maybe this could help:

In Debug mode the optimization may be turned off and even with "inline" the function may not be inlined but put separately. When it is compiled as a separate fuction the nstackwords stuff may be needed.

It may also be a difference if it is "static inline" or "inline" only. In the latter case one could get duplicated symbols when the function is used in several source files.

Maybe it helps.
richard
Respected Member
Posts: 318
Joined: Tue Dec 15, 2009 12:46 am

Post by richard »

What does the declaration of filtersection look like? The XC compiler follows the C99 inlining rules. If you have inline with out extern or static then the function is an inline definition. There must also be an external definition of the function which can be used if the compiler doesn't inline the inline definition into the call site.
User avatar
lilltroll
XCore Expert
Posts: 956
Joined: Fri Dec 11, 2009 3:53 am
Location: Sweden, Eskilstuna

Post by lilltroll »

It's written like this:

Code: Select all

 inline int filtersection(const unsigned int I,int IN,iir_fixed32 &f,int s[]){
 	int h,l;
 	{h, l} = macs(f.B[I][0], IN , 0 , 0);
 	{h, l} = macs(f.B[I][1], s[0] , h, l);
 	{h, l} = macs(f.B[I][2], s[1] , h, l);
 	{h, l} = macs(f.A[I][0], s[2] , h, l);
 	{h, l} = macs(f.A[I][1], s[3]>>1 , h, l);
 	s[1]=s[0];
 	s[0]=IN;
 	s[3]=s[2];
 	s[2]=(h<<2) + (l>>30);
 	return (s[2]); 
 	}
Since it tight with the timing I wish to use the inline
I found out that I get very few line between each macs in the dis-asm.

Code: Select all

                     0x10244 	maccs (l4r) r5, r2, r8, r7
                     0x10248 	ldw (2rus) r9, r6[i 0x4]
                     0x1024a 	ldw (2rus) r8, r3[i 0x0]
                     0x1024c 	maccs (l4r) r5, r2, r9, r8
                     0x10250 	ldw (2rus) r9, r6[i 0x8]
                     0x10252 	ldw (2rus) r8, r3[i 0x4]
                     0x10254 	maccs (l4r) r5, r2, r9, r8
                     0x10258 	ldc (ru6) r8, i 0x30
                     0x1025a 	add (3r) r6, r6, r8
                     0x1025c 	ldw (2rus) r9, r6[i 0x0]
                     0x1025e 	ldw (2rus) r8, r3[i 0x8]
                     0x10260 	maccs (l4r) r5, r2, r9, r8
                     0x10264 	ldw (2rus) r8, r6[i 0x4]
                     0x10266 	ldw (2rus) r6, r3[i 0xc]
                     0x10268 	ashr (l2rus) r6, r6, i 0x1
                     0x1026c 	maccs (l4r) r5, r2, r8, r6

A part from the calling code looks like this;

Code: Select all

	 			p_bclk 	<: 0xCCCCCCCC;
#if(BANKS>=1)
	 			TEMP_DAC=filtersection(0,TEMP_DAC,f,Init[6]);
#endif		 			
#if(BANKS>=2)
	 			TEMP_DAC=filtersection(1,TEMP_DAC,f,Init[7]);
#endif		 			

	 				 			
	 			p_bclk 	<: 0xCCCCCCCC;
where I have less than 3us of processing time between each p_bclk. (32 bits of I2S clock/data @ 44.1 kHz samplingrate). But if I can use the 250-300 available instructions in a nice way, I want it !

The little C I remember is the C89 - and what I remember does not include extern and things like this. But I can read about in in my old The ANSI C programming language (in swedish) that I have.

Should I add some more funny words after before inline ?? :oops:
Probably not the most confused programmer anymore on the XCORE forum.
User avatar
skoe
Experienced Member
Posts: 94
Joined: Tue Apr 27, 2010 10:55 pm

Post by skoe »

@lilltroll:
What you need is "static inline", I think.

@richard:
Thanks for the C99 hint. But even after having read chapter 6.7.4 of C99 I'm still not sure about the intended behaviour. This may be caused by my low English language capabilities. Let's see what the compilers do:

Code: Select all

$ cat a.xc

inline int a(int i)
{
    return i * 2;
}

int main(void)
{
    return a(5);
}

$ cat b.xc

inline int a(int i)
{
    return i * 2;
}

int f(int x)
{
    return a(x);
}


$ xcc -O0 a.xc b.xc

a.xc: Error: Undefined reference to 'a'
(What's this? Why do I need an external symbol now? Is this C99?)

(same in *.c)
$ gcc -std=c99 -O0 a.c b.c

/tmp/ccKhZg4h.o: In function `a':
b.c:(.text+0x0): multiple definition of `a'
(Symbol seems to be exported, is this what C99 wants?)
enable optimization:

Code: Select all

$ xcc -O2 a.xc b.xc

(works, actually inlined)

$ gcc -std=c99 -O2 a.c b.c

/tmp/ccZm1fAW.o: In function `a':
b.c:(.text+0x0): multiple definition of `a'
(export still exported?)

and now with "static inline":

gcc/xcc -O0/-O2 all combinations work, the static forbids the symbol to be exported, no matter if it is actually inlined or linked internally.
And objdump shows if it was really inlined.

I always used "static inline" before. But I must confess that I didn't think about what "inline" w/o another modifier means or even "export inline". Maybe that's the stuff that's called "implementation defined"?

Thomas
richard
Respected Member
Posts: 318
Joined: Tue Dec 15, 2009 12:46 am

Post by richard »

There are a couple of way to implement this. One solution is to add static to any inline definitions. In the case where the compiler doesn't inline the function you end up with a copy of the function in every file where it is called. For example:

foo.h:

Code: Select all

static inline void f() {}
bar1.xc

Code: Select all

#include "foo.h"
void g() {
  f();
}
bar2.xc

Code: Select all

#include "foo.h"
void h() {
  f();
}
At -O2 f() will be inlined in both g() and h() and the unreferenced definitions of f() will be eliminated. At -O0 f() will not be inlined and you will end up with two copies of f() with local linkage, one in bar1.o and one in bar2.o

The alternative is to provide an external definition in another file. For example:

foo.h:

Code: Select all

inline void f() {}
foo.xc:

Code: Select all

#include "foo.h"
extern inline void f(); // This will cause the compiler to emit an externally available definition for f()
bar1.xc

Code: Select all

#include "foo.h"
void g() {
  f();
}
bar2.xc

Code: Select all

#include "foo.h"
void h() {
  f();
}
At -O2 f() will be inlined in both g() and h() and the unreferenced definition of f() will be eliminated. At -O0 f() will not be inlined and you you end up with one copy of f() with global linkage in foo.o

The second method has the advantage that you don't get multiple copies of f() when compiled at -O0.
User avatar
skoe
Experienced Member
Posts: 94
Joined: Tue Apr 27, 2010 10:55 pm

Post by skoe »

Richard, your information is very valuable, but I still ask more to get rid of the remaining doubts. From C99:

"A function declared with an inline function specifier is an inline function. [...] Making a function an inline function suggests that calls to the function be as fast as possible."

After this paragraph I understand why gcc complains about multiple symbols when it does not inline the function, but I do not understand why xcc (llvm?) doesn't see it at all. (see example in my last post)
At -O0 f() will not be inlined and you will end up with two copies of f() with local linkage, one in bar1.o and one in bar2.o
That's correct. But if a programmer accepts it to appear at any place where it is called he can also accept it to appear in all files where it is called. When he uses -O0 the code is bloated anyway :) Mmmmh, okay, you are right.
The second method has the advantage that you don't get multiple copies of f() when compiled at -O0.
That's a good hint, I'll use this in my library.
and the unreferenced definition of f() will be eliminated
Ah, that's a nice feature of llvms link time optimization. It's not done when using "traditional" compilers like gcc. Just tried it. (This may be done not to eliminate symbols that are actually used as entry points without the knowledge of the linker.) Only when the symbol is defined in a code segment of a library which does not contain any symbol needed to resolve an external. However, it doesn't matter since we're talking about xcc here.

Thomas
richard
Respected Member
Posts: 318
Joined: Tue Dec 15, 2009 12:46 am

Post by richard »

Inline functions were supported in gcc before C99 with slightly different semantics (GNU 89 semantics). This behaviour is still default in standard GCC. To get C99 inline semantics in recent gcc versions you can use -std=gnu99 (C99 with GNU extensions) or -std=c99. My understanding is that at some point in the future gcc will default to -std=gnu99.

The frontend of the C compiler in the XMOS toolchain is based on gcc also defaults to GNU 89 semantics. Therefore in 9.9.2 the default handling of inline differs when compiling C code to when compiling XC code. You can use the -std=gnu99 to make the C compiler behave the same as the XC compiler. In the next release we will change the C compiler so that -std=gnu99 is the default.
User avatar
skoe
Experienced Member
Posts: 94
Joined: Tue Apr 27, 2010 10:55 pm

Post by skoe »

Thanks for the clarification, no questions left.

It seems that my GCC here (4.1) is too old, even with -std=c99 (see my 2nd post) it doesn't do it correctly.