A riddle for Pure-C experts

GFA, ASM, STOS, ...

Moderators: simonsunnyboy, Mug UK, Zorro 2, Moderator Team

Post Reply
ThorstenOtto
Atari God
Atari God
Posts: 1521
Joined: Sun Aug 03, 2014 5:54 pm

A riddle for Pure-C experts

Post by ThorstenOtto »

While working on the sources for MagiCNet, i stumbled upon a function that was apparently compiled by Pure-C, but which produces different code when i try to use the C Version. The original code looks like:

Code: Select all

short cdecl if_input(struct netif *nif, BUF *buf, long delay, short type)
{
	short r = 0;
	ushort sr;

#ifdef __PUREC__
	/* only for binary equivalence; might as well use splhigh() */
	sr = getsr();
	setipl7();
#else
	sr = splhigh();
#endif

	if (buf)
	{
		buf->info = type;
		r = if_enqueue(&nif->rcv, buf, IF_PRIORITIES - 1);
	}

	if (tmout == 0)
		tmout = addroottimeout(delay, if_doinput, 1);

	spl(sr);

	return r;
}
and is (apart from the inline macro to fiddle with the SR register) identical to the version from mintnet

However, the code produced by Pure-C looks like:

Code: Select all

if_input:
T000000:   MOVEM.L   D2-D4/A2,-(A7)
T000004:   MOVEA.L   $0018(A7),A2
T000008:   CLR.W     D3
T00000a:   MOVE.W    SR,D0
T00000c:   MOVE.W    D0,D4
T00000e:   ORI.W     #$0700,SR
T000012:   MOVE.L    A2,D0
T000014:   BEQ.B     T00003A
T000016:   MOVE.W    $0020(A7),D1
T00001a:   EXT.L     D1
T00001c:   MOVE.L    D1,$001A(A2)
T000020:   MOVEQ.L   #$01,D3
T000022:   MOVE.W    D3,-(A7)
T000024:   MOVE.L    D0,-(A7)
T000026:   MOVEA.L   $001A(A7),A0
T00002a:   PEA.L     $0054(A0)
T00002e:   JSR       if_enqueue
T000034:   LEA.L     $000A(A7),A7
T000038:   MOVE.W    D0,D3
T00003a:   MOVE.L    tmout,D0
T000040:   BNE.B     T000060
T000042:   MOVEQ.L   #$01,D1
T000044:   MOVE.W    D1,-(A7)
T000046:   PEA.L     if_doinput
T00004c:   MOVE.L    $0022(A7),-(A7)
T000050:   JSR       addroottimeout
T000056:   LEA.L     $000A(A7),A7
T00005a:   MOVE.L    D0,tmout
T000060:   MOVE.W    D4,D0
T000062:   MOVE.W    D0,SR
T000064:   MOVE.W    D3,D0
T000066:   MOVEM.L   (A7)+,D2-D4/A2
T00006a:   RTS
whereas the code found in the executable looks like this:

Code: Select all

if_input:
T000000:   MOVEM.L   D2-D3/A2,-(A7)
T000004:   MOVEQ.L   #$00,D1
T000006:   MOVE.W    SR,D3
T000008:   ORI.W     #$0700,SR
T00000c:   MOVE.L    $0014(A7),D1
T000010:   BEQ.B     T000036
T000012:   MOVE.W    $001C(A7),D2
T000016:   EXT.L     D2
T000018:   MOVEA.L   D1,A2
T00001a:   MOVE.L    D2,$001A(A2)
T00001e:   MOVE.W    #$0001,-(A7)
T000022:   MOVE.L    D1,-(A7)
T000024:   MOVEA.L   $0016(A7),A0
T000028:   PEA.L     $0054(A0)
T00002c:   BSR       if_enqueue
T000030:   LEA.L     $000A(A7),A7
T000034:   MOVE.W    D0,D1
if_input1:
T000036:   MOVE.L    tmout,D0
T00003c:   BNE.B     T000058
T00003e:   MOVE.W    #$0001,-(A7)
T000042:   PEA.L     if_doinput(PC)
T000046:   MOVE.L    $001E(A7),-(A7)
T00004a:   BSR       addroottimeout
T00004e:   LEA.L     $000A(A7),A7
T000052:   MOVE.L    D0,tmout
if_input2:
T000058:   MOVE.W    D3,SR
T00005a:   MOVE.W    D1,D0
T00005c:   MOVEM.L   (A7)+,D2-D3/A2
T000060:   RTS
If you take a closer look, you will see that they are functional equivalent. However, i was not able to find a construct that would produce that code, no matter how hard i tried. It doesn't look like heavily optimized by hand either (which does not make much sense anyway, since the actual work is done elsewhere).

