Modern PDP-11 C Compilers

Thanks, found it. I can fine tune those, I can see some further optimizations. A likely route is to handle signed and unsigned compares separately, that can be done.
Question for you: I would like to log a gcc defect for this, can I credit you for the report? Along the same lines, I’d credit you for contributing to the solution, unless you’d prefer not to be mentioned.

2 Likes

Question for you: I would like to log a gcc defect for this, can I credit you for the report? Along the same lines, I’d credit you for contributing to the solution, unless you’d prefer not to be mentioned.

Yes, I’d be happy to be credited in this way.

You show up with an alias “hoglet” here, but the email notification seems to have a real name. Which name should I use?
Also: can I use your spigot program as a test case for the GCC test suite to use?

I tend to use both: David Banks (hoglet)

Please go ahead and use the Pi Spigot as a test case.

Dave

1 Like

In the current development stream compiler (V13.0) the divide at line 93 (“p /= 10;”) generates a div instruction rather than a library call to unsigned 16 bit divide. The “unsigned” bit makes no sense, the current code does a signed divide as it should.
The long divides do generate library calls, as they must since they produce 32 bit quotients which isn’t what “div” does.
The register issue is still there, in -O0 only.

These changes were originally against the GCC 11.2 source tree, whch I think was the latest stable release the time.

This was the command I was using to build:

pdp11-aout-gcc -nostdlib -Ttext $ADDR src/crt0_gcc.s src/$i -lgcc -o $name

As far as I recall, I was working without optimization because there were more issues when optimization was enabled.

I’m not sure I’m following here; line 93 of which file?

spigot.c line 93, in function “print”.

In the version I built 4 months ago, that particular division in print() also generated a DIV instruction.

We are possibly talking at cross-purposes here.

Are you saying that one or other of the patches either is no longer needed, or just plain doesn’t make sense?

I have the latest GCC sources (from the git mirror) now checked out, so I’m able to fairly quickly test things.

It seems only the second patch (to pdp11.md) is needed for the spigot test case to run.

Here’s my test case for the first patch:

#include "tube.h"

void outhex(uint8_t i);
void outhex32(uint32_t i);
void outnl();

int program() {
   uint32_t a = 0x12345678;
   uint32_t *ap = &a;
   outhex32(*ap);
   outnl();
}

void outhex(uint8_t i) {
   i &= 15;
   if (i > 9) {
      outc(i + ('A' - 10));
   } else {
      outc(i + '0');
   }
}

void outhex32(uint32_t i) {
   int d;
   for (d = 0; d < 8; d++) {
      // Note: this uses ASHC which is a signed shift
      outhex((uint8_t)(i >> 28));
      i <<= 4;
   }
}

void outnl() {
   outc(10);
   outc(13);
}

This fails with the latest GCC, which generates the following code:

00000128 <_program>:
 128:	1166           	mov	r5, -(sp)
 12a:	1185           	mov	sp, r5
 12c:	65c6 fffa      	add	$-6, sp
 130:	15f5 1234 fffa 	mov	$11064, -6(r5)
 136:	15f5 5678 fffc 	mov	$53170, -4(r5)
 13c:	15c0 fffa      	mov	$-6, r0
 140:	6140           	add	r5, r0
 142:	1035 fffe      	mov	r0, -2(r5)
 146:	1d40 fffe      	mov	-2(r5), r0
 14a:	1200           	mov	(r0), r0     <<<<<  clobbers r0
 14c:	1c01 0002      	mov	2(r0), r1
 150:	1066           	mov	r1, -(sp)
 152:	1026           	mov	r0, -(sp)
 154:	09f7 004e      	jsr	pc, 1a6 <_outhex32>
 158:	65c6 0004      	add	$4, sp
 15c:	09f7 009c      	jsr	pc, 1fc <_outnl>
 160:	00a0           	nop
 162:	1146           	mov	r5, sp
 164:	1585           	mov	(sp)+, r5
 166:	0087           	rts	pc

With the patch (to pdp11.cc), the code is:

00000128 <_program>:
 128:	1166           	mov	r5, -(sp)
 12a:	1185           	mov	sp, r5
 12c:	65c6 fffa      	add	$-6, sp
 130:	15f5 1234 fffa 	mov	$11064, -6(r5)
 136:	15f5 5678 fffc 	mov	$53170, -4(r5)
 13c:	15c0 fffa      	mov	$-6, r0
 140:	6140           	add	r5, r0
 142:	1035 fffe      	mov	r0, -2(r5)
 146:	1d40 fffe      	mov	-2(r5), r0
 14a:	1c01 0002      	mov	2(r0), r1    <<<< swapped
 14e:	1200           	mov	(r0), r0     <<<< swapped
 150:	1066           	mov	r1, -(sp)
 152:	1026           	mov	r0, -(sp)
 154:	09f7 004e      	jsr	pc, 1a6 <_outhex32>
 158:	65c6 0004      	add	$4, sp
 15c:	09f7 009c      	jsr	pc, 1fc <_outnl>
 160:	00a0           	nop
 162:	1146           	mov	r5, sp
 164:	1585           	mov	(sp)+, r5
 166:	0087           	rts	pc

This is all with -O0

When we finally get our Imp77 compilers resurrected fully, remind me to build the old Pdp11
Imp compiler for you. It did rather well in Brian Wichmann’s Ackermann benchmark*, a little more info on which is mentioned here - we should have the ability to generate pdp11 assembler text interspersed with Imp source text so you can compare it to GCC et al. Due to some limitations in the current compilers, the pdp11 compiler isn’t ready to be rebuilt, but an older version of the source with some bits not yet recreated is temporarily at https://gtoal.com/tmp/imp11/ if you like looking at that sort of thing (ie unfamiliar languages, compiler code, historical software, etc).
[*: https://history.dcs.ed.ac.uk/archive/docs/Imp_Benchmarks/acklt.pdf
https://history.dcs.ed.ac.uk/archive/docs/Imp_Benchmarks/ackpe.pdf
https://history.dcs.ed.ac.uk/archive/docs/Imp_Benchmarks/ack.pdf ]

1 Like

Excellent articles! Recommended reading for lovers of the older architectures.