LADD and LSUB in XC ??

Technical questions regarding the XTC tools and programming with XMOS.
stefanharjes
Member
Posts: 13
Joined: Wed Jun 01, 2011 7:33 pm

Post by stefanharjes »

Hi,

in order to compare the efficiency c/xc I tried to do a long add in c and call this function from xc main:

Code: Select all

void call_c() {
  char iobuf[256]
  unsigned long first = 2147483655U;
  unsigned plus =  2147483649U;
  unsigned long after;
  after = first + (unsigned long) plus;
  sprintf(iobuf,"%lu + %u = %lu",first, plus, after);
  printstrln(iobuf);
}
the result on my XC-2 hardware:
2147483655 + 2147483649 = 8
why is this no long add? or is it the sprintf? any hints?

Stefan


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

Post by richard »

On the XCore long is 32bits. You need to use long long if you want a 64bit data type.
stefanharjes
Member
Posts: 13
Joined: Wed Jun 01, 2011 7:33 pm

Post by stefanharjes »

Hi all,

I still have problems with the ladd and was trying to write it in c and look at the asm, but I am
not even able to do a long addition in c. if I use the following code:

Code: Select all

void call_c() {
	printstrln("called c");
	char iobuf[256];
	long long int result;
	int i;
	result = 8589934592;  //2**33
	for(i=0;i<11;i++) {
		sprintf(iobuf," %lli + %i = ",result,i);
		printstr(iobuf);
		result = result+i;
		sprintf(iobuf,"%lli",result);
		printstrln(iobuf);
	}
}
I get strange results:
called c
0 + 2 = 0
0 + 2 = 1
1 + 2 = 3
3 + 2 = 6
6 + 2 = 10
10 + 2 = 15
15 + 2 = 21
21 + 2 = 28
28 + 2 = 36
36 + 2 = 45
45 + 2 = 55
so what am I doing wrong?

Best
User avatar
segher
XCore Expert
Posts: 844
Joined: Sun Jul 11, 2010 1:31 am

Post by segher »

Do you have the prototype for sprintf() in scope? Without it it won't
work, so #include <stdio.h> and see if that helps (if you already had
that -- it helps to post our actual code, not some snippet that is just
similar to our code :-) ).
stefanharjes
Member
Posts: 13
Joined: Wed Jun 01, 2011 7:33 pm

Post by stefanharjes »

sorry I forgot to paste the first two lines, but I indeed included the stdio.h and print.h

Code: Select all

#include <stdio.h>
#include <print.h>


void call_c() {
	printstrln("called c");
	char iobuf[256];
	long long int result;
	int i;
	result = 8589934592;
	for(i=0;i<11;i++) {
		sprintf(iobuf," %d + %d = ",result,i);
		printstr(iobuf);
		result = result+i;
		sprintf(iobuf,"%d",result);
		printstrln(iobuf);
	}

}
I call from xc:

Code: Select all

#include "ladd.h"

int main(void) {

	call_c();
	return 0;
}
with ladd.h

Code: Select all

#ifndef LADD_H_
#define LADD_H_

void call_c();

#endif /* LADD_H_ */
but the output is the same wired stuff as posted above.

Best
User avatar
segher
XCore Expert
Posts: 844
Joined: Sun Jul 11, 2010 1:31 am

Post by segher »

You're now doing

Code: Select all

      sprintf(iobuf,"%d",result);
which should be either

Code: Select all

      sprintf(iobuf,"%lld",result);
or

Code: Select all

      sprintf(iobuf,"%d",(int)result);
since "result" is a long long int, not an int.

Similar for the other sprintf(), of course.
stefanharjes
Member
Posts: 13
Joined: Wed Jun 01, 2011 7:33 pm

Post by stefanharjes »

Hi Segher,

Did you compile the code and did it work? You complained about me not posting the complete code, then I would expect that you at least tried to run it in the simulator.

In my case there is no difference in the program's output using either %d, %lli or %lld.

Stefan
MaxFlashrom
Experienced Member
Posts: 82
Joined: Fri Nov 05, 2010 2:59 pm

Post by MaxFlashrom »

stefanharjes wrote:Hi Segher,

Did you compile the code and did it work? You complained about me not posting the complete code, then I would expect that you at least tried to run it in the simulator.

In my case there is no difference in the program's output using either %d, %lli or %lld.

Stefan
Hi Stefan, I tried your code and looked at the assembler for it and variations of it. Although error messages from the compiler indicate that printf (and sprintf) understand %lld (for a signed long long) It fails to format them properly. i tried appending LL to integer constants because I was worried it might be trying to sign extend integers into long long ints but it didn't help. The compiler does understand long long ints and does appear to generate correct code when performing arithmetic but the printf fails to work properly. In your code you had result = result + i which probably wasn't the intention given what you put in the sprintf(); ie. ("a + b = %lu") This made the result look even stranger.

Incidentally, the XS1 architecture manual claims that MUL performs an unsigned word multiply with an unsigned word result. This is not what I see reading compiler output and tracing the code: I see it performing a signed multiply operation between 2 words with a signed word result.
EDIT: I have now realised that if one ignores the overflow that an unsigned multiply also works with 2's complement numbers, so it's not wrong, but as I observe below, it's perhaps not the whole story.

There is no difference between an unsigned add or subtract and a "signed" add or subtract anyway when using 2's complement arithmetic apart from the detection of overflow(which the XS1 doesn't do anyway) so the naming of these instructions as unsigned operations is not particularly instructive.

If I was feeling really keen with nothing better to do I could disassemble the implementation of printf and tell you exactly why it's broken but I'm not feeling that enthusiastic. I could be mistaken but nothing obvious seems to work.

Regards Max.
User avatar
segher
XCore Expert
Posts: 844
Joined: Sun Jul 11, 2010 1:31 am

Post by segher »

It seems newlib is built without the newlib_io_long_long flag set; this will
make printf() and friends use long int whenever it sees %ll, not long long
int as expected. Ouch.
User avatar
segher
XCore Expert
Posts: 844
Joined: Sun Jul 11, 2010 1:31 am

Post by segher »

stefanharjes wrote:Did you compile the code and did it work?
I didn't, since it was not valid C code, it would have been pointless.
You complained about me not posting the complete code, then I would expect that you at least tried to run it in the simulator.
I asked for complete code because it isn't clear what is happening without it.

Anyway, thanks to Max' detective work (and me reading the newlib code), it
seems we found the core problem: newlib is compiled without long long
text conversion support. You can rebuild newlib if you're feeling adventurous,
or you can open a ticket :-)