So the question is: can someone come up with some C-Code that would produce the code as found in the executable? (the needed headers files can be found in https://github.com/th-otto/magxnet, but testing purposes you could also use some dummy prototypes for the called functions).
seedy1812
Atari freak
Atari freak
Posts: 68
Joined: Tue May 18, 2010 2:04 pm

Re: A riddle for Pure-C experts

Post by seedy1812 »

The assembler produced from a compiler will vary from compiler to compiler and what options you have set ( optimize off , for size and for speed fro exmaple. Each compiler author will have different optimization strategies which will give different assembler output which does the same job.
User avatar
TheNameOfTheGame
Atari God
Atari God
Posts: 1738
Joined: Mon Jul 23, 2012 8:57 pm
Location: Almost Heaven, West Virginia

Re: A riddle for Pure-C experts

Post by TheNameOfTheGame »

I think that's the point Thorsten is making...can someone figure out the optimization/compiler flags/code layout/etc. that can produce the byte exact assembler code when compared to the old MagicNet binaries? If it was originally compiled from Pure-C then there should be a solution. Maybe from a different Pure-C version? Were there any patches for Pure-C that Vassilis might have applied to his copy of Pure-C? Could that section be object code from a different compiler? etc.,etc.

It's not a huge section of code. It is strange that even the registers that the two examples save on the stack are different.
neanderthal
Captain Atari
Captain Atari
Posts: 244
Joined: Sun Jul 10, 2016 10:58 pm

Re: A riddle for Pure-C experts

Post by neanderthal »

Hehe,yes,the difference in compilers,a flag here a flag there.Not to mention differences in compiler versions.The future of tweak these old programs and stuff might be hard to repro the binaries as for the first time.Had a hard time to do some identical old mint kernels,if one even can get them to compile properly at times.Due to folks seldom write down which version of Gcc or whatever was used.
ThorstenOtto
Atari God
Atari God
Posts: 1521
Joined: Sun Aug 03, 2014 5:54 pm

Re: A riddle for Pure-C experts

Post by ThorstenOtto »

@neanderthal, @seedys: that's not the point. The compiler in use was definitely Pure-C (or how do you think could i produce a 100% identical binary from c-code). Compiler-switches can of course make a difference, but not in this case. I've tried that already of course, and there are basically only 2 settings that could make a difference for such a small function, -Z and -G (-R to turn register variables off really does what it says, and the code would be much different).

What i mean is the way the code was written. Eg. "x = y; if (x != 0)..." produces different code than "if ((x = y) != 0)". Using while instead of for loops sometimes is also different. But all that is not the case here.
SteveBagley
Captain Atari
Captain Atari
Posts: 203
Joined: Mon Jan 21, 2013 9:31 am

Re: A riddle for Pure-C experts

Post by SteveBagley »

One thing that stands out looking at the two assembler routines side by side, is that the new version also uses JSR instead of BSR for subroutine calls. I’ve not had chance to check this out on an Atari yet but I’m wondering if the new version has been compiled in a separate file forcing the compiler to use JSR to make it possible to link (looking at the repo also suggests this is possible — there’s a separate ifinput.c file — but you may have got the same results with it in the file hence replacing it with ifinput.s). If so, tmout has presumably also gone from being a variable in the same file to one accessed as an extern.

I wonder if these two changes are enough to cause Pure C to use a different part of the code generator?

Steve
joska
Hardware Guru
Hardware Guru
Posts: 5030
Joined: Tue Oct 30, 2007 2:55 pm
Location: Florø, Norway
Contact:

Re: A riddle for Pure-C experts

Post by joska »

Maybe compiled with Turbo C or Pure C 1.0?
Jo Even

VanillaMiNT - Falcon060 - Milan060 - Falcon040 - MIST - Mega STE - Mega ST - STM - STE - Amiga 600 - Sharp MZ700 - MSX - Amstrad CPC - C64
ThorstenOtto
Atari God
Atari God
Posts: 1521
Joined: Sun Aug 03, 2014 5:54 pm

Re: A riddle for Pure-C experts

Post by ThorstenOtto »

SteveBagley wrote: Sat Jun 19, 2021 8:52 am there’s a separate ifinput.c file
Yes, normally that function would be part of if.c. In MagiCNet, that was definitely moved into a separate file, which can be seen by the order of the functions (Pure-C does not rearrange them, just sometimes omits functions that are not referenced anywhere). That also explains the BSR instead of JSR, which just means that it was compiled with short calls.
I wonder if these two changes are enough to cause Pure C to use a different part of the code generator?
In my project that source is already in a different file, too. Moving files/functions around sometimes has the strange effect that different temp registers are used, but that does not explain why the "buf" pointer isn't immediately loaded to a2 in the original code.
Maybe compiled with Turbo C or Pure C 1.0?
That would not make much sense, since the remaining code was compiled with Pure-C 1.1. And i can almost certainly rule that out: Turbo-C does not preserve D2 in cdecl functions, but the code does. And Pure-C 1.0 generates jsr d16(pc) calls for short calls, while newer versions generate bsr.
Post Reply

Return to “Coding”